Статия за това как успях да пусна VPN сървър зад NAT-а на домашния провайдер (без бял IP адрес). Веднага ще направя уговорка: че функционалността на това реализиране зависи директно от типа NAT, използван от вашия доставчик, както и от рутера.
И така, възникна необходимостта да се свържа от своя Android смартфон с домашния компютър, и двете устройства са свързани към Интернет чрез доставчици на NAT, а компютърът е свързан и чрез домашен рутер, който също прави NAT на връзките.
Класическата схема с използване на нает VPS/VDS с бял IP адрес, както и наемането на бял IP адрес от доставчика не бяха разгледани по няколко причини.
С оглед на опита от предишните статии, проведох няколко експеримента с STUN и NAT на доставчиците. Реших да направя малък експеримент, изпълнявайки командата на домашния рутер, работещ на фърмуер OpenWRT:
$ stun stun.sipnet.ruполучих резултат:
STUN client version 0.97
Primary: Independent Mapping, Independent Filter, random port, will hairpin
Return value is 0x000002
Дословен превод:
Independent Mapping — независимо отразяване
Independent Filter — независим филтър
random port — случаен порт
will hairpin — ще шпилка
Изпълнявайки аналогична команда на своя компютър, получих:
STUN client version 0.97
Primary: Independent Mapping, Port Dependent Filter, random port, will hairpin
Return value is 0x000006
Port Dependent Filter — зависим от порта филтър
Разликата в резултатите от командите показваше, че домашният рутер внася "своята лепта" в процеса на транслация на пакети от Интернет, като това се проявяваше в това, че при изпълнение на командата на компютъра:
stun stun.sipnet.ru -p 11111 -vаз получавах резултат:
…
MappedAddress = XX.1XX.1X4.2XX:4398
…
в този момент за кратко се отваряше UDP сесия, ако в този момент изпратя UDP заявка (например: netcat XX.1XX.1X4.2XX 4398 -u), то заявката пристигаше на домашния рутер, което потвърди TCPDump, стартиран на него, но заявката не достигаше до компютъра — IPtables като NAT транслатор на рутера я дропваше.

Но самият факт на преминаването на UDP заявката през доставчика NAT даваше надежда за успех. Тъй като рутерът е в моя юрисдикция, реших проблема с пренасочване на UDP/11111 порта към компютъра:
iptables -t nat -A PREROUTING -i eth1 -p udp -d 10.1XX.2XX.XXX --dport 11111 -j DNAT --to-destination 192.168.X.XXXТака получих възможност да инициирам UDP сесия и да получавам заявки от интернет от всяко IP адрес. В този момент стартирах OpenVPN-сървър (предварително конфигуриран), слушайки UDP/11111 порта, посочих на смартфона външния IP адрес и порта (XX.1XX.1X4.2XX:4398) и успешно се свързах със смартфона към компютъра. Но в тази реализация възникна проблем, трябваше по някакъв начин да поддържам UDP сесията до момента на свързването на OpenVPN клиента към сървъра, вариантът с периодично стартиране на STUN клиента не ми хареса — не исках да натоварвам ненужно STUN сървърите.
Също така обърнах внимание на записа «will hairpin — ще шпилка«, този режим
Hairpinning позволява на едно устройство в локалната мрежа зад NAT да получи достъп до друго устройство в същата мрежа по външния адрес на рутера.

В крайна сметка реших проблема с поддържането на UDP сесия, като просто стартирах клиента на същия компютър със сървъра.
Работеше по следния начин:
- стартирах STUN клиента с локален порт 11111
- получавах отговор с външния IP адрес и порта XX.1XX.1X4.2XX:4398
- изпращах данни с външния IP адрес и порта на имейл (може да е и друга услуга), настроена на смартфона
- стартирах OpenVPN сървъра на компютъра, който слушаше UDP/11111 порта
- стартирах OpenVPN клиента на компютъра, посочвайки XX.1XX.1X4.2XX:4398 за свързване
- по всяко време стартирах OpenVPN клиента на смартфона, посочвайки IP адреса и порта (в моя случай IP адресът не се променяше) за свързване

