Enrutamiento para dummies

jue, 27 sep 2012 by Foron

Si hay algo sobre lo que no hubiese querido escribir nunca en este blog es sobre el enrutamiento básico en Linux. Hace 10 años quizá hubiese sido más interesante, pero no ahora. Aún así, en este mundo del botón y del siguiente siguiente no tengo nada claro que la gente sepa exactamente lo que hay debajo de un "route -n", así que vamos a ello. Eso sí, para dummies. De hecho, me voy a pasar de básico, con lo que escribiré cosas que en condiciones normales merecerían una discusión. En fin.

Empezamos con el viejo comando "route -n", tan simple como siempre:

  # route -n
  Kernel IP routing table
  Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
  0.0.0.0         10.213.208.1    0.0.0.0         UG    0      0        0 eth0
  10.213.208.0    0.0.0.0         255.255.240.0   U     0      0        0 eth0
  192.168.10.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
  192.168.11.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1

Lo normal cuando usamos la combinación route/ifconfig en la mayoría de las distribuciones, una puerta de enlace, una red para llegar a esa puerta de enlace a través de un dispositivo, y luego, en este caso, nuestras redes locales.

¿No hay nada más?

Pues sí, hay mucho más, claro. Esto no es más que una mínima porción de la tabla de enrutamiento de vuestro kernel favorito. Vamos a verlo pasando a la utilidad "ip", la pobre, que lleva tanto tiempo existiendo, pero que tan poco se usa (solo comparable al uso eterno de los aliases de IPs, pero esta es otra historia).

  # ip route ls
  default via 10.213.208.1 dev eth0
  10.213.208.0/20 dev eth0  proto kernel  scope link  src 10.213.218.162
  192.168.10.0/24 dev eth1  proto kernel  scope link  src 192.168.10.1
  192.168.11.0/24 dev eth1  proto kernel  scope link  src 192.168.11.1

¿Todo este rollo para ver lo mismo con un formato diferente?

Sí, porque estamos viendo, una vez más, solo una parte de la tabla de enrutamiento. ¡Hola "ip rule"!

  # ip rule ls
  0:      from all lookup local
  32766:  from all lookup main
  32767:  from all lookup default

Y ahora, sorpresa:

  # ip route ls table default
  _vacio_
  # ip route ls table main
  default via 10.213.208.1 dev eth0
  10.213.208.0/20 dev eth0  proto kernel  scope link  src 10.213.218.162
  192.168.10.0/24 dev eth1  proto kernel  scope link  src 192.168.10.1
  192.168.11.0/24 dev eth1  proto kernel  scope link  src 192.168.11.1
  # ip route ls table local
  broadcast 10.213.208.0 dev eth0  proto kernel  scope link  src 10.213.218.162
  local 10.213.218.162 dev eth0  proto kernel  scope host  src 10.213.218.162
  broadcast 10.213.223.255 dev eth0  proto kernel  scope link  src 10.213.218.162
  broadcast 127.0.0.0 dev lo  proto kernel  scope link  src 127.0.0.1
  local 127.0.0.0/8 dev lo  proto kernel  scope host  src 127.0.0.1
  local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1
  broadcast 127.255.255.255 dev lo  proto kernel  scope link  src 127.0.0.1
  broadcast 192.168.10.0 dev eth1  proto kernel  scope link  src 192.168.10.1
  local 192.168.10.1 dev eth1  proto kernel  scope host  src 192.168.10.1
  broadcast 192.168.10.255 dev eth1  proto kernel  scope link  src 192.168.10.1
  broadcast 192.168.11.0 dev eth1  proto kernel  scope link  src 192.168.11.1
  local 192.168.11.1 dev eth1  proto kernel  scope host  src 192.168.11.1
  broadcast 192.168.11.255 dev eth1  proto kernel  scope link  src 192.168.11.1

Vaya sorpresa... Lo que vemos con un "route -n" es en realidad la tabla "main", que además, por ese 32766, parece tener menos prioridad que esa tabla "local" tan curiosa. Fácil de leer, ¿Verdad? Los broadcast los conocemos todos pero, ¿Y las rutas de tipo local? Sacado literalmente del manual (Sí, todo esto está en el manual de ip route!!!): "the destinations are assigned to this host. The packets are looped back and delivered locally". Y con esto hemos terminado, solo nos queda saber que "proto kernel" es la configuración más normal si no usamos software de enrutamiento (quagga, por ejemplo), y que "scope link" es para rutas broadcast y unicast mientras que "scope host" es para las locales.

