Goddag!
I denne artikel vil jeg fortælle, hvordan jeg realiserede () skript i Bash til at forbinde to computere, der befinder sig bag NAT, ved hjælp af teknologien UDP hole punching på eksemplet med OS Ubuntu/Debian.
Oprettelsen af forbindelsen består af flere trin:
- Start af noden og vent på, at den fjerne node er klar;
- Bestemmelse af den eksterne IP-adresse og UDP-port;
- Overførsel af den eksterne IP-adresse og UDP-port til den fjerne node;
- Modtagelse af den eksterne IP-adresse og UDP-port fra den fjerne node;
- Oprettelse af IPIP-tunnel;
- Overvågning af forbindelsen;
- Ved afbrydelse af forbindelsen skal IPIP-tunnelen slettes.
Jeg har længe overvejet, hvad der kan bruges til dataudveksling mellem noderne, det mest enkle og hurtige for mig lige nu er at arbejde via Yandex.Disk.
- For det første er det enkelt at bruge - der kræves 3 handlinger: oprette, læse, slette. Ved hjælp af curl er det:
Opret:curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folderLæs:
curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folderSlet:
curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder - For det andet er det let at installere:
apt install curl
Til bestemmelse af den eksterne IP-adresse og UDP-port bruges stun-client med kommandoen:
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"Installation med kommandoen:
apt install stun-clientTil oprettelse af tunnelen bruges standardværktøjer fra OS-pakken iproute2. Der findes som kan oprettes med standardværktøjer (L2TPv3, GRE osv.), men jeg valgte IPIP, fordi det skaber minimal ekstra belastning på systemet. Jeg prøvede L2TPv3 oven på UDP og blev skuffet, hastigheden faldt med 10 gange, men det kan være forskellige begrænsninger relateret til udbydere eller noget andet. Da IPIP-tunnelen fungerer på IP-niveau, bruges FOU-tunnelen til at arbejde på UDP-portniveau. For at oprette IPIP-tunnelen skal man:
— indlæse FOU-modulet:
modprobe fou— lytte på lokal port:
ip fou add port $localport ipproto 4— oprette tunnelen:
ip link add name fou$name type ipip remote $remoteip local $localip encap fou encap-sport $localport encap-dport $remoteport— aktivere tunnelens interface:
ip link set up dev fou$name— tildele interne lokale og interne fjerne IP-adresser til tunnelen:
ip addr add $intIP peer $peerip dev fou$nameSlet tunnelen:
ip link del dev fou$nameip fou del port $localportOvervågningen af tunnelens tilstand sker ved hjælp af periodisk ping af den interne IP-adresse på den fjernliggende nodes tunnel med kommandoen:
ping -c 1 $peerip -s 0Det periodiske ping er primært nødvendigt for at opretholde kanalen, ellers kan NAT-tabellerne på routerne blive renset, hvis tunnelen står stille, og så vil forbindelsen bryde.
Hvis pinget forsvinder, fjernes IPIP-tunnelen og venter på klarhed fra den fjernliggende node.
Selve scriptet:
#!/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 0Variabler brugernavn, adgangskode og folder skal være de samme på begge sider, mens intip — skal være forskellige, for eksempel: 10.0.0.1 og 10.0.0.2. Tiden på noderne skal være synkroniseret. Scriptet kan startes sådan:
nohup script.sh &Jeg vil gerne påpege, at IPIP-tunnelen ikke er sikker, eftersom trafikken ikke er krypteret, men dette kan nemt løses ved hjælp af IPsec fra , som jeg syntes var enkel og forståelig.
Jeg har brugt dette script til at forbinde til min arbejds-PC i flere uger og har ikke bemærket problemer. Det er praktisk, da jeg satte det op og glemte det.
Hvis du har kommentarer eller forslag, vil jeg være glad for at høre dem.
Tak for din opmærksomhed!
Kilde: habr.com
