Ekstansyon atik sou kijan mwen te reyisi òganize yon dirèk VPN- yon tinèl ant de òdinatè ki sitiye dèyè NAT founisè yo. Atik anvan an te dekri pwosesis pou etabli yon koneksyon lè l sèvi avèk yon twazyèm pati - yon entèmedyè (yon moun lwe VPS (Sa a aji kòm yon sòt de sèvè STUN ak transmetè done pou konekte nœuds yo.) Nan atik sa a, m ap di w kijan m te debouye m san yon VPS, men entèmedyè yo te rete: sèvè STUN nan ak Yandex.Disk.
Entwodiksyon
Apre ou fin li kòmantè yo nan pòs anvan an, mwen reyalize ke dezavantaj prensipal la nan aplikasyon an te itilize nan yon entèmedyè - yon twazyèm pati (VPS) ki endike paramèt aktyèl yo nan ne a, ki kote ak ki jan yo konekte. Lè nou konsidere rekòmandasyon yo pou itilize STUN sa a (ki genyen anpil) pou detèmine paramèt koneksyon aktyèl yo. Premye a tout, mwen deside sèvi ak TCPDump gade sa ki nan pake yo lè sèvè a STUN t ap travay ak kliyan epi li te resevwa kontni konplètman lizib. Googling pwotokòl mwen te rankontre atik ki dekri pwotokòl la. Mwen reyalize ke mwen pa t 'kapab aplike yon demann nan sèvè a STUN poukont mwen epi mete lide a nan yon "bwat byen lwen".
Teyori
Dènyèman, mwen te oblije enstale yon sèvè STUN sou Debian soti nan pake a
# apt install stun-serverak nan depandans yo mwen te wè pake a stun-client, men yon jan kanmenm mwen pa t 'peye atansyon sou li. Men, pita mwen sonje sou pake a stun-client ak deside konnen ki jan li fonksyone, apre googling ak rechèch nan Yandex mwen te resevwa:
# apt install stun-client
# stun stun.ekiga.net -p 21234 -v
Nan repons mwen te resevwa:
STUN kliyan vèsyon 0.97
Louvri pò 21234 ak fd 3
Louvri pò 21235 ak fd 4
Kodaj mesaj stun:
Kodaj Chanjman Demann: 0Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 4Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 2Pou voye msj len 28 a 216.93.246.18:3478
Resevwa mesaj stun: 92 bytes
MappedAddress = <IP mwen an>:2885
Adrès Sous = 216.93.246.18:3478
Adrès Chanje = 216.93.246.17:3479
Enkoni atribi: 32800
ServerName = Vovida.org 0.98-CPC
Resevwa mesaj kalite 257 id=1
Kodaj mesaj stun:
Kodaj Chanjman Demann: 0Pou voye msj len 28 a 216.93.246.17:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 4Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 2Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 0Pou voye msj len 28 bay <IP mwen>:2885
Resevwa mesaj stun: 28 bytes
ChanjmanDemann = 0
Resevwa mesaj kalite 1 id=11
Kodaj mesaj stun:
Kodaj Chanjman Demann: 0Pou voye msj len 28 a 216.93.246.17:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 4Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 2Pou voye msj len 28 a 216.93.246.18:3478
Resevwa mesaj stun: 92 bytes
MappedAddress = <IP mwen an>:2885
Adrès Sous = 216.93.246.17:3479
Adrès Chanje = 216.93.246.18:3478
Enkoni atribi: 32800
ServerName = Vovida.org 0.98-CPC
Resevwa mesaj kalite 257 id=10
Kodaj mesaj stun:
Kodaj Chanjman Demann: 4Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 2Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 4Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 2Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 4Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 2Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 4Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 2Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 4Pou voye msj len 28 a 216.93.246.18:3478
Kodaj mesaj stun:
Kodaj Chanjman Demann: 2Pou voye msj len 28 a 216.93.246.18:3478
tès I = 1
tès II = 0
tès III = 0
tès I(2) = 1
se nat = 1
kat IP menm = 1
epengl = 1
pò prezèvatè = 0
Prensipal: Kat Endepandan, Filtè Port Depandan, pò o aza, pral epengl
Valè retounen se 0x000006
Chaîne ak valè
MappedAddress = <IP mwen an>:2885
jis sa ou bezwen! Li te montre estati aktyèl la pou koneksyon an sou pò UDP lokal 21234. Men, sa a se sèlman mwatye batay la, kesyon an leve sou ki jan yo transfere done sa yo nan lame a aleka epi òganize yon koneksyon VPN. Sèvi ak pwotokòl lapòs la, oswa petèt Telegram?! Gen anpil opsyon epi mwen deside sèvi ak Yandex.disk, depi mwen te vin atravè atik sou travay Curl atravè WebDav ak Yandex.disk. Apre reflechi sou aplikasyon an, mwen te vini ak konplo sa a:
- Siyal ke nœuds yo pare yo etabli yon koneksyon pa prezans nan yon dosye espesifik ak yon timestamp sou Yandex.disk;
- Si nœuds yo pare, Lè sa a, resevwa paramèt aktyèl nan sèvè STUN la;
- Voye anviwònman aktyèl yo nan Yandex.disk;
- Tcheke prezans ak li paramèt yon ne aleka nan yon dosye sou Yandex.disk;
- Etabli yon koneksyon ak yon lame aleka lè l sèvi avèk OpenVPN.
Pratike
Apre reflechi yon ti kras, pran an kont eksperyans nan dènye atik la, mwen byen vit ekri yon script. Nou pral bezwen:
# apt install openvpn stun-client curl Script nan tèt li:
Premye vèsyon
# 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
donePou script la travay ou bezwen:
- Kopi nan clipboard epi kole nan editè, pou egzanp:
# nano vpn8.sh - presize non itilizatè a ak modpas pou Yandex.disk.
- Nan chan "—ifconfig 10.45.54.(1 oubyen 2) 255.255.255.252" espesifye adrès IP entèn koòdone a.
- kreye sekrè.kle kòmandman:
# openvpn --genkey --secret secret.key - fè script la ègzekutabl:
# chmod +x vpn8.sh - kouri script la:
# ./vpn8.sh nZbVGBuX5dtturDkote nZbVGBuX5dtturD se ID koneksyon ki pwodui isit la
Sou ne a aleka, fè tout bagay menm eksepte pou jenere sekrè.key ak ID koneksyon, yo dwe idantik.
Mizajou vèsyon (tan dwe senkronize pou operasyon kòrèk):
cat vpn10.sh
#!/bin/bash
stuns="stun.sipnet.ru stun.ekiga.net" # Список STUN серверов через пробел
username=" Login " # Логин от Яндекс.диска
password=" Password " # Пароль от Яндекс.диска
intip="10.23.22.1" # IP-адрес внутреннего интерфейса
WARN='33[37;1;41m'
END='33[0m'
RED='33[0;31m'
GREEN='33[0;32m'
al="ip echo readlink dirname grep awk md5sum openssl sha256sum shuf 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 /<путь к файлу>/vpn10.sh > /var/log/vpn10.log 2>/dev/hull & ${END}"
exit
fi
ABSOLUTE_FILENAME=`readlink -f "$0"` # полный путь до скрипта
DIR=`dirname "$ABSOLUTE_FILENAME"` # каталог в котором лежит скрипт
key="$DIR/secret.key"
until [[ -n "$iftosrv" ]]
do
echo "$(date) Определяю сетевой интерфейс"; iftosrv=`ip route get 8.8.8.8 | head -n 1 | sed 's|.*dev ||' | awk '{print $1}'`
sleep 5
done
timedatectl
name=$(uname -n | md5sum | awk '{print $1}')
vpn=$(echo $1 | md5sum | awk '{print $1}')
echo "$(date) Создаю папку на Яндекс.диске"
curl -X MKCOL --user "${username}:${password}" https://webdav.yandex.ru/vpn-$vpn
echo "$(date) ID на диске: $vpn"
until [ $c ];do
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 -e "$(date)${RED} Удаляю старый файл: $i${END}"
curl -X DELETE --user "${username}:${password}" https://webdav.yandex.ru/vpn-$vpn/$i
done
echo "$(date) ID на диске: $vpn"
openvpn --genkey --secret "$key"
passwd=`echo "$vpn-tt" | sha256sum | awk '{print $1}'`
openssl AES-256-CBC -e -in "$key" -out "$DIR/file.enc" -k "$passwd" -base64
curl -T "$DIR/file.enc" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/key.enc
rm "$DIR"/file.enc
echo -e "$(date) ${GREEN}Фаза 1 - Получение готовности удаленного узла${END}"
go=3
localport=`shuf -i 20000-65000 -n 1` # генерация локального порта
start=''
remote=''
timeout1=''
nextcheck=''
timestart=''
until [[ $b ]]
do
echo "$(date) Проверяю папку"
date=`date +%s`
timeout1=60
echo "$(date) Создание файла готовности $date"
echo "$date" > "/tmp/ready-$date-$name.txt"
curl -T "/tmp/ready-$date-$name.txt" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/ready-$name.txt
readyfile=`curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></>n</g' | grep -v $name | grep "ready" | grep "d:displayname" | sed 's/<d:displayname>//g' | sed 's/</d:displayname>//g'`
if [[ -z $readyfile ]]
then
echo -e "$(date) ${RED} Удаленный узел не готов ${END}"
echo "$(date) Жду 60 секунд"
sleep $timeout1
else
remote=$(curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$readyfile)
echo -e "$(date) ${GREEN} Удаленный узел готов ${END}"
start=`curl --silent --user "${username}:${password}" -X PROPFIND -H "Depth: 1" https://webdav.yandex.ru/vpn-$vpn/ | sed 's/></>n</g' | grep "start" | grep "d:displayname" | sed 's/-/ /g' | awk '{print $2}'`
if [[ -z $start ]]
then
let nextcheck=$timeout1-$date+$remote
let timestart=$date+$timeout1-$nextcheck
go=$nextcheck
echo "$timestart" > "/tmp/start-$date-$name.txt"
curl -T "/tmp/start-$date-$name.txt" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/start-$date-$name.txt
else
echo "$(date) жду $go секунд"
sleep $go
b=1
a=''
fi
fi
done
echo -e "$(date) ${GREEN}Фаза 2 - Обмен данными и установка соединения${END}"
mydata=''
filename=''
address=''
myip=''
ip=''
port=''
ex=0
until [ $a ]; do
until [[ -n "$mydata" ]]; do
k=`echo "$stuns" | wc -w`
x=1
z=`shuf -i 1-$k -n 1`
for st in $stuns; do
if [[ $x == $z ]]; then
stun=$st;
fi;
(( x++ ));
done
echo "$(date) Подключение и получение данных от STUN сервера: $stun"
sleep 5 && for pid in $(ps xa | grep "stun "$stun" 1 -p "$localport" -v" | grep -v grep | awk '{print $1}'); do kill $pid; done &
mydata=`stun "$stun" 1 -p "$localport" -v 2>&1 | grep "MappedAddress" | sort | uniq`
done
echo -e "$(date) ${GREEN}Мои данные соединения: $mydata${END}"
echo "$(date) Загрузка данных на Яндекс.диск"
echo "$mydata" > "$DIR/mydata"
echo "IntIP $intip" >> "$DIR/mydata"
curl -T "$DIR/mydata" --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$name-ipport.txt
rm "$DIR/mydata"
sleep 5
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 "ipport" | grep -v "$name" | sed 's|.*d:displayname>||' | sed 's/</ /g' | awk '{print $1}')
if [[ -n "$filename" ]]
then
echo "$(date) Чтение файла данных удаленного узла: $filename"
address=$(curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$filename | grep "MappedAddress" | head -n1 | sed 's/:/ /g')
intip2=$(curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/$filename | grep "IntIP" | head -n1 | awk '{print $2}')
echo "$(date) Определение IP-адреса и порта: $address $sesid2 $tunid2"
ip=$(echo "$address" | awk '{print $3}')
port=$(echo "$address" | awk '{print $4}')
myip=`ip route get "$ip" | head -n 1 | sed 's|.*src ||' | awk '{print $1}'`
if [[ -n "$ip" && -n "$port" && -n "$myip" && -n "$localport" ]];
then
echo -e "$(date) ${GREEN} Соединение $ip $port ${END}"
echo -e "`date` ${GREEN} $myip:$localport -> $ip:$port ${END}"
curl --silent --user "$username:$password" https://webdav.yandex.ru/vpn-$vpn/key.enc > "$DIR/secret.enc"
openssl AES-256-CBC -d -in "$DIR/secret.enc" -out "$key" -k "$passwd" -base64
chmod 600 "$key"
rm "$DIR/secret.enc"
openvpn --remote $ip --rport $port --lport $localport
--proto udp --dev tun --float --auth-nocache --verb 3 --mute 20
--ifconfig "$intip" "$intip2"
--secret "$key"
--auth SHA256 --cipher AES-256-CBC
--ncp-disable --ping 10 --ping-exit 20
--comp-lzo yes
a=1
b=''
fi
else
if (( $ex >= 5 ))
then
echo "$(date) Сброс"
a=1
b=''
fi
(( ex++ ))
sleep 5
fi
done
done
Pou script la travay ou bezwen:
- Kopi nan clipboard epi kole nan editè, pou egzanp:
# nano vpn10.sh - endike koneksyon an (2yèm liy) ak modpas pou Yandex.disk (3yèm liy).
- presize adrès IP entèn tinèl la (4yèm liy).
- fè script la ègzekutabl:
# chmod +x vpn10.sh - kouri script la:
# ./vpn10.sh nZbVGBuX5dtturDkote nZbVGBuX5dtturD se ID koneksyon ki pwodui isit la
Sou nòd aleka a, fè menm bagay la, presize entèn ki koresponn lan Adrès IP tinèl ak ID koneksyon.
Pou otorize script la lè yo limen, mwen sèvi ak lòd "nohup /<chemen script la>/vpn10.sh nZbVGBuX5dtturD> /var/log/vpn10.log 2>/dev/null &" ki nan fichye /etc/ rc.local
Konklizyon
Skript la fonksyone, li te teste. Ubuntu (18.04, 19.10, 20.04) ak Debian 9. Ou ka itilize nenpòt lòt sèvis kòm yon transmetè, men pou eksperyans lan mwen te itilize Yandex.Disk.
Pandan eksperyans yo, li te dekouvri ke kèk kalite founisè NAT pa pèmèt etabli yon koneksyon. Sitou soti nan operatè mobil kote torrent yo bloke.
Mwen planifye amelyore an tèm de:
- Otomatik jenerasyon secret.key chak fwa ou kòmanse, ankripte ak kopye nan Yandex.disk pou transfere nan yon ne aleka (Pran an kont nan vèsyon an mete ajou)
- Otomatik plasman nan adrès IP nan interfaces
- Chide done anvan ou telechaje sou Yandex.disk
- Optimizasyon Kòd
Se pou gen IPv6 nan chak kay!
Mizajou! Dènye dosye ak pake DEB isit la - yandex.disk
Sous: www.habr.com
