]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libpcap/pcap-new.c
Remove spurious newline
[FreeBSD/FreeBSD.git] / contrib / 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 /* 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
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
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
451 struct pcap_samp *pcap_setsampling(pcap_t *p)
452 {
453         return &p->rmt_samp;
454 }