]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/libpcap/fad-glifc.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / libpcap / fad-glifc.c
1 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
2 /*
3  * Copyright (c) 1994, 1995, 1996, 1997, 1998
4  *      The Regents of the University of California.  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  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by the Computer Systems
17  *      Engineering Group at Lawrence Berkeley Laboratory.
18  * 4. Neither the name of the University nor of the Laboratory may be used
19  *    to endorse or promote products derived from this software without
20  *    specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #ifndef lint
36 static const char rcsid[] _U_ =
37     "@(#) $Header: /tcpdump/master/libpcap/fad-glifc.c,v 1.7 2008-01-30 09:35:48 guy Exp $ (LBL)";
38 #endif
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #include <sys/param.h>
45 #include <sys/file.h>
46 #include <sys/ioctl.h>
47 #include <sys/socket.h>
48 #ifdef HAVE_SYS_SOCKIO_H
49 #include <sys/sockio.h>
50 #endif
51 #include <sys/time.h>                           /* concession to AIX */
52
53 struct mbuf;            /* Squelch compiler warnings on some platforms for */
54 struct rtentry;         /* declarations in <net/if.h> */
55 #include <net/if.h>
56 #include <netinet/in.h>
57
58 #include <ctype.h>
59 #include <errno.h>
60 #include <memory.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <unistd.h>
65
66 #include "pcap-int.h"
67
68 #ifdef HAVE_OS_PROTO_H
69 #include "os-proto.h"
70 #endif
71
72 /*
73  * Get a list of all interfaces that are up and that we can open.
74  * Returns -1 on error, 0 otherwise.
75  * The list, as returned through "alldevsp", may be null if no interfaces
76  * were up and could be opened.
77  *
78  * This is the implementation used on platforms that have SIOCGLIFCONF
79  * but don't have "getifaddrs()".  (Solaris 8 and later; we use
80  * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
81  */
82 int
83 pcap_findalldevs_interfaces(pcap_if_t **alldevsp, char *errbuf)
84 {
85         pcap_if_t *devlist = NULL;
86         register int fd4, fd6, fd;
87         register struct lifreq *ifrp, *ifend;
88         struct lifnum ifn;
89         struct lifconf ifc;
90         char *buf = NULL;
91         unsigned buf_size;
92 #ifdef HAVE_SOLARIS
93         char *p, *q;
94 #endif
95         struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
96         struct sockaddr *netmask, *broadaddr, *dstaddr;
97         int ret = 0;
98
99         /*
100          * Create a socket from which to fetch the list of interfaces,
101          * and from which to fetch IPv4 information.
102          */
103         fd4 = socket(AF_INET, SOCK_DGRAM, 0);
104         if (fd4 < 0) {
105                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
106                     "socket: %s", pcap_strerror(errno));
107                 return (-1);
108         }
109
110         /*
111          * Create a socket from which to fetch IPv6 information.
112          */
113         fd6 = socket(AF_INET6, SOCK_DGRAM, 0);
114         if (fd6 < 0) {
115                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
116                     "socket: %s", pcap_strerror(errno));
117                 (void)close(fd4);
118                 return (-1);
119         }
120
121         /*
122          * How many entries will SIOCGLIFCONF return?
123          */
124         ifn.lifn_family = AF_UNSPEC;
125         ifn.lifn_flags = 0;
126         ifn.lifn_count = 0;
127         if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) {
128                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
129                     "SIOCGLIFNUM: %s", pcap_strerror(errno));
130                 (void)close(fd6);
131                 (void)close(fd4);
132                 return (-1);
133         }
134
135         /*
136          * Allocate a buffer for those entries.
137          */
138         buf_size = ifn.lifn_count * sizeof (struct lifreq);
139         buf = malloc(buf_size);
140         if (buf == NULL) {
141                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
142                     "malloc: %s", pcap_strerror(errno));
143                 (void)close(fd6);
144                 (void)close(fd4);
145                 return (-1);
146         }
147
148         /*
149          * Get the entries.
150          */
151         ifc.lifc_len = buf_size;
152         ifc.lifc_buf = buf;
153         ifc.lifc_family = AF_UNSPEC;
154         ifc.lifc_flags = 0;
155         memset(buf, 0, buf_size);
156         if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) {
157                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
158                     "SIOCGLIFCONF: %s", pcap_strerror(errno));
159                 (void)close(fd6);
160                 (void)close(fd4);
161                 free(buf);
162                 return (-1);
163         }
164
165         /*
166          * Loop over the entries.
167          */
168         ifrp = (struct lifreq *)buf;
169         ifend = (struct lifreq *)(buf + ifc.lifc_len);
170
171         for (; ifrp < ifend; ifrp++) {
172                 /*
173                  * IPv6 or not?
174                  */
175                 if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
176                         fd = fd6;
177                 else
178                         fd = fd4;
179
180                 /*
181                  * Skip entries that begin with "dummy".
182                  * XXX - what are these?  Is this Linux-specific?
183                  * Are there platforms on which we shouldn't do this?
184                  */
185                 if (strncmp(ifrp->lifr_name, "dummy", 5) == 0)
186                         continue;
187
188 #ifdef HAVE_SOLARIS
189                 /*
190                  * Skip entries that have a ":" followed by a number
191                  * at the end - those are Solaris virtual interfaces
192                  * on which you can't capture.
193                  */
194                 p = strchr(ifrp->lifr_name, ':');
195                 if (p != NULL) {
196                         /*
197                          * We have a ":"; is it followed by a number?
198                          */
199                         while (isdigit((unsigned char)*p))
200                                 p++;
201                         if (*p == '\0') {
202                                 /*
203                                  * All digits after the ":" until the end.
204                                  */
205                                 continue;
206                         }
207                 }
208 #endif
209
210                 /*
211                  * Get the flags for this interface, and skip it if it's
212                  * not up.
213                  */
214                 strncpy(ifrflags.lifr_name, ifrp->lifr_name,
215                     sizeof(ifrflags.lifr_name));
216                 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
217                         if (errno == ENXIO)
218                                 continue;
219                         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
220                             "SIOCGLIFFLAGS: %.*s: %s",
221                             (int)sizeof(ifrflags.lifr_name),
222                             ifrflags.lifr_name,
223                             pcap_strerror(errno));
224                         ret = -1;
225                         break;
226                 }
227                 if (!(ifrflags.lifr_flags & IFF_UP))
228                         continue;
229
230                 /*
231                  * Get the netmask for this address on this interface.
232                  */
233                 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
234                     sizeof(ifrnetmask.lifr_name));
235                 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
236                     sizeof(ifrnetmask.lifr_addr));
237                 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
238                         if (errno == EADDRNOTAVAIL) {
239                                 /*
240                                  * Not available.
241                                  */
242                                 netmask = NULL;
243                         } else {
244                                 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
245                                     "SIOCGLIFNETMASK: %.*s: %s",
246                                     (int)sizeof(ifrnetmask.lifr_name),
247                                     ifrnetmask.lifr_name,
248                                     pcap_strerror(errno));
249                                 ret = -1;
250                                 break;
251                         }
252                 } else
253                         netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
254
255                 /*
256                  * Get the broadcast address for this address on this
257                  * interface (if any).
258                  */
259                 if (ifrflags.lifr_flags & IFF_BROADCAST) {
260                         strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
261                             sizeof(ifrbroadaddr.lifr_name));
262                         memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
263                             sizeof(ifrbroadaddr.lifr_addr));
264                         if (ioctl(fd, SIOCGLIFBRDADDR,
265                             (char *)&ifrbroadaddr) < 0) {
266                                 if (errno == EADDRNOTAVAIL) {
267                                         /*
268                                          * Not available.
269                                          */
270                                         broadaddr = NULL;
271                                 } else {
272                                         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
273                                             "SIOCGLIFBRDADDR: %.*s: %s",
274                                             (int)sizeof(ifrbroadaddr.lifr_name),
275                                             ifrbroadaddr.lifr_name,
276                                             pcap_strerror(errno));
277                                         ret = -1;
278                                         break;
279                                 }
280                         } else
281                                 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
282                 } else {
283                         /*
284                          * Not a broadcast interface, so no broadcast
285                          * address.
286                          */
287                         broadaddr = NULL;
288                 }
289
290                 /*
291                  * Get the destination address for this address on this
292                  * interface (if any).
293                  */
294                 if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
295                         strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
296                             sizeof(ifrdstaddr.lifr_name));
297                         memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
298                             sizeof(ifrdstaddr.lifr_addr));
299                         if (ioctl(fd, SIOCGLIFDSTADDR,
300                             (char *)&ifrdstaddr) < 0) {
301                                 if (errno == EADDRNOTAVAIL) {
302                                         /*
303                                          * Not available.
304                                          */
305                                         dstaddr = NULL;
306                                 } else {
307                                         (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
308                                             "SIOCGLIFDSTADDR: %.*s: %s",
309                                             (int)sizeof(ifrdstaddr.lifr_name),
310                                             ifrdstaddr.lifr_name,
311                                             pcap_strerror(errno));
312                                         ret = -1;
313                                         break;
314                                 }
315                         } else
316                                 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
317                 } else
318                         dstaddr = NULL;
319
320 #ifdef HAVE_SOLARIS
321                 /*
322                  * If this entry has a colon followed by a number at
323                  * the end, it's a logical interface.  Those are just
324                  * the way you assign multiple IP addresses to a real
325                  * interface, so an entry for a logical interface should
326                  * be treated like the entry for the real interface;
327                  * we do that by stripping off the ":" and the number.
328                  */
329                 p = strchr(ifrp->lifr_name, ':');
330                 if (p != NULL) {
331                         /*
332                          * We have a ":"; is it followed by a number?
333                          */
334                         q = p + 1;
335                         while (isdigit((unsigned char)*q))
336                                 q++;
337                         if (*q == '\0') {
338                                 /*
339                                  * All digits after the ":" until the end.
340                                  * Strip off the ":" and everything after
341                                  * it.
342                                  */
343                                 *p = '\0';
344                         }
345                 }
346 #endif
347
348                 /*
349                  * Add information for this address to the list.
350                  */
351                 if (add_addr_to_iflist(&devlist, ifrp->lifr_name,
352                     ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr,
353                     sizeof (struct sockaddr_storage),
354                     netmask, sizeof (struct sockaddr_storage),
355                     broadaddr, sizeof (struct sockaddr_storage),
356                     dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
357                         ret = -1;
358                         break;
359                 }
360         }
361         free(buf);
362         (void)close(fd6);
363         (void)close(fd4);
364
365         if (ret == -1) {
366                 /*
367                  * We had an error; free the list we've been constructing.
368                  */
369                 if (devlist != NULL) {
370                         pcap_freealldevs(devlist);
371                         devlist = NULL;
372                 }
373         }
374
375         *alldevsp = devlist;
376         return (ret);
377 }