tcpdump mailing list archives

Re: How to use specific protocol filters in pcap programming


From: Guy Harris <guy () alum mit edu>
Date: Tue, 28 Apr 2009 10:04:04 -0700


On Apr 28, 2009, at 2:26 AM, Javier Gálvez Guerrero wrote:

I'm trying to catch DHCP Requests/ACK and IEEE 802.11Probe Requests and Association ACK packets in a custom C program using libpcap but I'm facing some problems when applying filter chains different than simple ones like 'ether dst X' or 'port Y'. I would like to know what should I do in order to properly get packets with libpcap that Wireshark show me when issuing filter
chains like:

bootp.option.value == 03
wlan.fc.type_subtype == 0x04

If I use a filter like the previous ones I get a filter compiling error in 'pcap_compile(descr, &fp, filter, 0, netp)', so I would like to know how to get the same information with a pcap/tcpdump-compliant filter. Any idea
about how I could do it?

Whether you can, and how you'd do it, depends on the filter.

Libpcap translates the filter into a program in a pseudo-machine language, and the program is, on many platforms (*BSD, Mac OS X, Tru64 UNIX, Linux if you have "socket filter" support in the kernel, Windows) loaded into the kernel, so that packets that don't match the filter are discarded rather than being (potentially expensively) copied from the kernel to userland or copied into a buffer shared between the kernel and userland. That means that the capabilities of the pseudo-machine are deliberately limited, so the kernel can check whether the program is "safe"; one such limitation is that it does not support backward branches, so no loops (as a way of preventing infinite loops).

Libpcap supports testing somewhat arbitrary bytes in the packet with expressions; from the tcpdump man page - or, with libpcap 1.x/tcpdump 4.x, the pcap-filter man page:

              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.

                     For example, `ether[0] & 1 != 0'  catches all  multicast
                     traffic.   The  expression `ip[0] & 0xf != 5' catches all
                     IPv4 packets with options.   The  expression  `ip[6:2]  &
                     0x1fff  = 0' catches only unfragmented IPv4 datagrams and
                     frag zero of fragmented IPv4 datagrams.   This  check  is
                     implicitly  applied  to the tcp and udp index operations.
                     For instance, tcp[0] always means the first byte  of  the
                     TCP  header,  and never means the first byte of an inter-
                     vening fragment.

                     Some offsets and field values may be expressed  as  names
                     rather  than  as  numeric values.  The following protocol
                     header field offsets are available: icmptype  (ICMP  type
                     field),  icmpcode  (ICMP  code  field), and tcpflags (TCP
                     flags field).

                     The following ICMP type field values are available: icmp-
                     echoreply,  icmp-unreach,  icmp-sourcequench,  icmp-redi-
                     rect, icmp-echo,  icmp-routeradvert,  icmp-routersolicit,
                     icmp-timxceed,  icmp-paramprob,  icmp-tstamp, icmp-tstam-
                     preply, icmp-ireq,  icmp-ireqreply,  icmp-maskreq,  icmp-
                     maskreply.

                     The  following TCP flags field values are available: tcp-
                     fin, tcp-syn, tcp-rst, tcp-push, tcp-ack, tcp-urg.

              Primitives may be combined using:

                     A parenthesized group of primitives and operators (paren-
                     theses are special to the Shell and must be escaped).

                     Negation (`!' or `not').

                     Concatenation (`&&' or `and').

                     Alternation (`||' or `or').

              Negation  has highest precedence.  Alternation and concatenation
              have equal precedence and associate left to  right.   Note  that
              explicit  and  tokens,  not  juxtaposition, are now required for
              concatenation.

For the Wireshark filter "wlan.fc.type_subtype == 0x04", you're testing for a probe request. One way to do that is to explicitly check the first byte of the link-layer header:

        (wlan[0:1] & 0xfc) == 0x40

With newer versions of libpcap - 1.0 and later - and at least some versions of libpcap on, I think, OpenBSD, you could also have a filter of

        subtype probe‐req

or

        type mgt subtype probe-req

(either would work in libpcap 1.0; I don't remember which ones work on OpenBSD).

Unfortunately, the reason why "bootp.option.value == 03" works in Wireshark is that Wireshark dissects bootp/DHCP packets by looping through the options and adding entries for each of them; the filter "bootp.option.value == 03" matches any packet that has a bootp option with the value 3. I used the word "looping" very deliberately; as noted above, libpcap filters don't support loops, so they don't support testing for packets that have a bootp option *anywhere* in it with the value 3; there *is* no pcap filter equivalent to "bootp.option.value == 03".

The good news is that, if the bootp option that says "this is a DHCP message of a particular type" is always the *first* DHCP option, you could test for *that* with a pcap filter expression. I don't have time to determine what that expression would be, however.

BTW, in order to get packets with an interface in monitor mode, should I
enter any special configuration in my libpcap application?

That depends on what version of libpcap you're using, and on what OS you're running.

With libpcap 1.0, you could use pcap_create() to create a pcap_t handle, use pcap_set_rfmon() on that pcap_t to specify that it should use monitor mode, and then use pcap_activate() to start capturing. With earlier versions of libpcap, you'd have to put the interface into monitor mode using some complicated OS-dependent and possibly interface-dependent operations.

What about pcap_lookupnet(...)?

What about it? It has nothing to do with monitor mode; it's primarily useful for getting some parameters to pass to pcap_compile(), used to make some filter expressions (those that test the network number in IPv4 addresses, for example) work.-
This is the tcpdump-workers list.
Visit https://cod.sandelman.ca/ to unsubscribe.


Current thread: