O Linux não responde às mensagens de solicitação do ARP se o endereço IP solicitado estiver associado a outra interface (desativada)

9

Eu tenho um PC (kernel 3.2.0-23-generic ) que foi 192.168.1.2/24configurado para fazer eth0interface e também usa 192.168.1.1e 192.168.1.2endereços para 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:~# 

Como visto acima, tun0está desativado administrativamente ( ip link set dev tun0 down). Agora, quando recebo solicitações de ARP 192.168.1.2, o PC não responde a essas solicitações:

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

Somente depois de excluir a tun0interface ( ip link del dev tun0), o PC responderá à solicitação ARP para 192.168.1.2a eth0interface.

A tabela de roteamento é exatamente igual antes e depois 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:~# 

A entrada de roteamento abaixo já foi removida com o ip link set dev tun0 downcomando:

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

No entanto, embora as tabelas de roteamento sejam exatamente iguais antes e depois do ip link del dev tun0comando, as decisões de roteamento reais que o kernel tomará não são:

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

Esse é um comportamento esperado? Por que o kernel ignora a tabela de roteamento?

Martin
fonte
Você pode colar a saída do netstat -rn nos dois casos? A tabela de roteamento geralmente é o primeiro lugar para procurar esse tipo de erro.
Clarus 26/05
@Claris Atualizei meu post inicial.
Martin
Ter o mesmo IP em duas interfaces pode criar problemas e é melhor evitá-lo; isso significa que você deve rastrear o problema. O próximo passo é examinar o cache do arp, o arp -a mostra algo útil?
Clarus 27/05
@ Claris Parece que a causa principal é que o kernel ignora a tabela de roteamento quando a tun0interface está desabilitada, mas presente. Veja a saída dos ip route getcomandos no meu post inicial atualizado. No entanto, por que o kernel se comporta assim?
Martin

Respostas:

17

Sua tabela de roteamento não está sendo ignorada, exatamente. Ele está sendo substituído por uma tabela de roteamento de prioridade mais alta.

O que está acontecendo

A tabela de roteamento que você vê quando digita ip route shownão é a única tabela de roteamento usada pelo kernel. De fato, há três tabelas de roteamento por padrão e elas são pesquisadas na ordem mostrada pelo ip rulecomando:

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

A tabela com a qual você está mais familiarizado é main, mas a tabela de roteamento de prioridade mais alta é local. Esta tabela é gerenciada pelo kernel para acompanhar as rotas locais e de broadcast: em outras palavras, a localtabela informa ao kernel como rotear para os endereços de suas próprias interfaces. Parece algo como isto:

# 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

Confira essa referência de linha tun0. Isso é o que está causando seus resultados estranhos route get. Diz 192.168.1.1 é um endereço local, o que significa que, se queremos enviar uma resposta ARP para 192.168.1.1, é fácil; nós enviamos para nós mesmos. E como encontramos uma rota na localtabela, paramos de procurar uma rota e não nos incomodamos em verificar as tabelas mainou default.

Por que várias tabelas?

No mínimo, é bom poder digitar ip routee não ver todas as rotas "óbvias" bagunçando a tela (tente digitar route printem uma máquina Windows). Ele também pode servir como uma proteção mínima contra configurações incorretas: mesmo que a tabela de roteamento principal tenha se misturado, o kernel ainda sabe como se comunicar.

(Por que manter as rotas locais em primeiro lugar? Portanto, o kernel pode usar o mesmo código de pesquisa para endereços locais e para todo o resto. Isso torna as coisas mais simples internamente.)

Há outras coisas interessantes que você pode fazer com esse esquema de várias tabelas. Em particular, você pode adicionar suas próprias tabelas e especificar regras para quando elas são pesquisadas. Isso é chamado de "roteamento de política" e, se você quiser rotear um pacote com base no endereço de origem , é assim que se faz no Linux.

Se você estiver fazendo coisas especialmente complicadas ou experimentais, poderá adicionar ou remover localrotas especificando table localno ip routecomando. A menos que você saiba o que está fazendo, é provável que confunda o kernel. E, é claro, o kernel continuará adicionando e removendo suas próprias rotas, então você deve observar para garantir que o seu não seja sobrescrito.

Por fim, se você deseja ver todas as tabelas de roteamento de uma vez:

# ip route show table all

Para mais informações, consulte a ip-rule(8)página de manual ou os documentos do iproute2 . Você também pode tentar o HOWTO de roteamento avançado e controle de tráfego para obter alguns exemplos do que você pode fazer.

Jander
fonte
Obrigado! Depois que ip link set dev tun0 downa local 192.168.1.1 dev tun0 proto kernel scope host src 192.168.1.1regra ainda estava presente na localtabela de roteamento. Uma vez executada, ip link del dev tun0a regra mencionada foi removida. Ainda assim, estou certo de que todos os kernels modernos do Linux (2.6.x, 3.x, 4.x) usam RPDB para pesquisas de rotas e, portanto, várias tabelas?
Martin
2
Sim, você está correto e muito mais. O RPDB é surpreendentemente antigo! "O próprio RPDB foi parte integrante da reescrita da pilha de rede no kernel 2.2 do Linux". E from ip(8): " ipfoi escrito por Alexey N. Kuznetsof e adicionado no Linux 2.2."
Jander
Esta é uma das melhores explicações das várias tabelas de roteamento do kernel que eu já vi. Obrigado!
precisa saber é o seguinte
1

Sua configuração de filtragem de caminho reverso provavelmente é o problema. RFC3704 - seção 2.4

Nas distribuições Enterprise Linux (RHEL, CentOS, Scientific Linux, et al), a melhor maneira provável de resolver isso é modificando /etc/sysctl.confcomrp_filter = 2

Quando o RHEL tem vários IPs configurados, apenas um é acessível a partir de uma rede remota. Ou por que o RHEL ignora pacotes quando a rota para o tráfego de saída difere da rota do tráfego de entrada?

0xSheepdog
fonte
Se eu usar a verificação RPF frouxa (2) ou mesmo desativar a verificação RPF (0) completamente com for rp_filter_file in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > "$rp_filter_file"; doneo kernel, a eth0interface não será usada para rotear pacotes para 192.168.1.1. Somente quando eu excluo a tun0interface com ip link del dev tun0o kernel começa a usar a eth0interface.
Martin