  <chapter>
    <title id="ch-concepts">&lnd; Concepts</title>
    <para>
      This chapter introduces the main concepts of &lnd; and uses small
      code examples to illustrate their usage.
    </para>
    <sect1>
      <title>Initialization</title>
      <para>
        Of all the things in this manual, this is the one you should
        not forget :)
        <caution><para>
        Before you can do anything with it, you need to initialize &lnd; by
	calling <link linkend="libnd-init"><function>libnd_init()</function></link>.
        This is necessary in order to initialize the various subsystems
        such as &pcapnav;, preferences, several registries, etc.
        </para></caution>
      </para>
    </sect1>
    <sect1>
      <title>Trace Files</title>
      <para>
        Trace files are &lnd;'s bread and butter. They are represented by
        instances of <type>LND_Trace</type>, which maintain state for a
        trace file the user is manipulating. State information consists of
        consistency management data, filter settings, packet iteration configuration,
        file modification status and more. See <filename>libnd_trace.h</filename>
        for details.
      </para>
      <para>
        Instantiating a trace structure is done using
        <link linkend="libnd-trace-new"><function>libnd_trace_new()</function></link>,
        passing it the path of the trace file to load or <constant>NULL</constant> when
	you want to create a new file. Saving is done using
        <link linkend="libnd-trace-save"><function>libnd_trace_save()</function></link>
        and <link linkend="libnd-trace-save-as"><function>libnd_trace_save_as()</function></link>,
        and releasing a trace is done using
        <link linkend="libnd-trace-free"><function>libnd_trace_free()</function></link>.
      </para>
      <para>
        When you open a trace file, &lnd; does <emphasis>not</emphasis> load
        any packets. If you want to load any packets, from what part of the
        file, and how many packets, is entirely up to you. This is explained
        in detail in the section on trace parts below.
      </para>
      <para>
        To allow applications to integrate &lnd well, you can register 
        <emphasis>trace observers</emphasis>.
        These observers will then receive notifications when certain events occur
	on a trace file. A good example are GUI-based applications &mdash; these
	can register an observer to update the GUI whenever the trace is modified,
	for example. Trace observers are created using
        <link linkend="libnd-trace-observer-new"><function>libnd_trace_observer_new()</function></link>.
        The different possible events are defined in the
        <link linkend="LND-TraceObserverOp"><type>LND-TraceObserverOp</type></link>
        enumeration. The actual observer structures contain function pointers
        to the various event callbacks. These pointers are initialized to safe
        defaults when a new observer is created. You then hook different implementations
        into this structure, and register it with a trace using
        <link linkend="libnd-trace-add-observer"><function>libnd_trace_add_observer()</function></link>.
        Events are pushed to the observers using
        <link linkend="libnd-trace-tell-observers"><function>libnd_trace_tell_observers()</function></link>.
      </para>
      <para>
        To associate arbitrary data items with a trace, every trace comes
        with a simple key/value-based <emphasis>data storage</emphasis>,
        accessible through
        <link linkend="libnd-trace-get-data"><filename>libnd_trace_get_data()</filename></link>,
        <link linkend="libnd-trace-set-data"><filename>libnd_trace_set_data()</filename></link>, and
        <link linkend="libnd-trace-del-data"><filename>libnd_trace_del_data()</filename></link>.
        &lnd; only stores and retrieves the data objects &mdash; you have to do
        any cleaning-up yourself before releasing a trace.
      </para>
    </sect1>
    <sect1>
      <title>Protocols and Protocol Plugins</title>
      <para>
        &lnd; protocols make packet handling easy. Each protocol encodes
        knowledge of the protocol structure found in a packet, such as
        the protocol header, protocol data length etc. The more protocols
        &lnd; can access, the more detailed the interpretation of the raw
        packet data in packets becomes. In &lnd;, protocol knowledge is provided in
        <emphasis>protocol plugins</emphasis>, to allow support for new protocols
        to be added in a modular fashion.
      </para>
      <para>
        By default, &lnd; ships with protocol plugins for ARP, Ethernet,
        FDDI, ICMP, IP, Linux SLL, SNAP headers, TCP, and UDP. Everything
        else is interpreted as raw protocol data. More protocol plugins
        are always welcome! For details, see the chapter on how to
        write a protocol plugin below.
      </para>
      <para>
        Protocol plugins get picked up, initialized and registered automatically
        when &lnd; is bootstrapped. Each protocol is registered in the
        <emphasis>protocol registry</emphasis>, from which you can retrieve
        protocols by providing the layer in the protocol stack that the protocol resides
        in (as defined through the <link linkend="LND-ProtocolLayer"><type>LND_ProtocolLayer</type></link>
        enumeration), and the magic value that the protocol is commonly known
        under. At the link level, these are the <constant>DLT_xxx</constant> values
        as defined in <filename>/usr/include/net/bpf.h</filename>, at the 
        network layer the <constant>ETHERTYPE_xxx</constant> values of 
        <filename>/usr/include/net/ethernet.h</filename>, at the transport layer
        the <constant>IPPROTO_xxx</constant> values of 
        <filename>/usr/include/net/in.h</filename>, 
        and at the application level, these are the well-known port numbers as
        found in <filename>/etc/services</filename>. We'll look at an
        example of how to use this registry once we have introduced &lnd;'s
        packets.
      </para>
    </sect1>
    <sect1>
      <title>Packets</title>
      <para>
        Packets are instances of type <type>LND_Packet</type>.
        When requested, &lnd; initializes packets so that they contain
        detailed information about the nesting of the protocols contained
        in them. This depends on the number of protocols available to
        the library. &lnd;'s packet type also contains the raw packet data
	and packet header as provided by &pcap;.
      </para>
      <para>
        You normally do not need to create and initialize packets manually.
        Typically, you will either iterate over the packets in a trace area
        and obtain the initialized current packet from a
        <link linkend="packet-iterators">packet iterator</link>, or you will
        ask &lnd; to load a number of packets into memory for you and then
        directly operate in that sequence of loaded and initialized packets.
	If you're interested in how packet initialization works, or if you
	want to add support for a new protocol, you should have a look at the
	chapter that explains how to <link linkend="ch-protocol">write a protocol
	plugin</link>.
      </para>
      <para>
        Initialized packets make it easy to access protocol information of
        a given protocol at a given nesting level. You can easily obtain the
        first nested IP header from a packet, for example. Forget writing your
        own protocol-demuxer. 
      </para>
      <para>
        Now that protocols and packets are introduced, let's look at some
        code. Let's assume that we want to obtain the TCP header of a
        packet. We first retrieve the TCP protocol from the protocol registry.
        <programlisting>
