Wireshark-users: Re: [Wireshark-users] Complex Capture Filter Problem
From: Guy Harris <[email protected]>
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:

        expression
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.