Linux no responde a los mensajes de solicitud ARP si la dirección IP solicitada está asociada con otra interfaz (deshabilitada)

9

Tengo un PC (kernel 3.2.0-23-generic ) que ha 192.168.1.2/24configurado para eth0la interfaz y también utiliza 192.168.1.1y 192.168.1.2direcciones de tun0interfaz:

root@T42:~# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:16:41:54:01:93 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.2/24 scope global eth0
    inet6 fe80::216:41ff:fe54:193/64 scope link
       valid_lft forever preferred_lft forever
3: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN
    link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
4: irda0: <NOARP> mtu 2048 qdisc noop state DOWN qlen 8
    link/irda 00:00:00:00 brd ff:ff:ff:ff
5: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:13:ce:8b:99:3e brd ff:ff:ff:ff:ff:ff
    inet 10.30.51.53/24 brd 10.30.51.255 scope global eth1
    inet6 fe80::213:ceff:fe8b:993e/64 scope link
       valid_lft forever preferred_lft forever
6: tun0: <POINTOPOINT,MULTICAST,NOARP> mtu 1500 qdisc pfifo_fast state DOWN qlen 100
    link/none
    inet 192.168.1.1 peer 192.168.1.2/32 scope global tun0
root@T42:~# ip route show dev eth0
192.168.1.0/24  proto kernel  scope link  src 192.168.1.2 
root@T42:~# 

Como se ve arriba, tun0está deshabilitado administrativamente ( ip link set dev tun0 down). Ahora, cuando recibo solicitudes de ARP 192.168.1.2, la PC no responde a esas solicitudes:

root@T42:~# tcpdump -nei eth0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
15:30:34.875427 00:1a:e2:ae:cb:b7 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: Request who-has 192.168.1.2 tell 192.168.1.1, length 46
15:30:36.875268 00:1a:e2:ae:cb:b7 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 60: Request who-has 192.168.1.2 tell 192.168.1.1, length 46
15:30:39.138651 00:1a:e2:ae:cb:b7 > 00:1a:e2:ae:cb:b7, ethertype Loopback (0x9000), length 60:
^C
3 packets captured
3 packets received by filter
0 packets dropped by kernel
root@T42:~#

Sólo después borro la tun0interfaz ( ip link del dev tun0) del PC le responderá a la solicitud ARP para 192.168.1.2el eth0interfaz.

La tabla de enrutamiento se ve exactamente igual antes y después ip link del dev tun0:

root@T42:~# netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.30.51.254    0.0.0.0         UG        0 0          0 eth1
10.30.51.0      0.0.0.0         255.255.255.0   U         0 0          0 eth1
192.168.1.0     192.168.1.2     255.255.255.0   UG        0 0          0 eth0
root@T42:~# ip link del dev tun0
root@T42:~# netstat -rn
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         10.30.51.254    0.0.0.0         UG        0 0          0 eth1
10.30.51.0      0.0.0.0         255.255.255.0   U         0 0          0 eth1
192.168.1.0     192.168.1.2     255.255.255.0   UG        0 0          0 eth0
root@T42:~# 

La entrada de enrutamiento a continuación ya se elimina con el ip link set dev tun0 downcomando:

Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
192.168.1.2     0.0.0.0         255.255.255.255 UH        0 0          0 tun0

Sin embargo, aunque las tablas de enrutamiento son exactamente iguales antes y después del ip link del dev tun0comando, las decisiones de enrutamiento reales que tomará el núcleo no son:

T42:~# ip route get 192.168.1.1
local 192.168.1.1 dev lo  src 192.168.1.1 
    cache <local> 
T42:~# ip link del dev tun0
T42:~# ip route get 192.168.1.1
192.168.1.1 dev eth0  src 192.168.1.2 
    cache  ipid 0x8390
T42:~# 

¿Es este un comportamiento esperado? ¿Por qué el núcleo ignora la tabla de enrutamiento?

Martín
fuente
¿Puedes pegar la salida de netstat -rn para ambos casos? La tabla de enrutamiento suele ser el primer lugar para buscar este tipo de errores.
Clarus
@Claris Actualicé mi publicación inicial.
Martin
Tener la misma IP en dos interfaces puede crear problemas y es mejor evitarlo, dicho esto, debería poder rastrear el problema. El siguiente paso es mirar el caché de arp, ¿arp -a muestra algo útil?
Clarus
@Claris Parece que la causa raíz es que el núcleo ignora la tabla de enrutamiento cuando la tun0interfaz está deshabilitada, pero presente. Vea el resultado de los ip route getcomandos en mi publicación inicial actualizada. Sin embargo, ¿por qué el núcleo se comporta así?
Martin

Respuestas:

17

Su tabla de enrutamiento no se ignora exactamente. Está siendo anulado por una tabla de enrutamiento de mayor prioridad.

Que esta pasando