<![CDATA[
#include <libnd.h>
#include <netinet/in.h>
#include <netinet/tcp.h>


LND_Trace    *trace;
LND_Packet   *packet;
LND_Protocol *tcp;

struct tcphdr *tcphdr;

libnd_init();

/* Open a tracefile, load a few packets ... */
if (! (trace = libnd_trace_new("foo.trace")))
  {
     /* Didn't work -- appropriate error handling. */
  }

libnd_tpm_load_packets(trace->tpm);

/* Obtain the packet somehow: */
packet = libnd_trace_get_packets(trace);

if (! (tcp = libnd_proto_registry_find(LND_PROTO_LAYER_TRANS, IPPROTO_TCP)))
  {
     /* Protocol not found -- handle accordingly. */
  }
]]>
        </programlisting>
        Then, we try to obtain the TCP header from a packet by using the
        TCP protocol just obtained. If %NULL is returned, we know that the
        packet does not contain TCP data.
        <programlisting>
<![CDATA[

if (! (tcphdr = (struct tcphdr *) libnd_packet_get_data(packet, tcp, 0)))
  {
     /* This packet does not contain TCP headers */
  }
]]>
        </programlisting>
      </para>
      <para>
        Similarly to traces, applications can register <emphasis>observers</emphasis>
        to be informed when certain operations are performed on a packet.
	These operations are enumerated in the
	<link linkend="LND-PacketObserverOp"><type>LND_PacketObserverOp</type></link>
	enum.
      </para>
      <para>
        Since packets may be allocated and released quickly depending on
        the application, the memory management fir &lnd;'s packets is
        wrapped by a <emphasis>packet recycler</emphasis> that keeps packets
        that are no longer used in sets of packets needing up to a certain
        number of bytes for their raw data. Packet allocation is then performed
        by first checking if an unused packet with enough storage capacity
        is around anyway. Packet deallocation is performed by putting
        the packet into the pool of unused packets of similar storage
        capacity. This is all hidden in &lnd;, so you do not need to
        take care of this yourself.
      </para>
      <para>
        <emphasis>TODO:</emphasis> explain how to iterate over all protocol headers
	in a trace via packet->pd, and show how to print out TCP payloads as an
	example.
      </para>
    </sect1>
    <sect1>
      <title>Trace Areas, Trace Parts and Trace Part Managers</title>
      <para>
        As mentioned above, when opening a trace file &lnd; does not
	load the packets contained in the file into memory, because this
	approach is clearly bound to fail for larger traces -- and &tcpdump;
	traces often are hundreds of megabytes in size.
        It can load up to a configurable number of packets from a specified
	point in the file upon request, but typically you will just iterate
        over packets in a certain <emphasis>trace area</emphasis>, loading
        them one at a time to perform some operation on them. In code,
        trace areas are instances of
        <link linkend="LND-TraceArea"><type>LND_TraceArea</type></link>.
        Every trace has an active trace area. At creation time of the
        trace, this trace area is initialized to the entire trace.
        Trace areas are specified in one of two ways; either
        in terms of start- and end timestamps (e.g., from 08:00:00 to
        08:10:30 on August 4) or start- and end fractions (e.g., from 0.5
        to 1.0, that is, from the middle of the file to its end). You can
        set and obtain this area using
        <link linkend="libnd-trace-set-area"><function>libnd_trace_set_area()</function></link>
        and <link linkend="libnd-trace-get-area"><function>libnd_trace_get_area()</function></link>.
      </para>
      <para>
        Iterating over the packets in a trace area and modifying them
        creates a <emphasis>trace part</emphasis> (in code: instances
        of type <type>LND_TracePart</type>) &mdash a temporary
        overlay over the original trace with its extents defined by
        the trace area. When a multiple different trace areas are used,
        trace parts begin to pile up on the original input trace file,
        called the <emphasis>base file</emphasis>. Figure
	<link linkend="traceparts-fig1">1</link>
        illustrates the concepts of the base file, trace areas and trace
        parts.
      </para>
      <figure id="traceparts-fig1">
      <title>Trace Areas vs. Trace Parts</title>
        <mediaobject>
	  <imageobject>
	    <imagedata fileref="images/traceparts1.png" format="png" align="center">
	  </imageobject>
          <imageobject>
	    <imagedata fileref="images/traceparts1.eps" format="eps" align="center">
          </imageobject>
          <textobject>
	    <phrase>Trace Parts Example</phrase>
          </textobject>
	  <caption>
            <para>
	    A trace with three trace areas defined. The user first modified the packets
	    in area 1, followed by those in trace area 2 and area 3, and finally again
	    the packets in area 1. Each modification caused the creation of new
	    trace parts that got stacked up onto the base trace.
            </para>
	  </caption>
	</mediaobject>
      </figure>
      <para>        
        Making sure that the trace parts are properly maintained, overlayed
        and disposed of is the job of the <emphasis>trace part manager</emphasis>,
        abbreviated "TPM". Each trace has one. In code, a TPM is
        an instance of type <type>LND_TPM</type>. TPMs
        organize the trace parts in such a way that the user always sees
        a consistent view of the modified trace, take care of properly
	sequencing the packets when a trace file that has developed multiple
	trace parts is saved back to disk (illustrated in Figure 
	<link linkend="traceparts-fig2">2</link>), and handle automatically
	saving trace part contents out to temporary files when necessary.
      </para>
      <para>
        Intuitively, there are multiple ways to specify a location in a trace:
        <emphasis>global offsets</emphasis> simply give an offset in terms of
        a number of bytes from the start of the file. <emphasis>Timestamps</emphasis>
        specify the packet in the trace that is closest to a given timestamp.
        <emphasis>Fractional offsets</emphasis> are offsets relative to the entire
        size of the trace (for example, 0.5 is the middle of the trace). Keeping
	Figure <link linkend="traceparts-fig1">1</link> in mind, a location can
        also be defined as a <emphasis>trace part + local offset</emphasis>.
        The TPM provides a set of functions to convert from one representation
        to another. Examples of this API include
        <link linkend="libnd-tpm-map-loc-to-offset"<function>libnd_tpm_map_loc_to_offset()</function></link>,
        <link linkend="libnd-tpm-map-offset-to-loc"<function>libnd_tpm_map_offset_to_loc()</function></link>,
        <link linkend="libnd-tpm-map-fraction-to-loc"<function>libnd_tpm_map_fraction_to_loc()</function></link>, and
        <link linkend="libnd-tpm-map-timestamp-to-loc"<function>libnd_tpm_map_timestamp_to_loc()</function></link>.
      </para>
      <para>
        Trace parts can grow and shrink &mdash; after all, without this feature it
	would be fine to simply <function>mmap()</function> parts of the trace file.
	When a trace area is iterated and packets are written to temporary storage,
	the user is free to not write out all packets or introduce new ones. The TPMs
	keeps track of where the trace areas begin and end, and by what amount trace
	parts grow or shrink, relative to their original size.
      </para>
      <figure id="traceparts-fig2">
      <title>Synchronizing Traces</title>
        <mediaobject>
	  <imageobject>
	    <imagedata fileref="images/traceparts2.png" format="png" align="center">
	  </imageobject>
          <imageobject>
	    <imagedata fileref="images/traceparts2.eps" format="eps" align="center">
          </imageobject>
          <textobject>
	    <phrase>Synchronizing Traces</phrase>
          </textobject>
	  <caption>
            <para>
	    Upon saving a trace file, the trace parts sitting on top of the base file
	    get merged back into one file by "flattening" the parts: the higher trace
	    parts replace packets at corresponding positions in the lower parts, including
	    the base file.
            </para>
	  </caption>
	</mediaobject>
      </figure>
    </sect1>
    <sect1>
      <title id="packet-iterators">Packet Iterators</title>
      <para>
        Iterating over packets in &pcap; is done using either a callback mechanism
	that allows only little control over the iteration, or using <function>pcap_next()</function>
	to get a single packet. &lnd; provides a higher abstraction for iterating
	packets. The packet iterator API allows you to use common <type>for (...) { }</type>
	loops and provides one function for each of the three for-loop steps (initialization,
	exit checking and counter adjustment). Packet iterators are instances of type
	<type>LND_PacketIterator</type> and are statically initialized. Avoiding
	allocating and releasing an iterator structure every time an iteration is
	performed is easier for the programmer, given that there is no automatic
	garbage collection in C.
      </para>
      <para>
        There are multiple ways you can iterate over packets in a trace. The iteration
	mode is specified using one of the <link linkend="LND-PacketIteratorMode"><type>LND_PacketIteratorMode</type></link>
	constants when the iterator is initialized:
      <itemizedlist>	 
	<listitem>
	  <para>
	  <constant>LND_PACKET_IT_SEL_R</constant> assumes that you have loaded a number
	  of packets into memory, starting at the current location in the trace
	  (this is done using the
	  <link linkend="libnd-tpm-load-packets"><function>libnd_tpm_load_packets()</function></link>
	  call). Within the loaded packets, you can select individual packets using
	  <link linkend="libnd-tp-select-packet"><function>libnd_tp_select_packet()</function></link>.
	  This iterator mode will only iterate over those packets that are currently
	  in memory and have been selected, and assumes that no modifications to these
	  packets are made.
	  </para>
	</listitem>
	<listitem>
	  <para>
	  <constant>LND_PACKET_IT_SEL_RW</constant> is similar to <constant>LND_PACKET_IT_SEL_R</constant>
	  but allows modifications to the iterated packets.
	  </para>
	</listitem>
	<listitem>
	  <para>
	  <constant>LND_PACKET_IT_PART_R</constant> is used to request iteration of all packets
	  currently loaded into memory and assumes that no modifications are made.
	  </para>
	</listitem>
	<listitem>
	  <para>
	  <constant>LND_PACKET_IT_PART_RW</constant> is similar to <constant>LND_PACKET_IT_PART_R</constant>,
	  but allows modifications to the iterated packets.
	  </para>
	</listitem>
	<listitem>
	  <para>
	  <constant>LND_PACKET_IT_AREA_R</constant> is used to request iteration over packets
	  in a trace area, without any modifications to the packets.
	  </para>
	</listitem>
	<listitem>
	  <para>
	  <constant>LND_PACKET_IT_AREA_RW</constant> is similar to <constant>LND_PACKET_IT_AREA_R</constant>,
	  but allows modifications to the iterated packets. The difference between the read-only
	  and the read-write mode is bigger here compared to the other options, because
	  iteration of a trace area in read-write mode will lead to the creation of a new
	  trace area, whereas the other mode will not.
	  </para>
	</listitem>
      </itemizedlist>
      Let's look at an example of packet iterator usage. Let's assume you want to fix the
      checksums of all packets in the second half of your trace. Open a trace, and set
      the trace's active area to the second half of the trace:

        <programlisting>
