Question

I had filter="ip or vlan" and I pass it to libpcap like below and it is working in my application for a long time without any problem.

pcap_set_filter(pdesc->pd, filter, 0, netp);

Now I have been asked to parse arp trafic also . So I set my filter

"ip or vlan or arp or rarp"

. But my callback function is not being called for arp packets even for ip packets my function still being called.

In short my question is how to set libpcap filter correctly to get arp packets from system ?

Was it helpful?

Solution

I examined the BPF instructions in WireShark to figure out what happens. Here are the BPF filter programs for various filters:

1. Simple cases:

Filter: vlan

if the frame is VLAN-tagged then 
  return true 
else 
  return false

Filter: ip

if the frame is not VLAN-tagged and the protocol is IP then 
  return true 
else 
  return false

Filter: arp

if the frame is not VLAN-tagged and the protocol is ARP then 
  return true 
else 
  return false

Filter: rarp

if the frame is not VLAN-tagged and the protocol is RARP then 
  return true 
else 
  return false

Filter: ip or arp or rarp

if the frame is not VLAN-tagged and the protocol is either IP, ARP or RARP then 
  return true 
else 
  return false

2. Combining ip with vlan reveals that the order of search tags is important:

Your first filter was ip or vlan. Its pseudocode is as follows:

if either the frame is not VLAN-tagged and the protocol is IP 
   or the frame is VLAN-tagged
then 
  return true 
else 
  return false

For filter vlan or ip, we would like to see this:

if either the frame is VLAN-tagged
   or the frame is not VLAN-tagged and the protocol is IP
then
  return true
else
  return false  

This would mean the same, which is OK, because A or B should mean the same as B or A, shouldn't it. But we get this:

(000) ldh      [12]
(001) jeq      #0x8100          jt 4    jf 2
(002) ldh      [16]
(003) jeq      #0x800           jt 4    jf 5
(004) ret      #65535
(005) ret      #0

This means something like the following pseudocode:

if either the frame is VLAN-tagged
   or the frame is not VLAN-tagged but it has an EtherType field shifted 4 bytes right, which says the protocol is IP
then
  return true
else
  return false  

This doesn't make sense. Line (002) is unnecessary. The instructions should look like this:

(000) ldh      [12]
(001) jeq      #0x8100          jt 3    jf 2
(002) jeq      #0x800           jt 3    jf 4
(003) ret      #65535
(004) ret      #0

Maybe I will be killed for saying this, but I think this is bug in libpcap. Where does the above line (002) ldh [16] come from? If the filter was vlan and ip, then checking the bytes at offset 16 would make sense: now we want to find VLAN-tagged frames which contain an IP packet. In such frames, there are two EtherType fields: the first (at offset 12) contains the VLAN EtherType value (0x8100), an the second (at offset 16) contains the EtherType of the IP protocol (#0x800):

(000) ldh      [12]
(001) jeq      #0x8100          jt 2    jf 5
(002) ldh      [16]
(003) jeq      #0x800           jt 4    jf 5
(004) ret      #65535
(005) ret      #0

3. Why didn't your filter find ARP and RARP packets?

Your filter was ip or vlan or arp or rarp. This compiles to:

(000) ldh      [12]
(001) jeq      #0x800           jt 6    jf 2
(002) jeq      #0x8100          jt 6    jf 3
(003) ldh      [16]
(004) jeq      #0x806           jt 6    jf 5
(005) jeq      #0x8035          jt 6    jf 7
(006) ret      #65535
(007) ret      #0

This code has the above bug: libpcap tries to find the ARP and RARP EtherTypes at offset 16.

4. The solution to your problem

You can avoid the bug by adding them at the beginning of the filter: arp or rarp or ip or vlan. This compiles to:

(000) ldh      [12]
(001) jeq      #0x806           jt 5    jf 2
(002) jeq      #0x8035          jt 5    jf 3
(003) jeq      #0x800           jt 5    jf 4
(004) jeq      #0x8100          jt 5    jf 6
(005) ret      #65535
(006) ret      #0

Which means:

if either the frame is not VLAN-tagged and the protocol is either IP, ARP or RARP,
   or the frame is VLAN-tagged
then 
  return true 
else 
  return false
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top