Problem: IP-Regeln zum Weiterleiten von L4-Verkehr über eine bestimmte Schnittstelle werden nicht beachtet, wenn Pakete mit unterschiedlichen Quelladressen generiert werden.
Überblick Ich möchte Pakete mit einer anderen Quelladresse als der Adresse des Hosts generieren. Dazu verwende ich das Python-Paket Scapy. Hinweis: Mein Ziel ist es, DNS-Verkehr zu senden, ich konnte jedoch keine einfache Lösung finden, mit der ich die Quelladresse in DNS-Anfragen fälschen konnte. Daher generiere ich einfach ein UDP-Paket mit Quell- und Zieladresse an Port 53. Ich glaube, das funktioniert immer noch, da ich derzeit nur L3 und L4 teste und nicht das eigentliche DNS-Protokoll. Hier ist mein Skript
#!/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()
So sieht meine Routentabelle vor dem Ausführen des Skripts aus:
# 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
Hier sind die IP-Schnittstellen
# 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
Wenn ich das Skript mit ausführe, ./packet-gen.py "10.0.26.122" "10.0.26.123"
funktioniert es. Das liegt daran, dass ich meine IP-Regel/separate Routing-Tabelle noch nicht erstellt habe. Ich führe einen TCPdump auf dem Host (10.0.26.122) und auf dem Host am anderen Ende (10.0.26.123) aus und sehe, wie das UDP-Paket gesendet wird. Ich habe es auch mit getestet dig www.google.com @10.0.26.123
und sehe, wie eine tatsächliche DNS-Anfrage ausgeführt wird und ich bekomme eine Antwort.
Nun zum Problem. Ich möchte den Routeneintrag in der Haupttabelle entfernen und dann nur noch basierend auf der Portnummer routen. Dazu führe ich Folgendes aus, um zuerst den Routeneintrag zu 10.0.26.0/24 zu entfernen.
# 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
Der Eintrag wird entfernt. Wenn ich mein Skript erneut ausführe, funktioniert es nicht. Die Dig-Anforderung schlägt ebenfalls fehl. Dies ist zu erwarten, da in der Haupt-Routingtabelle des Kernels keine L3-Route vorhanden ist.
Zum Routing auf L4 habe ich zunächst eine neue IP-Routingtabelle erstellt, um den gesamten Datenverkehr über ens224 zu senden:
# ip route add table 53 0.0.0.0/0 dev ens224
Dann erstelle ich eine IP-Regel, um den gesamten Datenverkehr über Port 53 zu erfassen, und sende meine benutzerdefinierte Tabelle 53.
# ip rule add ipproto udp dport 53 lookup 53
Ich habe auch eine spezielle Sysctl-Regel für rp_filter erstellt, um die strengen Reverse-Path-Forwarding-Regeln zu lockern
# sysctl -w "net.ipv4.conf.ens224.rp_filter=2"
Wenn ich meine Arbeit überprüfe, sehe ich Folgendes:
# 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
Der letzte Befehl zeigt, dass standardmäßig die Standardroute verwendet wird, wenn die Kommunikation nicht über DNS erfolgt.
Um dies zu testen, versuche ich zunächst, 10.0.26.123 anzupingen. Das schlägt erwartungsgemäß fehl. Jetzt versuche ich, eine Dig-Anfrage zu stellen dig www.google.com @10.0.26.123
, und es funktioniert. Die Dig-Anfrage trifft die IP-Regel, bevor sie an die Haupttabelle geht, und wird entsprechend weitergeleitet. Ich sehe, dass der Datenverkehr den Dienst mit tcpdump (10.0.26.123) erreicht und von meinem Host (10.0.26.122) kommt.
Jetzt versuche ich, mein Scapy-Skript erneut auszuführen, und nichts. Selbst mit derselben Quelladresse wie der Host wird im TCPdump auf meinem Host oder dem Server nichts angezeigt. Ich habe versucht, die Quelladresse zu ändern, keine Änderung, nichts. Wenn ich die Haupt-L3-Route für 10.0.26.0/24 wieder in die Haupttabelle einfüge, funktioniert das Scapy-Skript wieder. Was übersehe ich hier? Warum beachtet mein generierter Datenverkehr die von mir erstellten IP-Regelsätze nicht?
Antwort1
Scapy verwendet nicht den Routing-Mechanismus des Betriebssystems, sondern nutzt stattdessen seine eigene Routing-Tabelle ( conf.route
Objekt), die beim Start von Scapy (oder bei jedem conf.route.resync()
Aufruf der Methode) mit der Routing-Tabelle des Betriebssystems synchronisiert wird.
Der Routing-Mechanismus von Scapy unterstützt kein Source-Routing, was das von Ihnen beschriebene Verhalten erklärt.