По този начин получих възможност да се свързвам със собствения си компютър от смартфона. Тази реализация позволява свързването на всеки OpenVPN клиент.
Практика
Ще ви трябват:
# apt install openvpn stun-client sendemailСлед като написах няколко скрипта, два конфигурационни файла и генерирах необходимите сертификати (тъй като клиентът на смартфона работи само с сертификати), получи се обикновена реализация на OpenVPN сървър.
Основният скрипт на компютъра
# cat vpn11.sh#!/bin/bash
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
ABSOLUTE_FILENAME=`readlink -f "$0"`
DIR=`dirname "$ABSOLUTE_FILENAME"`
localport=11111
until [[ $a ]]; do
address=`stun stun.sipnet.ru -v -p $localport 2>&1 | grep "MappedAddress" | sort | uniq | head -n 1 | sed 's/:/ /g' | awk '{print $3" "$4}'`
ip=`echo "$address" | awk {'print $1'}`
port=`echo "$address" | awk {'print $2'}`
srv="openvpn --config $DIR/server.conf --port $localport --daemon"
$srv
echo "$(date) Сервер запущен с внешним адресом $ip:$port"
$DIR/sendemail.sh "OpenVPN-Server" "$ip:$port"
sleep 1
openvpn --config $DIR/client.conf --remote $ip --port $port
echo "$(date) Cоединение клиента с сервером разорвано"
for i in `ps xa | grep "$srv" | grep -v grep | awk '{print $1}'`; do
kill $i && echo "$(date) Завершен процесс сервера $i ($srv)"
done
echo "Жду 15 сек"
sleep 15
doneСкрипт за изпращане на данни по имейл:
# cat sendemail.sh #!/bin/bash
from="От кого"
pass="Пароль"
to="Кому"
theme="$1"
message="$2"
server="smtp.yandex.ru:587"
sendEmail -o tls=yes -f "$from" -t "$to" -s "$server" -xu "$from" -xp "$pass" -u "$theme" -m "$message"Конфигурационен файл на сървъра:
# cat server.confproto udp
dev tun
ca /home/vpn11-srv/ca.crt
cert /home/vpn11-srv/server.crt
key /home/vpn11-srv/server.key
dh /home/vpn11-srv/dh2048.pem
server 10.2.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
tls-server
tls-auth /home/vpn11-srv/ta.key 0
tls-timeout 60
auth SHA256
cipher AES-256-CBC
client-to-client
keepalive 10 30
comp-lzo
max-clients 10
user nobody
group nogroup
persist-key
persist-tun
log /var/log/vpn11-server.log
verb 3
mute 20Конфигурационен файл на клиента:
# cat client.confclient
dev tun
proto udp
ca "/home/vpn11-srv/ca.crt"
cert "/home/vpn11-srv/client1.crt"
key "/home/vpn11-srv/client1.key"
tls-client
tls-auth "/home/vpn11-srv/ta.key" 1
auth SHA256
cipher AES-256-CBC
auth-nocache
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
log /var/log/vpn11-clent.log
verb 3
mute 20
ping 10
ping-exit 30Сертификатите бяха генерирани по тази статия.
Стартиране на скрипта:
# ./vpn11.shПреди това го направих изпълним
# chmod +x vpn11.shОт страна на смартфона
Инсталирах приложението OpenVPN за Android, копирайки конфигурационния файл, сертификатите и настройвайки го, се получи:
На смартфона проверявам пощата
Коригирам номера на порта в настройките
Стартирам клиента и се свързвам
В процеса на писане на статията прехвърлих конфигурацията от компютъра на Raspberry Pi 3 и опитах да пусна всичко това на LTE модем, но не стана! Резултатът от командата
# stun stun.ekiga.net -p 11111STUN client version 0.97
Primary: Independent Mapping, Port Dependent Filter, random port, will hairpin
Return value is 0x000006
стойността Port Dependent Filter не позволи на системата да стартира.
Но домашният доставчик без проблем разреши на системата да стартира на Raspberry Pi 3.
В комбинация с уеб камера, с VLC за
създаване на RTSP поток от уеб камерата
$ cvlc v4l2:///dev/video0:chroma=h264 :input-slave=alsa://hw:1,0 --sout '#transcode{vcodec=x264,venc=x264{preset=ultrafast,profile=baseline,level=31},vb=2048,fps=12,scale=1,acodec=mpga,ab=128,channels=2,samplerate=44100,scodec=none}:rtp{sdp=rtsp://10.2.0.1:8554/}' --no-sout-all --sout-keepи VLC на смартфона за гледане (поток rtsp://10.2.0.1:8554/), получи се добра система за видеонаблюдение на разстояние, може също така да се надигне Samba, да се маршрутизира трафик през VPN, дистанционно управление на компютъра и много други...
Извод
Както показа практиката, за организиране на VPN-сървър може да се мине и без външен IP адрес, за който трябва да се плаща, както и наеман VPS/VDS. Но всичко зависи от доставчика. Разбира се, бих искал да получа повече информация за различни доставчици и типовете използвани NAT, но това е само началото...
Благодаря за вниманието!
Източник: habr.com
