xref: /titanic_50/usr/src/lib/libsocket/inet/netmasks.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * All routines necessary to deal the "netmasks" database.  The sources
31*7c478bd9Sstevel@tonic-gate  * contain mappings between 32 bit Internet addresses and corresponding
32*7c478bd9Sstevel@tonic-gate  * 32 bit Internet address masks. The addresses are in dotted internet
33*7c478bd9Sstevel@tonic-gate  * address notation.
34*7c478bd9Sstevel@tonic-gate  */
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate #include <stdio.h>
37*7c478bd9Sstevel@tonic-gate #include <ctype.h>
38*7c478bd9Sstevel@tonic-gate #include <string.h>
39*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/socket.h>
42*7c478bd9Sstevel@tonic-gate #include <net/if.h>
43*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
44*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
45*7c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate static int str2addr(const char *, int, void *, char *, int);
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate static DEFINE_NSS_DB_ROOT(db_root);
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate static void
52*7c478bd9Sstevel@tonic-gate _nss_initf_netmasks(nss_db_params_t *p)
53*7c478bd9Sstevel@tonic-gate {
54*7c478bd9Sstevel@tonic-gate 	p->name = NSS_DBNAM_NETMASKS;
55*7c478bd9Sstevel@tonic-gate 	p->default_config = NSS_DEFCONF_NETMASKS;
56*7c478bd9Sstevel@tonic-gate }
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /*
59*7c478bd9Sstevel@tonic-gate  * Print a network number such as 129.144 as well as an IP address.
60*7c478bd9Sstevel@tonic-gate  * Assumes network byte order for both IP addresses and network numbers
61*7c478bd9Sstevel@tonic-gate  * (Network numbers are normally passed around in host byte order).
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate static char *
64*7c478bd9Sstevel@tonic-gate inet_nettoa(struct in_addr in)
65*7c478bd9Sstevel@tonic-gate {
66*7c478bd9Sstevel@tonic-gate 	uint32_t addr = in.s_addr;
67*7c478bd9Sstevel@tonic-gate 	uchar_t *up = (uchar_t *)&addr;
68*7c478bd9Sstevel@tonic-gate 	static char result[256];
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	/* Omit leading zeros */
71*7c478bd9Sstevel@tonic-gate 	if (up[0]) {
72*7c478bd9Sstevel@tonic-gate 		(void) sprintf(result, "%d.%d.%d.%d",
73*7c478bd9Sstevel@tonic-gate 		    up[0], up[1], up[2], up[3]);
74*7c478bd9Sstevel@tonic-gate 	} else if (up[1]) {
75*7c478bd9Sstevel@tonic-gate 		(void) sprintf(result, "%d.%d.%d", up[1], up[2], up[3]);
76*7c478bd9Sstevel@tonic-gate 	} else if (up[2]) {
77*7c478bd9Sstevel@tonic-gate 		(void) sprintf(result, "%d.%d", up[2], up[3]);
78*7c478bd9Sstevel@tonic-gate 	} else {
79*7c478bd9Sstevel@tonic-gate 		(void) sprintf(result, "%d", up[3]);
80*7c478bd9Sstevel@tonic-gate 	}
81*7c478bd9Sstevel@tonic-gate 	return (result);
82*7c478bd9Sstevel@tonic-gate }
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /*
85*7c478bd9Sstevel@tonic-gate  * Given a 32 bit key look it up in the netmasks database
86*7c478bd9Sstevel@tonic-gate  * based on the "netmasks" policy in /etc/nsswitch.conf.
87*7c478bd9Sstevel@tonic-gate  * If the key is a network number with the trailing zero's removed
88*7c478bd9Sstevel@tonic-gate  * (e.g. "192.9.200") this routine can't use inet_ntoa to convert
89*7c478bd9Sstevel@tonic-gate  * the address to the string key.
90*7c478bd9Sstevel@tonic-gate  * Returns zero if successful, non-zero otherwise.
91*7c478bd9Sstevel@tonic-gate  */
92*7c478bd9Sstevel@tonic-gate static int
93*7c478bd9Sstevel@tonic-gate getnetmaskbykey(const struct in_addr addr, struct in_addr *mask)
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate 	nss_XbyY_args_t arg;
96*7c478bd9Sstevel@tonic-gate 	nss_status_t	res;
97*7c478bd9Sstevel@tonic-gate 	char		tmp[NSS_LINELEN_NETMASKS];
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	/*
100*7c478bd9Sstevel@tonic-gate 	 * let the backend do the allocation to store stuff for parsing.
101*7c478bd9Sstevel@tonic-gate 	 * To simplify things, we put the dotted internet address form of
102*7c478bd9Sstevel@tonic-gate 	 * the network address in the 'name' field as a filter to speed
103*7c478bd9Sstevel@tonic-gate 	 * up the lookup.
104*7c478bd9Sstevel@tonic-gate 	 */
105*7c478bd9Sstevel@tonic-gate 	NSS_XbyY_INIT(&arg, mask, NULL, 0, str2addr);
106*7c478bd9Sstevel@tonic-gate 	(void) strcpy(tmp, inet_nettoa(addr));
107*7c478bd9Sstevel@tonic-gate 	arg.key.name = tmp;
108*7c478bd9Sstevel@tonic-gate 	res = nss_search(&db_root, _nss_initf_netmasks,
109*7c478bd9Sstevel@tonic-gate 			NSS_DBOP_NETMASKS_BYNET, &arg);
110*7c478bd9Sstevel@tonic-gate 	(void) NSS_XbyY_FINI(&arg);
111*7c478bd9Sstevel@tonic-gate 	return (arg.status = res);
112*7c478bd9Sstevel@tonic-gate }
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate /*
115*7c478bd9Sstevel@tonic-gate  * Given a 32 bit internet network number, it finds the corresponding netmask
116*7c478bd9Sstevel@tonic-gate  * address based on the "netmasks" policy in /etc/nsswitch.conf.
117*7c478bd9Sstevel@tonic-gate  * Returns zero if successful, non-zero otherwise.
118*7c478bd9Sstevel@tonic-gate  * Check both for the (masked) network number and the shifted network
119*7c478bd9Sstevel@tonic-gate  * number (e.g., both "10.0.0.0" and "10").
120*7c478bd9Sstevel@tonic-gate  * Assumes that the caller passes in an unshifted number (or an IP address).
121*7c478bd9Sstevel@tonic-gate  */
122*7c478bd9Sstevel@tonic-gate int
123*7c478bd9Sstevel@tonic-gate getnetmaskbynet(const struct in_addr net, struct in_addr *mask)
124*7c478bd9Sstevel@tonic-gate {
125*7c478bd9Sstevel@tonic-gate 	struct in_addr net1, net2;
126*7c478bd9Sstevel@tonic-gate 	uint32_t i;
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	i = ntohl(net.s_addr);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	/*
131*7c478bd9Sstevel@tonic-gate 	 * Try looking for the network number both with and without
132*7c478bd9Sstevel@tonic-gate 	 * the trailing zeros.
133*7c478bd9Sstevel@tonic-gate 	 */
134*7c478bd9Sstevel@tonic-gate 	if ((i & IN_CLASSA_NET) == 0) {
135*7c478bd9Sstevel@tonic-gate 		/* Assume already a right-shifted network number */
136*7c478bd9Sstevel@tonic-gate 		net2.s_addr = htonl(i);
137*7c478bd9Sstevel@tonic-gate 		if ((i & IN_CLASSB_NET) != 0) {
138*7c478bd9Sstevel@tonic-gate 			net1.s_addr = htonl(i << IN_CLASSC_NSHIFT);
139*7c478bd9Sstevel@tonic-gate 		} else if ((i & IN_CLASSC_NET) != 0) {
140*7c478bd9Sstevel@tonic-gate 			net1.s_addr = htonl(i << IN_CLASSB_NSHIFT);
141*7c478bd9Sstevel@tonic-gate 		} else {
142*7c478bd9Sstevel@tonic-gate 			net1.s_addr = htonl(i << IN_CLASSA_NSHIFT);
143*7c478bd9Sstevel@tonic-gate 		}
144*7c478bd9Sstevel@tonic-gate 	} else if (IN_CLASSA(i)) {
145*7c478bd9Sstevel@tonic-gate 		net1.s_addr = htonl(i & IN_CLASSA_NET);
146*7c478bd9Sstevel@tonic-gate 		net2.s_addr = htonl(i >> IN_CLASSA_NSHIFT);
147*7c478bd9Sstevel@tonic-gate 	} else if (IN_CLASSB(i)) {
148*7c478bd9Sstevel@tonic-gate 		net1.s_addr = htonl(i & IN_CLASSB_NET);
149*7c478bd9Sstevel@tonic-gate 		net2.s_addr = htonl(i >> IN_CLASSB_NSHIFT);
150*7c478bd9Sstevel@tonic-gate 	} else {
151*7c478bd9Sstevel@tonic-gate 		net1.s_addr = htonl(i & IN_CLASSC_NET);
152*7c478bd9Sstevel@tonic-gate 		net2.s_addr = htonl(i >> IN_CLASSC_NSHIFT);
153*7c478bd9Sstevel@tonic-gate 	}
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	if (getnetmaskbykey(net1, mask) == 0) {
156*7c478bd9Sstevel@tonic-gate 		return (0);
157*7c478bd9Sstevel@tonic-gate 	}
158*7c478bd9Sstevel@tonic-gate 	if (getnetmaskbykey(net2, mask) == 0) {
159*7c478bd9Sstevel@tonic-gate 		return (0);
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 	return (-1);
162*7c478bd9Sstevel@tonic-gate }
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate /*
165*7c478bd9Sstevel@tonic-gate  * Find the netmask used for an IP address.
166*7c478bd9Sstevel@tonic-gate  * Returns zero if successful, non-zero otherwise.
167*7c478bd9Sstevel@tonic-gate  *
168*7c478bd9Sstevel@tonic-gate  * Support Variable Length Subnetmasks by looking for the longest
169*7c478bd9Sstevel@tonic-gate  * matching subnetmask in the database.
170*7c478bd9Sstevel@tonic-gate  * Start by looking for a match for the full IP address and
171*7c478bd9Sstevel@tonic-gate  * mask off one rightmost bit after another until we find a match.
172*7c478bd9Sstevel@tonic-gate  * Note that for a match the found netmask must match what was used
173*7c478bd9Sstevel@tonic-gate  * for the lookup masking.
174*7c478bd9Sstevel@tonic-gate  * As a fallback for compatibility finally lookup the network
175*7c478bd9Sstevel@tonic-gate  * number with and without the trailing zeros.
176*7c478bd9Sstevel@tonic-gate  * In order to suppress redundant lookups in the name service
177*7c478bd9Sstevel@tonic-gate  * we keep the previous lookup key and compare against it before
178*7c478bd9Sstevel@tonic-gate  * doing the lookup.
179*7c478bd9Sstevel@tonic-gate  */
180*7c478bd9Sstevel@tonic-gate int
181*7c478bd9Sstevel@tonic-gate getnetmaskbyaddr(const struct in_addr addr, struct in_addr *mask)
182*7c478bd9Sstevel@tonic-gate {
183*7c478bd9Sstevel@tonic-gate 	struct in_addr prevnet, net;
184*7c478bd9Sstevel@tonic-gate 	uint32_t i, maskoff;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	i = ntohl(addr.s_addr);
187*7c478bd9Sstevel@tonic-gate 	prevnet.s_addr = 0;
188*7c478bd9Sstevel@tonic-gate 	mask->s_addr = 0;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	for (maskoff = 0xFFFFFFFF; maskoff != 0; maskoff = maskoff << 1) {
191*7c478bd9Sstevel@tonic-gate 		net.s_addr = htonl(i & maskoff);
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 		if (net.s_addr != prevnet.s_addr) {
194*7c478bd9Sstevel@tonic-gate 			if (getnetmaskbykey(net, mask) != 0) {
195*7c478bd9Sstevel@tonic-gate 				mask->s_addr = 0;
196*7c478bd9Sstevel@tonic-gate 			}
197*7c478bd9Sstevel@tonic-gate 		}
198*7c478bd9Sstevel@tonic-gate 		if (htonl(maskoff) == mask->s_addr)
199*7c478bd9Sstevel@tonic-gate 			return (0);
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 		prevnet.s_addr = net.s_addr;
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	/*
205*7c478bd9Sstevel@tonic-gate 	 * Non-VLSM fallback.
206*7c478bd9Sstevel@tonic-gate 	 * Try looking for the network number with and without the trailing
207*7c478bd9Sstevel@tonic-gate 	 * zeros.
208*7c478bd9Sstevel@tonic-gate 	 */
209*7c478bd9Sstevel@tonic-gate 	return (getnetmaskbynet(addr, mask));
210*7c478bd9Sstevel@tonic-gate }
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate /*
213*7c478bd9Sstevel@tonic-gate  * Parse netmasks entry into its components. The network address is placed
214*7c478bd9Sstevel@tonic-gate  * in buffer for use by check_addr for 'files' backend, to match the network
215*7c478bd9Sstevel@tonic-gate  * address. The network address is placed in the buffer as a network order
216*7c478bd9Sstevel@tonic-gate  * internet address, if buffer is non null. The network order form of the mask
217*7c478bd9Sstevel@tonic-gate  * itself is placed in 'ent'.
218*7c478bd9Sstevel@tonic-gate  */
219*7c478bd9Sstevel@tonic-gate int
220*7c478bd9Sstevel@tonic-gate str2addr(const char *instr, int lenstr, void *ent, char *buffer, int buflen)
221*7c478bd9Sstevel@tonic-gate {
222*7c478bd9Sstevel@tonic-gate 	int	retval;
223*7c478bd9Sstevel@tonic-gate 	struct in_addr	*mask = (struct in_addr *)ent;
224*7c478bd9Sstevel@tonic-gate 	const char	*p, *limit, *start;
225*7c478bd9Sstevel@tonic-gate 	struct in_addr	addr;
226*7c478bd9Sstevel@tonic-gate 	int		i;
227*7c478bd9Sstevel@tonic-gate 	char		tmp[NSS_LINELEN_NETMASKS];
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	p = instr;
230*7c478bd9Sstevel@tonic-gate 	limit = p + lenstr;
231*7c478bd9Sstevel@tonic-gate 	retval = NSS_STR_PARSE_PARSE;
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	while (p < limit && isspace(*p))	/* skip leading whitespace */
234*7c478bd9Sstevel@tonic-gate 		p++;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	if (buffer) {	/* for 'files' backend verification */
237*7c478bd9Sstevel@tonic-gate 		for (start = p, i = 0; p < limit && !isspace(*p); p++)
238*7c478bd9Sstevel@tonic-gate 			i++;
239*7c478bd9Sstevel@tonic-gate 		if (p < limit && i < buflen) {
240*7c478bd9Sstevel@tonic-gate 			(void) memcpy(tmp, start, i);
241*7c478bd9Sstevel@tonic-gate 			tmp[i] = '\0';
242*7c478bd9Sstevel@tonic-gate 			addr.s_addr = inet_addr(tmp);
243*7c478bd9Sstevel@tonic-gate 			/* Addr will always be an ipv4 address (32bits) */
244*7c478bd9Sstevel@tonic-gate 			if (addr.s_addr == 0xffffffffUL)
245*7c478bd9Sstevel@tonic-gate 				return (NSS_STR_PARSE_PARSE);
246*7c478bd9Sstevel@tonic-gate 			else {
247*7c478bd9Sstevel@tonic-gate 				(void) memcpy(buffer, (char *)&addr,
248*7c478bd9Sstevel@tonic-gate 				    sizeof (struct in_addr));
249*7c478bd9Sstevel@tonic-gate 			}
250*7c478bd9Sstevel@tonic-gate 		} else
251*7c478bd9Sstevel@tonic-gate 			return (NSS_STR_PARSE_ERANGE);
252*7c478bd9Sstevel@tonic-gate 	}
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	while (p < limit && isspace(*p))	/* skip intermediate */
255*7c478bd9Sstevel@tonic-gate 		p++;
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	if (mask) {
258*7c478bd9Sstevel@tonic-gate 		for (start = p, i = 0; p < limit && !isspace(*p); p++)
259*7c478bd9Sstevel@tonic-gate 			i++;
260*7c478bd9Sstevel@tonic-gate 		if (p <= limit) {
261*7c478bd9Sstevel@tonic-gate 			if ((i + 1) > NSS_LINELEN_NETMASKS)
262*7c478bd9Sstevel@tonic-gate 				return (NSS_STR_PARSE_ERANGE);
263*7c478bd9Sstevel@tonic-gate 			(void) memcpy(tmp, start, i);
264*7c478bd9Sstevel@tonic-gate 			tmp[i] = '\0';
265*7c478bd9Sstevel@tonic-gate 			addr.s_addr = inet_addr(tmp);
266*7c478bd9Sstevel@tonic-gate 			/* Addr will always be an ipv4 address (32bits) */
267*7c478bd9Sstevel@tonic-gate 			if (addr.s_addr == 0xffffffffUL)
268*7c478bd9Sstevel@tonic-gate 				retval = NSS_STR_PARSE_PARSE;
269*7c478bd9Sstevel@tonic-gate 			else {
270*7c478bd9Sstevel@tonic-gate 				mask->s_addr = addr.s_addr;
271*7c478bd9Sstevel@tonic-gate 				retval = NSS_STR_PARSE_SUCCESS;
272*7c478bd9Sstevel@tonic-gate 			}
273*7c478bd9Sstevel@tonic-gate 		}
274*7c478bd9Sstevel@tonic-gate 	}
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	return (retval);
277*7c478bd9Sstevel@tonic-gate }
278