Wie man mit tcpdump auf doppelt getagged Pakete prüft

Für einen bpf Filter benötige ich die Möglichkeit mehrfach mit VLANs getaggte Pakete zu erkennen und in deren Inhalt nach protokollspezifischen Werten zu durchsuchen. Natürlich möchte ich die binären Regeln nicht komplett von Hand schreiben.

Der einfache Ansatz ist sich das Regelwerk durch tcpdump selbst erzeugen zu lassen.

# tcpdump -s 0 -p -d 'ip and udp and src port 12345'
(000) ldh      [12]
(001) jeq      #0x800           jt 2    jf 10
(002) ldb      [23]
(003) jeq      #0x11            jt 4    jf 10
(004) ldh      [20]
(005) jset     #0x1fff          jt 10   jf 6
(006) ldxb     4*([14]&0xf)
(007) ldh      [x + 14]
(008) jeq      #0x3039          jt 9    jf 10
(009) ret      #262144
(010) ret      #0

Dieser Code macht folgendes:

  • Im Ethernet-Header (an Position 12) wird der Ethertype ermittelt.
  • Ist der IPv4 (0800), so geht's bei 2 weiter, anderenfalls Abbruch zu 10.
  • Im IP-Header (an Position 23 aus Sicht des kompletten Frames) steht die Protokollnummer.
  • Ist diese UDP (17 = 0x11), geht's weiter.
  • Nach dem variabel langen IP-Header (Länge in 32bit Worten an Position 14) folgt der UDP Header.
  • Dort steht an (der variablen) Position die Portnummer.
  • Entspricht die dem gewünschten Wert, gibt's einen positiven Rückgabewert (der i.d.R. die Länge der zu exahierenden Daten entspricht).
  • Anderenfalls gibt es den Fehlercode 0 zurück (oder auch 0 verwertbare Bytes).

Oder direkt binär, so wie ich es brauche:

# tcpdump -s 0 -p -ddd 'ip and udp and src port 12345'
11
40 0 0 12
21 0 8 2048
48 0 0 23
21 0 6 17
40 0 0 20
69 4 0 8191
177 0 0 14
72 0 0 14
21 0 1 12345
6 0 0 262144
6 0 0 0 

Dieser BPF Code nimmt an, dass das Paket direkt mit IP beginnt, es gibt keine VLAN Frames (die jeweils 4 Byte kosten).

Ich lönnte jetzt also an allen Stellen, wo auf eine Position im Paket Bezug genommen wird, einen entsprechenden Offset manuell hinzufügen. Dieses manuelle Nachpatchen ist jedoch nicht sonderlich wartungsfreundlich.

Nach einigem Suchen fand ich den undokumentierten Befehl vlan. Wenn man den vor den Ausdruck stellt, passt das tcpdump den BPF-Filter passend an.

# root@a10nsp:~ # tcpdump -s 0 -p -d 'vlan 123 and ip and udp and src port 12345'
(000) ldh      [12]
(001) jeq      #0x8100          jt 4    jf 2
(002) jeq      #0x88a8          jt 4    jf 3
(003) jeq      #0x9100          jt 4    jf 17
(004) ldh      [14]
(005) and      #0xfff
(006) jeq      #0x7b            jt 7    jf 17
(007) ldh      [16]
(008) jeq      #0x800           jt 9    jf 17
(009) ldb      [27]
(010) jeq      #0x11            jt 11   jf 17
(011) ldh      [24]
(012) jset     #0x1fff          jt 17   jf 13
(013) ldxb     4*([18]&0xf)
(014) ldh      [x + 18]
(015) jeq      #0x3039          jt 16   jf 17
(016) ret      #262144
(017) ret      #0 

Man sieht sehr schön, dass die Offsets für die Paketanalyse schön um vier Bytes verschoben wurden.

Gehen auch zwei VLANs?

# tcpdump -s 0 -p -d 'vlan 123 and vlan 456 and ip and udp and src port 12345'
(000) ldh      [12]
(001) jeq      #0x8100          jt 4    jf 2
(002) jeq      #0x88a8          jt 4    jf 3
(003) jeq      #0x9100          jt 4    jf 24
(004) ldh      [14]
(005) and      #0xfff
(006) jeq      #0x7b            jt 7    jf 24
(007) ldh      [16]
(008) jeq      #0x8100          jt 11   jf 9
(009) jeq      #0x88a8          jt 11   jf 10
(010) jeq      #0x9100          jt 11   jf 24
(011) ldh      [18]
(012) and      #0xfff
(013) jeq      #0x1c8           jt 14   jf 24
(014) ldh      [20]
(015) jeq      #0x800           jt 16   jf 24
(016) ldb      [31]
(017) jeq      #0x11            jt 18   jf 24
(018) ldh      [28]
(019) jset     #0x1fff          jt 24   jf 20
(020) ldxb     4*([22]&0xf)
(021) ldh      [x + 22]
(022) jeq      #0x3039          jt 23   jf 24
(023) ret      #262144
(024) ret      #0

Hervorragend: Nun werden doppelt getaggte Pakete ausgewertet. Allerdings muss man die VLAN Tags exakt kennen.

Ich möchte aber nur double tagged VLANs mit variablen VLAN-Nummern bearbeiten, kenne diese also nicht. Wie kann man das beschreiben? Vielleicht als Negation? Nicht VLAN 123? Gibt es eine VLAN Nummer die sicher nicht auftreten kann?

ja, die Null. Eine VLAN Header mit der VLAN-ID 0 ist definiert als untagged, gestattet aber QoS Parameter. Untagged will ich aber nicht, das ist also okay.

# tcpdump -s 0 -p -d 'not vlan 0 and not vlan 0 and ip and udp and src port 12345'
(000) ldh      [12]
(001) jeq      #0x8100          jt 4    jf 2
(002) jeq      #0x88a8          jt 4    jf 3
(003) jeq      #0x9100          jt 4    jf 6
(004) ldh      [14]
(005) jset     #0xfff           jt 6    jf 22
(006) ldh      [16]
(007) jeq      #0x8100          jt 10   jf 8
(008) jeq      #0x88a8          jt 10   jf 9
(009) jeq      #0x9100          jt 10   jf 12
(010) ldh      [18]
(011) jset     #0xfff           jt 12   jf 22
(012) ldh      [20]
(013) jeq      #0x800           jt 14   jf 22
(014) ldb      [31]
(015) jeq      #0x11            jt 16   jf 22
(016) ldh      [28]
(017) jset     #0x1fff          jt 22   jf 18
(018) ldxb     4*([22]&0xf)
(019) ldh      [x + 22]
(020) jeq      #0x3039          jt 21   jf 22
(021) ret      #262144
(022) ret      #0

Und tut!

Post a comment

Related content