We're now a non-profit! Support open source packet analysis by making a donation.

Wireshark-users: Re: [Wireshark-users] Complex Capture Filter Problem

From: Guy Harris <guy@xxxxxxxxxxxx>
Date: Fri, 14 Sep 2007 14:29:21 -0700

On Sep 13, 2007, at 1:45 PM, Travis Love wrote:

I'm trying to create a capture filter to help detect rogue DHCP servers with Wireshark. So far, what I've come up with is a capture and a viewing filter, each of which does half the work I need it to. The capture filter looks like:

(port 67 or port 68) and !(ether host 00:04:23:XX:XX:XX) and ! (ether host 00:04:23:XX:XX:YY)

So it captures only DHCP packets that aren't to/from either of our DHCP servers. I then have to apply:

frame[282:3] == 35:01:02 or frame[282:3] == 35:01:05 or frame[282:3] == 35:01:06

as a viewing filter in order to see only NAK, ACK, and DHCP OFFER packets. Is there a way to put the viewing filter into the capture filter so my box's RAM doesn't fill up with packets I'm not interested in?

If you want to move a test from a display filter that refers to frame[] to a capture filter that refers to frame[], for at least some network types, you can do that, although, given that libpcap/WinPcap's capture filter compiler isn't as fancy as Wireshark's display filter compiler, it involves some extra work.

From the tcpdump man page:

selects which packets will be dumped. If no expression is given, all packets on the net will be dumped. Otherwise, only
              packets for which expression is `true' will be dumped.

The expression consists of one or more primitives. Primitives usually consist of an id (name or number) preceded by one or
              more qualifiers. ...


More complex filter expressions are built up by using the words and, or and not to combine primitives. E.g., `host foo and not port ftp and not port ftp-data'. To save typing, identical qualifier lists can be omitted. E.g., `tcp dst port ftp or ftp- data or domain' is exactly the same as `tcp dst port ftp or tcp
              dst port ftp-data or tcp dst port domain'.

              Allowable primitives are:


              expr relop expr
True if the relation holds, where relop is one of >, <, >=, <=, =, !=, and expr is an arithmetic expression com- posed of integer constants (expressed in standard C syn- tax), the normal binary operators [+, -, *, /, &, |, <<, >>], a length operator, and special packet data acces- sors. Note that all comparisons are unsigned, so that, for example, 0x80000000 and 0xffffffff are > 0. To access data inside the packet, use the following syntax:
                          proto [ expr : size ]
Proto is one of ether, fddi, tr, wlan, ppp, slip, link, ip, arp, rarp, tcp, udp, icmp, ip6 or radio, and indi- cates the protocol layer for the index operation. (ether, fddi, wlan, tr, ppp, slip and link all refer to the link layer. radio refers to the "radio header" added to some 802.11 captures.) Note that tcp, udp and other upper-layer protocol types only apply to IPv4, not IPv6 (this will be fixed in the future). The byte offset, relative to the indicated protocol layer, is given by expr. Size is optional and indicates the number of bytes in the field of interest; it can be either one, two, or four, and defaults to one. The length operator, indi- cated by the keyword len, gives the length of the packet.

Fetches with a "size" value of 2 or 4 (the only valid values are 1, 2, and 4; see previous comment about libpcap/WinPcap's limitations) are big-endian.

That means that

frame[282:3] == 35:01:02 or frame[282:3] == 35:01:05 or frame[282:3] == 35:01:06

should translate to

(link[282:2] == 0x3501 and link[284:1] == 0x02) or (link[282:2] == 0x3501 and link[284:1] == 0x05) or (link[282:2] == 0x3501 and link[284:1] == 0x06)

(simplification of that is left as an exercise for the reader). I did a 2-byte comparison because that generates fewer BPF instructions; it might be that a 4-byte comparison after masking out the 4th byte would be even better.