Tunel VPN direct între computere prin NAT-urile furnizorilor (fără VPS, folosind serverul STUN și Yandex.disk)

Extensie articole despre cum am reușit să organizez un tunel VPN direct între două computere situate în spatele furnizorilor NAT. Articolul anterior descria procesul de organizare a unei conexiuni cu ajutorul unui terț - un intermediar (un VPS închiriat care acționează ca un server STUN și un transmițător de date nod pentru conexiune). În acest articol vă voi spune cum m-am descurcat fără VPS, dar intermediarii au rămas și au fost serverul STUN și Yandex.Disk...
Tunel VPN direct între computere prin NAT-uri furnizorului (fără VPS, folosind serverul STUN și Yandex.disk)

Introducere

După ce am citit comentariile postării anterioare, mi-am dat seama că principalul dezavantaj al implementării a fost utilizarea unui intermediar - un terț (VPS) care a indicat parametrii actuali ai nodului, unde și cum să se conecteze. Luând în considerare recomandările de utilizare a acestui STUN (dintre care sunt multe) pentru a determina parametrii actuali de conectare. În primul rând, am decis să folosesc TCPDump pentru a vedea conținutul pachetelor atunci când serverul STUN lucra cu clienții și primea conținut complet ilizibil. Căutând pe Google protocolul pe care l-am întâlnit articol care descrie protocolul. Mi-am dat seama că nu pot implementa singur o solicitare către serverul STUN și am pus ideea într-o „cutie îndepărtată”.

Теория

Recent, a trebuit să instalez serverul STUN pe Debian din pachet

# apt install stun-server

iar în dependențe am văzut pachetul stun-client, dar cumva nu i-am acordat atenție. Dar mai târziu mi-am amintit de pachetul stun-client și am decis să-mi dau seama cum funcționează, după ce am căutat pe Google pe Yandex:

# apt install stun-client
# stun stun.ekiga.net -p 21234 -v

Ca raspuns am primit:

Versiunea client STUN 0.97
S-a deschis portul 21234 cu fd 3
S-a deschis portul 21235 cu fd 4
Codificarea mesajului stun:
Codificare ChangeRequest: 0

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 4

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 2

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Mesaj de aturizare primit: 92 de octeți
MappedAddress = <IP-ul meu>:2885
Adresă sursă = 216.93.246.18:3478
Adresă schimbată = 216.93.246.17:3479
Atribut necunoscut: 32800
ServerName = Vovida.org 0.98-CPC
Mesajul primit de tip 257 id=1
Codificarea mesajului stun:
Codificare ChangeRequest: 0

Urmează să trimită mesajul len 28 la 216.93.246.17:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 4

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 2

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 0

Urmează să trimit mesajul len 28 către <IP-ul meu>:2885
Mesaj de aturizare primit: 28 de octeți
Solicitare de schimbare = 0
Mesajul primit de tip 1 id=11
Codificarea mesajului stun:
Codificare ChangeRequest: 0

Urmează să trimită mesajul len 28 la 216.93.246.17:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 4

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 2

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Mesaj de aturizare primit: 92 de octeți
MappedAddress = <IP-ul meu>:2885
Adresă sursă = 216.93.246.17:3479
Adresă schimbată = 216.93.246.18:3478
Atribut necunoscut: 32800
ServerName = Vovida.org 0.98-CPC
Mesajul primit de tip 257 id=10
Codificarea mesajului stun:
Codificare ChangeRequest: 4

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 2

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 4

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 2

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 4

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 2

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 4

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 2

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 4

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
Codificarea mesajului stun:
Codificare ChangeRequest: 2

Urmează să trimită mesajul len 28 la 216.93.246.18:3478
testul I = 1
testul II = 0
testul III = 0
testul I(2) = 1
este nat = 1
IP mapat același = 1
ac de păr = 1
port de conservare = 0
Primar: cartografiere independentă, filtru dependent de port, port aleatoriu, ac de păr
Valoarea returnată este 0x000006

Șir cu valoare

MappedAddress = <IP-ul meu>:2885

