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