inet.c revision 1.25
1/*	$OpenBSD: inet.c,v 1.25 2019/06/28 13:32:42 deraadt 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
45struct mbuf;
46struct 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 */
70void
71pcap_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 */
114char *
115pcap_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 == -1) {
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) == -1 ||
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) == -1) {
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
241int
242pcap_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 == -1) {
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) == -1) {
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) == -1) {
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}
299