<![CDATA[
#include <libnd.h>

LND_Trace          *trace;
LND_PacketIterator  pit;   /* NOT a pointer */
LND_TraceArea       area;

libnd_init();

/* Open a tracefile: */
if (! (trace = libnd_trace_new("foo.trace")))
  {
     /* Didn't work -- appropriate error handling. */
  }

/* Now set the trace area to the second half of the trace.
 * The default iteration mode of a trace is LND_PACKET_IT_AREA_R,
 * so we can either set it for the trace or just for the iterator.
 * Here we do the latter.
 */
libnd_trace_area_init_space(&area, 0.5, 1.0);
libnd_trace_set_area(trace, &area);
]]>
        </programlisting>

	Now, we need to iterate over the trace area we just configured. We initialize
	the packet iterator in the initialization component of the for-statement
	using <link linkend="libnd-pit-init"><function>libnd_pit_init()</function></link>
	if we want to use the iteration mode the trace currently uses, or we can
	pass a different one using <link linkend="libnd-pit-init-mode"><function>libnd_pit_init_mode()</function></link>.
	The currently iterated packet of the iterator can always be obtained
	using <link linkend="libnd-pit-get"><function>libnd_pit_get()</function></link>,
	and iterators are advanced using  <link linkend="libnd-pit-next"><function>libnd_pit_next()</function></link>.
	When <link linkend="libnd-pit-get"><function>libnd_pit_get()</function></link>
	returns <constant>NULL</constant>, we have reached the end of the iteration
	and the for-loop will be left automatically.

        <programlisting>
