อุโมงค์ VPN โดยตรงระหว่างคอมพิวเตอร์ผ่านผู้ให้บริการ NATs (ไม่มี VPS โดยใช้เซิร์ฟเวอร์ STUN และ Yandex.disk)

นามสกุล บทความ เกี่ยวกับวิธีที่ฉันจัดการเพื่อจัดระเบียบอุโมงค์ VPN โดยตรงระหว่างคอมพิวเตอร์สองเครื่องที่อยู่ด้านหลังผู้ให้บริการ NAT บทความก่อนหน้านี้อธิบายกระบวนการจัดระเบียบการเชื่อมต่อด้วยความช่วยเหลือของบุคคลที่สาม - ตัวกลาง (VPS ที่เช่าซึ่งทำหน้าที่เป็นบางอย่างเช่นเซิร์ฟเวอร์ STUN และตัวส่งสัญญาณข้อมูลโหนดสำหรับการเชื่อมต่อ) ในบทความนี้ ฉันจะบอกคุณว่าฉันจัดการอย่างไรโดยไม่ต้องใช้ VPS แต่คนกลางยังคงอยู่และพวกเขาเป็นเซิร์ฟเวอร์ STUN และ Yandex.Disk...
อุโมงค์ VPN โดยตรงระหว่างคอมพิวเตอร์ผ่านผู้ให้บริการ NATs (ไม่มี VPS โดยใช้เซิร์ฟเวอร์ STUN และ Yandex.disk)

การแนะนำ

หลังจากอ่านความคิดเห็นของโพสต์ก่อนหน้า ฉันพบว่าข้อเสียเปรียบหลักของการใช้งานคือการใช้ตัวกลาง - บุคคลที่สาม (VPS) ที่ระบุพารามิเตอร์ปัจจุบันของโหนด สถานที่และวิธีการเชื่อมต่อ พิจารณาคำแนะนำในการใช้ STUN นี้ (ซึ่งมีอยู่มากมาย) เพื่อกำหนดพารามิเตอร์การเชื่อมต่อปัจจุบัน ก่อนอื่น ฉันตัดสินใจใช้ TCPDump เพื่อดูเนื้อหาของแพ็กเก็ตเมื่อเซิร์ฟเวอร์ STUN ทำงานร่วมกับไคลเอนต์และได้รับเนื้อหาที่ไม่สามารถอ่านได้ทั้งหมด Google โปรโตคอลที่ฉันเจอ บทความที่อธิบายโปรโตคอล. ฉันรู้ว่าฉันไม่สามารถดำเนินการตามคำขอไปยังเซิร์ฟเวอร์ STUN ด้วยตัวเองได้ และนำแนวคิดนี้ไปไว้ใน "กล่องที่ห่างไกล"

ทฤษฎี

เมื่อเร็ว ๆ นี้ฉันต้องติดตั้งเซิร์ฟเวอร์ STUN บน Debian จากแพ็คเกจ

# apt install stun-server

และในการพึ่งพาฉันเห็นแพ็คเกจสตันไคลเอ็นต์ แต่อย่างใดฉันก็ไม่ได้สนใจมัน แต่ต่อมาฉันจำแพ็คเกจ stun-client ได้และตัดสินใจว่ามันทำงานอย่างไรหลังจาก googling และค้นหาใน Yandex ฉันได้รับ:

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

ในการตอบสนองฉันได้รับ:

ไคลเอนต์ STUN เวอร์ชัน 0.97
เปิดพอร์ต 21234 ด้วย fd 3
เปิดพอร์ต 21235 ด้วย fd 4
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 0

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 4

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 2

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
ได้รับข้อความสตัน: 92 ไบต์
MappedAddress = <IP ของฉัน>:2885
ที่อยู่ต้นทาง = 216.93.246.18:3478
ที่อยู่ที่เปลี่ยนแปลง = 216.93.246.17:3479
แอตทริบิวต์ที่ไม่รู้จัก: 32800
ชื่อเซิร์ฟเวอร์ = Vvida.org 0.98-CPC
ได้รับข้อความประเภท 257 id=1
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 0

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.17:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 4

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 2

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 0

