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