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