blob: 6fa52e6ece6954a4dad58ee8afa19aa51dd8f3e4 [file] [log] [blame]
Elliott Hughes965a4b52017-05-15 10:37:39 -07001/*
2 * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California)
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino, CACE Technologies
16 * nor the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#ifdef HAVE_CONFIG_H
Haibo Huang165065a2018-07-23 17:26:52 -070035#include <config.h>
Elliott Hughes965a4b52017-05-15 10:37:39 -070036#endif
37
Haibo Huang165065a2018-07-23 17:26:52 -070038/*
39 * sockutils.h may include <crtdbg.h> on Windows, and pcap-int.h will
40 * include portability.h, and portability.h, on Windows, expects that
41 * <crtdbg.h> has already been included, so include sockutils.h first.
42 */
43#include "sockutils.h"
Elliott Hughes965a4b52017-05-15 10:37:39 -070044#include "pcap-int.h" // for the details of the pcap_t structure
45#include "pcap-rpcap.h"
Haibo Huang165065a2018-07-23 17:26:52 -070046#include "rpcap-protocol.h"
Elliott Hughes965a4b52017-05-15 10:37:39 -070047#include <errno.h> // for the errno variable
48#include <stdlib.h> // for malloc(), free(), ...
49#include <string.h> // for strstr, etc
50
Haibo Huang165065a2018-07-23 17:26:52 -070051#ifndef _WIN32
Elliott Hughes965a4b52017-05-15 10:37:39 -070052#include <dirent.h> // for readdir
53#endif
54
Elliott Hughes965a4b52017-05-15 10:37:39 -070055/* String identifier to be used in the pcap_findalldevs_ex() */
56#define PCAP_TEXT_SOURCE_FILE "File"
57/* String identifier to be used in the pcap_findalldevs_ex() */
58#define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
59
60/* String identifier to be used in the pcap_findalldevs_ex() */
61#define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
Elliott Hughes965a4b52017-05-15 10:37:39 -070062
63/****************************************************
64 * *
65 * Function bodies *
66 * *
67 ****************************************************/
68
69int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
70{
Elliott Hughes965a4b52017-05-15 10:37:39 -070071 int type;
Haibo Huang165065a2018-07-23 17:26:52 -070072 char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
Elliott Hughes965a4b52017-05-15 10:37:39 -070073 pcap_t *fp;
74 char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
Haibo Huang165065a2018-07-23 17:26:52 -070075 pcap_if_t *lastdev; /* Last device in the pcap_if_t list */
76 pcap_if_t *dev; /* Device we're adding to the pcap_if_t list */
Elliott Hughes965a4b52017-05-15 10:37:39 -070077
Haibo Huang165065a2018-07-23 17:26:52 -070078 /* List starts out empty. */
79 (*alldevs) = NULL;
80 lastdev = NULL;
Elliott Hughes965a4b52017-05-15 10:37:39 -070081
82 if (strlen(source) > PCAP_BUF_SIZE)
83 {
84 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
85 return -1;
86 }
87
88 /*
89 * Determine the type of the source (file, local, remote)
90 * There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters.
91 * In the first case, the name of the directory we have to look into must be present (therefore
92 * the 'name' parameter of the pcap_parsesrcstr() is present).
93 * In the second case, the name of the adapter is not required (we need just the host). So, we have
94 * to use a first time this function to get the source type, and a second time to get the appropriate
95 * info, which depends on the source type.
96 */
97 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
98 return -1;
99
Haibo Huang165065a2018-07-23 17:26:52 -0700100 switch (type)
Elliott Hughes965a4b52017-05-15 10:37:39 -0700101 {
Haibo Huang165065a2018-07-23 17:26:52 -0700102 case PCAP_SRC_IFLOCAL:
103 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
Elliott Hughes965a4b52017-05-15 10:37:39 -0700104 return -1;
105
106 /* Initialize temporary string */
107 tmpstring[PCAP_BUF_SIZE] = 0;
108
109 /* The user wants to retrieve adapters from a local host */
110 if (pcap_findalldevs(alldevs, errbuf) == -1)
111 return -1;
112
Haibo Huang165065a2018-07-23 17:26:52 -0700113 if (*alldevs == NULL)
Elliott Hughes965a4b52017-05-15 10:37:39 -0700114 {
115 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
116 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
117 " on the local machine.");
118 return -1;
119 }
120
121 /* Scan all the interfaces and modify name and description */
122 /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */
123 dev = *alldevs;
124 while (dev)
125 {
126 /* Create the new device identifier */
127 if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
128 return -1;
129
130 /* Delete the old pointer */
131 free(dev->name);
132
133 /* Make a copy of the new device identifier */
134 dev->name = strdup(tmpstring);
135 if (dev->name == NULL)
136 {
Haibo Huang165065a2018-07-23 17:26:52 -0700137 pcap_fmt_errmsg_for_errno(errbuf,
138 PCAP_ERRBUF_SIZE, errno,
139 "malloc() failed");
140 pcap_freealldevs(*alldevs);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700141 return -1;
142 }
143
144 /* Create the new device description */
145 if ((dev->description == NULL) || (dev->description[0] == 0))
146 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER,
147 dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
148 else
149 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER,
150 dev->description, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
151
152 /* Delete the old pointer */
153 free(dev->description);
154
155 /* Make a copy of the description */
156 dev->description = strdup(tmpstring);
157 if (dev->description == NULL)
158 {
Haibo Huang165065a2018-07-23 17:26:52 -0700159 pcap_fmt_errmsg_for_errno(errbuf,
160 PCAP_ERRBUF_SIZE, errno,
161 "malloc() failed");
162 pcap_freealldevs(*alldevs);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700163 return -1;
164 }
165
166 dev = dev->next;
167 }
168
169 return 0;
Elliott Hughes965a4b52017-05-15 10:37:39 -0700170
Haibo Huang165065a2018-07-23 17:26:52 -0700171 case PCAP_SRC_FILE:
Elliott Hughes965a4b52017-05-15 10:37:39 -0700172 {
173 size_t stringlen;
Haibo Huang165065a2018-07-23 17:26:52 -0700174#ifdef _WIN32
Elliott Hughes965a4b52017-05-15 10:37:39 -0700175 WIN32_FIND_DATA filedata;
176 HANDLE filehandle;
177#else
178 struct dirent *filedata;
179 DIR *unixdir;
180#endif
181
Haibo Huang165065a2018-07-23 17:26:52 -0700182 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
Elliott Hughes965a4b52017-05-15 10:37:39 -0700183 return -1;
184
185 /* Check that the filename is correct */
186 stringlen = strlen(name);
187
188 /* The directory must end with '\' in Win32 and '/' in UNIX */
Haibo Huang165065a2018-07-23 17:26:52 -0700189#ifdef _WIN32
Elliott Hughes965a4b52017-05-15 10:37:39 -0700190#define ENDING_CHAR '\\'
191#else
192#define ENDING_CHAR '/'
193#endif
194
195 if (name[stringlen - 1] != ENDING_CHAR)
196 {
197 name[stringlen] = ENDING_CHAR;
198 name[stringlen + 1] = 0;
199
200 stringlen++;
201 }
202
203 /* Save the path for future reference */
204 pcap_snprintf(path, sizeof(path), "%s", name);
205
Haibo Huang165065a2018-07-23 17:26:52 -0700206#ifdef _WIN32
Elliott Hughes965a4b52017-05-15 10:37:39 -0700207 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */
208 if (name[stringlen - 1] != '*')
209 {
210 name[stringlen] = '*';
211 name[stringlen + 1] = 0;
212 }
213
214 filehandle = FindFirstFile(name, &filedata);
215
216 if (filehandle == INVALID_HANDLE_VALUE)
217 {
218 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
219 return -1;
220 }
221
222#else
223 /* opening the folder */
224 unixdir= opendir(path);
225
226 /* get the first file into it */
227 filedata= readdir(unixdir);
228
229 if (filedata == NULL)
230 {
231 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
232 return -1;
233 }
234#endif
235
Haibo Huang165065a2018-07-23 17:26:52 -0700236 /* Add all files we find to the list. */
Elliott Hughes965a4b52017-05-15 10:37:39 -0700237 do
238 {
239
Haibo Huang165065a2018-07-23 17:26:52 -0700240#ifdef _WIN32
Elliott Hughes965a4b52017-05-15 10:37:39 -0700241 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
242#else
243 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
244#endif
245
246 fp = pcap_open_offline(filename, errbuf);
247
248 if (fp)
249 {
250 /* allocate the main structure */
Haibo Huang165065a2018-07-23 17:26:52 -0700251 dev = (pcap_if_t *)malloc(sizeof(pcap_if_t));
Elliott Hughes965a4b52017-05-15 10:37:39 -0700252 if (dev == NULL)
253 {
Haibo Huang165065a2018-07-23 17:26:52 -0700254 pcap_fmt_errmsg_for_errno(errbuf,
255 PCAP_ERRBUF_SIZE, errno,
256 "malloc() failed");
257 pcap_freealldevs(*alldevs);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700258 return -1;
259 }
260
261 /* Initialize the structure to 'zero' */
262 memset(dev, 0, sizeof(pcap_if_t));
263
Haibo Huang165065a2018-07-23 17:26:52 -0700264 /* Append it to the list. */
265 if (lastdev == NULL)
266 {
267 /*
268 * List is empty, so it's also
269 * the first device.
270 */
271 *alldevs = dev;
272 }
273 else
274 {
275 /*
276 * Append after the last device.
277 */
278 lastdev->next = dev;
279 }
280 /* It's now the last device. */
281 lastdev = dev;
282
Elliott Hughes965a4b52017-05-15 10:37:39 -0700283 /* Create the new source identifier */
284 if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1)
Haibo Huang165065a2018-07-23 17:26:52 -0700285 {
286 pcap_freealldevs(*alldevs);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700287 return -1;
Haibo Huang165065a2018-07-23 17:26:52 -0700288 }
Elliott Hughes965a4b52017-05-15 10:37:39 -0700289
290 stringlen = strlen(tmpstring);
291
292 dev->name = (char *)malloc(stringlen + 1);
293 if (dev->name == NULL)
294 {
Haibo Huang165065a2018-07-23 17:26:52 -0700295 pcap_fmt_errmsg_for_errno(errbuf,
296 PCAP_ERRBUF_SIZE, errno,
297 "malloc() failed");
298 pcap_freealldevs(*alldevs);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700299 return -1;
300 }
301
302 strlcpy(dev->name, tmpstring, stringlen);
303
304 dev->name[stringlen] = 0;
305
306 /* Create the description */
307 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_FILE,
308 filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
309
310 stringlen = strlen(tmpstring);
311
312 dev->description = (char *)malloc(stringlen + 1);
313
314 if (dev->description == NULL)
315 {
Haibo Huang165065a2018-07-23 17:26:52 -0700316 pcap_fmt_errmsg_for_errno(errbuf,
317 PCAP_ERRBUF_SIZE, errno,
318 "malloc() failed");
319 pcap_freealldevs(*alldevs);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700320 return -1;
321 }
322
323 /* Copy the new device description into the correct memory location */
324 strlcpy(dev->description, tmpstring, stringlen + 1);
325
326 pcap_close(fp);
327 }
328 }
Haibo Huang165065a2018-07-23 17:26:52 -0700329#ifdef _WIN32
Elliott Hughes965a4b52017-05-15 10:37:39 -0700330 while (FindNextFile(filehandle, &filedata) != 0);
331#else
332 while ( (filedata= readdir(unixdir)) != NULL);
333#endif
334
335
Haibo Huang165065a2018-07-23 17:26:52 -0700336#ifdef _WIN32
Elliott Hughes965a4b52017-05-15 10:37:39 -0700337 /* Close the search handle. */
338 FindClose(filehandle);
339#endif
340
341 return 0;
342 }
343
Elliott Hughes965a4b52017-05-15 10:37:39 -0700344 case PCAP_SRC_IFREMOTE:
Haibo Huang165065a2018-07-23 17:26:52 -0700345 return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700346
347 default:
Haibo Huang165065a2018-07-23 17:26:52 -0700348 strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700349 return -1;
350 }
Elliott Hughes965a4b52017-05-15 10:37:39 -0700351}
352
Elliott Hughes965a4b52017-05-15 10:37:39 -0700353pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
354{
Haibo Huang165065a2018-07-23 17:26:52 -0700355 char name[PCAP_BUF_SIZE];
Elliott Hughes965a4b52017-05-15 10:37:39 -0700356 int type;
357 pcap_t *fp;
Haibo Huang165065a2018-07-23 17:26:52 -0700358 int status;
Elliott Hughes965a4b52017-05-15 10:37:39 -0700359
360 if (strlen(source) > PCAP_BUF_SIZE)
361 {
362 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
363 return NULL;
364 }
365
Haibo Huang165065a2018-07-23 17:26:52 -0700366 /*
367 * Determine the type of the source (file, local, remote) and,
368 * if it's file or local, the name of the file or capture device.
369 */
370 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
Elliott Hughes965a4b52017-05-15 10:37:39 -0700371 return NULL;
372
Elliott Hughes965a4b52017-05-15 10:37:39 -0700373 switch (type)
374 {
375 case PCAP_SRC_FILE:
Haibo Huang165065a2018-07-23 17:26:52 -0700376 return pcap_open_offline(name, errbuf);
377
378 case PCAP_SRC_IFLOCAL:
379 fp = pcap_create(name, errbuf);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700380 break;
381
382 case PCAP_SRC_IFREMOTE:
Elliott Hughes965a4b52017-05-15 10:37:39 -0700383 /*
Haibo Huang165065a2018-07-23 17:26:52 -0700384 * Although we already have host, port and iface, we prefer
385 * to pass only 'source' to pcap_open_rpcap(), so that it
386 * has to call pcap_parsesrcstr() again.
Elliott Hughes965a4b52017-05-15 10:37:39 -0700387 * This is less optimized, but much clearer.
388 */
Haibo Huang165065a2018-07-23 17:26:52 -0700389 return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf);
Elliott Hughes965a4b52017-05-15 10:37:39 -0700390
391 default:
392 strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
393 return NULL;
394 }
Haibo Huang165065a2018-07-23 17:26:52 -0700395
396 if (fp == NULL)
397 return (NULL);
398 status = pcap_set_snaplen(fp, snaplen);
399 if (status < 0)
400 goto fail;
401 if (flags & PCAP_OPENFLAG_PROMISCUOUS)
402 {
403 status = pcap_set_promisc(fp, 1);
404 if (status < 0)
405 goto fail;
406 }
407 if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS)
408 {
409 status = pcap_set_immediate_mode(fp, 1);
410 if (status < 0)
411 goto fail;
412 }
413#ifdef _WIN32
414 /*
415 * This flag is supported on Windows only.
416 * XXX - is there a way to support it with
417 * the capture mechanisms on UN*X? It's not
418 * exactly a "set direction" operation; I
419 * think it means "do not capture packets
420 * injected with pcap_sendpacket() or
421 * pcap_inject()".
422 */
423 /* disable loopback capture if requested */
424 if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
425 fp->opt.nocapture_local = 1;
426#endif /* _WIN32 */
427 status = pcap_set_timeout(fp, read_timeout);
428 if (status < 0)
429 goto fail;
430 status = pcap_activate(fp);
431 if (status < 0)
432 goto fail;
Elliott Hughes965a4b52017-05-15 10:37:39 -0700433 return fp;
Haibo Huang165065a2018-07-23 17:26:52 -0700434
435fail:
436 if (status == PCAP_ERROR)
437 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
438 name, fp->errbuf);
439 else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
440 status == PCAP_ERROR_PERM_DENIED ||
441 status == PCAP_ERROR_PROMISC_PERM_DENIED)
442 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
443 name, pcap_statustostr(status), fp->errbuf);
444 else
445 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
446 name, pcap_statustostr(status));
447 pcap_close(fp);
448 return NULL;
Elliott Hughes965a4b52017-05-15 10:37:39 -0700449}
450
451struct pcap_samp *pcap_setsampling(pcap_t *p)
452{
Haibo Huang165065a2018-07-23 17:26:52 -0700453 return &p->rmt_samp;
Elliott Hughes965a4b52017-05-15 10:37:39 -0700454}