Linux ne répond pas aux messages de requête ARP si l'adresse IP demandée est associée à une autre interface (désactivée)

9

J'ai un PC (noyau 3.2.0-23-générique ) qui a 192.168.1.2/24configuré pour l' eth0interface et utilise également 192.168.1.1et 192.168.1.2adresses pour l' tun0interface:

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:~# 

Comme vu ci-dessus, tun0est administrativement désactivé ( ip link set dev tun0 down). Maintenant, lorsque je reçois des demandes ARP pour 192.168.1.2, le PC ne répond pas à ces demandes:

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:~#

Seulement après supprimer l' tun0interface ( ip link del dev tun0) le PC répondra à la demande ARP pour 192.168.1.2le eth0interface.

La table de routage se ressemble exactement avant et aprè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:~# 

L'entrée de routage ci-dessous est déjà supprimée avec la ip link set dev tun0 downcommande:

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

Cependant, alors que les tables de routage se ressemblent exactement avant et après la ip link del dev tun0commande, les décisions de routage réelles que le noyau prendra ne seront pas:

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:~# 

Est-ce un comportement attendu? Pourquoi le noyau ignore-t-il la table de routage?

Martin
la source
Pouvez-vous coller la sortie de netstat -rn dans les deux cas? La table de routage est généralement le premier endroit pour rechercher ce type d'erreurs.
Clarus
@Claris J'ai mis à jour mon message initial.
Martin
Avoir la même IP sur deux interfaces peut créer des problèmes et il vaut mieux l'éviter, cela étant dit, vous devriez être en mesure de retracer le problème. La prochaine étape consiste à regarder le cache arp, est-ce que arp -a montre quelque chose d'utile?
Clarus
@Claris On dirait que la cause principale est que le noyau ignore la table de routage lorsque l' tun0interface est désactivée, mais présente. Voir la sortie des ip route getcommandes dans mon post initial mis à jour. Cependant, pourquoi le noyau se comporte-t-il ainsi?
Martin

Réponses:

17

Votre table de routage n'est pas ignorée, exactement. Il est annulé par une table de routage de priorité plus élevée.

Que se passe-t-il

La table de routage que vous voyez lorsque vous tapez ip route shown'est pas la seule table de routage utilisée par le noyau. En fait, il y a trois tables de routage par défaut, et elles sont recherchées dans l'ordre indiqué par la ip rulecommande:

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

La table que vous connaissez le mieux est main, mais la table de routage la plus prioritaire est local. Cette table est gérée par le noyau pour garder une trace des routes locales et de diffusion: en d'autres termes, la localtable indique au noyau comment router vers les adresses de ses propres interfaces. Cela ressemble à ceci:

# 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

Découvrez ce référencement de ligne tun0. C'est ce qui cause vos résultats étranges route get. Il dit que 192.168.1.1 est une adresse locale, ce qui signifie que si nous voulons envoyer une réponse ARP à 192.168.1.1, c'est facile; nous nous l'envoyons. Et puisque nous avons trouvé un itinéraire dans le localtableau, nous arrêtons de rechercher un itinéraire, et ne prenons pas la peine de vérifier les tables mainor default.

Pourquoi plusieurs tables?

Au minimum, il est agréable de pouvoir taper ip routeet de ne pas voir tous ces itinéraires "évidents" encombrant l'affichage (essayez de taper route printsur une machine Windows). Il peut également servir de protection minimale contre les erreurs de configuration: même si la table de routage principale s'est mélangée, le noyau sait toujours se parler.

(Pourquoi garder les routes locales en premier lieu? Ainsi, le noyau peut utiliser le même code de recherche pour les adresses locales que pour tout le reste. Cela simplifie les choses en interne.)

Il y a d'autres choses intéressantes que vous pouvez faire avec ce schéma à plusieurs tables. En particulier, vous pouvez ajouter vos propres tables et spécifier des règles de recherche. C'est ce qu'on appelle le «routage de stratégie», et si vous avez déjà voulu router un paquet en fonction de son adresse source , voici comment le faire sous Linux.

Si vous faites des choses particulièrement délicates ou expérimentales, vous pouvez ajouter ou supprimer des localitinéraires vous-même en spécifiant table localdans la ip routecommande. À moins que vous ne sachiez ce que vous faites, vous risquez de confondre le noyau. Et bien sûr, le noyau continuera à ajouter et à supprimer ses propres routes, vous devez donc veiller à ce que les vôtres ne soient pas écrasées.

Enfin, si vous souhaitez voir toutes les tables de routage à la fois:

# ip route show table all

Pour plus d'informations, consultez la ip-rule(8)page de manuel ou les documents iproute2 . Vous pouvez également essayer le HOWTO Advanced Routing and Traffic Control pour quelques exemples de ce que vous pouvez faire.

Jander
la source
Merci! Après ip link set dev tun0 downla local 192.168.1.1 dev tun0 proto kernel scope host src 192.168.1.1règle était en effet toujours présent dans la localtable de routage. Une fois que j'ai exécuté ip link del dev tun0la règle mentionnée a été supprimée. Pourtant, une question - ai-je raison de dire que tous les noyaux Linux modernes (2.6.x, 3.x, 4.x) utilisent RPDB pour les recherches de route et donc plusieurs tables?
Martin
2
Oui, vous avez raison et plus encore. RPDB est étonnamment vieux! "Le RPDB lui-même faisait partie intégrante de la réécriture de la pile réseau dans le noyau Linux 2.2." Et de ip(8): "a ipété écrit par Alexey N. Kuznetsof et ajouté dans Linux 2.2."
Jander
C'est l'une des meilleures explications des multiples tables de routage du noyau que j'ai vues. Merci!
djluko
1

Votre configuration de filtrage de chemin inverse est probablement le problème. RFC3704 - section 2.4

Dans les distributions Enterprise Linux (RHEL, CentOS, Scientific Linux, et al), la meilleure façon de résoudre ce problème est de modifier /etc/sysctl.confavecrp_filter = 2

Lorsque RHEL a plusieurs adresses IP configurées, une seule est accessible à partir d'un réseau distant. Ou pourquoi RHEL ignore-t-il les paquets lorsque l'itinéraire pour le trafic sortant diffère de l'itinéraire du trafic entrant?

0xSheepdog
la source
Si j'utilise la vérification RPF lâche (2) ou même que je désactive la vérification RPF (0) avec for rp_filter_file in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > "$rp_filter_file"; donele noyau, n'utilise pas l' eth0interface pour acheminer les paquets vers 192.168.1.1. Ce n'est qu'une fois que j'ai supprimé l' tun0interface que ip link del dev tun0le noyau commence à utiliser l' eth0interface.
Martin