Dober dan!
V tem članku želim opisati, kako sem izvedel () skript v Bash za povezovanje dveh računalnikov, ki se nahajata za NAT, s pomočjo tehnologije UDP hole punching na primeru operacijskega sistema Ubuntu/Debian.
Organizacija povezave je sestavljena iz več korakov:
- Zagon vozlišča in čakanje na pripravljenost oddaljenega vozlišča;
- Določitev zunanjega IP-naslova in UDP vrata;
- Prenos zunanjega IP-naslova in UDP vrata oddaljenemu vozlišču;
- Prejem zunanjega IP-naslova in UDP vrata od oddaljenega vozlišča;
- Organizacija IPIP tunela;
- Nadzor povezave;
- Ob prekinitvi povezave odstranite IPIP tunel.
Dolgo sem razmišljal in še vedno razmišljam, kaj bi lahko uporabili za izmenjavo podatkov med vozlišči, trenutno zame najbolj enostavna in hitra rešitev je uporaba Yandex.Disk.
- Prvič, preprosto je za uporabo — potrebna so 3 dejanja: ustvariti, prebrati, izbrisati. S pomočjo curl to je:
Ustvari:curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folderPreberi:
curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folderIzbriši:
curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder - Drugič, enostavna je za namestitev:
apt install curl
Za določitev zunanjega IP-naslova in UDP vrata se uporabi stun-client z ukazom:
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"Namestitev s ukazom:
apt install stun-clientZa organizacijo tunela se uporabljajo privzeta sredstva operacijskega sistema iz paketa iproute2. Obstaja ki jih je mogoče vzpostaviti z običajnimi sredstvi (L2TPv3, GRE itd.), vendar sem izbral IPIP, ker ustvarja minimalno dodatno obremenitev sistema. Poskusil sem L2TPv3 čez UDP in se razočaral, hitrost je padla za 10-krat, vendar so lahko razlog za to razne omejitve, povezane z izvajalci storitev ali s čim drugim. Ker IPIP tunel deluje na ravni IP, se uporablja FOU tunel, da se deluje na ravni UDP vrat. Za organizacijo IPIP tunela potrebujete:
— nalaganje FOU modula:
modprobe fou— poslušanje lokalnega porta:
ip fou add port $localport ipproto 4— ustvarjanje tunela:
ip link add name fou$name type ipip remote $remoteip local $localip encap fou encap-sport $localport encap-dport $remoteport— aktiviranje vmesnika tunela:
ip link set up dev fou$name— dodelitev notranjega lokalnega in notranjega oddaljenega IP-naslova tunela:
ip addr add $intIP peer $peerip dev fou$nameOdstranite tunel:
ip link del dev fou$nameip fou del port $localportStanje tunela se nadzire putem periodičnog pinga unutarnjoj IP adresi tunela udaljenog čvora, naredbom:
ping -c 1 $peerip -s 0Periodični ping je prvenstveno potreban za održavanje kanala, inače se tijekom mirovanja tunela na usmjerivačima mogu očistiti NAT tablice i tada će veza biti prekinuta.
Ako ping nestane, IPIP tunel se uklanja i čeka na spremnost od udaljenog čvora.
Sam skript:
#!/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 0Spremenljivke username, password in folder moraju biti isti s obje strane, dok su intip — različiti, na primjer: 10.0.0.1 i 10.0.0.2. Vrijeme na čvorovima mora biti sinkronizirano. Skriptu možete pokrenuti na sljedeći način:
nohup script.sh &Napominjem da IPIP tunel nije siguran s aspekta da se promet ne šifrira, ali to se lako rješava pomoću IPsec-a , čini mi se jednostavnom i razumljivom.
Koristim ovu skriptu za povezivanje s radnim računalom već nekoliko tjedana i nisam primijetio probleme. Udobno je jer sam je postavio i zaboravio.
Možda imate primjedbe i prijedloge, rado ću ih saslušati.
Hvala za pozornost!
Izvor: habr.com
