Проблема: IP-правило, созданное для маршрутизации трафика L4 через определенный интерфейс, не соблюдается, если пакеты генерируются с другим адресом источника.
Обзор Я хочу сгенерировать пакеты с исходным адресом, отличным от адреса хоста. Для этого я использую пакет Scapy из Python. Примечание: моя цель — отправлять и отправлять трафик DNS, однако я не смог найти простого решения, которое позволило бы мне подделывать исходный адрес в запросах DNS, поэтому я просто генерирую пакет UDP с адресом src и dst на порту 53, полагаю, это все еще работает, поскольку я тестирую только L3 и L4, а не фактический протокол DNS на данный момент. Вот мой скрипт
#!/usr/bin/python3
# The following is designed to generate a packet with a different source address
import sys
from scapy.all import *
def main():
S = "10.0.26.122" # spoofed source IP address
D = "10.0.26.123" # destination IP address
SP = 53 # source port
DP = 53 # destination port
payload = "This is a fake message" # packet payload
spoofed_packet = IP(src=S, dst=D) / UDP(sport=53, dport=53) / payload
send(spoofed_packet)
#Entry point
main()
Перед запуском скрипта моя таблица маршрутизации выглядит так:
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.104.8.1 0.0.0.0 UG 101 0 0 ens192
10.0.21.0 0.0.0.0 255.255.255.0 U 104 0 0 ens256
10.0.26.0 0.0.0.0 255.255.255.0 U 0 0 0 ens224
10.0.27.0 0.0.0.0 255.255.255.0 U 102 0 0 ens193
10.0.28.0 10.0.29.1 255.255.255.0 UG 100 0 0 ens161
10.0.29.0 0.0.0.0 255.255.255.0 U 100 0 0 ens161
10.104.8.0 0.0.0.0 255.255.255.0 U 101 0 0 ens192
10.212.134.0 10.104.8.1 255.255.255.0 UG 101 0 0 ens192
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
Вот IP-интерфейсы
# ip -br a
lo UNKNOWN 127.0.0.1/8
ens161 UP 10.0.29.122/24
ens192 UP 10.104.8.122/24
ens193 UP 10.0.27.122/24
ens224 UP 10.0.26.122/24
ens256 UP 10.0.21.122/24
virbr0 DOWN 192.168.122.1/24
virbr0-nic DOWN
ip_vti0@NONE DOWN
Когда я запускаю скрипт с помощью , ./packet-gen.py "10.0.26.122" "10.0.26.123"
он работает. Это потому, что я еще не построил свое правило ip / отдельную таблицу маршрутизации. Я выполняю tcpdump на хосте (10.0.26.122) и на дальнем хосте (10.0.26.123) и вижу, что отправляется пакет UDP. Я также протестировал с помощью dig www.google.com @10.0.26.123
и вижу, что выполняется реальный запрос DNS и получен ответ.
Теперь проблема. Я хочу удалить запись маршрута в основной таблице, а затем только маршрут на основе номера порта. Для этого я запускаю следующее, чтобы сначала удалить запись маршрута на 10.0.26.0/24.
# ip route del 10.0.26.0/24 dev ens224
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.104.8.1 0.0.0.0 UG 101 0 0 ens192
10.0.21.0 0.0.0.0 255.255.255.0 U 104 0 0 ens256
10.0.27.0 0.0.0.0 255.255.255.0 U 102 0 0 ens193
10.0.28.0 10.0.29.1 255.255.255.0 UG 100 0 0 ens161
10.0.29.0 0.0.0.0 255.255.255.0 U 100 0 0 ens161
10.104.8.0 0.0.0.0 255.255.255.0 U 101 0 0 ens192
10.212.134.0 10.104.8.1 255.255.255.0 UG 101 0 0 ens192
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
Запись удалена. Если я снова запущу свой скрипт, он не сработает. Запрос dig также не сработает. Это ожидаемо, так как в основной таблице маршрутизации ядра нет маршрута L3.
Для маршрутизации на L4 я сначала создал новую таблицу маршрутизации IP для отправки всего трафика через ens224:
# ip route add table 53 0.0.0.0/0 dev ens224
Затем я создаю IP-правило для захвата любого трафика, использующего порт 53, и отправляю свою пользовательскую таблицу 53.
# ip rule add ipproto udp dport 53 lookup 53
Я также создал специальное правило sysctl для rp_filter, чтобы ослабить строгие правила переадресации обратного пути.
# sysctl -w "net.ipv4.conf.ens224.rp_filter=2"
Для проверки своей работы я вижу следующее:
# ip route list table 53
default dev ens224 scope link
# ip rule list
0: from all lookup local
32765: from all ipproto udp dport 53 lookup 53
32766: from all lookup main
32767: from all lookup default
# ip route get 10.0.26.123 ipproto udp dport 53
10.0.26.123 dev ens224 table 53 src 10.0.26.122 uid 0
cache
# ip route get 10.0.26.123
10.0.26.123 via 10.104.8.1 dev ens192 src 10.104.8.122 uid 0
cache
Последняя команда показывает, что по умолчанию, если связь не DNS, используется маршрут по умолчанию.
Чтобы проверить это, я сначала пытаюсь пинговать 10.0.26.123. Он терпит неудачу, что и ожидалось. Теперь я пытаюсь выполнить запрос dig dig www.google.com @10.0.26.123
, и он работает. Запрос dig попадает в правило ip перед тем, как перейти в основную таблицу, и маршрутизируется соответствующим образом. Я вижу, что трафик достигает службы с помощью tcpdump (10.0.26.123) и исходит с моего хоста (10.0.26.122).
Теперь я снова пробую запустить свой скрипт scapy, и ничего. Даже с тем же исходным адресом, что и у хоста, ничего в tcpdump на моем хосте или сервере. Я пробовал изменить исходный адрес, никаких изменений, ничего. Если я добавлю обратно основной маршрут L3 для 10.0.26.0/24 в основную таблицу, скрипт scapy снова заработает. Что я здесь упускаю? Почему мой сгенерированный трафик не будет учитывать созданные мной наборы правил ip?
решение1
Scapy не использует механизм маршрутизации ОС, а использует собственную таблицу маршрутизации ( conf.route
объект), синхронизированную с таблицей маршрутизации ОС при запуске Scapy (или при вызове conf.route.resync()
метода).
Механизм маршрутизации Scapy не поддерживает исходную маршрутизацию, что объясняет описанное вами поведение.