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