Content-type: text/html Manpage of LIBPNET6


Section: LIBPNET6 API Reference (3)
Updated: March 30, 2003
Index Return to Main Contents



 - libpnet6's functionality to access raw network packets, (the so-called packet "sniffing"). See pnet6(3) for an introduction to libpnet6.

This document describes the functions in libpnet6 that you can use to read and write raw network packets directly from or to a network interface card (in less fancy terms, this is referred to as "packet sniffing" and "packet injection").

In particular, this section will explain the PNET_PKTACCESS and PNetPacket structures and the functions used with them.

You'll need to include <pnet6pkt.h> next to <pnet6.h> in order to be able to use the functions described here.



libpnet6 provides a simple API to access a network interface card directly so as to be able to read and write custom network packets (not only IP, but anything), bypassing the kernel network stack. Normally, such functionality is desired when a user application needs to interpret special packets, such as ARP packets, or IP packets that carry datagrams with a protocol unknown to the kernel. This moves packet handling out of the kernel and into user level applications, which promotes simplicity, maintenance and non-intrusive software upgrades (i.e., no kernel update and recompilation will be necessary in order to handle non-standard network datagrams).

libpnet6 refers to packet sniffing and injection as "packet access". Packet access happens through two data structures: the opaque and the non-opaque PNetPacket struct.



Packets are accessed through an interface (normally an ethernet card, but can be anything, such as a PPP link). The actual device that receives a packet is represented in libpnet6 by the PNET_PKTACCESS object. This is a description of the actual network interface and differs significantly per operating system. For that reason, it is an opaque object, meaning, its elements are not accessible directly, but only through the functions described here.

In order to access the network in raw mode, a PNET_PKTACCESS object must be create and initialized. After that packets can be read or written through this object. Each PNET_PKTACCESS object maintains a single buffer where incoming packets are stored. Packets are made available to the application through the following struct:

typedef struct pnet_pkt {
    pnet_ulong   pkt_tssec;   /* Seconds and microseconds timestamp */
    pnet_ulong   pkt_tsusec;  /* of when we got this packet measured in UT */
    pnet_ushort  pkt_grablen; /* # bytes we got from the real packet */
    pnet_uint    pkt_datalen; /* Actual length of the packet */
    byte*        pkt_buf;     /* Pointer to packet payload (shared!) */ 
    PNET_PKTACCESS pkt_pa;    /* PacketAccess interface we got packet from */
} PNetPacket;

When an application makes a read request for the next packet, its pkt_buf member is set to point to a position inside the (common) buffer for the given PNET_PKTACCESS object, which is identified through the pkt_pa member. The length of the packet inside this buffer is given by the pkt_grablen member, while pkt_datalen normally holds the real amount of bytes the packet contains. I say normally, because some operating systems fail to provide an accurate value for this member. In such cases, pkt_datalen is equal to pkt_grablen. Finally, each packet has a timestamp of when it was received (which can differ from the time it is actually accessed by the application through a read call).

Normally, an application is not interested in all packets on the network. However, it is possible to put a network interface card (if it supports it) in the so-called promiscuous mode. This causes the card to receive a copy of every single packet that passes by, and makes it available to the application. The two issues related to this are

1. network traffic privacy;

2. efficiency.

The first point means that an application which accesses network traffic using an interface card in promiscuous mode is able to monitor other people's traffic. Not only is this morally and ethically questionable, it can also be quite illegal in most democratic countries. However, it is not our place to judge anyone, since this feature can have its legitimate uses.

The second point is more interesting from a computer programmer's point of view. On large networks, traffic loads can be considerable. Since an application normally does not need to inspect (or even can for that matter) every single packet, it will be forced to filter out unwanted packets. Fortunately, libpnet6 provides a very easy way of placing a packet filter on a PNET_PKTACCESS device. This is described below.



All functions return -1 on failure, and 0 on success. In the current version of libpnet6, any errors are logged to a file or the standard error stream.

PNET_PKTACCESS pnetPktOpenInterface( const char * ifname, int promiscuous ,int msec ,int glen );

Initializes and opens a PNET_PKTACCESS object. The actual device to use for packet access is passed as the argument ifname. The name to use is the one reported by "ifconfig" (for Linux this is normally "eth0" or "eth1"; for FreeBSD this can be for instance "rl0" or something else). The promiscuous flags tells libpnet6 to put the device into promiscuous mode, that is, it tells the device to receive all packets that pass by, not only the ones destined for the local host. (NOTE: be aware that this makes it in essence possible to spy on other people's network traffic, something which is hardly legal in most democratic countries. For this purpose, an applicatoin should never look at the contents of other people's packets, but only at their headers---which still borders on the morally questionable.) The msec argument causes the device to wait at least that many milliseconds before returning from a read operation. This is useful if your operating system supports kernel level packet buffering, since it reduces the number of kernel-user space copy operations---the kernel can return more than one packet per single read operation (provided more than one packets arrive within the time interval specified), which reduces load. This features is not available on all systems.

