]> The Tcpdump Group git mirrors - libpcap/blob - pcap-new.c
Make sure asprintf() is declared if it's present.
[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 #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
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 pcap_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 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE,
123 "No interfaces found! Make sure libpcap/WinPcap 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 pcap_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 pcap_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 pcap_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 pcap_snprintf(filename, sizeof(filename), "%s%s", path, filedata.cFileName);
253 #else
254 if (pathlen + strlen(filedata->d_name) >= sizeof(filename))
255 continue;
256 pcap_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
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 if (strlen(source) > PCAP_BUF_SIZE)
362 {
363 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "The source string is too long. Cannot handle it correctly.");
364 return NULL;
365 }
366
367 /*
368 * Determine the type of the source (file, local, remote) and,
369 * if it's file or local, the name of the file or capture device.
370 */
371 if (pcap_parsesrcstr(source, &type, NULL, NULL, name, errbuf) == -1)
372 return NULL;
373
374 switch (type)
375 {
376 case PCAP_SRC_FILE:
377 return pcap_open_offline(name, errbuf);
378
379 case PCAP_SRC_IFLOCAL:
380 fp = pcap_create(name, errbuf);
381 break;
382
383 case PCAP_SRC_IFREMOTE:
384 /*
385 * Although we already have host, port and iface, we prefer
386 * to pass only 'source' to pcap_open_rpcap(), so that it
387 * has to call pcap_parsesrcstr() again.
388 * This is less optimized, but much clearer.
389 */
390 return pcap_open_rpcap(source, snaplen, flags, read_timeout, auth, errbuf);
391
392 default:
393 pcap_strlcpy(errbuf, "Source type not supported", PCAP_ERRBUF_SIZE);
394 return NULL;
395 }
396
397 if (fp == NULL)
398 return (NULL);
399 status = pcap_set_snaplen(fp, snaplen);
400 if (status < 0)
401 goto fail;
402 if (flags & PCAP_OPENFLAG_PROMISCUOUS)
403 {
404 status = pcap_set_promisc(fp, 1);
405 if (status < 0)
406 goto fail;
407 }
408 if (flags & PCAP_OPENFLAG_MAX_RESPONSIVENESS)
409 {
410 status = pcap_set_immediate_mode(fp, 1);
411 if (status < 0)
412 goto fail;
413 }
414 #ifdef _WIN32
415 /*
416 * This flag is supported on Windows only.
417 * XXX - is there a way to support it with
418 * the capture mechanisms on UN*X? It's not
419 * exactly a "set direction" operation; I
420 * think it means "do not capture packets
421 * injected with pcap_sendpacket() or
422 * pcap_inject()".
423 */
424 /* disable loopback capture if requested */
425 if (flags & PCAP_OPENFLAG_NOCAPTURE_LOCAL)
426 fp->opt.nocapture_local = 1;
427 #endif /* _WIN32 */
428 status = pcap_set_timeout(fp, read_timeout);
429 if (status < 0)
430 goto fail;
431 status = pcap_activate(fp);
432 if (status < 0)
433 goto fail;
434 return fp;
435
436 fail:
437 if (status == PCAP_ERROR)
438 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
439 name, fp->errbuf);
440 else if (status == PCAP_ERROR_NO_SUCH_DEVICE ||
441 status == PCAP_ERROR_PERM_DENIED ||
442 status == PCAP_ERROR_PROMISC_PERM_DENIED)
443 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)",
444 name, pcap_statustostr(status), fp->errbuf);
445 else
446 pcap_snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s",
447 name, pcap_statustostr(status));
448 pcap_close(fp);
449 return NULL;
450 }
451
452 struct pcap_samp *pcap_setsampling(pcap_t *p)
453 {
454 return &p->rmt_samp;
455 }