<![CDATA[
for (libnd_pit_init_mode(&pit, trace, LND_PACKT_IT_AREA_RW); libnd_pit_get(&pit); libnd_pit_next(&pit))
  {
     /* Now just rely on the library and the protocol plugins to fix the packet
      * for us if it's currently broken:
      */
     libnd_packet_fix(libnd_pit_get(&pit));
  }
]]>
        </programlisting>
	
	In case you are wondering,
	<link linkend="libnd-packet-fix"><function>libnd_packet_fix()</function></link>
	walks the initialized protocol segments of the given packet in reverse order
	(for example, payload first, then TCP, then IP) and calls a protocol-dependant
	function that corrects the checksum. It is up to each protocol plugin if
	and how checksum correction is implemented.
	
	<warning>
          <para>
	    Note that if you have other conditions in your loop that may lead to
	    breaking out of the loop, you <emphasis>MUST</emphasis> call
	    <link linkend="libnd-pit-cleanup"><function>libnd_pit_cleanup()</function></link>
	    when doing so. The packet iterators normally do this for you when
	    they hit the end of the iteration, but when you stop the iteration
	    before that, you have to take care of that.
	  </para>
	</warning>
      </para>
    </sect1>
    <sect1>
      <title>Packet Filters</title>
      <para>
        Packet iteration is nice but only helpful when you can skip the packets
	you don't care about. &lnd; provides a filtering framework that allows
	stateful packet filtering where the actual filtering condition is entirely
	up to you.
      </para>
      <para>
        Packet filters in &lnd; are instances of type <type>LND_Filter</type>.
	Their implementation depends on function pointers you provide for
	<link linkend="LND-FilterInitFunc">initialization</link>,
	<link linkend="LND-FilterFunc">filtering</link>, and
	<link linkend="LND-FilterCleanupFunc">cleanup</link>.
	Every filter has a name, and possible state-keeping data that are used
	during the filtering process. A new filter is created using
	<link linkend="libnd-filter-new"><function>libnd_filter_new()</function></link>.
	<note>
	  <para>
	    Keep in mind that if you do not require some of the callbacks (like
	    when your filtering is not stateful), you do not need to define and pass
	    all of the callbacks.
	  </para>
	</note>
	A filter is applied to a packet using
	<link linkend="libnd-filter-apply"><function>libnd_filter_apply()</function></link>,
	which results in the packet's filtered flag being set or unset (and an according
	event being passed to any listening observers).
        <caution>
          <para>
	  A packet <emphasis>passes</emphasis> a filter when your filtering
	  function returns <emphasis><constant>TRUE</constant></emphasis> for
	  it.
          </para>	
        </caution>
        As an example, let's sketch out the code for a filter that will filter
	out all packets that are more than 100 bytes in size. First let's open
	a trace as usual. We will also need a packet iterator, but the default
	settings (iteration mode of <constant>LND_PACKET_IT_AREA_R</constant>
	and an area defining the entire trace) are fine this time.
        <programlisting>
