El comportamiento normal sería el siguiente:
Red local, eth0
ip 192.168.1.1
mascara 255.255.255.0
Primera salida a internet, eth1
ip 1.2.3.4
mascara 255.255.255.0
ruta por defecto 1.2.3.254
Primera salida a internet, eth2
ip2.3.4.5
mascara 255.255.255.0
ruta por defecto 2.3.4.254
Segun este esquema, las tablas de ruteo quedarían así:
Destination Gateway Genmask Flags MSS Window irtt Iface
192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
1.2.3.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
2.3.4.0 0.0.0.0 255.255.255.0 U 0 0 0 eth2
0.0.0.0 1.2.3.254 0.0.0.0 UG 0 0 0 eth1
0.0.0.0 2.3.4.254 0.0.0.0 UG 0 0 0 eth2
Como se puede ver, aparecen dos rutas por defecto. Sin embargo el sistema utilizará siempre la primera que haya a no ser que la interfaz esté caída, o sea que falte la letra "U" (de up).
En qué nos afecta esto? Supongamos que nos viene un paquete destinado a la ip 1.2.3.4 proveniente de algún lugar de internet, digamos 5.5.5.5. Cuando el sistema mande la respuesta, esta saldrá por la placa eth1, porque es la primera ruta que sirve para alcanzar la ip 5.5.5.5 y todo funciona bien.
Pero qué pasa si viene un paquete proveniente, digamos, de 6.6.6.6, destinado a 2.3.4.5. El paquete llegará sin problemas pero cuando haya que enviar la respuesta, esta saldrá, de nuevo, por la eth1. Pero resulta que la IP de origen del paquete de respueta tiene que ser, obviamente, 2.3.4.5 y el proveedor de internet al que llegamos por la eth1 no querrá rutear paquetes con esa ip de origen. El paquete debería haber salido por la eth2, dirigido a su router correspondiente, el 2.3.4.254.
Lo que necesitamos, es alguna manera de decirle al sistema qué hacer en esta situación, y ahí es donde aparece la capacidad de ruteo avanzado que tiene Linux.
El documento Linux Advanced Routing and Traffic Control how-to
explica claramente este problema y la manera de solucionarlo. Lo que yo les presento ahora es un script que se encarga de hacer todo automáticamente.
La situación es que tenemos dos rutas por defecto y debemos utilizar cada una según corresponda.
ATENCION: esto no se trata de balancear cargas por las dos conexiones. Se trata simplemente de que ambas sean utilizables desde internet.
Para solucionar esta situación, lo que hace es crear una tabla para cada placa de red que haya. En cada una tiene rutas para llegar a las demás redes, y la ruta por defecto que corresponda a esa placa. De esa forma, se puede configurar en cada placa de red una ruta por defecto diferente.
Para seleccionar cuál de todas estas tablas de ruteo es la que debemos utilizar en cada momento, se debe crear reglas que seleccionan la tabla correspondiente en función de la IP de origen del paquete. La IP de origen es lo que distingue una placa de red de otra, así que nos sirve para saber por qué placa está saliendo el paquete.
Para su funcinamiento, el script utiliza la información de los archivos de configuración de la red, que se encuentran en /etc/sysconfig/network-scripts. Al menos en los sistemas que siguen la Linux Standard Base, este directorio contiene archivos con el nombre ifcfg-<nombre de la placa de red>. Por ejemplo /etc/sysconfig/network-scripts/ifcfg-eth1 contendría:
DEVICE=eth
BOOTPROTO=static
IPADDR=1.2.3.4
NETMASK=255.255.255.0
GATEWAY=1.2.3.254
ONBOOT=yes
METRIC=10
MII_NOT_SUPPORTED=no
USERCTL=no
DNS1=127.0.0.1
RESOLV_MODS=no
IPV6INIT=no
IPV6TO4INIT=no
ACCOUNTING=no
Lo que nos interesa de este archivo son la IPADDR, NETMASK y GATEWAY. Con estos datos podemos generar automáticamente lo que necesitamos.
A continuación el script:
#limpiar reglas anteriores por si lo ejecutamos de nuevo
ip rule show | awk 'BEGIN{FS=":"}{if(index($2,"lookup main")==0 && index($2,"lookup default")==0 && index($2,"lookup local")==0) system ("ip rule del " $2) }'
#recorrer las intefaces de red #para cada una crear una tabla cuenta=0 for ifcfg in /etc/sysconfig/network-scripts/ifcfg-* do cuenta=$(( cuenta + 1 )) TABLE=100$cuenta . $ifcfg echo "DEVICE=$DEVICE" export `ipcalc -n $IPADDR $NETMASK` NET=$NETWORK/$NETMASK ip route flush table $TABLE ip route add $NET dev $DEVICE src $IPADDR table $TABLE if [ "$GATEWAY" != "" ] then ip route add default via $GATEWAY table $TABLE fi ip route add $NETWORK dev $DEVICE src $IPADDR ip rule add from $IPADDR table $TABLE ip rule add fwmark $TABLE table $TABLE tables="$tables $TABLE" if [ "$GATEWAY" != "" ] then ip route add default via $GATEWAY table $TABLE fi echo echo echo echo done for TABLE in $tables do for ifcfg in /etc/sysconfig/network-scripts/ifcfg-* do . $ifcfg export `ipcalc -n $IPADDR $NETMASK` NET=$NETWORK/$NETMASK ip route add $NET dev $DEVICE table $TABLE done done echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter ip route flush cache