Simpleng UDP hole punching gamit ang isang IPIP tunnel bilang isang halimbawa

Magandang araw!

Sa artikulong ito gusto kong sabihin sa iyo kung paano ko ipinatupad (isa pa) isang Bash script para sa pagkonekta ng dalawang computer na matatagpuan sa likod ng NAT gamit ang UDP hole punching technology gamit ang Ubuntu/Debian OS bilang isang halimbawa.

Ang pagtatatag ng koneksyon ay binubuo ng ilang hakbang:

  1. Pagsisimula ng isang node at naghihintay para sa remote na node na maging handa;
  2. Pagtukoy sa panlabas na IP address at UDP port;
  3. Paglilipat ng panlabas na IP address at UDP port sa isang malayuang host;
  4. Pagkuha ng panlabas na IP address at UDP port mula sa isang malayuang host;
  5. Organisasyon ng isang IPIP tunnel;
  6. Pagsubaybay sa koneksyon;
  7. Kung nawala ang koneksyon, tanggalin ang IPIP tunnel.

Nag-isip ako nang mahabang panahon at iniisip pa rin kung ano ang maaaring magamit upang makipagpalitan ng data sa pagitan ng mga node, ang pinakasimple at pinakamabilis para sa akin sa sandaling ito ay gumagana sa pamamagitan ng Yandex.disk.

  • Una, ito ay madaling gamitin - kailangan mo ng 3 aksyon: lumikha, magbasa, magtanggal. Sa curl ito ay:
    Lumikha:

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

    Basahin:

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

    Tanggalin:

    curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder
  • Pangalawa, madaling i-install:
    apt install curl

Upang matukoy ang panlabas na IP address at UDP port, gamitin ang stun-client command:

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

Pag-install gamit ang command:

apt install stun-client

Upang ayusin ang isang tunnel, ginagamit ang karaniwang mga tool sa OS mula sa iproute2 package. Umiiral maraming lagusan na maaaring itaas gamit ang karaniwang paraan (L2TPv3, GRE, atbp.), ngunit pinili ko ang IPIP dahil lumilikha ito ng kaunting karagdagang pagkarga sa system. Sinubukan ko ang L2TPv3 sa UDP at nabigo ako, bumaba ang bilis ng 10 beses, ngunit ito ay maaaring iba't ibang mga paghihigpit na nauugnay sa mga provider o iba pa. Dahil ang IPIP tunnel ay tumatakbo sa IP level, ang FOU tunnel ay ginagamit para gumana sa UDP port level. Upang ayusin ang isang IPIP tunnel kailangan mo:

β€” i-load ang FOU module:

modprobe fou

β€” makinig sa lokal na port:

ip fou add port $localport ipproto 4

- lumikha ng isang tunel:

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

β€” itaas ang interface ng tunnel:

ip link set up dev fou$name

β€” magtalaga ng mga panloob na lokal at panloob na malalayong IP address ng tunel:

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

Magtanggal ng tunnel:

ip link del dev fou$name

ip fou del port $localport

Ang tunnel state ay sinusubaybayan sa pamamagitan ng pana-panahong pag-ping sa panloob na IP address ng remote node tunnel na may utos:

ping -c 1 $peerip -s 0

Ang panaka-nakang ping ay kailangan lalo na upang mapanatili ang channel, kung hindi, kapag ang tunnel ay idle, ang mga NAT table sa mga router ay maaaring i-clear at pagkatapos ay masira ang koneksyon.

Kung mawala ang ping, ang IPIP tunnel ay tatanggalin at maghihintay para sa pagiging handa mula sa remote host.

Ang script mismo:

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

Mga variable username, password ΠΈ folder dapat pareho sa magkabilang panig, ngunit intip - iba, halimbawa: 10.0.0.1 at 10.0.0.2. Ang oras sa mga node ay dapat na naka-synchronize. Maaari mong patakbuhin ang script tulad nito:

nohup script.sh &

Nais kong iguhit ang iyong pansin sa katotohanan na ang IPIP tunnel ay hindi ligtas mula sa punto ng view ng katotohanan na ang trapiko ay hindi naka-encrypt, ngunit ito ay madaling malutas gamit ang IPsec over artikulong ito, tila simple at naiintindihan ko.

Ilang linggo ko nang ginagamit ang script na ito para kumonekta sa isang work PC at wala akong napansing anumang problema. Maginhawa sa mga tuntunin ng pagtatakda nito at pagkalimot nito.

Marahil ay magkakaroon ka ng mga komento at mungkahi, ikalulugod kong makinig.

Salamat sa iyo!

Pinagmulan: www.habr.com

Magdagdag ng komento