Linux не відповідає на повідомлення запиту ARP, якщо запитувана IP-адреса пов'язана з іншим (відключеним) інтерфейсом


9

У мене є ПК (ядро 3.2.0-23-generic ), який 192.168.1.2/24налаштований на eth0інтерфейс, а також використовує 192.168.1.1та 192.168.1.2адреси для 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:~# 

Як було показано вище, tun0адміністративно вимкнено ( ip link set dev tun0 down). Тепер, коли я отримую запити ARP 192.168.1.2, ПК не відповідає на ці запити:

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

Тільки після того, як я видаляю tun0інтерфейс ( ip link del dev tun0) комп'ютер буде відповідати на запит ARP для 192.168.1.2на eth0інтерфейсі.

Таблиця маршрутизації виглядає точно так само до і після 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:~# 

Запис маршрутизації нижче видаляється вже ip link set dev tun0 downкомандою:

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

Однак, хоча таблиці маршрутизації точно подібні до та після ip link del dev tun0команди, фактичні рішення ядра маршрутизації приймуть не такі:

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

Це очікувана поведінка? Чому ядро ​​ігнорує таблицю маршрутизації?


Чи можете ви вставити вихід netstat -rn в обох випадках? Таблиця маршрутизації, як правило, є першим місцем для пошуку таких помилок.
Clarus

@Claris Я оновив своє початкове повідомлення.
Мартін

Наявність однакового IP-адреси на двох інтерфейсах може створювати проблеми, і найкраще уникати цього, але, як кажуть, ви повинні мати можливість простежити проблему. Наступний крок - переглянути кеш арпу, чи показує arp-щось щось корисне?
Clarus

@Claris Схоже, першопричиною є те, що ядро ​​ігнорує таблицю маршрутизації, коли tun0інтерфейс відключений, але присутній. Дивіться результати ip route getкоманд у моєму оновленому початковому дописі. Однак чому ядро ​​поводиться так?
Мартін

Відповіді:


17

Ваша таблиця маршрутизації точно не ігнорується. Це перекрито таблицею маршрутизації з вищим пріоритетом.

Що відбувається

Таблиця маршрутизації, яку ви бачите під час введення ip route show, не єдина таблиця маршрутизації, яку використовує ядро. Насправді є три таблиці маршрутизації за замовчуванням, і їх шукають у порядку, показаному ip ruleкомандою:

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

Таблиця, з якою ви найбільше знайома, є mainтаблиця маршрутизації з найвищим пріоритетом local. Ця таблиця керує ядром для відстеження локальних та широкомовних маршрутів: іншими словами, localтаблиця повідомляє ядру, як прокласти маршрут до власних інтерфейсів. Це виглядає приблизно так:

# 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

Ознайомтеся з посиланням на цей рядок tun0. Ось що викликає ваші дивні результати route get. Каже, 192.168.1.1 - це локальна адреса, це означає, що якщо ми хочемо надіслати відповідь ARP на 192.168.1.1, це легко; ми відправляємо це собі. А оскільки ми знайшли маршрут у localтаблиці, ми зупиняємо пошук маршруту і не переймаємось перевіркою mainабо defaultтаблицями.

Чому кілька таблиць?

Як мінімум, приємно мати можливість вводити ip routeта не бачити всіх тих "очевидних" маршрутів, що захаращують дисплей (спробуйте ввести route printна машині Windows). Він також може служити якоюсь мінімальною захистом від неправильних конфігурацій: навіть якщо основна таблиця маршрутизації стала змішаною, ядро ​​все ще вміє говорити самому.

(Навіщо зберігати локальні маршрути в першу чергу? Тож ядро ​​може використовувати той самий код пошуку для локальних адрес, як і для всього іншого. Це робить речі все простішими.)

Є й інші цікаві речі, які можна зробити за допомогою цієї схеми з декількома таблицями. Зокрема, ви можете додати свої власні таблиці та вказати правила для їх пошуку. Це називається "маршрутизація політики", і якщо ви коли-небудь хотіли направити пакет на основі його вихідної адреси, це зробити, як це зробити в Linux.

Якщо ви робите особливо складні або експериментальні речі, ви можете додавати або видаляти localмаршрути самостійно, вказавши table localв ip routeкоманді. Якщо ви не знаєте, що ви робите, ви, швидше за все, заплутаєте ядро. І звичайно, ядро ​​все одно продовжуватиме додавати та видаляти власні маршрути, тому вам доведеться стежити за тим, щоб ваші не перезаписалися.

Нарешті, якщо ви хочете одразу переглянути всі таблиці маршрутів:

# ip route show table all

Для отримання додаткової інформації ознайомтеся з довідковоюip-rule(8) сторінкою або документами iproute2 . Ви можете також спробувати розширені маршрутизації та управління трафіком HOWTO для деяких прикладів того, що ви можете зробити.


Дякую! Після того ip link set dev tun0 downяк local 192.168.1.1 dev tun0 proto kernel scope host src 192.168.1.1правило все ще було присутнє в localтаблиці маршрутизації. Щойно я виконав ip link del dev tun0вказане правило було видалено. І все-таки одне питання - чи правильно я підтверджую, що всі сучасні ядра Linux (2.6.x, 3.x, 4.x) використовують RPDB для пошуку маршрутів і, отже, декількох таблиць?
Мартін

2
Так, ви правильні та багато іншого. RPDB напрочуд старий! "Сам RPDB був невід'ємною частиною переписування мережевого стеку в Linux ядро ​​2.2." І з ip(8): " ipнаписав Олексій Н. Кузнецоф і додав до Linux 2.2."
Джандер

Це одне з найкращих пояснень я бачив декілька таблиць маршрутизації ядра. Дякую!
djluko

1

Ваша зворотна фільтрація шляху конфігурація, ймовірно , проблема. RFC3704 - розділ 2.4

У дистрибутивах Enterprise Linux (RHEL, CentOS, Scientific Linux та ін.) Можливий найкращий спосіб вирішити це - змінити за /etc/sysctl.confдопомогоюrp_filter = 2

Коли в RHEL налаштовано кілька IP-адрес, до віддаленої мережі можна дістатися лише один. Або чому RHEL ігнорує пакети, коли маршрут для вихідного трафіку відрізняється від маршруту вхідного трафіку?


Якщо я використовую вільну перевірку RPF (2) або навіть відключаю перевірку RPF (0) взагалі з for rp_filter_file in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > "$rp_filter_file"; doneядром, не використовується eth0інтерфейс для маршрутизації пакетів до 192.168.1.1. Лише після видалення tun0інтерфейсу з ip link del dev tun0ядром починає використовувати eth0інтерфейс.
Мартін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.