While developing a network sniffer I had to find a way to write pcap logs. However the docs I found were rather fragmented. I try to do a short roundup here. In fact, the format is pretty plain and it’s a pity that there seems not to be a quick’n’easy doc for it.

Every log-file starts with a header:

struct pcap_hdr {
	unsigned long  magic;         /* always 0xa1b2c3d4 */
	unsigned short version_major; /* 2 for now */
	unsigned short version_minor; /* 4 for now */
	unsigned long  thiszone;      /* GMT to local correction */
	unsigned long  sigfigs;       /* accuracy of timestamps, 0 is fine */
	unsigned long  snaplen;       /* max length of captured packets */
	unsigned long  network;       /* data link type */

The only really significant field here is network, which defines the format of the packets. I’m using 113 in dietsniff which means DLT_LINUX_SLL (“Linux cooked sockets”), i.e. those from PF_SOCKET sockets. man pcap contains a list and explanation of more possible formats.

While the header mentioned above appears only once at the beginning of a log file, the following applies to every single packet that is written to the log. First of all, every packet is preceded with a generic header:

struct pcap_rec_hdr {
	struct timeval  ts;	/* timestamp */
	unsigned long	incl_len;	/* number of octets of packet saved in file */
	unsigned long	orig_len;	/* actual length of packet */

The timestamp of the packet, the length that is contained in the log and the real length. So it’s possible to save only a certain amount of bytes of every packet.

The following data of each packet depends heavily of the specified format. I’m going to show how I did it for DLT_LINUX_SLL: first, we need just another header (again, for each packet):

struct pcap_sll_hdr {
	unsigned short pkttype;
	unsigned short hatype;
	unsigned short halen;
	char addr[8];
	unsigned short protocol;

These fields resemble those from struct sockaddr_ll which is returned with each packet so it’s just about 4 assignments and one memcpy(). The definition of this struct can be deducted from the pcap man page in the explanation of DLT_LINUX_SLL. I guess the other types should similarly straightforward.

After this, the packet can be finally dumped to the file.