Назад | Перейти на главную страницу

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

У меня такая ситуация:

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

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.

Спасибо Рафалу Рамоки - решение простое - вам нужно отключить 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.

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