En este artículo quiero contarles cómo implementé ( otro ) script en Bash para conectar dos computadoras detrás de NAT usando la tecnología de perforación de agujeros UDP usando el ejemplo del sistema operativo Ubuntu / Debian.
Establecer una conexión consta de varios pasos:
- Iniciar un nodo y esperar que el nodo remoto esté listo;
- Determinar la dirección IP externa y el puerto UDP;
- Transferencia de dirección IP externa y puerto UDP al host remoto;
- Obtener una dirección IP externa y un puerto UDP de un host remoto;
- Organización de un túnel IPIP;
- Monitoreo de la conexión;
- Si se pierde la conexión, elimine el túnel IPIP.
Pensé durante mucho tiempo y sigo pensando que se puede usar para intercambiar datos entre nodos, lo más simple y rápido para mí en este momento es trabajar a través de Yandex.Disk.
- Primero, es fácil de usar: necesita 3 pasos: crear, leer, eliminar. Con curl esto es:
Crear:
curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folder
Leer:
curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folder
Eliminar:
curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder
- En segundo lugar, es fácil de instalar:
apt install curl
Para determinar la dirección IP externa y el puerto UDP, use el comando stun-client:
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"
Instalación con el comando:
apt install stun-client
Para organizar el túnel, se utilizan las herramientas estándar del sistema operativo del paquete iproute2. Hay muchos túneles que se pueden configurar por medios estándar (L2TPv3, GRE, etc.), pero elegí IPIP porque crea una carga adicional mínima en el sistema. Probé L2TPv3 sobre UDP y me decepcionó, la velocidad se redujo en un factor de 10, pero puede haber varias restricciones relacionadas con los proveedores u otra cosa. Dado que el túnel IPIP funciona a nivel IP, el túnel FOU se utiliza para operar a nivel de puerto UDP. Para organizar un túnel IPIP, debe:
- cargar el módulo FOU:
modprobe fou
- escuchar puerto local:
ip fou add port $localport ipproto 4
- crea un túnel:
ip link add name fou$name type ipip remote $remoteip local $localip encap fou encap-sport $localport encap-dport $remoteport
- abrir la interfaz del túnel:
ip link set up dev fou$name
- Asignar la dirección IP del túnel interno local y remoto interno:
ip addr add $intIP peer $peerip dev fou$name
Eliminar túnel:
ip link del dev fou$name
ip fou del port $localport
El estado del túnel se supervisa haciendo ping periódicamente a la dirección IP interna del túnel del host remoto con el comando:
ping -c 1 $peerip -s 0
Se necesita un ping periódico principalmente para mantener el canal; de lo contrario, si el túnel está inactivo en los enrutadores, las tablas NAT se pueden borrar y luego la conexión se interrumpirá.
Si se pierde el ping, el túnel IPIP se cae y espera a que el host remoto esté listo.
El guión en sí:
#!/bin/bash
username="username@yandex.ru"
password="password"
folder="vpnid"
intip="10.0.0.1"
localport=`shuf -i 10000-65000 -n 1`
cid=`shuf -i 10000-99999 -n 1`
tid=`shuf -i 10-99 -n 1`
function yaread {
curl -s --user "$1:$2" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$3 | sed 's/></>\n</g' | grep "displayname" | sed 's/<d:displayname>//g' | sed 's/<\/d:displayname>//g' | grep -v $3 | grep -v $4 | sort -r
}
function yacreate {
curl -s -X MKCOL --user "$1:$2" https://webdav.yandex.ru/$3
}
function yadelete {
curl -s -X DELETE --user "$1:$2" https://webdav.yandex.ru/$3
}
function myipport {
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress" | sort | uniq | awk '{print $3}' | head -n1
}
function tunnel-up {
modprobe fou
ip fou add port $4 ipproto 4
ip link add name fou$7 type ipip remote $1 local $3 encap fou encap-sport $4 encap-dport $2
ip link set up dev fou$7
ip addr add $6 peer $5 dev fou$7
}
function tunnel-check {
sleep 10
pings=0
until [[ $pings == 4 ]]; do
if ping -c 1 $1 -s 0 &>/dev/null;
then echo -n .; n=0
else echo -n !; ((pings++))
fi
sleep 15
done
}
function tunnel-down {
ip link del dev fou$1
ip fou del port $2
}
trap 'echo -e "\nDisconnecting..." && yadelete $username $password $folder; tunnel-down $tunnelid $localport; echo "IPIP tunnel disconnected!"; exit 1' 1 2 3 8 9 14 15
until [[ -n $end ]]; do
yacreate $username $password $folder
until [[ -n $ip ]]; do
mydate=`date +%s`
timeout="60"
list=`yaread $username $password $folder $cid | head -n1`
yacreate $username $password $folder/$mydate:$cid
for l in $list; do
if [ `echo $l | sed 's/:/ /g' | awk {'print $1'}` -ge $(($mydate-65)) ]; then
#echo $list
myipport=`myipport $localport`
yacreate $username $password $folder/$mydate:$cid:$myipport:$intip:$tid
timeout=$(( $timeout + `echo $l | sed 's/:/ /g' | awk {'print $1'}` - $mydate + 3 ))
ip=`echo $l | sed 's/:/ /g' | awk '{print $3}'`
port=`echo $l | sed 's/:/ /g' | awk '{print $4}'`
peerip=`echo $l | sed 's/:/ /g' | awk '{print $5}'`
peerid=`echo $l | sed 's/:/ /g' | awk '{print $6}'`
if [[ -n $peerid ]]; then tunnelid=$(($peerid*$tid)); fi
fi
done
if ( [[ -z "$ip" ]] && [ "$timeout" -gt 0 ] ) ; then
echo -n "!"
sleep $timeout
fi
done
localip=`ip route get $ip | head -n1 | sed 's|.*src ||' | cut -d' ' -f1`
tunnel-up $ip $port $localip $localport $peerip $intip $tunnelid
tunnel-check $peerip
tunnel-down $tunnelid $localport
yadelete $username $password $folder
unset ip port myipport
done
exit 0
Las variables de nombre de usuario , contraseña y carpeta deben ser las mismas en ambos lados, pero el intip debe ser diferente, por ejemplo: 10.0.0.1 y 10.0.0.2. El tiempo en los nodos debe estar sincronizado. Puede ejecutar el script de esta manera:
nohup script.sh &
Le llamo la atención sobre el hecho de que el túnel IPIP es inseguro desde el punto de vista del hecho de que el tráfico no está encriptado, pero esto se resuelve fácilmente usando IPsec en este artículo , me pareció simple y directo.
He estado usando este script para conectarme a una PC que funciona durante varias semanas y no he notado ningún problema. Conveniente en términos de configuración y olvido.
Quizás tenga comentarios y sugerencias, me alegrará saberlo.
¡Gracias por tu atención!