La tabla de enrutamiento que ve cuando escribe ip route showno es la única tabla de enrutamiento que utiliza el núcleo. De hecho, hay tres tablas de enrutamiento de forma predeterminada, y se buscan en el orden que muestra el ip rulecomando:

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

La tabla con la que está más familiarizado es main, pero la tabla de enrutamiento de mayor prioridad es local. El kernel administra esta tabla para realizar un seguimiento de las rutas locales y de difusión: en otras palabras, la localtabla le dice al kernel cómo enrutar a las direcciones de sus propias interfaces. Se parece a esto:

# ip route show table local
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.1.0 dev eth0  proto kernel  scope link  src 192.168.1.2
local 192.168.1.1 dev tun0  proto kernel  scope host  src 192.168.1.1
local 192.168.1.2 dev eth0  proto kernel  scope host  src 192.168.1.2
broadcast 192.168.1.255 dev eth0  proto kernel  scope link  src 192.168.1.2

Echa un vistazo a esa referencia de línea tun0. Eso es lo que está causando sus extraños resultados route get. Dice que 192.168.1.1 es una dirección local, lo que significa que si queremos enviar una respuesta ARP a 192.168.1.1, es fácil; Nos lo enviamos a nosotros mismos. Y como encontramos una ruta en la localtabla, dejamos de buscar una ruta y no nos molestamos en revisar las tablas maino default.

¿Por qué varias mesas?

Como mínimo, es bueno poder escribir ip routey no ver todas esas rutas "obvias" que abarrotan la pantalla (intente escribir route printen una máquina con Windows). También puede servir como una protección mínima contra la configuración incorrecta: incluso si la tabla de enrutamiento principal se ha mezclado, el núcleo todavía sabe cómo hablar consigo mismo.

(¿Por qué mantener las rutas locales en primer lugar? De modo que el núcleo puede usar el mismo código de búsqueda para direcciones locales que para todo lo demás. Hace las cosas más simples internamente).

Hay otras cosas interesantes que puede hacer con este esquema de tablas múltiples. En particular, puede agregar sus propias tablas y especificar reglas para cuando se buscan. Esto se denomina "enrutamiento de políticas", y si alguna vez ha querido enrutar un paquete en función de su dirección de origen , así es cómo hacerlo en Linux.

Si está haciendo cosas especialmente difíciles o experimentales, puede agregar o eliminar localrutas usted mismo especificando table localen el ip routecomando. Sin embargo, a menos que sepa lo que está haciendo, es probable que confunda el núcleo. Y, por supuesto, el núcleo continuará agregando y eliminando sus propias rutas, por lo que debe vigilar para asegurarse de que las suyas no se sobrescriban.

Finalmente, si desea ver todas las tablas de enrutamiento a la vez:

# ip route show table all

Para obtener más información, consulte la ip-rule(8)página de manual o los documentos de iproute2 . También puede probar el COMO avanzado de enrutamiento y control de tráfico para ver algunos ejemplos de lo que puede hacer.

Jander
fuente
¡Gracias! Después de que ip link set dev tun0 downla local 192.168.1.1 dev tun0 proto kernel scope host src 192.168.1.1regla todavía estaba presente en localla tabla de enrutamiento. Una vez que ejecuté ip link del dev tun0la regla mencionada fue eliminada. Aún así, una pregunta: ¿estoy en lo cierto al decir que todos los núcleos modernos de Linux (2.6.x, 3.x, 4.x) usan RPDB para búsquedas de rutas y, por lo tanto, múltiples tablas?
Martin
2
Sí, tienes razón y más. ¡RPDB es sorprendentemente viejo! "El RPDB en sí mismo fue una parte integral de la reescritura de la pila de red en el kernel 2.2 de Linux". Y de ip(8): " ipfue escrito por Alexey N. Kuznetsof y agregado en Linux 2.2".
Jander
Esta es una de las mejores explicaciones de las tablas de enrutamiento de kernel múltiple que he visto. ¡Gracias!
djluko
1

Su configuración de filtrado de ruta inversa es probablemente el problema. RFC3704 - sección 2.4

En las distribuciones de Enterprise Linux (RHEL, CentOS, Scientific Linux, et al), la mejor manera probable de resolver esto es modificar /etc/sysctl.confconrp_filter = 2

Cuando RHEL tiene múltiples IP configuradas, solo se puede acceder a una desde una red remota. ¿O por qué RHEL ignora los paquetes cuando la ruta para el tráfico saliente difiere de la ruta del tráfico entrante?

0x perro pastor
fuente
Si uso la comprobación de RPF suelta (2) o incluso deshabilito la comprobación de RPF (0) por completo con for rp_filter_file in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > "$rp_filter_file"; doneel kernel, no utilizo la eth0interfaz para enrutar paquetes a 192.168.1.1. Solo una vez que elimino la tun0interfaz con ip link del dev tun0el kernel comienza a usar la eth0interfaz.
Martin