inet.c revision 1.3
1/*	$OpenBSD */
2/*	$NetBSD: inet.c,v 1.2.6.1 1996/06/05 18:04:32 cgd Exp $	*/
3
4/*
5 * Copyright (c) 1994
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the Computer Systems
19 *	Engineering Group at Lawrence Berkeley Laboratory.
20 * 4. Neither the name of the University nor of the Laboratory may be used
21 *    to endorse or promote products derived from this software without
22 *    specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#ifndef lint
38static char rcsid[] =
39    "@(#) Header: inet.c,v 1.4 94/06/07 01:16:50 leres Exp (LBL)";
40#endif
41
42#include <sys/param.h>
43#include <sys/file.h>
44#include <sys/ioctl.h>
45#include <sys/socket.h>
46#ifdef SOLARIS
47#include <sys/sockio.h>
48#endif
49
50#include <net/if.h>
51#include <netinet/in.h>
52
53#include <ctype.h>
54#include <errno.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <unistd.h>
59#include <pcap.h>
60
61/* Not all systems have IFF_LOOPBACK */
62#ifdef IFF_LOOPBACK
63#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK)
64#else
65#define ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo0") == 0)
66#endif
67
68/*
69 * Return the name of a network interface attached to the system, or NULL
70 * if none can be found.  The interface must be configured up; the
71 * lowest unit number is preferred; loopback is ignored.
72 */
73char *
74pcap_lookupdev(errbuf)
75	register char *errbuf;
76{
77	register int fd, minunit, n;
78	register char *cp;
79	register struct ifreq *ifrp, *ifend, *ifnext, *mp;
80	struct ifconf ifc;
81	struct ifreq ibuf[16], ifr;
82	static char device[sizeof(ifrp->ifr_name) + 1];
83
84	fd = socket(AF_INET, SOCK_DGRAM, 0);
85	if (fd < 0) {
86		(void)sprintf(errbuf, "socket: %s", pcap_strerror(errno));
87		return (NULL);
88	}
89	ifc.ifc_len = sizeof ibuf;
90	ifc.ifc_buf = (caddr_t)ibuf;
91
92	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
93	    ifc.ifc_len < sizeof(struct ifreq)) {
94		(void)sprintf(errbuf, "SIOCGIFCONF: %s", pcap_strerror(errno));
95		(void)close(fd);
96		return (NULL);
97	}
98	ifrp = ibuf;
99	ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
100
101	mp = NULL;
102	minunit = 666;
103	for (; ifrp < ifend; ifrp = ifnext) {
104#if BSD - 0 >= 199006
105		n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
106		if (n < sizeof(*ifrp))
107			ifnext = ifrp + 1;
108		else
109			ifnext = (struct ifreq *)((char *)ifrp + n);
110		if (ifrp->ifr_addr.sa_family != AF_INET)
111			continue;
112#else
113		ifnext = ifrp + 1;
114#endif
115		/*
116		 * Need a template to preserve address info that is
117		 * used below to locate the next entry.  (Otherwise,
118		 * SIOCGIFFLAGS stomps over it because the requests
119		 * are returned in a union.)
120		 */
121		strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
122		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
123			(void)sprintf(errbuf, "SIOCGIFFLAGS: %s",
124			    pcap_strerror(errno));
125			(void)close(fd);
126			return (NULL);
127		}
128
129		/* Must be up and not the loopback */
130		if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr))
131			continue;
132
133		for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
134			continue;
135		n = atoi(cp);
136		if (n < minunit) {
137			minunit = n;
138			mp = ifrp;
139		}
140	}
141	(void)close(fd);
142	if (mp == NULL) {
143		(void)strcpy(errbuf, "no suitable device found");
144		return (NULL);
145	}
146
147	(void)strncpy(device, mp->ifr_name, sizeof(device) - 1);
148	device[sizeof(device) - 1] = '\0';
149	return (device);
150}
151
152int
153pcap_lookupnet(device, netp, maskp, errbuf)
154	register char *device;
155	register u_int32_t *netp, *maskp;
156	register char *errbuf;
157{
158	register int fd;
159	register struct sockaddr_in *sin;
160	struct ifreq ifr;
161
162	fd = socket(AF_INET, SOCK_DGRAM, 0);
163	if (fd < 0) {
164		(void)sprintf(errbuf, "socket: %s", pcap_strerror(errno));
165		return (-1);
166	}
167	(void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
168	if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
169		(void)sprintf(errbuf, "SIOCGIFADDR: %s: %s",
170		    device, pcap_strerror(errno));
171		(void)close(fd);
172		return (-1);
173	}
174	sin = (struct sockaddr_in *)&ifr.ifr_addr;
175	*netp = sin->sin_addr.s_addr;
176	if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
177		(void)sprintf(errbuf, "SIOCGIFNETMASK: %s: %s",
178		    device, pcap_strerror(errno));
179		(void)close(fd);
180		return (-1);
181	}
182	(void)close(fd);
183	*maskp = sin->sin_addr.s_addr;
184	if (*maskp == 0) {
185		if (IN_CLASSA(*netp))
186			*maskp = IN_CLASSA_NET;
187		else if (IN_CLASSB(*netp))
188			*maskp = IN_CLASSB_NET;
189		else if (IN_CLASSC(*netp))
190			*maskp = IN_CLASSC_NET;
191		else {
192			(void)sprintf(errbuf, "inet class for 0x%x unknown",
193			    *netp);
194			return (-1);
195		}
196	}
197	*netp &= *maskp;
198	return (0);
199}
200