Libpcap tutorial

From wiki.ucalgary.ca
Revision as of 22:54, 31 January 2011 by Locasto (talk | contribs) (The Delta: What this tutorial has that others do not)
Jump to: navigation, search

A libpcap Tutorial

The PCAP library is a C language library (and has variants and translations for other languages and execution environments) that allows both customizable packet capture from the network (or a pre-recorded trace file) and packet injection into the network (or output trace file). It is mainly a library for managing the reading and writing process of packets to and from a data source. It is not particularly well-suited for arbitrary packet formulation.

Other libpcap tutorial exist; for example, see:

and pcap comes with a Unix manual page describing the various functions and flags provided by the library:

Tutorial Task Description

This tutorial will show how to use libpcap to transcribe packets from one data source to another (in a fashion similar to the effect of tcpreplay) while injecting packet content from other sources (such as a program, another trace file, or a network interface). It is assumed that this other source has formulated the packets they wish to appear in the output.

Here is a picture of what we'll build:

VEI Library Architecture

We will build a C library that has two sources of input and one output target. The first input source is a "background" PCAP file trace. The second source of input is an asynchronously-invoked function call `inject_event'. The purpose of the library is to weave these two input sources into a single output file.

The library will have an API containing three functions: initialization, start of transcription, and event injection. In this tutorial, we will build both the library and an example client of the library.

What You'll Need

You will need the following environment set up for this tutorial:

  • A Unix-style platform. This tutorial assumes Linux, specifically Fedora Core 10.
  • A text editor. I use emacs, but you can use vi, nano, pico, or something else.
  • A C compiler. I use gcc.
  • A threads package. I use pthreads.
  • A version of the libpcap library and its development package (e.g.,:
[michael@proton docs]$ yum list installed | grep pcap
jpcap.i386                          0.7-6.fc10                         @updates 
libpcap.i386                        14:0.9.8-3.fc10                    installed
libpcap-devel.i386                  14:0.9.8-3.fc10                    @fedora  
pcapdiff.noarch                     0.1-3.fc9                          @fedora  
pcapy.i386                          0.10.5-3.fc9                       @fedora  
[michael@proton docs]$ 

The Delta: What this tutorial has that others do not

This tutorial exists because I had to find out some things the "hard" way (e.g., reading the documentation). This section isn't meant to be boastful; other tutorials focus on what they focus on because this served the purpose of the author. I had a different set of requirements when I approached the task of using libpcap. Here are those things:

  • how to read and write to dumpfiles
  • the format of the PCAP savefile (particularly the record format of timestamp value plus packet structure)
    • This was important to understand the structure type returned by libpcap and where it got its data. It was also useful to open up a hex editor and map the structure to the header portion of the file and see the bytes in network order in individual fields, including the mapping of MAC and IP addresses.
    • http://www.manpagez.com/man/5/pcap-savefile/
  • the explanations for the data link types (needed for some of the API functions, but buried down in the man page)
    • at a certain point, I needed to use pcap_open_dead() to get a propert pcap_t handle to use with pcap_dump_fopen(), and one argument to pcap_open_dead() is an `int linktype', but the description of link types is buried in the man page. I eventually found that I needed to specify: DLT_EN10MB (which seems obvious in retrospect, but for someone without any knowledge of the pcap API, this didn't jump out until after a thorough reading of the man page.
    • http://www.manpagez.com/man/7/pcap-linktype/
  • how to structure a program to use pcap for multiple purposes at once (i.e., using pthreads to do multiple things at once, not just open an interface and sniff)
  • potential bugs in releasing dump file handles

The Tutorial

The following steps describe a set of tasks, building off how to set up the development environment to writing simple packet replay code to adding in some advanced features.

Step 0: Controlling Compilation and the Build Process

This tutorial uses a directory structure and Makefile to ease the repeated process of compiling.

$ mkdir bin
$ mkdir include
$ mkdir src
$ mkdir lib

Create a file called `Makefile' in the src/ directory. You may choose to use [this one]

We will put the C source files in src/, the VEI library header file in include/, the compiled sample client in bin/, and the compiled library archive file in lib/

Step 1: The Library API

Before diving into libpcap code, we first want to define the services that our packet transcription/replay library will provide.

int initialize_vei_library(FILE* background_trace,
                           FILE* output_trace);
int start_vei_transcription(void);
int inject_event(VEI_EVENT_TYPE event);
void vei_finish(void); 

We'll need to place these in a header file and define a data type for the injected event. Because we use the data type FILE, our header file will need to include the stdio.h file. Our header file also defines a bunch of error codes that could be returned from these functions.

After we take a look at our sample client, we'll come back to the implementation of these functions in the vei.c file; this is where the actual libpcap code gets used.

Step 2: A Sample Client

Our example client will be called "nech0" (for Network Echo) and (for now) simply transcribe one PCAP file to another. It is responsible for a few things, including opening the files involved via the C library, calling the library initialization routine, and calling the library transcription routine. This client also calls the library's shutdown function.

We need to use the large file features of Linux because we may be asked to transcribe very large (i.e., >2GB network trace files).

//this is the preferred way of signaling to the compiler to use large file support
#define _FILE_OFFSET_BITS   64

Next we need to include the appropriate header files that our nech0 client will use:

#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>
#include <features.h>
#include "vei.h"

Our main() function is pretty simple. It prints out some diagnostic information and passes two parameters to the actual "work" function. Our program expects two arguments: the background file to replay and the name of the target output file.

int main(int argc,
         char* argv[])
{
   if(3==argc)
   {
       const char* ver = pcap_lib_version();
       fprintf(stdout,
               "nech0 is using %s\n",
               ver);
       fprintf(stdout,
               "echoing [%s] to [%s]\n",
               argv[1],
               argv[2]);
       do_echo(argv[1], argv[2]);
       fprintf(stdout, "nech0 calling shutdown()...\n");
       shutdown();
   }else{
       fprintf(stderr,
               "nech0 srcfile.cap dstfile.cap\n");
       return -1;
   }
   return 0;
}

Let's provide implementations of the do_echo() and shutdown() functions. `shutdown' is pretty simple:

void
shutdown()
{
   vei_finish();
   return;
}

The do_echo function is a bit lengthier but still pretty straightforward.

static void
do_echo(char* src,
        char* dst)
{
   int init_result = 0;
   int kickoff_result = 0;
   FILE* btrace = NULL; //background trace file handle
   FILE* otrace = NULL; //target output trace file handle
   btrace = fopen(src, "r");
   otrace = fopen(dst, "wb");
   init_result = initialize_vei_library(btrace, otrace);
   kickoff_result = start_vei_transcription();
   return;
}

Note that I have elided any error checking or error handling at this level. It should be there in your code.

Step 3: Packet Record Transcription

Now we get to the meat of the tutorial. How do we tell libpcap to open a trace file and start replaying it to an output sink?


Step 4: Adding in Injection

Contributions

See the wiki history for this page.