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.5.2.1 2005/04/19 00:54:16 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 SIOCLGIFCONF
79 * but don't have "getifaddrs()". (Solaris 8 and later; we use
80 * SIOCLGIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
81 */
82 int
pcap_findalldevs(pcap_if_t ** alldevsp,char * errbuf)83 pcap_findalldevs(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 haven't had any errors yet; do any platform-specific
368 * operations to add devices.
369 */
370 if (pcap_platform_finddevs(&devlist, errbuf) < 0)
371 ret = -1;
372 }
373
374 if (ret == -1) {
375 /*
376 * We had an error; free the list we've been constructing.
377 */
378 if (devlist != NULL) {
379 pcap_freealldevs(devlist);
380 devlist = NULL;
381 }
382 }
383
384 *alldevsp = devlist;
385 return (ret);
386 }
387