]> The Tcpdump Group git mirrors - libpcap/blob - inet.c
add config.h, remove gnuc.h. remove __dead
[libpcap] / inet.c
1 /*
2 * Copyright (c) 1994, 1995, 1996, 1997, 1998
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the Computer Systems
16 * Engineering Group at Lawrence Berkeley Laboratory.
17 * 4. Neither the name of the University nor of the Laboratory may be used
18 * to endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static const char rcsid[] =
36 "@(#) $Header: /tcpdump/master/libpcap/inet.c,v 1.34 2000-07-11 00:37:04 assar Exp $ (LBL)";
37 #endif
38
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42
43 #include <sys/param.h>
44 #include <sys/file.h>
45 #include <sys/ioctl.h>
46 #include <sys/socket.h>
47 #ifdef HAVE_SYS_SOCKIO_H
48 #include <sys/sockio.h>
49 #endif
50 #include <sys/time.h> /* concession to AIX */
51
52 struct mbuf;
53 struct rtentry;
54 #include <net/if.h>
55 #include <netinet/in.h>
56
57 #include <ctype.h>
58 #include <errno.h>
59 #include <memory.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 #ifdef HAVE_IFADDRS_H
65 #include <ifaddrs.h>
66 #endif
67
68 #include "pcap-int.h"
69
70 #ifdef HAVE_OS_PROTO_H
71 #include "os-proto.h"
72 #endif
73
74 /* Not all systems have IFF_LOOPBACK */
75 #ifdef IFF_LOOPBACK
76 #define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK)
77 #else
78 #define ISLOOPBACK(p) ((p)->ifr_name[0] == 'l' && (p)->ifr_name[1] == 'o' && \
79 (isdigit((p)->ifr_name[2]) || (p)->ifr_name[2] == '\0'))
80 #endif
81
82 /*
83 * Return the name of a network interface attached to the system, or NULL
84 * if none can be found. The interface must be configured up; the
85 * lowest unit number is preferred; loopback is ignored.
86 */
87 char *
88 pcap_lookupdev(errbuf)
89 register char *errbuf;
90 {
91 #ifdef HAVE_IFADDRS_H
92 struct ifaddrs *ifap, *ifa, *mp;
93 int n, minunit;
94 char *cp;
95 static char device[IF_NAMESIZE + 1];
96
97 if (getifaddrs(&ifap) != 0) {
98 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
99 "getifaddrs: %s", pcap_strerror(errno));
100 return NULL;
101 }
102
103 mp = NULL;
104 minunit = 666;
105 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
106 if ((ifa->ifa_flags & IFF_UP) == 0)
107 continue;
108 #ifdef IFF_LOOPBACK
109 if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
110 continue;
111 #else
112 if (strncmp(ifa->ifa_name, "lo", 2) == 0 &&
113 (ifa->ifa_name[2] == '\0' || isdigit(ifa->ifa_name[2]))) {
114 continue;
115 }
116 #endif
117
118 for (cp = ifa->ifa_name; !isdigit(*cp); ++cp)
119 continue;
120 n = atoi(cp);
121 if (n < minunit) {
122 minunit = n;
123 mp = ifa;
124 }
125 }
126 if (mp == NULL) {
127 (void)strlcpy(errbuf, "no suitable device found",
128 PCAP_ERRBUF_SIZE);
129 #ifdef HAVE_FREEIFADDRS
130 freeifaddrs(ifap);
131 #else
132 free(ifap);
133 #endif
134 return (NULL);
135 }
136
137 (void)strlcpy(device, mp->ifa_name, sizeof(device));
138 #ifdef HAVE_FREEIFADDRS
139 freeifaddrs(ifap);
140 #else
141 free(ifap);
142 #endif
143 return (device);
144 #else
145 register int fd, minunit, n;
146 register char *cp;
147 register struct ifreq *ifrp, *ifend, *ifnext, *mp;
148 struct ifconf ifc;
149 char *buf;
150 struct ifreq ifr;
151 static char device[sizeof(ifrp->ifr_name) + 1];
152 unsigned buf_size;
153
154 fd = socket(AF_INET, SOCK_DGRAM, 0);
155 if (fd < 0) {
156 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
157 "socket: %s", pcap_strerror(errno));
158 return (NULL);
159 }
160
161 buf_size = 8192;
162
163 for (;;) {
164 buf = malloc (buf_size);
165 if (buf == NULL) {
166 close (fd);
167 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
168 "out of memory");
169 return (NULL);
170 }
171
172 ifc.ifc_len = buf_size;
173 ifc.ifc_buf = buf;
174 memset (buf, 0, buf_size);
175 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
176 && errno != EINVAL) {
177 free (buf);
178 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
179 "SIOCGIFCONF: %s", pcap_strerror(errno));
180 (void)close(fd);
181 return (NULL);
182 }
183 if (ifc.ifc_len < buf_size)
184 break;
185 free (buf);
186 buf_size *= 2;
187 }
188
189 ifrp = (struct ifreq *)buf;
190 ifend = (struct ifreq *)(buf + ifc.ifc_len);
191
192 mp = NULL;
193 minunit = 666;
194 for (; ifrp < ifend; ifrp = ifnext) {
195 #ifdef HAVE_SOCKADDR_SA_LEN
196 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
197 if (n < sizeof(*ifrp))
198 ifnext = ifrp + 1;
199 else
200 ifnext = (struct ifreq *)((char *)ifrp + n);
201 if (ifrp->ifr_addr.sa_family != AF_INET)
202 continue;
203 #else
204 ifnext = ifrp + 1;
205 #endif
206 /*
207 * Need a template to preserve address info that is
208 * used below to locate the next entry. (Otherwise,
209 * SIOCGIFFLAGS stomps over it because the requests
210 * are returned in a union.)
211 */
212 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
213 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
214 if (errno == ENXIO)
215 continue;
216 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
217 "SIOCGIFFLAGS: %.*s: %s",
218 (int)sizeof(ifr.ifr_name), ifr.ifr_name,
219 pcap_strerror(errno));
220 (void)close(fd);
221 free (buf);
222 return (NULL);
223 }
224
225 /* Must be up and not the loopback */
226 if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr))
227 continue;
228
229 for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
230 continue;
231 n = atoi(cp);
232 if (n < minunit) {
233 minunit = n;
234 mp = ifrp;
235 }
236 }
237 (void)close(fd);
238 if (mp == NULL) {
239 (void)strlcpy(errbuf, "no suitable device found",
240 PCAP_ERRBUF_SIZE);
241 free(buf);
242 return (NULL);
243 }
244
245 (void)strlcpy(device, mp->ifr_name, sizeof(device));
246 free(buf);
247 return (device);
248 #endif
249 }
250
251 int
252 pcap_lookupnet(device, netp, maskp, errbuf)
253 register char *device;
254 register bpf_u_int32 *netp, *maskp;
255 register char *errbuf;
256 {
257 register int fd;
258 register struct sockaddr_in *sin;
259 struct ifreq ifr;
260
261 fd = socket(AF_INET, SOCK_DGRAM, 0);
262 if (fd < 0) {
263 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
264 pcap_strerror(errno));
265 return (-1);
266 }
267 memset(&ifr, 0, sizeof(ifr));
268 #ifdef linux
269 /* XXX Work around Linux kernel bug */
270 ifr.ifr_addr.sa_family = AF_INET;
271 #endif
272 (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
273 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
274 if (errno == EADDRNOTAVAIL) {
275 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
276 "%s: no IPv4 address assigned", device);
277 } else {
278 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
279 "SIOCGIFADDR: %s: %s",
280 device, pcap_strerror(errno));
281 }
282 (void)close(fd);
283 return (-1);
284 }
285 sin = (struct sockaddr_in *)&ifr.ifr_addr;
286 *netp = sin->sin_addr.s_addr;
287 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
288 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
289 "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno));
290 (void)close(fd);
291 return (-1);
292 }
293 (void)close(fd);
294 *maskp = sin->sin_addr.s_addr;
295 if (*maskp == 0) {
296 if (IN_CLASSA(*netp))
297 *maskp = IN_CLASSA_NET;
298 else if (IN_CLASSB(*netp))
299 *maskp = IN_CLASSB_NET;
300 else if (IN_CLASSC(*netp))
301 *maskp = IN_CLASSC_NET;
302 else {
303 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
304 "inet class for 0x%x unknown", *netp);
305 return (-1);
306 }
307 }
308 *netp &= *maskp;
309 return (0);
310 }