In this lession we are going to learn how to handle packet capture to a file (dump to file). WinPcap offers a wide range of functions to save the network traffic to a file and to read the content of dumps – this lesson will teach how to use all of these functions. We'll see also how to use the kernel dump feature of WinPcap to obtain high-performance dumps (NOTE: At the moment, due to some problems with the new kernel buffer, this feature has been disabled).
The format for dump files is the libpcap one. This format contains the data of the captured packets in binary form and is a standard used by many network tools including WinDump, Ethereal and Snort.
Saving packets to a dump file
First of all, let's see how to write packets in libpcap format.
The following example captures the packets from the selected interface and saves them on a file whose name is provided by the user.
#include "pcap.h"
void packet_handler(u_char *param,
const struct pcap_pkthdr *header,
const u_char *pkt_data);
int main(int argc, char **argv)
{
int inum;
int i=0;
if(argc != 2)
{
printf("usage: %s filename", argv[0]);
return -1;
}
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
for(d=alldevs; d; d=d->
next)
{
printf(
"%d. %s", ++i, d->
name);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf_s("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
return -1;
}
for(d=alldevs, i=0; i< inum-1 ;d=d->
next, i++);
65536,
1000,
NULL,
errbuf
) ) == NULL)
{
fprintf(stderr,
"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->
name);
return -1;
}
if(dumpfile==NULL)
{
fprintf(stderr,"\nError opening output file\n");
return -1;
}
printf(
"\nlistening on %s... Press Ctrl+C to stop...\n", d->
description);
pcap_loop(adhandle, 0, packet_handler, (
unsigned char *)dumpfile);
return 0;
}
void packet_handler(u_char *dumpfile,
const struct pcap_pkthdr *header,
const u_char *pkt_data)
{
}
#define PCAP_OPENFLAG_PROMISCUOUS
Defines if the adapter has to go in promiscuous mode.
#define PCAP_SRC_IF_STRING
String that will be used to determine the type of source in use (file, remote/local interface).
struct pcap pcap_t
Descriptor of an open capture instance. This structure is opaque to the user, that handles its conten...
struct pcap_dumper pcap_dumper_t
libpcap savefile descriptor.
#define PCAP_ERRBUF_SIZE
Size to use when allocating the buffer that contains the libpcap errors.
pcap_t * pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
Open a generic source in order to capture / send (WinPcap only) traffic.
void pcap_freealldevs(pcap_if_t *alldevsp)
Free an interface list returned by pcap_findalldevs().
void pcap_dump(u_char *user, const struct pcap_pkthdr *h, const u_char *sp)
Save a packet to disk.
int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
Collect a group of packets.
pcap_dumper_t * pcap_dump_open(pcap_t *p, const char *fname)
Open a file to write packets.
int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
Create a list of network devices that can be opened with pcap_open().
Item in a list of interfaces, used by pcap_findalldevs().
char * name
a pointer to a string giving a name for the device to pass to pcap_open_live()
struct pcap_if * next
if not NULL, a pointer to the next element in the list; NULL for the last element of the list
char * description
if not NULL, a pointer to a string giving a human-readable description of the device
Header of a packet in the dump file.
As you can see, the structure of the program is very similar to the ones we have seen in the previous lessons. The differences are:
- a call to pcap_dump_open() is issued once the interface is opened. This call opens a dump file and associates it with the interface.
- the packets are written to this file with a pcap_dump() from the packet_handler() callback. The parameters of pcap_dump() are in 1-1 correspondence with the parameters of pcap_handler().
Reading packets from a dump file
Now that we have a dump file available, we can try to read its content. The following code opens a WinPcap/libpcap dump file and displays every packet contained in the file. The file is opened with pcap_open_offline(), then the usual pcap_loop() is used to sequence through the packets. As you can see, reading packets from an offline capture is nearly identical to receiving them from a physical interface.
This example introduces another function: pcap_createsrcsrc(). This function is required to create a source string that begins with a marker used to tell WinPcap the type of the source, e.g. "rpcap://" if we are going to open an adapter, or "file://" if we are going to open a file. This step is not required when pcap_findalldevs_ex() is used (the returned values already contain these strings). However, it is required in this example because the name of the file is read from the user input.
#include <stdio.h>
#include <pcap.h>
#define LINE_LEN 16
void dispatcher_handler(u_char *,
const struct pcap_pkthdr *,
const u_char *);
int main(int argc, char **argv)
{
if(argc != 2){
printf("usage: %s filename", argv[0]);
return -1;
}
NULL,
NULL,
argv[1],
errbuf
) != 0)
{
fprintf(stderr,"\nError creating a source string\n");
return -1;
}
65536,
1000,
NULL,
errbuf
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the file %s.\n", source);
return -1;
}
return 0;
}
void dispatcher_handler(u_char *temp1,
const struct pcap_pkthdr *header,
const u_char *pkt_data)
{
u_int i=0;
(VOID)temp1;
printf(
"%ld:%ld (%ld)\n", header->
ts.tv_sec, header->
ts.tv_usec, header->
len);
for (i=1; (i < header->
caplen + 1 ) ; i++)
{
printf("%.2x ", pkt_data[i-1]);
if ( (i % LINE_LEN) == 0) printf("\n");
}
printf("\n\n");
}
#define PCAP_SRC_FILE
Internal representation of the type of source in use (file, remote/local interface).
#define PCAP_BUF_SIZE
Defines the maximum buffer size in which address, port, interface names are kept.
int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf)
Accept a set of strings (host name, port, ...), and it returns the complete source string according t...
struct timeval ts
time stamp
bpf_u_int32 len
length this packet (off wire)
bpf_u_int32 caplen
length of portion present
The following example has the same purpose of the last one, but pcap_next_ex() is used instead of the pcap_loop() callback method.
#include <stdio.h>
#include <pcap.h>
#define LINE_LEN 16
int main(int argc, char **argv)
{
const u_char *pkt_data;
u_int i=0;
int res;
if(argc != 2)
{
printf("usage: %s filename", argv[0]);
return -1;
}
NULL,
NULL,
argv[1],
errbuf
) != 0)
{
fprintf(stderr,"\nError creating a source string\n");
return -1;
}
65536,
1000,
NULL,
errbuf
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the file %s.\n", source);
return -1;
}
{
printf(
"%ld:%ld (%ld)\n", header->
ts.tv_sec, header->
ts.tv_usec, header->
len);
for (i=1; (i < header->
caplen + 1 ) ; i++)
{
printf("%.2x ", pkt_data[i-1]);
if ( (i % LINE_LEN) == 0) printf("\n");
}
printf("\n\n");
}
if (res == -1)
{
printf(
"Error reading the packets: %s\n",
pcap_geterr(fp));
}
return 0;
}
int pcap_next_ex(pcap_t *p, struct pcap_pkthdr **pkt_header, const u_char **pkt_data)
Read a packet from an interface or from an offline capture.
char * pcap_geterr(pcap_t *p)
return the error text pertaining to the last pcap library error.
Writing packets to a dump file with pcap_live_dump
NOTE: At the moment, due to some problems with the new kernel buffer, this feature has been disabled.
Recent versions of WinPcap provide a further way to save network traffic to disk, the pcap_live_dump() function. pcap_live_dump() takes three parameters: a file name, the maximum size (in bytes) that this file is allowed to reach and the maximum amount of packets that the file is allowed to contain. Zero means no limit for both these values. Notice that the program can set a filter (with pcap_setfilter(), see the tutorial Filtering the traffic) before calling pcap_live_dump() to define the subset of the traffic that will be saved.
pcap_live_dump() is non-blocking, therefore it starts the dump and returns immediately: The dump process goes on asynchronously until the maximum file size or the maximum amount of packets has been reached.
The application can wait or check the end of the dump with pcap_live_dump_ended(). Beware that if the sync parameter is nonzero, this function will block your application forever if the limits are both 0.
#include <stdlib.h>
#include <stdio.h>
#include <pcap.h>
#error At the moment the kernel dump feature is not supported in the driver
main(int argc, char **argv) {
u_int inum, i=0;
printf("kdump: saves the network traffic to file using WinPcap kernel-level dump faeature.\n");
printf("\t Usage: %s [adapter] | dump_file_name max_size max_packs\n", argv[0]);
printf("\t Where: max_size is the maximum size that the dump file will reach (0 means no limit)\n");
printf("\t Where: max_packs is the maximum number of packets that will be saved (0 means no limit)\n\n");
if(argc < 5){
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
for(d=alldevs; d; d=d->
next)
{
printf(
"%d. %s", ++i, d->
name);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return -1;
}
printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
return -1;
}
for(d=alldevs, i=0; i< inum-1 ;d=d->
next, i++);
{
fprintf(stderr,"\nError opening adapter\n");
return -1;
}
printf(
"Unable to start the dump, %s\n",
pcap_geterr(fp));
return -1;
}
}
else{
{
fprintf(stderr,"\nError opening adapter\n");
return -1;
}
printf(
"Unable to start the dump, %s\n",
pcap_geterr(fp));
return -1;
}
}
return 0;
}
pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf)
Open a live capture from the network.
int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf)
Construct a list of network devices that can be opened with pcap_open_live().
void pcap_close(pcap_t *p)
close the files associated with p and deallocates resources.
int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks)
Save a capture to file.
int pcap_live_dump_ended(pcap_t *p, int sync)
Return the status of the kernel dump process, i.e. tells if one of the limits defined with pcap_live_...
The difference between pcap_live_dump() and pcap_dump(), apart from the possibility to set limits, is performance. pcap_live_dump() exploits the ability of the WinPcap NPF driver (see NPF driver internals manual) to write dumps from kernel level, minimizing the number of context switches and memory copies.
Obviously, since this feature is currently not available on other operating systems, pcap_live_dump() is WinPcap specific and is present only under Win32.
<<< Previous Next >>>