Прямой VPN-туннель между двумя компьютерами находящимися за NATами провайдеров

Статья о том, как мне удалось организовать прямой (точка-точка) VPN-туннель между двумя компьютерами, каждый из которых находился за NAT'ом провайдеров, при помощи VPS и простых скриптов, используя стандартные утилиты Linux, без каких-либо настроек сетевого оборудования.

Введение


Существует множество программ (TeamViewer, Hamachi) для удаленного управления компьютером, передачи данных и т.п. Работают они на удивление хорошо и в любых условиях. Но как правило это платные сервисы. Как устроены эти программы неизвестно, да и особого желания их использовать они у меня не вызывают. Я как пользователь ОС Linux (в основном Ubuntu) использовал для передачи данных и управлением своими ПК связку из OpenVPN, SSH, VNC, RDP и прочие сервисы в зависимости от потребности. Для того чтобы организовать сеть между двух компьютеров я использовал VPN-сервер, что бы эти компьютеры подключались к OpenVPN серверу и весь трафик шел через сервер. Это не совсем хорошо, ведь трафик проходит двойной путь, в следствии этого терялась скорость.

Теория


Я давно задумался о решении по организации канала передачи данных непосредственно от узла к узлу, которые находятся за NATом провайдеров, без использования серверов-посредников. Перебрав некоторое количество статей о различных технологиях типа GRE-туннелей, IPsec, UDP Hole Punching, OpenVPN и прочего, я понял, что узлы должны пробивать соединение навстречу друг другу, то есть посылать пакеты на IP и порт удаленного узла. Поставил несколько опытов по организации GRE-туннеля через NAT, передачу сообщения при помощи NetCat навстречу друг другу, иногда это работало, иногда нет, всё зависело от типа используемого провайдером NAT. Не так давно попалась на глаза интересная статья, в которой было описание организации работы OpenVPN соединения между двумя компьютерами (далее узлами). Я прочитал, проверил и заработало, но при условии, что локальный порт узла и внешний порт будут совпадать, то есть мой провайдер будет использовать Cone NAT. Мне же стало интересно организовать туннель между двумя компьютерами при условии, что оба будут находятся за любым типом (Cone или Symmetric) NAT, то есть локальный порт может не совпадать с внешним портом. Задача уперлась в невозможность определения текущего порта внешнего интерфейса без внешней помощи. Если внешний IP-адрес хоть как-то можно узнать (например: curl ifconfig.me), а вот с определением текущего внешнего порта возникла трудность.

Практика


Для решения этой задачи пришлось использовать VPS (S-синий овал), на нем я поднял скрипт который выполнял роль «Соединителя», что-то типа STUN-сервера: при помощи утилиты TCPDump получал UDP-пакет (далее везде используется UDP протокол) на определенный интерфейс и порт, парсил содержимое пакета, определял IP-адрес/порт источника и отвечал утилитой NetCat возвращая текущие параметры (IP-адрес и порт) соединения, а так же параметры (IP-адрес и порт) удаленного узла к которому нужно подключиться, если эти данные были доступны, иначе ждал пока они не появятся. Все это дело сопоставлялось с идентификатором (ID) соединения, так как несколько соединений могли мешать друг другу, при использовании ID все решалось. Также была проблема того, что узел получал свои же старые данные и пытался по ним подключиться и это решилось с помощью хеша Hostname.

image

На узлах A и B я использовал скрипт и сгенерированный заранее ключ для авторизации VPN-соединения, работало это так: запускался скрипт, случайно выбирался локальный порт в диапазоне от 20000 до 65000 и с этого порта отправлялся пакет на VPS, который содержал в себе ID соединения и хеш hostname, с помощью утилиты NetCat и тут же запускался TCPDump ожидая ответа. В ответ приходил пакет который содержал в себе текущие данные (IP-адрес/порт) этого узла, а при наличие данных удаленного узла, они тоже приходили и начинался обмен приветствиями между узлами. Если же данных удаленного узла не было, то опрос повторялся с периодичностью 30-45 секунд, для поддержания сессии. В момент когда все необходимые данные (IP-адрес и порт текущего узла и удаленного) были на узлах, начинался обмен пакетами, пакет содержал в себе число m=0 и сгенерированное число от 0 до 254 (это число спользовалось для генерации внутреннего IP-адреса VPN-соединения). Удаленный узел получив пакет с m=0 отправлял в ответ m=1 и так далее до 10. При получении пакета m=10 инициировалась посылка пачки пакетов с периодичность в 1 секунду с m=13 и запуск OpenVPN, удаленный узел получив m=13 тоже запускал OpenVPN используя локальный порт, IP-адрес и порт удаленного узла, а также сгенерированный внутренний IP вида 10.X.X.{1,2}/30.

