2 * Copyright (c) 2002 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2008 CACE Technologies, Davis (California)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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.
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
47 #include <dirent.h> // for readdir
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"
55 /* String identifier to be used in the pcap_findalldevs_ex() */
56 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
58 /****************************************************
62 ****************************************************/
64 int pcap_findalldevs_ex(char *source
, struct pcap_rmtauth
*auth
, pcap_if_t
**alldevs
, char *errbuf
)
67 char name
[PCAP_BUF_SIZE
], path
[PCAP_BUF_SIZE
], filename
[PCAP_BUF_SIZE
];
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 */
74 if (strlen(source
) > PCAP_BUF_SIZE
)
76 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The source string is too long. Cannot handle it correctly.");
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.
89 if (pcap_parsesrcstr(source
, &type
, NULL
, NULL
, NULL
, errbuf
) == -1)
94 case PCAP_SRC_IFLOCAL
:
95 if (pcap_parsesrcstr(source
, &type
, NULL
, NULL
, NULL
, errbuf
) == -1)
98 /* Initialize temporary string */
99 tmpstring
[PCAP_BUF_SIZE
] = 0;
101 /* The user wants to retrieve adapters from a local host */
102 if (pcap_findalldevs(alldevs
, errbuf
) == -1)
105 if ((alldevs
== NULL
) || (*alldevs
== NULL
))
107 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
,
108 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
109 " on the local machine.");
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 */
118 /* Create the new device identifier */
119 if (pcap_createsrcstr(tmpstring
, PCAP_SRC_IFLOCAL
, NULL
, NULL
, dev
->name
, errbuf
) == -1)
122 /* Delete the old pointer */
125 /* Make a copy of the new device identifier */
126 dev
->name
= strdup(tmpstring
);
127 if (dev
->name
== NULL
)
129 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
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
);
138 pcap_snprintf(tmpstring
, sizeof(tmpstring
) - 1, "%s '%s' %s", PCAP_TEXT_SOURCE_ADAPTER
,
139 dev
->description
, PCAP_TEXT_SOURCE_ON_LOCAL_HOST
);
141 /* Delete the old pointer */
142 free(dev
->description
);
144 /* Make a copy of the description */
145 dev
->description
= strdup(tmpstring
);
146 if (dev
->description
== NULL
)
148 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
161 WIN32_FIND_DATA filedata
;
164 struct dirent
*filedata
;
168 if (pcap_parsesrcstr(source
, &type
, NULL
, NULL
, name
, errbuf
) == -1)
171 /* Check that the filename is correct */
172 stringlen
= strlen(name
);
174 /* The directory must end with '\' in Win32 and '/' in UNIX */
176 #define ENDING_CHAR '\\'
178 #define ENDING_CHAR '/'
181 if (name
[stringlen
- 1] != ENDING_CHAR
)
183 name
[stringlen
] = ENDING_CHAR
;
184 name
[stringlen
+ 1] = 0;
189 /* Save the path for future reference */
190 pcap_snprintf(path
, sizeof(path
), "%s", name
);
193 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */
194 if (name
[stringlen
- 1] != '*')
196 name
[stringlen
] = '*';
197 name
[stringlen
+ 1] = 0;
200 filehandle
= FindFirstFile(name
, &filedata
);
202 if (filehandle
== INVALID_HANDLE_VALUE
)
204 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error when listing files: does folder '%s' exist?", path
);
209 /* opening the folder */
210 unixdir
= opendir(path
);
212 /* get the first file into it */
213 filedata
= readdir(unixdir
);
215 if (filedata
== NULL
)
217 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error when listing files: does folder '%s' exist?", path
);
226 pcap_snprintf(filename
, sizeof(filename
), "%s%s", path
, filedata
.cFileName
);
228 pcap_snprintf(filename
, sizeof(filename
), "%s%s", path
, filedata
->d_name
);
231 fp
= pcap_open_offline(filename
, errbuf
);
235 /* allocate the main structure */
236 if (*alldevs
== NULL
) /* This is in case it is the first file */
238 (*alldevs
) = (pcap_if_t
*)malloc(sizeof(pcap_if_t
));
243 dev
->next
= (pcap_if_t
*)malloc(sizeof(pcap_if_t
));
247 /* check that the malloc() didn't fail */
250 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
254 /* Initialize the structure to 'zero' */
255 memset(dev
, 0, sizeof(pcap_if_t
));
257 /* Create the new source identifier */
258 if (pcap_createsrcstr(tmpstring
, PCAP_SRC_FILE
, NULL
, NULL
, filename
, errbuf
) == -1)
261 stringlen
= strlen(tmpstring
);
263 dev
->name
= (char *)malloc(stringlen
+ 1);
264 if (dev
->name
== NULL
)
266 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
270 strlcpy(dev
->name
, tmpstring
, stringlen
);
272 dev
->name
[stringlen
] = 0;
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
);
278 stringlen
= strlen(tmpstring
);
280 dev
->description
= (char *)malloc(stringlen
+ 1);
282 if (dev
->description
== NULL
)
284 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "malloc() failed: %s", pcap_strerror(errno
));
288 /* Copy the new device description into the correct memory location */
289 strlcpy(dev
->description
, tmpstring
, stringlen
+ 1);
295 while (FindNextFile(filehandle
, &filedata
) != 0);
297 while ( (filedata
= readdir(unixdir
)) != NULL
);
302 /* Close the search handle. */
303 FindClose(filehandle
);
309 case PCAP_SRC_IFREMOTE
:
310 return pcap_findalldevs_ex_remote(source
, auth
, alldevs
, errbuf
);
313 strlcpy(errbuf
, "Source type not supported", PCAP_ERRBUF_SIZE
);
318 int pcap_createsrcstr(char *source
, int type
, const char *host
, const char *port
, const char *name
, char *errbuf
)
324 strlcpy(source
, PCAP_SRC_FILE_STRING
, PCAP_BUF_SIZE
);
325 if ((name
) && (*name
))
327 strlcat(source
, name
, PCAP_BUF_SIZE
);
332 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The file name cannot be NULL.");
337 case PCAP_SRC_IFREMOTE
:
339 strlcpy(source
, PCAP_SRC_IF_STRING
, PCAP_BUF_SIZE
);
340 if ((host
) && (*host
))
342 if ((strcspn(host
, "aAbBcCdDeEfFgGhHjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ")) == strlen(host
))
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
);
351 strlcat(source
, host
, PCAP_BUF_SIZE
);
353 if ((port
) && (*port
))
355 strlcat(source
, ":", PCAP_BUF_SIZE
);
356 strlcat(source
, port
, PCAP_BUF_SIZE
);
359 strlcat(source
, "/", PCAP_BUF_SIZE
);
363 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The host name cannot be NULL.");
367 if ((name
) && (*name
))
368 strlcat(source
, name
, PCAP_BUF_SIZE
);
373 case PCAP_SRC_IFLOCAL
:
375 strlcpy(source
, PCAP_SRC_IF_STRING
, PCAP_BUF_SIZE
);
377 if ((name
) && (*name
))
378 strlcat(source
, name
, PCAP_BUF_SIZE
);
385 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The interface type is not valid.");
391 int pcap_parsesrcstr(const char *source
, int *type
, char *host
, char *port
, char *name
, char *errbuf
)
395 char tmpname
[PCAP_BUF_SIZE
];
396 char tmphost
[PCAP_BUF_SIZE
];
397 char tmpport
[PCAP_BUF_SIZE
];
400 /* Initialization stuff */
412 /* Look for a 'rpcap://' identifier */
413 if ((ptr
= strstr(source
, PCAP_SRC_IF_STRING
)) != NULL
)
415 if (strlen(PCAP_SRC_IF_STRING
) == strlen(source
))
417 /* The source identifier contains only the 'rpcap://' string. */
418 /* So, this is a local capture. */
419 *type
= PCAP_SRC_IFLOCAL
;
423 ptr
+= strlen(PCAP_SRC_IF_STRING
);
425 if (strchr(ptr
, '[')) /* This is probably a numeric address */
427 ntoken
= sscanf(ptr
, "[%[1234567890:.]]:%[^/]/%s", tmphost
, tmpport
, tmpname
);
429 if (ntoken
== 1) /* probably the port is missing */
430 ntoken
= sscanf(ptr
, "[%[1234567890:.]]/%s", tmphost
, tmpname
);
432 tmptype
= PCAP_SRC_IFREMOTE
;
436 ntoken
= sscanf(ptr
, "%[^/:]:%[^/]/%s", tmphost
, tmpport
, tmpname
);
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
446 if (strchr(ptr
, '/'))
448 /* We're on a remote capture */
449 sscanf(ptr
, "%[^/]/%s", tmphost
, tmpname
);
450 tmptype
= PCAP_SRC_IFREMOTE
;
454 /* We're on a local capture */
456 strlcpy(tmpname
, ptr
, PCAP_BUF_SIZE
);
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 */
462 tmptype
= PCAP_SRC_IFLOCAL
;
466 tmptype
= PCAP_SRC_IFREMOTE
;
470 strlcpy(host
, tmphost
, PCAP_BUF_SIZE
);
472 strlcpy(port
, tmpport
, PCAP_BUF_SIZE
);
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
485 strlcpy(name
, tmpname
, PCAP_BUF_SIZE
);
490 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The interface name has not been specified in the source string.");
499 /* Look for a 'file://' identifier */
500 if ((ptr
= strstr(source
, PCAP_SRC_FILE_STRING
)) != NULL
)
502 ptr
+= strlen(PCAP_SRC_FILE_STRING
);
506 strlcpy(name
, ptr
, PCAP_BUF_SIZE
);
509 *type
= PCAP_SRC_FILE
;
516 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The file name has not been specified in the source string.");
523 /* Backward compatibility; the user didn't use the 'rpcap://, file://' specifiers */
524 if ((source
) && (*source
))
527 strlcpy(name
, source
, PCAP_BUF_SIZE
);
530 *type
= PCAP_SRC_IFLOCAL
;
537 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The interface name has not been specified in the source string.");
543 pcap_t
*pcap_open(const char *source
, int snaplen
, int flags
, int read_timeout
, struct pcap_rmtauth
*auth
, char *errbuf
)
545 char name
[PCAP_BUF_SIZE
];
550 if (strlen(source
) > PCAP_BUF_SIZE
)
552 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The source string is too long. Cannot handle it correctly.");
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.
560 if (pcap_parsesrcstr(source
, &type
, NULL
, NULL
, name
, errbuf
) == -1)
566 return pcap_open_offline(name
, errbuf
);
568 case PCAP_SRC_IFLOCAL
:
569 fp
= pcap_create(name
, errbuf
);
572 case PCAP_SRC_IFREMOTE
:
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.
579 return pcap_open_rpcap(source
, snaplen
, flags
, read_timeout
, auth
, errbuf
);
582 strlcpy(errbuf
, "Source type not supported", PCAP_ERRBUF_SIZE
);
588 status
= pcap_set_snaplen(fp
, snaplen
);
591 if (flags
& PCAP_OPENFLAG_PROMISCUOUS
)
593 status
= pcap_set_promisc(fp
, 1);
597 if (flags
& PCAP_OPENFLAG_MAX_RESPONSIVENESS
)
599 status
= pcap_set_immediate_mode(fp
, 1);
603 status
= pcap_set_timeout(fp
, read_timeout
);
606 status
= pcap_activate(fp
);
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
619 if (fp
->adapter
!= NULL
)
621 /* disable loopback capture if requested */
622 if (flags
& PCAP_OPENFLAG_NOCAPTURE_LOCAL
)
624 if (!PacketSetLoopbackBehavior(fp
->adapter
, NPF_DISABLE_LOOPBACK
))
626 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Unable to disable the capture of loopback packets.");
636 if (status
== PCAP_ERROR
)
637 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "%s: %s",
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
);
645 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "%s: %s",
646 name
, pcap_statustostr(status
));
651 struct pcap_samp
*pcap_setsampling(pcap_t
*p
)