1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
|
/*
* getif.c : get an interface structure
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#if defined(SUNOS) || defined(SVR4)
#include <sys/sockio.h>
#endif
#ifdef SVR4
#include <sys/stropts.h>
#endif
#ifdef _AIX32
#include <sys/time.h> /* for struct timeval in net/if.h */
#endif
#include <net/if.h> /* for struct ifreq */
#include <netinet/in.h>
#ifndef NO_UNISTD
#include <unistd.h>
#endif
#include <syslog.h>
#include <errno.h>
#include <assert.h>
#include "getif.h"
#include "report.h"
#ifdef __bsdi__
#define BSD 43
#endif
static struct ifreq ifreq[10]; /* Holds interface configuration */
static struct ifconf ifconf; /* points to ifreq */
static int nmatch();
/* Return a pointer to the interface struct for the passed address. */
struct ifreq *
getif(s, addrp)
int s; /* socket file descriptor */
struct in_addr *addrp; /* destination address on interface */
{
int maxmatch;
int len, m, incr;
struct ifreq *ifrq, *ifrmax;
struct sockaddr_in *sip;
char *p;
/* If no address was supplied, just return NULL. */
if (!addrp)
return (struct ifreq *) 0;
/* Get the interface config if not done already. */
if (ifconf.ifc_len == 0) {
#ifdef SVR4
/*
* SysVr4 returns garbage if you do this the obvious way!
* This one took a while to figure out... -gwr
*/
struct strioctl ioc;
ioc.ic_cmd = SIOCGIFCONF;
ioc.ic_timout = 0;
ioc.ic_len = sizeof(ifreq);
ioc.ic_dp = (char *) ifreq;
m = ioctl(s, I_STR, (char *) &ioc);
ifconf.ifc_len = ioc.ic_len;
ifconf.ifc_req = ifreq;
#else /* SVR4 */
ifconf.ifc_len = sizeof(ifreq);
ifconf.ifc_req = ifreq;
m = ioctl(s, SIOCGIFCONF, (caddr_t) & ifconf);
#endif /* SVR4 */
if ((m < 0) || (ifconf.ifc_len <= 0)) {
report(LOG_ERR, "ioctl SIOCGIFCONF");
return (struct ifreq *) 0;
}
}
maxmatch = 7; /* this many bits or less... */
ifrmax = (struct ifreq *) 0;/* ... is not a valid match */
p = (char *) ifreq;
len = ifconf.ifc_len;
while (len > 0) {
ifrq = (struct ifreq *) p;
sip = (struct sockaddr_in *) &ifrq->ifr_addr;
m = nmatch(addrp, &(sip->sin_addr));
if (m > maxmatch) {
maxmatch = m;
ifrmax = ifrq;
}
/* XXX - Could this be just #ifndef IFNAMSIZ instead? -gwr */
#if (BSD - 0) < 43
/* BSD not defined or earlier than 4.3 */
incr = sizeof(*ifrq);
#else /* NetBSD */
incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
#endif /* NetBSD */
p += incr;
len -= incr;
}
return ifrmax;
}
/*
* Return the number of leading bits matching in the
* internet addresses supplied.
*/
static int
nmatch(ca, cb)
u_char *ca, *cb; /* ptrs to IP address, network order */
{
u_int m = 0; /* count of matching bits */
u_int n = 4; /* bytes left, then bitmask */
/* Count matching bytes. */
while (n && (*ca == *cb)) {
ca++;
cb++;
m += 8;
n--;
}
/* Now count matching bits. */
if (n) {
n = 0x80;
while (n && ((*ca & n) == (*cb & n))) {
m++;
n >>= 1;
}
}
return (m);
}
/*
* Local Variables:
* tab-width: 4
* c-indent-level: 4
* c-argdecl-indent: 4
* c-continued-statement-offset: 4
* c-continued-brace-offset: -4
* c-label-offset: -4
* c-brace-offset: 0
* End:
*/
|