1 /*
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 #include <config.h>
35
36 #include "ftmacros.h"
37 #include "diag-control.h"
38
39 /*
40 * sockutils.h may include <crtdbg.h> on Windows, and pcap-int.h will
41 * include portability.h, and portability.h, on Windows, expects that
42 * <crtdbg.h> has already been included, so include sockutils.h first.
43 */
44 #include "sockutils.h"
45 #include "pcap-int.h" // for the details of the pcap_t structure
46 #include "pcap-rpcap.h"
47 #include "rpcap-protocol.h"
48 #include <errno.h> // for the errno variable
49 #include <stdlib.h> // for malloc(), free(), ...
50 #include <string.h> // for strstr, etc
51
52 #ifndef _WIN32
53 #include <dirent.h> // for readdir
54 #endif
55
56 /* String identifier to be used in the pcap_findalldevs_ex() */
57 #define PCAP_TEXT_SOURCE_FILE "File"
58 #define PCAP_TEXT_SOURCE_FILE_LEN (sizeof PCAP_TEXT_SOURCE_FILE - 1)
59 /* String identifier to be used in the pcap_findalldevs_ex() */
60 #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
61 #define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof "Network adapter" - 1)
62
63 /* String identifier to be used in the pcap_findalldevs_ex() */
64 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
65 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_LOCAL_HOST + 1)
66
67 /****************************************************
68 * *
69 * Function bodies *
70 * *
71 ****************************************************/
72
pcap_findalldevs_ex(const char * source,struct pcap_rmtauth * auth,pcap_if_t ** alldevs,char * errbuf)73 int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
74 {
75 int type;
76 char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
77 size_t pathlen;
78 size_t stringlen;
79 pcap_t *fp;
80 char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
81 pcap_if_t *lastdev; /* Last device in the pcap_if_t list */
82 pcap_if_t *dev; /* Device we're adding to the pcap_if_t list */
83
84 /* List starts out empty. */
85 (*alldevs) = NULL;
86 lastdev = NULL;
87
88 if (source == NULL)
89 {
90 snprintf(errbuf, PCAP_ERRBUF_SIZE,
91 "The source string must not be NULL.");
92 return -1;
93 }
94 if (strlen(source) > PCAP_BUF_SIZE)
95 {
96 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
97 return -1;
98 }
99
100 /*
101 * Determine the type of the source (file, local, remote)
102 *
103 * To list files in a local directory, the source string must specify
104 * the directory name. To list local or remote capture devices, the
105 * source string must not specify a device name. Retrieve the name
106 * component now and validate it for each source type next.
107 */
108 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
109 return -1;
110
111 switch (type)
112 {
113 case PCAP_SRC_IFLOCAL:
114 if (strlen(name)) {
115 snprintf(errbuf, PCAP_ERRBUF_SIZE,
116 "To list local capture devices, the source string must not include a device name.");
117 return -1;
118 }
119
120 /* Initialize temporary string */
121 tmpstring[PCAP_BUF_SIZE] = 0;
122
123 /* The user wants to retrieve adapters from a local host */
124 if (pcap_findalldevs(alldevs, errbuf) == -1)
125 return -1;
126
127 if (*alldevs == NULL)
128 {
129 snprintf(errbuf, PCAP_ERRBUF_SIZE,
130 "No interfaces found! Make sure libpcap/Npcap is properly installed"
131 " on the local machine.");
132 return -1;
133 }
134
135 /* Scan all the interfaces and modify name and description */
136 /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */
137 dev = *alldevs;
138 while (dev)
139 {
140 char *localdesc, *desc;
141
142 /* Create the new device identifier */
143 if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
144 return -1;
145
146 /* Delete the old pointer */
147 free(dev->name);
148
149 /* Make a copy of the new device identifier */
150 dev->name = strdup(tmpstring);
151 if (dev->name == NULL)
152 {
153 pcapint_fmt_errmsg_for_errno(errbuf,
154 PCAP_ERRBUF_SIZE, errno,
155 "malloc() failed");
156 pcap_freealldevs(*alldevs);
157 return -1;
158 }
159
160 /*
161 * Create the description.
162 */
163 if ((dev->description == NULL) || (dev->description[0] == 0))
164 localdesc = dev->name;
165 else
166 localdesc = dev->description;
167 if (pcapint_asprintf(&desc, "%s '%s' %s",
168 PCAP_TEXT_SOURCE_ADAPTER, localdesc,
169 PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1)
170 {
171 pcapint_fmt_errmsg_for_errno(errbuf,
172 PCAP_ERRBUF_SIZE, errno,
173 "malloc() failed");
174 pcap_freealldevs(*alldevs);
175 return -1;
176 }
177
178 /* Now overwrite the description */
179 free(dev->description);
180 dev->description = desc;
181
182 dev = dev->next;
183 }
184
185 return 0;
186
187 case PCAP_SRC_FILE:
188 {
189 #ifdef _WIN32
190 WIN32_FIND_DATA filedata;
191 HANDLE filehandle;
192 #else
193 struct dirent *filedata;
194 DIR *unixdir;
195 #endif
196
197 /* Check that the filename is correct */
198 stringlen = strlen(name);
199
200 if (! stringlen) {
201 snprintf(errbuf, PCAP_ERRBUF_SIZE,
202 "To list local files, the source string must include a directory.");
203 return -1;
204 }
205
206 /* The directory must end with '\' in Win32 and '/' in UNIX */
207 #ifdef _WIN32
208 #define ENDING_CHAR '\\'
209 #else
210 #define ENDING_CHAR '/'
211 #endif
212
213 if (name[stringlen - 1] != ENDING_CHAR)
214 {
215 name[stringlen] = ENDING_CHAR;
216 name[stringlen + 1] = 0;
217
218 stringlen++;
219 }
220
221 /* Save the path for future reference */
222 snprintf(path, sizeof(path), "%s", name);
223 pathlen = strlen(path);
224
225 #ifdef _WIN32
226 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */
227 if (name[stringlen - 1] != '*')
228 {
229 name[stringlen] = '*';
230 name[stringlen + 1] = 0;
231 }
232
233 filehandle = FindFirstFile(name, &filedata);
234
235 if (filehandle == INVALID_HANDLE_VALUE)
236 {
237 snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
238 return -1;
239 }
240
241 #else
242 /* opening the folder */
243 unixdir= opendir(path);
244 if (unixdir == NULL) {
245 DIAG_OFF_FORMAT_TRUNCATION
246 snprintf(errbuf, PCAP_ERRBUF_SIZE,
247 "Error when listing files in '%s': %s", path, pcap_strerror(errno));
248 DIAG_ON_FORMAT_TRUNCATION
249 return -1;
250 }
251
252 /* get the first file into it */
253 errno = 0;
254 filedata= readdir(unixdir);
255
256 if (filedata == NULL)
257 {
258 DIAG_OFF_FORMAT_TRUNCATION
259 snprintf(errbuf, PCAP_ERRBUF_SIZE,
260 "Error when listing files in '%s': %s", path, pcap_strerror(errno));
261 DIAG_ON_FORMAT_TRUNCATION
262 closedir(unixdir);
263 return -1;
264 }
265 #endif
266
267 /* Add all files we find to the list. */
268 do
269 {
270 #ifdef _WIN32
271 /* Skip the file if the pathname won't fit in the buffer */
272 if (pathlen + strlen(filedata.cFileName) >= sizeof(filename))
273 continue;
274 snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
275 #else
276 if (pathlen + strlen(filedata->d_name) >= sizeof(filename))
277 continue;
278 DIAG_OFF_FORMAT_TRUNCATION
279 snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
280 DIAG_ON_FORMAT_TRUNCATION
281 #endif
282
283 fp = pcap_open_offline(filename, errbuf);
284
285 if (fp)
286 {
287 /* allocate the main structure */
288 dev = (pcap_if_t *)malloc(sizeof(pcap_if_t));
289 if (dev == NULL)
290 {
291 pcapint_fmt_errmsg_for_errno(errbuf,
292 PCAP_ERRBUF_SIZE, errno,
293 "malloc() failed");
294 pcap_freealldevs(*alldevs);
295 #ifdef _WIN32
296 FindClose(filehandle);
297 #else
298 closedir(unixdir);
299 #endif
300 return -1;
301 }
302
303 /* Initialize the structure to 'zero' */
304 memset(dev, 0, sizeof(pcap_if_t));
305
306 /* Append it to the list. */
307 if (lastdev == NULL)
308 {
309 /*
310 * List is empty, so it's also
311 * the first device.
312 */
313 *alldevs = dev;
314 }
315 else
316 {
317 /*
318 * Append after the last device.
319 */
320 lastdev->next = dev;
321 }
322 /* It's now the last device. */
323 lastdev = dev;
324
325 /* Create the new source identifier */
326 if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1)
327 {
328 pcap_freealldevs(*alldevs);
329 #ifdef _WIN32
330 FindClose(filehandle);
331 #else
332 closedir(unixdir);
333 #endif
334 return -1;
335 }
336
337 dev->name = strdup(tmpstring);
338 if (dev->name == NULL)
339 {
340 pcapint_fmt_errmsg_for_errno(errbuf,
341 PCAP_ERRBUF_SIZE, errno,
342 "malloc() failed");
343 pcap_freealldevs(*alldevs);
344 #ifdef _WIN32
345 FindClose(filehandle);
346 #else
347 closedir(unixdir);
348 #endif
349 return -1;
350 }
351
352 /*
353 * Create the description.
354 */
355 if (pcapint_asprintf(&dev->description,
356 "%s '%s' %s", PCAP_TEXT_SOURCE_FILE,
357 filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST) == -1)
358 {
359 pcapint_fmt_errmsg_for_errno(errbuf,
360 PCAP_ERRBUF_SIZE, errno,
361 "malloc() failed");
362 pcap_freealldevs(*alldevs);
363 #ifdef _WIN32
364 FindClose(filehandle);
365 #else
366 closedir(unixdir);
367 #endif
368 return -1;
369 }
370
371 pcap_close(fp);
372 }
373 }
374 #ifdef _WIN32
375 while (FindNextFile(filehandle, &filedata) != 0);
376 #else
377 while ( (filedata= readdir(unixdir)) != NULL);
378 #endif
379
380
381 /* Close the search handle. */
382 #ifdef _WIN32
383 FindClose(filehandle);
384 #else
385 closedir(unixdir);
386 #endif
387
388 return 0;
389 }
390
391 case PCAP_SRC_IFREMOTE:
392 if (strlen(name)) {
393 snprintf(errbuf, PCAP_ERRBUF_SIZE,
394 "To list remote capture devices, the source string must not include a device name.");
395 return -1;
396 }
397
398 return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf);
399
400 default:
401 pcapint_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
402 return -1;
403 }
404 }
405
pcap_open(const char * source,int snaplen,int flags,int read_timeout,struct pcap_rmtauth * auth,char * errbuf)406 pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
407 {
408 char name[PCAP_BUF_SIZE];
409 int type;
410 pcap_t *fp;
411 int status;
412
413 /*
414 * A null device name is equivalent to the "any" device -
415 * which might not be supported on this platform, but
416 * this means that you'll get a "not supported" error
417 * rather than, say, a crash when we try to dereference
418 * the null pointer.
419 */
420 if (source == NULL)
421 source = "any";
422
423 if (strlen(source) > PCAP_BUF_SIZE)
424 {
425 snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
426 return NULL;
427 }
428
429 /*
430 * Determine the type of the source (file, local, remote) and,
431 * if it's file or local, the name of the file or capture device.
432 */
433 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
434 return NULL;
435
436 switch (type)
437 {
438 case PCAP_SRC_FILE:
439 if (! strlen(name)) {
440 snprintf(errbuf, PCAP_ERRBUF_SIZE,
441 "To open a local file, the source string must include the file path.");
442 return NULL;
443 }
444 return pcap_open_offline(name, errbuf);
445
446 case PCAP_SRC_IFLOCAL:
447 if (! strlen(name)) {
448 snprintf(errbuf, PCAP_ERRBUF_SIZE,
449 "To open a local capture device, the source string must include the device name.");
450 return NULL;
451 }
452 fp = pcap_create(name, errbuf);
453 break;
454
455 case PCAP_SRC_IFREMOTE:
456 if (! strlen(name)) {
457 snprintf(errbuf, PCAP_ERRBUF_SIZE,
458 "To open a remote capture device, the source string must include the device name.");
459 return NULL;
460 }
461 /*
462 * Although we already have host, port and iface, we prefer
463 * to pass only 'source' to pcap_open_rpcap(), so that it
464 * has to call pcap_parsesrcstr() again.
465 * This is less optimized, but much clearer.
466 */
467 return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf);
468
469 default:
470 pcapint_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
471 return NULL;
472 }
473
474 if (fp == NULL)
475 return (NULL);
476 status = pcap_set_snaplen(fp, snaplen);
477 if (status < 0)
478 goto fail;
479 if (flags & PCAP_OPENFLAG_PROMISCUOUS)
480 {
481 status = pcap_set_promisc(fp, 1);
482 if (status < 0)
483 goto fail;
484 }
485 if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS)
486 {
487 status = pcap_set_immediate_mode(fp, 1);
488 if (status < 0)
489 goto fail;
490 }
491 #ifdef _WIN32
492 /*
493 * This flag is supported on Windows only.
494 * XXX - is there a way to support it with
495 * the capture mechanisms on UN*X? It's not
496 * exactly a "set direction" operation; I
497 * think it means "do not capture packets
498 * injected with pcap_sendpacket() or
499 * pcap_inject()".
500 */
501 /* disable loopback capture if requested */
502 if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
503 fp->opt.nocapture_local = 1;
504 #endif /* _WIN32 */
505 status = pcap_set_timeout(fp, read_timeout);
506 if (status < 0)
507 goto fail;
508 status = pcap_activate(fp);
509 if (status < 0)
510 goto fail;
511 return fp;
512
513 fail:
514 DIAG_OFF_FORMAT_TRUNCATION
515 if (status == PCAP_ERROR)
516 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
517 name, fp->errbuf);
518 else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
519 status == PCAP_ERROR_PERM_DENIED ||
520 status == PCAP_ERROR_PROMISC_PERM_DENIED)
521 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
522 name, pcap_statustostr(status), fp->errbuf);
523 else
524 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
525 name, pcap_statustostr(status));
526 DIAG_ON_FORMAT_TRUNCATION
527 pcap_close(fp);
528 return NULL;
529 }
530
pcap_setsampling(pcap_t * p)531 struct pcap_samp *pcap_setsampling(pcap_t *p)
532 {
533 return &p->rmt_samp;
534 }
535