Perforación UDP sencilla utilizando un túnel IPIP como ejemplo

Buen tiempo!

En este artículo quiero contarte cómo implementé (uno masScript de Bash para conectar dos ordenadores detrás de NAT utilizando la tecnología UDP hole punching, usando el sistema operativo como ejemplo. Ubuntu/Debian.

Establecer una conexión consta de varios pasos:

  1. Iniciar un nodo y esperar a que el nodo remoto esté listo;
  2. Determinar la dirección IP externa y el puerto UDP;
  3. Transferir una dirección IP externa y un puerto UDP a un host remoto;
  4. Obtener una dirección IP externa y un puerto UDP desde un host remoto;
  5. Organización de un túnel IPIP;
  6. Monitoreo de conexión;
  7. Si se pierde la conexión, elimine el túnel IPIP.

Pensé durante mucho tiempo y sigo pensando qué 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.

  • En primer lugar, es fácil de usar: necesita 3 acciones: crear, leer y eliminar. Con rizo 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

    Borrar:

    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, utilice el comando stun-client:

stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"

Instalación con comando:

apt install stun-client

Para organizar un túnel, se utilizan herramientas estándar del sistema operativo del paquete iproute2. existe muchos túneles que se puede generar utilizando 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 10 veces, pero podrían ser varias restricciones relacionadas con los proveedores o algo más. Dado que el túnel IPIP opera a nivel de IP, el túnel FOU se utiliza para operar a nivel de puerto UDP. Para organizar un túnel IPIP necesita:

— cargar el módulo FOU:

modprobe fou

— escuchar el puerto local:

ip fou add port $localport ipproto 4

- crear un túnel:

ip link add name fou$name type ipip remote $remoteip local $localip encap fou  encap-sport $localport encap-dport $remoteport

— elevar la interfaz del túnel:

ip link set up dev fou$name

— asignar direcciones IP internas locales y remotas internas del túnel:

ip addr add $intIP peer $peerip dev fou$name

Eliminar un túnel:

ip link del dev fou$name

ip fou del port $localport

El estado del túnel se monitorea haciendo ping periódicamente a la dirección IP interna del túnel del nodo remoto con el comando:

ping -c 1 $peerip -s 0

El ping periódico es necesario principalmente para mantener el canal; de lo contrario, cuando el túnel esté inactivo, las tablas NAT en los enrutadores pueden borrarse y luego se interrumpirá la conexión.

Si el ping desaparece, entonces el túnel IPIP se elimina 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

Variables nombre de usuario, la contraseña и carpeta debe ser igual en ambos lados, pero ojeada - diferentes, por ejemplo: 10.0.0.1 y 10.0.0.2. La hora de los nodos debe estar sincronizada. Puedes ejecutar el script de esta manera:

nohup script.sh &

Me gustaría llamar su atención sobre el hecho de que el túnel IPIP no es seguro desde el punto de vista del hecho de que el tráfico no está cifrado, pero esto se puede solucionar fácilmente utilizando IPsec sobre este artículo, me pareció simple y comprensible.

He estado usando este script para conectarme a una PC del trabajo durante varias semanas y no he notado ningún problema. Conveniente en términos de configurarlo y olvidarlo.

Quizás tenga comentarios y sugerencias, estaré encantado de escucharlos.

Gracias por su atención!

Fuente: habr.com

Compre alojamiento confiable para sitios con protección DDoS, servidores VPS VDS 🔥 Compra alojamiento web fiable con protección DDoS, servidores VPS VDS | ProHoster