-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathtutorial_live_capture.html
410 lines (379 loc) · 29.8 KB
/
tutorial_live_capture.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
---
title: Tutorials
layout: default
section: tutorials
redirect_to: https://pcapplusplus.github.io/docs/tutorials/capture-packets
---
<h1><a href="tutorials.html">Tutorials</a></h1>
<h2>Part 3: Capturing and sending packets</h2>
<p>This part explains how to capture packets from a live network interface and how to send packets from it</p>
<p>Table of contents:</p>
<ul>
<li><a href="tutorial_intro.html">Part 1: Introduction and basics</a></li>
<li><a href="tutorial_pcap_files.html">Part 2: Reading and writing pcap files</a></li>
<li>Part 3: Capturing and sending packets
<ol>
<li><a href="#intro">Introduction</a></li>
<li><a href="#pcaplivedevice">PcapLiveDevice and WinPcapLiveDevice instances</a></li>
<li><a href="#capture_packets">Capturing packets</a></li>
<li><a href="#send_packets">Sending packets</a></li>
<li><a href="#filtering">Filtering packets</a></li>
<li><a href="#run_example">Running the example</a></li>
</ol>
</li>
<li><a href="tutorial_packet_parsing.html">Part 4: Packet parsing</a></li>
<li><a href="tutorial_packet_craft_n_edit.html">Part 5: Packet crafting and editing</a></li>
<li><a href="tutorial_dpdk.html">Part 6: Working with DPDK</a></li>
</ul>
<h2 id="intro">Introduction</h2>
<p>PcapPlusPlus provides simple and easy-to-use wrappers for libpcap/WinPcap APIs for capturing and sending packets over network interfaces. These wrappers pretty much sum up in the following classes:</p>
<ul>
<li><strong>PcapLiveDevice</strong> - wraps libpcap functionality of capturing and sending packets and also provide information and statistics on the network interface</li>
<li><strong>WinPcapLiveDevice</strong> - wraps WinPcap functionality which is basically similar to libpcap but provides adjustments for Windows OS. This class inherits PcapLiveDevice and provides the necessary changes for Windows vs. Linux/MacOS</li>
<li><strong>PcapLiveDeviceList</strong> - A singleton class that creates, stores and provides access to all PcapLiveDevice or WinPcapLiveDevice instances. These instances are initialized on startup and wrap all the network interfaces installed on the machine</li>
<li><strong>PcapRemoteDevice</strong> - wraps WinPcap functionality for <a href="https://www.winpcap.org/docs/docs_412/html/group__remote.html">remote packet capture</a>. As this functionality is less common and less used, it won't be covered in this tutorial. You can take a look at PcapPlusPlus documentation for a comprehensive overview and API description</li>
<li><strong></strong></li>
</ul>
<p>In this tutorial we'll write a simple application that demonstrates how to capture and send packet over the network.</p>
<h2 id="pcaplivedevice">PcapLiveDevice and WinPcapLiveDevice instances</h2>
<p>Let's start out application with a "main" method and a single include to "PcapLiveDeviceList.h". This header file contains another include to "PcapLiveDevice.h" and those 2 files contain all the APIs for capturing and sending packets:</p>
<pre><code class="language-cpp">#include "stdlib.h"
#include "PcapLiveDeviceList.h"
/**
* main method of the application
*/
int main(int argc, char* argv[])
{
// write your code here
}</code>
</pre>
<p>The next step would be to find the <code class="language-cpp">PcapLiveDevice</code> or <code class="language-cpp">WinPcapLiveDevice</code> instance which represents the network interface we'd like to use. We can use the <code class="language-cpp">PcapLiveDeviceList</code> singleton for retrieving an interface by IPv4 address or by name. We'll use the retrieve-by-IP method (here I use IP address of "10.0.0.1". Of course you should change that to the IP address of your network interface):</p>
<pre><code class="language-cpp">// IPv4 address of the interface we want to sniff
std::string interfaceIPAddr = "10.0.0.1";
// find the interface by IP address
pcpp::PcapLiveDevice* dev = pcpp::PcapLiveDeviceList::getInstance().getPcapLiveDeviceByIp(interfaceIPAddr.c_str());
if (dev == NULL)
{
printf("Cannot find interface with IPv4 address of '%s'\n", interfaceIPAddr.c_str());
exit(1);
}</code>
</pre>
<p>Now we have an instance of <code class="language-cpp">PcapLiveDevice</code> or <code class="language-cpp">WinPcapLiveDevice</code> we can use. You may wonder who decides whether to return this type or the other and where does <code class="language-cpp">WinPcapLiveDevice</code> fits in. Well, <code class="language-cpp">WinPcapLiveDevice</code> actually inherits <code class="language-cpp">PcapLiveDevice</code> and the <code class="language-cpp">PcapLiveDeviceList</code> singleton creates the relevant type of instances according to the operating system the application is running on. So <code class="language-cpp">pcpp::PcapLiveDevice* dev</code> can be either of type <code class="language-cpp">PcapLiveDevice</code> or <code class="language-cpp">WinPcapLiveDevice</code>, but the API of the two is the same so we shouldn't really care.</p>
<p>Before actually capturing packets let's demonstrate some more cool features this instance enables like presenting information about the network interface. There's a bunch of information PcapPlusPlus exposes on the interface. Some of it already exists in libpcap/WinPcap and is only wrapped by the <code class="language-cpp">PcapLiveDevice</code> class, but some of it doesn't exist in libpcap/WinPcap and is collected by querying the various OS's APIs.</p>
<p>The next lines of code demonstrate how to get the following information:</p>
<ul>
<li>Interface name (e.g "eth0" in Linux)</li>
<li>Interface description (where exposed by the OS)</li>
<li>Interface MAC address</li>
<li>Interface default gateway</li>
<li>Interface maximum transmission unit (MTU)</li>
<li>The DNS server associated with this interface</li>
</ul>
<pre><code class="language-cpp">// before capturing packets let's print some info about this interface
printf("Interface info:\n");
// get interface name
printf(" Interface name: %s\n", dev->getName());
// get interface description
printf(" Interface description: %s\n", dev->getDesc());
// get interface MAC address
printf(" MAC address: %s\n", dev->getMacAddress().toString().c_str());
// get default gateway for interface
printf(" Default gateway: %s\n", dev->getDefaultGateway().toString().c_str());
// get interface MTU
printf(" Interface MTU: %d\n", dev->getMtu());
// get DNS server if defined for this interface
if (dev->getDnsServers().size() > 0)
printf(" DNS server: %s\n", dev->getDnsServers().at(0).toString().c_str());</code>
</pre>
<h2 id="capture_packets">Capturing packets</h2>
<p>Now let's move on to capturing packets. Before start capturing we must first open the device:</p>
<pre><code class="language-cpp">// open the device before start capturing/sending packets
if (!dev->open())
{
printf("Cannot open device\n");
exit(1);
}</code>
</pre>
<p>For the sake of this demo we'll create a struct that collects statistics on captured packets. It examines every packet and counts number of Ethernet, IPv4, IPv6, TCP, UDP, DNS, HTTP and SSL packets we have seen during the capture.</p>
<pre><code class="language-cpp">/**
* A struct for collecting packet statistics
*/
struct PacketStats
{
int ethPacketCount;
int ipv4PacketCount;
int ipv6PacketCount;
int tcpPacketCount;
int udpPacketCount;
int dnsPacketCount;
int httpPacketCount;
int sslPacketCount;
/**
* Clear all stats
*/
void clear() { ethPacketCount = 0; ipv4PacketCount = 0; ipv6PacketCount = 0; tcpPacketCount = 0; udpPacketCount = 0; tcpPacketCount = 0; dnsPacketCount = 0; httpPacketCount = 0; sslPacketCount = 0; }
/**
* C'tor
*/
PacketStats() { clear(); }
/**
* Collect stats from a packet
*/
void consumePacket(pcpp::Packet& packet)
{
if (packet.isPacketOfType(pcpp::Ethernet))
ethPacketCount++;
if (packet.isPacketOfType(pcpp::IPv4))
ipv4PacketCount++;
if (packet.isPacketOfType(pcpp::IPv6))
ipv6PacketCount++;
if (packet.isPacketOfType(pcpp::TCP))
tcpPacketCount++;
if (packet.isPacketOfType(pcpp::UDP))
udpPacketCount++;
if (packet.isPacketOfType(pcpp::HTTP))
httpPacketCount++;
if (packet.isPacketOfType(pcpp::SSL))
sslPacketCount++;
}
/**
* Print stats to console
*/
void printToConsole()
{
printf("Ethernet packet count: %d\n", ethPacketCount);
printf("IPv4 packet count: %d\n", ipv4PacketCount);
printf("IPv6 packet count: %d\n", ipv6PacketCount);
printf("TCP packet count: %d\n", tcpPacketCount);
printf("UDP packet count: %d\n", udpPacketCount);
printf("DNS packet count: %d\n", dnsPacketCount);
printf("HTTP packet count: %d\n", httpPacketCount);
printf("SSL packet count: %d\n", sslPacketCount);
}
};</code>
</pre>
<p>Let's create an instance of this struct:</p>
<pre><code class="language-cpp">// create the stats object
PacketStats stats;</code>
</pre>
<p>We'll demonstrate the 3 types of packet capturing options currently available in PcapPlusPlus:</p>
<ul>
<li>Asynchronous packet capture using a callback function</li>
<li>Asynchronous packet capture using a packet list (vector)</li>
<li>Synchronous (blocking) packet capture using a callback function</li>
</ul>
<h4>Asynchronous packet capture using a callback function</h4>
<p>The first way we'll demonstrate is capturing packets asynchronously, meaning the packet capture is happening on a different thread created by PcapPlusPlus. Whenever a packet is captured a callback function provided by the user is invoked, and the context where this callback is running is the packet capture thread (not the main thread). For showing that let's first create our callback function. The callback function header complies to the <code class="language-cpp">OnPacketArrivesCallback</code> typedef defined in "PcapLiveDevice.h". Its parameters will be a pointer to the packet currently captured, a pointer to the interface instance doing this capture and a pointer to an object supplied by the user at the beginning of the packet capture (a cookie). Why do we need this cookie? in order to pass objects (or data) between our main code and the callback running in a static context-less environment. The cookie is a way of providing a context to our callback function. In our case this context will be an instance of the statistics collector we just defined: <code class="language-cpp">PacketStats</code></p>
<pre><code class="language-cpp">/**
* A callback function for the async capture which is called each time a packet is captured
*/
static void onPacketArrives(pcpp::RawPacket* packet, pcpp::PcapLiveDevice* dev, void* cookie)
{
// extract the stats object form the cookie
PacketStats* stats = (PacketStats*)cookie;
// parsed the raw packet
pcpp::Packet parsedPacket(packet);
// collect stats from packet
stats->consumePacket(parsedPacket);
}</code>
</pre>
<p>As you can see this callback is doing something pretty simple: cast the cookie as <code class="language-cpp">PacketStats*</code>, parse the raw packet as parsed packet, and feed it to the <code class="language-cpp">PacketStats</code> instance to collect information about the protocols used in this packet</p>
<p>Now let's activate the packet capture and pass it a pointer to the callback and a pointer to the <code class="language-cpp">PacketStats</code> instance we created:</p>
<pre><code class="language-cpp">printf("\nStarting async capture...\n");
// start capture in async mode. Give a callback function to call to whenever a packet is captured and the stats object as the cookie
dev->startCapture(onPacketArrives, &stats);</code>
</pre>
<p>Please remember the packet capture is happening in a different thread so code written from now on in our main thread will work in parallel. For the sake of this demo let's choose not to do anything and wait (sleep) for 10 seconds and then stop the capture. Since there is no one "sleep" method compatible for all operating systems PcapPlusPlus provides a macro called <code class="language-cpp">PCAP_SLEEP</code> which runs the right "sleep" method according to the operating system the application is currently running on. For using this macro we need to add an include phrase to "PlatformSpecificUtils.h" in Common++:</p>
<pre><code class="language-cpp">#include "PlatformSpecificUtils.h"</code></pre>
<p>Now let's write the code that sleeps for 10 seconds and then stops the packet capture:</p>
<pre><code class="language-cpp">// sleep for 10 seconds in main thread, in the meantime packets are captured in the async thread
PCAP_SLEEP(10);
// stop capturing packets
dev->stopCapture();</code>
</pre>
<p>In the meantime, while the main thread was sleeping, packets were (hopefully) captured by the packet capture thread and information was collected in the <code class="language-cpp">PacketStats</code> instance. So let's print the results:</p>
<pre><code class="language-cpp">// print results
printf("Results:\n");
stats.printToConsole();</code>
</pre>
<p>Here is an output example I got in a specific run of this code:</p>
<pre><code class="language-shell">Starting async capture...
Results:
Ethernet packet count: 2346
IPv4 packet count: 2346
IPv6 packet count: 0
TCP packet count: 2203
UDP packet count: 143
DNS packet count: 0
HTTP packet count: 87
SSL packet count: 342</code>
</pre>
<h4>Asynchronous packet capture using a packet list (vector)</h4>
<p>Now let's see a different way to capture packet in PcapPlusPlus. Here instead of using a callback function, we'll supply PcapPlusPlus an instance of raw packet pointer list and the capture thread will fill it with pointers to captured packets. In this capturing method the capture is still asynchronous, meaning it happens on a different thread created by PcapPlusPlus, but there is no callback function involved. The advantage here is that you can use the packets that were captured in the main thread.</p>
<p>PcapPlusPlus provides a class for representing a list of raw packet pointers. It's called <code class="language-cpp">RawPacketVector</code>. This class actually wraps <code class="language-cpp">std::vector</code> and add some more functionality such as freeing the raw packet instances inside the list when the list memory is freed.</p>
<p>So let's create an instance of <code class="language-cpp">RawPacketVector</code> and start the packet capture:</p>
<pre><code class="language-cpp">printf("\nStarting capture with packet vector...\n");
// create an empty packet vector object
pcpp::RawPacketVector packetVec;
// start capturing packets. All packets will be added to the packet vector
dev->startCapture(packetVec);</code>
</pre>
<p>As we said the packet capture happens in another thread so like in the previous example let's sleep for 10 seconds in the main thread and then stop the capture:</p>
<pre><code class="language-cpp">// sleep for 10 seconds in main thread, in the meantime packets are captured in the async thread
PCAP_SLEEP(10);
// stop capturing packets
dev->stopCapture();</code>
</pre>
<p>Now the raw packet list is (hopefully) filled with packets that were captured. Let's go over all packets and feed them to our stats collector (let's first clear the stats collector from its previous run). Note this code is running on the main thread and it's an example of how to access the packets in the main thread after they were captured. For going over the packets we'll use an iterator provided in the <code class="language-cpp">RawPacketVector</code> class:</p>
<pre><code class="language-cpp">// go over the packet vector and feed all packets to the stats object
for (pcpp::RawPacketVector::ConstVectorIterator iter = packetVec.begin(); iter != packetVec.end(); iter++)
{
// parse raw packet
pcpp::Packet parsedPacket(*iter);
// feed packet to the stats object
stats.consumePacket(parsedPacket);
}</code>
</pre>
<p>Now let's print the results:</p>
<pre><code class="language-cpp">// print results
printf("Results:\n");
stats.printToConsole();</code>
</pre>
<p>Here is an output example I got in a specific run of this code:</p>
<pre><code class="language-shell">Starting capture with packet vector...
Results:
Ethernet packet count: 4064
IPv4 packet count: 4058
IPv6 packet count: 6
TCP packet count: 3939
UDP packet count: 121
DNS packet count: 0
HTTP packet count: 127
SSL packet count: 188</code>
</pre>
<h4>Synchronous (blocking) packet capture using a callback function</h4>
<p>The last way we'll demonstrate to capture packets is a synchronous way where the main thread is blocked during the packet capture and released only when the user instructs or after a timeout pre-defined by the user. In this case there is no separate thread created for the packet capture and everything is happening on the main thread. This method requires a callback of type <code class="language-cpp">OnPacketArrivesStopBlocking</code> to be defined by the user. Let's first define this callback:</p>
<pre><code class="language-cpp">/**
* a callback function for the blocking mode capture which is called each time a packet is captured
*/
static bool onPacketArrivesBlockingMode(pcpp::RawPacket* packet, pcpp::PcapLiveDevice* dev, void* cookie)
{
// extract the stats object form the cookie
PacketStats* stats = (PacketStats*)cookie;
// parsed the raw packet
pcpp::Packet parsedPacket(packet);
// collect stats from packet
stats->consumePacket(parsedPacket);
// return false means we don't want to stop capturing after this callback
return false;
}</code>
</pre>
<p>As you can see the callback accepts several parameters: a pointer to the packet currently captured, a pointer to the interface instance doing this capture and a pointer to an object supplied by the user at the beginning of the packet capture (a cookie). Until now everything seems similar to the <code class="language-cpp">OnPacketArrivesCallback</code> callback we demonstrated previously. But there is one important difference: the returning value. In <code class="language-cpp">OnPacketArrivesCallback</code> there is no return value but in <code class="language-cpp">OnPacketArrivesStopBlocking</code> the return value is boolean. This boolean return value allows the user who writes the callback to stop the synchronous packet capture any time, by returning a "true" value. As long as the return value is "false" the packet capture will continue until the timeout expires (we'll get to that soon), but if "true" is returned the capture will stop immediately. In our example we choose to always return "false" but you're welcome to try returning "true" and see that it's working. Besides returning "false" the callback is doing the same as the previous callback: cast the cookie as <code class="language-cpp">PacketStats*</code>, parse the raw packet as parsed packet, and feed it to the <code class="language-cpp">PacketStats</code> instance to collect information about the protocols used in this packet</p>
<p>Now let's start the packet capture. Here, of course, we don't need to sleep as everything is happening on the main thread. But we do want to stop the capture at some point (please remember we always return "false" in the callback so that won't stop the capturing). Here is where the timeout feature comes in hand: when starting the packet capture you can provide a timeout of when to stop the packet capture (if not previously stopped by returning "true" from the callback function). If you provide a timeout of 0 or less it's like saying there is no timeout and the capture will continue until a "true" value is returned from the callback. The timeout unit is in seconds</p>
<pre><code class="language-cpp">printf("\nStarting capture in blocking mode...\n");
// clear stats
stats.clear();
// start capturing in blocking mode. Give a callback function to call to whenever a packet is captured, the stats object as the cookie and a 10 seconds timeout
dev->startCaptureBlockingMode(onPacketArrivesBlockingMode, &stats, 10);
// thread is blocked until capture is finished
// capture is finished, print results
printf("Results:\n");
stats.printToConsole();</code>
</pre>
<p>Please notice we don't need to activate <code class="language-cpp">dev->stopCapture()</code> here</p>
<p>Here is an output example I got in a specific run of this code:</p>
<pre><code>Starting capture in blocking mode...
Results:
Ethernet packet count: 1266
IPv4 packet count: 1263
IPv6 packet count: 3
TCP packet count: 1115
UDP packet count: 147
DNS packet count: 0
HTTP packet count: 36
SSL packet count: 251</code>
</pre>
<h2 id="send_packets">Sending packets</h2>
<p>Until now we saw the different methods of capturing packets. But <code class="language-cpp">PcapLiveDevice</code> or <code class="language-cpp">WinPcapLiveDevice</code> also provide APIs for sending packets to the network. The APIs are rather straight forward and enable sending one packet or multiple packets in a batch, and also enable to send raw packets (of type <code class="language-cpp">RawPacket</code>) or parsed packets (of type <code class="language-cpp">Packet</code>). We won't go over all of the methods, we'll demonstrate some of them. The rest should be quite easy to understand.</p>
<p>Let's start with sending one raw packet. In this example we'll use the raw packet vector we collected from the packet capture in the previous section, iterate on it and send each packet to the network one by one. Let's look at the code first:</p>
<pre><code class="language-cpp">printf("\nSending %d packets one by one...\n", (int)packetVec.size());
// go over the vector of packets and send them one by one
for (pcpp::RawPacketVector::ConstVectorIterator iter = packetVec.begin(); iter != packetVec.end(); iter++)
{
// send the packet. If fails exit the application
if (!dev->sendPacket(**iter))
{
printf("Couldn't send packet\n");
exit(1);
}
}
printf("%d packets sent\n", (int)packetVec.size());</code>
</pre>
<p>As you can see we send each packet using the <code class="language-cpp">dev->sendPacket()</code> method. Notice the return value is a boolean saying whether the packet was sent successfully or not.</p>
<p>Now let's demonstrate sending a bunch of packets. Here we'll only demonstrate sending a raw packet list (<code class="language-cpp">RawPacketVector</code>). Let's see the code:</p>
<pre><code class="language-cpp">printf("\nSending %d packets...\n", (int)packetVec.size());
// send all packets in the vector. The returned number shows how many packets were actually sent (expected to be equal to vector size)
int packetsSent = dev->sendPackets(packetVec);
printf("%d packets sent\n", packetsSent);</code>
</pre>
<p>As you can see we're using the same raw packet list from the previous section. The return value is how many packets were sent successfully.</p>
<h2 id="filtering">Filtering packets</h2>
<p>Now let's learn how to use the packet filtering mechanism provided by PcapPlusPlus. Basically libpcap and WinPcap support the <a href="https://en.wikipedia.org/wiki/Berkeley_Packet_Filter">BPF (Berkeley Packet Filter)</a> format for setting a filter on an interface. When setting a filter only packets that match the filter will be passed to the user, all the other packets will be ignored by the capturing mechanism. The BPF format is great and widely used but for my opinion is too complicated and not easy to understand. In addition it's a string-based format and I don't know any C++ API that wraps it in an organized C++ class structure. That's why I developed one, quite simple and not covering all of the BPF options, but is sufficient for most use-cases (I think). In this section we'll learn how to use it and give a small example (the rest can be read in PcapPlusPlus API documentation)</p>
<p>As already mentioned, the filtering mechanism is actually an hierarchy of classes representing different kinds of filters, for example: IPv4 filters (<code class="language-cpp">IPFilter</code>), TCP/UDP Port filters (<code class="language-cpp">PortFilter</code>), MAC address filters (<code class="language-cpp">MacAddressFilter</code>), VLAN filters (<code class="language-cpp">VlanFilter</code>), protocol filter (<code class="language-cpp">ProtoFilter</code>), etc. but also composite operators like "and" (<code class="language-cpp">AndFilter</code>), "or" (<code class="language-cpp">OrFilter</code>) and "not" (<code class="language-cpp">NotFilter</code>). The root class for all of them is <code class="language-cpp">GeneralFilter</code>. Each class exposes a simple API (usually in the constructor) for setting the filter values. For example: in IPv4 filter (<code class="language-cpp">IPFilter</code>) the user should provide in the constructor what is the IPv4 address to set as a filter and also in which direction to look for this address (source address, destination address or both):</p>
<pre><code class="language-cpp">IPFilter(const std::string& ipAddress, Direction dir)</code></pre>
<p>We'll not go over all the filter classes but we'll do a quick demonstration of how to construct a complex filter and set it to a <code class="language-cpp">PcapLiveDevice</code> instance. Filters can be also applied to other devices that support it such as pcap and pcap-ng files (<code class="language-cpp">PcapFileReaderDevice</code> and <code class="language-cpp">PcapNgFileReaderDevice</code>).</p>
<p>Let's start with building the filter. The filter we'd like to build is: "capture only TCP packets which their source or destination port is 80" (which are basically HTTP packets). Let's see the code for doing that:</p>
<pre><code class="language-cpp">// create a filter instance to capture only traffic on port 80
pcpp::PortFilter portFilter(80, pcpp::SRC_OR_DST);
// create a filter instance to capture only TCP traffic
pcpp::ProtoFilter protocolFilter(pcpp::TCP);
// create an AND filter to combine both filters - capture only TCP traffic on port 80
pcpp::AndFilter andFilter;
andFilter.addFilter(&portFilter);
andFilter.addFilter(&protocolFilter);</code>
</pre>
<p>As you can see we created 3 filter instances:</p>
<ul>
<li><code class="language-cpp">PortFilter</code> - in the constructor we gave it the port we'd like to filter on (80) and instructed it to search on both source and destnation port of each packet</li>
<li><code class="language-cpp">ProtoFilter</code> - in the constructor we told it to filter only TCP packets</li>
<li><code class="language-cpp">AndFilter</code> - this filter is to combine the port and protocol filters. So we created it and provided it pointers to the port and protocol filters we previously created</li>
</ul>
<p>That's it, our filter is ready. Now let's set this filter in the <code class="language-cpp">PcapLiveDevice</code> we have from the previous sections:</p>
<pre><code class="language-cpp">// set the filter on the device
dev->setFilter(andFilter);</code>
</pre>
<p>Now let's write some code to capture packets from the network and print the results (we use the same asynchronous capturing using a callback function method learnt in the previous sections):</p>
<pre><code class="language-cpp">printf("\nStarting packet capture with a filter in place...\n");
// start capture in async mode. Give a callback function to call to whenever a packet is captured and the stats object as the cookie
dev->startCapture(onPacketArrives, &stats);
// sleep for 10 seconds in main thread, in the meantime packets are captured in the async thread
PCAP_SLEEP(10);
// stop capturing packets
dev->stopCapture();
// print results - should capture only packets which match the filter (which is TCP port 80)
printf("Results:\n");
stats.printToConsole();</code>
</pre>
<p>Here is an output example I got after running this code:</p>
<pre><code class="language-shell">Starting packet capture with a filter in place...
Results:
Ethernet packet count: 703
IPv4 packet count: 703
IPv6 packet count: 0
TCP packet count: 703
UDP packet count: 0
DNS packet count: 0
HTTP packet count: 58
SSL packet count: 0</code>
</pre>
<p>As you can see the filter worked as there are no UDP, SSL or DNS packets, although I made sure there was UDP/DNS/SSL traffic running on my machine at the time of the capture. It was simply filtered by the capturing device</p>
<h2 id="run_example">Running the example</h2>
<p>All code that was covered in this tutorial can be found <a href="https://github.com/seladb/PcapPlusPlus/tree/master/Examples/Tutorials/Tutorial-LiveTraffic">here</a>. In order to compile and run the code please first download and compile PcapPlusPlus code or downloaded a pre-compiled version from <a href="https://github.com/seladb/PcapPlusPlus/releases/latest">the latest PcapPlusPlus release</a>. Then follow these instruction, according to your platform:</p>
<ul>
<li>Linux and MacOS - make sure PcapPlusPlus is installed (by running <strong>sudo make install</strong> in PcapPlusPlus main directory). Then either change the <code class="language-shell">Makefile.non_windows</code> file name to <code class="language-shell">Makefile</code> and run <code class="language-shell">make all</code>, or run <code class="language-shell">make -f Makefile.non_windows all</code></li>
<li>Windows using MinGW or MinGW-w64 - either change the <code class="language-shell">Makefile.windows</code> file name to <code class="language-shell">Makefile</code> and run <code class="language-shell">make all</code>, or run <code class="language-shell">make -f Makefile.windows all</code></li>
<li>Windows using Visual Studio 2015 - there is a Visual Studio 2015 solution containing all tutorials <a href="https://github.com/seladb/PcapPlusPlus/tree/master/mk/vs2015/Tutorials.sln">here</a>. Just open it and compile all tutorials</li>
</ul>
<p>In all options the compiled executable will be inside the tutorial directory (<code class="language-shell">[PcapPlusPlus Folder]/Examples/Tutorials/Tutorial-LiveTraffic</code>)</p>
<script>function topFunction() { document.body.scrollTop = 0; document.documentElement.scrollTop = 0; }</script>
<p><a onclick="topFunction()" href="#">Go to top ↑</a></p>