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.
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.
43 #include "sockutils.h"
44 #include "pcap-int.h" // for the details of the pcap_t structure
45 #include "pcap-rpcap.h"
46 #include "rpcap-protocol.h"
47 #include <errno.h> // for the errno variable
48 #include <stdlib.h> // for malloc(), free(), ...
49 #include <string.h> // for strstr, etc
52 #include <dirent.h> // for readdir
55 /* String identifier to be used in the pcap_findalldevs_ex() */
56 #define PCAP_TEXT_SOURCE_FILE "File"
57 #define PCAP_TEXT_SOURCE_FILE_LEN (sizeof PCAP_TEXT_SOURCE_FILE - 1)
58 /* String identifier to be used in the pcap_findalldevs_ex() */
59 #define PCAP_TEXT_SOURCE_ADAPTER "Network adapter"
60 #define PCAP_TEXT_SOURCE_ADAPTER_LEN (sizeof "Network adapter" - 1)
62 /* String identifier to be used in the pcap_findalldevs_ex() */
63 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST "on local host"
64 #define PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN (sizeof PCAP_TEXT_SOURCE_ON_LOCAL_HOST + 1)
66 /****************************************************
70 ****************************************************/
72 int pcap_findalldevs_ex(const char *source
, struct pcap_rmtauth
*auth
, pcap_if_t
**alldevs
, char *errbuf
)
75 char name
[PCAP_BUF_SIZE
], path
[PCAP_BUF_SIZE
], filename
[PCAP_BUF_SIZE
];
79 char tmpstring
[PCAP_BUF_SIZE
+ 1]; /* Needed to convert names and descriptions from 'old' syntax to the 'new' one */
80 pcap_if_t
*lastdev
; /* Last device in the pcap_if_t list */
81 pcap_if_t
*dev
; /* Device we're adding to the pcap_if_t list */
83 /* List starts out empty. */
87 if (strlen(source
) > PCAP_BUF_SIZE
)
89 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The source string is too long. Cannot handle it correctly.");
94 * Determine the type of the source (file, local, remote)
95 * There are some differences if pcap_findalldevs_ex() is called to list files and remote adapters.
96 * In the first case, the name of the directory we have to look into must be present (therefore
97 * the 'name' parameter of the pcap_parsesrcstr() is present).
98 * In the second case, the name of the adapter is not required (we need just the host). So, we have
99 * to use a first time this function to get the source type, and a second time to get the appropriate
100 * info, which depends on the source type.
102 if (pcap_parsesrcstr(source
, &type
, NULL
, NULL
, NULL
, errbuf
) == -1)
107 case PCAP_SRC_IFLOCAL
:
108 if (pcap_parsesrcstr(source
, &type
, NULL
, NULL
, NULL
, errbuf
) == -1)
111 /* Initialize temporary string */
112 tmpstring
[PCAP_BUF_SIZE
] = 0;
114 /* The user wants to retrieve adapters from a local host */
115 if (pcap_findalldevs(alldevs
, errbuf
) == -1)
118 if (*alldevs
== NULL
)
120 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
,
121 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
122 " on the local machine.");
126 /* Scan all the interfaces and modify name and description */
127 /* This is a trick in order to avoid the re-implementation of the pcap_findalldevs here */
131 char *localdesc
, *desc
;
133 /* Create the new device identifier */
134 if (pcap_createsrcstr(tmpstring
, PCAP_SRC_IFLOCAL
, NULL
, NULL
, dev
->name
, errbuf
) == -1)
137 /* Delete the old pointer */
140 /* Make a copy of the new device identifier */
141 dev
->name
= strdup(tmpstring
);
142 if (dev
->name
== NULL
)
144 pcap_fmt_errmsg_for_errno(errbuf
,
145 PCAP_ERRBUF_SIZE
, errno
,
147 pcap_freealldevs(*alldevs
);
152 * Create the description.
153 * First, allocate a buffer large enough
156 if ((dev
->description
== NULL
) || (dev
->description
[0] == 0))
157 localdesc
= dev
->name
;
159 localdesc
= dev
->description
;
160 stringlen
= PCAP_TEXT_SOURCE_ADAPTER_LEN
161 + 1 + 1 /* space and ' */
163 + 1 + 1 /* ' and space */
164 + PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN
165 + 1; /* terminating '\0' */
166 desc
= (char *)malloc(stringlen
);
169 pcap_fmt_errmsg_for_errno(errbuf
,
170 PCAP_ERRBUF_SIZE
, errno
,
172 pcap_freealldevs(*alldevs
);
175 pcap_snprintf(desc
, stringlen
, "%s '%s' %s",
176 PCAP_TEXT_SOURCE_ADAPTER
, localdesc
,
177 PCAP_TEXT_SOURCE_ON_LOCAL_HOST
);
179 /* Now overwrite the description */
180 free(dev
->description
);
181 dev
->description
= desc
;
191 WIN32_FIND_DATA filedata
;
194 struct dirent
*filedata
;
198 if (pcap_parsesrcstr(source
, &type
, NULL
, NULL
, name
, errbuf
) == -1)
201 /* Check that the filename is correct */
202 stringlen
= strlen(name
);
204 /* The directory must end with '\' in Win32 and '/' in UNIX */
206 #define ENDING_CHAR '\\'
208 #define ENDING_CHAR '/'
211 if (name
[stringlen
- 1] != ENDING_CHAR
)
213 name
[stringlen
] = ENDING_CHAR
;
214 name
[stringlen
+ 1] = 0;
219 /* Save the path for future reference */
220 pcap_snprintf(path
, sizeof(path
), "%s", name
);
221 pathlen
= strlen(path
);
224 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */
225 if (name
[stringlen
- 1] != '*')
227 name
[stringlen
] = '*';
228 name
[stringlen
+ 1] = 0;
231 filehandle
= FindFirstFile(name
, &filedata
);
233 if (filehandle
== INVALID_HANDLE_VALUE
)
235 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error when listing files: does folder '%s' exist?", path
);
240 /* opening the folder */
241 unixdir
= opendir(path
);
243 /* get the first file into it */
244 filedata
= readdir(unixdir
);
246 if (filedata
== NULL
)
248 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "Error when listing files: does folder '%s' exist?", path
);
253 /* Add all files we find to the list. */
257 /* Skip the file if the pathname won't fit in the buffer */
258 if (pathlen
+ strlen(filedata
.cFileName
) >= sizeof(filename
))
260 pcap_snprintf(filename
, sizeof(filename
), "%s%s", path
, filedata
.cFileName
);
262 if (pathlen
+ strlen(filedata
->d_name
) >= sizeof(filename
))
264 pcap_snprintf(filename
, sizeof(filename
), "%s%s", path
, filedata
->d_name
);
267 fp
= pcap_open_offline(filename
, errbuf
);
271 /* allocate the main structure */
272 dev
= (pcap_if_t
*)malloc(sizeof(pcap_if_t
));
275 pcap_fmt_errmsg_for_errno(errbuf
,
276 PCAP_ERRBUF_SIZE
, errno
,
278 pcap_freealldevs(*alldevs
);
282 /* Initialize the structure to 'zero' */
283 memset(dev
, 0, sizeof(pcap_if_t
));
285 /* Append it to the list. */
289 * List is empty, so it's also
297 * Append after the last device.
301 /* It's now the last device. */
304 /* Create the new source identifier */
305 if (pcap_createsrcstr(tmpstring
, PCAP_SRC_FILE
, NULL
, NULL
, filename
, errbuf
) == -1)
307 pcap_freealldevs(*alldevs
);
311 dev
->name
= strdup(tmpstring
);
312 if (dev
->name
== NULL
)
314 pcap_fmt_errmsg_for_errno(errbuf
,
315 PCAP_ERRBUF_SIZE
, errno
,
317 pcap_freealldevs(*alldevs
);
322 * Create the description.
323 * First, allocate a buffer large enough
326 stringlen
= PCAP_TEXT_SOURCE_FILE_LEN
327 + 1 + 1 /* space and ' */
329 + 1 + 1 /* ' and space */
330 + PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN
331 + 1; /* terminating '\0' */
332 dev
->description
= (char *)malloc(stringlen
);
333 if (dev
->description
== NULL
)
335 pcap_fmt_errmsg_for_errno(errbuf
,
336 PCAP_ERRBUF_SIZE
, errno
,
338 pcap_freealldevs(*alldevs
);
343 * Now format the new device description
346 pcap_snprintf(dev
->description
, stringlen
,
347 "%s '%s' %s", PCAP_TEXT_SOURCE_FILE
,
348 filename
, PCAP_TEXT_SOURCE_ON_LOCAL_HOST
);
354 while (FindNextFile(filehandle
, &filedata
) != 0);
356 while ( (filedata
= readdir(unixdir
)) != NULL
);
361 /* Close the search handle. */
362 FindClose(filehandle
);
368 case PCAP_SRC_IFREMOTE
:
369 return pcap_findalldevs_ex_remote(source
, auth
, alldevs
, errbuf
);
372 pcap_strlcpy(errbuf
, "Source type not supported", PCAP_ERRBUF_SIZE
);
377 pcap_t
*pcap_open(const char *source
, int snaplen
, int flags
, int read_timeout
, struct pcap_rmtauth
*auth
, char *errbuf
)
379 char name
[PCAP_BUF_SIZE
];
384 if (strlen(source
) > PCAP_BUF_SIZE
)
386 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "The source string is too long. Cannot handle it correctly.");
391 * Determine the type of the source (file, local, remote) and,
392 * if it's file or local, the name of the file or capture device.
394 if (pcap_parsesrcstr(source
, &type
, NULL
, NULL
, name
, errbuf
) == -1)
400 return pcap_open_offline(name
, errbuf
);
402 case PCAP_SRC_IFLOCAL
:
403 fp
= pcap_create(name
, errbuf
);
406 case PCAP_SRC_IFREMOTE
:
408 * Although we already have host, port and iface, we prefer
409 * to pass only 'source' to pcap_open_rpcap(), so that it
410 * has to call pcap_parsesrcstr() again.
411 * This is less optimized, but much clearer.
413 return pcap_open_rpcap(source
, snaplen
, flags
, read_timeout
, auth
, errbuf
);
416 pcap_strlcpy(errbuf
, "Source type not supported", PCAP_ERRBUF_SIZE
);
422 status
= pcap_set_snaplen(fp
, snaplen
);
425 if (flags
& PCAP_OPENFLAG_PROMISCUOUS
)
427 status
= pcap_set_promisc(fp
, 1);
431 if (flags
& PCAP_OPENFLAG_MAX_RESPONSIVENESS
)
433 status
= pcap_set_immediate_mode(fp
, 1);
439 * This flag is supported on Windows only.
440 * XXX - is there a way to support it with
441 * the capture mechanisms on UN*X? It's not
442 * exactly a "set direction" operation; I
443 * think it means "do not capture packets
444 * injected with pcap_sendpacket() or
447 /* disable loopback capture if requested */
448 if (flags
& PCAP_OPENFLAG_NOCAPTURE_LOCAL
)
449 fp
->opt
.nocapture_local
= 1;
451 status
= pcap_set_timeout(fp
, read_timeout
);
454 status
= pcap_activate(fp
);
460 if (status
== PCAP_ERROR
)
461 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "%s: %s",
463 else if (status
== PCAP_ERROR_NO_SUCH_DEVICE
||
464 status
== PCAP_ERROR_PERM_DENIED
||
465 status
== PCAP_ERROR_PROMISC_PERM_DENIED
)
466 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "%s: %s (%s)",
467 name
, pcap_statustostr(status
), fp
->errbuf
);
469 pcap_snprintf(errbuf
, PCAP_ERRBUF_SIZE
, "%s: %s",
470 name
, pcap_statustostr(status
));
475 struct pcap_samp
*pcap_setsampling(pcap_t
*p
)