Einfaches Stanzen von UDP-Löchern am Beispiel eines IPIP-Tunnels

Gute Tageszeit!



In diesem Artikel möchte ich Ihnen erklären, wie ich (ein anderes ) Skript in Bash implementiert habe, um zwei Computer hinter NAT mithilfe der UDP-Hole-Punching-Technologie am Beispiel des Ubuntu / Debian-Betriebssystems zu verbinden.



Das Herstellen einer Verbindung besteht aus mehreren Schritten:



  1. Starten eines Knotens und Warten auf die Bereitschaft des Remote-Knotens;
  2. Bestimmen der externen IP-Adresse und des UDP-Ports;
  3. Übertragung der externen IP-Adresse und des UDP-Ports an den Remote-Host;
  4. Abrufen einer externen IP-Adresse und eines UDP-Ports von einem Remote-Host;
  5. Organisation eines IPIP-Tunnels;
  6. Verbindungsüberwachung;
  7. Wenn die Verbindung unterbrochen wird, löschen Sie den IPIP-Tunnel.


Ich habe lange darüber nachgedacht und denke immer noch, dass es zum Austausch von Daten zwischen Knoten verwendet werden kann. Im Moment ist es für mich am einfachsten und schnellsten, über Yandex.Disk zu arbeiten.



  • Erstens ist es einfach zu bedienen - Sie benötigen 3 Schritte: Erstellen, Lesen, Löschen. Mit Curl ist dies:

    Erstellen:



    curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folder


    Lesen:

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


    Löschen:



    curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder
  • Zweitens ist es einfach zu installieren:



    apt install curl


Verwenden Sie den Befehl stun-client, um die externe IP-Adresse und den UDP-Port zu ermitteln:



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


Installation mit dem Befehl:



apt install stun-client


Zum Organisieren des Tunnels werden die Standard-Betriebssystemtools aus dem iproute2-Paket verwendet. Es gibt viele Tunnel , die mit Standardmitteln eingerichtet werden können (L2TPv3, GRE usw.), aber ich habe IPIP gewählt, weil es das System nur minimal zusätzlich belastet. Ich habe L2TPv3 über UDP ausprobiert und war enttäuscht, die Geschwindigkeit ist um den Faktor 10 gesunken, aber es kann verschiedene Einschränkungen in Bezug auf Anbieter oder etwas anderes geben. Da der IPIP-Tunnel auf IP-Ebene betrieben wird, wird der FOU-Tunnel für den Betrieb auf UDP-Port-Ebene verwendet. Um einen IPIP-Tunnel zu organisieren, müssen Sie:



- das FOU-Modul laden:



modprobe fou


- lokalen Port abhören:



ip fou add port $localport ipproto 4


- einen Tunnel erstellen:



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


- Rufen Sie die Tunnelschnittstelle auf:



ip link set up dev fou$name


- interne lokale und interne Remote-Tunnel-IP-Adresse zuweisen:



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


Tunnel löschen:



ip link del dev fou$name


ip fou del port $localport


Der Tunnelstatus wird überwacht, indem regelmäßig die interne IP-Adresse des Tunnels des Remote-Hosts mit dem folgenden Befehl gepingt wird:



ping -c 1 $peerip -s 0


Ein periodischer Ping ist in erster Linie erforderlich, um den Kanal aufrechtzuerhalten. Andernfalls können die NAT-Tabellen gelöscht werden, wenn der Tunnel auf den Routern inaktiv ist, und die Verbindung wird unterbrochen.



Wenn der Ping verloren geht, wird der IPIP-Tunnel gelöscht und wartet darauf, dass der Remote-Host bereit ist.



Das Skript selbst:



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


Der Benutzername , Passwort und Ordner Variablen müssen auf beiden Seiten, aber die intip muss anders, zum Beispiel: 10.0.0.1 und 10.0.0.2. Die Zeit an den Knoten muss synchronisiert werden. Sie können das Skript folgendermaßen ausführen:



nohup script.sh &


Ich mache Sie darauf aufmerksam, dass der IPIP-Tunnel unter dem Gesichtspunkt der Tatsache, dass der Datenverkehr nicht verschlüsselt ist, unsicher ist. Dies lässt sich jedoch mit IPSec für diesen Artikel leicht lösen. Es schien mir einfach und unkompliziert.



Ich verwende dieses Skript seit mehreren Wochen, um eine Verbindung zu einem funktionierenden PC herzustellen, und habe keine Probleme festgestellt. Praktisch beim Einrichten und Vergessen.



Vielleicht haben Sie Kommentare und Vorschläge, ich werde mich freuen zu hören.



Vielen Dank für Ihre Aufmerksamkeit!



All Articles