Wednesday, March 11, 2015

How to filter IP addresses inside GRE in tcpdump

If you ever debugged network node with GRE you should know that  painful feeling of tcpdump output. Thousands IPs and you can not differentiate them, because they are in GRE.

And there is no filters for IP addresses inside GRE. You can not say 'tcpdump -ni eth0 proto gre and host 192.168.0.1'. Well, you can, but 'host' will be used only to filter source or destination of GRE packets, not the incapsulated IP packet.

Unfortunately there is no nice syntax. Fortunately, there is some, at least.

You'll need to convert IP address to network-byte-ordered  integer. For this every octet should be converted to hex and joined together 'as is'. 100.64.6.7 will become 0x64400607.

For python: there is module ipaddress, but it's not available in default installation. So we'll do it manually with minimal code:

>>>  "0x%x%x%x%x" % tuple(map(int,'192.168.0.1'.split('.')))
'0xc0a801'

(sorry for mad code, but I wanted to keep it short).

Result of that code is 'number' representing IP address (in the example above - 192.168.0.1).

Now we can run tcpdump:

tcpdump -ni eth1 'proto gre and (ip[54:4]=0xc0a801 or ip[58:4]=0xc0a801)'

Numbers in the square brackets near 'ip' is offset and size of the field. IPv4 address is 4 bytes long. Because GRE add 42 bytes overhead (20 bytes first IP header, 8 bytes GRE header, 14 bytes encapsulated Ethernet header), we taking normal IP source/destination offset (see here) and adding it.

ip[54:4] is the source IP
ip[58:4] is the destination IP
ip [51:1] is type (protocol type, like ICMP, TCP or UDP).

ARP stuff is:

ip[56:4] (sender) and ip[66:4] (target) addresses.
ip[50:6] and ip[60:6] are (sender/target) MAC addresses (but you will need to calculate proper hex humber for 6-byte MAC - I didn't test this).

2 comments:

  1. can you provide the similar filter for ipv6 traffic inside ipv4GRE tunnel

    ReplyDelete
  2. This will show ether/IP/gre/ether/ip6/icmp (I'm using Ethernet in GRE, if you're using IP in GRE then you'll need to decrease 40 and 48 by something (maybe 14?))

    # tcpdump -i vmx0 'proto gre and (ip[40:2]=0x86dd) and (ip[48:1]=0x3a)'

    If you just want ether/IP/gre/ether/ip6/:

    # tcpdump -i vmx0 'proto gre and (ip[40:2]=0x86dd)'

    ReplyDelete