<![CDATA[
#include <libnd.h>

LND_Trace          *trace;
LND_PacketIterator  pit;   /* NOT a pointer */
LND_TraceArea       area;

libnd_init();

/* Open a tracefile: */
if (! (trace = libnd_trace_new("foo.trace")))
  {
     /* Didn't work -- appropriate error handling. */
  }
]]>
        </programlisting>
	Now we need to define our filter implementation. This filter is stateless, since
	it only checks the &pcap; packet length field against our limit. Therefore,
	all we need to define is a function that follows the 
	<link linkend="LND-FilterFunc"><function>LND_FilterFunc()</function></link>
	signature.
        <programlisting>
<![CDATA[
#define PACKET_SIZE_LIMIT         100

gboolean
filter_length(LND_Filter *filter, LND_Packet *packet, void *filter_data)
{
  return (packet->ph.len <= PACKET_SIZE_LIMIT) ? TRUE : FALSE;
}
]]>
        </programlisting>
	Now we need to create a filter that uses this filtering method, activate
	the filter for our trace, and iterate over the trace.
        <programlisting>
<![CDATA[
LND_Filter         *filter;

if (! (filter = libnd_filter_new("size filter",
                                 NULL, /* no initialization needed */
				 filter_length,
				 NULL, /* no cleanup needed */
				 NULL, /* no state, so no state cleanup needed */
				 NULL))) /* no statekeeping needed */
  {
     /* Didn't work -- appropriate error handling. */
  }

libnd_trace_add_filter(trace, filter);

for (libnd_pit_init(&pit, trace); libnd_pit_get(&pit); libnd_pit_next(&pit))
  printf("Packet with header length %i passed the filter\n", libnd_pit_get(&pit)->ph.len);
]]>
        </programlisting>
	The iterator takes care of checking the filtering condition for
	us, and only passes us the packets we are actually interested in &mdash;
	namely those of no more than 100 bytes in size.
      </para>
      <para>
        There are two other concepts for filtering: the <emphasis>filter
        registry</emphasis>
        stores created filters and can retrieve them by name. <emphasis>Filter
        factories</emphasis> add one level of indirection and provide a unique
        starting point for filter generation. They are still experimental and
        likely to change in the future.
      </para>
    </sect1>
    <sect1>
      <title>Preferences Management</title>
      <para>
        &lnd; does preferences management for you. Preferences are partitioned
        by a namespace system, where each set of common preference options
        is put in the same <emphasis>preferences domain</emphasis>.
        domain, you can define a set of <emphasis>apply callbacks</emphasis>
        that get called when preference modifications are applied (using
        <link linkend="libnd-prefs-apply"><function>libnd_prefs_apply()</function></link>).
        You can save the current preference settings to disk at any time
        using
        <link linkend="libnd-prefs-save"><function>libnd_prefs_save()</function></link>.
      </para>
      <para>
        You create a new preferences domain using
        <link linkend="libnd-prefs-add-domain"><function>libnd_prefs_add_domain()</function></link>).
        Besides a name for the new domain, this function is passed an array
        of preference settings. This array can be defined statically, using an array
        of instances
        of type <type>LND_PrefsEntry</type>. Here is how &lnd; defines its own
        preferences: 
        <programlisting>