Внимание: скрипты написаны и проверены на ОС Ubuntu 18.04 и Debian 9

Скрипт на VPS:

# cat connector2.sh

#!/bin/bash
if [[ $1 == '' ]]; then echo -e "Укажите номер порта который нужно слушать"; exit; fi
iface=`ip route get 8.8.8.8 | head -n 1 | sed 's|.*dev ||' | awk '{print $1}'`
a=0
until (( $a == 500)); do
	packet=`tcpdump -i $iface udp port $1 -vvn -c1 -A`
		if [[ "$packet" == *"Ident"* ]]; then
			pack=`echo "$packet" | grep -e "udp sum ok" -e "Ident"`
 			myip=`echo $pack | sed 's/\./ /g' | awk '{print $1"."$2"."$3"."$4}'`
 			myport=`echo $pack | sed 's/\./ /g' | awk '{print $5}'`
 			id=`echo $pack | sed 's|.*Ident:||' | awk '{print $1}'`
 			myname=`echo $pack | sed 's|.*Ident:||' | awk '{print $2}'`
			echo "$myip:$myport $myname" > /tmp/vpn2-$id-$myname
			echo "MyData $myip:$myport $(cat /tmp/vpn2-$id-* | grep -v $myname | awk {'print $1'})" | nc $myip $myport -u -p $1 -w 1
			cat /tmp/vpn2-$id-*
			topoint=`cat /tmp/vpn2-$id-* | grep -v "$myname" | sed 's/:/ /g'`
			if [[ $topoint != '' ]]; then
						ip=`echo $topoint | awk '{print $1}'`
						port=`echo $topoint | awk '{print $2}'`
						echo "MyData $ip:$port $(cat /tmp/vpn2-$id-* | grep $myname | awk {'print $1'})" | nc $ip $port -u -p $1 -w 1
						fi
fi
done

Запускается автоматически строкой в /etc/rc.local

#!/bin/bash
nohup /путь-до-скрипта/connector2.sh 13013 > /var/log/connector2.log &
exit

где 13013 — это порт который нужно слушать, /var/log/connector2.log — лог.

Скрипт на узлах: # cat vpn7.sh
#!/bin/bash
######################## Задаем цветной текст ###
WARN='\033[37;1;41m'				#
END='\033[0m'					#
RED='\033[0;31m'         #  ${RED}		#
GREEN='\033[0;32m'      #  ${GREEN}		#
#################################################
####################### Проверяем наличие необходымих приложений #########################################################
al="ip echo readlink dirname ps grep awk kill md5sum shuf nc curl sleep openvpn tcpdump cat"
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 /<путь к файлу>/vpn7.sh  > /var/log/vpn7.log 2>/dev/hull & ${END}"; exit; fi
ABSOLUTE_FILENAME=`readlink -f "$0"`                                                    # полный путь до скрипта
DIR=`dirname "$ABSOLUTE_FILENAME"`                                                      # каталог в котором лежит скрипт
############################### Проверка наличия и загрузка конфигурационного файла ##################################
cfg="$DIR/vpn.cfg"
if [[ -f "$cfg" ]]; then
		      echo "$(date) Загружаю конфигурационный файл $cfg"
                      source "$cfg"
                  else
                      echo "$(date) Конфигурационный файл не обнаружен!"
                  fi


############################### Проверка наличия секретного ключа ##################################
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
#########################################################################################
localport=`shuf -i 20000-65000 -n 1`						# Выбор локального порта
name=`uname -n | md5sum | awk '{print $1}'`                                             # Имя узла
ipsrv="45.141.103.45"                                                                  # IP-адрес сервера получения данных о второй стороне
portsrv="13013"

############################### Запуск цикла ###########

