libpcap
libpcap copied to clipboard
Possible filter Bug when using MPLS
Version:
tcpdump version 4.9.3 libpcap version 1.8.1 OpenSSL 1.1.1 11 Sep 2018
As indicated in this issue https://github.com/the-tcpdump-group/libpcap/issues/1070 I am doing some packet filtering on ip.tos field, however, the expected packets that might come can be normal ethernet
+ip
or can have mpls
headers in between. As shown in that previous issue I ended up using filters of the following nature:
tcpdump -n -i <intf> "(ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14)"
This is the only way I found to parse packets with mpls headers (in this case, up to 9 stacked labels). Now, this seemed to work well, until today which I started to see some specific TCP ACK packets (not sure if other packets could match too) started to be captured as well. After some investigation, I found out that, this only happens when I parse more than 8 MPLS labels, thus I deduced this had to be related to the depth of the parsing.
Now, I was thinking, why is this even matching the filter at all? I looked at all the packets that are matching this filter, and they all have the byte 51 equal to 0x0e
(which is 14 and its the tos field I am matching).
For example, the following packet, matches the filter (this is a normal tcp ack, with tos field equal 0, but with a byte equal 0x0e... in a very specific place which I guess triggers this weird behaviour.
0e8ee077695a1ac57a389fb5080045000034150840003e0604bb0a0007010a0008010139013110075f69d5828e0c801097624b0e00000101080ad317debb605f89ae
Is this a bug? How can it even match this packet, when the ether type is not mpls, and thus it should not even parse that deep? And even if it did it, it should not match?
Thank you for providing this analysis. This might be a bug, but to tell it would be necessary to reproduce this behaviour. Could you add a .pcap file with at least one packet that triggers the false positive?
Do you see the same behavior if you disable the optimizer?
--no-optimize
Do not run the packet-matching code optimizer. This is useful only if you suspect a bug in the optimizer.
I see some curious output in the optimized code (run tcpdump -d
with your filter), but haven't taken the time to diagram exactly what it's looking at in the packet.
Hi @infrastation
Here I upload a pcap where you can see this behaviour. This is a pcap that was captured with this exact filter, and there is one packet that should not be there, its a TCP packet for which I added the hex in my original post.
If you run the filter, the TCP packet passes the filter (due to the matching 0x0e by chance...)
tcpdump -r PAR-eth10.pcap "(ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14)"
If yo remove 1 ((mpls && ip[1]==14)), then only the MPLS/UDP packets match.
tcpdump -r PAR-eth10.pcap "(ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14) or (mpls && ip[1]==14)"
@fenner Same happens with --no-optimize
flag.
The bug exists in the program whether there are 8 or 9 copies, it's just that once you get to 9, you happen to get to offset 51 looking for the 0xe, and there's a 0xe in the tcp checksum of that packet.
The bug is early on:
(000) ldh [12]
(001) jeq #0x800 jt 2 jf 4
(002) ldb [15]
(003) jeq #0xe jt 93 jf 13
(004) jeq #0x8847 jt 5 jf 13
(005) ldb [16]
(006) and #0x1
(007) jeq #0x1 jt 8 jf 13
(008) ldb [18]
(009) and #0xf0
(010) jeq #0x40 jt 11 jf 13
(011) ldb [19]
(012) jeq #0xe jt 93 jf 13
(013) ldb [16]
(014) jset #0x1 jt 23 jf 15
In instruction 1, we check for ether proto IP; then in instruction 3 we check if ip[1] == 14. That's correctly implementing your first (ip[1]==14)
clause. But, if ip[1] != 14, we jump over the check for ether proto MPLS at instruction 4, and head straight to the "does the first label have bos set" at 13/14.
Just adding information for now, no insight as to what the expression generator is doing wrong.
I converted the tcp packet's ethertype to MPLS, and that makes it clear that the filter is even more buggy - it moves past the BOS bit on (what would be) the 3rd label and selects the packet based on the 0x470e
(guessing based on 0x47 & 0xf0 == 0x40 that it's IP, then the 0x0e that you're looking for) that happens to appear what would be 6 labels further in.
demo.zip