Linux antwortet nicht auf ARP-Anforderungsnachrichten, wenn die angeforderte IP-Adresse einer anderen (deaktivierten) Schnittstelle zugeordnet ist

9

Ich habe einen PC (Kernel 3.2.0-23-generic ), der für die Schnittstelle 192.168.1.2/24konfiguriert ist eth0und auch Schnittstellen verwendet 192.168.1.1und 192.168.1.2adressiert tun0:

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

Wie oben gezeigt, tun0ist administrativ deaktiviert ( ip link set dev tun0 down). Wenn ich jetzt ARP-Anfragen für erhalte, antwortet 192.168.1.2der PC nicht auf diese Anfragen:

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

Erst nachdem ich die löschen tun0Schnittstelle ( ip link del dev tun0) wird der PC auf ARP - Anfrage antworten für 192.168.1.2auf - eth0Schnittstelle.

Die Routing-Tabelle sieht vorher und nachher genau gleich aus 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:~# 

Der unten stehende Routing-Eintrag wird bereits mit dem folgenden ip link set dev tun0 downBefehl entfernt:

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

Während Routing-Tabellen vor und nach dem ip link del dev tun0Befehl genau gleich sind , sind die tatsächlichen Routing-Entscheidungen, die der Kernel treffen wird, nicht:

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

Ist das ein erwartetes Verhalten? Warum ignoriert der Kernel die Routing-Tabelle?

Martin
quelle
Können Sie die Ausgabe von netstat -rn für beide Fälle einfügen? Die Routing-Tabelle ist normalerweise der erste Ort, an dem nach solchen Fehlern gesucht wird.
Clarus
@ Claris Ich habe meinen ersten Beitrag aktualisiert.
Martin
Die gleiche IP auf zwei Schnittstellen kann zu Problemen führen und wird am besten vermieden. Allerdings sollten Sie in der Lage sein, das Problem aufzuspüren. Der nächste Schritt besteht darin, den Arp-Cache zu betrachten. Zeigt arp -a etwas Nützliches?
Clarus
@Claris Die Hauptursache ist anscheinend, dass der Kernel die Routing-Tabelle ignoriert, wenn die tun0Schnittstelle deaktiviert, aber vorhanden ist. Siehe die Ausgabe von ip route getBefehlen in meinem aktualisierten ersten Beitrag. Warum verhält sich der Kernel jedoch so?
Martin

Antworten:

17

Ihre Routing-Tabelle wird nicht genau ignoriert. Es wird von einer Routing-Tabelle mit höherer Priorität außer Kraft gesetzt.

Was ist los

Die Routing-Tabelle, die Sie bei der Eingabe sehen, ip route showist nicht die einzige Routing-Tabelle, die der Kernel verwendet. Tatsächlich gibt es standardmäßig drei Routing-Tabellen, die in der vom ip ruleBefehl angegebenen Reihenfolge durchsucht werden :

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

Die Tabelle, mit der Sie am besten vertraut sind main, ist die Routing-Tabelle mit der höchsten Priorität local. Diese Tabelle wird vom Kernel verwaltet, um lokale Routen und Broadcast-Routen zu verfolgen. Mit anderen Worten, die localTabelle teilt dem Kernel mit, wie er zu den Adressen seiner eigenen Schnittstellen routen soll. Es sieht ungefähr so ​​aus:

# 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

Überprüfen Sie diese Zeilenreferenzierung tun0. Das ist es, was deine seltsamen Ergebnisse verursacht route get. Es heißt, 192.168.1.1 sei eine lokale Adresse. Wenn wir also eine ARP-Antwort an 192.168.1.1 senden möchten, ist dies einfach. wir schicken es uns. Und da wir eine Route in der localErgebnistabelle, halten wir für einen Weg suchen, und nicht die Mühe , die Überprüfung mainoder defaultTabellen.

Warum mehrere Tabellen?

