Linux – tcpdump read both ipv4 and ipv6 packets from pcap

ipv6linuxnetworkingtcpdumpwireshark

I'm trying to gain some info from payload of TCP and UDP. The filter

(tcp.stream && tcp.flags.push == 1) || udp.stream

in Wireshark gives me both IPv4 and IPv6 packets.

But I can't figure out how to do that through the tcpdump. I tried:

tcpdump -X 'tcp[tcpflags] & tcp-push != 0 or udp' -r some.pcap

But there are only IPv4 packets. Something like

tcpdump -X '((tcp[tcpflags] & tcp-push != 0) or udp) and (ip or ip6)' -r some.pcap

also displays only IPv4 packets. Any examples would be helpful.

Best Answer

Perhaps it will help you:

tcpdump 'ip6[6]==17 or udp or (ip6[6]==6 and ip6[53]&8!=0) or tcp[13]&8!=0' -X -r some.pcap

In tcpdump you can't retrieve ipv6 packets the way you are trying, because it does not support (at least up to 4.9.2 version) BPF filters under ipv6.

So,

  • ip6[6]==17 means udp over ipv6 (the 6th byte is the ipv6-header protocol field), ip6[6]==6 means tcp over ipv6 respectively;

  • ip6[53]&8!=0 means tcp-push over ipv6 (40 bytes of ipv6-header and 13th byte of tcp-header, which is tcp-flags);

  • tcp[13]&8!=0 is the same as your tcp[tcpflags] & tcp-push != 0.

More info: ipv6 tcpip pocketguide and here.

Keep in mind (!): Using ip6[6] to identify the protocol fails if any extension headers are present (as pointed by kasperd). More about ipv6 extension headers here. Hence such way tcp-packets over ipv6 with extension headers will not be captured.

Also, you can write your own simple filter for specific (e.g. to get the last character of payload) purposes like:

perl -le 'print map { /(?:Flags \[P\.\]|UDP).*(\S)$/s } split /\d{2}:\d{2}:\d{2}\.\d{6}/, `tcpdump -X -r some.pcap 2>/dev/null`'
Related Question