Artículo sobre cómo logré iniciar un servidor VPN detrás del NAT de un proveedor doméstico (sin una dirección IP pública). De inmediato aclaro que la funcionalidad de esta implementación depende directamente del tipo de NAT que use su proveedor, así como del enrutador..
Así, surgió la necesidad de conectarme desde mi smartphone Android a la computadora doméstica, ambos dispositivos conectados a Internet a través de NATs de proveedor, además, la computadora está conectada a través de un enrutador doméstico que también NATea las conexiones.
No se consideró el esquema clásico utilizando VPS/VDS arrendado con una dirección IP pública, así como alquilar una dirección IP pública de un proveedor, por varias razones.
Considerando la experiencia de artículos anteriores, realizando varios experimentos con STUNs y NATs de proveedores. Decidí realizar un pequeño experimento ejecutando el comando en el enrutador doméstico que funciona con el firmware OpenWRT:
$ stun stun.sipnet.ruobtuve el resultado:
Versión del cliente STUN 0.97
Primario: Mapeo Independiente, Filtro Independiente, puerto aleatorio, se hará hairpin
El valor de retorno es 0x000002
Traducción literal:
Mapeo Independiente — mapeo independiente
Filtro Independiente — filtro independiente
puerto aleatorio — puerto aleatorio
se hará hairpin — habrá hairpin
Ejecutando un comando similar en mi PC, obtuve:
Versión del cliente STUN 0.97
Primario: Mapeo Independiente, Filtro Dependiente del Puerto, puerto aleatorio, se hará hairpin
El valor de retorno es 0x000006
Filtro Dependiente del Puerto — filtro dependiente del puerto
La diferencia en los resultados de los comandos indicaba que el enrutador doméstico estaba contribuyendo al proceso de traducción de paquetes de Internet, lo que se manifestaba en que al ejecutar el comando en la computadora:
stun stun.sipnet.ru -p 11111 -vobtenía el resultado:
…
MappedAddress = XX.1XX.1X4.2XX:4398
…
en ese momento se abría una sesión UDP por un tiempo, si en ese momento se enviaba una solicitud UDP (por ejemplo: netcat XX.1XX.1X4.2XX 4398 -u), la solicitud llegaba al enrutador doméstico, como confirmó TCPDump ejecutado en él, pero la solicitud no alcanzaba la computadora — IPtables como traductor NAT en el enrutador la descartaba.

Pero el hecho de que la solicitud UDP pasara a través del NAT del proveedor daba esperanza de éxito. Como el enrutador está bajo mi jurisdicción, resolví el problema re rutando el puerto UDP/11111 a la computadora:
iptables -t nat -A PREROUTING -i eth1 -p udp -d 10.1XX.2XX.XXX --dport 11111 -j DNAT --to-destination 192.168.X.XXXDe esta manera, obtuve la posibilidad de iniciar una sesión UDP y recibir solicitudes de Internet desde cualquier dirección IP. En ese momento, inicié el servidor OpenVPN (previamente configurado) escuchando en el puerto UDP/11111, indiqué en el smartphone la dirección IP externa y el puerto (XX.1XX.1X4.2XX:4398) y me conecté con éxito desde el smartphone a la computadora. Sin embargo, en esta implementación surgió un problema, era necesario mantener la sesión UDP hasta que el cliente de OpenVPN se conectara al servidor; la opción de iniciar periódicamente el cliente STUN no me gustó, ya que no quería sobrecargar los servidores STUN innecesariamente.
También noté la anotación "se hará hairpin — habrá hairpin"; este modo
Hairpinning permite que una máquina en la red local detrás de un NAT acceda a otra máquina en la misma red usando la dirección externa del enrutador.

Al final, resolví el problema de mantener la sesión UDP de manera simple: inicié el cliente en la misma computadora que el servidor.
Esto funcionaba así:
- iniciaba el cliente STUN con el puerto local 11111
- obtenía una respuesta con la dirección IP externa y el puerto XX.1XX.1X4.2XX:4398
- enviaba datos con la dirección IP externa y el puerto al correo (puede ser cualquier otro servicio), configurado en el smartphone
- iniciaba el servidor OpenVPN en la computadora escuchando en el puerto UDP/11111
- iniciaba el cliente OpenVPN en la computadora indicando XX.1XX.1X4.2XX:4398 para la conexión
- en cualquier momento, iniciaba el cliente OpenVPN en el smartphone indicando la dirección IP y el puerto (en mi caso la dirección IP no cambiaba) para la conexión

Así, obtuve la posibilidad de conectarme a mi computadora desde el smartphone. Esta implementación permite conectar cualquier cliente OpenVPN.
Práctica
Se necesitará:
# apt install openvpn stun-client sendemailEscribiendo un par de scripts, un par de archivos de configuración y generando los certificados necesarios (ya que el cliente en el smartphone funciona solo con certificados), obtuve una implementación estándar del servidor OpenVPN.
El script principal en la computadora
# 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
doneScript para enviar datos por correo:
# 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"Archivo de configuración del servidor:
# 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 20Archivo de configuración del cliente:
# cat client.confcliente
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 30La generación de certificados se realizó a partir de este artículo.
Ejecutando el script:
# ./vpn11.shHaciendo que sea ejecutable previamente
# chmod +x vpn11.shEn el lado del teléfono inteligente
Instalando la aplicación OpenVPN para Android, copiando el archivo de configuración, certificados y configurándolo, quedó así:
En el teléfono inteligente estoy revisando el correo
Corrijo el número de puerto en la configuración
Inicio el cliente y me conecto
Mientras escribía este artículo, transferí la configuración de la computadora a una Raspberry Pi 3 y traté de ejecutar todo esto en un módem LTE, ¡pero no funcionó! El resultado del comando
# stun stun.ekiga.net -p 11111Versión del cliente STUN 0.97
Primario: Mapeo Independiente, Filtro Dependiente del Puerto, puerto aleatorio, se hará hairpin
El valor de retorno es 0x000006
valor Filtro dependiente del puerto no permitió que el sistema se iniciara.
Pero el proveedor doméstico permitió que el sistema se iniciara sin problemas en la Raspberry Pi 3.
Junto con la cámara web, usando VLC para
crear un flujo RTSP desde la cámara web
$ 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-keepy VLC en el teléfono inteligente para ver (flujo rtsp://10.2.0.1:8554/), se obtuvo un buen sistema de videovigilancia a distancia, también se puede levantar Samba, enrutar tráfico a través de VPN, controlar remotamente la computadora y mucho más...
Salida
Como ha mostrado la práctica, se puede organizar un servidor VPN sin una dirección IP externa por la que hay que pagar, al igual que por la que se alquila VPS/VDS. Pero todo depende del proveedor. Por supuesto, me gustaría obtener más información sobre varios proveedores y tipos de NAT utilizados, pero eso es solo el comienzo...
¡Gracias por su atención!
Fuente: habr.com