กำลังจะส่งข้อความของ len 28 ไปที่ <My IP>:2885
ได้รับข้อความสตัน: 28 ไบต์
คำขอเปลี่ยนแปลง = 0
ได้รับข้อความประเภท 1 id=11
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 0

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.17:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 4

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 2

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
ได้รับข้อความสตัน: 92 ไบต์
MappedAddress = <IP ของฉัน>:2885
ที่อยู่ต้นทาง = 216.93.246.17:3479
ที่อยู่ที่เปลี่ยนแปลง = 216.93.246.18:3478
แอตทริบิวต์ที่ไม่รู้จัก: 32800
ชื่อเซิร์ฟเวอร์ = Vvida.org 0.98-CPC
ได้รับข้อความประเภท 257 id=10
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 4

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 2

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 4

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 2

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 4

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 2

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 4

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 2

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 4

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
เข้ารหัสข้อความสตัน:
การเข้ารหัสคำขอเปลี่ยนแปลง: 2

กำลังจะส่งข้อความของ len 28 ไปที่ 216.93.246.18:3478
ทดสอบฉัน = 1
ทดสอบครั้งที่สอง = 0
ทดสอบ III = 0
ทดสอบ ผม(2) = 1
คือแนท = 1
แมป IP เดียวกัน = 1
กิ๊บ = 1
พอร์ตผู้พิทักษ์ = 0
หลัก: การแมปอิสระ, ตัวกรองขึ้นอยู่กับพอร์ต, พอร์ตสุ่ม, จะติดกิ๊บ
ค่าส่งคืนคือ 0x000006

สตริงที่มีค่า

MappedAddress = <IP ของฉัน>:2885

สิ่งที่คุณต้องการ! มันแสดงสถานะปัจจุบันสำหรับการเชื่อมต่อบนพอร์ต UDP ท้องถิ่น 21234 แต่นี่เป็นเพียงครึ่งหนึ่งของการต่อสู้ คำถามเกิดขึ้นว่าจะถ่ายโอนข้อมูลนี้ไปยังโฮสต์ระยะไกลและจัดระเบียบการเชื่อมต่อ VPN ได้อย่างไร ใช้โปรโตคอลเมลหรืออาจจะเป็นโทรเลข! มีตัวเลือกมากมายและฉันตัดสินใจใช้ Yandex.disk เนื่องจากฉันเจอ บทความเกี่ยวกับการทำงาน Curl ผ่าน WebDav กับ Yandex.disk. หลังจากคิดถึงการนำไปปฏิบัติแล้ว ฉันก็เกิดแนวคิดขึ้นมาดังนี้

  1. ส่งสัญญาณว่าโหนดพร้อมที่จะสร้างการเชื่อมต่อโดยการมีไฟล์เฉพาะพร้อมการประทับเวลาบน Yandex.disk
  2. หากโหนดพร้อม ให้รับพารามิเตอร์ปัจจุบันจากเซิร์ฟเวอร์ STUN
  3. อัปโหลดการตั้งค่าปัจจุบันไปยัง Yandex.disk
  4. ตรวจสอบการมีอยู่และอ่านพารามิเตอร์ของโหนดระยะไกลจากไฟล์บน Yandex.disk
  5. การสร้างการเชื่อมต่อกับโฮสต์ระยะไกลโดยใช้ OpenVPN

การปฏิบัติ

หลังจากคิดสักนิดโดยคำนึงถึงประสบการณ์จากบทความที่แล้วฉันก็รีบเขียนสคริปต์ เราจะต้อง:

# apt install openvpn stun-client curl 

สคริปต์นั้นเอง:

รุ่นเดิม

# 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

