
Ich verwende „tcpdump“, um den Datenverkehr zu erfassen, und möchte nach HTTP-Methoden filtern. Wenn ich IPv4-Pakete habe, verwende ich: tcpdump -s 0 -A 'tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420'
Zum Filtern nach HTTP-GET-Paketen.
Leider tcp[]
funktioniert der Filter nicht bei IPv6-Paketen. Laut der Dokumentation
Arithmetische Ausdrücke für Transportschicht-Header wie
tcp[0]
funktionieren bei IPv6-Paketen nicht.
Daher suche ich nach einer anderen Möglichkeit, mit tcpdump nur HTTP-Methoden für IPv6-Verkehr zu filtern.
Ich habe versucht, nach einer Lösung zu suchen, aber es scheint, als ob sie eine Verwendung von grep beinhalten, die für meine Bedürfnisse nicht geeignet ist, da ich den gesamten gefilterten Datenverkehr direkt in eine PCAP-Datei ausgeben möchte
Antwort1
Einschränkungen tcpdump
bei IPv6 ab Version 4.99.x
Um für IPv4 den Payload-Offset im Paket zu erhalten, kann man den Payload-Offset mehr oder weniger einfach berechnen, indem man verwendetDas humanitäre Völkerrecht von IPv4+ TCP-Datenoffsetum auch IPv4-Optionen und TCP-Optionen zu berücksichtigen. Dies ist einfach genug, um intcpdumpdirekt, wenn es den BPF-Bytecode-Filter generiert (einige BPF-Dokumentationen sind verfügbar, zum BeispielDort).
Bei IPv6 kann es stattdessen eine variable (möglicherweise zwischen 0 und 9) Anzahl von Erweiterungsheadern zwischen dem festen Header und dem oberen Header geben. Das würde bedeuten, Code für möglicherweise 10 Fälle (0, 1, 2, ... 9 Erweiterungsheader) einzuschließen, um den Payload-Offset in einem Paket zu finden, vorausgesetzt, es gibt keine zusätzlichen Besonderheiten für bestimmte Fälle und es wird auch nicht versucht, einen Schutz vor fehlerhaften Paketen zu haben (was zu falsch positiven Treffern führen könnte): Ich kann nur annehmen, dass dies aufgrund der Komplexität und der mangelnden Bereitschaft, eine fehlerhafte Implementierung bereitzustellen, die solche Header ignoriert, nicht implementiert wurde.
Sogar ein einfacher Test wie dieser ip6 and tcp dst port 80
berücksichtigt keine Erweiterungsheader, wie der unten generierte BPF-Code zeigt:
$ tcpdump --version
tcpdump version 4.99.3
libpcap version 1.10.3 (with TPACKET_V3)
OpenSSL 3.0.9 30 May 2023
$ tcpdump -y EN10MB -d ip6 and tcp dst port 80
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 7
(002) ldb [20]
(003) jeq #0x6 jt 4 jf 7
(004) ldh [56]
(005) jeq #0x50 jt 6 jf 7
(006) ret #262144
(007) ret #0
Daher kann es sein, dass Sie Verkehr verpassen.
Ab tcpdump 4.99.x scheint die einzige Stelle, an der eine angemessene Handhabung der IPv6-Erweiterungsheader vorhanden ist, am Ende der Manpage dokumentiert zu sein:
ip6 proto
sollte der Header-Kette folgen, tut dies aber derzeit nicht.ip6 protochain
Für dieses Verhalten ist eine Angabe vorgesehen.
Tatsächlich ist tcpdump ab 4.99.x derzeit ip6 and tcp
gleichwertig mit ip6 proto 6
(sie erzeugen den gleichen Bytecode):
$ tcpdump -y EN10MB -d ip6 and tcp
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 8
(002) ldb [20]
(003) jeq #0x6 jt 7 jf 4
(004) jeq #0x2c jt 5 jf 8
(005) ldb [54]
(006) jeq #0x6 jt 7 jf 8
(007) ret #262144
(008) ret #0
while ip6 protochain 6
führt eine weitaus gründlichere Prüfung durch und ist das, was bei jedem Test erwartet werden sollte, an dem eine obere Schicht (letzter Transportheader) wie TCP beteiligt ist:
$ tcpdump -y EN10MB -d ip6 protochain 6
(000) ldh [12]
(001) jeq #0x86dd jt 2 jf 35
(002) ldb [20]
(003) ldx #0x28
(004) jeq #0x6 jt 32 jf 5
(005) jeq #0x3b jt 32 jf 6
(006) jeq #0x0 jt 10 jf 7
(007) jeq #0x3c jt 10 jf 8
(008) jeq #0x2b jt 10 jf 9
(009) jeq #0x2c jt 10 jf 19
(010) ldb [x + 14]
(011) st M[0]
(012) ldb [x + 15]
(013) add #1
(014) mul #8
(015) add x
(016) tax
(017) ld M[0]
(018) ja 4
(019) jeq #0x33 jt 20 jf 32
(020) txa
(021) ldb [x + 14]
(022) st M[0]
(023) txa
(024) add #1
(025) tax
(026) ldb [x + 14]
(027) add #2
(028) mul #4
(029) tax
(030) ld M[0]
(031) ja 4
(032) add #0
(033) jeq #0x6 jt 34 jf 35
(034) ret #262144
(035) ret #0
Über den 4 Tests einschließlich jt 10
und Zeilen zwischen (10
) und (018) ja 4
Schleife über 4 der spezifischen IPv6-Erweiterungsheader, um sie zu überspringen, während mit IPSec AH (19)
umgegangen (31)
wird. Ich wüsste nicht, wie man anderswo solchen Code mit dem generieren könntetcpdumpSprache (anstatt beispielsweise direktBPFCode). Die Verwendung ip6 protochain 6 and ip6 and tcp dst port 80
beginnt einfach von vorne oder schlimmer noch, anstatt den gerade erhaltenen TCP-Header zu nutzen.
Die gleiche Art von Problem wird in verschiedenen Netzwerkeinrichtungen und Tools für Linux beschrieben. Beispiel:tc u32
erzählt:
icmp_code
VAL_MASK_8Gehen Sie von einem Next-Header-Protokoll vom Typ ICMP oder IPv6-ICMP aus und passen Sie die Feldwerte für „Typ“ oder „Code“ an.Dies ist gefährlich, da der Code davon ausgehtminimale Headergröße für IPv4 undFehlende Erweiterungsheader für IPv6.
Dabei wird noch nicht einmal berücksichtigt, dass speziell bei HTTP bei Wiederverwendung der Verbindung die nächste HTTP-Abfrage möglicherweise nicht einmal am Anfang einer Paketgrenze steht, und dass eine solche als Daten statt als Abfrage eingebettete Abfrage möglicherweise übereinstimmt, wenn solche Daten am Anfang der Paketgrenze erscheinen.
Testen Sie den Fall „0 Extension-Header“ mit tcpdump
Version 4.99.x
Hier ist der Test mit 0 Erweiterungsheadern, also auf der gleichen Ebene wietcpdumptut dies derzeit, mit minimaler Überprüfung:
tcpdump -n -s 0 -A 'ip6[6] == 6 and ( ip6[4:2] - ((ip6[52] & 0xf0) >> 2) >= 4 ) and ip6[40 + ((ip6[52] & 0xf0) >> 2) :4] == 0x47455420'
Dies kann wie folgt dokumentiert werden (immer noch nur für den Fall des 0-Extension-Headers, bei dem der TCP-Header immer an Position 40 beginnt):
Der nächste Header ist TCP
ip6[6] == 6
IPv6Nutzlastlänge:
ip6[4:2]
TCPDatenoffset (feste IPv6-Größe von 40 + 12 = 52) (und entsprechende Anpassung, um Bytes zu erhalten)
(ip6[52] & 0xf0) >> 2
TCP-Nutzlastlänge = IPv6-Nutzlastlänge – TCP-Datenoffset
Testen Sie, ob mindestens 4 Byte TCP-Nutzlast für mindestens die Länge von „GET“ vorhanden sind.
ip6[4:2] - ((ip6[52] & 0xf0) >> 2) >= 4
Die in ASCII/UTF-8 kodierte 4-Byte-Zeichenfolge „GET“ kann mit dem 4-Byte-Wert 0x47455420 dargestellt werden.
Der TCP-Nutzlastoffset ist die feste IPv6-Headerlänge (40) + der TCP-Datenoffset
40 + ((ip6[52] & 0xf0) >> 2)
Testen Sie, ob das erste 4-Byte-Wort ab der festen IPv6-Headerlänge (40) + Datenoffset dem Wert für die Zeichenfolge „GET“ entspricht.
ip6[40 + ((ip6[52] & 0xf0) >> 2) :4] = 0x47455420
Nftablesmit Linux-Kernel >= 5.15.54 +tcpdump
Ich schlage eine einfache alternative Methode nur für Linux vor, dieNftablesund erfordert einen ausreichend aktuellen Kernel (Linux-Kernel-Version>= 5.15.54zurückportiert von5.16) sowieNftables>= 1.0.1zur Unterstützung der@ih
(innerer Header/Nutzlast) Rohnutzlast, und nicht nur @th
(Transportheader), weilNftables@th
selbst ist viel zu eingeschränkt, um beliebige Verarbeitungen auf sinnvolle Weise durchzuführen .
Das IPv6-Datagramm wurde bereits analysiert, einschließlich aller IPv6-Erweiterungsheader, und sowohl @th- als auch @in-Zeiger sind bereits verfügbar fürNftables: Es ist keine weitere Verarbeitung erforderlich, um alle Fälle zu erhalten. Ich verlasse mich aufNftableseine Prüfung scheitern zu lassen, wenn das Paket zu kurz ist, ohne die tatsächliche TCP-Nutzlastgröße berechnen zu müssen (im Gegensatz zutcpdumpund BPF,Nftableskann keine Subtraktionen durchführen, daher gibt es keine Möglichkeit, die Größe richtig zu überprüfen).
DerNftablesDas folgende Beispiel versucht, das genaue Beispiel des OP nachzuahmen, kann dies aber nicht immer in allen Details ohne gewisse Anpassungen. Keine Richtung oder Port, erfasst eingehende Pakete vor NAT und ausgehende Pakete nach NAT (daher die gewählten Hooks und Prioritäten). Das ausgewählte Paket wird schließlichgesendet an dieAbonnierenEinrichtung:
In der zweiten Form der Anrufung (wennnflog_gruppeangegeben ist), übergibt der Linux-Kernel das Paket an nfnetlink_log, das das Protokoll über einen Netlink-Socket an die angegebene Gruppe sendet. Ein Userspace-Prozess kann die Gruppe abonnieren, um die Protokolle zu erhalten [...]
table ip6 special_log
delete table ip6 special_log
table ip6 special_log {
chain log_to_nflog {
log group 4242
}
chain ih_filter {
meta l4proto tcp @ih,0,32 0x47455420 counter jump log_to_nflog
}
chain c_ingress {
type filter hook prerouting priority -150; policy accept;
jump ih_filter
}
chain c_egress {
type filter hook postrouting priority 150; policy accept;
jump ih_filter
}
}
Unter LinuxAbonnierenDie Einrichtung ist als Pseudoschnittstelle verfügbar für (libpcapUnd)tcpdump:
# tcpdump -D |grep nflog
12.nflog (Linux netfilter log (NFLOG) interface) [none]
Die vonNftableskann daher wie folgt angezeigt werden (unter Wiederverwendung der gleichen NFLOG-Gruppe: 4242):
tcpdump -n -s 0 -A -i nflog:4242
Vorbehalt: Es gibt mehr Latenz als bei einer direkten Aufnahme.
Hinweis: Richtige Handhabung durchNftableseines Falles mit einem Erweiterungsheader wurde tatsächlich mit UDP (anstatt TCP) und fragmentierten Paketen (verarbeitet durch denFragmentkopfzeile) verwenden socat
(in einem separaten Netzwerk-Namespace, um nf_defrag_ipv6
ein Eingreifen zu verhindern), weil es viel einfacher ist, mit UDP ein fragmentiertes Paket zu generieren als mit TCP und ich keine andere Methode gefunden habe, um irgendwo einen Erweiterungsheader zu haben.