]> The Tcpdump Group git mirrors - libpcap/blob - fad-glifc.c
Remove some apparently-unneeded includes.
[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 #include <config.h>
36
37 #include <sys/param.h>
38 #include <sys/file.h>
39 #include <sys/ioctl.h>
40 #include <sys/socket.h>
41 #include <sys/sockio.h>
42
43 struct mbuf; /* Squelch compiler warnings on some platforms for */
44 struct rtentry; /* declarations in <net/if.h> */
45 #include <net/if.h>
46 #include <netinet/in.h>
47
48 #include <errno.h>
49 #include <memory.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54
55 #include "pcap-int.h"
56
57 #ifdef HAVE_OS_PROTO_H
58 #include "os-proto.h"
59 #endif
60
61 /*
62 * Only Solaris 10 uses this file.
63 */
64
65 /*
66 * Get a list of all interfaces that are up and that we can open.
67 * Returns -1 on error, 0 otherwise.
68 * The list, as returned through "alldevsp", may be null if no interfaces
69 * were up and could be opened.
70 *
71 * This is the implementation used on platforms that have SIOCGLIFCONF
72 * but don't have "getifaddrs()". (Solaris 8 and later; we use
73 * SIOCGLIFCONF rather than SIOCGIFCONF in order to get IPv6 addresses.)
74 */
75 int
76 pcapint_findalldevs_interfaces(pcap_if_list_t *devlistp, char *errbuf,
77 int (*check_usable)(const char *), get_if_flags_func get_flags_func)
78 {
79 register int fd4, fd6, fd;
80 register struct lifreq *ifrp, *ifend;
81 struct lifnum ifn;
82 struct lifconf ifc;
83 char *buf = NULL;
84 unsigned buf_size;
85 char *p, *q;
86 struct lifreq ifrflags, ifrnetmask, ifrbroadaddr, ifrdstaddr;
87 struct sockaddr *netmask, *broadaddr, *dstaddr;
88 int ret = 0;
89
90 /*
91 * Create a socket from which to fetch the list of interfaces,
92 * and from which to fetch IPv4 information.
93 */
94 fd4 = socket(AF_INET, SOCK_DGRAM, 0);
95 if (fd4 < 0) {
96 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
97 errno, "socket: AF_INET");
98 return (-1);
99 }
100
101 /*
102 * Create a socket from which to fetch IPv6 information.
103 */
104 fd6 = socket(AF_INET6, SOCK_DGRAM, 0);
105 if (fd6 < 0) {
106 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
107 errno, "socket: AF_INET6");
108 (void)close(fd4);
109 return (-1);
110 }
111
112 /*
113 * How many entries will SIOCGLIFCONF return?
114 */
115 ifn.lifn_family = AF_UNSPEC;
116 ifn.lifn_flags = 0;
117 ifn.lifn_count = 0;
118 if (ioctl(fd4, SIOCGLIFNUM, (char *)&ifn) < 0) {
119 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
120 errno, "SIOCGLIFNUM");
121 (void)close(fd6);
122 (void)close(fd4);
123 return (-1);
124 }
125
126 /*
127 * Allocate a buffer for those entries.
128 */
129 buf_size = ifn.lifn_count * sizeof (struct lifreq);
130 buf = malloc(buf_size);
131 if (buf == NULL) {
132 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
133 errno, "malloc");
134 (void)close(fd6);
135 (void)close(fd4);
136 return (-1);
137 }
138
139 /*
140 * Get the entries.
141 */
142 ifc.lifc_len = buf_size;
143 ifc.lifc_buf = buf;
144 ifc.lifc_family = AF_UNSPEC;
145 ifc.lifc_flags = 0;
146 memset(buf, 0, buf_size);
147 if (ioctl(fd4, SIOCGLIFCONF, (char *)&ifc) < 0) {
148 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
149 errno, "SIOCGLIFCONF");
150 (void)close(fd6);
151 (void)close(fd4);
152 free(buf);
153 return (-1);
154 }
155
156 /*
157 * Loop over the entries.
158 */
159 ifrp = (struct lifreq *)buf;
160 ifend = (struct lifreq *)(buf + ifc.lifc_len);
161
162 for (; ifrp < ifend; ifrp++) {
163 /*
164 * Skip entries that begin with "dummy".
165 * XXX - what are these? Is this Linux-specific?
166 * Are there platforms on which we shouldn't do this?
167 */
168 if (strncmp(ifrp->lifr_name, "dummy", 5) == 0)
169 continue;
170
171 /*
172 * Can we capture on this device?
173 */
174 if (!(*check_usable)(ifrp->lifr_name)) {
175 /*
176 * No.
177 */
178 continue;
179 }
180
181 /*
182 * IPv6 or not?
183 */
184 if (((struct sockaddr *)&ifrp->lifr_addr)->sa_family == AF_INET6)
185 fd = fd6;
186 else
187 fd = fd4;
188
189 /*
190 * Get the flags for this interface.
191 */
192 strncpy(ifrflags.lifr_name, ifrp->lifr_name,
193 sizeof(ifrflags.lifr_name));
194 if (ioctl(fd, SIOCGLIFFLAGS, (char *)&ifrflags) < 0) {
195 if (errno == ENXIO)
196 continue;
197 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE,
198 errno, "SIOCGLIFFLAGS: %.*s",
199 (int)sizeof(ifrflags.lifr_name),
200 ifrflags.lifr_name);
201 ret = -1;
202 break;
203 }
204
205 /*
206 * Get the netmask for this address on this interface.
207 */
208 strncpy(ifrnetmask.lifr_name, ifrp->lifr_name,
209 sizeof(ifrnetmask.lifr_name));
210 memcpy(&ifrnetmask.lifr_addr, &ifrp->lifr_addr,
211 sizeof(ifrnetmask.lifr_addr));
212 if (ioctl(fd, SIOCGLIFNETMASK, (char *)&ifrnetmask) < 0) {
213 if (errno == EADDRNOTAVAIL) {
214 /*
215 * Not available.
216 */
217 netmask = NULL;
218 } else {
219 pcapint_fmt_errmsg_for_errno(errbuf,
220 PCAP_ERRBUF_SIZE, errno,
221 "SIOCGLIFNETMASK: %.*s",
222 (int)sizeof(ifrnetmask.lifr_name),
223 ifrnetmask.lifr_name);
224 ret = -1;
225 break;
226 }
227 } else
228 netmask = (struct sockaddr *)&ifrnetmask.lifr_addr;
229
230 /*
231 * Get the broadcast address for this address on this
232 * interface (if any).
233 */
234 if (ifrflags.lifr_flags & IFF_BROADCAST) {
235 strncpy(ifrbroadaddr.lifr_name, ifrp->lifr_name,
236 sizeof(ifrbroadaddr.lifr_name));
237 memcpy(&ifrbroadaddr.lifr_addr, &ifrp->lifr_addr,
238 sizeof(ifrbroadaddr.lifr_addr));
239 if (ioctl(fd, SIOCGLIFBRDADDR,
240 (char *)&ifrbroadaddr) < 0) {
241 if (errno == EADDRNOTAVAIL) {
242 /*
243 * Not available.
244 */
245 broadaddr = NULL;
246 } else {
247 pcapint_fmt_errmsg_for_errno(errbuf,
248 PCAP_ERRBUF_SIZE, errno,
249 "SIOCGLIFBRDADDR: %.*s",
250 (int)sizeof(ifrbroadaddr.lifr_name),
251 ifrbroadaddr.lifr_name);
252 ret = -1;
253 break;
254 }
255 } else
256 broadaddr = (struct sockaddr *)&ifrbroadaddr.lifr_broadaddr;
257 } else {
258 /*
259 * Not a broadcast interface, so no broadcast
260 * address.
261 */
262 broadaddr = NULL;
263 }
264
265 /*
266 * Get the destination address for this address on this
267 * interface (if any).
268 */
269 if (ifrflags.lifr_flags & IFF_POINTOPOINT) {
270 strncpy(ifrdstaddr.lifr_name, ifrp->lifr_name,
271 sizeof(ifrdstaddr.lifr_name));
272 memcpy(&ifrdstaddr.lifr_addr, &ifrp->lifr_addr,
273 sizeof(ifrdstaddr.lifr_addr));
274 if (ioctl(fd, SIOCGLIFDSTADDR,
275 (char *)&ifrdstaddr) < 0) {
276 if (errno == EADDRNOTAVAIL) {
277 /*
278 * Not available.
279 */
280 dstaddr = NULL;
281 } else {
282 pcapint_fmt_errmsg_for_errno(errbuf,
283 PCAP_ERRBUF_SIZE, errno,
284 "SIOCGLIFDSTADDR: %.*s",
285 (int)sizeof(ifrdstaddr.lifr_name),
286 ifrdstaddr.lifr_name);
287 ret = -1;
288 break;
289 }
290 } else
291 dstaddr = (struct sockaddr *)&ifrdstaddr.lifr_dstaddr;
292 } else
293 dstaddr = NULL;
294
295 /*
296 * If this entry has a colon followed by a number at
297 * the end, it's a logical interface. Those are just
298 * the way you assign multiple IP addresses to a real
299 * interface, so an entry for a logical interface should
300 * be treated like the entry for the real interface;
301 * we do that by stripping off the ":" and the number.
302 */
303 p = strchr(ifrp->lifr_name, ':');
304 if (p != NULL) {
305 /*
306 * We have a ":"; is it followed by a number?
307 */
308 q = p + 1;
309 while (PCAP_ISDIGIT(*q))
310 q++;
311 if (*q == '\0') {
312 /*
313 * All digits after the ":" until the end.
314 * Strip off the ":" and everything after
315 * it.
316 */
317 *p = '\0';
318 }
319 }
320
321 /*
322 * Add information for this address to the list.
323 */
324 if (pcapint_add_addr_to_if(devlistp, ifrp->lifr_name,
325 ifrflags.lifr_flags, get_flags_func,
326 (struct sockaddr *)&ifrp->lifr_addr,
327 sizeof (struct sockaddr_storage),
328 netmask, sizeof (struct sockaddr_storage),
329 broadaddr, sizeof (struct sockaddr_storage),
330 dstaddr, sizeof (struct sockaddr_storage), errbuf) < 0) {
331 ret = -1;
332 break;
333 }
334 }
335 free(buf);
336 (void)close(fd6);
337 (void)close(fd4);
338
339 return (ret);
340 }