Revisad los manuales de "ip rule" e "ip route", por favor, y entended cada entrada de estas tablas y reglas.

Ya que estamos, vamos a jugar un poco con todo esto que hemos visto, aunque seguimos en "modo sencillo" y no nos vamos a complicar demasiado. Solo unas ideas.

Nota: No hagáis caso a las IPs que uso a partir de aquí. Intentaré mantenerlas coherentes, pero me las estoy inventando sobre la marcha.

Tenemos reglas en "ip rule", tenemos tablas de enrutamiento, ... ¿Apostamos a que todo esto es modificable/configurable? ¡Por supuesto!

Vamos a vuestra distribución Debian favorita, y busquemos el fichero "/etc/iproute2/rt_tables"

  # cat /etc/iproute2/rt_tables
  #
  # reserved values
  #
  255     local
  254     main
  253     default
  0       unspec
  #
  # local
  #
  #1      inr.ruhep

  1001 proveedor1
  1002 proveedor2

No, en vuestros ficheros no van a estar las líneas "proveedor1" y "proveedor2". Las he añadido yo, alegremente. Donde estoy escribiendo este post no hay múltiples lineas de acceso a Internet, pero me voy a inventar, como ejemplo, que en mi equipo hay dos ADSL de proveedores diferentes. Uno me ha asignado la IP 192.0.2.33/24, con puerta de enlace 192.0.2.1, y el segundo 198.51.100.33/24, con gateway 198.51.100.1.

Como ya sabemos todo sobre enrutamiento, queremos mandar a los comerciales a través del primer proveedor, y a los técnicos a través del segundo. Supongamos que los comerciales están todos en la subred "172.16.0.0/24", y los técnicos en "172.16.1.0/24".

¡Juguemos con ip rule!

  # ip rule add from 172.16.0.0/24 table proveedor1
  # ip rule add from 172.16.1.0/24 table proveedor2
  # ip rule ls
  0:      from all lookup local
  32764:  from 172.16.1.0/24 lookup proveedor2
  32765:  from 172.16.0.0/24 lookup proveedor1
  32766:  from all lookup main
  32767:  from all lookup default

Efectivamente, hemos separado el tráfico en dos tablas, por ahora vacías. Es el turno de ip route:

  # ip route add 172.16.0.0/16 dev eth0 src 172.16.0.1 table proveedor1
  # ip route add 192.0.2.0/24 dev eth1 src 192.0.2.33 table proveedor1
  # ip route add default via 192.0.2.1 table proveedor1

  # ip route add 172.16.0.0/16 dev eth0 src 172.16.0.1 table proveedor2
  # ip route add 198.51.100.0/24 dev eth2 src 198.51.100.33 table proveedor2
  # ip route add default via 198.51.100.1 table proveedor2

¿Veis lo que hemos hecho? Hemos asignado dos puertas de enlace por defecto diferentes, en base al origen, por lo que todo lo que venga desde 172.16.0.0/24 irá por 192.0.2.1, y lo originado en 172.16.1.0/24 por 198.51.100.1. Por si fuera poco, el tráfico que no entre en ninguna de estas dos subredes accederá a la tabla main (from all lookup main), y con ello usará la puerta de enlace por defecto de toda la vida, esa que pensábamos que era única.

Y ya está, aquí lo dejo, aunque debo recordaros que esto no es una guía tipo copy/paste, ni remotamente.

Notas:

  • Como no podía ser de otra forma, el direccionamiento interno de este post no puede salir directamente a Internet. Hay que hacer SNAT (o el masquerade de toda la vida) en iptables. Lo normal es que conntrack haga magia y sepa dónde mandar vuestro tráfico, pero también es posible que se tenga que jugar más a fondo con ello.
  • Las entradas que añaden rutas a las tablas están simplificadas. Sería deseable completarlas, por ejemplo para evitar avisos de ICMP sobre mejores rutas si quisiésemos mandar tráfico entre redes. Lo dicho, no es más que un ejemplo.
  • En función de las configuraciones, interfaces, firewalls, ... puede ser posible que se tenga que cambiar algún parámetro de kernel, como por ejemplo, lo relacionado con rp_filter (Google es vuestro amigo). Por supuesto, ni que decir ip_forward.
  • Una vez más, esto es un mínimo ejemplo de lo mucho que se puede hacer. Las reglas, sin ir más lejos, pueden definirse por IP origen, destino, o incluso por marca de firewall, con lo que las posibilidades son enormes.
  • Os recomiendo completar lo visto en este post con todo lo que hay alrededor del enrutamiento en un kernel normal, con soporte Netfilter. Pista.

Comments