Enostavno UDP hole punching na primeru IPIP-tunnela

Dober dan!

V tem članku želim opisati, kako sem izvedel (še en) 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:

  1. Zagon vozlišča in čakanje na pripravljenost oddaljenega vozlišča;
  2. Določitev zunanjega IP-naslova in UDP vrata;
  3. Prenos zunanjega IP-naslova in UDP vrata oddaljenemu vozlišču;
  4. Prejem zunanjega IP-naslova in UDP vrata od oddaljenega vozlišča;
  5. Organizacija IPIP tunela;
  6. Nadzor povezave;
  7. 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/$folder

    Preberi:

    curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folder

    Izbriš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-client

Za organizacijo tunela se uporabljajo privzeta sredstva operacijskega sistema iz paketa iproute2. Obstaja številni tuneli 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$name

Odstranite tunel:

ip link del dev fou$name

ip fou del port $localport

Stanje tunela se nadzire putem periodičnog pinga unutarnjoj IP adresi tunela udaljenog čvora, naredbom:

ping -c 1 $peerip -s 0

Periodič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 0

Spremenljivke 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 this article, č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

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster