iproute2

net-tools es el nombre con que se conoce al conjunto de herramientas tridicionalmente para administrar una red, como ifconfig, route, arp y netstat. Estas herramientas siguen siendo válidas, aunque su desarrollo se detuvo en 2001, y algunas distribuciones como Arch o CentOS/RHEL 7 las marcan como deprecated. Como alternativa, contamos con iproute2. iproute2 es un conjunto de herramientas para administrar la red que busca ser la alternativa a las herramientas anteriormente mencionadas. Hace las mismas cosas, y añade otras que permiten convertir a GNU/Linux en un sistema de enrutamiento avanzado, tales como enrutamiento por origen, balanceo de carga, tunneling, gestión del ancho de banda, etc. Y además, iproute2 está actualmente en desarrollo.

iproute2 permite hacer cosas que net-tools no, como las siguientes:

  • Enrutamiento por origen
  • QoS (Quality of Service)
  • VLAN switching
  • bridging
  • Etc.

Equivalencias de iproute2 con net-tools

A continuación presento algunos comandos equivalentes entre net-tools e iproute2

Mostrar las interfaces conectadas

Con net-tools:

$ ifconfig -a

Con iproute2

$ ip link show

Activar o desactivar una interfaz de red

Con net-tools:

$ sudo ifconfig eth1 up $ sudo ifconfig eth1 down

Con iproute2

$ sudo ip link set eth1 down $ sudo ip link set eth1 up

Asignar una dirección IPv4 a una interfaz

Con net-tools:

$ sudo ifconfig eth1 10.0.0.1/24

Con iproute2

$ sudo ip addr add 10.0.0.1/24 dev eth1

Mediante iproute2 es posible asignar múltiples direcciones IPv4 a una interfaz, cosa que no es posible hacer mediante ifconfig (la única forma es mediante ip aliases). Por ejemplo:

$ sudo ip addr add 10.0.0.1/24 broadcast 10.0.0.255 dev eth1 $ sudo ip addr add 10.0.0.2/24 broadcast 10.0.0.255 dev eth1 $ sudo ip addr add 10.0.0.3/24 broadcast 10.0.0.255 dev eth1

Borrar una dirección IPv4 de una interfaz

Con net-tools no hay una manera formal de borrar una dirección IPv4. La única forma de hacer eso es asignando 0:

$ sudo ifconfig eth1 0

Con iproute2

$ sudo ip addr del 10.0.0.1/24 dev eth1

Mostrar las direcciones IPv4 de una interfaz

Con net-tools:

$ ifconfig eth1

Con iproute2

$ ip addr show dev eth1

Asignar una dirección IPv6 a una interfaz de red

IPv6 permite por su naturaleza asignar múltiples direcciones a una misma interfaz, lo que está soportado de forma nativa por net-tools y por iproute2

Con net-tools:

$ sudo ifconfig eth1 inet6 add 2002:0db5:0:f102::1/64 $ sudo ifconfig eth1 inet6 add 2003:0db5:0:f102::1/64

Con iproute2

$ sudo ip -6 addr add 2002:0db5:0:f102::1/64 dev eth1 $ sudo ip -6 addr add 2003:0db5:0:f102::1/64 dev eth1

Mostrar las direcciones IPv6 de una interfaz

Con net-tools:

$ ifconfig eth1

Con iproute2

$ ip -6 addr show dev eth1

Borrar una dirección IPv6 de una interfaz

Con net-tools:

$ sudo ifconfig eth1 inet6 del 2002:0db5:0:f102::1/64

Con iproute2

$ sudo ip -6 addr del 2002:0db5:0:f102::1/64 dev eth1

Cambiar la MAC de una interfaz de red

Con net-tools:

$ sudo ifconfig eth1 hw ether 08:00:27:75:2a:66

Con iproute2

$ sudo ip link set dev eth1 address 08:00:27:75:2a:67

Ver la tabla de rutas

Con net-tools:

$ route -n $ netstat -rn

Con iproute2

$ ip route show

Crear una ruta por defecto

Con net-tools:

$ sudo route add default gw 192.168.1.2 eth0 $ sudo route del default gw 192.168.1.1 eth0

Con iproute2

$ sudo ip route add default via 192.168.1.2 dev eth0 $ sudo ip route replace default via 192.168.1.2 dev eth0

Añadir o borrar una ruta estática

Con net-tools:

$ sudo route add -net 172.16.32.0/24 gw 192.168.1.1 dev eth0 $ sudo route del -net 172.16.32.0/24

Con iproute2

$ sudo ip route add 172.16.32.0/24 via 192.168.1.1 dev eth0 $ sudo ip route del 172.16.32.0/24

Ver estadísticas de sockets

Con net-tools:

$ netstat $ netstat -l

Con iproute2

$ ss $ ss -l

Ver la tabla ARP

Con net-tools:

$ arp -an

Con iproute2

$ ip neigh

Añadir o borrar una entrada ARP

Con net-tools:

$ sudo arp -s 192.168.1.100 00:0c:29:c0:5a:ef $ sudo arp -d 192.168.1.100

Con iproute2

$ sudo ip neigh add 192.168.1.100 lladdr 00:0c:29:c0:5a:ef dev eth0 $ sudo ip neigh del 192.168.1.100 dev eth0

Añadir, eliminar o ver direcciones MAC multicast

Con net-tools:

$ sudo ipmaddr add 33:44:00:00:00:01 dev eth0 $ sudo ipmaddr del 33:44:00:00:00:01 dev eth0 $ ipmaddr show dev eth0 $ netstat -g

Con iproute2

$ sudo ip maddr add 33:44:00:00:00:01 dev eth0 $ sudo ip maddr del 33:44:00:00:00:01 dev eth0 $ ip maddr list dev eth0

Comprobación de rutas

Mediante la opción get, podemos comprobar la resolución que da el algoritmo de resolución de rutas a la hora de seleccionar el siguiente salto hacia una determinada IP. Por ejemplo... ¿Qué ruta tomaría un paquete que debe llegar hasta la IP 80.58.32.33?

usuario@par:~$ ip route get 80.58.32.33 80.58.32.33 via 192.168.1.1 dev eth0 src 192.168.1.100 cache users 1 used 4 mtu 1500 advmss 1460 hoplimit 64

La caché de rutas

El kernel de GNU/Linux busca primero en una caché de rutas, que es una referencia rápida a la tabla de rutas, que se rellena en base paquetes previamente enrutados. Las entradas de la caché se van borrando periódicamente pero aun así, si se realiza algún cambio en la tabla de rutas, se pueden obtener resultados no deseados si no se borra la caché. Para ello se utiliza la opción flush cache. Para poder consultar la caché actual:

usuario@par:~$ ip route show cache broadcast 192.168.1.255 dev eth0 src 192.168.1.100 cache mtu 1500 advmss 1460 hoplimit 64 broadcast 192.168.1.255 from 192.168.1.100 dev eth0 cache mtu 1500 advmss 1460 hoplimit 64 local 192.168.1.100 from 80.58.32.33 dev lo src 192.168.1.100 cache iif eth0 80.58.32.33 from 192.168.1.100 via 192.168.1.1 dev eth0 cache mtu 1500 advmss 1460 hoplimit 64
usuario@par:~$ ip route flush cache

Confiruaciones multi-wan

En configuraciones multiwan, tenemos varias opciones. Tenemos enrutamiento por origen, es decir, escoger por donde enviar un paquete según de donde venga. También podemos configurar el balanceo de carga (simétrico o asimétrico) para que los paquetes se repartan en tre varios ISP. También podemos hacer configuraciones de alta disponibilidad, para que en caso de caida de un ISP, dirijamos todo el tráfico por el otro.

En este caso, vamos ver las dos primeras opciones, es decir, enrutamiento por origen y balanceo de carga. La alta disponibilidad se puede conseguir de diferentes maneras, pero no es nuestro objetivo de momento... todo a su debido tiempo.

Enrutamiento por origen

En general cuando hablamos de enrutamiento, nos referimos al reenvío de paquetes en función del destino, y no del origen. Sin embargo puede que esto no sea suficiente. En ocasiones podemos desear que todo lo que venga de un determinado host, o grupo de ellos, vaya por una u otra ruta.

Cuando utilizamos el comando route, interactuamos únicamente con dos tablas de rutas. En concreto, hablamos de la tabla main y de la tabla local. En realidad, las distribuciones modernas de GNU/Linux pueden tener muchas tablas de rutas diferentes. De este modo, las decisiones de enrutamiento pueden ser diferentes, según la tabla que utilicemos.

Inicialmente, GNU/Linux define 3 tablas diferentes: local, main y default. Para poder ver la tablas de rutas que utiliza nuestro host, podemos ejecutar el siguiente comando:

usuario@router:~$ ip rule show 0: from all lookup local 32766: from all lookup main 32767: from all lookup default

El kernel de GNU/Linux busca en las diferentes tablas, empezando por la que tiene un índice menor, procesando cada tabla hasta que el paquete ha sido enrutado correctamente.

La tabla local (con prioridad 0) maneja el tráfico que no saldrá del host, así como el tráfico bradcast. La tabla main es la siguiente en ser procesada, y la que modificamos con el comando route. La última tabla en ser consultada, default permite decidir que hacer en caso de que ninguna tabla haya resuelto la ruta.

Además de estas tres tablas, podemos añadir otras, en el archivo /etc/iproute2/rt_tables. Para ver su contenido, podemos utilizar el comando siguiente:

usuario@router:~$ cat /etc/iproute2/rt_tables # # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep

Podemos comprobar lo que contiene cada tabla, añadiendo su nombre con el comando ip route show. Por ejemplo, la tabla main:

usuario@router:~$ ip route show table main 192.168.3.0/24 dev eth2 proto kernel scope link src 192.168.3.1 192.168.2.0/24 dev eth1 proto kernel scope link src 192.168.2.2 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.2 default via 192.168.1.1 dev eth0 metric 100
usuario@router:~$ ip route show table local local 192.168.3.1 dev eth2 proto kernel scope host src 192.168.3.1 broadcast 192.168.3.0 dev eth2 proto kernel scope link src 192.168.3.1 broadcast 192.168.2.255 dev eth1 proto kernel scope link src 192.168.2.2 broadcast 192.168.1.0 dev eth0 proto kernel scope link src 192.168.1.2 broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1 local 192.168.1.2 dev eth0 proto kernel scope host src 192.168.1.2 broadcast 192.168.3.255 dev eth2 proto kernel scope link src 192.168.3.1 broadcast 192.168.2.0 dev eth1 proto kernel scope link src 192.168.2.2 broadcast 192.168.1.255 dev eth0 proto kernel scope link src 192.168.1.2 local 192.168.2.2 dev eth1 proto kernel scope host src 192.168.2.2 broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1 local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1

Ahora vamos a añadir una nueva tabla de rutas en el router. Para ello, utilizamos un comando como el siguiente:

usuario@par:~$ echo "250 ISP2" >> /etc/iproute2/rt_tables

Una vez creada la nueva tabla, podemos añadir rutas en la misma. En las nuevas rutas, indicaremos que deseamos que la "máquina 2" salga por el "ISP 2":

usuario@router:~$ ip route add 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.2 table ISP2 usuario@router:~$ ip route add 192.168.2.0/24 dev eth1 proto kernel scope link src 192.168.2.2 table ISP2 usuario@router:~$ ip route add 192.168.3.0/24 dev eth2 proto kernel scope link src 192.168.3.1 table ISP2 ip route add default via 192.168.2.1 dev eth1 table ISP2

Las tres primeras rutas, permiten que el router sepa enviar paquetes que van a redes directamente conectadas. La última routa es una ruta por defecto hacia el "ISP 2".

Además de tablas, GNU/Linux utiliza reglas. Anteriormente vimos las reglas, al ejecutar el comando ip rule show. Recordemos:

usuario@par:~$ ip rule show 0: from all lookup local 32766: from all lookup main 32767: from all lookup default

Las reglas sirven para indicar qué IPs de origen deben ser enrutadas por origen en qué tabla. Por ejemplo, en nuestro caso, que queremos que lo que venga desde la "máquina 2" sea enruado según la tabla "ISP2", debemos hacer lo siguiente:

usuario@router:~$ ip rule add from 192.168.3.3/32 table ISP2

Ahora podemos ver la nueva regla, junta a las mostradas anteriormente, indicando que cuando un paquete proviene de 192.168.3.3, debe de enrutarse según la tabla "ISP2".

usuario@par:~$ ip rule show 0: from all lookup local 32765: from 192.168.3.3/32 lookup ISP2 32766: from all lookup main 32767: from all lookup default

Y con esto ya hemos terminado. Ahora, el router dirigirá el tráfico por uno u otro sitio. Para comprobar la configuración, podemos utilizar traceroute.

Balanceo de carga

Otra posibilidad interesante que nos ofrece iproute2 es el balanceo de carga. Aunque la topología es la misma que en el ejemplo anterior, en este caso buscamos que los paquetes vayan repartiéndose por diferentes enlaces. De este modo se puede conseguir utilizar simultáneamente dos ISPs de forma transparente a los usuarios. En este caso, el router actua como "balanceador de carga".

Además, este balanceo se puede realizar de manera asimétrica, de forma que viaje mayor cantidad de tráfico por el ISP 1 que por el ISP 2, tal y como muestra la figura siguiente.

Para ejecutar esta técnica, necesitamos los siguientes elementos:

  • Una tabla por cada ISP.
    • Cada tabla debe tener una ruta por defecto hacia el ISP correspondiente.
    • Además, debe tener rutas válidas hacia las redes directamente conectadas.
  • Una regla para cada tabla, de forma que cada interfaz del balanceador sepa qué ISP escoger.
  • Una regla en la tabla main que balancee el tráfico.

Vamos a concretar. Parto de la idea de que el balanceador tiene la configuración por defecto y hemos borrado cualquier acción que hayamos hecho anteriormente.

Creamos una tabla por cada ISP. Para ello, editamos el archivo /etc/iproute2/rt_table y lo dejamos como se indica a continuación:

usuario@router:~$ cat /etc/iproute2/rt_tables # # reserved values # 255 local 254 main 253 default 0 unspec # # local # #1 inr.ruhep 250 ISP1 251 ISP2

No necesariamente se tienen que asignar los números 250 y 251 a las tablas. Lo que se debe cumplir es que sean menores que local, main y default.

Ahora que ya tenemos definidas nuestras tablas, debemos llenarlas de rutas. A continuación indico cuales serían las mínimas rutas necesarias para funcionar.

Para la tabla ISP1:

usuario@router:~$ ip route add 192.168.1.0/24 proto kernel scope link src 192.168.1.2 dev eth0 table ISP1 usuario@router:~$ ip route add default via 192.168.1.1 table ISP1

Y para la tabla ISP2:

usuario@router:~$ ip route add 192.168.2.0/24 proto kernel scope link src 192.168.2.2 dev eth1 table ISP2 usuario@router:~$ ip route add default via 192.168.2.1 table ISP2

También debemos crear reglas para indicar que cuando un paquete provenga de la interfaz eth0 (192.168.1.2) sea enrutado según la tabla ISP1, y que cuando provenga de la interfaz eth1 (192.168.2.2) sea enrutado según la tabla ISP2. Para ello ejecutamos los siguiente comandos:

usuario@router:~$ ip rule add from 192.168.1.2 table ISP1 usuario@router:~$ ip rule add from 192.168.2.2 table ISP2

Estrictamente estos dos comandos anteriores no son necesarios en nuestro ejemplo. La razón es que salvo que los paquetes sean generados en el mismo router, no figurarán con dirección origen 192.168.1.2 o 192.168.2.2. Alguien puede pensar que sí en caso de estar haciendo NAT, pero tampoco es el caso, puesto que NAT se aplica tras tomar la decisión de enrutamiento. Entonces... ¿Para qué sirve?
Puede sernos útil especialmente en casos de "dual homed host", es decir, máquinas conectadas a dos interfaces entre las que balancear, y hacer un enrutamiento más complejo según la interfaz que emite un paquete. Por ejemplo, en servidores.

Ahora solo nos queda incluir una ruta para el balaceo de carga en la tabla main, como sigue:

usuario@router:~$ ip route add default scope global nexthop via 192.168.1.1 dev eth0 weight 1 nexthop via 192.168.2.1 dev eth1 weight 1

Con esto hacemos que el tráfico se balancee de forma simétrica entre uno y otro enlace. Mediante el parámetro weight, establecemos el peso que tiene cada enlace. Por ello, con ambos parámetros weight valiendo 1, el peso es el mismo, por tanto el 50% del tráfico se enviará por una interfaz y el 50% por la otra.

Si se desea que, por ejemplo, el 75% del tráfico se envíe por el ISP 1 y el 25% restante por el ISP 2, podemos cambiar el comando anterior del siguiente modo:

usuario@router:~$ ip route add default scope global nexthop via 192.168.1.1 dev eth0 weight 3 nexthop via 192.168.2.1 dev eth1 weight 1

Práctica 1. Crea una infraestructura como la de la imagen siguiente mediante máquinas virtuales, para conseguir enrutamiento por origen, de forma que la máquina 1 salga por el ISP 1 y la máquina 2 salga por el ISP 2.

Las interfaces de los routers de los ISPs estarán configurados en modo puente, y con IPs válidas en la red del sistema operativo host. Para comprobar qué ISP se está usando en cada momento, puedes utilizar el comando tcpdump -i eth0 en "ISP1" e "ISP2". O bien se puede utilizar "Wireshark" en el S.O. host, escuchando el tráfico que sale desde la interfaz eth0 de ISP1 e ISP2.

Se deben "natear" las comunicaciones salientes hacia la red de cada ISP. No se aplicará NAT en el router, así que debes crear las rutas necesarias en ISP1 e ISP2 para que los paquetes viajen correctamente hasta 192.168.3.0/24.

Práctica 2. Crea una infraestructura mediante máquinas virtuales igual que de la práctica anterior, para conseguir balanceo de carga, de forma que el tráfico se reparta entre el ISP 1 y el ISP 2.

Configura las interfaces "públicas" (eth0) de ISP1 e ISP2 del mismo modo que en el ejercicio anterior. Utiliza "Wireshark" para generar estadísticas fiables sobre el uso de los ISPs, escuchando el tráfico que sale desde la interfaz eth0 de ISP1 e ISP2.

Saludos.