until [[ $count > 100 ]]; do
#########################################################################################
until [[ -n "$iftosrv" ]]; do echo "$(date) Определяю сетевой интерфейс"; iftosrv=`ip route get $ipsrv | head -n 1 | sed 's|.*dev ||' | awk '{print $1}'`; sleep 5; done	# Определение интерфейса
netcattosrv="nc -u $ipsrv $portsrv -p $localport -w 1"				# Команда посылки пакета NC
tcpdumptosrv="tcpdump -i $iftosrv udp and src port $portsrv and src $ipsrv and dst port $localport -n -c1 -A"   # Команда приема пакета
id=`echo $1| md5sum | awk '{print $1}'` 					# Преобразеум имя узла в md5 что бы не светить реальное имя
##################### Получение данных о себе и удаленного узла ###################################
echo -e "$(date) ${GREEN}Фаза 1 - Получение данных с сервера $ipsrv:$portsrv ${END}"
echo -e "$(date) ${GREEN}Использую интерфейс $iftosrv и локальный порт $localport ${END}"
until [[ -n "$ip" && -n "$port" ]]; do
			if [[ -z "$data" ]]; then
				sleep 1 && echo "Ident: $id $name" | $netcattosrv > /dev/null &
				sleep 4 && pid=`ps xa | grep "$tcpdumptosrv" | grep -v grep | awk '{print $1}'` && if [[ -n $pid ]]; then kill $pid; echo "$(date) Нет ответа от сервера, пробую еще раз..."; fi &
				data=`$tcpdumptosrv`
				sleep 2
			fi
			if [[ -n "$data" ]]; then
				#echo "Ответ: $data"
				data=`echo "$data" | grep "MyData" | sed 's|.*MyData ||' | sed 's/:/ /g'`
				myip=`echo "$data" | awk '{print $1}'`
				myport=`echo "$data" | awk '{print $2}'`
				ip=`echo "$data" | awk '{print $3}'`
				port=`echo "$data" | awk '{print $4}'`
				data=''
				if [[ -z $tst ]]; then echo -e "$(date) ${GREEN}Мой внешний IP: $myip и порт: $myport ${END}"; fi
				if [[ -n $localport && -n $myport && -z $tst ]];then
										if [[ $localport == $myport ]]; then
										echo -e "$(date) ${GREEN}Мой локальный порт $localport и внешний порт $myport одиноковые, используется CONE NAT ${END}"; tst=1
										else
										echo -e "$(date) ${RED}Мой локальный порт $localport и внешний порт $myport разные, используется SYMMETRIC NAT ${END}"; tst=1
										fi
										fi
				fi
			if [[ -n "$ip" && -n "$port" ]]; then
								echo -e "$(date) ${GREEN}Получил данные об удаленном узле: IP: $ip Порт: $port, переходим на следующий этап... ${END}";
							 else
								sleep=`shuf -i 30-45 -n 1`;
								echo -e "$(date) ${RED}Нет данных удаленного узла, возможно он еще не вышел на связь, ожидаю данных $sleep секунд и проверяю еще раз... ${END}";
								sleep $sleep && pid=`ps xa | grep "$tcpdumptosrv" | grep -v grep | awk '{print $1}'` && if [[ -n $pid ]]; then kill $pid; fi &
								data=`$tcpdumptosrv`
							 fi
			done

