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