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 для обоих случаев? Таблица маршрутизации обычно является первым местом, где нужно искать подобные ошибки.
Кларус
@Claris Я обновил свой начальный пост.
Мартин
Наличие одного и того же IP-адреса на двух интерфейсах может создать проблемы, и этого лучше избегать, при этом вы должны быть в состоянии отследить проблему. Следующим шагом является просмотр кеша arp. Показывает ли arp -a что-нибудь полезное?
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 Advanced Routing and Traffic Control, чтобы получить примеры того, что вы можете сделать.

Jander
источник
Спасибо! После того, как правило было действительно все еще присутствует в таблице маршрутизации. После того как я выполнил указанное правило было удалено. Тем не менее, один вопрос - правильно ли я, что все современные ядра Linux (2.6.x, 3.x, 4.x) используют RPDB для поиска маршрутов и, следовательно, нескольких таблиц? ip link set dev tun0 downlocal 192.168.1.1 dev tun0 proto kernel scope host src 192.168.1.1localip link del dev tun0
Мартин
2
Да, вы правы и многое другое. РПДБ на удивление стар! «Сама 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 игнорирует пакеты, когда маршрут для исходящего трафика отличается от маршрута входящего трафика?

0xSheepdog
источник
Если я использую свободную проверку 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интерфейс.
Мартин