1694 lines
62 KiB
HTML
1694 lines
62 KiB
HTML
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Npcap Development Tutorial</title><meta name="generator" content="DocBook XSL Stylesheets V1.79.2"><meta name="description" content="A step-by-step guide to writing software that uses Npcap to list network adapters, capture packets, and send network traffic."><link rel="home" href="index.html" title="Npcap: Nmap Project's packet sniffing library for Windows"><link rel="up" href="index.html" title="Npcap: Nmap Project's packet sniffing library for Windows"><link rel="prev" href="npcap-devguide.html" title="Developing software with Npcap"><link rel="next" href="npcap-internals.html" title="Npcap internals"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Npcap Development Tutorial</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="npcap-devguide.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="npcap-internals.html">Next</a></td></tr></table><hr></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="npcap-tutorial"></a>Npcap Development Tutorial</h2></div><div><div class="abstract"><p class="title"><b>Abstract</b></p>
|
||
<p>A step-by-step guide to writing software that uses Npcap to list
|
||
network adapters, capture packets, and send network traffic.</p>
|
||
</div></div></div></div>
|
||
|
||
|
||
|
||
<p>This section shows how to use the features of the Npcap API. It is
|
||
organized as a tutorial, subdivided into a set of lessons that will
|
||
introduce the reader, in a step-by-step fashion, to program development
|
||
using Npcap, from the basic functions (obtaining the adapter list,
|
||
starting a capture, etc.) to the most advanced ones (handling send queues
|
||
and gathering statistics about network traffic).</p>
|
||
|
||
|
||
|
||
<p>The samples are written in plain C, so a basic knowledge of C
|
||
programming is required. Also, since this is a tutorial about a library
|
||
dealing with "raw" networking packets, good knowledge of networks and
|
||
network protocols is assumed.</p>
|
||
|
||
<p>The code in this section is copied from the <a class="xref" href="npcap-devguide.html#npcap-examples" title="Examples">the section called “Examples”</a> in the source
|
||
distribution and the SDK. The code is released under a BSD-3-clause license and
|
||
copyright: NetGroup, Politecnico di Torino (Italy); CACE Technologies,
|
||
Davis (California); and Insecure.com, LLC. Full text of the code license
|
||
can be found in each source file.</p>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-devlist"></a>Obtaining the device list</h3></div></div></div>
|
||
|
||
<p>Typically, the first thing that a Npcap-based application does is
|
||
get a list of attached network adapters. Both libpcap and Npcap provide
|
||
the <a class="ulink" href="wpcap/pcap_findalldevs.html" target="_top">pcap_findalldevs_ex()</a> function for this purpose:
|
||
this function returns a linked list of <code class="literal">pcap_if</code> structures, each of which contains
|
||
comprehensive information about an attached adapter. In particular, the
|
||
fields <code class="literal">name</code> and <code class="literal">description</code> contain the name and a
|
||
human readable description, respectively, of the corresponding
|
||
device.</p>
|
||
|
||
<p>The following code retrieves the adapter list and shows it on the
|
||
screen, printing an error if no adapters are found.</p>
|
||
|
||
<pre class="programlisting">
|
||
#include "pcap.h"
|
||
|
||
main()
|
||
{
|
||
pcap_if_t *alldevs;
|
||
pcap_if_t *d;
|
||
int i=0;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
|
||
/* Retrieve the device list from the local machine */
|
||
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1)
|
||
{
|
||
fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf);
|
||
exit(1);
|
||
}
|
||
|
||
/* Print the list */
|
||
for(d= alldevs; d != NULL; d= d->next)
|
||
{
|
||
printf("%d. %s", ++i, d->name);
|
||
if (d->description)
|
||
printf(" (%s)\n", d->description);
|
||
else
|
||
printf(" (No description available)\n");
|
||
}
|
||
|
||
if (i == 0)
|
||
{
|
||
printf("\nNo interfaces found! Make sure Npcap is installed.\n");
|
||
return;
|
||
}
|
||
|
||
/* We don't need any more the device list. Free it */
|
||
pcap_freealldevs(alldevs);
|
||
}
|
||
</pre>
|
||
|
||
<p>Some comments about this code.</p>
|
||
|
||
<p>First of all, <a class="ulink" href="./wpcap/pcap_findalldevs.html" target="_top">pcap_findalldevs_ex()</a>, like
|
||
other libpcap functions, has an <code class="literal">errbuf</code> parameter. This
|
||
parameter points to a string filled by libpcap with a description of the
|
||
error if something goes wrong.</p>
|
||
|
||
<p>Second, remember that not all the OSes supported by libpcap provide a
|
||
description of the network interfaces, therefore if we want to write a
|
||
portable application, we must consider the case in which
|
||
<code class="literal">description</code> is null: we print the string "No
|
||
description available" in that situation.</p>
|
||
|
||
<p>Note finally that we free the list with <a class="ulink" href="wpcap/pcap_findalldevs.html" target="_top">pcap_freealldevs()</a> once when
|
||
we have finished with it.</p>
|
||
|
||
<p>Assuming we have compiled the program, let's try to run it. On a
|
||
particular Windows workstation, the result we optained is</p>
|
||
|
||
<pre class="screen">
|
||
1. \Device\NPF_{4E273621-5161-46C8-895A-48D0E52A0B83} (Realtek RTL8029(AS) Ethernet Adapter)
|
||
2. \Device\NPF_{5D24AE04-C486-4A96-83FB-8B5EC6C7F430} (3Com EtherLink PCI)
|
||
</pre>
|
||
|
||
<p>As you can see, the name of the network adapters (that will be passed
|
||
to libpcap when opening the devices) under Windows are quite unreadable,
|
||
so the parenthetical descriptions can be very helpful.</p>
|
||
</div>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-devdetails"></a>Obtaining advanced information about installed devices</h3></div></div></div>
|
||
|
||
|
||
<p>Lesson 1 (<a class="xref" href="npcap-tutorial.html#npcap-tutorial-devlist" title="Obtaining the device list">the section called “Obtaining the device list”</a>) demonstrated how
|
||
to get basic information (i.e. device name and description) about
|
||
available adapters. Actually, Npcap provides also other advanced
|
||
information. In particular, every <code class="literal">pcap_if</code> structure
|
||
returned by <a class="ulink" href="wpcap/pcap_findalldevs.html" target="_top">pcap_findalldevs_ex()</a>
|
||
contains also a list of <code class="literal">pcap_addr</code> structures,
|
||
with:</p>
|
||
|
||
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">a list of addresses for that interface.</li><li class="listitem">a list of netmasks (each of which corresponds to an entry in
|
||
the addresses list).</li><li class="listitem">a list of broadcast addresses (each of which corresponds to an
|
||
entry in the addresses list).</li><li class="listitem">a list of destination addresses (each of which corresponds to
|
||
an entry in the addresses list).</li></ul></div>
|
||
|
||
<p>Additionally, <code class="literal">pcap_findalldevs_ex()</code> can also
|
||
return remote adapters and a list of pcap files that are located in a
|
||
given local folder.</p>
|
||
|
||
<p>The following sample provides an ifprint() function that prints the
|
||
complete contents of a <code class="literal">pcap_if</code> structure. It is
|
||
invoked by the program for every entry returned by
|
||
<code class="literal">pcap_findalldevs_ex()</code>.</p>
|
||
|
||
<pre class="programlisting">
|
||
/* Print all the available information on the given interface */
|
||
void ifprint(pcap_if_t *d)
|
||
{
|
||
pcap_addr_t *a;
|
||
char ip6str[128];
|
||
|
||
/* Name */
|
||
printf("%s\n",d->name);
|
||
|
||
/* Description */
|
||
if (d->description)
|
||
printf("\tDescription: %s\n",d->description);
|
||
|
||
/* Loopback Address*/
|
||
printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");
|
||
|
||
/* IP addresses */
|
||
for(a=d->addresses;a;a=a->next) {
|
||
printf("\tAddress Family: #%d\n",a->addr->sa_family);
|
||
|
||
switch(a->addr->sa_family)
|
||
{
|
||
case AF_INET:
|
||
printf("\tAddress Family Name: AF_INET\n");
|
||
if (a->addr)
|
||
printf("\tAddress: %s\n",iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
|
||
if (a->netmask)
|
||
printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
|
||
if (a->broadaddr)
|
||
printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
|
||
if (a->dstaddr)
|
||
printf("\tDestination Address: %s\n",iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));
|
||
break;
|
||
|
||
case AF_INET6:
|
||
printf("\tAddress Family Name: AF_INET6\n");
|
||
if (a->addr)
|
||
printf("\tAddress: %s\n", ip6tos(a->addr, ip6str, sizeof(ip6str)));
|
||
break;
|
||
|
||
default:
|
||
printf("\tAddress Family Name: Unknown\n");
|
||
break;
|
||
}
|
||
}
|
||
printf("\n");
|
||
}
|
||
</pre>
|
||
|
||
</div>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-openadapter"></a>Opening an adapter and capturing the packets</h3></div></div></div>
|
||
|
||
|
||
<p>Now that we've seen how to obtain an adapter to play with, let's
|
||
start the real job, opening an adapter and capturing some traffic. In
|
||
this lesson we'll write a program that prints some information about each
|
||
packet flowing through the adapter.</p>
|
||
|
||
<p>The function that opens a capture device is <a class="ulink" href="wpcap/pcap_open.html" target="_top">pcap_open()</a>. The parameters,
|
||
<code class="literal">snaplen</code>, <code class="literal">flags</code> and
|
||
<code class="literal">to_ms</code> deserve some explanation.</p>
|
||
|
||
<p><code class="literal">snaplen</code> specifies the portion of the packet to capture. On
|
||
some OSes (like xBSD and Win32), the packet driver can be configured to
|
||
capture only the initial part of any packet: this decreases the amount of
|
||
data to copy to the application and therefore improves the efficiency of
|
||
the capture. In this case we use the value 65536 which is higher than the
|
||
greatest MTU that we could encounter. In this manner we ensure that the
|
||
application will always receive the whole packet.</p>
|
||
|
||
<p><code class="literal">flags:</code> the most important flag is the one that
|
||
indicates if the adapter will be put in promiscuous mode. In normal
|
||
operation, an adapter only captures packets from the network that are
|
||
destined to it; the packets exchanged by other hosts are therefore
|
||
ignored. Instead, when the adapter is in promiscuous mode it captures all
|
||
packets whether they are destined to it or not. This means that on shared
|
||
media (like non-switched Ethernet), Npcap will be able to capture the
|
||
packets of other hosts. Promiscuous mode is the default for most capture
|
||
applications, so we enable it in the following example.</p>
|
||
|
||
<p><code class="literal">to_ms</code> specifies the read timeout, in milliseconds.
|
||
A read on the adapter (for example, with <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_dispatch()</a> or <a class="ulink" href="wpcap/pcap_next_ex.html" target="_top">pcap_next_ex()</a>) will always
|
||
return after <code class="literal">to_ms</code> milliseconds, even if no packets
|
||
are available from the network. <code class="literal">to_ms</code> also defines the
|
||
interval between statistical reports if the adapter is in statistical
|
||
mode (see the lesson "\ref wpcap_tut9" for information about statistical
|
||
mode). Setting <code class="literal">to_ms</code> to 0 means no timeout, a read on
|
||
the adapter never returns if no packets arrive. A -1 timeout on the other
|
||
side causes a read on the adapter to always return immediately.</p>
|
||
|
||
<pre class="programlisting">
|
||
#include <pcap.h>
|
||
#include "misc.h" /* LoadNpcapDlls */
|
||
|
||
/* prototype of the packet handler */
|
||
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
|
||
|
||
int main()
|
||
{
|
||
pcap_if_t *alldevs;
|
||
pcap_if_t *d;
|
||
int inum;
|
||
int i=0;
|
||
pcap_t *adhandle;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
|
||
/* Load Npcap and its functions. */
|
||
if (!LoadNpcapDlls())
|
||
{
|
||
fprintf(stderr, "Couldn't load Npcap\n");
|
||
exit(1);
|
||
}
|
||
|
||
/* Retrieve the device list on the local machine */
|
||
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
|
||
{
|
||
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
|
||
exit(1);
|
||
}
|
||
|
||
/* Print the list */
|
||
for(d=alldevs; d; d=d->next)
|
||
{
|
||
printf("%d. %s", ++i, d->name);
|
||
if (d->description)
|
||
printf(" (%s)\n", d->description);
|
||
else
|
||
printf(" (No description available)\n");
|
||
}
|
||
|
||
if(i==0)
|
||
{
|
||
printf("\nNo interfaces found! Make sure Npcap 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");
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
/* Jump to the selected adapter */
|
||
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
|
||
|
||
/* Open the device */
|
||
if ( (adhandle= pcap_open(d->name, // name of the device
|
||
65536, // portion of the packet to capture
|
||
// 65536 guarantees that the whole packet will be captured on all the link layers
|
||
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
|
||
1000, // read timeout
|
||
NULL, // authentication on the remote machine
|
||
errbuf // error buffer
|
||
) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by Npcap\n", d->name);
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
printf("\nlistening on %s...\n", d->description);
|
||
|
||
/* At this point, we don't need any more the device list. Free it */
|
||
pcap_freealldevs(alldevs);
|
||
|
||
/* start the capture */
|
||
pcap_loop(adhandle, 0, packet_handler, NULL);
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
/* Callback function invoked by libpcap for every incoming packet */
|
||
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
|
||
{
|
||
struct tm ltime;
|
||
char timestr[16];
|
||
time_t local_tv_sec;
|
||
|
||
/*
|
||
* unused variables
|
||
*/
|
||
(VOID)(param);
|
||
(VOID)(pkt_data);
|
||
|
||
/* convert the timestamp to readable format */
|
||
local_tv_sec = header->ts.tv_sec;
|
||
localtime_s(&ltime, &local_tv_sec);
|
||
strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);
|
||
|
||
printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
|
||
}
|
||
</pre>
|
||
|
||
<p>Once the adapter is opened, the capture can be started with <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_dispatch()</a> or <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_loop()</a>. These two functions are
|
||
very similar, the difference is that <code class="literal">pcap_dispatch()</code>
|
||
returns (although not guaranteed) when the timeout expires while
|
||
<code class="literal">pcap_loop()</code> doesn't return until
|
||
<code class="literal">cnt</code> packets have been captured, so it can block for an
|
||
arbitrary period on an under-utilized network.
|
||
<code class="literal">pcap_loop()</code> is enough for the purpose of this sample,
|
||
while <code class="literal">pcap_dispatch()</code> is normally used in a more
|
||
complex program.</p>
|
||
|
||
<p>Both of these functions have a <code class="literal">callback</code> parameter,
|
||
<code class="literal">packet_handler</code>, pointing to a function that will
|
||
receive the packets. This function is invoked by libpcap for every new
|
||
packet coming from the network and receives a generic status
|
||
(corresponding to the <code class="literal">user</code> parameter of <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_loop()</a> and <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_dispatch()</a>), a header with some
|
||
information on the packet like the timestamp and the length and the
|
||
actual data of the packet including all the protocol headers. Note that
|
||
the frame CRC is normally not present, because it is removed by the
|
||
network adapter after frame validation. Note also that most adapters
|
||
discard packets with wrong CRCs, therefore Npcap is normally not able
|
||
to capture them.</p>
|
||
|
||
<p>The above example extracts the timestamp and the length of every
|
||
packet from the <code class="literal">pcap_pkthdr</code> header and prints them on
|
||
the screen.</p>
|
||
|
||
<p>Please note that there may be a drawback using <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_loop()</a> mainly related to the
|
||
fact that the handler is called by the packet capture driver; therefore
|
||
the user application does not have direct control over it. Another
|
||
approach (and to have more readable programs) is to use the <a class="ulink" href="wpcap/pcap_next_ex.html" target="_top">pcap_next_ex()</a> function, which is
|
||
presented in the next example (<a class="xref" href="npcap-tutorial.html#npcap-tutorial-pcap-next-ex" title="Capturing the packets without the callback">the section called “Capturing the packets without the callback”</a>).</p>
|
||
</div>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-pcap-next-ex"></a>Capturing the packets without the callback</h3></div></div></div>
|
||
|
||
|
||
<p>The example program in this lesson behaves exactly like the previous
|
||
program (<a class="xref" href="npcap-tutorial.html#npcap-tutorial-openadapter" title="Opening an adapter and capturing the packets">the section called “Opening an adapter and capturing the packets”</a>), but it uses
|
||
<a class="ulink" href="wpcap/pcap_next_ex.html" target="_top">pcap_next_ex()</a> instead of
|
||
<a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_loop()</a>.</p>
|
||
|
||
<p>The callback-based capture mechanism of <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_loop()</a> is elegant and it could
|
||
be a good choice in some situations. However, handling a callback is
|
||
sometimes not practical—it often makes the program more complex
|
||
especially in situations with multithreaded applications or C++
|
||
classes.</p>
|
||
|
||
<p>In these cases, <a class="ulink" href="wpcap/pcap_next_ex.html" target="_top">pcap_next_ex()</a> retrievs a packet
|
||
with a direct call—using <code class="literal">pcap_next_ex()</code>,
|
||
packets are received only when the programmer wants them.</p>
|
||
|
||
<p>The parameters of this function are the same as a capture callback.
|
||
It takes an adapter descriptor and a couple of pointers that will be
|
||
initialized and returned to the user (one to a
|
||
<code class="literal">pcap_pkthdr</code> structure and another to a buffer with the
|
||
packet data).</p>
|
||
|
||
<p>In the following program, we recycle the callback code of the
|
||
previous lesson's example and move it inside main() right after the call
|
||
to <a class="ulink" href="wpcap/pcap_next_ex.html" target="_top">pcap_next_ex()</a>.</p>
|
||
|
||
<pre class="programlisting">
|
||
/* Open the device */
|
||
if ( (adhandle= pcap_open(d->name, // name of the device
|
||
65536, // portion of the packet to capture.
|
||
// 65536 guarantees that the whole packet will be captured on all the link layers
|
||
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
|
||
1000, // read timeout
|
||
NULL, // authentication on the remote machine
|
||
errbuf // error buffer
|
||
) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by Npcap\n", d->name);
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
printf("\nlistening on %s...\n", d->description);
|
||
|
||
/* At this point, we don't need any more the device list. Free it */
|
||
pcap_freealldevs(alldevs);
|
||
|
||
/* Retrieve the packets */
|
||
while((res = pcap_next_ex( adhandle, &header, &pkt_data)) >= 0){
|
||
|
||
if(res == 0)
|
||
/* Timeout elapsed */
|
||
continue;
|
||
|
||
/* convert the timestamp to readable format */
|
||
local_tv_sec = header->ts.tv_sec;
|
||
localtime_s(&ltime, &local_tv_sec);
|
||
strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);
|
||
|
||
printf("%s,%.6d len:%d\n", timestr, header->ts.tv_usec, header->len);
|
||
}
|
||
|
||
if(res == -1){
|
||
printf("Error reading the packets: %s\n", pcap_geterr(adhandle));
|
||
return -1;
|
||
}
|
||
</pre>
|
||
|
||
<p>Why do we use <a class="ulink" href="wpcap/pcap_next_ex.html" target="_top">pcap_next_ex()</a> instead of the old
|
||
<a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_next()</a>? Because
|
||
<code class="literal">pcap_next()</code> has some drawbacks. First of all, it is
|
||
inefficient because it hides the callback method but still relies on
|
||
<code class="literal">pcap_dispatch()</code>. Second, it is not able to detect EOF,
|
||
so it's not very useful when gathering packets from a file.</p>
|
||
|
||
<p>Notice also that <code class="literal">pcap_next_ex()</code> returns different
|
||
values for success, timeout elapsed, error and EOF conditions.</p>
|
||
</div>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-filtering"></a>Filtering the traffic</h3></div></div></div>
|
||
|
||
|
||
<p>One of the most powerful features offered by Npcap (and by libpcap as
|
||
well) is the filtering engine. It provides a very efficient way to
|
||
receive subsets of the network traffic, and is (usually) integrated with
|
||
the capture mechanism provided by Npcap. The functions used to filter
|
||
packets are <a class="ulink" href="wpcap/pcap_compile.html" target="_top">pcap_compile()</a>
|
||
and <a class="ulink" href="wpcap/pcap_setfilter.html" target="_top">pcap_setfilter()</a>.</p>
|
||
|
||
<p><a class="ulink" href="wpcap/pcap_compile.html" target="_top">pcap_compile()</a> takes a
|
||
string containing a high-level Boolean (filter) expression and produces a
|
||
low-level byte code that can be interpreted by the fileter engine in the
|
||
packet driver. The syntax of the boolean expression can be found in the
|
||
<a class="ulink" href="wpcap/pcap-filter.html" target="_top">Filtering expression syntax</a>
|
||
section of this documentation.</p>
|
||
|
||
<p><a class="ulink" href="wpcap/pcap_setfilter.html" target="_top">pcap_setfilter()</a>
|
||
associates a filter with a capture session in the kernel driver. Once
|
||
<code class="literal">pcap_setfilter()</code> is called, the associated filter will
|
||
be applied to all the packets coming from the network, and all the
|
||
conformant packets (i.e., packets for which the Boolean expression
|
||
evaluates to true) will be actually copied to the application.</p>
|
||
|
||
<p>The following code shows how to compile and set a filter. Note that
|
||
we must retrieve the netmask from the <code class="literal">pcap_if</code>
|
||
structure that describes the adapter, because some filters created by
|
||
<code class="literal">pcap_compile()</code> require it.</p>
|
||
|
||
<p>The filter passed to <code class="literal">pcap_compile()</code> in this code
|
||
snippet is "ip and tcp", which means to "keep only the packets that are
|
||
both IPv4 and TCP and deliver them to the application".</p>
|
||
|
||
|
||
<pre class="programlisting">
|
||
if (d->addresses != NULL)
|
||
/* Retrieve the mask of the first address of the interface */
|
||
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
|
||
else
|
||
/* If the interface is without an address we suppose to be in a C class network */
|
||
netmask=0xffffff;
|
||
|
||
|
||
//compile the filter
|
||
if (pcap_compile(adhandle, &fcode, "ip and tcp", 1, netmask) < 0)
|
||
{
|
||
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
//set the filter
|
||
if (pcap_setfilter(adhandle, &fcode) < 0)
|
||
{
|
||
fprintf(stderr,"\nError setting the filter.\n");
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
</pre>
|
||
|
||
<p>If you want to see some code that uses the filtering functions shown
|
||
in this lesson, look at the example presented in the next Lesson, <a class="xref" href="npcap-tutorial.html#npcap-tutorial-interpreting" title="Interpreting the packets">the section called “Interpreting the packets”</a>.</p>
|
||
|
||
</div>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-interpreting"></a>Interpreting the packets</h3></div></div></div>
|
||
|
||
|
||
<p>Now that we are able to capture and filter network traffic, we want
|
||
to put our knowledge to work with a simple "real world"
|
||
application.</p>
|
||
|
||
<p>In this lesson we will take code from the previous lessons and use
|
||
these pieces to build a more useful program. the main purpose of the
|
||
current program is to show how the protocol headers of a captured packet
|
||
can be parsed and interpreted. The resulting application, called UDPdump,
|
||
prints a summary of the UDP traffic on our network.</p>
|
||
|
||
<p>We have chosen to parse and display the UDP protocol because it is
|
||
more accessible than other protocols such as TCP and consequently is an
|
||
excellent initial example. Let's look at the code:</p>
|
||
|
||
<pre class="programlisting">
|
||
#include <pcap.h>
|
||
#include <Winsock2.h>
|
||
#include <tchar.h>
|
||
BOOL LoadNpcapDlls()
|
||
{
|
||
_TCHAR npcap_dir[512];
|
||
UINT len;
|
||
len = GetSystemDirectory(npcap_dir, 480);
|
||
if (!len) {
|
||
fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
|
||
return FALSE;
|
||
}
|
||
_tcscat_s(npcap_dir, 512, _T("\\Npcap"));
|
||
if (SetDllDirectory(npcap_dir) == 0) {
|
||
fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/* 4 bytes IP address */
|
||
typedef struct ip_address{
|
||
u_char byte1;
|
||
u_char byte2;
|
||
u_char byte3;
|
||
u_char byte4;
|
||
}ip_address;
|
||
|
||
/* IPv4 header */
|
||
typedef struct ip_header{
|
||
u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
|
||
u_char tos; // Type of service
|
||
u_short tlen; // Total length
|
||
u_short identification; // Identification
|
||
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
|
||
u_char ttl; // Time to live
|
||
u_char proto; // Protocol
|
||
u_short crc; // Header checksum
|
||
ip_address saddr; // Source address
|
||
ip_address daddr; // Destination address
|
||
u_int op_pad; // Option + Padding
|
||
}ip_header;
|
||
|
||
/* UDP header*/
|
||
typedef struct udp_header{
|
||
u_short sport; // Source port
|
||
u_short dport; // Destination port
|
||
u_short len; // Datagram length
|
||
u_short crc; // Checksum
|
||
}udp_header;
|
||
|
||
/* prototype of the packet handler */
|
||
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
|
||
|
||
|
||
int main()
|
||
{
|
||
pcap_if_t *alldevs;
|
||
pcap_if_t *d;
|
||
int inum;
|
||
int i=0;
|
||
pcap_t *adhandle;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
u_int netmask;
|
||
char packet_filter[] = "ip and udp";
|
||
struct bpf_program fcode;
|
||
|
||
/* Load Npcap and its functions. */
|
||
if (!LoadNpcapDlls())
|
||
{
|
||
fprintf(stderr, "Couldn't load Npcap\n");
|
||
exit(1);
|
||
}
|
||
|
||
/* Retrieve the device list */
|
||
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
|
||
{
|
||
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
|
||
exit(1);
|
||
}
|
||
|
||
/* Print the list */
|
||
for(d=alldevs; d; d=d->next)
|
||
{
|
||
printf("%d. %s", ++i, d->name);
|
||
if (d->description)
|
||
printf(" (%s)\n", d->description);
|
||
else
|
||
printf(" (No description available)\n");
|
||
}
|
||
|
||
if(i==0)
|
||
{
|
||
printf("\nNo interfaces found! Make sure Npcap 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");
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
/* Jump to the selected adapter */
|
||
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
|
||
|
||
/* Open the adapter */
|
||
if ( (adhandle= pcap_open(d->name, // name of the device
|
||
65536, // portion of the packet to capture.
|
||
// 65536 grants that the whole packet will be captured on all the MACs.
|
||
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
|
||
1000, // read timeout
|
||
NULL, // remote authentication
|
||
errbuf // error buffer
|
||
) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by Npcap\n", d->name);
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
/* Check the link layer. We support only Ethernet for simplicity. */
|
||
if(pcap_datalink(adhandle) != DLT_EN10MB)
|
||
{
|
||
fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
if(d->addresses != NULL)
|
||
/* Retrieve the mask of the first address of the interface */
|
||
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
|
||
else
|
||
/* If the interface is without addresses we suppose to be in a C class network */
|
||
netmask=0xffffff;
|
||
|
||
|
||
//compile the filter
|
||
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
|
||
{
|
||
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
//set the filter
|
||
if (pcap_setfilter(adhandle, &fcode)<0)
|
||
{
|
||
fprintf(stderr,"\nError setting the filter.\n");
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
printf("\nlistening on %s...\n", d->description);
|
||
|
||
/* At this point, we don't need any more the device list. Free it */
|
||
pcap_freealldevs(alldevs);
|
||
|
||
/* start the capture */
|
||
pcap_loop(adhandle, 0, packet_handler, NULL);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Callback function invoked by libpcap for every incoming packet */
|
||
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
|
||
{
|
||
struct tm ltime;
|
||
char timestr[16];
|
||
ip_header *ih;
|
||
udp_header *uh;
|
||
u_int ip_len;
|
||
u_short sport,dport;
|
||
time_t local_tv_sec;
|
||
|
||
/*
|
||
* Unused variable
|
||
*/
|
||
(VOID)(param);
|
||
|
||
/* convert the timestamp to readable format */
|
||
local_tv_sec = header->ts.tv_sec;
|
||
localtime_s(&ltime, &local_tv_sec);
|
||
strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);
|
||
|
||
/* print timestamp and length of the packet */
|
||
printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);
|
||
|
||
/* retireve the position of the ip header */
|
||
ih = (ip_header *) (pkt_data +
|
||
14); //length of ethernet header
|
||
|
||
/* retireve the position of the udp header */
|
||
ip_len = (ih->ver_ihl & 0xf) * 4;
|
||
uh = (udp_header *) ((u_char*)ih + ip_len);
|
||
|
||
/* convert from network byte order to host byte order */
|
||
sport = ntohs( uh->sport );
|
||
dport = ntohs( uh->dport );
|
||
|
||
/* print ip addresses and udp ports */
|
||
printf("%d.%d.%d.%d.%d -> %d.%d.%d.%d.%d\n",
|
||
ih->saddr.byte1,
|
||
ih->saddr.byte2,
|
||
ih->saddr.byte3,
|
||
ih->saddr.byte4,
|
||
sport,
|
||
ih->daddr.byte1,
|
||
ih->daddr.byte2,
|
||
ih->daddr.byte3,
|
||
ih->daddr.byte4,
|
||
dport);
|
||
}
|
||
</pre>
|
||
|
||
<p>First of all, we set the filter to "ip and udp". In this way we are
|
||
sure that packet_handler() will receive only UDP packets over IPv4: this
|
||
simplifies the parsing and increases the efficiency of the
|
||
program.</p>
|
||
|
||
<p>We have also created a couple of structs that describe the IP and UDP
|
||
headers. These structs are used by packet_handler() to properly locate
|
||
the various header fields.</p>
|
||
|
||
<p>packet_handler(), although limited to a single protocol dissector
|
||
(UDP over IPv4), shows how complex "sniffers" like tcpdump/WinDump decode
|
||
the network traffic. Since we aren't interested in the MAC header, we
|
||
skip it. For simplicity and before starting the capture, we check the MAC
|
||
layer with <a class="ulink" href="wpcap/pcap_datalink.html" target="_top">pcap_datalink()</a>
|
||
to make sure that we are dealing with an Ethernet network. This way we
|
||
can be sure that the MAC header is exactly 14 bytes.</p>
|
||
|
||
<p>The IP header is located just after the MAC header. We will extract
|
||
the IP source and destination addresses from the IP header.</p>
|
||
|
||
<p>Reaching the UDP header is a bit more complicated, because the IP
|
||
header doesn't have a fixed length. Therefore, we use the IP header's
|
||
length field to know its size. Once we know the location of the UDP
|
||
header, we extract the source and destination ports.</p>
|
||
|
||
<p>The extracted values are printed on the screen, and the result is
|
||
something like:</p>
|
||
<pre class="screen">
|
||
\Device\Packet_{A7FD048A-5D4B-478E-B3C1-34401AC3B72F} (Xircom t 10/100 Adapter)
|
||
Enter the interface number (1-2):1
|
||
listening on Xircom CardBus Ethernet 10/100 Adapter...
|
||
16:13:15.312784 len:87 130.192.31.67.2682 -> 130.192.3.21.53
|
||
16:13:15.314796 len:137 130.192.3.21.53 -> 130.192.31.67.2682
|
||
16:13:15.322101 len:78 130.192.31.67.2683 -> 130.192.3.21.53
|
||
</pre>
|
||
<p>Each of the final 3 lines represents a different packet.</p>
|
||
</div>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-offline"></a>Handling offline dump files</h3></div></div></div>
|
||
|
||
|
||
<p>In this lession we are going to learn how to handle packet capture to
|
||
a file (dump to file). Npcap 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.</p>
|
||
|
||
<p>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, Wireshark and Snort.</p>
|
||
|
||
<div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="npcap-tutorial-offline-saving"></a>Saving packets to a dump file</h4></div></div></div>
|
||
|
||
|
||
<p>First of all, let's see how to write packets in libpcap
|
||
format.</p>
|
||
|
||
<p>The following example captures the packets from the selected
|
||
interface and saves them on a file whose name is provided by the
|
||
user.</p>
|
||
<pre class="programlisting">
|
||
#include <pcap.h>
|
||
#include "misc.h" /* LoadNpcapDlls */
|
||
|
||
/* prototype of the packet handler */
|
||
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
|
||
|
||
int main(int argc, char **argv)
|
||
{
|
||
pcap_if_t *alldevs;
|
||
pcap_if_t *d;
|
||
int inum;
|
||
int i=0;
|
||
pcap_t *adhandle;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
pcap_dumper_t *dumpfile;
|
||
|
||
/* Load Npcap and its functions. */
|
||
if (!LoadNpcapDlls())
|
||
{
|
||
fprintf(stderr, "Couldn't load Npcap\n");
|
||
exit(1);
|
||
}
|
||
|
||
/* Check command line */
|
||
if(argc != 2)
|
||
{
|
||
printf("usage: %s filename", argv[0]);
|
||
return -1;
|
||
}
|
||
|
||
/* Retrieve the device list on the local machine */
|
||
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
|
||
{
|
||
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
|
||
exit(1);
|
||
}
|
||
|
||
/* Print the list */
|
||
for(d=alldevs; d; d=d->next)
|
||
{
|
||
printf("%d. %s", ++i, d->name);
|
||
if (d->description)
|
||
printf(" (%s)\n", d->description);
|
||
else
|
||
printf(" (No description available)\n");
|
||
}
|
||
|
||
if(i==0)
|
||
{
|
||
printf("\nNo interfaces found! Make sure Npcap 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");
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
/* Jump to the selected adapter */
|
||
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
|
||
|
||
|
||
/* Open the device */
|
||
if ( (adhandle= pcap_open(d->name, // name of the device
|
||
65536, // portion of the packet to capture
|
||
// 65536 guarantees that the whole packet will be captured on all the link layers
|
||
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
|
||
1000, // read timeout
|
||
NULL, // authentication on the remote machine
|
||
errbuf // error buffer
|
||
) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by Npcap\n", d->name);
|
||
/* Free the device list */
|
||
pcap_freealldevs(alldevs);
|
||
return -1;
|
||
}
|
||
|
||
/* Open the dump file */
|
||
dumpfile = pcap_dump_open(adhandle, argv[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);
|
||
|
||
/* At this point, we no longer need the device list. Free it */
|
||
pcap_freealldevs(alldevs);
|
||
|
||
/* start the capture */
|
||
pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Callback function invoked by libpcap for every incoming packet */
|
||
void packet_handler(u_char *dumpfile, const struct pcap_pkthdr *header, const u_char *pkt_data)
|
||
{
|
||
/* save the packet on the dump file */
|
||
pcap_dump(dumpfile, header, pkt_data);
|
||
}
|
||
</pre>
|
||
|
||
<p>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:</p>
|
||
|
||
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">a call to <a class="ulink" href="wpcap/pcap_dump_open.html" target="_top">pcap_dump_open()</a> is issued
|
||
once the interface is opened. This call opens a dump file and
|
||
associates it with the interface.</li><li class="listitem">the packets are written to this file with a <a class="ulink" href="wpcap/pcap_dump.html" target="_top">pcap_dump()</a> from the
|
||
packet_handler() callback. The parameters of
|
||
<code class="literal">pcap_dump()</code> are in 1-1 correspondence with the
|
||
parameters of <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_handler()</a>.</li></ul></div>
|
||
</div>
|
||
|
||
<div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="npcap-tutorial-offline-reading"></a>Reading packets from a dump file</h4></div></div></div>
|
||
|
||
|
||
<p>Now that we have a dump file available, we can try to read its
|
||
content. The following code opens a Npcap/libpcap dump file and
|
||
displays every packet contained in the file. The file is opened with
|
||
<a class="ulink" href="wpcap/pcap_open_offline.html" target="_top">pcap_open_offline()</a>,
|
||
then the usual <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_loop()</a> 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.</p>
|
||
|
||
<p>This example introduces another function:
|
||
<code class="literal">pcap_createsrcstr()</code>. This function is required to
|
||
create a source string that begins with a marker used to tell Npcap 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 <code class="literal">pcap_findalldevs_ex()</code> 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.</p>
|
||
|
||
<pre class="programlisting">
|
||
#include <stdio.h>
|
||
#include <pcap.h>
|
||
#include "misc.h" /* LoadNpcapDlls */
|
||
|
||
#define LINE_LEN 16
|
||
|
||
void dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *);
|
||
|
||
int main(int argc, char **argv)
|
||
{
|
||
pcap_t *fp;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
char source[PCAP_BUF_SIZE];
|
||
|
||
/* Load Npcap and its functions. */
|
||
if (!LoadNpcapDlls())
|
||
{
|
||
fprintf(stderr, "Couldn't load Npcap\n");
|
||
exit(1);
|
||
}
|
||
|
||
if(argc != 2){
|
||
|
||
printf("usage: %s filename", argv[0]);
|
||
return -1;
|
||
|
||
}
|
||
|
||
/* Create the source string according to the new Npcap syntax */
|
||
if ( pcap_createsrcstr( source, // variable that will keep the source string
|
||
PCAP_SRC_FILE, // we want to open a file
|
||
NULL, // remote host
|
||
NULL, // port on the remote host
|
||
argv[1], // name of the file we want to open
|
||
errbuf // error buffer
|
||
) != 0)
|
||
{
|
||
fprintf(stderr,"\nError creating a source string\n");
|
||
return -1;
|
||
}
|
||
|
||
/* Open the capture file */
|
||
if ( (fp= pcap_open(source, // name of the device
|
||
65536, // portion of the packet to capture
|
||
// 65536 guarantees that the whole packet will be captured on all the link layers
|
||
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
|
||
1000, // read timeout
|
||
NULL, // authentication on the remote machine
|
||
errbuf // error buffer
|
||
) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open the file %s.\n", source);
|
||
return -1;
|
||
}
|
||
|
||
// read and dispatch packets until EOF is reached
|
||
pcap_loop(fp, 0, dispatcher_handler, NULL);
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
void dispatcher_handler(u_char *temp1,
|
||
const struct pcap_pkthdr *header, const u_char *pkt_data)
|
||
{
|
||
u_int i=0;
|
||
|
||
/*
|
||
* Unused variable
|
||
*/
|
||
(VOID)temp1;
|
||
|
||
/* print pkt timestamp and pkt len */
|
||
printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len);
|
||
|
||
/* Print the packet */
|
||
for (i=1; (i < header->caplen + 1 ) ; i++)
|
||
{
|
||
printf("%.2x ", pkt_data[i-1]);
|
||
if ( (i % LINE_LEN) == 0) printf("\n");
|
||
}
|
||
|
||
printf("\n\n");
|
||
|
||
}
|
||
</pre>
|
||
|
||
<p>The following example has the same purpose of the last one, but
|
||
<a class="ulink" href="wpcap/pcap_next_ex.html" target="_top">pcap_next_ex()</a> is used
|
||
instead of the <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_loop()</a>
|
||
callback method.</p>
|
||
|
||
<pre class="programlisting">
|
||
#include <stdio.h>
|
||
#include <pcap.h>
|
||
#include "misc.h" /* LoadNpcapDlls */
|
||
|
||
#define LINE_LEN 16
|
||
|
||
int main(int argc, char **argv)
|
||
{
|
||
pcap_t *fp;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
char source[PCAP_BUF_SIZE];
|
||
struct pcap_pkthdr *header;
|
||
const u_char *pkt_data;
|
||
u_int i=0;
|
||
int res;
|
||
|
||
/* Load Npcap and its functions. */
|
||
if (!LoadNpcapDlls())
|
||
{
|
||
fprintf(stderr, "Couldn't load Npcap\n");
|
||
exit(1);
|
||
}
|
||
|
||
if(argc != 2)
|
||
{
|
||
printf("usage: %s filename", argv[0]);
|
||
return -1;
|
||
}
|
||
|
||
/* Create the source string according to the new Npcap syntax */
|
||
if ( pcap_createsrcstr( source, // variable that will keep the source string
|
||
PCAP_SRC_FILE, // we want to open a file
|
||
NULL, // remote host
|
||
NULL, // port on the remote host
|
||
argv[1], // name of the file we want to open
|
||
errbuf // error buffer
|
||
) != 0)
|
||
{
|
||
fprintf(stderr,"\nError creating a source string\n");
|
||
return -1;
|
||
}
|
||
|
||
/* Open the capture file */
|
||
if ( (fp= pcap_open(source, // name of the device
|
||
65536, // portion of the packet to capture
|
||
// 65536 guarantees that the whole packet will be captured on all the link layers
|
||
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
|
||
1000, // read timeout
|
||
NULL, // authentication on the remote machine
|
||
errbuf // error buffer
|
||
) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open the file %s.\n", source);
|
||
return -1;
|
||
}
|
||
|
||
/* Retrieve the packets from the file */
|
||
while((res = pcap_next_ex( fp, &header, &pkt_data)) >= 0)
|
||
{
|
||
/* print pkt timestamp and pkt len */
|
||
printf("%ld:%ld (%ld)\n", header->ts.tv_sec, header->ts.tv_usec, header->len);
|
||
|
||
/* Print the packet */
|
||
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;
|
||
}
|
||
|
||
</pre>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-sending"></a>Sending Packets</h3></div></div></div>
|
||
|
||
<p>Although the name <span class="emphasis"><em>Npcap</em></span> indicates clearly that the purpose
|
||
of the library is packet capture, other useful features for raw
|
||
networking are provided. Among them, the user can find a complete set of
|
||
functions to send packets.</p>
|
||
|
||
<div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="id574106"></a>Sending a single packet with <code class="literal">pcap_sendpacket()</code></h4></div></div></div>
|
||
|
||
|
||
<p>The simplest way to send a packet is shown in the following code
|
||
snippet. After opening an adapter, <a class="ulink" href="wpcap/pcap_inject.html" target="_top">pcap_sendpacket()</a> is called to
|
||
send a hand-crafted packet. <code class="literal">pcap_sendpacket()</code> takes
|
||
as arguments a buffer containing the data to send, the length of the
|
||
buffer and the adapter that will send it. Notice that the buffer is
|
||
sent to the net as is, without any manipulation. This means that the
|
||
application has to create the correct protocol headers in order to send
|
||
something meaningful.</p>
|
||
|
||
<pre class="programlisting">
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
#include <pcap.h>
|
||
#include "misc.h" /* LoadNpcapDlls */
|
||
|
||
|
||
void main(int argc, char **argv)
|
||
{
|
||
pcap_t *fp;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
u_char packet[100];
|
||
int i;
|
||
|
||
/* Load Npcap and its functions. */
|
||
if (!LoadNpcapDlls())
|
||
{
|
||
fprintf(stderr, "Couldn't load Npcap\n");
|
||
exit(1);
|
||
}
|
||
|
||
/* Check the validity of the command line */
|
||
if (argc != 2)
|
||
{
|
||
printf("usage: %s interface (e.g. 'rpcap://eth0')", argv[0]);
|
||
return;
|
||
}
|
||
|
||
/* Open the output device */
|
||
if ( (fp= pcap_open(argv[1], // name of the device
|
||
100, // portion of the packet to capture (only the first 100 bytes)
|
||
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
|
||
1000, // read timeout
|
||
NULL, // authentication on the remote machine
|
||
errbuf // error buffer
|
||
) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by Npcap\n", argv[1]);
|
||
return;
|
||
}
|
||
|
||
/* Supposing to be on ethernet, set mac destination to 1:1:1:1:1:1 */
|
||
packet[0]=1;
|
||
packet[1]=1;
|
||
packet[2]=1;
|
||
packet[3]=1;
|
||
packet[4]=1;
|
||
packet[5]=1;
|
||
|
||
/* set mac source to 2:2:2:2:2:2 */
|
||
packet[6]=2;
|
||
packet[7]=2;
|
||
packet[8]=2;
|
||
packet[9]=2;
|
||
packet[10]=2;
|
||
packet[11]=2;
|
||
|
||
/* Fill the rest of the packet */
|
||
for(i=12;i<100;i++)
|
||
{
|
||
packet[i]=(u_char)i;
|
||
}
|
||
|
||
/* Send down the packet */
|
||
if (pcap_sendpacket(fp, packet, 100 /* size */) != 0)
|
||
{
|
||
fprintf(stderr,"\nError sending the packet: %s\n", pcap_geterr(fp));
|
||
return;
|
||
}
|
||
|
||
return;
|
||
}
|
||
</pre>
|
||
|
||
</div>
|
||
|
||
<div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a name="id574120"></a>Send queues</h4></div></div></div>
|
||
|
||
|
||
<p>While <a class="ulink" href="wpcap/pcap_inject.html" target="_top">pcap_sendpacket()</a>
|
||
offers a simple and immediate way to send a single packet,
|
||
<span class="emphasis"><em>send queues</em></span> provide an advanced, powerful and
|
||
optimized mechanism to send a collection of packets. A send queue is a
|
||
container for a variable number of packets that will be sent to the
|
||
network. It has a size, that represents the maximum amount of bytes it
|
||
can store.</p>
|
||
|
||
<p>A send queue is created calling the
|
||
<code class="literal">pcap_sendqueue_alloc()</code> function, specifying the size
|
||
of the new send queue.</p>
|
||
|
||
<p>Once the send queue is created,
|
||
<code class="literal">pcap_sendqueue_queue()</code> can be used to add a packet
|
||
to the send queue. This function takes a <code class="literal">pcap_pkthdr</code>
|
||
with the timestamp and the length and a buffer with the data of the
|
||
packet. These parameters are the same as those received by <a class="ulink" href="wpcap/pcap_next_ex.html" target="_top">pcap_next_ex()</a> and
|
||
<code class="literal">pcap_handler()</code>, therefore queuing a packet that was
|
||
just captured or read from a file is a matter of passing these
|
||
parameters to <code class="literal">pcap_sendqueue_queue()</code>.</p>
|
||
|
||
<p>To transmit a send queue, Npcap provides the
|
||
<code class="literal">pcap_sendqueue_transmit()</code> function. Note the third
|
||
parameter: if nonzero, the send will be
|
||
<span class="emphasis"><em>synchronized</em></span>, i.e. the relative timestamps of the
|
||
packets will be respected. This operation requires a remarkable amount
|
||
of CPU, because the synchronization takes place in the kernel driver
|
||
using "busy wait" loops. Although this operation is quite CPU
|
||
intensive, it often results in very high precision packet transmissions
|
||
(often around few microseconds or less).</p>
|
||
|
||
<p>Note that transmitting a send queue with
|
||
<code class="literal">pcap_sendqueue_transmit()</code> is much more efficient
|
||
than performing a series of <a class="ulink" href="wpcap/pcap_inject.html" target="_top">pcap_sendpacket()</a>, because the
|
||
send queue is buffered at kernel level drastically decreasing the
|
||
number of context switches.</p>
|
||
|
||
<p>When a queue is no longer needed, it can be deleted with
|
||
<code class="literal">pcap_sendqueue_destroy()</code> that frees all the buffers
|
||
associated with the send queue.</p>
|
||
|
||
<p>The next program shows how to use send queues. It opens a capture
|
||
file with <a class="ulink" href="wpcap/pcap_open_offline.html" target="_top">pcap_open_offline()</a>, then
|
||
it moves the packets from the file to a properly allocated send queue.
|
||
At his point it transmits the queue, synchronizing it if requested by
|
||
the user.</p>
|
||
|
||
<p>Note that the link-layer of the dumpfile is compared with the one
|
||
of the interface that will send the packets using <a class="ulink" href="wpcap/pcap_datalink.html" target="_top">pcap_datalink()</a>, and a warning
|
||
is printed if they are different—it is important that the
|
||
capture-file link-layer be the same as the adapter's link layer for
|
||
otherwise the transmission is pointless.</p>
|
||
|
||
<pre class="programlisting">
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
#include <pcap.h>
|
||
|
||
#ifdef WIN32
|
||
#include <tchar.h>
|
||
BOOL LoadNpcapDlls()
|
||
{
|
||
TCHAR npcap_dir[512];
|
||
UINT len;
|
||
len = GetSystemDirectory(npcap_dir, 480);
|
||
if (!len) {
|
||
fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
|
||
return FALSE;
|
||
}
|
||
_tcscat_s(npcap_dir, 512, TEXT("\\Npcap"));
|
||
if (SetDllDirectory(npcap_dir) == 0) {
|
||
fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
#endif
|
||
|
||
void usage();
|
||
|
||
void main(int argc, char **argv)
|
||
{
|
||
pcap_t *indesc,*outdesc;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
char source[PCAP_BUF_SIZE];
|
||
FILE *capfile;
|
||
int caplen, sync;
|
||
u_int res;
|
||
pcap_send_queue *squeue;
|
||
struct pcap_pkthdr *pktheader;
|
||
u_char *pktdata;
|
||
float cpu_time;
|
||
u_int npacks = 0;
|
||
errno_t fopen_error;
|
||
|
||
#ifdef WIN32
|
||
/* Load Npcap and its functions. */
|
||
if (!LoadNpcapDlls())
|
||
{
|
||
fprintf(stderr, "Couldn't load Npcap\n");
|
||
exit(1);
|
||
}
|
||
#endif
|
||
|
||
/* Check the validity of the command line */
|
||
if (argc <= 2 || argc >= 5)
|
||
{
|
||
usage();
|
||
return;
|
||
}
|
||
|
||
/* Retrieve the length of the capture file */
|
||
fopen_error = fopen_s(&capfile, argv[1],"rb");
|
||
if(fopen_error != 0){
|
||
printf("Error opening the file, errno %d.\n", fopen_error);
|
||
return;
|
||
}
|
||
|
||
fseek(capfile , 0, SEEK_END);
|
||
caplen= ftell(capfile)- sizeof(struct pcap_file_header);
|
||
fclose(capfile);
|
||
|
||
/* Chek if the timestamps must be respected */
|
||
if(argc == 4 && argv[3][0] == 's')
|
||
sync = TRUE;
|
||
else
|
||
sync = FALSE;
|
||
|
||
/* Open the capture */
|
||
/* Create the source string according to the new WinPcap syntax */
|
||
if ( pcap_createsrcstr( source, // variable that will keep the source string
|
||
PCAP_SRC_FILE, // we want to open a file
|
||
NULL, // remote host
|
||
NULL, // port on the remote host
|
||
argv[1], // name of the file we want to open
|
||
errbuf // error buffer
|
||
) != 0)
|
||
{
|
||
fprintf(stderr,"\nError creating a source string\n");
|
||
return;
|
||
}
|
||
|
||
/* Open the capture file */
|
||
if ( (indesc= pcap_open(source, 65536, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open the file %s.\n", source);
|
||
return;
|
||
}
|
||
|
||
/* Open the output adapter */
|
||
if ( (outdesc= pcap_open(argv[2], 100, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open adapter %s.\n", source);
|
||
return;
|
||
}
|
||
|
||
/* Check the MAC type */
|
||
if (pcap_datalink(indesc) != pcap_datalink(outdesc))
|
||
{
|
||
printf("Warning: the datalink of the capture differs from the one of the selected interface.\n");
|
||
printf("Press a key to continue, or CTRL+C to stop.\n");
|
||
getchar();
|
||
}
|
||
|
||
/* Allocate a send queue */
|
||
squeue = pcap_sendqueue_alloc(caplen);
|
||
|
||
/* Fill the queue with the packets from the file */
|
||
while ((res = pcap_next_ex( indesc, &pktheader, &pktdata)) == 1)
|
||
{
|
||
if (pcap_sendqueue_queue(squeue, pktheader, pktdata) == -1)
|
||
{
|
||
printf("Warning: packet buffer too small, not all the packets will be sent.\n");
|
||
break;
|
||
}
|
||
|
||
npacks++;
|
||
}
|
||
|
||
if (res == -1)
|
||
{
|
||
printf("Corrupted input file.\n");
|
||
pcap_sendqueue_destroy(squeue);
|
||
return;
|
||
}
|
||
|
||
/* Transmit the queue */
|
||
|
||
cpu_time = (float)clock ();
|
||
|
||
if ((res = pcap_sendqueue_transmit(outdesc, squeue, sync)) < squeue->len)
|
||
{
|
||
printf("An error occurred sending the packets: %s. Only %d bytes were sent\n", pcap_geterr(outdesc), res);
|
||
}
|
||
|
||
cpu_time = (clock() - cpu_time)/CLK_TCK;
|
||
|
||
printf ("\n\nElapsed time: %5.3f\n", cpu_time);
|
||
printf ("\nTotal packets generated = %d", npacks);
|
||
printf ("\nAverage packets per second = %d", (int)((double)npacks/cpu_time));
|
||
printf ("\n");
|
||
|
||
/* free the send queue */
|
||
pcap_sendqueue_destroy(squeue);
|
||
|
||
/* Close the input file */
|
||
pcap_close(indesc);
|
||
|
||
/*
|
||
* lose the output adapter
|
||
* IMPORTANT: remember to close the adapter, otherwise there will be no guarantee that all the
|
||
* packets will be sent!
|
||
*/
|
||
pcap_close(outdesc);
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
void usage()
|
||
{
|
||
|
||
printf("\nSendcap, sends a libpcap/tcpdump capture file to the net. Copyright (C) 2002 Loris Degioanni.\n");
|
||
printf("\nUsage:\n");
|
||
printf("\t sendcap file_name adapter [s]\n");
|
||
printf("\nParameters:\n");
|
||
printf("\nfile_name: the name of the dump file that will be sent to the network\n");
|
||
printf("\nadapter: the device to use. Use \"WinDump -D\" for a list of valid devices\n");
|
||
printf("\ns: if present, forces the packets to be sent synchronously, i.e. respecting the timestamps in the dump file. This option will work only under Windows NTx.\n\n");
|
||
|
||
exit(0);
|
||
}
|
||
</pre>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a name="npcap-tutorial-statistics"></a>Gathering Statistics on the network traffic</h3></div></div></div>
|
||
|
||
|
||
<p>This lesson shows another advanced feature of Npcap: the ability to
|
||
collect statistics about network traffic. The statistical engine makes
|
||
use of the kernel-level packet filter to efficiently classify the
|
||
incoming packet.</p>
|
||
|
||
<p>In order to use this feature, the programmer must open an adapter and
|
||
put it in <span class="emphasis"><em>statistical mode</em></span>. This can be done with
|
||
<code class="literal">pcap_setmode()</code>. In particular,
|
||
<code class="literal">MODE_STAT</code> must be used as the <code class="literal">mode</code>
|
||
argument of this function.</p>
|
||
|
||
<p>With statistical mode, making an application that monitors the TCP
|
||
traffic load is a matter of few lines of code. The following sample shows
|
||
how to do it.</p>
|
||
|
||
<pre class="programlisting">
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
|
||
#include <pcap.h>
|
||
|
||
#include <tchar.h>
|
||
BOOL LoadNpcapDlls()
|
||
{
|
||
_TCHAR npcap_dir[512];
|
||
UINT len;
|
||
len = GetSystemDirectory(npcap_dir, 480);
|
||
if (!len) {
|
||
fprintf(stderr, "Error in GetSystemDirectory: %x", GetLastError());
|
||
return FALSE;
|
||
}
|
||
_tcscat_s(npcap_dir, 512, _T("\\Npcap"));
|
||
if (SetDllDirectory(npcap_dir) == 0) {
|
||
fprintf(stderr, "Error in SetDllDirectory: %x", GetLastError());
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
void usage();
|
||
|
||
void dispatcher_handler(u_char *, const struct pcap_pkthdr *, const u_char *);
|
||
|
||
|
||
void main(int argc, char **argv)
|
||
{
|
||
pcap_t *fp;
|
||
char errbuf[PCAP_ERRBUF_SIZE];
|
||
struct timeval st_ts;
|
||
u_int netmask;
|
||
struct bpf_program fcode;
|
||
|
||
/* Load Npcap and its functions. */
|
||
if (!LoadNpcapDlls())
|
||
{
|
||
fprintf(stderr, "Couldn't load Npcap\n");
|
||
exit(1);
|
||
}
|
||
|
||
/* Check the validity of the command line */
|
||
if (argc != 2)
|
||
{
|
||
usage();
|
||
return;
|
||
}
|
||
|
||
/* Open the output adapter */
|
||
if ( (fp= pcap_open(argv[1], 100, PCAP_OPENFLAG_PROMISCUOUS, 1000, NULL, errbuf) ) == NULL)
|
||
{
|
||
fprintf(stderr,"\nUnable to open adapter %s.\n", errbuf);
|
||
return;
|
||
}
|
||
|
||
/* Don't care about netmask, it won't be used for this filter */
|
||
netmask=0xffffff;
|
||
|
||
//compile the filter
|
||
if (pcap_compile(fp, &fcode, "tcp", 1, netmask) <0 )
|
||
{
|
||
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
|
||
/* Free the device list */
|
||
return;
|
||
}
|
||
|
||
//set the filter
|
||
if (pcap_setfilter(fp, &fcode)<0)
|
||
{
|
||
fprintf(stderr,"\nError setting the filter.\n");
|
||
pcap_close(fp);
|
||
/* Free the device list */
|
||
return;
|
||
}
|
||
|
||
/* Put the interface in statstics mode */
|
||
if (pcap_setmode(fp, MODE_STAT)<0)
|
||
{
|
||
fprintf(stderr,"\nError setting the mode.\n");
|
||
pcap_close(fp);
|
||
/* Free the device list */
|
||
return;
|
||
}
|
||
|
||
|
||
printf("TCP traffic summary:\n");
|
||
|
||
/* Start the main loop */
|
||
pcap_loop(fp, 0, dispatcher_handler, (PUCHAR)&st_ts);
|
||
|
||
pcap_close(fp);
|
||
return;
|
||
}
|
||
|
||
void dispatcher_handler(u_char *state, const struct pcap_pkthdr *header, const u_char *pkt_data)
|
||
{
|
||
struct timeval *old_ts = (struct timeval *)state;
|
||
u_int delay;
|
||
LARGE_INTEGER Bps,Pps;
|
||
struct tm ltime;
|
||
char timestr[16];
|
||
time_t local_tv_sec;
|
||
|
||
/* Calculate the delay in microseconds from the last sample. */
|
||
/* This value is obtained from the timestamp that the associated with the sample. */
|
||
delay=(header->ts.tv_sec - old_ts->tv_sec) * 1000000 - old_ts->tv_usec + header->ts.tv_usec;
|
||
/* Get the number of Bits per second */
|
||
Bps.QuadPart=(((*(LONGLONG*)(pkt_data + 8)) * 8 * 1000000) / (delay));
|
||
/* ^ ^
|
||
| |
|
||
| |
|
||
| |
|
||
converts bytes in bits -- |
|
||
|
|
||
delay is expressed in microseconds --
|
||
*/
|
||
|
||
/* Get the number of Packets per second */
|
||
Pps.QuadPart=(((*(LONGLONG*)(pkt_data)) * 1000000) / (delay));
|
||
|
||
/* Convert the timestamp to readable format */
|
||
local_tv_sec = header->ts.tv_sec;
|
||
localtime_s(&ltime, &local_tv_sec);
|
||
strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);
|
||
|
||
/* Print timestamp*/
|
||
printf("%s ", timestr);
|
||
|
||
/* Print the samples */
|
||
printf("BPS=%I64u ", Bps.QuadPart);
|
||
printf("PPS=%I64u\n", Pps.QuadPart);
|
||
|
||
//store current timestamp
|
||
old_ts->tv_sec=header->ts.tv_sec;
|
||
old_ts->tv_usec=header->ts.tv_usec;
|
||
}
|
||
|
||
|
||
void usage()
|
||
{
|
||
|
||
printf("\nShows the TCP traffic load, in bits per second and packets per second.\nCopyright (C) 2002 Loris Degioanni.\n");
|
||
printf("\nUsage:\n");
|
||
printf("\t tcptop adapter\n");
|
||
printf("\t You can use \"WinDump -D\" if you don't know the name of your adapters.\n");
|
||
|
||
exit(0);
|
||
}
|
||
</pre>
|
||
|
||
<p>Before enabling statistical mode, the user has the option to set a
|
||
filter that defines the subset of network traffic that will be monitored.
|
||
See the <a class="ulink" href="wpcap/pcap-filter.html" target="_top">Filtering expression
|
||
syntax</a> documentation for details. If no filter has been set,
|
||
all of the traffic will be monitored.</p>
|
||
|
||
<p>Once
|
||
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">the filter is set</li><li class="listitem"><code class="literal">pcap_setmode()</code> is called</li><li class="listitem">callback invocation is enabled with <a class="ulink" href="wpcap/pcap_loop.html" target="_top">pcap_loop()</a></li></ul></div><p>
|
||
the interface descriptor starts to work in statistical mode. Notice the
|
||
fourth parameter (<code class="literal">to_ms</code>) of <a class="ulink" href="wpcap/pcap_open.html" target="_top">pcap_open()</a>: it defines the interval
|
||
among the statistical samples. The callback function receives the samples
|
||
calculated by the driver every <code class="literal">to_ms</code> milliseconds.
|
||
These samples are encapsulated in the second and third parameters of the
|
||
callback function.
|
||
|
||
Two 64-bit counters are provided: the number of packets and the amount of
|
||
bytes received during the last interval.</p>
|
||
|
||
<p>In the example, the adapter is opened with a timeout of 1000 ms. This
|
||
means that dispatcher_handler() is called once per second. At this point
|
||
a filter that keeps only tcp packets is compiled and set. Then
|
||
<code class="literal">pcap_setmode()</code> and <code class="literal">pcap_loop()</code> are
|
||
called. Note that a struct timeval pointer is passed to
|
||
<code class="literal">pcap_loop()</code> as the <code class="literal">user</code> parameter.
|
||
This structure will be used to store a timestamp in order to calculate
|
||
the interval between two samples. dispatcher_handler()uses this interval
|
||
to obtain the bits per second and the packets per second and then prints
|
||
these values on the screen.</p>
|
||
|
||
<p>Note finally that this example is by far more efficient than a
|
||
program that captures the packets in the traditional way and calculates
|
||
statistics at user-level. Statistical mode requires the minumum amount of
|
||
data copies and context switches and therefore the CPU is optimized.
|
||
Moreover, a very small amount of memory is required.</p>
|
||
</div>
|
||
</div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="npcap-devguide.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="npcap-internals.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Developing software with Npcap </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Npcap internals</td></tr></table></div></body></html>
|