เพื่อให้สคริปต์ทำงานได้คุณต้องมี:

  1. คัดลอกไปยังคลิปบอร์ดและวางลงในโปรแกรมแก้ไข เช่น:
    # nano vpn8.sh 
  2. ระบุชื่อผู้ใช้และรหัสผ่านสำหรับ Yandex.disk
  3. ในฟิลด์ "—ifconfig 10.45.54.(1 หรือ 2) 255.255.255.252" ระบุที่อยู่ IP ภายในของอินเทอร์เฟซ
  4. สร้าง ความลับคีย์ โดยคำสั่ง:
    # openvpn --genkey --secret secret.key 
  5. ทำให้สคริปต์ปฏิบัติการได้:
    # chmod +x vpn8.sh
  6. รันสคริปต์:
    # ./vpn8.sh nZbVGBuX5dtturD

    โดยที่ nZbVGBuX5dtturD คือ ID การเชื่อมต่อที่สร้างขึ้น ที่นี่

บนโหนดระยะไกล ให้ทำทุกอย่างเหมือนกัน ยกเว้นการสร้าง secret.key และ ID การเชื่อมต่อ ซึ่งจะต้องเหมือนกัน

เวอร์ชันที่อัปเดต (ต้องซิงโครไนซ์เวลาเพื่อให้การทำงานถูกต้อง):

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

เพื่อให้สคริปต์ทำงานได้คุณต้องมี:

  1. คัดลอกไปยังคลิปบอร์ดและวางลงในโปรแกรมแก้ไข เช่น:
    # nano vpn10.sh 
  2. ระบุการเข้าสู่ระบบ (บรรทัดที่ 2) และรหัสผ่านสำหรับ Yandex.disk (บรรทัดที่ 3)
  3. ระบุที่อยู่ IP ภายในของช่องสัญญาณ (บรรทัดที่ 4)
  4. ทำให้สคริปต์ปฏิบัติการได้:
    # chmod +x vpn10.sh
  5. รันสคริปต์:
    # ./vpn10.sh nZbVGBuX5dtturD

    โดยที่ nZbVGBuX5dtturD คือ ID การเชื่อมต่อที่สร้างขึ้น ที่นี่

บนโหนดระยะไกล ให้ทำเช่นเดียวกัน ระบุที่อยู่ IP ภายในที่สอดคล้องกันของช่องสัญญาณและรหัสการเชื่อมต่อ

หากต้องการรันสคริปต์อัตโนมัติเมื่อเปิดใช้งาน ฉันใช้คำสั่ง “nohup /<path to the script>/vpn10.sh nZbVGBuX5dtturD > /var/log/vpn10.log 2>/dev/null &” ที่มีอยู่ในไฟล์ /etc/ rc.local

ข้อสรุป

สคริปต์ใช้งานได้ทดสอบบน Ubuntu (18.04, 19.10, 20.04) และ Debian 9 คุณสามารถใช้บริการอื่น ๆ เป็นตัวส่งสัญญาณได้ แต่สำหรับประสบการณ์ฉันใช้ Yandex.disk
ในระหว่างการทดลอง พบว่าผู้ให้บริการ NAT บางประเภทไม่อนุญาตให้สร้างการเชื่อมต่อ ส่วนใหญ่มาจากผู้ให้บริการมือถือที่มีการบล็อกทอร์เรนต์

ฉันวางแผนที่จะปรับปรุงในแง่ของ:

  • การสร้าง secret.key อัตโนมัติทุกครั้งที่คุณเริ่ม เข้ารหัสและคัดลอกไปยัง Yandex.disk เพื่อถ่ายโอนไปยังโหนดระยะไกล (คำนึงถึงในเวอร์ชันที่อัปเดต)
  • การกำหนดที่อยู่ IP ของอินเทอร์เฟซโดยอัตโนมัติ
  • การเข้ารหัสข้อมูลก่อนอัปโหลดไปยัง Yandex.disk
  • การเพิ่มประสิทธิภาพโค้ด

ให้มี IPv6 ในทุกบ้าน!

อัพเดท! ไฟล์ล่าสุดและแพ็คเกจ DEB ที่นี่ - yandex.disk

ที่มา: will.com

เพิ่มความคิดเห็น