exact ce ai nevoie! A afișat starea curentă a conexiunii pe portul local UDP 21234. Dar aceasta este doar jumătate din luptă, a apărut întrebarea cum să transferați aceste date către gazda de la distanță și să organizați o conexiune VPN. Folosind protocolul de e-mail, sau poate Telegram?! Există multe opțiuni și am decis să folosesc Yandex.disk, de când am dat peste articol despre lucrul Curl prin WebDav cu Yandex.disk. După ce m-am gândit la implementare, am venit cu următoarea schemă:

  1. Semnalează că nodurile sunt gata să stabilească o conexiune prin prezența unui anumit fișier cu un marcaj de timp pe Yandex.disk;
  2. Dacă nodurile sunt gata, atunci primiți parametrii actuali de la serverul STUN;
  3. Încărcați setările curente pe Yandex.disk;
  4. Verificați prezența și citiți parametrii unui nod la distanță dintr-un fișier de pe Yandex.disk;
  5. Stabilirea unei conexiuni cu o gazdă la distanță folosind OpenVPN.

Practică

După ce m-am gândit puțin, ținând cont de experiența ultimului articol, am scris rapid un scenariu. Noi vom avea nevoie:

# apt install openvpn stun-client curl 

Scenariul în sine:

versiunea originala

# 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

Pentru ca scriptul să funcționeze, aveți nevoie de:

  1. Copiați în clipboard și inserați în editor, de exemplu:
    # nano vpn8.sh 
  2. specificați numele de utilizator și parola pentru Yandex.disk.
  3. în câmpul „—ifconfig 10.45.54.(1 sau 2) 255.255.255.252” specificați adresa IP internă a interfeței
  4. crea cheie secreta comanda:
    # openvpn --genkey --secret secret.key 
  5. faceți scriptul executabil:
    # chmod +x vpn8.sh
  6. rulați scriptul:
    # ./vpn8.sh nZbVGBuX5dtturD

    unde nZbVGBuX5dtturD este ID-ul de conexiune generat aici

Pe nodul de la distanță, faceți totul la fel, cu excepția generarii secret.key și ID-ul conexiunii, acestea trebuie să fie identice.

Versiune actualizată (ora trebuie să fie sincronizată pentru o funcționare corectă):

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

Pentru ca scriptul să funcționeze, aveți nevoie de:

  1. Copiați în clipboard și inserați în editor, de exemplu:
    # nano vpn10.sh 
  2. indicați autentificarea (linia a 2-a) și parola pentru Yandex.disk (linia a 3-a).
  3. specificați adresa IP internă a tunelului (linia a 4-a).
  4. faceți scriptul executabil:
    # chmod +x vpn10.sh
  5. rulați scriptul:
    # ./vpn10.sh nZbVGBuX5dtturD

    unde nZbVGBuX5dtturD este ID-ul de conexiune generat aici

Pe nodul la distanță, faceți același lucru, specificați adresa IP internă corespunzătoare a tunelului și ID-ul conexiunii.

Pentru a rula automat scriptul atunci când este pornit, folosesc comanda „nohup /<calea către script>/vpn10.sh nZbVGBuX5dtturD > /var/log/vpn10.log 2>/dev/null &” conținută în fișierul /etc/ rc.local

Concluzie

Scriptul funcționează, testat pe Ubuntu (18.04, 19.10, 20.04) și Debian 9. Puteți folosi orice alt serviciu ca transmițător, dar pentru experiență am folosit Yandex.disk.
În timpul experimentelor, s-a descoperit că unele tipuri de furnizori NAT nu permit stabilirea unei conexiuni. În principal de la operatorii de telefonie mobilă unde torrentele sunt blocate.

Plănuiesc să mă îmbunătățesc în ceea ce privește:

  • Generarea automată a secret.key de fiecare dată când porniți, criptați și copiați pe Yandex.disk pentru transfer pe un nod la distanță (ținând cont în versiunea actualizată)
  • Alocarea automată a adreselor IP ale interfețelor
  • Criptarea datelor înainte de a le încărca pe Yandex.disk
  • Optimizarea codului

Să fie IPv6 în fiecare casă!

Actualizat! Cele mai recente fișiere și pachetul DEB aici - yandex.disc

Sursa: www.habr.com

Adauga un comentariu