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