Reputation: 1192
I want to capture TCP packets that have SYN and FIN flags set using scappy. Unfortunately using the standard scapy filter for this scenario "tcp[tcpflags] & (tcp-syn|tcp-fin) != 0" I noticed that my sniffer doesn't pick up on IPv6 traffic, only IPv4. If I set the filter simply at "tcp" I can clearly see TCP traffic on IPv6. (I also checked with Wireshark and IPv6 traffic is present).
Why can't scapy pick up on the IPv6 traffic when the filter is slightly more complex than mere protocol filtering? More specifically, I am using the following formulation to test for IPv6 capture and there is never any detected:
def testing(pkt):
if IPv6 in pkt:
print(pkt[IPv6].show())
sniff(filter="tcp[tcpflags] & (tcp-syn|tcp-fin) != 0", iface="eth0", prn=testing)
Upvotes: 1
Views: 81
Reputation: 16552
That's a libpcap issue, not a Scapy issue.
The tcp[]
filter is syntax sugar for a fairly dumb "offset from start of packet" mechanism – it does not actually search for the TCP header per-packet; it merely expands the tcp[tcpflags]
aka tcp[13]
offset (13 bytes into the TCP header) to be relative from the beginning of the entire captured packet; your filter becomes ip[20+13] & ...
.
The problem with that is, of course, IPv4 and IPv6 have different header sizes and a single offset can only be correct for one or the other. So in order to avoid accidentally matching fields for the wrong protocol, it first checks the IP version and only then checks the TCP field – and unfortunately, at the moment, it doesn't have an "else" case that would do the same for IPv6. As noted in libpcap's gencode.c:
gen_load_internal() {
/*
* The offset is relative to the beginning of
* the transport-layer header.
*
* Load the X register with the length of the IPv4 header
* (plus the offset of the link-layer header, if it's
* a variable-length header), in bytes.
*
* XXX - are there any cases where we want
* cstate->off_nl_nosnap?
* XXX - we should, if we're built with
* IPv6 support, generate code to load either
* IPv4, IPv6, or both, as appropriate.
*/
s = gen_loadx_iphdrlen(cstate);
[...]
/*
* Do the computation only if the packet contains
* the protocol in question - which is true only
* if this is an IP datagram and is the first or
* only fragment of that datagram.
*/
gen_and(gen_proto_abbrev_internal(cstate, proto), b = gen_ipfrag(cstate));
if (inst->b)
gen_and(inst->b, b);
gen_and(gen_proto_abbrev_internal(cstate, Q_IP), b);
}
Upvotes: 2