13229Spst/*
23229Spst * getif.c : get an interface structure
318471Swosch *
450476Speter * $FreeBSD$
53229Spst */
63229Spst
73229Spst#include <sys/types.h>
83229Spst#include <sys/socket.h>
93229Spst#include <sys/ioctl.h>
103229Spst
113229Spst#if defined(SUNOS) || defined(SVR4)
123229Spst#include <sys/sockio.h>
133229Spst#endif
143229Spst#ifdef	SVR4
153229Spst#include <sys/stropts.h>
163229Spst#endif
173229Spst
1813572Spst#include <sys/time.h>		/* for struct timeval in net/if.h */
193229Spst#include <net/if.h>				/* for struct ifreq */
203229Spst#include <netinet/in.h>
213229Spst
223229Spst#ifndef	NO_UNISTD
233229Spst#include <unistd.h>
243229Spst#endif
253229Spst#include <syslog.h>
263229Spst#include <errno.h>
273229Spst#include <assert.h>
283229Spst
293229Spst#include "getif.h"
303229Spst#include "report.h"
313229Spst
323229Spst#ifdef	__bsdi__
333229Spst#define BSD 43
343229Spst#endif
353229Spst
363229Spststatic struct ifreq ifreq[10];	/* Holds interface configuration */
373229Spststatic struct ifconf ifconf;	/* points to ifreq */
383229Spst
393229Spststatic int nmatch();
403229Spst
413229Spst/* Return a pointer to the interface struct for the passed address. */
423229Spststruct ifreq *
433229Spstgetif(s, addrp)
443229Spst	int s;						/* socket file descriptor */
453229Spst	struct in_addr *addrp;		/* destination address on interface */
463229Spst{
473229Spst	int maxmatch;
483229Spst	int len, m, incr;
493229Spst	struct ifreq *ifrq, *ifrmax;
503229Spst	struct sockaddr_in *sip;
513229Spst	char *p;
523229Spst
533229Spst	/* If no address was supplied, just return NULL. */
543229Spst	if (!addrp)
553229Spst		return (struct ifreq *) 0;
563229Spst
573229Spst	/* Get the interface config if not done already. */
583229Spst	if (ifconf.ifc_len == 0) {
593229Spst#ifdef	SVR4
603229Spst		/*
613229Spst		 * SysVr4 returns garbage if you do this the obvious way!
623229Spst		 * This one took a while to figure out... -gwr
633229Spst		 */
643229Spst		struct strioctl ioc;
653229Spst		ioc.ic_cmd = SIOCGIFCONF;
663229Spst		ioc.ic_timout = 0;
673229Spst		ioc.ic_len = sizeof(ifreq);
683229Spst		ioc.ic_dp = (char *) ifreq;
693229Spst		m = ioctl(s, I_STR, (char *) &ioc);
703229Spst		ifconf.ifc_len = ioc.ic_len;
713229Spst		ifconf.ifc_req = ifreq;
723229Spst#else	/* SVR4 */
733229Spst		ifconf.ifc_len = sizeof(ifreq);
743229Spst		ifconf.ifc_req = ifreq;
753229Spst		m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf);
763229Spst#endif	/* SVR4 */
773229Spst		if ((m < 0) || (ifconf.ifc_len <= 0)) {
783229Spst			report(LOG_ERR, "ioctl SIOCGIFCONF");
793229Spst			return (struct ifreq *) 0;
803229Spst		}
813229Spst	}
823229Spst	maxmatch = 7;				/* this many bits or less... */
833229Spst	ifrmax = (struct ifreq *) 0;/* ... is not a valid match  */
843229Spst	p = (char *) ifreq;
853229Spst	len = ifconf.ifc_len;
863229Spst	while (len > 0) {
873229Spst		ifrq = (struct ifreq *) p;
883229Spst		sip = (struct sockaddr_in *) &ifrq->ifr_addr;
89132848Skan		m = nmatch((u_char *)addrp, (u_char *)&(sip->sin_addr));
903229Spst		if (m > maxmatch) {
913229Spst			maxmatch = m;
923229Spst			ifrmax = ifrq;
933229Spst		}
9413582Spst#ifndef IFNAMSIZ
953229Spst		/* BSD not defined or earlier than 4.3 */
963229Spst		incr = sizeof(*ifrq);
9713582Spst#else
983229Spst		incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
9913582Spst#endif
1003229Spst
1013229Spst		p += incr;
1023229Spst		len -= incr;
1033229Spst	}
1043229Spst
1053229Spst	return ifrmax;
1063229Spst}
1073229Spst
1083229Spst/*
1093229Spst * Return the number of leading bits matching in the
1103229Spst * internet addresses supplied.
1113229Spst */
1123229Spststatic int
1133229Spstnmatch(ca, cb)
1143229Spst	u_char *ca, *cb;			/* ptrs to IP address, network order */
1153229Spst{
1163229Spst	u_int m = 0;				/* count of matching bits */
1173229Spst	u_int n = 4;				/* bytes left, then bitmask */
1183229Spst
1193229Spst	/* Count matching bytes. */
1203229Spst	while (n && (*ca == *cb)) {
1213229Spst		ca++;
1223229Spst		cb++;
1233229Spst		m += 8;
1243229Spst		n--;
1253229Spst	}
1263229Spst	/* Now count matching bits. */
1273229Spst	if (n) {
1283229Spst		n = 0x80;
1293229Spst		while (n && ((*ca & n) == (*cb & n))) {
1303229Spst			m++;
1313229Spst			n >>= 1;
1323229Spst		}
1333229Spst	}
1343229Spst	return (m);
1353229Spst}
1363229Spst
1373229Spst/*
1383229Spst * Local Variables:
1393229Spst * tab-width: 4
1403229Spst * c-indent-level: 4
1413229Spst * c-argdecl-indent: 4
1423229Spst * c-continued-statement-offset: 4
1433229Spst * c-continued-brace-offset: -4
1443229Spst * c-label-offset: -4
1453229Spst * c-brace-offset: 0
1463229Spst * End:
1473229Spst */
148