Почему сетевой стек игнорирует ответы icmp от интерфейса не по умолчанию?

У меня следующая ситуация:

  • eth0 - шлюз по умолчанию (ip: 172.28.183.100, gw: 172.28.183.1)
  • eth0 - вторичное сетевое соединение ( ip: 172.28.171.2, gw: 172.28.171.2).

маршрутизация выглядит так:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
172.28.183.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
172.28.171.0    0.0.0.0         255.255.255.0   U     0      0        0 eth2
172.28.173.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
78.46.78.0      172.28.171.1    255.255.255.0   UG    0      0        0 eth2
169.254.0.0     0.0.0.0         255.255.0.0     U     1000   0        0 eth0
0.0.0.0         172.28.183.1    0.0.0.0         UG    100    0        0 eth0

Как видите, существует специальный маршрут для 78.46.78.0/24 - этот трафик должен проходить по вторичной сети eth2.

Который работает. Я могу делать любые tcp соединения с машинами в 78.46.78.0/24.

Но, когда я пытаюсь проверить их, я получаю странный результат:

root@blob:~# mtr --report --report-cycles=5 78.46.78.198
HOST: blob                        Loss%   Snt   Last   Avg  Best  Wrst StDev
  1. 172.28.171.1                  0.0%     5    0.6   0.6   0.5   0.6   0.0
  2. ???                          100.0     5    0.0   0.0   0.0   0.0   0.0

В выводе tcpdump я вижу возвращенные ответы превышения времени жизни:

10:16:28.158888 IP 172.28.171.2 > 78.46.78.198: ICMP echo request, id 2092, seq 59520, length 44
10:16:28.159363 IP 172.28.171.1 > 172.28.171.2: ICMP time exceeded in-transit, length 72
10:16:28.259153 IP 172.28.171.2 > 78.46.78.198: ICMP echo request, id 2092, seq 59776, length 44
10:16:28.359546 IP 172.28.171.2 > 78.46.78.198: ICMP echo request, id 2092, seq 60032, length 44
10:16:28.408129 IP 10.9.208.1 > 172.28.171.2: ICMP time exceeded in-transit, length 36
10:16:28.428193 IP 10.9.208.2 > 172.28.171.2: ICMP time exceeded in-transit, length 36
10:16:28.459953 IP 172.28.171.2 > 78.46.78.198: ICMP echo request, id 2092, seq 60288, length 44
10:16:28.560260 IP 172.28.171.2 > 78.46.78.198: ICMP echo request, id 2092, seq 60544, length 44
10:16:28.618138 IP 10.9.213.6 > 172.28.171.2: ICMP time exceeded in-transit, length 36
10:16:28.660678 IP 172.28.171.2 > 78.46.78.198: ICMP echo request, id 2092, seq 60800, length 44
10:16:28.708130 IP 10.9.212.253 > 172.28.171.2: ICMP time exceeded in-transit, length 36
10:16:28.730193 IP 213.158.195.13 > 172.28.171.2: ICMP time exceeded in-transit, length 36
10:16:28.761086 IP 172.28.171.2 > 78.46.78.198: ICMP echo request, id 2092, seq 61056, length 44
10:16:28.861380 IP 172.28.171.2 > 78.46.78.198: ICMP echo request, id 2092, seq 61312, length 44
10:16:28.938167 IP 213.248.89.153 > 172.28.171.2: ICMP time exceeded in-transit, length 36

но с strace на mtr я вижу, что эти ответы ICMP не доставляются на mtr!

Я думаю, что причина может заключаться в том, что исходный ip ответа icmp исходит от "неправильного" интерфейса " - т.е. ICMP-ответ приходит (например) 10.9.212.253 (некоторый промежуточный маршрутизатор), но этот ip должен маршрутизироваться через eth0, в то время как речь идет о eth2.

Это разумная причина? Что я могу сделать, чтобы заставить mtr работать даже с моей "специальной" сетью?

Iptables устанавливается с помощью:

iptables -P INPUT   DROP
iptables -P FORWARD DROP
iptables -P OUTPUT  ACCEPT

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo                                  -j ACCEPT
iptables -A INPUT -i eth1                                -j ACCEPT
iptables -A INPUT -p icmp                                -j ACCEPT

iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth1                              -j ACCEPT

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o eth2 -j MASQUERADE

iptables -A INPUT   -j LOG --log-prefix 'IPTABLES: '
iptables -A FORWARD -j LOG --log-prefix 'IPTABLES: '

Но я не вижу связанных с icmp пакетов с kern.log.

1 ответ

Решение

Благодаря Rafał Ramocki - решение простое - вы должны отключить rp_filter-ing на интерфейсе eth2:

echo 0 > /proc/sys/net/ipv4/conf/eth2/rp_filter

Из документов ядра:

rp_filter
---------

Integer value determines if a source validation should be made. 1 means yes, 0
means no.  Disabled by default, but local/broadcast address spoofing is always
on.

If you  set this to 1 on a router that is the only connection for a network to
the net,  it  will  prevent  spoofing  attacks  against your internal networks
(external addresses  can  still  be  spoofed), without the need for additional
firewall rules.

Хотя это хорошо для предотвращения атак спуфинга (по крайней мере, некоторых), это определенно убивает некоторые функциональные возможности, если у вас есть больше интернет-соединений.

Другие вопросы по тегам