<![CDATA[
static LND_PrefsEntry prefs_entries_netdude[] = {
  { "tcpdump_path",              LND_PREFS_STR, LND_UNUSED, LND_UNUSED, TCPDUMP },
  { "tcpdump_resolve",           LND_PREFS_INT, FALSE,      LND_UNUSED, LND_UNUSED  },
  { "tcpdump_print_domains",     LND_PREFS_INT, FALSE,      LND_UNUSED, LND_UNUSED  },
  { "tcpdump_quick",             LND_PREFS_INT, FALSE,      LND_UNUSED, LND_UNUSED  },
  { "tcpdump_print_link",        LND_PREFS_INT, FALSE,      LND_UNUSED, LND_UNUSED  },
  { "tcpdump_print_timestamp",   LND_PREFS_INT, FALSE,      LND_UNUSED, LND_UNUSED  },
  { "workdir",                   LND_PREFS_STR, LND_UNUSED, LND_UNUSED, "/tmp" },
  { "num_mem_packets",           LND_PREFS_INT, 500,        LND_UNUSED, LND_UNUSED },
};
]]>
        </programlisting>
     </para>
      <para>
        Preferences are then queried and set using
        <link linkend="libnd-prefs-get-str-item"><function>libnd_prefs_get_str_item()</function></link>)
        and
        <link linkend="libnd-prefs-set-str-item"><function>libnd_prefs_set_str_item()</function></link>)
        (and corresponding calls for integer and floating point settings).
        To obtain the directory in which &lnd; stores its temporary data,
        you would use the following code:
        <programlisting>
