Creando túneles TCP/IP (port forwarding) con SSH: Los 8 escenarios posibles usando OpenSSH

Fuente

http://endebian.wordpress.com/2012/02/08/creando-tuneles-tcpip-port-forwarding-con-ssh-los-8-escenarios-posibles-usando-openssh/

La función típica del protocolo de red Secure Shell (SSH) es acceder en modo terminal a un sistema remoto y ejecutar allí comandos de forma segura gracias a que los datos van cifrados. Pero además, a través de esa conexión de datos segura, es posible crear túneles (reenviar puertos / port forwarding) entre los extremos conectados de forma que las conexiones TCP/IP se encauzan a través de la conexión SSH con lo que podemos conseguir saltarnos cualquier firewall o bloqueo de puertos siempre que tengamos la posibilidad de conectar con SSH.

En esta entrada no entraremos en los detalles del reenvío de puertos, sino que pretende ser una chuleta, una referencia rápida (cheat sheet) de cómo reenviar puertos TCP con OpenSSH en los 8 diferentes escenarios que se pueden dar. Otros clientes de SSH como PuTTY también permiten el reenvío de puertos, pero la configuración se hará con un interfaz gráfico. Nosotros nos centraremos en OpenSSH.

En los siguientes ejemplos y situaciones supondremos que tenemos una red externa y una red interna y entre ambas redes, la única conexión posible es una conexión SSH entre el nodo de la red external externo1 y el nodo de la red interna interno1. El nodo externo2 está en la red externa y tiene conectividad total con externo1. El nodo interno2 está en la red interna y tiene conectividad total con interno1.


Túneles SSH: Sin túnel




Escenario 1: Usar en externo1 un servicio TCP ofrecido por interno1 (Local port forwarding / bind_address=localhost / host=localhost)

El sistema externo1 se puede conectar al sistema interno1 a través de OpenSSH y además quiere conectarse al servidor de VNC (puerto 5900) del sistema interno1:

Túneles SSH: Escenario 1



Lo conseguiremos con este comando:

externo1 $ ssh -L 7900:localhost:5900 usuario@interno1



Ahora en el sistema externo1 podemos comprobar que el puerto 7900 está esperando conexiones:

externo1 $ netstat -ltn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
...
tcp 0 0 127.0.0.1:7900 0.0.0.0:* LISTEN
...



Sólo necesitamos ejecutar ahora en externo1:

externo1 $ vncviewer localhost::7900



para conectarnos al servidor VNC de interno1.

Nota: Esta forma de cambiar el puerto del no está documentada en el man vncviewer. Aparece en: About VNCViewer configuration of the output TCP port. También es así como lo hace el vncviewer de TightVNC.

Escenario 2: Usar en externo2 un servicio TCP ofrecido por interno1 (Local port forwarding / bind_address=0.0.0.0 / host=localhost)

Esta vez partimos de una situación similar a la anterior pero ahora queremos que sea externo2 quien se conecte al servidor VNC de interno1:

Túneles SSH: Escenario 2



El comando adecuado sería este:

externo1 $ ssh -L 0.0.0.0:7900:localhost:5900 usuario@interno1



Es similar al del primer escenario; pero en aquél, si nos fijamos en la salida del netstat, el puerto 7900 se había asociado a la dirección de localhost, a la 127.0.0.1, por lo que sólo procesos locales podían conectarse a él. Esta vez especificamos que el puerto se asocie a 0.0.0.0, para que el sistema acepte conexiones a cualquier IP local de la máquina:

externo1 $ netstat -ltn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
...
tcp 0 0 0.0.0.0:7900 0.0.0.0:* LISTEN
...



De modo que ahora, desde externo2, podemos ejecutar:

externo2 $ vncviewer externo1::7900



para conectarnos al servidor VNC de interno1.

En lugar de especificar la IP 0.0.0.0, también podríamos usar la opción -g (Allows remote hosts to connect to local forwarded ports) así:

externo1 $ ssh -g -L 7900:localhost:5900 usuario@interno1



con exactamente el mismo resultado que el comando anterior:

externo1 $ ssh -L 0.0.0.0:7900:localhost:5900 usuario@interno1



Por otra parte, si hubiéramos querido restringir la conexión a sólo alguna de las IPs locales del sistema, podríamos haber sido más específicos:

externo1 $ ssh -L 192.168.24.80:7900:localhost:5900 usuario@interno1

externo1 $ netstat -ltn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
...
tcp 0 0 192.168.24.80:7900 0.0.0.0:* LISTEN
...



Escenario 3: Usar en interno1 un servicio TCP ofrecido por externo1 (Remote port forwarding / bind_address=localhost / host=localhost)

En el primer escenario, era el propio sistema con el servidor de SSH el que ofrecía otro servicio. Ahora el sistema con el cliente de SSH es el que ofrece el servicio que el sistema con el servidor de SSH quiere usar:

Túneles SSH: Escenario 3



El comando que usaremos es el mismo que en el primer escenario cambiando el parámetro -L por -R:

externo1 $ ssh -R 7900:localhost:5900 usuario@interno1



Y ahora donde veremos que tenemos el puerto 7900 escuchando es en interno1:

interno1 $ netstat -lnt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
...
tcp 0 0 127.0.0.1:7900 0.0.0.0:* LISTEN
...



De modo que ahora desde interno1 podemos usar el servidor VNC de externo1 así:

interno1 $ vncviewer localhost::7900



