Buon pomeriggio!
In questo articolo voglio raccontare come ho realizzato () uno script Bash per connettere due computer dietro NAT, utilizzando la tecnologia UDP hole punching con esempio su OS Ubuntu/Debian.
L'organizzazione della connessione consiste in diversi passaggi:
- Avvio del nodo e attesa che il nodo remoto sia pronto;
- 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 continuo a pensare a cosa si può utilizzare per lo scambio di dati tra i nodi, per me la cosa più semplice e veloce al momento è l'utilizzo di Yandex.Disk.
- In primo luogo, è semplice da usare: ci sono 3 azioni: creare, leggere, eliminare. Con curl questo è:
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, utilizzare il client stun con il comando:
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"Installazione con il comando:
apt install stun-clientPer organizzare un tunnel, si utilizzano gli strumenti di sistema di base forniti nel pacchetto iproute2. Esistono che possono essere creati utilizzando gli strumenti di base (L2TPv3, GRE, ecc.), ma ho scelto IPIP perché genera un carico aggiuntivo minimo sul sistema. Ho provato L2TPv3 sopra UDP e sono rimasto deluso, la velocità è diminuita di 10 volte, ma potrebbero esserci vari vincoli legati ai fornitori o qualcos'altro. Poiché il tunnel IPIP opera a livello IP, utilizza un tunnel FOU per lavorare a livello delle porte UDP. Per organizzare un tunnel IPIP è necessario:
— 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 locale interno e l'indirizzo IP remoto interno del tunnel:
ip addr add $intIP peer $peerip dev fou$nameRimuovere il tunnel:
ip link del dev fou$nameip fou del port $localportIl monitoraggio dello stato del tunnel avviene tramite un ping periodico all'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, in caso di inattività del tunnel, le tabelle NAT sui router potrebbero essere svuotate e, di conseguenza, la connessione si interromperà.
Se il ping non risponde, il tunnel IPIP viene rimosso e attende la disponibilità dal nodo remoto.
In effetti, 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 cartella devono essere identici su entrambi i lati, mentre intip devono essere diversi, ad esempio: 10.0.0.1 e 10.0.0.2. L'ora sui nodi deve essere sincronizzata. Puoi avviare lo script così:
nohup script.sh &Vorrei sottolineare che il tunnel IPIP non è sicuro dal punto di vista della crittografia del traffico, ma questo può essere facilmente risolto con IPsec. , mi è sembrato semplice e chiaro.
Uso questo script per connettermi al computer di lavoro da diverse settimane e non ho riscontrato problemi. È comodo in quanto lo configuro e poi dimentico.
Se hai commenti o suggerimenti, sarei felice di ascoltarli.
Grazie per l'attenzione!
Fonte: habr.com
