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