Einfaches UDP-Lochlochen am Beispiel eines IPIP-Tunnels

Gute Zeit!

In diesem Artikel möchte ich Ihnen erzählen, wie ich (noch eins) ein Bash-Skript zum Verbinden zweier Computer hinter NAT mithilfe der UDP-Hole-Punching-Technologie am Beispiel des Ubuntu/Debian-Betriebssystems.

Der Verbindungsaufbau besteht aus mehreren Schritten:

  1. Einen Knoten starten und darauf warten, dass der Remote-Knoten bereit ist;
  2. Ermittlung der externen IP-Adresse und des UDP-Ports;
  3. Übertragen einer externen IP-Adresse und eines UDP-Ports an einen Remote-Host;
  4. Erhalten einer externen IP-Adresse und eines UDP-Ports von einem Remote-Host;
  5. Organisation eines IPIP-Tunnels;
  6. Verbindungsüberwachung;
  7. Wenn die Verbindung verloren geht, löschen Sie den IPIP-Tunnel.

Ich habe lange darüber nachgedacht und denke immer noch darüber nach, womit man Daten zwischen Knoten austauschen kann. Am einfachsten und schnellsten ist für mich derzeit die Arbeit über Yandex.disk.

  • Erstens ist es einfach zu bedienen – Sie benötigen drei Aktionen: Erstellen, Lesen, Löschen. Mit Curl ist das:
    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

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

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

Installation mit Befehl:

apt install stun-client

Um einen Tunnel zu organisieren, werden Standard-Betriebssystemtools aus dem iproute2-Paket verwendet. Existiert viele Tunnel Dies kann mit Standardmitteln (L2TPv3, GRE usw.) erhöht werden, ich habe mich jedoch für IPIP entschieden, da es nur eine minimale zusätzliche Belastung für das System verursacht. Ich habe L2TPv3 über UDP ausprobiert und war enttäuscht, die Geschwindigkeit ist um das Zehnfache gesunken, aber das könnten verschiedene Einschränkungen im Zusammenhang mit Anbietern oder etwas anderes sein. Da der IPIP-Tunnel auf IP-Ebene arbeitet, wird der FOU-Tunnel für den Betrieb auf UDP-Port-Ebene verwendet. Um einen IPIP-Tunnel zu organisieren, benötigen Sie:

— Laden Sie das FOU-Modul:

modprobe fou

— Hören Sie sich den lokalen Port an:

ip fou add port $localport ipproto 4

— Erstellen Sie einen Tunnel:

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

– Erhöhen Sie die Tunnelschnittstelle:

ip link set up dev fou$name

— Weisen Sie interne lokale und interne Remote-IP-Adressen des Tunnels zu:

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

Einen Tunnel löschen:

ip link del dev fou$name

ip fou del port $localport

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

ping -c 1 $peerip -s 0

Regelmäßiges Ping ist in erster Linie erforderlich, um den Kanal aufrechtzuerhalten. Andernfalls werden die NAT-Tabellen auf den Routern möglicherweise gelöscht, wenn der Tunnel inaktiv ist, und die Verbindung wird unterbrochen.

Wenn der Ping verschwindet, wird der IPIP-Tunnel gelöscht und wartet auf die Bereitschaft des Remote-Hosts.

Das Skript selbst:

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

Variablen Benutzername, Passwort и Flyer sollte auf beiden Seiten gleich sein, aber Hinweis - unterschiedlich, zum Beispiel: 10.0.0.1 und 10.0.0.2. Die Uhrzeit auf den Knoten muss synchronisiert sein. Sie können das Skript wie folgt ausführen:

nohup script.sh &

Ich möchte Sie darauf aufmerksam machen, dass der IPIP-Tunnel unter dem Gesichtspunkt der Tatsache, dass der Datenverkehr nicht verschlüsselt ist, unsicher ist, dies kann jedoch mithilfe von IPsec over leicht gelöst werden Dieser Artikel, es kam mir einfach und verständlich vor.

Ich verwende dieses Skript nun seit mehreren Wochen, um eine Verbindung zu einem Arbeits-PC herzustellen, und habe keine Probleme festgestellt. Praktisch im Hinblick auf das Einstellen und Vergessen.

Vielleicht haben Sie Kommentare und Vorschläge, ich freue mich über Ihr Feedback.

Danke!

Source: habr.com

Kommentar hinzufügen