Dobar dan!
U ovom članku želim pričati o tome kako sam implementirao () Bash skript za povezivanje dva računala koja se nalaze iza NAT-a, koristeći tehnologiju UDP hole punching na primjeru OS Ubuntu/Debian.
Organizacija veze se sastoji od nekoliko koraka:
- Pokretanje čvora i čekanje na spremnost udaljenog čvora;
- Određivanje vanjske IP adrese i UDP porta;
- Slanje vanjske IP adrese i UDP porta udaljenom čvoru;
- Primanje vanjske IP adrese i UDP porta od udaljenog čvora;
- Organizacija IPIP tunela;
- Praćenje veze;
- U slučaju prekida veze, obriši IPIP tunel.
Dugo sam razmišljao i još razmišljam o tome što se može koristiti za razmjenu podataka između čvorova, trenutno mi je najjednostavnije i najbrže korištenje Yandex.Diska.
- Prvo, jednostavnost korištenja — treba tri koraka: kreirati, pročitati, obrisati. Uz curl to izgleda ovako:
Kreirati:curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folderPročitati:
curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folderObrisati:
curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder - Drugo, jednostavnost instalacije:
apt install curl
Za određivanje vanjske IP adrese i UDP porta koristi se stun-client komanda:
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"Instalacija komandom:
apt install stun-clientZa organizaciju tunela koriste se standardna sredstva operativnog sustava iz paketa iproute2. Postoji koje se mogu podići standardnim sredstvima (L2TPv3, GRE i dr.), ali sam odabrao IPIP jer stvara minimalno dodatno opterećenje na sustav. Pokušao sam L2TPv3 preko UDP-a i bio razočaran, brzina se smanjila deset puta, ali to mogu biti različita ograničenja povezana s davateljima usluga ili nečim sličnim. Kako IPIP tunel radi na razini IP-a, koristi se FOU tunel za rad na razini UDP portova. Za organizaciju IPIP tunela potrebno je:
— učitati FOU modul:
modprobe fou— slušati lokalni port:
ip fou add port $localport ipproto 4— kreirati tunel:
ip link add name fou$name type ipip remote $remoteip local $localip encap fou encap-sport $localport encap-dport $remoteport— podići tunelski interfejs:
ip link set up dev fou$name— odrediti unutarnju lokalnu i unutarnju udaljenu IP adresu tunela:
ip addr add $intIP peer $peerip dev fou$nameObrisati tunel:
ip link del dev fou$nameip fou del port $localportMonitoring status of the tunnel is performed through periodic pings of the internal IP address of the remote node's tunnel, using the command:
ping -c 1 $peerip -s 0Periodic pings are primarily needed to maintain the channel; otherwise, during tunnel idle time, NAT tables on routers may clear, and the connection will be lost.
If the ping is lost, the IPIP tunnel is removed and waits for readiness from the remote node.
Here is the script itself:
#!/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 0Varijable korisničko_ime, lozinka i folder must be the same on both sides, but intip — should be different, for example: 10.0.0.1 and 10.0.0.2. The time on nodes should be synchronized. The script can be launched as follows:
nohup script.sh &I would like to point out that the IPIP tunnel is not secure in terms of traffic being unencrypted, but this is easily addressed using IPsec. , it seemed simple and understandable to me.
I have been using this script to connect to my work PC for several weeks now and have not noticed any issues. It's convenient in that I set it up and forgot it.
You may have comments and suggestions; I would be happy to listen.
Hvala na pažnji!
Izvor: habr.com
