Berkeley Packet Filter

The Berkeley Packet Filter (BPF) provides link-layer access to data available on the network through interfaces attached to the system.

To use BPF, open a device node, /dev/bpf, and then issue ioctl() commands to control the operation of the device. A popular example of a tool using BPF is tcpdump (see the Utilities Reference).

The device /dev/bpf is a cloning device, meaning you can open it multiple times. It is in principle similar to a cloning interface, except BPF provides no network interface, only a method to open the same device multiple times.

To capture network traffic, you must attach a BPF device to an interface. The traffic on this interface is then passed to BPF for evaluation. To attach an interface to an open BPF device, use the BIOCSETIF ioctl() command. The interface is identified by passing a struct ifreq, which contains the interface name in ASCII encoding. This is used to find the interface from the kernel tables. BPF registers itself to the interface's struct ifnet field, if_bpf, to inform the system that it's interested in traffic on this particular interface. The listener can also pass a set of filtering rules to capture only certain packets, for example ones matching a given combination of host and port.

BPF captures packets by supplying a bpf_tap() tapping interface to link layer drivers, and by relying on the drivers to always pass packets to it. Drivers honor this request and commonly have code which, along both the input and output paths, does:

#if NBPFILTER > 0
    if (ifp->if_bpf)
        bpf_mtap(ifp->if_bpf, m0);
#endif

This passes the mbuf to the BPF for inspection. BPF inspects the data and decides if anyone listening to this particular interface is interested in it. The filter inspecting the data is highly optimized to minimize the time spent inspecting each packet. If the filter matches, the packet is copied to await being read from the device.

The BPF tapping feature and the interfaces provided by pfil provide similar services, but their functionality is disjoint. The BPF mtap wants to access packets right off the wire without any alteration and possibly copy them for further use. Callers linking into pfil want to modify and possibly drop packets.

BPF has quite a rich and complex syntax and is a standard interface that is used by a lot of networking software. It should be your interface of first choice when packet interception / transmission is required. It will also be a slightly lower performance interface given that it does operate across process boundaries with filtered packets being copied before being passed outside of the stack domain and into the application domain. The tcpdump and libpcap library operate using the BPF interface to intercept and display packet activity.