ProHoster > Blog > uprava > Izravni VPN tunel između računala putem NAT-ova pružatelja (bez VPS-a, koristeći STUN poslužitelj i Yandex.disk)
Izravni VPN tunel između računala putem NAT-ova pružatelja (bez VPS-a, koristeći STUN poslužitelj i Yandex.disk)
Nastavak Članak o tome kako sam uspio organizirati izravni VPN tunel između dva računala smještena iza NAT providera. U prethodnom članku opisan je proces organiziranja veze uz pomoć treće strane - posrednika (iznajmljeni VPS koji djeluje kao nešto poput STUN servera i node data transmitera za vezu). U ovom članku ću vam reći kako sam uspio bez VPS-a, ali posrednici su ostali i to su STUN server i Yandex.Disk...
Uvod
Nakon što sam pročitao komentare prethodnog posta, shvatio sam da je glavni nedostatak implementacije korištenje posrednika - treće strane (VPS) koji je ukazivao na trenutne parametre čvora, gdje i kako se spojiti. Uzimajući u obzir preporuke za korištenje ovog STUN-a (kojih ima jako puno) za određivanje trenutnih parametara veze. Prije svega, odlučio sam koristiti TCPDump za pregled sadržaja paketa kada je STUN poslužitelj radio s klijentima i primio potpuno nečitljiv sadržaj. Guglajući protokol na koji sam naišao članak koji opisuje protokol. Shvatio sam da ne mogu sam implementirati zahtjev prema STUN serveru i stavio sam ideju u "daleku kutiju".
teorija
Nedavno sam morao instalirati STUN poslužitelj na Debianu iz paketa
# apt install stun-server
i u ovisnostima sam vidio paket stun-client, ali nekako nisam obraćao pozornost na njega. Ali kasnije sam se sjetio paketa stun-client i odlučio shvatiti kako funkcionira, nakon guglanja i pretraživanja na Yandexu dobio sam:
STUN klijent verzija 0.97
Otvoren port 21234 s fd 3
Otvoren port 21235 s fd 4
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 0
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 4
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 2
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Primljena poruka o omamljivanju: 92 bajta
MappedAddress = <Moj IP>:2885
Izvorna adresa = 216.93.246.18:3478
Promijenjena adresa = 216.93.246.17:3479
Nepoznati atribut: 32800
Naziv poslužitelja = Vovida.org 0.98-CPC
Primljena poruka tipa 257 id=1
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 0
Upravo ću poslati poruku od len 28 na 216.93.246.17:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 4
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 2
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 0
Upravo ću poslati poruku len 28 na <My IP>:2885
Primljena poruka o omamljivanju: 28 bajta
Zahtjev za promjenu = 0
Primljena poruka tipa 1 id=11
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 0
Upravo ću poslati poruku od len 28 na 216.93.246.17:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 4
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 2
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Primljena poruka o omamljivanju: 92 bajta
MappedAddress = <Moj IP>:2885
Izvorna adresa = 216.93.246.17:3479
Promijenjena adresa = 216.93.246.18:3478
Nepoznati atribut: 32800
Naziv poslužitelja = Vovida.org 0.98-CPC
Primljena poruka tipa 257 id=10
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 4
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 2
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 4
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 2
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 4
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 2
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 4
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 2
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 4
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Encoding ChangeRequest: 2
Upravo ću poslati poruku od len 28 na 216.93.246.18:3478
test I = 1
test II = 0
test III = 0
test I(2) = 1
je nat = 1
mapirani IP isti = 1
ukosnica = 1
port čuvara = 0
Primarno: neovisno mapiranje, filtar ovisan o portu, nasumični port, bit će ukosnica
Povratna vrijednost je 0x000006
Niz s vrijednošću
MappedAddress = <Moj IP>:2885
upravo ono što vam treba! Prikazivao je trenutni status veze na lokalnom UDP portu 21234. Ali to je samo pola bitke, postavilo se pitanje kako te podatke prenijeti na udaljeni host i organizirati VPN vezu. Koristeći mail protokol, ili možda Telegram?! Postoji mnogo opcija i odlučio sam koristiti Yandex.disk, budući da sam naišao članak o radu Curla putem WebDava s Yandex.diskom. Nakon razmišljanja o implementaciji, došao sam do sljedeće sheme:
Signalizirajte da su čvorovi spremni uspostaviti vezu prisutnošću određene datoteke s vremenskom oznakom na Yandex.disku;
Ako su čvorovi spremni, tada primajte trenutne parametre sa STUN poslužitelja;
Prenesite trenutne postavke na Yandex.disk;
Provjerite prisutnost i očitajte parametre udaljenog čvora iz datoteke na Yandex.disku;
Uspostavljanje veze s udaljenim hostom pomoću OpenVPN-a.
Praksa
Nakon malo razmišljanja, uzimajući u obzir iskustvo prošlog članka, brzo sam napisao scenarij. Mi ćemo trebati:
# apt install openvpn stun-client curl
Sama skripta:
Originalna verzija
# cat vpn8.sh
#!/bin/bash
######################## Задаем цветной текст ###
WARN='33[37;1;41m' #
END='33[0m' #
RED='33[0;31m' # ${RED} #
GREEN='33[0;32m' # ${GREEN} #
#################################################
####################### Проверяем наличие необходымих приложений #########################################################
al="echo readlink dirname grep awk md5sum shuf nc curl sleep openvpn cat stun"
ch=0
for i in $al; do which $i > /dev/null || echo -e "${WARN}Для работы необходим $i ${END}"; which $i > /dev/null || ch=1; done
if (( $ch > 0 )); then echo -e "${WARN}Ой, отсутствуют необходимые для корректной работы приложения${END}"; exit; fi
#######################################################################################################################
if [[ $1 == '' ]]; then echo -e "${WARN}Введите идентификатор соединения (любое уникальное слово, должно быть одинаковое с двух сторон!) ${END} t
${GREEN}Для запуска в автоматическом режиме при включении компьютера можно прописать в /etc/rc.local строку nohup /<путь к файлу>/vpn8.sh > /var/log/vpn8.log 2>/dev/hull & ${END}"; exit; fi
ABSOLUTE_FILENAME=`readlink -f "$0"` # полный путь до скрипта
DIR=`dirname "$ABSOLUTE_FILENAME"` # каталог в котором лежит скрипт
############################### Проверка наличия секретного ключа ##################################
key="$DIR/secret.key"
if [ ! -f "$key" ]; then
echo -e "${WARN}Секретный ключ VPN-соединения не найден, для генерации ключа выполните:
openvpn --genkey --secret secret.key Внимание: ключ используется для авторизации и должен
быть одинаковым с двух сторон!!!${END}
# ls -l secret.key
-rw------- 1 root root 637 ноя 27 11:12 secret.key
# chmod 600 secret.key";
exit;
fi
########################################################################################################################
ABSOLUTE_FILENAME=`readlink -f "$0"` # полный путь до скрипта
DIR=`dirname "$ABSOLUTE_FILENAME"` # каталог в котором лежит скрипт
name=$(uname -n | md5sum | awk '{print $1}')
vpn=$(echo $1 | md5sum | awk '{print $1}')
stun="stun.ekiga.net" # STUN сервер
username="Yandex" # Логин от Яндекс.диска
password="Password" # Пароль от Яндекс.диска
localport=`shuf -i 20000-65000 -n 1` # генерация локального порта
echo "$(date) Создаю папку на Яндекс.диске"
curl -X MKCOL --user "${username}:${password}" https://webdav.yandex.ru/vpn-$vpn
echo "$(date) Очищаю папку от всякого мусора"
for i in `curl --silent --user "$username:$password" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></n/g' | grep "d:displayname" | sed 's/d:displayname//g' | sed 's/>//g' | sed 's/<//' | sed 's////g' | grep -v $(date +%Y-%m-%d-%H-%M)`; do
echo "$(date) Delete: $i"
curl -X DELETE --user "${username}:${password}" https://webdav.yandex.ru/vpn-$vpn/$i
done
until [ $c ];do
until [[ $b ]]; do
echo "$(date) Проверяю папку"
date=`date +%Y-%m-%d-%H-%M`
mydata=`curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></>n</g' | grep $name | grep $date | grep "d:displayname"`
if [[ -z $mydata ]]; then
echo "$(date) Файл готовности создан"
echo "$date" > "/tmp/$date-$name-ready.txt"
curl -T "/tmp/$date-$name-ready.txt" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$date-$name-ready.txt
else
echo "$(date) Файл готовности уже существует - $date"
fi
remote=`curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></>n</g' | grep -v $name | grep $date | grep "d:displayname"`
if [[ -z $remote ]]; then
echo -e "$(date) ${RED} Удаленный узел не готов ${END}"
echo "$(date) Жду"
sleep 20
else
echo -e "$(date) ${GREEN} Удаленный узел готов ${END}"
b=1
a=''
fi
done
until [ $a ]; do
echo "$(date) Подключение и получение данных от STUN сервера: $stun"
mydata=`stun $stun -p $localport -v 2>&1 | grep MappedAddress | sort | uniq`
echo -e "$(date) ${GREEN}Мои данные соединения: $mydata${END}"
echo "$mydata" > "$DIR/mydata"
echo "$(date) Загрузка данных на Яндекс.диск"
curl -T "$DIR/mydata" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$name.txt
echo "$(date) Получение файла данных удаленного узла"
filename=$(curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></n/g' | grep "d:displayname>" | grep "txt" | grep -v "$name" | grep -v "ready" | sed 's|.*d:displayname>||' | sed 's/</ /g' | awk '{print $1}')
echo "$(date) Чтение файла данных удаленного узла: $filename"
address=$(curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$filename | sort | uniq | head -n1 | sed 's/:/ /g')
echo "$(date) Определение IP-адреса и порта"
ip=$(echo "$address" | awk '{print $3}')
port=$(echo "$address" | awk '{print $4}')
if [[ -n "$ip" && -n "$port" ]]; then
echo -e "$(date) ${GREEN} Соединение $ip $port ${END}"
openvpn --remote $ip --rport $port --lport $localport
--proto udp --dev tap --float --auth-nocache --verb 3 --mute 20
--ifconfig 10.45.54.2 255.255.255.252
--secret "$DIR/secret.key"
--auth SHA256 --cipher AES-256-CBC
--ncp-disable --ping 10 --ping-exit 30
--comp-lzo yes
echo -e "$(date) ${WARN} Соединение разорвано${END}"
a=1
b=''
else
a=1
b=''
fi
done
done
Da bi skripta radila potrebno vam je:
Kopirajte u međuspremnik i zalijepite u uređivač, na primjer:
# nano vpn8.sh
navedite korisničko ime i lozinku za Yandex.disk.
u polju "—ifconfig 10.45.54.(1 ili 2) 255.255.255.252" navedite internu IP adresu sučelja
Na udaljenom čvoru učinite isto, navedite odgovarajuću internu IP adresu tunela i ID veze.
Za automatsko pokretanje skripte kada je uključena, koristim naredbu “nohup /<put do skripte>/vpn10.sh nZbVGBuX5dtturD > /var/log/vpn10.log 2>/dev/null &” koja se nalazi u datoteci /etc/ rc.lokalni
Zaključak
Skripta radi, testirano na Ubuntu (18.04, 19.10, 20.04) i Debianu 9. Možete koristiti bilo koji drugi servis kao odašiljač, ali za iskustvo sam koristio Yandex.disk.
Tijekom eksperimenata otkriveno je da neke vrste NAT providera ne dopuštaju uspostavljanje veze. Uglavnom od mobilnih operatera kod kojih su torrenti blokirani.
Planiram se poboljšati u smislu:
Automatsko generiranje secret.key svaki put kada pokrenete, šifrirate i kopirate na Yandex.disk za prijenos na udaljeni čvor (uzeti u obzir u ažuriranoj verziji)
Automatsko dodjeljivanje IP adresa sučelja
Šifriranje podataka prije učitavanja na Yandex.disk
Optimizacija koda
Neka IPv6 bude u svakom domu!
Ažurirano! Najnovije datoteke i DEB paket ovdje - yandex.disk