Using libpcapnav

`libpcapnav` Manual
Prev |  | Next

# Using `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.

| First of all, to make it easier to configure your software to use `libpcapnav`, it comes with a shellscript that provides the neccessary compiler and linker flags, like many other packages do: `pcapnav-config`. Use the `--cflags` option to obtain the compiler options and `--libs` to obtain the linker options.

If you use the autoconf/automake tools, I recommend something along these lines to use in your `configure` template:

    dnl ##################################################
    dnl # Check for pcapnav and pcapnav.h
    dnl ##################################################
    AC_ARG_WITH(pcapnav,
                AC_HELP_STRING([--with-pcapnav=DIR], [Use pcapnav in <DIR>]),
                [CFLAGS="$CFLAGS -I$withval/include"
                LIBS="-L$withval/lib $LIBS"])

    AC_PATH_GENERIC(pcapnav,, [
        AC_SUBST(pcapnav_libs)
        AC_SUBST(pcapnav_cflags)],
        AC_MSG_ERROR(Cannot find pcapnav: Is pcapnav-config in path?))
    pcapnav_libs=`pcapnav-config --libs`
    pcapnav_cflags=`pcapnav-config --cflags`

Time 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, &current_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(&current_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.

Prev | Home | Next
How does it work? |  | `libpcapnav` API Reference