1 /* $NetBSD: fad-glifc.c,v 1.2 2014/11/19 19:33:30 christos Exp $ */
2
3 /* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
4 /*
5 * Copyright (c) 1994, 1995, 1996, 1997, 1998
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the Computer Systems
19 * Engineering Group at Lawrence Berkeley Laboratory.
20 * 4. Neither the name of the University nor of the Laboratory may be used
21 * to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 __RCSID("$NetBSD: fad-glifc.c,v 1.2 2014/11/19 19:33:30 christos Exp $");
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
pcap_findalldevs_interfaces(pcap_if_t ** alldevsp,char * errbuf)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.
212 */
213 strncpy(ifrflags.lifr_name, ifrp->lifr_name,
214 sizeof(ifrflags.lifr_name));
215 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
216 if (errno == ENXIO)
217 continue;
218 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
219 "SIOCGLIFFLAGS: %.*s: %s",
220 (int)sizeof(ifrflags.lifr_name),
221 ifrflags.lifr_name,
222 pcap_strerror(errno));
223 ret = -1;
224 break;
225 }
226
227 /*
228 * Get the netmask for this address on this interface.
229 */
230 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
231 sizeof(ifrnetmask.lifr_name));
232 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
233 sizeof(ifrnetmask.lifr_addr));
234 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
235 if (errno == EADDRNOTAVAIL) {
236 /*
237 * Not available.
238 */
239 netmask = NULL;
240 } else {
241 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
242 "SIOCGLIFNETMASK: %.*s: %s",
243 (int)sizeof(ifrnetmask.lifr_name),
244 ifrnetmask.lifr_name,
245 pcap_strerror(errno));
246 ret = -1;
247 break;
248 }
249 } else
250 netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
251
252 /*
253 * Get the broadcast address for this address on this
254 * interface (if any).
255 */
256 if (ifrflags.lifr_flags & IFF_BROADCAST) {
257 strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
258 sizeof(ifrbroadaddr.lifr_name));
259 memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
260 sizeof(ifrbroadaddr.lifr_addr));
261 if (ioctl(fd, SIOCGLIFBRDADDR,
262 (char *)&ifrbroadaddr) < 0) {
263 if (errno == EADDRNOTAVAIL) {
264 /*
265 * Not available.
266 */
267 broadaddr = NULL;
268 } else {
269 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
270 "SIOCGLIFBRDADDR: %.*s: %s",
271 (int)sizeof(ifrbroadaddr.lifr_name),
272 ifrbroadaddr.lifr_name,
273 pcap_strerror(errno));
274 ret = -1;
275 break;
276 }
277 } else
278 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
279 } else {
280 /*
281 * Not a broadcast interface, so no broadcast
282 * address.
283 */
284 broadaddr = NULL;
285 }
286
287 /*
288 * Get the destination address for this address on this
289 * interface (if any).
290 */
291 if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
292 strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
293 sizeof(ifrdstaddr.lifr_name));
294 memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
295 sizeof(ifrdstaddr.lifr_addr));
296 if (ioctl(fd, SIOCGLIFDSTADDR,
297 (char *)&ifrdstaddr) < 0) {
298 if (errno == EADDRNOTAVAIL) {
299 /*
300 * Not available.
301 */
302 dstaddr = NULL;
303 } else {
304 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
305 "SIOCGLIFDSTADDR: %.*s: %s",
306 (int)sizeof(ifrdstaddr.lifr_name),
307 ifrdstaddr.lifr_name,
308 pcap_strerror(errno));
309 ret = -1;
310 break;
311 }
312 } else
313 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
314 } else
315 dstaddr = NULL;
316
317 #ifdef HAVE_SOLARIS
318 /*
319 * If this entry has a colon followed by a number at
320 * the end, it's a logical interface. Those are just
321 * the way you assign multiple IP addresses to a real
322 * interface, so an entry for a logical interface should
323 * be treated like the entry for the real interface;
324 * we do that by stripping off the ":" and the number.
325 */
326 p = strchr(ifrp->lifr_name, ':');
327 if (p != NULL) {
328 /*
329 * We have a ":"; is it followed by a number?
330 */
331 q = p + 1;
332 while (isdigit((unsigned char)*q))
333 q++;
334 if (*q == '\0') {
335 /*
336 * All digits after the ":" until the end.
337 * Strip off the ":" and everything after
338 * it.
339 */
340 *p = '\0';
341 }
342 }
343 #endif
344
345 /*
346 * Add information for this address to the list.
347 */
348 if (add_addr_to_iflist(&devlist, ifrp->lifr_name,
349 ifrflags.lifr_flags, (struct sockaddr *)&ifrp->lifr_addr,
350 sizeof (struct sockaddr_storage),
351 netmask, sizeof (struct sockaddr_storage),
352 broadaddr, sizeof (struct sockaddr_storage),
353 dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
354 ret = -1;
355 break;
356 }
357 }
358 free(buf);
359 (void)close(fd6);
360 (void)close(fd4);
361
362 if (ret == -1) {
363 /*
364 * We had an error; free the list we've been constructing.
365 */
366 if (devlist != NULL) {
367 pcap_freealldevs(devlist);
368 devlist = NULL;
369 }
370 }
371
372 *alldevsp = devlist;
373 return (ret);
374 }
375