The last argument glen indicates the number of bytes per packet that libpnet6 should read. Since most interesting information is contained within a packet's headers (usually up to the first 100 or so bytes), restricting read calls to return this amount of data keeps overhead low, while providing all the useful information.

If the function succeeds, a non-NULL pointer is returned, representing a valid packet access device. NULL is returned on error.

int pnetPktAddFilter(PNET_PKTACCESS * pa, const char * expr);

This function expects a string containing an expression that describes a packet filter. Such an expression is then translated into a form that the kernel can understand, and is installed on the given PNET_PKTACCESS device. All packets will now be checked against this filter by the kernel, and only those packets that pass will be handed over to the application. This saves considerable times since unwanted packets never have to go through an expensive kernel-user space copy operation only to be rejected by the application.

The actual filter expressions are identical to the ones used by applicatoins like ''tcpdump'' or ''ethereal''. Refer to their man pages for the precise details of packet filter expressions.

void pnetPktCloseInterface( PNET_PKTACCESS pa );

Closes the packet access device corresponding to pa, which it assumes to be a structrure returned by a successful previous call to pnetPktOpenInterface().

int pnetPktGetStats(PNET_PKTACCESS pa, pnet_uint * rcv, pnet_uint * dropped);

Returns statistics about the amount of packets the interface has received. The variable rcv is set to the number of packets that the interface has actually received, while dropped is set to the number of packets that were dropped (either by the interface itself, or the kernel) due to lack of buffering space, usually because the application is not able to keep up with the flow of packets. Returns 0 on success, -1 on failure.

NOTE: see below for details on how to restrict the flow of packets passed to the application.

int pnetPktSetReadMode(PNET_PKTACCESS pa, int mode);

Sets the read mode of the interface. Read mode can be raw, or cooked: in raw-mode, the entire packet, including link-layer headers is returned by a read call. In cooked-mode, libpnet6 strips the link-layer headers from each packet before handing it over to an application. The advantage of cooked mode is that it saves you the trouble of having to parse the actual link layer headers, which requires you to know the type of underlying link. The modeFp can be either PNET_READ_RAW, enabling raw read mode, and PNET_READ_COOKED, enabling cooked read mode.

By default, an interface is in raw mode after a call to pnetPktOpenInterface().

int pnetPktSetReadTimeout(PNET_PKTACCESS pa, int msec);

Sets a time-out for read operations on this interface. A read call will block msec number of milliseconds prior to returning, enabling the kernel to buffer more than one packet should they arrive withing the specified time-out interval. This reduces copy operations accross the kernel/user space boundary. This buffering is not supported by all operating systems and kernels.

int pnetPktNextPacket(PNET_PKTACCESS pa, PNetPacket * pkt);

Returns the next packet from the interface. The pkt's pkt_buf pointer is set to point to the beginning of the next packet. Depending on whether the device is in raw or cooked mode, the link-layer headers will be skipped.

int pnetPktWrite(PNET_PKTACCESS pa, pnet_byte * buf, pnet_uint blen);

Writes (injects) a packet (in)to the network. The complete packet, including a corresponding datalink header must be passed in buf. The packet's length is given by blen. Obviously, intimate knowledge of the underlying datalink type is required.

byte* pnetPktLLSource( PNetPacket* pkt, int * plen);

Returns the link-layer address of this packet. The address length is returned through plen. It is normally 6 for Ethernet, but can be different depending on the link-layer type.

byte* pnetPktLLDest( PNetPacket* pkt, int * plen);

Returns the link-layer address of this packet. The address length is returned through plen. It is normally 6 for Ethernet, but can be different depending on the link-layer type.

int pnetPktLLType( PNetPacket * pkt, int * ptype);

Returns the type of the packet as known to the datalink layer. Examples are 0x8000 for an IP packet, or 0x86dd for an IPv6 packets.


libpnet6 does not use libpcap for its packet access. However, the filter expressions recognized by pnetPktAddFilter() are identical to those recongnized by tcpdump or any other application relying on libpcap.



tcpdump, pnet6(3), pnet6-addr(3), pnet6-api(3), pnet6-aux(3), pnet6-if(3), pnet6-ip(3), pnet6-log(3), pnet6-pkt(3), pnet6-raw(3), pnet6-socket(3), pnet6-tcp(3), pnet6-threads(3), pnet6-udp(3).



The current version of libpnet6 is highly experimental.

You can always get the most recent version from





Peter Bozarov. Send mail to kingofgib (at)




This document was created by man2html, using the manual pages.
Time: 06:22:19 GMT, May 26, 2003