###################### Организация соединения с удаленным узлом
iftopeer=`ip route get "$ip" | head -n 1 | sed 's|.*dev ||' | awk '{print $1}'`
echo -e "$(date) ${GREEN}Фаза 2 - Установка соединения с удаленным узлом $ip:$port${END}"
echo -e "$(date) ${GREEN}Попытка установки соединения: $myip:$myport -> $ip:$port ${END}"
m=0
t=0
connect=0
until (( $connect >= 10 )); do
                        if [ -z "$oktet" ]; then
							echo "$(date) Октета нет, генерирую и сохраняю в $cfg"
                                                        oktet=`shuf -i 0-254 -n 1`
							echo "oktet=$oktet" >> $cfg
                                                 fi
			netcattopeer="nc -u $ip $port -p $localport -w 1"
			tcpdumptopeer="tcpdump -i $iftopeer udp and port $localport and src "$ip" -n -c1 -A"
			until (( $m >= 10 )); do
				for w in {1..3}; do
						   for pid1nc in `ps xa | grep "$netcattopeer" | grep -v grep | awk '{print $1}'`;do kill $pid1nc; done;
						   echo "445Hi: $m $oktet" | $netcattopeer > /dev/null &
						   sleep 1
						   for pidnc in `ps xa | grep "$netcattopeer" | grep -v grep | awk '{print $1}'`;do kill $pidnc; done
						 done &
				sleep 4 && pid=`ps xa | grep "$tcpdumptopeer" | grep -v grep | awk '{print $1}'` && sleep 10 && if [[ -n $pid ]]; then kill $pid && echo -e "$(date) ${RED} Нет ответа от пира, пробую еще раз... ${END}"; fi &
				peer=`$tcpdumptopeer`
				if [[ -n $peer ]]; then
					newport=`echo "$peer" | grep " IP " | sed "s|.* $ip.||" | awk '{print $1}'`
					if (( $newport != $port )); then
									echo -e "$(date) ${WARN}Порт изменился $port -> $newport ${END}";
									port=$newport;
									netcattopeer="nc -u $ip $port -p $localport -w 1"
									fi
					mm=`echo "$peer" | grep "445Hi: " | sed 's|.*445Hi: ||' | awk '{print $1}'`
					echo -e "$(date) ${GREEN} Получил: $mm - передаю: $mm+1 ${END}"
					if (( $m <= $mm )); then
								 m=$(( $mm + 1 ));
							     fi
					text=`echo "$peer" | grep "445Hi: " | sed 's|.*445Hi: ||' | awk '{print $2}'`
						else
					(( t++ ))
					echo -e "$(date) ${RED} Данных нет $t раз ${END}"
					if (( $t > 5 ));then echo -e "$(date) ${RED} Превышен интервал ожидания, переподключаюсь ${END}"; m=10; connect=1012; ip=''; port=''; fi
					fi
				done
			if (( $connect < 1012 )); then
			echo -e "$(date) ${GREEN}Значение: $m ${END}"

			if [[ -n $endoktet ]]; then 	echo "$(date) Обнаружен конечный октет = $endoktet"
							if [[ $endoktet == 1 ]]; then
										    ipaddress="10.$text.$oktet.1"
										 else
										    ipaddress="10.$oktet.$text.2"
										 fi
						else
							echo "$(date) Не обнаружен конечный октет, генерирую и сохраняю в $cfg"
				                        if [[ $port > $myport ]]; then
                                	                       			    ipaddress="10.$text.$oktet.1"
                                        	              			    echo "endoktet=1" >> $cfg
                                                	        		  else
                                                  	      			    ipaddress="10.$oktet.$text.2"
                                                   	     			    echo "endoktet=2" >> $cfg
                                                     	  			  fi

						fi

			m=12
			for w in {1..9}; do
					   for pid2nc in `ps xa | grep "$netcattopeer" | grep -v grep | awk '{print $1}'`;do kill $pid2nc; done;
					   echo "445Hi: $m $oktet" | $netcattopeer > /dev/null; sleep 0.5;
					 done
			for pidnc in `ps xa | grep "$netcattopeer" | grep -v grep | awk '{print $1}'`; do
								kill $pidnc && echo -e "$(date) ${RED}Завершен процесс $pidnc (NetCat) для освобождения порта $localport${END}";
								done
			rpfilter=`cat /proc/sys/net/ipv4/conf/all/rp_filter`
			if [[ $rpfilter == 1 ]]; then
							echo -e "$(date) ${GREEN}rp_filter=$rpfilter - активна защита от подмены адресов (спуфинга)${END}";
						 else
							echo -e "$(date) ${RED}Внимение, rp_filter=$rpfilter! Включаю (sysctl -w net.ipv4.conf.all.rp_filter=1) «строгий режим» проверки для защиты от подмены адресов (спуфинга) ${END}";
							sysctl -w net.ipv4.conf.all.rp_filter=1
						 fi
			echo -e "$(date) ${GREEN} Запускаюсь... IP-адрес: $ipaddress...${END}"
			$(which lsmod) | grep tun || $(which modprobe) tun
			openvpn --remote $ip --rport $port --lport $localport \
                        --proto udp --dev tap --float --auth-nocache --verb 3 --mute 20 \
                        --ifconfig "$ipaddress" 255.255.255.252 \
                        --secret "$DIR/secret.key" \
                        --auth SHA256 --cipher AES-256-CBC \
                        --ncp-disable --ping 10  --ping-exit 40 \
			--comp-lzo yes
			echo -e "$(date) ${RED} Соединение прервано... ${END}"
			m=0
			t=0
                        (( connect++ ));
			fi
			done
