Buon pomeriggio!
In questo articolo voglio raccontare come ho realizzato () script in Bash per collegare due computer che si trovano dietro NAT, utilizzando la tecnologia UDP hole punching con esempio su OS Ubuntu/Debian.
L'organizzazione della connessione si compone di vari passaggi:
- Avvio del nodo e attesa della disponibilità del nodo remoto;
- Determinazione dell'indirizzo IP esterno e della porta UDP;
- Trasmissione dell'indirizzo IP esterno e della porta UDP al nodo remoto;
- Ricezione dell'indirizzo IP esterno e della porta UDP dal nodo remoto;
- Organizzazione di un tunnel IPIP;
- Monitoraggio della connessione;
- In caso di interruzione della connessione eliminare il tunnel IPIP.
Ho pensato a lungo e sto ancora pensando a cosa si può utilizzare per lo scambio di dati tra i nodi, la cosa più semplice e veloce per me al momento è l'uso di Yandex.Disk.
- In primo luogo, è semplice da usare: sono necessari 3 passaggi: creare, leggere, eliminare. Con curl ciò significa:
Creare:curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folderLeggere:
curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folderEliminare:
curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder - In secondo luogo, è semplice da installare:
apt install curl
Per determinare l'indirizzo IP esterno e la porta UDP si utilizza stun-client con il comando:
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"Installare con il comando:
apt install stun-clientPer organizzare il tunnel si utilizzano gli strumenti standard del sistema operativo dal pacchetto iproute2. Ci sono che possono essere creati con strumenti standard (L2TPv3, GRE, ecc.), ma ho scelto IPIP perché crea un carico addizionale minimo sul sistema. Ho provato L2TPv3 sopra UDP e sono rimasto deluso, la velocità è diminuita di 10 volte, ma potrebbero esserci vari limiti legati ai fornitori o ad altro. Poiché il tunnel IPIP funziona a livello di IP, si utilizza un tunnel FOU per lavorare a livello delle porte UDP. Per organizzare un tunnel IPIP sono necessari:
— caricare il modulo FOU:
modprobe fou— ascoltare 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— attivare l'interfaccia del tunnel:
ip link set up dev fou$name— assegnare l'indirizzo IP interno locale e l'indirizzo IP interno remoto del tunnel:
ip addr add $intIP peer $peerip dev fou$nameEliminare il tunnel:
ip link del dev fou$nameip fou del port $localportIl monitoraggio delle condizioni del tunnel avviene mediante il ping periodico dell'indirizzo IP interno del tunnel del nodo remoto, con il comando:
ping -c 1 $peerip -s 0Il ping periodico è necessario principalmente per mantenere attivo il canale, altrimenti durante un inattività del tunnel sui router potrebbero svuotarsi le tabelle NAT e allora la connessione si interromperà.
Se il ping viene perso, il tunnel IPIP viene rimosso e attende che il nodo remoto sia pronto.
Lo script stesso:
#!/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 0Variabili username, password e folder devono essere identici su entrambi i lati, mentre intip — sono diversi, per esempio: 10.0.0.1 e 10.0.0.2. L'ora sui nodi deve essere sincronizzata. Lo script può essere avviato in questo modo:
nohup script.sh &Voglio sottolineare che il tunnel IPIP non è sicuro in termini di traffico in quanto non è criptato, ma questo può essere facilmente risolto con IPsec da , mi è sembrato semplice e chiaro.
Utilizzo questo script per connettermi al PC di lavoro da diverse settimane e non ho riscontrato problemi. È comodo in quanto l'ho configurato e dimenticato.
Forse avrete commenti e suggerimenti, sarò felice di ascoltarli.
Grazie per l'attenzione!
Fonte: habr.com
