God tid på dagen!
I denne artikkelen vil jeg fortelle deg hvordan jeg implementerte () скрипт на Bash для соединения двух компьютеров, находящимися за NAT, с использованием технологии UDP hole punching на примере ОС Ubuntu/Debian.
Etablering av en forbindelse består av flere trinn:
- Starte en node og vente på at den eksterne noden skal være klar;
- Bestemme den eksterne IP-adressen og UDP-porten;
- Overføre en ekstern IP-adresse og UDP-port til en ekstern vert;
- Innhenting av en ekstern IP-adresse og UDP-port fra en ekstern vert;
- Organisering av en IPIP-tunnel;
- Tilkobling overvåking;
- Hvis tilkoblingen blir brutt, slett IPIP-tunnelen.
Jeg tenkte lenge og tror fortsatt hva som kan brukes til å utveksle data mellom noder, det enkleste og raskeste for meg for øyeblikket fungerer gjennom Yandex.disk.
- For det første er det enkelt å bruke - du trenger 3 handlinger: opprette, lese, slette. Med krøll er dette:
Skape:curl -s -X MKCOL --user "$usename:$password" https://webdav.yandex.ru/$folderLese:
curl -s --user "$usename:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/$folderSlett:
curl -s -X DELETE --user "$usename:$password" https://webdav.yandex.ru/$folder - For det andre er det enkelt å installere:
apt install curl
For å finne den eksterne IP-adressen og UDP-porten, bruk stun-client-kommandoen:
stun stun.sipnet.ru -v -p $1 2>&1 | grep "MappedAddress"Installasjon med kommando:
apt install stun-clientFor å organisere en tunnel brukes standard OS-verktøy fra iproute2-pakken. Finnes som kan heves ved bruk av standardmidler (L2TPv3, GRE, etc.), men jeg valgte IPIP fordi det skaper minimal ekstra belastning på systemet. Jeg prøvde L2TPv3 over UDP og ble skuffet, hastigheten falt 10 ganger, men dette kan være ulike restriksjoner knyttet til leverandører eller noe annet. Siden IPIP-tunnelen opererer på IP-nivå, brukes FOU-tunnelen til å operere på UDP-portnivå. For å organisere en IPIP-tunnel trenger du:
— last inn FOU-modulen:
modprobe fou— lytt til lokal port:
ip fou add port $localport ipproto 4— lag en tunnel:
ip link add name fou$name type ipip remote $remoteip local $localip encap fou encap-sport $localport encap-dport $remoteport— heve tunnelgrensesnittet:
ip link set up dev fou$name- tilordne interne lokale og interne eksterne IP-adresser til tunnelen:
ip addr add $intIP peer $peerip dev fou$nameSlett en tunnel:
ip link del dev fou$nameip fou del port $localportTunneltilstanden overvåkes ved å periodisk pinge den interne IP-adressen til den eksterne nodetunnelen med kommandoen:
ping -c 1 $peerip -s 0Periodisk ping er nødvendig først og fremst for å opprettholde kanalen, ellers, når tunnelen er inaktiv, kan NAT-tabellene på ruterne bli slettet, og da vil forbindelsen bli brutt.
Hvis pinget forsvinner, slettes IPIP-tunnelen og venter på beredskap fra den eksterne verten.
Selve manuset:
#!/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 0Variabler brukernavn, passord и mappe skal være lik på begge sider, men tips - forskjellige, for eksempel: 10.0.0.1 og 10.0.0.2. Tiden på nodene må synkroniseres. Du kan kjøre skriptet slik:
nohup script.sh &Jeg vil gjøre deg oppmerksom på at IPIP-tunnelen er utrygg med tanke på at trafikken ikke er kryptert, men dette kan enkelt løses ved hjelp av IPsec over , det virket enkelt og forståelig for meg.
Jeg har brukt dette skriptet for å koble til en arbeids-PC i flere uker nå og har ikke merket noen problemer. Praktisk med tanke på å sette den og glemme den.
Kanskje du vil ha kommentarer og forslag, jeg vil gjerne høre.
Takk for din oppmerksomhet!
Kilde: www.habr.com