Escenario 4: Usar en interno2 un servicio TCP ofrecido por externo1 (Remote port forwarding / bind_address=0.0.0.0 / host=localhost)

Similar al tercer escenario pero ahora, igual que hacíamos en el segundo escenario, asociaremos el puerto reenviado a la IP 0.0.0.0 para que otros nodos puedan usar el servicio:

Túneles SSH: Escenario 4



El comando apropiado es:

externo1 $ ssh -R 0.0.0.0:7900:localhost:5900 usuario@interno1



Sin embargo, es importante entender que, por motivos de seguridad, esto no funcionará si en la configuración del servidor de SSH no modificamos el valor del parámetroGatewayPorts que por defecto está a no:

GatewayPorts

Specifies whether remote hosts are allowed to connect to ports forwarded for the client. By default, sshd(8) binds remote port forwardings to the loopback address. This prevents other remote hosts from connecting to forwarded ports. GatewayPorts can be used to specify that sshd should allow remote port forwardings to bind to non-loopback addresses, thus allowing other hosts to connect. The argument may be “no” to force remote port forwardings to be available to the local host only, “yes” to force remote port forwardings to bind to the wildcard address, or “clientspecified” to allow the client to select the address to which the forwarding is bound. The default is “no”.



Si no tenemos la posibilidad de modificar la configuración del servidor, no podremos usar este tipo de reenvío de puertos. Al menos no de forma sencilla, ya que, si no hay otros impedimentos, un usuario puede abrir un puerto (>1024) para escuchar conexiones externas y reenviar dicha petición a localhost:7900. Esto se podría hacer, por ejemplo, con netcat (Debian #310431: sshd_config should warn about GatewayPorts workaround.)

De modo que en el /etc/ssh/sshd_config añadiremos:

GatewayPorts clientspecified



tras lo cual tendremos que releer la configuración con “sudo /etc/init.d/ssh reload” (Debian y Ubuntu).

Comprobamos que interno1 está escuchando peticiones de todas las IPs:

interno1 $ netstat -ltn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
...
tcp 0 0 0.0.0.0:7900 0.0.0.0:* LISTEN
...



Y ya podremos usar el servicio de VNC desde interno2:

interno2 $ vncviewer interno1::7900



Escenario 5: Usar en externo1 un servicio TCP ofrecido por interno2 (Local port forwarding / bind_address=localhost / host=interno2)

Túneles SSH: Escenario 5



En este escenario usaremos el siguiente comando:

externo1 $ ssh -L 7900:interno2:5900 usuario@interno1



Y accederemos al servicio ejecutando en externo1 el comando:

externo1 $ vncviewer localhost::7900



Escenario 6: Usar en interno1 un servicio TCP ofrecido por externo2 (Remote port forwarding / bind_address=localhost / host=externo2)

Túneles SSH: Escenario 6



En este escenario usaremos el siguiente comando:

externo1 $ ssh -R 7900:externo2:5900 usuario@interno1



Y accederemos al servicio ejecutando en interno1 el comando:

interno1 $ vncviewer localhost::7900



Escenario 7: Usar en externo2 un servicio TCP ofrecido por interno2 (Local port forwarding / bind_address=0.0.0.0 / host=interno2)

Túneles SSH: Escenario 7



En este escenario usaremos el siguiente comando:

externo1 $ ssh -L 0.0.0.0:7900:interno2:5900 usuario@interno1



o alternativamente:

externo1 $ ssh -g -L 7900:interno2:5900 usuario@interno1



Y accederemos al servicio ejecutando en externo2 el comando:

externo2 $ vncviewer externo1::7900



Escenario 8: Usar en interno2 un servicio TCP ofrecido por externo2 (Remote port forwarding / bind_address=0.0.0.0 / host=externo2)

Túneles SSH: Escenario 8



En este escenario usaremos el siguiente comando:

externo1 $ ssh -R 0.0.0.0:7900:externo2:5900 usuario@interno1



El servidor SSH tiene que estar configurado con “GatewayPorts clientspecified“, como hemos visto en el escenario 4.

Y accederemos al servicio ejecutando en interno2 el comando:

interno2 $ vncviewer interno1::7900



Actualización 26/10/2010:

Si queremos crear muchos túneles a la vez, puede ser cómodo usar un fichero de configuración en lugar de componer un comando larguísimo. Imaginemos que nuestro único punto de entrada a una red es por SSH y necesitamos crearnos túneles para acceder a los diferentes servidores de la red por SSH, VNC o Remote Desktop. Podríamos componer un fichero como el siguiente con todas las redirecciones que vamos a necesitar (en relación al servidor de SOCKS que se menciona: Reenvío dinámico de puertos / montar un servidor SOCKS con SSH):

# Servidor SOCKS
DynamicForward 1080

# Redirecciones SSH
LocalForward 2221 servidorlinux1:22
LocalForward 2222 servidorlinux2:22
LocalForward 2223 172.16.23.45:22
LocalForward 2224 172.16.23.48:22

# Redirecciones RDP para sistemas Windows
LocalForward 3391 servidorwindows1:3389
LocalForward 3392 servidorwindows2:3389

# Redirecciones VNC para sistemas con "vncserver"
LocalForward 5902 servidorlinux1:5901
LocalForward 5903 172.16.23.45:5901



y sólo necesitamos ejecutar esto para crear todas las redirecciones:

externo1 $ ssh -F $HOME/redirecciones usuario@interno1



:wq