Files
NE_YuR/network/start/lib/npcap/docs/npcap-tutorial.html
2025-11-17 22:22:52 +08:00

1694 lines
62 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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 &#8220;Examples&#8221;</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 */, &amp;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-&gt;next)
{
printf("%d. %s", ++i, d-&gt;name);
if (d-&gt;description)
printf(" (%s)\n", d-&gt;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 &#8220;Obtaining the device list&#8221;</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-&gt;name);
/* Description */
if (d-&gt;description)
printf("\tDescription: %s\n",d-&gt;description);
/* Loopback Address*/
printf("\tLoopback: %s\n",(d-&gt;flags &amp; PCAP_IF_LOOPBACK)?"yes":"no");
/* IP addresses */
for(a=d-&gt;addresses;a;a=a-&gt;next) {
printf("\tAddress Family: #%d\n",a-&gt;addr-&gt;sa_family);
switch(a-&gt;addr-&gt;sa_family)
{
case AF_INET:
printf("\tAddress Family Name: AF_INET\n");
if (a-&gt;addr)
printf("\tAddress: %s\n",iptos(((struct sockaddr_in *)a-&gt;addr)-&gt;sin_addr.s_addr));
if (a-&gt;netmask)
printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a-&gt;netmask)-&gt;sin_addr.s_addr));
if (a-&gt;broadaddr)
printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a-&gt;broadaddr)-&gt;sin_addr.s_addr));
if (a-&gt;dstaddr)
printf("\tDestination Address: %s\n",iptos(((struct sockaddr_in *)a-&gt;dstaddr)-&gt;sin_addr.s_addr));
break;
case AF_INET6:
printf("\tAddress Family Name: AF_INET6\n");
if (a-&gt;addr)
printf("\tAddress: %s\n", ip6tos(a-&gt;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 &lt;pcap.h&gt;
#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, &amp;alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* Print the list */
for(d=alldevs; d; d=d-&gt;next)
{
printf("%d. %s", ++i, d-&gt;name);
if (d-&gt;description)
printf(" (%s)\n", d-&gt;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", &amp;inum);
if(inum &lt; 1 || inum &gt; 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&lt; inum-1 ;d=d-&gt;next, i++);
/* Open the device */
if ( (adhandle= pcap_open(d-&gt;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-&gt;name);
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistening on %s...\n", d-&gt;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-&gt;ts.tv_sec;
localtime_s(&amp;ltime, &amp;local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", &amp;ltime);
printf("%s,%.6d len:%d\n", timestr, header-&gt;ts.tv_usec, header-&gt;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 &#8220;Capturing the packets without the callback&#8221;</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 &#8220;Opening an adapter and capturing the packets&#8221;</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&#8212;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&#8212;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-&gt;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-&gt;name);
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistening on %s...\n", d-&gt;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, &amp;header, &amp;pkt_data)) &gt;= 0){
if(res == 0)
/* Timeout elapsed */
continue;
/* convert the timestamp to readable format */
local_tv_sec = header-&gt;ts.tv_sec;
localtime_s(&amp;ltime, &amp;local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", &amp;ltime);
printf("%s,%.6d len:%d\n", timestr, header-&gt;ts.tv_usec, header-&gt;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-&gt;addresses != NULL)
/* Retrieve the mask of the first address of the interface */
netmask=((struct sockaddr_in *)(d-&gt;addresses-&gt;netmask))-&gt;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, &amp;fcode, "ip and tcp", 1, netmask) &lt; 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, &amp;fcode) &lt; 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 &#8220;Interpreting the packets&#8221;</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 &lt;pcap.h&gt;
#include &lt;Winsock2.h&gt;
#include &lt;tchar.h&gt;
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, &amp;alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* Print the list */
for(d=alldevs; d; d=d-&gt;next)
{
printf("%d. %s", ++i, d-&gt;name);
if (d-&gt;description)
printf(" (%s)\n", d-&gt;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", &amp;inum);
if(inum &lt; 1 || inum &gt; 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&lt; inum-1 ;d=d-&gt;next, i++);
/* Open the adapter */
if ( (adhandle= pcap_open(d-&gt;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-&gt;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-&gt;addresses != NULL)
/* Retrieve the mask of the first address of the interface */
netmask=((struct sockaddr_in *)(d-&gt;addresses-&gt;netmask))-&gt;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, &amp;fcode, packet_filter, 1, netmask) &lt;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, &amp;fcode)&lt;0)
{
fprintf(stderr,"\nError setting the filter.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
printf("\nlistening on %s...\n", d-&gt;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-&gt;ts.tv_sec;
localtime_s(&amp;ltime, &amp;local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", &amp;ltime);
/* print timestamp and length of the packet */
printf("%s.%.6d len:%d ", timestr, header-&gt;ts.tv_usec, header-&gt;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-&gt;ver_ihl &amp; 0xf) * 4;
uh = (udp_header *) ((u_char*)ih + ip_len);
/* convert from network byte order to host byte order */
sport = ntohs( uh-&gt;sport );
dport = ntohs( uh-&gt;dport );
/* print ip addresses and udp ports */
printf("%d.%d.%d.%d.%d -&gt; %d.%d.%d.%d.%d\n",
ih-&gt;saddr.byte1,
ih-&gt;saddr.byte2,
ih-&gt;saddr.byte3,
ih-&gt;saddr.byte4,
sport,
ih-&gt;daddr.byte1,
ih-&gt;daddr.byte2,
ih-&gt;daddr.byte3,
ih-&gt;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 -&gt; 130.192.3.21.53
16:13:15.314796 len:137 130.192.3.21.53 -&gt; 130.192.31.67.2682
16:13:15.322101 len:78 130.192.31.67.2683 -&gt; 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&#8212;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 &lt;pcap.h&gt;
#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, &amp;alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* Print the list */
for(d=alldevs; d; d=d-&gt;next)
{
printf("%d. %s", ++i, d-&gt;name);
if (d-&gt;description)
printf(" (%s)\n", d-&gt;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", &amp;inum);
if(inum &lt; 1 || inum &gt; 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&lt; inum-1 ;d=d-&gt;next, i++);
/* Open the device */
if ( (adhandle= pcap_open(d-&gt;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-&gt;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-&gt;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 &lt;stdio.h&gt;
#include &lt;pcap.h&gt;
#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-&gt;ts.tv_sec, header-&gt;ts.tv_usec, header-&gt;len);
/* Print the packet */
for (i=1; (i &lt; header-&gt;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 &lt;stdio.h&gt;
#include &lt;pcap.h&gt;
#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, &amp;header, &amp;pkt_data)) &gt;= 0)
{
/* print pkt timestamp and pkt len */
printf("%ld:%ld (%ld)\n", header-&gt;ts.tv_sec, header-&gt;ts.tv_usec, header-&gt;len);
/* Print the packet */
for (i=1; (i &lt; header-&gt;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 &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;pcap.h&gt;
#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&lt;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&#8212;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 &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;pcap.h&gt;
#ifdef WIN32
#include &lt;tchar.h&gt;
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 &lt;= 2 || argc &gt;= 5)
{
usage();
return;
}
/* Retrieve the length of the capture file */
fopen_error = fopen_s(&amp;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 &amp;&amp; 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, &amp;pktheader, &amp;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)) &lt; squeue-&gt;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 &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;pcap.h&gt;
#include &lt;tchar.h&gt;
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, &amp;fcode, "tcp", 1, netmask) &lt;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, &amp;fcode)&lt;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)&lt;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)&amp;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-&gt;ts.tv_sec - old_ts-&gt;tv_sec) * 1000000 - old_ts-&gt;tv_usec + header-&gt;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-&gt;ts.tv_sec;
localtime_s(&amp;ltime, &amp;local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", &amp;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-&gt;tv_sec=header-&gt;ts.tv_sec;
old_ts-&gt;tv_usec=header-&gt;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>