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 <sys/time.h> /* for struct timeval in net/if.h */
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(u_char *ca, u_char *cb);
38
39 /* Return a pointer to the interface struct for the passed address. */
40 struct ifreq *
getif(s,addrp)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((u_char *)addrp, (u_char *)&(sip->sin_addr));
88 if (m > maxmatch) {
89 maxmatch = m;
90 ifrmax = ifrq;
91 }
92 #ifndef IFNAMSIZ
93 /* BSD not defined or earlier than 4.3 */
94 incr = sizeof(*ifrq);
95 #else
96 incr = ifrq->ifr_addr.sa_len + IFNAMSIZ;
97 #endif
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
nmatch(ca,cb)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