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

Пинг собственного IP-адреса в обход ядра

Интересно, есть ли способ обойти ядро ​​и перенаправить пакет ping на мой сетевой шлюз, когда я проверяю свой IP-адрес.

Например, мой частный IP-адрес - 172.31.42.99, а IP-адрес шлюза - 172.31.32.1. Что я хочу сделать, так это когда я сделаю "ping 172.31.42.99", я получу результат "ping 172.31.32.1".

Я не эксперт по таблице IP-маршрутизации или iptables, я не уверен, есть ли способ, отредактировав таблицу маршрутизации или iptables для этого?

Я пытался редактировать таблицы маршрутизации, используя sudo ip route add 172.31.42.99/32 via 172.31.32.1 а также попытался отредактировать цепочки iptables PREROUTING в таблице nat. Ни один из них не работал.

Я ценю любую помощь или идеи.

ОБНОВЛЕНИЕ: давая здесь ответ более верный

когда я сделаю «ping 172.31.42.99», я получу результат «ping 172.31.32.1».

и не требует какой-либо специальной маршрутизации и не требует, чтобы 172.31.32.1 был маршрутизатором: простой DNAT.

использование перехватчиков OUTPUT netfilter

Сетевой стек linux имеет перехватчики netfilter, вставленные между различными этапами маршрутизации, как можно увидеть на этом схематический. Следует отметить, что входящие пакеты не обрабатываются в том же месте, что и исходящие пакеты, отправленные локально. В то время как перехватчики netfilter для первого находятся в перехватчиках PREROUTING, перехватчики для последнего находятся в перехватчиках OUTPUT: именно там должно быть помещено правило nat, а не в nat / PREROUTING, которое не будет видеть этот трафик. Так как я не знаю, что еще существует, на всякий случай вставляю его перед любым другим правилом:

iptables -t nat -I OUTPUT -p icmp -d 172.31.42.99 -j DNAT --to-destination 172.31.32.1

Действия, выполняемые в перехватчиках OUTPUT, могут запускать проверку перенаправления (как показано на предыдущей схеме): изменять первоначально выбранный маршрут для данного пакета. Обратите внимание, что это не влияет на другие характеристики IP-пакета: например, исходный IP-адрес не изменяется. Для конкретного случая OP это нормально, источник уже будет правильным. Во многих других случаях также необходимо внести другие неудобные изменения (например, SNAT в nat / POSTROUTING).

# ping 172.31.42.99
PING 172.31.42.99 (172.31.42.99) 56(84) bytes of data.
64 bytes from 172.31.42.99: icmp_seq=1 ttl=64 time=0.090 ms
64 bytes from 172.31.42.99: icmp_seq=2 ttl=64 time=0.122 ms
64 bytes from 172.31.42.99: icmp_seq=3 ttl=64 time=0.105 ms
^C
--- 172.31.42.99 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 89ms
rtt min/avg/max/mdev = 0.090/0.105/0.122/0.017 ms

в то же время:

# conntrack -E -p icmp
    [NEW] icmp     1 30 src=172.31.42.99 dst=172.31.42.99 type=8 code=0 id=2029 [UNREPLIED] src=172.31.32.1 dst=172.31.42.99 type=0 code=0 id=2029
 [UPDATE] icmp     1 30 src=172.31.42.99 dst=172.31.42.99 type=8 code=0 id=2029 src=172.31.32.1 dst=172.31.42.99 type=0 code=0 id=2029

(некоторое время спустя)

[DESTROY] icmp     1 src=172.31.42.99 dst=172.31.42.99 type=8 code=0 id=2029 src=172.31.32.1 dst=172.31.42.99 type=0 code=0 id=2029

Эквивалент с использованием столы вместо того iptables можно было бы:

# nft add table ip mynat
# nft add chain ip mynat dnaticmp '{ type nat hook output priority -100; policy accept; }'
# nft add rule ip mynat dnaticmp ip protocol icmp ip daddr 172.31.42.99 dnat to 172.31.32.1

Предыдущий ответ основан на трюках с таблицами маршрутизации

... что, вероятно, было не тем, что предполагал OP

Я даю тебе достаточно веревки, чтобы ты повесился.

