Linux nie odpowiada na komunikaty żądania ARP, jeśli żądany adres IP jest powiązany z innym (wyłączonym) interfejsem

9

Mam komputer (jądro 3.2.0-23-generic ), który 192.168.1.2/24skonfigurował eth0interfejs, a także używa 192.168.1.1i 192.168.1.2adresy tun0interfejsu:

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

Jak widać powyżej, tun0administracyjnie jest wyłączony ( ip link set dev tun0 down). Teraz, gdy otrzymuję żądania ARP 192.168.1.2, komputer nie odpowiada na te żądania:

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

Dopiero po usunięciu tun0interfejsu ( ip link del dev tun0) komputer odpowie na żądanie ARP 192.168.1.2dotyczące eth0interfejsu.

Tabela routingu wygląda dokładnie tak samo przed i po 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:~# 

Poniższy wpis routingu został już usunięty za pomocą ip link set dev tun0 downpolecenia:

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

Jednak, chociaż tabele routingu są dokładnie takie same przed i po ip link del dev tun0komendzie, rzeczywiste decyzje dotyczące routingu podejmowane przez jądro nie są:

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

Czy to jest oczekiwane zachowanie? Dlaczego jądro ignoruje tablicę routingu?

Jaskółka oknówka
źródło
Czy możesz wkleić dane wyjściowe polecenia netstat -rn dla obu przypadków? Tabela routingu jest zazwyczaj pierwszym miejscem, w którym można szukać tego rodzaju błędów.
Claris
@Claris Zaktualizowałem swój początkowy post.
Martin
Posiadanie tego samego adresu IP na dwóch interfejsach może powodować problemy i najlepiej go unikać, biorąc pod uwagę, że powinieneś być w stanie zlokalizować problem. Następnym krokiem jest przyjrzenie się pamięci podręcznej arp, czy arp -a pokazuje coś użytecznego?
Claris
@Claris Wygląda na to, że główną przyczyną jest to, że jądro ignoruje tablicę routingu, gdy tun0interfejs jest wyłączony, ale obecny. Zobacz wyniki ip route getpoleceń w moim zaktualizowanym początkowym poście. Dlaczego jednak jądro tak się zachowuje?
Martin

Odpowiedzi:

13

Twoja tabela routingu nie jest dokładnie ignorowana. Zostaje zastąpione przez tablicę routingu o wyższym priorytecie.

Co się dzieje

Tabela routingu widoczna podczas pisania ip route shownie jest jedyną tabelą routingu używaną przez jądro. W rzeczywistości istnieją domyślnie trzy tabele routingu, które są przeszukiwane w kolejności pokazanej przez ip rulepolecenie:

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

Tabela, którą najbardziej znasz, to maintabela routingu o najwyższym priorytecie local. Tą tabelą zarządza jądro, aby śledzić trasy lokalne i rozgłaszania: innymi słowy, localtabela informuje jądro, w jaki sposób należy kierować do adresów własnych interfejsów. Wygląda to mniej więcej tak:

# 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

Sprawdź tę linię odniesienia tun0. To właśnie powoduje twoje dziwne wyniki route get. Mówi, że 192.168.1.1 to adres lokalny, co oznacza, że ​​jeśli chcemy wysłać odpowiedź ARP na 192.168.1.1, jest to łatwe; wysyłamy to do siebie. A ponieważ znaleźliśmy trasę w localtabeli, przestajemy szukać trasy i nie zawracamy sobie głowy sprawdzaniem tabel mainlub default.

Dlaczego wiele stołów?

Przynajmniej miło jest móc pisać ip routei nie widzieć wszystkich tych „oczywistych” tras zaśmiecających ekran (spróbuj pisać route printna komputerze z systemem Windows). Może również służyć jako minimalna ochrona przed błędną konfiguracją: nawet jeśli główna tablica routingu uległa pomyłce, jądro nadal wie, jak rozmawiać z samym sobą.

(Po co przede wszystkim utrzymywać trasy lokalne? Jądro może używać tego samego kodu wyszukiwania dla adresów lokalnych, jak robi to we wszystkich innych przypadkach. Ułatwia to wewnętrznie).

Istnieją inne ciekawe rzeczy, które możesz zrobić z tym schematem wielu tabel. W szczególności możesz dodawać własne tabele i określać zasady ich przeszukiwania. Nazywa się to „routingiem zasad”, a jeśli kiedykolwiek chciałeś skierować pakiet na podstawie jego adresu źródłowego , oto jak to zrobić w Linuksie.

Jeśli robisz szczególnie trudne lub eksperymentalne rzeczy, możesz localsamodzielnie dodawać lub usuwać trasy, określając table localw ip routepoleceniu. Jeśli nie wiesz, co robisz, prawdopodobnie pomylisz jądro. I oczywiście jądro nadal będzie dodawać i usuwać własne trasy, więc musisz uważać, aby się nie nadpisać.

Wreszcie, jeśli chcesz zobaczyć wszystkie tabele routingu na raz:

# ip route show table all

Aby uzyskać więcej informacji, sprawdź ip-rule(8)stronę podręcznika lub dokumenty iproute2 . Możesz także wypróbować Advanced Routing and Traffic Control HOWTO, aby uzyskać przykłady tego, co możesz zrobić.

Jander
źródło
Dzięki! Po ip link set dev tun0 downtym, jak local 192.168.1.1 dev tun0 proto kernel scope host src 192.168.1.1reguła rzeczywiście była nadal obecna w localtablicy routingu. Po wykonaniu ip link del dev tun0wspomniana reguła została usunięta. Nadal jedno pytanie - czy mam rację, że wszystkie współczesne jądra Linuksa (2.6.x, 3.x, 4.x) używają RPDB do wyszukiwania tras, a tym samym wielu tabel?
Martin
2
Tak, masz rację i więcej. RPDB jest zaskakująco stary! „Sam RPDB był integralną częścią przepisywania stosu sieciowego w jądrze Linuksa 2.2.” I z ip(8): „ ipzostało napisane przez Alexeya N. Kuznetsofa i dodane w Linuksie 2.2.”
Jander
1

Twój odwrotnego filtrowania ścieżka config jest chyba problem. RFC3704 - sekcja 2.4

W dystrybucjach Enterprise Linux (RHEL, CentOS, Scientific Linux i in.) Prawdopodobnie najlepszym sposobem na rozwiązanie tego problemu jest modyfikacja za /etc/sysctl.confpomocąrp_filter = 2

https://access.redhat.com/solutions/53031

0x Owczarek
źródło
Jeśli użyję luźnego sprawdzania RPF (2) lub nawet wyłączę sprawdzanie RPF (0) razem z for rp_filter_file in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > "$rp_filter_file"; donejądrem nie używam eth0interfejsu do routingu pakietów do 192.168.1.1. Dopiero gdy usunę tun0interfejs z ip link del dev tun0jądrem, zacznie korzystać z eth0interfejsu.
Martin