/

Enrutar Trafico Con Iptables

Created 2020-03-02 Modifyed 2020-03-02
1040 Words

En alguna ocasión, es posible que necesitemos que el tráfico que recibe una máquina en un determinado puerto, sea redirigido a otra máquina diferente.

Por poner un ejemplo, pillamos un servidor en cualquier proveedor. El proveedor nos da una ip pública a través de la cual podemos acceder a dicho server.

Pero dentro del servidor, queremos montar un sistema de contenedores con lxc. En el ejemplo de la foto, se puede ver, que el servidor contratado tiene la ip 82.85.85.82 (más adelante crearemos un contenedor llamado host para simularlo) y dentro de el, hemos creado tres contenedores, y cada uno de ellos tendrá un servicio diferente. En uno pondremos un apache, en otro un nginx, y en otro un servidor dns.

Bien, nuestro objetivo, es que el trafico que reciba nuestro host por el puerto 80, se redirija al contenedor con el servicio apache (lxc0), el tráfico recibido en el host por el puerto 8080, lo enrutaremos al lxc que contiene el nginx (lxc1), y el tráfico recibido por el host en el puerto 53 udp sea redirigido al contenedor que tiene el servicio dns (lxc2).

athos@athos-Z97P-D3:~$ lxc launch ubuntu:16.04 lxc0
Creating lxc0
Starting lxc0
athos@athos-Z97P-D3:~$ lxc launch ubuntu:16.04 lxc1
Creating lxc1
Starting lxc1
athos@athos-Z97P-D3:~$ lxc launch ubuntu:16.04 lxc2
Creating lxc2
Starting lxc2
athos@athos-Z97P-D3:~$ lxc list | grep lxc
| lxc0       | RUNNING | 10.163.200.199 (eth0) | fd42:def5:a1ff:ca5:216:3eff:fe5e:3885 (eth0) | PERSISTENT | 0         |
| lxc1       | RUNNING | 10.163.200.79 (eth0)  | fd42:def5:a1ff:ca5:216:3eff:fe22:c9ca (eth0) | PERSISTENT | 0         |
| lxc2       | RUNNING | 10.163.200.134 (eth0) | fd42:def5:a1ff:ca5:216:3eff:fe95:68dc (eth0) | PERSISTENT | 0         |
athos@athos-Z97P-D3:~$ 

Bueno, ahí se pueden ver las ips internas que tendrá cada uno de nuestros contenedores (no coinciden con la imagen de arriba)

Instalamos los servicios en cada uno de los contenedores y podemos comprobar que cada contenedor nos da la respuesta esperada.

lxc0:

lxc1:

lxc2:

athos@athos-Z97P-D3:~/Documents/athosnetwork.es/front$ dig example.com @10.163.200.134

; <<>> DiG 9.10.3-P4-Ubuntu <<>> example.com @10.163.200.134
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35944
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;example.com.			IN	A

;; ANSWER SECTION:
example.com.		3600	IN	A	127.0.0.2

;; Query time: 6 msec
;; SERVER: 10.163.200.134#53(10.163.200.134)
;; WHEN: Mon Mar 02 22:18:11 CET 2020
;; MSG SIZE  rcvd: 67

Ahora voy a crear otro contenedor llamado host, que simulará nuestro host (valga la redundancia).

| host       | RUNNING | 10.163.200.252 (eth0) | fd42:def5:a1ff:ca5:216:3eff:fed0:c0a (eth0)  | PERSISTENT | 0         |

Hacemos las llamadas a este contenedor para ver su respuesta y como podemos ver, de momento si accedemos a esa ip no nos responde nada

Y si le consultamos la dns anteriormente tampoco

athos@athos-Z97P-D3:~/Documents/athosnetwork.es/front$ dig example.com @10.163.200.252

; <<>> DiG 9.10.3-P4-Ubuntu <<>> example.com @10.163.200.252
;; global options: +cmd
;; connection timed out; no servers could be reached

Ahora, vamos a hacer, que al acceder al host puerto 80 redirija el tráfico al contenedor lxc0

root@host:~# iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.163.200.199:80
root@host:~# iptables -t nat -A POSTROUTING -j MASQUERADE 
root@host:~# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DNAT       tcp  --  anywhere             anywhere             tcp dpt:http to:10.163.200.199:80

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere   

Y ahora vemos que si nos redirecciona al contenedor que tiene el apache (lxc0)

Bien, el segundo paso, es hacer que cuando accedamos al puerto 8080 del host, nos redireccione al nginx(lxc1)

root@host:~# iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.163.200.79:80
root@host:~# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DNAT       tcp  --  anywhere             anywhere             tcp dpt:http to:10.163.200.199:80
DNAT       tcp  --  anywhere             anywhere             tcp dpt:http-alt to:10.163.200.79:80

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere            
MASQUERADE  all  --  anywhere             anywhere            

Y otra vez vemos que redirige bien

El tercer paso es hacer lo mismo con el puerto udp 53, tiene que redirigir al contenedor lxc2

root@host:~# iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to-destination 10.163.200.134
root@host:~# iptables -L -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
DNAT       tcp  --  anywhere             anywhere             tcp dpt:http to:10.163.200.199:80
DNAT       tcp  --  anywhere             anywhere             tcp dpt:http-alt to:10.163.200.79:80
DNAT       udp  --  anywhere             anywhere             udp dpt:domain to:10.163.200.134

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  anywhere             anywhere            
MASQUERADE  all  --  anywhere             anywhere            

Y la prueba es correcta

athos@athos-Z97P-D3:~$ dig example.com @10.163.200.252

; <<>> DiG 9.10.3-P4-Ubuntu <<>> example.com @10.163.200.252
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3046
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;example.com.			IN	A

;; ANSWER SECTION:
example.com.		3600	IN	A	127.0.0.2

;; Query time: 2 msec
;; SERVER: 10.163.200.252#53(10.163.200.252)
;; WHEN: Mon Mar 02 22:30:28 CET 2020
;; MSG SIZE  rcvd: 67


Resumiendo, con estas dos sencillas reglas podemos enrutar tráfico entre varias maquinas

iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.163.200.103:80

iptables -t nat -A POSTROUTING -j MASQUERADE