done

Скопировать скрипт в буфер и вставить в тектовый редактор, например:
# nano vpn7.sh

Сделать скрипт исполняемым:
# chmod +x vpn7.sh

Для первого запуска сгенерируем ключ авторизации secret.key, на удаленной стороне генерировать не надо, нужно скопировать его:
# openvpn --genkey --secret secret.key 

Запустим скрипт, например так:
# ./vpn7.sh 517vA0051smB4dE

Ключ 517vA0051smB4dE сгенерировал на strongpasswordgenerator.com

Запускается автоматически строкой в /etc/rc.local

#!/bin/bash
nohup /путь-до-скрипта/vpn7.sh <ID-соединения> >/var/log/vpn7.log 2>/dev/hull &
exit

где ID-соединения — это любая уникальная фраза для вашего соединения, /var/log/vpn7.log — лог соединения, ipsrv=«45.141.103.45» — IP-адрес узла где запущен connector2.sh (первый скрипт).

Если все настроено правильно, то будет работать как часы: включил и через пару минут у тебя есть связь с удаленным узлом. В скриптах используются бесконечные циклы и временные задержки, то есть скрипт работает пока включен узел и при потере связи будет пытаться восстановить её. Скрипты не идеальные но, сам факт того что эта технология работает дает мне массу новых идей, например:

  • использовать узел для хранения особо важных данных, и иметь к ним доступ, допустим, в случае утери ноутбука все данные будут на узле
  • использовать на ноутбуке удаленный рабочий стол компьютера
  • организовать связи с компьютером друга и поиграть в сетевую игру
  • иметь доступ к домашней камере видеонаблюдения с рабочего компьютера или просмотреть веб-камеру ноутбука

Приемущества:

  • простота в настройке и использовании
  • трафик идет напрямую
  • трафик шифруется и защищен от перехвата
  • нет необходимости пробрасывать порты
  • скрипт запускается автоматически

Недостатки:

  • главный недостаток это использования VPS как источника данных для соединения, но я думаю над этим
  • некоторые провайдеры блокируют трафик между другими провайдерами (замечено у сотовых операторов)
  • при использовании с обоих сторон одного провадера может не сработать, зависит от типа NAT
  • при использовании провадером «жесткого» NAT может не сработать

В планах дальнейшее развитие скрипта до какой-нибудь системы, минимизировать время ожидания ответов, прикрутить шифрование передаваемых данных, адаптировать его к ОС Windows и Android, научить работать через Proxy и тому подобное.

Думаю на фоне дефицита белых IPv4 адресов моё решение будет актуально.

