Enkel UDP hole punching med ett exempel pÄ IPIP-tunnel

God dag!

I denna artikel vill jag berÀtta om hur jag har implementerat (Ànnu en) skript i Bash för att koppla samman tvÄ datorer som finns bakom NAT, med hjÀlp av teknologin UDP hole punching med exempel frÄn operativsystemet Ubuntu/Debian.

Genomförandet av anslutningen bestÄr av flera steg:

  1. Starta noden och vÀnta pÄ att den fjÀrrnod ska bli redo;
  2. BestÀmma extern IP-adress och UDP-port;
  3. Överföra extern IP-adress och UDP-port till den fjĂ€rrnod;
  4. Mottag extern IP-adress och UDP-port frÄn den fjÀrrnod;
  5. Organisera IPIP-tunnel;
  6. Övervaka anslutningen;
  7. Vid avbrott i anslutningen ska IPIP-tunneln tas bort.

Jag har tÀnkt lÀnge och fortsÀtter att tÀnka pÄ vad som kan anvÀndas för datadelning mellan noder, det enklaste och snabbaste för mig just nu Àr att anvÀnda Yandex.Disk.

  • För det första Ă€r det enkelt att anvĂ€nda – tre Ă„tgĂ€rder: skapa, lĂ€sa, ta bort. Med curl gör man detta:
    Skapa:
    curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folder

    LĂ€sa:

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

    Ta bort:

    curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder
  • För det andra Ă€r det enkelt att installera:
    apt install curl

För att bestÀmma extern IP-adress och UDP-port anvÀnds stun-client med kommandot:

stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"

Installation med kommandot:

apt install stun-client

För att organisera tunneln anvÀnds standardverktyg frÄn OS-paketet iproute2. Det finns mÄnga tunnlar som kan upprÀttas med standardmedel (L2TPv3, GRE, etc.), men jag valde IPIP eftersom det skapar minimal extra belastning pÄ systemet. Jag testade L2TPv3 över UDP och blev besviken, hastigheten minskade tio gÄnger, men det kan bero pÄ olika begrÀnsningar relaterade till leverantörer eller nÄgot annat. Eftersom IPIP-tunneln fungerar pÄ IP-nivÄ anvÀnds FOU-tunneln för att arbeta pÄ UDP-portnivÄ. För att organisera IPIP-tunneln behövs:

— ladda FOU-modulen:

modprobe fou

— lyssna pĂ„ lokal port:

ip fou add port $localport ipproto 4

— skapa tunneln:

ip link add name fou$name type ipip remote $remoteip local $localip encap fou  encap-sport $localport encap-dport $remoteport

— aktivera tunnelnĂ€tverksgrĂ€nssnittet:

ip link set up dev fou$name

— tilldela intern lokal och intern fjĂ€rr IP-adress till tunneln:

ip addr add $intIP peer $peerip dev fou$name

Ta bort tunneln:

ip link del dev fou$name

ip fou del port $localport

Övervakning av tunnelns tillstĂ„nd sker genom periodisk ping av den interna IP-adressen för tunnelns fjĂ€rrnod med kommandot:

ping -c 1 $peerip -s 0

Den periodiska pingen behövs frÀmst för att upprÀtthÄlla kanalen, annars kan NAT-tabellerna pÄ routrarna rensas under inaktivitet i tunneln, vilket leder till att anslutningen bryts.

Om pingen försvinner tas IPIP-tunneln bort och vÀntar pÄ att fjÀrrnoden ska bli redo.

SjÀlva skriptet:

#!/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

Variabler username, password och folder mÄste vara identiska pÄ bÄda sidor, men intip kan vara olika, till exempel: 10.0.0.1 och 10.0.0.2. Tiden pÄ noderna mÄste vara synkroniserad. Skriptet kan startas sÄ hÀr:

nohup script.sh &

Jag vill pÄpeka att IPIP-tunneln inte Àr sÀker ur den synvinkeln att trafiken inte Àr krypterad, men detta kan enkelt lösas med hjÀlp av IPsec. denna artikel, det verkade enkelt och förstÄeligt för mig.

Jag har anvÀnt detta skript för att ansluta till min arbetsdator i flera veckor utan att mÀrka nÄgra problem. Det Àr praktiskt eftersom jag har stÀllt in det en gÄng och sedan glömt det.

Kanske har du nÄgra kommentarer eller förslag, jag skulle vara glad att lyssna.

Tack för uppmÀrksamheten!

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster