Bună ziua!
În acest articol vreau să împărtășesc cum am implementat () un script Bash pentru conectarea a două computere, aflate în spatele NAT, folosind tehnologia UDP hole punching pe sistemele de operare Ubuntu/Debian.
Organizarea conexiunii constă din mai mulți pași:
- Pornirea nodului și așteptarea pregătirii nodului la distanță;
- Determinarea adresei IP externe și a portului UDP;
- Transmiterea adresei IP externe și a portului UDP nodului la distanță;
- Obținerea adresei IP externe și a portului UDP de la nodul la distanță;
- Organizarea tunelului IPIP;
- Monitorizarea conexiunii;
- La întreruperea conexiunii, șterge tunelul IPIP.
M-am gândit mult și mă gândesc încă ce aș putea folosi pentru schimbul de date între noduri, cel mai simplu și rapid pentru mine în acest moment este lucrul prin Yandex.Disk.
- În primul rând, este simplu de utilizat — sunt necesare 3 acțiuni: creați, citiți, ștergeți. Cu ajutorul curl, acestea sunt:
Creează:curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folderCitește:
curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folderȘterge:
curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder - În al doilea rând, este simplu de instalat:
apt install curl
Pentru a determina adresa IP externă și portul UDP se folosește comanda stun-client:
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"Instalare cu comanda:
apt install stun-clientPentru organizarea tunelului se folosesc instrumentele standard ale sistemului de operare din pachetul iproute2. Există care pot fi ridicate cu ajutoare standard (L2TPv3, GRE etc.), dar am ales IPIP pentru că acesta creează o sarcină suplimentară minimă asupra sistemului. Am încercat L2TPv3 peste UDP și am fost dezamăgit, viteza a scăzut de 10 ori, dar acest lucru poate fi din cauza diferitelor limitări legate de furnizori sau din alte motive. Deoarece tunelul IPIP funcționează la nivelul IP, se folosește tunelul FOU pentru a funcționa la nivelul porturilor UDP. Pentru organizarea tunelului IPIP este necesar:
— să încarci modulul FOU:
modprobe fou— să asculți un port local:
ip fou add port $localport ipproto 4— să creezi un tunel:
ip link add name fou$name type ipip remote $remoteip local $localip encap fou encap-sport $localport encap-dport $remoteport— să ridici interfața tunelului:
ip link set up dev fou$name— să aloci adresele IP interne locale și externe ale tunelului:
ip addr add $intIP peer $peerip dev fou$nameȘterge tunelul:
ip link del dev fou$nameip fou del port $localportMonitorizarea stării tunelului se realizează prin ping-uri periodice ale adresei IP interne a tunelului gazdei de la distanță, cu comanda:
ping -c 1 $peerip -s 0Ping-ul periodic este necesar în primul rând pentru a menține canalul, altfel, în cazul inactivității tunelului, tabelele NAT de pe routere pot fi șterse, moment în care conexiunea se va întrerupe.
Dacă ping-ul dispare, tunelul IPIP este șters și așteaptă disponibilitatea de la gazda de la distanță.
Iată scriptul:
#!/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 0Variabile username, parola și folder trebuie să fie identice de ambele părți, în timp ce intip — diferite, de exemplu: 10.0.0.1 și 10.0.0.2. Timpul pe noduri trebuie să fie sincronizat. Scriptul poate fi pornit astfel:
nohup script.sh &Menționez că tunelul IPIP nu este sigur din punct de vedere al faptului că traficul nu este criptat, dar acest lucru poate fi ușor rezolvat cu ajutorul IPsec, deoarece , mi s-a părut simplu și clar.
Folosesc acest script pentru a mă conecta la PC-ul de lucru de câteva săptămâni și nu am observat probleme. Este convenabil din punct de vedere că l-am configurat și l-am uitat.
Poate aveți observații și sugestii, aș fi bucuros să le aud.
Vă mulțumesc pentru atenție!
Sursa: habr.com
