]> The Tcpdump Group git mirrors - libpcap/blob - pcap-new.c
Merge pull request #1 from the-tcpdump-group/master
[libpcap] / pcap-new.c
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 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include "pcap-int.h" // for the details of the pcap_t structure
39 #include "sockutils.h"
40 #include "rpcap-protocol.h"
41 #include "pcap-rpcap-int.h"
42 #include <errno.h> // for the errno variable
43 #include <stdlib.h> // for malloc(), free(), ...
44 #include <string.h> // for strstr, etc
45
46 #ifndef _WIN32
47 #include <dirent.h> // for readdir
48 #endif
49
50 /* String identifier to be used in the pcap_findalldevs_ex() */
51 #define PCAP_TEXT_SOURCE_FILE "File"
52 /* String identifier to be used in the pcap_findalldevs_ex() */
53 #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
54
55 /* String identifier to be used in the pcap_findalldevs_ex() */
56 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
57
58 /****************************************************
59 * *
60 * Function bodies *
61 * *
62 ****************************************************/
63
64 int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
65 {
66 int type;
67 char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
68 pcap_t *fp;
69 char tmpstring[PCAP_BUF_SIZE + 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
70 pcap_if_t *dev; /* Previous device into the pcap_if_t chain */
71
72 (*alldevs) = NULL;
73
74 if (strlen(source) > PCAP_BUF_SIZE)
75 {
76 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
77 return -1;
78 }
79
80 /*
81 * Determine the type of the source (file, local, remote)
82 * There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters.
83 * In the first case, the name of the directory we have to look into must be present (therefore
84 * the 'name' parameter of the pcap_parsesrcstr() is present).
85 * In the second case, the name of the adapter is not required (we need just the host). So, we have
86 * to use a first time this function to get the source type, and a second time to get the appropriate
87 * info, which depends on the source type.
88 */
89 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
90 return -1;
91
92 switch (type)
93 {
94 case PCAP_SRC_IFLOCAL:
95 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
96 return -1;
97
98 /* Initialize temporary string */
99 tmpstring[PCAP_BUF_SIZE] = 0;
100
101 /* The user wants to retrieve adapters from a local host */
102 if (pcap_findalldevs(alldevs, errbuf) == -1)
103 return -1;
104
105 if ((alldevs == NULL) || (*alldevs == NULL))
106 {
107 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
108 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
109 " on the local machine.");
110 return -1;
111 }
112
113 /* Scan all the interfaces and modify name and description */
114 /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */
115 dev = *alldevs;
116 while (dev)
117 {
118 /* Create the new device identifier */
119 if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
120 return -1;
121
122 /* Delete the old pointer */
123 free(dev->name);
124
125 /* Make a copy of the new device identifier */
126 dev->name = strdup(tmpstring);
127 if (dev->name == NULL)
128 {
129 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
130 return -1;
131 }
132
133 /* Create the new device description */
134 if ((dev->description == NULL) || (dev->description[0] == 0))
135 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER,
136 dev->name, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
137 else
138 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER,
139 dev->description, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
140
141 /* Delete the old pointer */
142 free(dev->description);
143
144 /* Make a copy of the description */
145 dev->description = strdup(tmpstring);
146 if (dev->description == NULL)
147 {
148 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
149 return -1;
150 }
151
152 dev = dev->next;
153 }
154
155 return 0;
156
157 case PCAP_SRC_FILE:
158 {
159 size_t stringlen;
160 #ifdef _WIN32
161 WIN32_FIND_DATA filedata;
162 HANDLE filehandle;
163 #else
164 struct dirent *filedata;
165 DIR *unixdir;
166 #endif
167
168 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
169 return -1;
170
171 /* Check that the filename is correct */
172 stringlen = strlen(name);
173
174 /* The directory must end with '\' in Win32 and '/' in UNIX */
175 #ifdef _WIN32
176 #define ENDING_CHAR '\\'
177 #else
178 #define ENDING_CHAR '/'
179 #endif
180
181 if (name[stringlen - 1] != ENDING_CHAR)
182 {
183 name[stringlen] = ENDING_CHAR;
184 name[stringlen + 1] = 0;
185
186 stringlen++;
187 }
188
189 /* Save the path for future reference */
190 pcap_snprintf(path, sizeof(path), "%s", name);
191
192 #ifdef _WIN32
193 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */
194 if (name[stringlen - 1] != '*')
195 {
196 name[stringlen] = '*';
197 name[stringlen + 1] = 0;
198 }
199
200 filehandle = FindFirstFile(name, &filedata);
201
202 if (filehandle == INVALID_HANDLE_VALUE)
203 {
204 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
205 return -1;
206 }
207
208 #else
209 /* opening the folder */
210 unixdir= opendir(path);
211
212 /* get the first file into it */
213 filedata= readdir(unixdir);
214
215 if (filedata == NULL)
216 {
217 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
218 return -1;
219 }
220 #endif
221
222 do
223 {
224
225 #ifdef _WIN32
226 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
227 #else
228 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
229 #endif
230
231 fp = pcap_open_offline(filename, errbuf);
232
233 if (fp)
234 {
235 /* allocate the main structure */
236 if (*alldevs == NULL) /* This is in case it is the first file */
237 {
238 (*alldevs) = (pcap_if_t *)malloc(sizeof(pcap_if_t));
239 dev = (*alldevs);
240 }
241 else
242 {
243 dev->next = (pcap_if_t *)malloc(sizeof(pcap_if_t));
244 dev = dev->next;
245 }
246
247 /* check that the malloc() didn't fail */
248 if (dev == NULL)
249 {
250 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
251 return -1;
252 }
253
254 /* Initialize the structure to 'zero' */
255 memset(dev, 0, sizeof(pcap_if_t));
256
257 /* Create the new source identifier */
258 if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1)
259 return -1;
260
261 stringlen = strlen(tmpstring);
262
263 dev->name = (char *)malloc(stringlen + 1);
264 if (dev->name == NULL)
265 {
266 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
267 return -1;
268 }
269
270 strlcpy(dev->name, tmpstring, stringlen);
271
272 dev->name[stringlen] = 0;
273
274 /* Create the description */
275 pcap_snprintf(tmpstring, sizeof(tmpstring) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_FILE,
276 filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
277
278 stringlen = strlen(tmpstring);
279
280 dev->description = (char *)malloc(stringlen + 1);
281
282 if (dev->description == NULL)
283 {
284 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "malloc() failed: %s", pcap_strerror(errno));
285 return -1;
286 }
287
288 /* Copy the new device description into the correct memory location */
289 strlcpy(dev->description, tmpstring, stringlen + 1);
290
291 pcap_close(fp);
292 }
293 }
294 #ifdef _WIN32
295 while (FindNextFile(filehandle, &filedata) != 0);
296 #else
297 while ( (filedata= readdir(unixdir)) != NULL);
298 #endif
299
300
301 #ifdef _WIN32
302 /* Close the search handle. */
303 FindClose(filehandle);
304 #endif
305
306 return 0;
307 }
308
309 case PCAP_SRC_IFREMOTE:
310 return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf);
311
312 default:
313 strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
314 return -1;
315 }
316 }
317
318 int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf)
319 {
320 switch (type)
321 {
322 case PCAP_SRC_FILE:
323 {
324 strlcpy(source, PCAP_SRC_FILE_STRING, PCAP_BUF_SIZE);
325 if ((name) && (*name))
326 {
327 strlcat(source, name, PCAP_BUF_SIZE);
328 return 0;
329 }
330 else
331 {
332 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name cannot be NULL.");
333 return -1;
334 }
335 }
336
337 case PCAP_SRC_IFREMOTE:
338 {
339 strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
340 if ((host) && (*host))
341 {
342 if ((strcspn(host, "aAbBcCdDeEfFgGhHjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")) == strlen(host))
343 {
344 /* the host name does not contains alphabetic chars. So, it is a numeric address */
345 /* In this case we have to include it between square brackets */
346 strlcat(source, "[", PCAP_BUF_SIZE);
347 strlcat(source, host, PCAP_BUF_SIZE);
348 strlcat(source, "]", PCAP_BUF_SIZE);
349 }
350 else
351 strlcat(source, host, PCAP_BUF_SIZE);
352
353 if ((port) && (*port))
354 {
355 strlcat(source, ":", PCAP_BUF_SIZE);
356 strlcat(source, port, PCAP_BUF_SIZE);
357 }
358
359 strlcat(source, "/", PCAP_BUF_SIZE);
360 }
361 else
362 {
363 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The host name cannot be NULL.");
364 return -1;
365 }
366
367 if ((name) && (*name))
368 strlcat(source, name, PCAP_BUF_SIZE);
369
370 return 0;
371 }
372
373 case PCAP_SRC_IFLOCAL:
374 {
375 strlcpy(source, PCAP_SRC_IF_STRING, PCAP_BUF_SIZE);
376
377 if ((name) && (*name))
378 strlcat(source, name, PCAP_BUF_SIZE);
379
380 return 0;
381 }
382
383 default:
384 {
385 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface type is not valid.");
386 return -1;
387 }
388 }
389 }
390
391 int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf)
392 {
393 char *ptr;
394 int ntoken;
395 char tmpname[PCAP_BUF_SIZE];
396 char tmphost[PCAP_BUF_SIZE];
397 char tmpport[PCAP_BUF_SIZE];
398 int tmptype;
399
400 /* Initialization stuff */
401 tmpname[0] = 0;
402 tmphost[0] = 0;
403 tmpport[0] = 0;
404
405 if (host)
406 *host = 0;
407 if (port)
408 *port = 0;
409 if (name)
410 *name = 0;
411
412 /* Look for a 'rpcap://' identifier */
413 if ((ptr = strstr(source, PCAP_SRC_IF_STRING)) != NULL)
414 {
415 if (strlen(PCAP_SRC_IF_STRING) == strlen(source))
416 {
417 /* The source identifier contains only the 'rpcap://' string. */
418 /* So, this is a local capture. */
419 *type = PCAP_SRC_IFLOCAL;
420 return 0;
421 }
422
423 ptr += strlen(PCAP_SRC_IF_STRING);
424
425 if (strchr(ptr, '[')) /* This is probably a numeric address */
426 {
427 ntoken = sscanf(ptr, "[%[1234567890:.]]:%[^/]/%s", tmphost, tmpport, tmpname);
428
429 if (ntoken == 1) /* probably the port is missing */
430 ntoken = sscanf(ptr, "[%[1234567890:.]]/%s", tmphost, tmpname);
431
432 tmptype = PCAP_SRC_IFREMOTE;
433 }
434 else
435 {
436 ntoken = sscanf(ptr, "%[^/:]:%[^/]/%s", tmphost, tmpport, tmpname);
437
438 if (ntoken == 1)
439 {
440 /*
441 * This can be due to two reasons:
442 * - we want a remote capture, but the network port is missing
443 * - we want to do a local capture
444 * To distinguish between the two, we look for the '/' char
445 */
446 if (strchr(ptr, '/'))
447 {
448 /* We're on a remote capture */
449 sscanf(ptr, "%[^/]/%s", tmphost, tmpname);
450 tmptype = PCAP_SRC_IFREMOTE;
451 }
452 else
453 {
454 /* We're on a local capture */
455 if (*ptr)
456 strlcpy(tmpname, ptr, PCAP_BUF_SIZE);
457
458 /* Clean the host name, since it is a remote capture */
459 /* NOTE: the host name has been assigned in the previous "ntoken= sscanf(...)" line */
460 tmphost[0] = 0;
461
462 tmptype = PCAP_SRC_IFLOCAL;
463 }
464 }
465 else
466 tmptype = PCAP_SRC_IFREMOTE;
467 }
468
469 if (host)
470 strlcpy(host, tmphost, PCAP_BUF_SIZE);
471 if (port)
472 strlcpy(port, tmpport, PCAP_BUF_SIZE);
473 if (type)
474 *type = tmptype;
475
476 if (name)
477 {
478 /*
479 * If the user wants the host name, but it cannot be located into the source string, return error
480 * However, if the user is not interested in the interface name (e.g. if we're called by
481 * pcap_findalldevs_ex(), which does not have interface name, do not return error
482 */
483 if (tmpname[0])
484 {
485 strlcpy(name, tmpname, PCAP_BUF_SIZE);
486 }
487 else
488 {
489 if (errbuf)
490 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified in the source string.");
491
492 return -1;
493 }
494 }
495
496 return 0;
497 }
498
499 /* Look for a 'file://' identifier */
500 if ((ptr = strstr(source, PCAP_SRC_FILE_STRING)) != NULL)
501 {
502 ptr += strlen(PCAP_SRC_FILE_STRING);
503 if (*ptr)
504 {
505 if (name)
506 strlcpy(name, ptr, PCAP_BUF_SIZE);
507
508 if (type)
509 *type = PCAP_SRC_FILE;
510
511 return 0;
512 }
513 else
514 {
515 if (errbuf)
516 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The file name has not been specified in the source string.");
517
518 return -1;
519 }
520
521 }
522
523 /* Backward compatibility; the user didn't use the 'rpcap://, file://' specifiers */
524 if ((source) && (*source))
525 {
526 if (name)
527 strlcpy(name, source, PCAP_BUF_SIZE);
528
529 if (type)
530 *type = PCAP_SRC_IFLOCAL;
531
532 return 0;
533 }
534 else
535 {
536 if (errbuf)
537 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The interface name has not been specified in the source string.");
538
539 return -1;
540 }
541 };
542
543 pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
544 {
545 char name[PCAP_BUF_SIZE];
546 int type;
547 pcap_t *fp;
548 int status;
549
550 if (strlen(source) > PCAP_BUF_SIZE)
551 {
552 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
553 return NULL;
554 }
555
556 /*
557 * Determine the type of the source (file, local, remote) and,
558 * if it's file or local, the name of the file or capture device.
559 */
560 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
561 return NULL;
562
563 switch (type)
564 {
565 case PCAP_SRC_FILE:
566 return pcap_open_offline(name, errbuf);
567
568 case PCAP_SRC_IFLOCAL:
569 fp = pcap_create(name, errbuf);
570 break;
571
572 case PCAP_SRC_IFREMOTE:
573 /*
574 * Although we already have host, port and iface, we prefer
575 * to pass only 'source' to pcap_open_rpcap(), so that it
576 * has to call pcap_parsesrcstr() again.
577 * This is less optimized, but much clearer.
578 */
579 return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf);
580
581 default:
582 strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
583 return NULL;
584 }
585
586 if (fp == NULL)
587 return (NULL);
588 status = pcap_set_snaplen(fp, snaplen);
589 if (status < 0)
590 goto fail;
591 if (flags & PCAP_OPENFLAG_PROMISCUOUS)
592 {
593 status = pcap_set_promisc(fp, 1);
594 if (status < 0)
595 goto fail;
596 }
597 if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS)
598 {
599 status = pcap_set_immediate_mode(fp, 1);
600 if (status < 0)
601 goto fail;
602 }
603 status = pcap_set_timeout(fp, read_timeout);
604 if (status < 0)
605 goto fail;
606 status = pcap_activate(fp);
607 if (status < 0)
608 goto fail;
609 #ifdef _WIN32
610 /*
611 * This flag is supported on Windows only.
612 * XXX - is there a way to support it with
613 * the capture mechanisms on UN*X? It's not
614 * exactly a "set direction" operation; I
615 * think it means "do not capture packets
616 * injected with pcap_sendpacket() or
617 * pcap_inject()".
618 */
619 if (fp->adapter != NULL)
620 {
621 /* disable loopback capture if requested */
622 if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
623 {
624 if (!PacketSetLoopbackBehavior(fp->adapter, NPF_DISABLE_LOOPBACK))
625 {
626 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Unable to disable the capture of loopback packets.");
627 pcap_close(fp);
628 return NULL;
629 }
630 }
631 }
632 #endif /* _WIN32 */
633 return fp;
634
635 fail:
636 if (status == PCAP_ERROR)
637 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
638 name, fp->errbuf);
639 else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
640 status == PCAP_ERROR_PERM_DENIED ||
641 status == PCAP_ERROR_PROMISC_PERM_DENIED)
642 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
643 name, pcap_statustostr(status), fp->errbuf);
644 else
645 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
646 name, pcap_statustostr(status));
647 pcap_close(fp);
648 return NULL;
649 }
650
651 struct pcap_samp *pcap_setsampling(pcap_t *p)
652 {
653 return &p->rmt_samp;
654 }