1 #ifndef lint
2 static char sccsid[] = "@(#)$Id: subnet.c,v 1.16 1994/12/04 00:18:40 sob Exp sob $";
3 #endif
4
5 #include "common.h"
6 #ifdef TESTSUBNET
7 #ifndef DEBUG
8 #define DEBUG
9 #endif
10 #include <stdio.h>
11 #endif
12
13 #include <unistd.h>
14 #include <stdlib.h>
15
16 #ifdef SUBNET
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #ifndef NETMASK
23 #include <net/if.h>
24 #endif
25 #ifdef STREAMS_TLI
26 #include <stropts.h>
27 #endif
28 #ifdef SVR4
29 #include <sys/sockio.h>
30 #endif
31 #include <sys/ioctl.h>
32 #ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG
33 #include <fcntl.h>
34 #endif
35
36 #if defined(DEBUG) && defined(SYSLOG)
37 # ifdef FAKESYSLOG
38 # include "fakesyslog.h"
39 # else
40 # include <syslog.h>
41 # endif
42 #endif
43
44 /*
45 * The following routines provide a general interface for
46 * subnet support. Like the library function "inet_netof",
47 * which returns the standard (i.e., non-subnet) network
48 * portion of an internet address, "inet_snetof" returns
49 * the subnetwork portion -- if there is one. If there
50 * isn't, it returns 0.
51 *
52 * Subnets, under 4.3, are specific to a given set of
53 * machines -- right down to the network interfaces.
54 * Because of this, the function "getifconf" must be
55 * called first. This routine builds a table listing
56 * all the (internet) interfaces present on a machine,
57 * along with their subnet masks. Then when inet_snetof
58 * is called, it can quickly scan this table.
59 *
60 * Unfortunately, there "ain't no graceful way" to handle
61 * certain situations. For example, the kernel permits
62 * arbitrary subnet bits -- that is, you could have a
63 * 22 bit network field and a 10 bit subnet field.
64 * However, due to braindamage at the user level, in
65 * such sterling routines as getnetbyaddr, you need to
66 * have a subnet mask which is an even multiple of 8.
67 * Unless you are running with class C subnets, in which
68 * case it should be a multiple of 4. Because of this rot,
69 * if you have non-multiples of 4 bits of subnet, you should
70 * define DAMAGED_NETMASK when you compile. This will round
71 * things off to a multiple of 8 bits.
72 *
73 * Finally, you may want subnet support even if your system doesn't
74 * support the ioctls to get subnet mask information. If you want
75 * such a thing, you can define NETMASK to be a constant that is
76 * the subnet mask for your network.
77 *
78 * And don't *even* get me started on how the definitions of the inet_foo()
79 * routines changed between 4.2 and 4.3, making internet addresses
80 * be unsigned long vs. struct in_addr. Don't blame me if this
81 * won't lint...
82 */
83
84 /*
85 * One structure for each interface, containing
86 * the network number and subnet mask, stored in HBO.
87 */
88 struct in_if {
89 u_long i_net; /* Network number, shifted right */
90 u_long i_subnetmask; /* Subnet mask for this if */
91 int i_bitshift; /* How many bits right for outside */
92 };
93
94 /*
95 * Table (eventually, once we malloc) of
96 * internet interface subnet information.
97 */
98 static struct in_if *in_ifsni;
99
100 static int if_count;
101
102 /*
103 * Get the network interface configuration,
104 * and squirrel away the network numbers and
105 * subnet masks of each interface. Return
106 * number of interfaces found, or -1 on error.
107 * N.B.: don't call this more than once...
108 */
109
110 int
getifconf()111 getifconf()
112 {
113 #ifndef NETMASK
114 register int i, j;
115 int s;
116 struct ifconf ifc;
117 char buf[1024];
118 register struct ifreq *ifr;
119 u_long addr;
120 #ifdef STREAMS_TLI
121 struct strioctl ioc;
122 #endif
123
124 /*
125 * Find out how many interfaces we have, and malloc
126 * room for information about each one.
127 */
128
129 #ifdef USE_STREAMS_DEVICE_FOR_IF_CONFIG
130 s = open("/dev/ip", O_RDONLY);
131 #else
132 s = socket(AF_INET, SOCK_DGRAM, 0);
133 #endif
134 if (s < 0)
135 return (-1);
136
137 ifc.ifc_len = sizeof(buf);
138 #ifdef STREAMS_TLI
139 ioc.ic_cmd = SIOCGIFCONF;
140 ioc.ic_timout = 0;
141 ioc.ic_dp = (caddr_t)buf;
142 ioc.ic_len = sizeof(buf);
143 if(ioctl(s, I_STR, &ioc) < 0 ||
144 ioc.ic_len < sizeof(struct ifreq)) {
145 (void) close(s);
146 return (-1);
147 }
148 #ifdef SIZE_RETURNED_IN_BUFFER
149 ifc.ifc_len = ioc.ic_len - sizeof(int);
150 ifc.ifc_buf = buf + sizeof(int);
151 #else /* !SIZE_RETURNED_IN_BUFFER */
152 ifc.ifc_len = ioc.ic_len;
153 ifc.ifc_buf = buf;
154 #endif /* !SIZE_RETURNED_IN_BUFFER */
155
156 #else /* !STREAMS_TLI */
157 ifc.ifc_len = sizeof(buf);
158 ifc.ifc_buf = buf;
159 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
160 (void) close(s);
161 return (-1);
162 }
163 #endif /* !STREAMS_TLI */
164
165 /*
166 * if_count here is the count of possible
167 * interfaces we may be interested in... actual
168 * interfaces may be less (some may not be internet,
169 * not all are necessarily up, etc.)
170 */
171
172 #if defined(DEBUG)
173 #if defined(SYSLOG)
174 syslog(LOG_DEBUG, "getifconf: interface count: %d", if_count);
175 #else
176 fprintf(stderr, "getifconf: interface count: %d\n", if_count);
177 #endif
178 #endif
179 if_count = ifc.ifc_len / sizeof (struct ifreq);
180
181 in_ifsni = (struct in_if *)
182 malloc((unsigned) if_count * sizeof (struct in_if));
183 if (in_ifsni == 0) {
184 (void) close(s);
185 return (-1);
186 }
187
188 for (i = j = 0; i < if_count; ++i) {
189 struct sockaddr_in *s_in;
190
191 ifr = &ifc.ifc_req[i];
192 #ifdef STREAMS_TLI
193 ioc.ic_cmd = SIOCGIFFLAGS;
194 ioc.ic_timout = 0;
195 ioc.ic_dp = (caddr_t)ifr;
196 ioc.ic_len = sizeof(struct ifreq);
197 if(ioctl(s, I_STR, &ioc))
198 #else /* !STREAMS_TLI */
199 if (ioctl(s, SIOCGIFFLAGS, (char *)ifr) < 0)
200 #endif
201 continue;
202 if ((ifr->ifr_flags & IFF_UP) == 0)
203 continue;
204 #ifdef STREAMS_TLI
205 ioc.ic_cmd = SIOCGIFADDR;
206 ioc.ic_timout = 0;
207 ioc.ic_dp = (caddr_t)ifr;
208 ioc.ic_len = sizeof(struct ifreq);
209 if(ioctl(s, I_STR, &ioc))
210 #else /* !STREAMS_TLI */
211 if (ioctl(s, SIOCGIFADDR, (char *)ifr) < 0)
212 #endif
213 continue;
214 if (ifr->ifr_addr.sa_family != AF_INET)
215 continue;
216 s_in = (struct sockaddr_in *) &ifr->ifr_addr;
217 addr = s_in->sin_addr.s_addr;
218 in_ifsni[j].i_net = inet_netof(s_in->sin_addr);
219 #if defined(DEBUG)
220 #if defined(SYSLOG)
221 syslog(LOG_DEBUG, "getifconf: interface addr: %s",
222 inet_ntoa(s_in->sin_addr));
223 #else
224 fprintf(stderr, "getifconf: interface addr: %s\n",
225 inet_ntoa(s_in->sin_addr));
226 #endif
227 #endif
228
229 #ifdef STREAMS_TLI
230 ioc.ic_cmd = SIOCGIFNETMASK;
231 ioc.ic_timout = 0;
232 ioc.ic_dp = (caddr_t)ifr;
233 ioc.ic_len = sizeof(struct ifreq);
234 if(ioctl(s, I_STR, &ioc))
235 #else /* !STREAMS_TLI */
236 if (ioctl(s, SIOCGIFNETMASK, (char *)ifr) < 0)
237 #endif
238 continue;
239 s_in = (struct sockaddr_in *) &ifr->ifr_addr;
240 in_ifsni[j].i_subnetmask = ntohl(s_in->sin_addr.s_addr);
241 #if defined(DEBUG)
242 #if defined(SYSLOG)
243 syslog(LOG_DEBUG, "getifconf: interface subnet mask: %s",
244 inet_ntoa(s_in->sin_addr));
245 #else
246 fprintf(stderr, "getifconf: interface subnet mask: %s\n",
247 inet_ntoa(s_in->sin_addr));
248 #endif
249 #endif /*
250 * The following should "never happen". But under SunOS
251 * 3.4, along with the rest of their broken networking code,
252 * SIOCGIFNETMASK can get a netmask which is 0. There
253 * really isn't anything that "right" that we can do
254 * about it, so we'll set their subnet mask to be their
255 * *net*work mask. Which may or may not be right.
256 */
257 if (in_ifsni[j].i_subnetmask == 0) {
258 addr = ntohl(addr);
259 if (IN_CLASSA(addr))
260 in_ifsni[j].i_subnetmask = IN_CLASSA_NET;
261 else if (IN_CLASSB(addr))
262 in_ifsni[j].i_subnetmask = IN_CLASSB_NET;
263 else if (IN_CLASSC(addr))
264 in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
265 else /* what to do ... */
266 in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
267 } else
268 in_ifsni[j].i_bitshift = bsr(in_ifsni[j].i_subnetmask);
269 j++;
270 }
271
272 if_count = j;
273
274 (void) close(s);
275
276 return (if_count);
277
278 #else /* hard-coded subnets */
279
280 if_count = 1;
281
282 in_ifsni = (struct in_if *) malloc(if_count * sizeof (struct in_if));
283 if (in_ifsni == 0) {
284 return (-1);
285 }
286 in_ifsni[0].i_net = 0;
287 in_ifsni[0].i_subnetmask = NETMASK;
288 in_ifsni[0].i_bitshift = bsr(in_ifsni[0].i_subnetmask);
289 return (if_count);
290 #endif
291 }
292
293
294 /*
295 * Return the (sub)network number from an internet address.
296 * "in" is in NBO, return value in host byte order.
297 * If "in" is not a subnet, return 0.
298 */
299
300 u_long
inet_snetof(in)301 inet_snetof(in)
302 u_long in;
303 {
304 register int j;
305 register u_long i = ntohl(in);
306 register u_long net;
307 struct in_addr in_a;
308
309 in_a.s_addr = in;
310 net = inet_netof(in_a);
311
312 /*
313 * Check whether network is a subnet;
314 * if so, return subnet number.
315 */
316 for (j = 0; j < if_count; ++j)
317 #ifdef NETMASK
318 if (1) {
319 #else
320 if (net == in_ifsni[j].i_net) {
321 #endif
322 net = i & in_ifsni[j].i_subnetmask;
323 in_a.s_addr = htonl(net);
324 if (inet_lnaof(in_a) == 0)
325 return (0);
326 else
327 return (net >> in_ifsni[j].i_bitshift);
328 }
329
330 return (0);
331 }
332
333
334 /*
335 * Return the number of bits required to
336 * shift right a mask into a getnetent-able entity.
337 */
338
339 int
bsr(mask)340 bsr(mask)
341 register long mask;
342 {
343 register int count = 0;
344
345 if (mask == 0) /* "never happen", except with SunOS 3.4 */
346 return (0);
347
348 while ((mask & 1) == 0) {
349 ++count;
350 mask >>= 1;
351 }
352 #ifdef DAMAGED_NETMASK
353 count /= 8; /* XXX gag retch puke barf */
354 count *= 8;
355 #endif
356 return (count);
357 }
358
359 #endif
360
361 #ifdef TESTSUBNET
main()362 main()
363 {
364 if(getifconf()<0)
365 printf("getifconf failed!\n");
366 else
367 printf("getifconf succeeded\n");
368 }
369 #endif
370