]> The Tcpdump Group git mirrors - libpcap/blob - inet.c
Declare "install_bpf_program()" in "pcap-int.h", not "gencode.h"; it has
[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.36 2000-09-20 15:10:29 torsten 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 #define ISLOOPBACK_IFA(p) ((p)->ifa_flags & IFF_LOOPBACK)
78 #else
79 #define ISLOOPBACK(p) ((p)->ifr_name[0] == 'l' && (p)->ifr_name[1] == 'o' && \
80 (isdigit((p)->ifr_name[2]) || (p)->ifr_name[2] == '\0'))
81 #define ISLOOPBACK_IFA(p) ((p)->ifa_name[0] == 'l' && (p)->ifa_name[1] == 'o' && \
82 (isdigit((p)->ifa_name[2]) || (p)->ifa_name[2] == '\0'))
83 #endif
84
85 /*
86 * Return the name of a network interface attached to the system, or NULL
87 * if none can be found. The interface must be configured up; the
88 * lowest unit number is preferred; loopback is ignored.
89 */
90 char *
91 pcap_lookupdev(errbuf)
92 register char *errbuf;
93 {
94 #ifdef HAVE_IFADDRS_H
95 struct ifaddrs *ifap, *ifa, *mp;
96 int n, minunit;
97 char *cp;
98 static char device[IF_NAMESIZE + 1];
99
100 if (getifaddrs(&ifap) != 0) {
101 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
102 "getifaddrs: %s", pcap_strerror(errno));
103 return NULL;
104 }
105
106 mp = NULL;
107 minunit = 666;
108 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
109 const char *endcp;
110
111 if ((ifa->ifa_flags & IFF_UP) == 0 || ISLOOPBACK_IFA(ifa))
112 continue;
113
114 endcp = ifa->ifa_name + strlen(ifa->ifa_name);
115 for (cp = ifa->ifa_name; cp < endcp && !isdigit(*cp); ++cp)
116 continue;
117
118 if (isdigit (*cp)) {
119 n = atoi(cp);
120 } else {
121 n = 0;
122 }
123 if (n < minunit) {
124 minunit = n;
125 mp = ifa;
126 }
127 }
128 if (mp == NULL) {
129 (void)strlcpy(errbuf, "no suitable device found",
130 PCAP_ERRBUF_SIZE);
131 #ifdef HAVE_FREEIFADDRS
132 freeifaddrs(ifap);
133 #else
134 free(ifap);
135 #endif
136 return (NULL);
137 }
138
139 (void)strlcpy(device, mp->ifa_name, sizeof(device));
140 #ifdef HAVE_FREEIFADDRS
141 freeifaddrs(ifap);
142 #else
143 free(ifap);
144 #endif
145 return (device);
146 #else
147 register int fd, minunit, n;
148 register char *cp;
149 register struct ifreq *ifrp, *ifend, *ifnext, *mp;
150 struct ifconf ifc;
151 char *buf;
152 struct ifreq ifr;
153 static char device[sizeof(ifrp->ifr_name) + 1];
154 unsigned buf_size;
155
156 fd = socket(AF_INET, SOCK_DGRAM, 0);
157 if (fd < 0) {
158 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
159 "socket: %s", pcap_strerror(errno));
160 return (NULL);
161 }
162
163 buf_size = 8192;
164
165 for (;;) {
166 buf = malloc (buf_size);
167 if (buf == NULL) {
168 close (fd);
169 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
170 "out of memory");
171 return (NULL);
172 }
173
174 ifc.ifc_len = buf_size;
175 ifc.ifc_buf = buf;
176 memset (buf, 0, buf_size);
177 if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0
178 && errno != EINVAL) {
179 free (buf);
180 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
181 "SIOCGIFCONF: %s", pcap_strerror(errno));
182 (void)close(fd);
183 return (NULL);
184 }
185 if (ifc.ifc_len < buf_size)
186 break;
187 free (buf);
188 buf_size *= 2;
189 }
190
191 ifrp = (struct ifreq *)buf;
192 ifend = (struct ifreq *)(buf + ifc.ifc_len);
193
194 mp = NULL;
195 minunit = 666;
196 for (; ifrp < ifend; ifrp = ifnext) {
197 const char *endcp;
198
199 #ifdef HAVE_SOCKADDR_SA_LEN
200 n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
201 if (n < sizeof(*ifrp))
202 ifnext = ifrp + 1;
203 else
204 ifnext = (struct ifreq *)((char *)ifrp + n);
205 if (ifrp->ifr_addr.sa_family != AF_INET)
206 continue;
207 #else
208 ifnext = ifrp + 1;
209 #endif
210 /*
211 * Need a template to preserve address info that is
212 * used below to locate the next entry. (Otherwise,
213 * SIOCGIFFLAGS stomps over it because the requests
214 * are returned in a union.)
215 */
216 strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
217 if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
218 if (errno == ENXIO)
219 continue;
220 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
221 "SIOCGIFFLAGS: %.*s: %s",
222 (int)sizeof(ifr.ifr_name), ifr.ifr_name,
223 pcap_strerror(errno));
224 (void)close(fd);
225 free (buf);
226 return (NULL);
227 }
228
229 /* Must be up and not the loopback */
230 if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr))
231 continue;
232
233 endcp = ifrp->ifr_name + strlen(ifrp->ifr_name);
234 for (cp = ifrp->ifr_name; cp < endcp && !isdigit(*cp); ++cp)
235 continue;
236
237 if (isdigit (*cp)) {
238 n = atoi(cp);
239 } else {
240 n = 0;
241 }
242 if (n < minunit) {
243 minunit = n;
244 mp = ifrp;
245 }
246 }
247 (void)close(fd);
248 if (mp == NULL) {
249 (void)strlcpy(errbuf, "no suitable device found",
250 PCAP_ERRBUF_SIZE);
251 free(buf);
252 return (NULL);
253 }
254
255 (void)strlcpy(device, mp->ifr_name, sizeof(device));
256 free(buf);
257 return (device);
258 #endif
259 }
260
261 int
262 pcap_lookupnet(device, netp, maskp, errbuf)
263 register char *device;
264 register bpf_u_int32 *netp, *maskp;
265 register char *errbuf;
266 {
267 register int fd;
268 register struct sockaddr_in *sin;
269 struct ifreq ifr;
270
271 /*
272 * The pseudo-device "any" listens on all interfaces and therefore
273 * has the network address and -mask "0.0.0.0" therefore catching
274 * all traffic. Using NULL for the interface is the same as "any".
275 */
276 if (!device || strcmp(device, "any") == 0) {
277 *netp = *maskp = 0;
278 return 0;
279 }
280
281 fd = socket(AF_INET, SOCK_DGRAM, 0);
282 if (fd < 0) {
283 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE, "socket: %s",
284 pcap_strerror(errno));
285 return (-1);
286 }
287 memset(&ifr, 0, sizeof(ifr));
288 #ifdef linux
289 /* XXX Work around Linux kernel bug */
290 ifr.ifr_addr.sa_family = AF_INET;
291 #endif
292 (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
293 if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
294 if (errno == EADDRNOTAVAIL) {
295 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
296 "%s: no IPv4 address assigned", device);
297 } else {
298 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
299 "SIOCGIFADDR: %s: %s",
300 device, pcap_strerror(errno));
301 }
302 (void)close(fd);
303 return (-1);
304 }
305 sin = (struct sockaddr_in *)&ifr.ifr_addr;
306 *netp = sin->sin_addr.s_addr;
307 if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
308 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
309 "SIOCGIFNETMASK: %s: %s", device, pcap_strerror(errno));
310 (void)close(fd);
311 return (-1);
312 }
313 (void)close(fd);
314 *maskp = sin->sin_addr.s_addr;
315 if (*maskp == 0) {
316 if (IN_CLASSA(*netp))
317 *maskp = IN_CLASSA_NET;
318 else if (IN_CLASSB(*netp))
319 *maskp = IN_CLASSB_NET;
320 else if (IN_CLASSC(*netp))
321 *maskp = IN_CLASSC_NET;
322 else {
323 (void)snprintf(errbuf, PCAP_ERRBUF_SIZE,
324 "inet class for 0x%x unknown", *netp);
325 return (-1);
326 }
327 }
328 *netp &= *maskp;
329 return (0);
330 }