<![CDATA[
char *workdir;

if (! libnd_prefs_get_str_item(LND_DOM_NETDUDE, "workdir", &workdir))
  {
    /* Error -- preference setting undefined. */
  }

printf("libnetdude's temporary storage area is %s\n", workdir);
]]>
        </programlisting>
      </para>
      <note>
       <para>
       The relationship between setting preferences, applying preferences, and
       saving preferences is as follows: preferences are modified in memory
       when you use one of the <function>libnd_prefs_set_xxx()</function>
       functions. Those modifications are lost when the application exits,
       unless you call
       <link linkend="libnd-prefs-save"><function>libnd_prefs_save()</function></link>
       to save them to disk. Calling 
       <link linkend="libnd-prefs-apply"><function>libnd_prefs_apply()</function></link>
       only causes the registered application callbacks to be called, so that 
       other parts of the application can synchronize their operation
       to the new settings.
       </para>
      </note>       
    </sect1>
    <sect1>
      <title>&tcpdump; Communication</title>
      <para>
        &lnd; associates a &tcpdump; process with every trace. The programmer
        can send individual packets to this &tcpdump; instance and obtain
        the familiar &tcpdump; output for that packet (limited however to
        a single line -- this is one of the many occasions where the fact that
	some of &tcpdump;'s protocol parsers output more than a single line per packet
	makes things a royal pain in the arsenal).
      </para>
      <para>
        The function you want to look at for doing this is
        <link linkend="libnd-tcpdump-get-packet-line"><function>libnd_tcpdump_get_packet_line()</function></link>.
        You can also specify the command line options passed to the &tcpdump;
        process when it is forked, using
        <link linkend="libnd-tcpdump-options-add"><function>libnd_tcpdump_options_add()</function></link>.
        and
        <link linkend="libnd-tcpdump-options-reset"><function>libnd_tcpdump_options_reset()</function></link>.
        The default options that are always passed are <command>-l -r</command>.
        Depending on you preferences settings in the <constant>LND_DOM_NETDUDE</constant>
        domain, other flags are sent as well:
        <command>-nnn</command> depending on <constant>tcpdump_resolve</constant>,
        <command>-N</command> depending on <constant>tcpdump_domains</constant>,
        <command>-q</command> depending on <constant>tcpdump_quick</constant>, and
        <command>-e</command> depending one<constant>tcpdump_print_link</constant>.        
      </para>
      <para>
        For an example of the &tcpdump; interface being used, please have a look
        at the source code of the Netdude application that uses this feature
        to display a list of &tcpdump; output strings for the set of packets
        that are loaded into memory.
      </para>
    </sect1>
    <sect1>
      <title>Feature Plugins</title>
      <para>
        Feature plugins are &lnd;'s mechanism to provide reusable
        packet manipulation modules that can contain arbitrary code,
        use other libraries, interface to other applications etc.
        Examples are advanced filter implementations (like "drop all
        incomplete TCP flows"), address mappers, or statistical analyzers.
        For details on writing a feature plugin, see the separate chapter on
        <link linkend="ch-feature">Feature Plugins</link>.
       </para>
    </sect1>
  </chapter>
