¿Por qué interfaz de red sale el tráfico UDP?

[spanish]

Sobre el post anterior…

Me ha pasado ya más de una vez que cuando un servidor tiene más de un interfaz de red (sean físicos o virtuales) y tiene algún servicio sobre UDP, aunque reciba tráfico UDP por todos los interfaces, cuando contesta siempre lo hace por el interfaz que da a su gateway, con la IP de ese interfaz.

Es decir, simplificando imaginaos que tenemos algo más o menos así:

esquemaredudp.png

si recibimos un paquete por el interfaz de la izq., se responde por ese mismo interfaz con IPa. Pero si lo recibimos por el de la drcha., también se responde por la izq. con IPa. ¿Y qué pasa cuando el cliente recibe la respuesta correcta pero desde una IP que no tiene nada que ver con la del servidor al que le ha preguntado? ¿Con un direccionamiento completamente distinto? ¿Y si, además, entre cliente y servidor hay algún firewall haciendo NAT?

Esto por supuesto desbarata el servicio. En el caso que comentaba ayer era una VPN L2TP, y ni siquiera se conseguía establecer la conexión. En otras ocasiones me ha pasado esto con un servidor de DNS, y según el sistema operativo del cliente aceptaba sin más la respuesta aunque viniera desde una IP incorrecta, no lo hacía y presentaba una alerta de seguridad.

Supongo que esto en parte es culpa de cada implementación en concreto, digo yo que en programación se podrá ver a qué IP iba dirigido el paquete que se acaba de recibir y la respuesta enviarla por el interfaz y con la IP que toca, pero por lo visto o esto no es así o no siempre se tiene en cuenta.

Ayer con ayuda de un compañero que controla de iptables y tal lo solucionamos así:

  • con iptables, detectar el tráfico que queremos «redirigir» por otro interfaz y marcarlo
  • en función de esa marca, definir una tabla de rutas con «ip rule/route» y encaminarlo a un GW en el otro extremo
  • de nuevo con iptables y aprovechando la marca anterior, hacer NAT de la dirección de origen

Un ejemplo para redirigir tráfico UDP en función del puerto $PORT con la IP $IPb a través de la puerta de enlace $GWb sería:

[/spanish]
[english]

It has happened to me a cuple of times when dealing with UDP-based services that, when a server has more than one network interface (either physical or virtual), all the UDP traffic goes out through the interface on the default gateway’s network segment and with that interface’s IP address, even when the original request came through the other interface and was directed to the other IP address.

Graphically, say you have something similar to this:

esquemaredudp.png

If the server receives a request on IPa, the response goes out through that same interface and with origin IPa. But if the request arrives on IPb through the interface on the right, the response is also sent through the left interface with IPa. And what happens when the client receives a response from an incorrect IP address? Maybe even from a completely different network segment? And if there’s a fw in between doing NAT?

Of course this breaks the service. This week I’ve had this very problem setting up a L2TP VPN, and it was impossible to establish the tunnel. On some other ocasions I’ve had a similar problem with a DNS server, and the outcome depended on the client’s operating system: some OSes accepted the DNS response even when it came from a different address than that of the server originally queried; others would reject it and even raise a security alert.

I guess that this behaviour can be programmatically controlled. I mean, when you receive a packet you can check the IP address it was sent to, and craft the response so that it gets sent with that same address from the right interface. But it seems that this is seldom done.

Yesterday I got around this issue with the help of iptables and a coworker more knowledgeable than me on routing issues:

  • with iptables, you can detect the traffic to «redirect» and mark it
  • depending on this mark and using «ip rule/route», have a special routing table that sends this traffic to the proper GW/through the right interface.
  • with iptables again and using the previous mark, do a SNAT on the origin IP address

An example for redirecting all UDP traffic from a certain $PORT using IP address $IPb through gateway $GWb would be:

[/english]


echo 255 local > /etc/iproute2/rt_tables
echo 254 main >> /etc/iproute2/rt_tables
echo 253 default >> /etc/iproute2/rt_tables
echo 0 unspec >> /etc/iproute2/rt_tables
echo 200 udp >> /etc/iproute2/rt_tables
ip rule add fwmark 1 table udp
ip route add default via $GWb dev eth0 table l2tp
iptables -t mangle -A OUTPUT -p udp -m udp --sport $PORT -j MARK --set-mark 0x1
iptables -t nat -A POSTROUTING -m mark --mark 0x1 -j SNAT --to-source $IPb

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.