Semplice foratura UDP utilizzando un tunnel IPIP come esempio

Buon momento della giornata!

In questo articolo voglio raccontarvi come ho implementato (ancora uno) uno script Bash per connettere due computer situati dietro NAT utilizzando la tecnologia di perforazione UDP utilizzando come esempio il sistema operativo Ubuntu/Debian.

La creazione di una connessione prevede diversi passaggi:

  1. Avvio di un nodo e attesa che il nodo remoto sia pronto;
  2. Determinazione dell'indirizzo IP esterno e della porta UDP;
  3. Trasferimento di un indirizzo IP esterno e di una porta UDP a un host remoto;
  4. Ottenere un indirizzo IP esterno e una porta UDP da un host remoto;
  5. Organizzazione di un tunnel IPIP;
  6. Monitoraggio della connessione;
  7. Se la connessione viene persa, eliminare il tunnel IPIP.

Ho pensato a lungo e penso ancora a cosa possa essere utilizzato per scambiare dati tra nodi, il più semplice e veloce per me al momento è lavorare tramite Yandex.disk.

  • Innanzitutto, è facile da usare: sono necessarie 3 azioni: creare, leggere, eliminare. Con curl questo è:
    creato:

    curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folder

    Leggere:

    curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folder

    Elimina:

    curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder
  • In secondo luogo, è facile da installare:
    apt install curl

Per determinare l'indirizzo IP esterno e la porta UDP, utilizzare il comando stun-client:

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

Installazione con comando:

apt install stun-client

Per organizzare un tunnel vengono utilizzati gli strumenti del sistema operativo standard del pacchetto iproute2. Esiste molti tunnel che può essere aumentato utilizzando mezzi standard (L2TPv3, GRE, ecc.), ma ho scelto IPIP perché crea un carico aggiuntivo minimo sul sistema. Ho provato L2TPv3 su UDP e sono rimasto deluso, la velocità è diminuita di 10 volte, ma queste potrebbero essere varie restrizioni legate ai provider o qualcos'altro. Poiché il tunnel IPIP opera a livello IP, il tunnel FOU viene utilizzato per operare a livello di porta UDP. Per organizzare un tunnel IPIP è necessario:

— caricare il modulo FOU:

modprobe fou

— ascolta la porta locale:

ip fou add port $localport ipproto 4

— creare un tunnel:

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

— alzare l'interfaccia del tunnel:

ip link set up dev fou$name

— assegnare gli indirizzi IP locali interni e remoti interni del tunnel:

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

Elimina un tunnel:

ip link del dev fou$name

ip fou del port $localport

Lo stato del tunnel viene monitorato eseguendo periodicamente il ping dell'indirizzo IP interno del tunnel del nodo remoto con il comando:

ping -c 1 $peerip -s 0

Il ping periodico è necessario principalmente per mantenere il canale, altrimenti, quando il tunnel è inattivo, le tabelle NAT sui router potrebbero essere cancellate e quindi la connessione verrà interrotta.

Se il ping scompare, il tunnel IPIP viene eliminato e attende che l'host remoto sia pronto.

La sceneggiatura stessa:

#!/bin/bash
username="[email protected]"
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

variabili nome utente, parola d'ordine и cartella dovrebbe essere lo stesso su entrambi i lati, ma intuizione - diversi, ad esempio: 10.0.0.1 e 10.0.0.2. L'ora sui nodi deve essere sincronizzata. Puoi eseguire lo script in questo modo:

nohup script.sh &

Vorrei attirare la vostra attenzione sul fatto che il tunnel IPIP non è sicuro dal punto di vista del traffico non crittografato, ma questo può essere facilmente risolto utilizzando IPsec su questo articolo, mi è sembrato semplice e comprensibile.

Utilizzo questo script per connettermi a un PC di lavoro ormai da diverse settimane e non ho notato alcun problema. Comodo in termini di impostarlo e dimenticarlo.

Forse avrai commenti e suggerimenti, sarò felice di ascoltarli.

Grazie!

Fonte: habr.com

Aggiungi un commento