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