]> The Tcpdump Group git mirrors - libpcap/blob - pcap-new.c
c4d35d186781a89e57716465e22e91f2fe5a855e
[libpcap] / pcap-new.c
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 #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)
61
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)
65
66 /****************************************************
67 * *
68 * Function bodies *
69 * *
70 ****************************************************/
71
72 int pcap_findalldevs_ex(const char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf)
73 {
74 int type;
75 char name[PCAP_BUF_SIZE], path[PCAP_BUF_SIZE], filename[PCAP_BUF_SIZE];
76 size_t pathlen;
77 size_t stringlen;
78 pcap_t *fp;
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 */
82
83 /* List starts out empty. */
84 (*alldevs) = NULL;
85 lastdev = NULL;
86
87 if (strlen(source) > PCAP_BUF_SIZE)
88 {
89 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
90 return -1;
91 }
92
93 /*
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.
101 */
102 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
103 return -1;
104
105 switch (type)
106 {
107 case PCAP_SRC_IFLOCAL:
108 if (pcap_parsesrcstr(source, &type, NULL, NULL, NULL, errbuf) == -1)
109 return -1;
110
111 /* Initialize temporary string */
112 tmpstring[PCAP_BUF_SIZE] = 0;
113
114 /* The user wants to retrieve adapters from a local host */
115 if (pcap_findalldevs(alldevs, errbuf) == -1)
116 return -1;
117
118 if (*alldevs == NULL)
119 {
120 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
121 "No interfaces found! Make sure libpcap/WinPcap is properly installed"
122 " on the local machine.");
123 return -1;
124 }
125
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 */
128 dev = *alldevs;
129 while (dev)
130 {
131 char *localdesc, *desc;
132
133 /* Create the new device identifier */
134 if (pcap_createsrcstr(tmpstring, PCAP_SRC_IFLOCAL, NULL, NULL, dev->name, errbuf) == -1)
135 return -1;
136
137 /* Delete the old pointer */
138 free(dev->name);
139
140 /* Make a copy of the new device identifier */
141 dev->name = strdup(tmpstring);
142 if (dev->name == NULL)
143 {
144 pcap_fmt_errmsg_for_errno(errbuf,
145 PCAP_ERRBUF_SIZE, errno,
146 "malloc() failed");
147 pcap_freealldevs(*alldevs);
148 return -1;
149 }
150
151 /*
152 * Create the description.
153 * First, allocate a buffer large enough
154 * for the name.
155 */
156 if ((dev->description == NULL) || (dev->description[0] == 0))
157 localdesc = dev->name;
158 else
159 localdesc = dev->description;
160 stringlen = PCAP_TEXT_SOURCE_ADAPTER_LEN
161 + 1 + 1 /* space and ' */
162 + strlen(localdesc)
163 + 1 + 1 /* ' and space */
164 + PCAP_TEXT_SOURCE_ON_LOCAL_HOST_LEN
165 + 1; /* terminating '\0' */
166 desc = (char *)malloc(stringlen);
167 if (desc == NULL)
168 {
169 pcap_fmt_errmsg_for_errno(errbuf,
170 PCAP_ERRBUF_SIZE, errno,
171 "malloc() failed");
172 pcap_freealldevs(*alldevs);
173 return -1;
174 }
175 pcap_snprintf(desc, stringlen, "%s '%s' %s",
176 PCAP_TEXT_SOURCE_ADAPTER, localdesc,
177 PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
178
179 /* Now overwrite the description */
180 free(dev->description);
181 dev->description = desc;
182
183 dev = dev->next;
184 }
185
186 return 0;
187
188 case PCAP_SRC_FILE:
189 {
190 #ifdef _WIN32
191 WIN32_FIND_DATA filedata;
192 HANDLE filehandle;
193 #else
194 struct dirent *filedata;
195 DIR *unixdir;
196 #endif
197
198 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
199 return -1;
200
201 /* Check that the filename is correct */
202 stringlen = strlen(name);
203
204 /* The directory must end with '\' in Win32 and '/' in UNIX */
205 #ifdef _WIN32
206 #define ENDING_CHAR '\\'
207 #else
208 #define ENDING_CHAR '/'
209 #endif
210
211 if (name[stringlen - 1] != ENDING_CHAR)
212 {
213 name[stringlen] = ENDING_CHAR;
214 name[stringlen + 1] = 0;
215
216 stringlen++;
217 }
218
219 /* Save the path for future reference */
220 pcap_snprintf(path, sizeof(path), "%s", name);
221 pathlen = strlen(path);
222
223 #ifdef _WIN32
224 /* To perform directory listing, Win32 must have an 'asterisk' as ending char */
225 if (name[stringlen - 1] != '*')
226 {
227 name[stringlen] = '*';
228 name[stringlen + 1] = 0;
229 }
230
231 filehandle = FindFirstFile(name, &filedata);
232
233 if (filehandle == INVALID_HANDLE_VALUE)
234 {
235 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
236 return -1;
237 }
238
239 #else
240 /* opening the folder */
241 unixdir= opendir(path);
242
243 /* get the first file into it */
244 filedata= readdir(unixdir);
245
246 if (filedata == NULL)
247 {
248 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "Error when listing files: does folder '%s' exist?", path);
249 return -1;
250 }
251 #endif
252
253 /* Add all files we find to the list. */
254 do
255 {
256 #ifdef _WIN32
257 /* Skip the file if the pathname won't fit in the buffer */
258 if (pathlen + strlen(filedata.cFileName) >= sizeof(filename))
259 continue;
260 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
261 #else
262 if (pathlen + strlen(filedata->d_name) >= sizeof(filename))
263 continue;
264 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata->d_name);
265 #endif
266
267 fp = pcap_open_offline(filename, errbuf);
268
269 if (fp)
270 {
271 /* allocate the main structure */
272 dev = (pcap_if_t *)malloc(sizeof(pcap_if_t));
273 if (dev == NULL)
274 {
275 pcap_fmt_errmsg_for_errno(errbuf,
276 PCAP_ERRBUF_SIZE, errno,
277 "malloc() failed");
278 pcap_freealldevs(*alldevs);
279 return -1;
280 }
281
282 /* Initialize the structure to 'zero' */
283 memset(dev, 0, sizeof(pcap_if_t));
284
285 /* Append it to the list. */
286 if (lastdev == NULL)
287 {
288 /*
289 * List is empty, so it's also
290 * the first device.
291 */
292 *alldevs = dev;
293 }
294 else
295 {
296 /*
297 * Append after the last device.
298 */
299 lastdev->next = dev;
300 }
301 /* It's now the last device. */
302 lastdev = dev;
303
304 /* Create the new source identifier */
305 if (pcap_createsrcstr(tmpstring, PCAP_SRC_FILE, NULL, NULL, filename, errbuf) == -1)
306 {
307 pcap_freealldevs(*alldevs);
308 return -1;
309 }
310
311 dev->name = strdup(tmpstring);
312 if (dev->name == NULL)
313 {
314 pcap_fmt_errmsg_for_errno(errbuf,
315 PCAP_ERRBUF_SIZE, errno,
316 "malloc() failed");
317 pcap_freealldevs(*alldevs);
318 return -1;
319 }
320
321 /*
322 * Create the description.
323 * First, allocate a buffer large enough
324 * for the name.
325 */
326 stringlen = PCAP_TEXT_SOURCE_FILE_LEN
327 + 1 + 1 /* space and ' */
328 + strlen(filename)
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)
334 {
335 pcap_fmt_errmsg_for_errno(errbuf,
336 PCAP_ERRBUF_SIZE, errno,
337 "malloc() failed");
338 pcap_freealldevs(*alldevs);
339 return -1;
340 }
341
342 /*
343 * Now format the new device description
344 * into that buffer.
345 */
346 pcap_snprintf(dev->description, stringlen,
347 "%s '%s' %s", PCAP_TEXT_SOURCE_FILE,
348 filename, PCAP_TEXT_SOURCE_ON_LOCAL_HOST);
349
350 pcap_close(fp);
351 }
352 }
353 #ifdef _WIN32
354 while (FindNextFile(filehandle, &filedata) != 0);
355 #else
356 while ( (filedata= readdir(unixdir)) != NULL);
357 #endif
358
359
360 #ifdef _WIN32
361 /* Close the search handle. */
362 FindClose(filehandle);
363 #endif
364
365 return 0;
366 }
367
368 case PCAP_SRC_IFREMOTE:
369 return pcap_findalldevs_ex_remote(source, auth, alldevs, errbuf);
370
371 default:
372 pcap_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
373 return -1;
374 }
375 }
376
377 pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf)
378 {
379 char name[PCAP_BUF_SIZE];
380 int type;
381 pcap_t *fp;
382 int status;
383
384 if (strlen(source) > PCAP_BUF_SIZE)
385 {
386 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
387 return NULL;
388 }
389
390 /*
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.
393 */
394 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
395 return NULL;
396
397 switch (type)
398 {
399 case PCAP_SRC_FILE:
400 return pcap_open_offline(name, errbuf);
401
402 case PCAP_SRC_IFLOCAL:
403 fp = pcap_create(name, errbuf);
404 break;
405
406 case PCAP_SRC_IFREMOTE:
407 /*
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.
412 */
413 return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf);
414
415 default:
416 pcap_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
417 return NULL;
418 }
419
420 if (fp == NULL)
421 return (NULL);
422 status = pcap_set_snaplen(fp, snaplen);
423 if (status < 0)
424 goto fail;
425 if (flags & PCAP_OPENFLAG_PROMISCUOUS)
426 {
427 status = pcap_set_promisc(fp, 1);
428 if (status < 0)
429 goto fail;
430 }
431 if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS)
432 {
433 status = pcap_set_immediate_mode(fp, 1);
434 if (status < 0)
435 goto fail;
436 }
437 #ifdef _WIN32
438 /*
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
445 * pcap_inject()".
446 */
447 /* disable loopback capture if requested */
448 if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
449 fp->opt.nocapture_local = 1;
450 #endif /* _WIN32 */
451 status = pcap_set_timeout(fp, read_timeout);
452 if (status < 0)
453 goto fail;
454 status = pcap_activate(fp);
455 if (status < 0)
456 goto fail;
457 return fp;
458
459 fail:
460 if (status == PCAP_ERROR)
461 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
462 name, fp->errbuf);
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);
468 else
469 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
470 name, pcap_statustostr(status));
471 pcap_close(fp);
472 return NULL;
473 }
474
475 struct pcap_samp *pcap_setsampling(pcap_t *p)
476 {
477 return &p->rmt_samp;
478 }