Enkel UDP-hålslagning med en IPIP-tunnel som exempel

Bra tid på dagen!

I den här artikeln vill jag berätta hur jag implementerade (en till) ett Bash-skript för att ansluta två datorer bakom NAT med hjälp av UDP-hålslagningsteknik med Ubuntu/Debian OS som exempel.

Att upprätta en anslutning består av flera steg:

  1. Starta en nod och vänta på att fjärrnoden ska vara klar;
  2. Fastställande av extern IP-adress och UDP-port;
  3. Överföra en extern IP-adress och UDP-port till en fjärrvärd;
  4. Skaffa en extern IP-adress och UDP-port från en fjärrvärd;
  5. Organisation av en IPIP-tunnel;
  6. Anslutningsövervakning;
  7. Om anslutningen bryts, radera IPIP-tunneln.

Jag tänkte länge och tänker fortfarande på vad som kan användas för att utbyta data mellan noder, det enklaste och snabbaste för mig för tillfället är att arbeta genom Yandex.disk.

  • För det första är det lätt att använda - du behöver tre åtgärder: skapa, läsa, ta bort. Med curl är 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

    Radera:

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

För att fastställa den externa IP-adressen och UDP-porten, använd kommandot stun-client:

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

Installation med kommando:

apt install stun-client

För att organisera en tunnel används standard OS-verktyg från iproute2-paketet. Existerar många tunnlar som kan höjas med standardmedel (L2TPv3, GRE, etc.), men jag valde IPIP eftersom det skapar minimal extra belastning på systemet. Jag försökte L2TPv3 över UDP och blev besviken, hastigheten sjönk 10 gånger, men dessa kan vara olika restriktioner relaterade till leverantörer eller något annat. Eftersom IPIP-tunneln arbetar på IP-nivå, används FOU-tunneln för att arbeta på UDP-portnivå. För att organisera en IPIP-tunnel behöver du:

— ladda FOU-modulen:

modprobe fou

— lyssna på lokal hamn:

ip fou add port $localport ipproto 4

— skapa en tunnel:

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

— höja tunnelgränssnittet:

ip link set up dev fou$name

— tilldela interna lokala och interna fjärr-IP-adresser för tunneln:

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

Ta bort en tunnel:

ip link del dev fou$name

ip fou del port $localport

Tunneltillståndet övervakas genom att regelbundet pinga den interna IP-adressen för fjärrnodtunneln med kommandot:

ping -c 1 $peerip -s 0

Periodisk ping behövs främst för att upprätthålla kanalen, annars, när tunneln är inaktiv, kan NAT-tabellerna på routrarna rensas och då kommer anslutningen att brytas.

Om pingningen försvinner raderas IPIP-tunneln och väntar på beredskap från fjärrvärden.

Själva skriptet:

#!/bin/bash
username="[email protected]"
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 Användarnamn, Lösenord и mapp bör vara samma på båda sidor, men titt - olika, till exempel: 10.0.0.1 och 10.0.0.2. Tiden på noderna måste synkroniseras. Du kan köra skriptet så här:

nohup script.sh &

Jag vill uppmärksamma er på att IPIP-tunneln är osäker med tanke på att trafiken inte är krypterad, men detta kan enkelt lösas med IPsec över den här artikeln, det verkade enkelt och förståeligt för mig.

Jag har använt det här skriptet för att ansluta till en arbetsdator i flera veckor nu och har inte märkt några problem. Bekvämt när det gäller att ställa in det och glömma det.

Kanske har du kommentarer och förslag, jag lyssnar gärna.

Tack för din uppmärksamhet!

Källa: will.com

Lägg en kommentar