inet.c revision 17683
117683Spst/*
217683Spst * Copyright (c) 1994, 1995, 1996
317683Spst *	The Regents of the University of California.  All rights reserved.
417683Spst *
517683Spst * Redistribution and use in source and binary forms, with or without
617683Spst * modification, are permitted provided that the following conditions
717683Spst * are met:
817683Spst * 1. Redistributions of source code must retain the above copyright
917683Spst *    notice, this list of conditions and the following disclaimer.
1017683Spst * 2. Redistributions in binary form must reproduce the above copyright
1117683Spst *    notice, this list of conditions and the following disclaimer in the
1217683Spst *    documentation and/or other materials provided with the distribution.
1317683Spst * 3. All advertising materials mentioning features or use of this software
1417683Spst *    must display the following acknowledgement:
1517683Spst *	This product includes software developed by the Computer Systems
1617683Spst *	Engineering Group at Lawrence Berkeley Laboratory.
1717683Spst * 4. Neither the name of the University nor of the Laboratory may be used
1817683Spst *    to endorse or promote products derived from this software without
1917683Spst *    specific prior written permission.
2017683Spst *
2117683Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2217683Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2317683Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2417683Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2517683Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2617683Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2717683Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2817683Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2917683Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3017683Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3117683Spst * SUCH DAMAGE.
3217683Spst */
3317683Spst
3417683Spst#ifndef lint
3517683Spststatic char rcsid[] =
3617683Spst    "@(#) $Header: inet.c,v 1.18 96/07/15 00:48:49 leres Exp $ (LBL)";
3717683Spst#endif
3817683Spst
3917683Spst#include <sys/param.h>
4017683Spst#include <sys/file.h>
4117683Spst#include <sys/ioctl.h>
4217683Spst#include <sys/socket.h>
4317683Spst#ifdef HAVE_SYS_SOCKIO_H
4417683Spst#include <sys/sockio.h>
4517683Spst#endif
4617683Spst#include <sys/time.h>				/* concession to AIX */
4717683Spst
4817683Spst#if __STDC__
4917683Spststruct mbuf;
5017683Spststruct rtentry;
5117683Spst#endif
5217683Spst
5317683Spst#include <net/if.h>
5417683Spst#include <netinet/in.h>
5517683Spst
5617683Spst#include <ctype.h>
5717683Spst#include <errno.h>
5817683Spst#include <memory.h>
5917683Spst#include <stdio.h>
6017683Spst#include <stdlib.h>
6117683Spst#include <string.h>
6217683Spst#include <unistd.h>
6317683Spst
6417683Spst#include "pcap-int.h"
6517683Spst
6617683Spst#include "gnuc.h"
6717683Spst#ifdef HAVE_OS_PROTO_H
6817683Spst#include "os-proto.h"
6917683Spst#endif
7017683Spst
7117683Spst/* Not all systems have IFF_LOOPBACK */
7217683Spst#ifdef IFF_LOOPBACK
7317683Spst#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK)
7417683Spst#else
7517683Spst#define ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo0") == 0)
7617683Spst#endif
7717683Spst
7817683Spst/*
7917683Spst * Return the name of a network interface attached to the system, or NULL
8017683Spst * if none can be found.  The interface must be configured up; the
8117683Spst * lowest unit number is preferred; loopback is ignored.
8217683Spst */
8317683Spstchar *
8417683Spstpcap_lookupdev(errbuf)
8517683Spst	register char *errbuf;
8617683Spst{
8717683Spst	register int fd, minunit, n;
8817683Spst	register char *cp;
8917683Spst	register struct ifreq *ifrp, *ifend, *ifnext, *mp;
9017683Spst	struct ifconf ifc;
9117683Spst	struct ifreq ibuf[16], ifr;
9217683Spst	static char device[sizeof(ifrp->ifr_name) + 1];
9317683Spst
9417683Spst	fd = socket(AF_INET, SOCK_DGRAM, 0);
9517683Spst	if (fd < 0) {
9617683Spst		(void)sprintf(errbuf, "socket: %s", pcap_strerror(errno));
9717683Spst		return (NULL);
9817683Spst	}
9917683Spst	ifc.ifc_len = sizeof ibuf;
10017683Spst	ifc.ifc_buf = (caddr_t)ibuf;
10117683Spst
10217683Spst	if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
10317683Spst	    ifc.ifc_len < sizeof(struct ifreq)) {
10417683Spst		(void)sprintf(errbuf, "SIOCGIFCONF: %s", pcap_strerror(errno));
10517683Spst		(void)close(fd);
10617683Spst		return (NULL);
10717683Spst	}
10817683Spst	ifrp = ibuf;
10917683Spst	ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
11017683Spst
11117683Spst	mp = NULL;
11217683Spst	minunit = 666;
11317683Spst	for (; ifrp < ifend; ifrp = ifnext) {
11417683Spst#ifdef HAVE_SOCKADDR_SA_LEN
11517683Spst		n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
11617683Spst		if (n < sizeof(*ifrp))
11717683Spst			ifnext = ifrp + 1;
11817683Spst		else
11917683Spst			ifnext = (struct ifreq *)((char *)ifrp + n);
12017683Spst		if (ifrp->ifr_addr.sa_family != AF_INET)
12117683Spst			continue;
12217683Spst#else
12317683Spst		ifnext = ifrp + 1;
12417683Spst#endif
12517683Spst		/*
12617683Spst		 * Need a template to preserve address info that is
12717683Spst		 * used below to locate the next entry.  (Otherwise,
12817683Spst		 * SIOCGIFFLAGS stomps over it because the requests
12917683Spst		 * are returned in a union.)
13017683Spst		 */
13117683Spst		strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
13217683Spst		if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
13317683Spst			(void)sprintf(errbuf, "SIOCGIFFLAGS: %s",
13417683Spst			    pcap_strerror(errno));
13517683Spst			(void)close(fd);
13617683Spst			return (NULL);
13717683Spst		}
13817683Spst
13917683Spst		/* Must be up and not the loopback */
14017683Spst		if ((ifr.ifr_flags & IFF_UP) == 0 || ISLOOPBACK(&ifr))
14117683Spst			continue;
14217683Spst
14317683Spst		for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
14417683Spst			continue;
14517683Spst		n = atoi(cp);
14617683Spst		if (n < minunit) {
14717683Spst			minunit = n;
14817683Spst			mp = ifrp;
14917683Spst		}
15017683Spst	}
15117683Spst	(void)close(fd);
15217683Spst	if (mp == NULL) {
15317683Spst		(void)strcpy(errbuf, "no suitable device found");
15417683Spst		return (NULL);
15517683Spst	}
15617683Spst
15717683Spst	(void)strncpy(device, mp->ifr_name, sizeof(device) - 1);
15817683Spst	device[sizeof(device) - 1] = '\0';
15917683Spst	return (device);
16017683Spst}
16117683Spst
16217683Spstint
16317683Spstpcap_lookupnet(device, netp, maskp, errbuf)
16417683Spst	register char *device;
16517683Spst	register bpf_u_int32 *netp, *maskp;
16617683Spst	register char *errbuf;
16717683Spst{
16817683Spst	register int fd;
16917683Spst	register struct sockaddr_in *sin;
17017683Spst	struct ifreq ifr;
17117683Spst
17217683Spst	fd = socket(AF_INET, SOCK_DGRAM, 0);
17317683Spst	if (fd < 0) {
17417683Spst		(void)sprintf(errbuf, "socket: %s", pcap_strerror(errno));
17517683Spst		return (-1);
17617683Spst	}
17717683Spst	memset(&ifr, 0, sizeof(ifr));
17817683Spst#ifdef linux
17917683Spst	/* XXX Work around Linux kernel bug */
18017683Spst	ifr.ifr_addr.sa_family = AF_INET;
18117683Spst#endif
18217683Spst	(void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
18317683Spst	if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
18417683Spst		(void)sprintf(errbuf, "SIOCGIFADDR: %s: %s",
18517683Spst		    device, pcap_strerror(errno));
18617683Spst		(void)close(fd);
18717683Spst		return (-1);
18817683Spst	}
18917683Spst	sin = (struct sockaddr_in *)&ifr.ifr_addr;
19017683Spst	*netp = sin->sin_addr.s_addr;
19117683Spst	if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0) {
19217683Spst		(void)sprintf(errbuf, "SIOCGIFNETMASK: %s: %s",
19317683Spst		    device, pcap_strerror(errno));
19417683Spst		(void)close(fd);
19517683Spst		return (-1);
19617683Spst	}
19717683Spst	(void)close(fd);
19817683Spst	*maskp = sin->sin_addr.s_addr;
19917683Spst	if (*maskp == 0) {
20017683Spst		if (IN_CLASSA(*netp))
20117683Spst			*maskp = IN_CLASSA_NET;
20217683Spst		else if (IN_CLASSB(*netp))
20317683Spst			*maskp = IN_CLASSB_NET;
20417683Spst		else if (IN_CLASSC(*netp))
20517683Spst			*maskp = IN_CLASSC_NET;
20617683Spst		else {
20717683Spst			(void)sprintf(errbuf, "inet class for 0x%x unknown",
20817683Spst			    *netp);
20917683Spst			return (-1);
21017683Spst		}
21117683Spst	}
21217683Spst	*netp &= *maskp;
21317683Spst	return (0);
21417683Spst}
215