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