Zumindest ist es schön, in der Lage zu sein, ip routeall diese "offensichtlichen" Routen zu tippen und nicht zu sehen, die die Anzeige überladen (versuchen Sie, route printauf einem Windows-Computer zu tippen ). Es kann auch als minimaler Schutz vor Fehlkonfigurationen dienen: Selbst wenn die Hauptrouting-Tabelle durcheinander geraten ist, weiß der Kernel immer noch, wie er mit sich selbst sprechen kann.

(Warum sollten lokale Routen überhaupt beibehalten werden? Der Kernel kann also für lokale Adressen denselben Suchcode verwenden wie für alles andere. Dies vereinfacht die Dinge intern.)

Es gibt andere interessante Dinge, die Sie mit diesem Schema mit mehreren Tabellen tun können. Insbesondere können Sie Ihre eigenen Tabellen hinzufügen und Regeln für die Suche angeben. Dies wird als "Richtlinienrouting" bezeichnet. Wenn Sie jemals ein Paket basierend auf seiner Quelladresse weiterleiten wollten , gehen Sie wie folgt unter Linux vor.

Wenn Sie besonders knifflige oder experimentelle Dinge tun, können Sie localRouten selbst hinzufügen oder entfernen , indem Sie table localim ip routeBefehl angeben . Wenn Sie jedoch nicht wissen, was Sie tun, werden Sie den Kernel wahrscheinlich verwirren. Und natürlich wird der Kernel weiterhin seine eigenen Routen hinzufügen und entfernen, sodass Sie darauf achten müssen, dass Ihre nicht überschrieben werden.

Wenn Sie schließlich alle Routing-Tabellen gleichzeitig anzeigen möchten:

# ip route show table all

Weitere Informationen finden Sie in der ip-rule(8)Manpage oder in den iproute2-Dokumenten . Sie können auch das Advanced Routing and Traffic Control HOWTO ausprobieren, um einige Beispiele für Ihre Möglichkeiten zu erhalten.

Jander
quelle
Vielen Dank! Nachdem ip link set dev tun0 downdie local 192.168.1.1 dev tun0 proto kernel scope host src 192.168.1.1Regel tatsächlich noch in der localRouting-Tabelle vorhanden war. Sobald ich ausgeführt habe, wurde ip link del dev tun0die erwähnte Regel entfernt. Eine Frage: Stimmt es, dass alle modernen Linux-Kernel (2.6.x, 3.x, 4.x) RPDB für Routensuchen und damit für mehrere Tabellen verwenden?
Martin
2
Ja, du bist richtig und mehr. RPDB ist überraschend alt! "Die RPDB selbst war ein wesentlicher Bestandteil des Umschreibens des Netzwerkstapels im Linux-Kernel 2.2." Und aus ip(8): " ipwurde von Alexey N. Kuznetsof geschrieben und in Linux 2.2 hinzugefügt."
Jander
Dies ist eine der besten Erklärungen für die mehreren Kernel-Routing-Tabellen, die ich gesehen habe. Vielen Dank!
Djluko
1

Ihre Konfiguration für die umgekehrte Pfadfilterung ist wahrscheinlich das Problem. RFC3704 - Abschnitt 2.4

In Enterprise Linux - Distributionen (RHEL, CentOS, Scientific Linux, et al) der wahrscheinlich beste Weg , dies zu lösen , ist zu ändern , /etc/sysctl.confmitrp_filter = 2

Wenn für RHEL mehrere IPs konfiguriert sind, ist nur eine über ein Remote-Netzwerk erreichbar. Oder warum ignoriert RHEL Pakete, wenn sich die Route für ausgehenden Verkehr von der Route für eingehenden Verkehr unterscheidet?

0xSheepdog
quelle
Wenn ich die lose RPF-Prüfung (2) verwende oder sogar die RPF-Prüfung (0) ganz deaktiviere, verwendet for rp_filter_file in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > "$rp_filter_file"; doneder Kernel die eth0Schnittstelle nicht zum Weiterleiten von Paketen an 192.168.1.1. Erst wenn ich die tun0Schnittstelle mit ip link del dev tun0dem Kernel lösche, wird die Schnittstelle eth0verwendet.
Martin