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