Обновлено 11.12.2019, добавлено:
  • команда активации защиты от подмены адресов, уязвимость CVE-2019-14899
  • команды завершающие зависшие процессы NC, ускоряется процесс установки соединения
  • внутренние IP-адреса генерируются при первом запуске и их составляющие хранятся в vpn.cfg
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 37

    0
    Человек который придумает серверную часть под vps сервер на винде которая запускается 1 ( ОДНОЙ! ) кнопкой старт — озолотится

      0
      Вы можете установить OpenSSH на системе с Windows установкой одной галочки в списке «компонентов», а потом использовать этот SSH-сервер как SOCKS-прокси с помощью либо обычного ssh-клиента, либо многопоточной быстродейственной альтернативы.
        0
        SOCKS прокси я могу написать сам как клиент так и сервер
        Меня же интересует реализация VPN! сервера 1 кнопкой что несколько разные вещи
          +1
          А зачем?

          Несмотря на то, что оверхед у пакетной маршрутизации меньше, чем у проксирования соединений, практическая скорость у прокси в условиях реальной сети выше по весьма банальной причине: TCP-ретрансмиты при потерях происходят независимо на двух разных участках — между прокси и клиентом и между прокси и целевым узлом.

          Если всё что требуется — это гонять весь трафик через удалённый сервер, то проксирование как технология — самое то. Ну а в качестве узла для доступа внутрь частной сети Windows попросту не самый удачный выбор именно с технологической точки зрения.
        +1
        Эмммм… Вы покупаете впс и используете его для такой цели? Что мешает поставить, к примеру, StrongSwon и сделать все что угодно, хоть Site-2-Site и забугорный интернет?
          0
          VPS использую для разных целей, например: Apache2, Nginx, Mysql, PHP, Bind9, Postfix, Dovecot, OpenVPN и прочее… Всего по-немножку
          Данное решение используется для подключения двух компьютеров каждый из которых находится за NATами, StrongSwon можно использовать поверх
            +1
            Всем доброго дня! Пару комментариями выше человек посоветовал использовать SOCKS прокси, я к нему присоединяюсь. Самое нехорошая привычка это мешать Production с Testinng ом. В вашем случае у вас есть VPS, который в принципе видно используется в качестве вполне рабочего сервера, зачем вы открываете туннели на рабочей машине? Подумайте о безопасности, что если на другом конце у кого сидит зловредный скрипт, который обязательно воспользуется новой (для него) сетью.
          +3
          Через tor без VPS: habr.com/ru/post/237019
            +2
            Отличная идея! Может быть стоит развить её дальше и пробивать NAT с использованием публичных STUN-серверов, как это делают, например, браузеры для использования WebRTC?
              0
              Я думал об этом и думаю дальше, нужно понять как устроены пакеты которые нужно посылать на STUN и пакеты которые я получу в ответ
                +1
                STUN дает только ответ на вопрос «какой у меня IP и порт», но от этого нет толку, если эта информация останется только у меня. Внешний сервер (ну или TOR hidden service, как уже предложили) нужен (в том числе при использовании WebRTC) как централизованная точка встречи для передачи этой информации другой стороне.
                +1
                Думаю можно в роли диспетчера вместо выделенного сервера задекйствовать вебхостинг.
                  +2
                  Я правильно понимаю, что если провайдер NATит с сохранением dst и фильтрацией по нему входящего трафика, то эта схема не заработает?
                    0
                    Да, в данном случае много чего зависит от того, как реализован NAT провайдера, но как правило используются динамические IP и тогда придется их всех заблокировать, что маловероятно… Torrent не блокируют, принцип похожий
                      0
                      Извиняюсь, с утра не полностью понял вопроса, да «если провайдер NATит с сохранением dst и фильтрацией по нему входящего трафика», но в этот момент узел шлет пакет навстречу удаленному узлу, и если там нет фильтрации, то уделенный узел изменит порт назначения и все будет хорошо, но вот если с двух сторон будет такая ситуация, то без посредника не обойтись. Я думаю об этом.
                        0
                        Любопытно проверить, если с одного локального порта отправлять пакеты на разные адреса, то сколько будет строк трансляции NAT, и по какому принципу они будет перезаписываться. При этом в софте нужно контролировать номер создаваемого локального порта соединения.
                          0
                          Результат будет зависеть от того, какой протокол (TCP или UDP) использовать и тип NAT (NATов) по маршруту пакета…
                      +2
                      Можно и без VPS.
                      1) через любой STUN-сервер получаете ответ на вопрос «какой у меня внешние IP и порт»
                      2) через любой мессенджер через API, отправляете эту информацию второй стороне.
                        +1
                        Можно хранить данные по портам на dynamic DNS сервисе. Мессенжеры тут излишни как и VPS.
                        0
                        Как готовое решение можно использовать Tinc VPN.

                        Automatic full mesh routing
                        Regardless of how you set up the tinc daemons to connect to each other, VPN traffic is always (if possible) sent directly to the destination, without going through intermediate hops.
                        NAT traversal
                        As long as one node in the VPN allows incoming connections on a public IP address (even if it is a dynamic IP address), tinc will be able to do NAT traversal, allowing direct communication between peers.
                          0

                          К сожалению tincd по удобству установки "одной кнопкой" пока где-то далеко.

                          +3
                          какую только дичь люди не творят, лишь бы не юзать IPv6 ))))
                          (это, скорее, вопрос ко всяким провайдерам, которые до сих пор не дают нативный IPv6, или требуют за него у клиентов неадекватную денежку)

                          Сам говорю с позиции провайдера, который спокойно, неспеша, в рамках смены технологических циклов — ввел в эксплуатацию dual stack.
                          Ничего нет сложного и расходы на это не являются основными даже и близко
                          (это если вам будут говорить, что оборудование и софт обновить для поддержки ipv6 — это очень дорого). CG-NAT тоже дорого. А оборудование, в любом случае, обновляется каждые 5-7 лет. (Хотя бы потому, что трафики растут). И там уже везде давно есть ipv6.
                          И в клиентских роутерах и ОС тоже завезли.
                          На дворе 2020 год.
                          Серьезно — хватит бояццо и ненавидеть IPv6.
                          Я уже дошел до стадии принятия неизбежного )

                          P.S.
                          Только не надо начинать холивар, что ipv6 гомно и не безопасно…
                          IPv6 решает отлично задачу с нехваткой IPv4.
                          Да, возникают новые проблемы и задачи.
                          Это нормально.
                          Все решается соответствующими инструментами.
                          В частности, так называемая безопасность NAT (а на самом деле к безопасности имеет мало отношения) — «невидимость» домашних устройств «снаружи» для всего мира — в случае IPv6 аналогичный эффект легко решается statefull фаерволом (по дефолту запрет на инициацию соединений снаружи).
                          Но! При этом, при желании, что-то можно лего разрешить.
                          И вся эта дичь с NATом не нужна…
                            +2
                            Это вопрос не «скорее» а «в первую очередь» к провайдерам.
                            Ростелеком, сцк…
                              0
                              Да, согласен)

                              У этих мастодонтов очень длинные технологические циклы и инерционность.
                              Но, рано или поздно они это сделают.

                              В Беларуси вон — законодательно заставили давать IPv6 по требованию с 1 янв 2020
                              (Кстати, в Указе ничего не указали по поводу бесплатности — исполнители (провайдеры) могут установить заградительный ценник или требование установить определенные CPE за сотни нефти или довести процедуру до маразма)
                              0
                              Я IPv6 не боюсь, у меня его просто нет. Ни дома, ни на работе
                                0
                                А я его даже на телефоне включил. Удобно.
                                0
                                Не могли бы вы озвучить название провайдера?
                                  0
                                  На Yota не завелся IPv6
                                    0
                                    Благодарю за статью и за ответ, точно в приоритетном списке на «поковырять в свободное время».
                                    Однако мой вопрос адресован в данном случае white_crow
                                  0
                                  toxtun, toxvpn, yggdtasil, peervpn… tinc, множество вариаций на тему, и все требуют тем не менее что-то промежуточное…
                                    0

                                    Интересный (с точки зрения опыта) вариант велосипеда.
                                    Обычно велосипед такой:


                                    1. есть внешний сервер, который в себе хранит данные об адресе и порте и "имени" клиентов, которые ждут соединение.
                                    2. Есть ещё один внешний сервер, который ждёт запроса (а запрос открывает порт), достает из него адрес и порт и отправляет эти данные обратно
                                    3. Клиент "регистрируется" на первом внешнем сервере, используя данные, полученные от второго
                                    4. Клиент запрашивает данные для соединения с другим клиентом, обращаясь на первый сервер

                                    Первый и второй сервер могут быть на одной машине и даже на одном порту (но лучше разделить)
                                    Могут дополнительно быть всякие авторизации, запросы подключений, запросы обновления адреса-порта, статистика и тп

                                      +1

                                      Идея зачёт!
                                      Жаль что мне знаний на хватает всё это понять и осмыслить.

                                        0
                                        Спасибо! Будет время — постараюсь расписать максимально подробно, до каждой строки
                                        +1
                                        Идея хорoшая, осмелюсь дать несколько советов:
                                        — от tcpdump лучше отказаться в пользу http (php, python, nginx/lua/webdav2 etc...) т.к.он переводит интерфес в режим promisc
                                        — диапазон доступных портов можно взять здесь /proc/sys/net/ipv4/ip_local_port_range

                                        в итоге, задача сводится к тому, чтобы договорится о номерах портов и адресах, для этого можно использовать какой-нибудь pastebin и, как тут уже предлагалось, публичный stun-сервер.
                                          0
                                          Т.е., создание вручную чего-то такого, что умеет тот же tinc?

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                          Самое читаемое