libpcapnav
In case you are used to using libpcap
, handling libpcapnav
will be
trivial. The API is intentionally just a minimal wrapper around
libpcap
calls, with a few extra functions to perform the trace file
navigation. Essentially, wherever you said "pcap" before, you
now say "pcapnav". This chapter will walk you through an example
that demonstrates how to open a trace file, navigate to specific
points in the file, and read & write packets.
To make it easier to configure your software package to use
|
If you use the autoconf/automake tools, we recommend something along the following lines for your configure script:
dnl ################################################## dnl # Check for pcapnav dnl ################################################## AC_ARG_WITH(pcapnav-config, AC_HELP_STRING([--with-pcapnav-config=FILE], [Use given pcapnav-config]), [ pcncfg="$withval" ], [ AC_PATH_GENERIC(pcapnav,, pcncfg="pcapnav-config", AC_MSG_ERROR(Cannot find libpcapnav: Is pcapnav-config in path?)) ]) pcapnav_libs=`$pcncfg --libs` pcapnav_cflags=`$pcncfg --cflags` AC_SUBST(pcapnav_libs) AC_SUBST(pcapnav_cflags) |
libpcapnav
code examplesTime for some code. We will introduce variables whenever context requires it, and not necessarily at the beginning. In order to make the API known to the compiler, include pcapnav.h. This includes pcap.h for you, so you don't need to do it.
#include <pcapnav.h> |
libpcapnav
needs a tiny bit of initialization (right now
only for debugging purposes, but this might change in the
future). After that, the functions access their stateful
information just like libpcap
through a handle structure
that you obtain as follows:
pcapnav_t *pn; /* Initialize the library */ pcapnav_init(); /* Now create a pcapnav handle */ if ( (pn = pcapnav_open_offline("foo.trace")) == NULL) { /* Didn't work -- appropriate error handling */ } |
At this point you can iterate the packets in the trace as usual, or navigate to some region in the trace. For example, you find out the timeframe that is contained in the trace:
struct bpf_timeval start_tv, end_tv; if (pcapnav_get_timespan(pn, &start_tv, &end_tv) != 0) { printf("Could not obtain timespan.\n"); /* Rest of error handling */ } |
libpcapnav
jumped close to the end of trace, resynchronized with
the packet stream and copied out the timestamp of the last packet.
Note that it is recommended to always use struct bpf_timeval when
using libpcapnav
and not struct timeval. This masks some deviations
in naming among different platforms.
Now say you know that an interesting event occurred in the traffic
at a specific time. You want to jump to the packet whose
timestamp is closest to that time, and then dump all packets
that were captured within the next ten minutes to a new trace
file. We'll need a libpcap
dumper, as usual. To obtain the
standard %pcap; handle from a %pcapnav; handle, use
pcapnav_pcap()
:
pcap_dumper_t *dumper; char *savefile; /* Obtain savefile name somehow ... */ if ( (dumper = pcap_dump_open(pcapnav_pcap(pn), savefile)) == NULL) { printf("Could not open savefile %s\n", savefile); /* Rest of error handling */ } |
Now let's jump to the timestamp we are interested in:
struct bpf_timeval event_tv; pcapnav_result_t result; /* Set event_tv to the correct time somehow ... */ /* Attempt to jump to that timestamp: */ result = pcapnav_goto_timestamp(pn, &event_tv); |
At this point, several things may have gone wrong: maybe the timestamp you are looking for actually falls outside the timeframe contained in the trace, or it was not possible to determine unambiguously the sequence of packets. After performing navigation, you should therefore always perform error checking! |
The following outcomes are possible:
PCAPNAV_DEFINITELY
: yay. This is what
you want: libpcapnav
was able to unambiguously resynchronize to
the stream.
PCAPNAV_ERROR
: a real problem occurred, such
as invalid input.
PCAPNAV_NONE
: no packet could be found;
synchronization with the packet stream failed.
PCAPNAV_CLASH
: there was more than one possible
way to resynchronize to the stream, and they all looked equally likely.
This should happen only rarely and is best resolved by attempting
the jump again, but to a slightly different offset.
PCAPNAV_PERHAPS
: it looks like libpcapnav
resynchronized
successfully, but there was not enough data to be sure, for example
near the end of a trace.
We want to be sure that things work, so we check for PCAPNAV_DEFINITELY
:
if (result != PCAPNAV_DEFINITELY) { printf("Navigation failed.\n"); /* Rest of error handling */ } |
We want the next 10 minutes of traffic, so let's obtain the timestamp of the packet we're now pointing at, and add 10 minutes as a stop condition.
struct bpf_timeval current_tv, stop_tv; if (pcapnav_get_current_timestamp(pn, ¤t_tv) != 0) { printf("Something went wrong -- invalid input?\n"); /* Rest of error handling */ } /* Current timestamp is now in current_tv, add 10 mins for stop condition: */ stop_tv = current_tv; stop_tv.tv_sec += 10*60; |
Almost there — now just iterate!
const u_char *packet_data; struct pcap_pkthdr header; do { if (! (packet_data = pcapnav_next(pn, &header))) { printf("No more packets readable -- aborting.\n"); /* Rest of error handling */ } /* Dump packet to new trace: */ pcap_dump((u_char *) dumper, &header, packet_data); current_tv = header.ts; } while (pcapnav_timeval_cmp(¤t_tv, &stop_tv) <= 0); |
We're done, now clean up:
pcap_dump_close(dumper); pcapnav_close(pn); |
In other scenarios you may find the callback-based
pcapnav_loop()
more convenient. Please
have a look at the API reference in the following chapter
for more details.
If your libpcapnav
was built with debugging support enabled (by passing
--enable-debugging
at configure time), you can enable
and disable debugging output at any time in your
program in the global pcapnav_runtime_options
structure. The relevant elements are as follows:
debug
: enables debugging output when
set to a value >= 1, and disables it when set to 0.
Initialially, it is disabled.
calldepth_limit
: you can limit the calldepth
up to which debugging output is displayed, to avoid excessive logging.
By default, everything is logged (loglevel 0).
Setting these values in a non-debugging libpcapnav
will still compile (no need
for preprocessor hacks) but won't have any effect.
libpcapnav
to append packets to existing traces When creating an output dumper using libpcap
(using
pcap_dump_open()
), the output trace file
is created from scratch. Using libpcapnav
, you can also create
a libpcap
dumper out of an existing trace and append packets
at the trace's end.
The function you use for this purpose is
pcapnav_dump_open()
.
It allows you to append packets to an existing trace file, given that the linklevel
protocols are the same (that's imposed by the current libpcap
file format).
There are three different modes you can select for the operation:
LND_DUMP_TRUNC
: the normal way. The output file,
if it exists already, is truncated and new packets are written from
the beginning. Otherwise the output trace is created, just as with
pcap_dump_open()
.
LND_DUMP_APPEND_SAFE
: appends packets to the end of the
trace, including checking whether the last packet is truncated or not.
Truncated packets occur when a libpcap
packet header is present in the
trace and indicates a packet size that is not actually fully present
in the file. In this case, the size in the libpcap
header is corrected
to the part of the packet actually present, and new packets are appended
after that.
LND_DUMP_APPEND_FAST
: appends packets to the end of the
trace, without paranoia checking. This is much faster than the safe alternative
above, but should only be used when you can assume that the existing trace is
not truncated at the end (for example, because you just created it and closed
it properly).
Once you're done, you can close the dumper as usual, using
pcap_dump_close()
.