1 /* $NetBSD: fad-glifc.c,v 1.4 2018/09/03 15:26:43 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.4 2018/09/03 15:26:43 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_list_t * devlistp,char * errbuf,int (* check_usable)(const char *),get_if_flags_func get_flags_func)83 pcap_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
84 int (*check_usable)(const char *), get_if_flags_func get_flags_func)
85 {
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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
106 errno, "socket: AF_INET");
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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
116 errno, "socket: AF_INET6");
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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
129 errno, "SIOCGLIFNUM");
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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
142 errno, "malloc");
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 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
158 errno, "SIOCGLIFCONF");
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 * Skip entries that begin with "dummy".
174 * XXX - what are these? Is this Linux-specific?
175 * Are there platforms on which we shouldn't do this?
176 */
177 if (strncmp(ifrp->lifr_name, "dummy", 5) == 0)
178 continue;
179
180 /*
181 * Can we capture on this device?
182 */
183 if (!(*check_usable)(ifrp->lifr_name)) {
184 /*
185 * No.
186 */
187 continue;
188 }
189
190 /*
191 * IPv6 or not?
192 */
193 if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
194 fd = fd6;
195 else
196 fd = fd4;
197
198 /*
199 * Get the flags for this interface.
200 */
201 strncpy(ifrflags.lifr_name, ifrp->lifr_name,
202 sizeof(ifrflags.lifr_name));
203 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
204 if (errno == ENXIO)
205 continue;
206 pcap_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
207 errno, "SIOCGLIFFLAGS: %.*s",
208 (int)sizeof(ifrflags.lifr_name),
209 ifrflags.lifr_name);
210 ret = -1;
211 break;
212 }
213
214 /*
215 * Get the netmask for this address on this interface.
216 */
217 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
218 sizeof(ifrnetmask.lifr_name));
219 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
220 sizeof(ifrnetmask.lifr_addr));
221 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
222 if (errno == EADDRNOTAVAIL) {
223 /*
224 * Not available.
225 */
226 netmask = NULL;
227 } else {
228 pcap_fmt_errmsg_for_errno(errbuf,
229 PCAP_ERRBUF_SIZE, errno,
230 "SIOCGLIFNETMASK: %.*s",
231 (int)sizeof(ifrnetmask.lifr_name),
232 ifrnetmask.lifr_name);
233 ret = -1;
234 break;
235 }
236 } else
237 netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
238
239 /*
240 * Get the broadcast address for this address on this
241 * interface (if any).
242 */
243 if (ifrflags.lifr_flags & IFF_BROADCAST) {
244 strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
245 sizeof(ifrbroadaddr.lifr_name));
246 memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
247 sizeof(ifrbroadaddr.lifr_addr));
248 if (ioctl(fd, SIOCGLIFBRDADDR,
249 (char *)&ifrbroadaddr) < 0) {
250 if (errno == EADDRNOTAVAIL) {
251 /*
252 * Not available.
253 */
254 broadaddr = NULL;
255 } else {
256 pcap_fmt_errmsg_for_errno(errbuf,
257 PCAP_ERRBUF_SIZE, errno,
258 "SIOCGLIFBRDADDR: %.*s",
259 (int)sizeof(ifrbroadaddr.lifr_name),
260 ifrbroadaddr.lifr_name);
261 ret = -1;
262 break;
263 }
264 } else
265 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
266 } else {
267 /*
268 * Not a broadcast interface, so no broadcast
269 * address.
270 */
271 broadaddr = NULL;
272 }
273
274 /*
275 * Get the destination address for this address on this
276 * interface (if any).
277 */
278 if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
279 strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
280 sizeof(ifrdstaddr.lifr_name));
281 memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
282 sizeof(ifrdstaddr.lifr_addr));
283 if (ioctl(fd, SIOCGLIFDSTADDR,
284 (char *)&ifrdstaddr) < 0) {
285 if (errno == EADDRNOTAVAIL) {
286 /*
287 * Not available.
288 */
289 dstaddr = NULL;
290 } else {
291 pcap_fmt_errmsg_for_errno(errbuf,
292 PCAP_ERRBUF_SIZE, errno,
293 "SIOCGLIFDSTADDR: %.*s",
294 (int)sizeof(ifrdstaddr.lifr_name),
295 ifrdstaddr.lifr_name);
296 ret = -1;
297 break;
298 }
299 } else
300 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
301 } else
302 dstaddr = NULL;
303
304 #ifdef HAVE_SOLARIS
305 /*
306 * If this entry has a colon followed by a number at
307 * the end, it's a logical interface. Those are just
308 * the way you assign multiple IP addresses to a real
309 * interface, so an entry for a logical interface should
310 * be treated like the entry for the real interface;
311 * we do that by stripping off the ":" and the number.
312 */
313 p = strchr(ifrp->lifr_name, ':');
314 if (p != NULL) {
315 /*
316 * We have a ":"; is it followed by a number?
317 */
318 q = p + 1;
319 while (isdigit((unsigned char)*q))
320 q++;
321 if (*q == '\0') {
322 /*
323 * All digits after the ":" until the end.
324 * Strip off the ":" and everything after
325 * it.
326 */
327 *p = '\0';
328 }
329 }
330 #endif
331
332 /*
333 * Add information for this address to the list.
334 */
335 if (add_addr_to_if(devlistp, ifrp->lifr_name,
336 ifrflags.lifr_flags, get_flags_func,
337 (struct sockaddr *)&ifrp->lifr_addr,
338 sizeof (struct sockaddr_storage),
339 netmask, sizeof (struct sockaddr_storage),
340 broadaddr, sizeof (struct sockaddr_storage),
341 dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
342 ret = -1;
343 break;
344 }
345 }
346 free(buf);
347 (void)close(fd6);
348 (void)close(fd4);
349
350 return (ret);
351 }
352