3

The greater filter filters packets by their total length. Is it possible to filter by the payload's length? I know this is possible as a display filter, but I was wondering if it's possible to do this in a capture filter.

1 Answers1

3

The method to do this is almost given as an example in tcpdump's manual, for the IPv4 case:

To print all IPv4 HTTP packets to and from port 80, i.e. print only packets that contain data, not, for example, SYN and FIN packets and ACK-only packets. (IPv6 is left as an exercise for the reader.)

tcpdump 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

The tcpdump's expression is compiled into BPF bytecode (try adding the option -d to tcpdump to see how it looks like), that can dereference pointers and do some arithmetic and bitwise operations on them.

The tcp match and the tcp[] dereference above don't allow to simply filter for TCP payload size. So the next filter substracts to the total IPv4 packet length the (variable) IP header length to get the remaining TCP segment length, then substract from the result the TCP segment data offset (thus removing the TCP segment header + options length). If the value remaining is non-zero, that means there is data in the payload.

So for example to match any IPv4 packet with a TCP data payload between 4 and 6 bytes on the eth0 interface, this would be:

tcpdump -n -s0 -p -i eth0 'ip and tcp and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) >= 4) and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) <= 6)'

Don't worry the compiled bytecode (again, that can be displayed by adding the -d option) is optimized and the result takes (here, Linux, tcpdump 4.9.3 and libpcap 1.8.3) only one more line of bytecode to add the second comparison despite the repetition.

A.B
  • 6,306