Предварительное условие (которое заполняется OP): 172.31.32.1 должен быть маршрутизатором (и его предполагаемое поведение было протестировано ниже только с Linux маршрутизатор, поэтому он также может быть маршрутизатором Linux на случай, если поведение изменится).

Я предполагаю (не указано в OP), что IP-сеть - 172.31.32.0/20, а сетевой интерфейс системы называется eth0.

Причина, по которой вам не удалось изменить результаты, изменив видимый routes заключается в том, что при добавлении адреса в интерфейс некоторые маршруты также автоматически добавляются в ... скрытый местный таблица маршрутизации. Эта таблица имеет самый низкий приоритет, потому что она вызывается из правило приоритет 0:

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

# 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 172.31.32.0 dev eth0 proto kernel scope link src 172.31.42.99 
local 172.31.42.99 dev eth0 proto kernel scope host src 172.31.42.99 
broadcast 172.31.47.255 dev eth0 proto kernel scope link src 172.31.42.99 

# ip route get from 172.31.42.99 172.31.42.99
local 172.31.42.99 from 172.31.42.99 dev lo uid 0 
    cache <local> 

Здесь цель состоит в том, чтобы переопределить для локального случая предыдущую запись. Единственный способ - "переместить" правило 0 в значение с более высоким приоритетом, чтобы иметь возможность вставить что-то перед:

# ip rule add pref 100 from all lookup local
# ip rule delete pref 0

И добавьте правило, которое будет переопределять маршруты в более новую таблицу маршрутизации, но только для случая вывода, созданного локально, что переводится в специальный синтаксис iif lo действительно имеет значение исходящий скорее, чем из интерфейса lo:

# ip rule add pref 50 iif lo lookup 500

и необходимый маршрут (который позаботится о разрешении ARP, установив IP-адрес маршрутизатора в качестве шлюза):

# ip route add table 500 172.31.42.99/32 via 172.31.32.1

Теперь у нас есть два действительных маршрута (так что каждое направление даже пройдет Строгая пересылка по обратному пути при смене интерфейсов: eth0 и вот).

  • добавлен специальный маршрут:

    # ip route get from 172.31.42.99 172.31.42.99
    172.31.42.99 from 172.31.42.99 via 172.31.32.1 dev eth0 table 500 uid 0 
        cache 
    
  • а также, только с тех пор, как теперь действуют в обратном направлении:

    # ip route get from 172.31.42.99 iif eth0 172.31.42.99
    local 172.31.42.99 from 172.31.42.99 dev lo table local 
        cache <local> iif eth0 
    

Результат:

# ping 172.31.42.99
PING 172.31.42.99 (172.31.42.99) 56(84) bytes of data.
From 172.31.32.1: icmp_seq=1 Redirect Host(New nexthop: 172.31.42.99)
64 bytes from 172.31.42.99: icmp_seq=1 ttl=63 time=0.147 ms
From 172.31.32.1: icmp_seq=2 Redirect Host(New nexthop: 172.31.42.99)
64 bytes from 172.31.42.99: icmp_seq=2 ttl=63 time=0.129 ms
From 172.31.32.1: icmp_seq=3 Redirect Host(New nexthop: 172.31.42.99)
[...]

Это работает только потому, что 172.31.32.1 - маршрутизатор. Что на самом деле происходит для одного пинга:

  • система отправляет ICMP-запрос на настроенный шлюз: маршрутизатор,
  • Маршрутизатор обнаруживает, что система неправильно настроена, и в той же локальной сети (которой является сама система) есть лучший прямой пункт назначения для обработки этого запроса и отправляет перенаправление ICMP, чтобы сообщить ему, чтобы он исправил свое поведение. Узел без маршрутизации просто сбросил бы пакет,
  • маршрутизатор по-прежнему направляет эхо-запрос ICMP в пункт назначения 172.31.42.99: обратно отправителю,
  • система получает эхо-сообщение ICMP (с действующим маршрутом и даже с прохождением правил строгой пересылки обратного пути) и отправляет обратно ответ ICMP так же, как и раньше,
  • маршрутизатор снова отправляет перенаправление ICMP,
  • маршрутизатор все еще направляет ответ ICMP,
  • система (и команда ping) получает ответ ICMP.