ProHoster > Блог > Administracija > Direktan VPN tunel između računara preko NAT-ova provajdera (bez VPS-a, koristeći STUN server i Yandex.disk)
Direktan VPN tunel između računara preko NAT-ova provajdera (bez VPS-a, koristeći STUN server i Yandex.disk)
Nastavak članci o tome kako sam uspio organizirati direktan VPN tunel između dva kompjutera smještena iza NAT provajdera. U prethodnom članku opisan je proces organizacije veze uz pomoć treće strane - posrednika (iznajmljeni VPS koji djeluje kao STUN server i čvorni predajnik podataka za vezu). U ovom članku ću vam reći kako sam se snašao bez VPS-a, ali su posrednici ostali a to su bili 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 povezati. Uzimajući u obzir preporuke za korištenje ovog STUN (kojih ima dosta) za određivanje trenutnih parametara veze. Pre svega, odlučio sam da koristim TCPDump da pogledam sadržaj paketa kada STUN server radi sa klijentima i dobija potpuno nečitljiv sadržaj. Guglam protokol na koji sam naišao članak koji opisuje protokol. Shvatio sam da ne mogu sam implementirati zahtjev na STUN server i stavio sam ideju u „udaljenu kutiju“.
Teorija
Nedavno sam iz paketa morao instalirati STUN server na Debian
# apt install stun-server
a u zavisnostima sam vidio paket stun-client, ali nekako nisam obraćao pažnju na njega. Ali kasnije sam se sjetio paketa stun-client i odlučio da shvatim kako funkcionira, nakon guglanja i pretraživanja u Yandexu dobio sam:
STUN klijent verzija 0.97
Otvoren port 21234 sa fd 3
Otvoren port 21235 sa fd 4
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 0
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 4
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 2
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Primljena omamljujuća poruka: 92 bajta
Mapirana adresa = <Moj IP>:2885
SourceAddress = 216.93.246.18:3478
Promijenjena Adresa = 216.93.246.17:3479
Nepoznati atribut: 32800
Ime servera = Vovida.org 0.98-CPC
Primljena poruka tipa 257 id=1
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 0
Spremam se za slanje poruke od len 28 na 216.93.246.17:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 4
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 2
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 0
Sprema se slanje poruke od len 28 na <Moj IP>:2885
Primljena omamljujuća poruka: 28 bajta
Zahtjev za promjenu = 0
Primljena poruka tipa 1 id=11
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 0
Spremam se za slanje poruke od len 28 na 216.93.246.17:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 4
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 2
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Primljena omamljujuća poruka: 92 bajta
Mapirana adresa = <Moj IP>:2885
SourceAddress = 216.93.246.17:3479
Promijenjena Adresa = 216.93.246.18:3478
Nepoznati atribut: 32800
Ime servera = Vovida.org 0.98-CPC
Primljena poruka tipa 257 id=10
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 4
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 2
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 4
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 2
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 4
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 2
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 4
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 2
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 4
Spremam se za slanje poruke od len 28 na 216.93.246.18:3478
Kodiranje ošamućene poruke:
Zahtjev za promjenu kodiranja: 2
Spremam se za slanje poruke 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 za čuvanje = 0
Primarno: Nezavisno mapiranje, Filter zavisan od porta, nasumični port, ukosnica
Povratna vrijednost je 0x000006
String sa vrijednošću
Mapirana adresa = <Moj IP>:2885
upravo ono što ti treba! Prikazao je trenutni status veze na lokalnom UDP portu 21234. Ali ovo je samo pola bitke, postavlja se pitanje kako prenijeti te podatke na udaljeni host i organizirati VPN vezu. Koristeći mail protokol, ili možda Telegram?! Postoji mnogo opcija i odlučio sam da koristim Yandex.disk, pošto sam naišao članak o radu Curl putem WebDav-a s Yandex.disk. Nakon razmišljanja o implementaciji, došao sam do sljedeće šeme:
Signalizirajte da su čvorovi spremni za uspostavljanje veze prisustvom određene datoteke sa vremenskom oznakom na Yandex.disk;
Ako su čvorovi spremni, primajte trenutne parametre od STUN servera;
Otpremite trenutne postavke na Yandex.disk;
Provjerite prisutnost i pročitajte parametre udaljenog čvora iz datoteke na Yandex.disk;
Uspostavljanje veze sa udaljenim hostom koristeći OpenVPN.
Praksa
Nakon malo razmišljanja, uzimajući u obzir iskustvo iz prošlog članka, brzo sam napisao scenarij. trebat će nam:
# 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 funkcionisala potrebno vam je:
Kopirajte u međuspremnik i zalijepite u editor, 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 interfejsa
Na udaljenom čvoru uradite isto, navedite odgovarajuću internu IP adresu tunela i ID veze.
Za automatsko pokretanje skripte kada je uključen, koristim naredbu “nohup /<put do skripte>/vpn10.sh nZbVGBuX5dtturD > /var/log/vpn10.log 2>/dev/null &” sadržanu u datoteci /etc/ rc.local
zaključak
Skripta radi, testirana 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.
Tokom eksperimenata je otkriveno da neki tipovi NAT provajdera ne dozvoljavaju uspostavljanje veze. Uglavnom od mobilnih operatera kod kojih su torrenti blokirani.
Planiram da se poboljšam u smislu:
Automatsko generiranje secret.key svaki put kada pokrenete, šifrirajte i kopirajte na Yandex.disk za prijenos na udaljeni čvor (uzimajući u obzir u ažuriranoj verziji)
Automatsko dodeljivanje IP adresa interfejsima
Šifriranje podataka prije učitavanja na Yandex.disk
Optimizacija koda
Neka IPv6 bude u svakom domu!
Ažurirano! Najnoviji fajlovi i DEB paket ovdje - yandex.disk