xref: /titanic_44/usr/src/lib/libinetutil/common/inetutil.c (revision 6e91bba0d6c6bdabbba62cefae583715a4a58e2a)
1e11c3f44Smeem /*
2e11c3f44Smeem  * CDDL HEADER START
3e11c3f44Smeem  *
4e11c3f44Smeem  * The contents of this file are subject to the terms of the
5e11c3f44Smeem  * Common Development and Distribution License (the "License").
6e11c3f44Smeem  * You may not use this file except in compliance with the License.
7e11c3f44Smeem  *
8e11c3f44Smeem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9e11c3f44Smeem  * or http://www.opensolaris.org/os/licensing.
10e11c3f44Smeem  * See the License for the specific language governing permissions
11e11c3f44Smeem  * and limitations under the License.
12e11c3f44Smeem  *
13e11c3f44Smeem  * When distributing Covered Code, include this CDDL HEADER in each
14e11c3f44Smeem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15e11c3f44Smeem  * If applicable, add the following below this CDDL HEADER, with the
16e11c3f44Smeem  * fields enclosed by brackets "[]" replaced with your own identifying
17e11c3f44Smeem  * information: Portions Copyright [yyyy] [name of copyright owner]
18e11c3f44Smeem  *
19e11c3f44Smeem  * CDDL HEADER END
20e11c3f44Smeem  */
21e11c3f44Smeem 
22e11c3f44Smeem /*
23*6e91bba0SGirish Moodalbail  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24e11c3f44Smeem  * Use is subject to license terms.
25e11c3f44Smeem  */
26e11c3f44Smeem 
27e11c3f44Smeem #include <unistd.h>
28e11c3f44Smeem #include <netinet/in.h>
29e11c3f44Smeem #include <libinetutil.h>
30*6e91bba0SGirish Moodalbail #include <inet/ip.h>
31*6e91bba0SGirish Moodalbail #include <strings.h>
32*6e91bba0SGirish Moodalbail #include <errno.h>
33*6e91bba0SGirish Moodalbail #include <libsocket_priv.h>
34e11c3f44Smeem 
35e11c3f44Smeem /*
36e11c3f44Smeem  * Internet utility functions.
37e11c3f44Smeem  */
38e11c3f44Smeem 
39e11c3f44Smeem /*
40e11c3f44Smeem  * Given a host-order address, calculate client's default net mask.
41e11c3f44Smeem  * Consult netmasks database to see if net is further subnetted.
42e11c3f44Smeem  * We'll only snag the first netmask that matches our criteria.
43e11c3f44Smeem  * We return the resultant netmask in host order.
44e11c3f44Smeem  */
45e11c3f44Smeem void
46e11c3f44Smeem get_netmask4(const struct in_addr *n_addrp, struct in_addr *s_addrp)
47e11c3f44Smeem {
48e11c3f44Smeem 	struct in_addr	hp, tp;
49e11c3f44Smeem 
50e11c3f44Smeem 	/*
51e11c3f44Smeem 	 * First check if VLSM is in use.
52e11c3f44Smeem 	 */
53e11c3f44Smeem 	hp.s_addr = htonl(n_addrp->s_addr);
54e11c3f44Smeem 	if (getnetmaskbyaddr(hp, &tp) == 0) {
55e11c3f44Smeem 		s_addrp->s_addr = ntohl(tp.s_addr);
56e11c3f44Smeem 		return;
57e11c3f44Smeem 	}
58e11c3f44Smeem 
59e11c3f44Smeem 	/*
60e11c3f44Smeem 	 * Fall back on standard classed networks.
61e11c3f44Smeem 	 */
62e11c3f44Smeem 	if (IN_CLASSA(n_addrp->s_addr))
63e11c3f44Smeem 		s_addrp->s_addr = IN_CLASSA_NET;
64e11c3f44Smeem 	else if (IN_CLASSB(n_addrp->s_addr))
65e11c3f44Smeem 		s_addrp->s_addr = IN_CLASSB_NET;
66e11c3f44Smeem 	else if (IN_CLASSC(n_addrp->s_addr))
67e11c3f44Smeem 		s_addrp->s_addr = IN_CLASSC_NET;
68e11c3f44Smeem 	else
69e11c3f44Smeem 		s_addrp->s_addr = IN_CLASSE_NET;
70e11c3f44Smeem }
71e11c3f44Smeem 
72e11c3f44Smeem /*
73e11c3f44Smeem  * Checks if the IP addresses `ssp1' and `ssp2' are equal.
74e11c3f44Smeem  */
75e11c3f44Smeem boolean_t
76e11c3f44Smeem sockaddrcmp(const struct sockaddr_storage *ssp1,
77e11c3f44Smeem     const struct sockaddr_storage *ssp2)
78e11c3f44Smeem {
79e11c3f44Smeem 	struct in_addr addr1, addr2;
80e11c3f44Smeem 	const struct in6_addr *addr6p1, *addr6p2;
81e11c3f44Smeem 
82e11c3f44Smeem 	if (ssp1->ss_family != ssp2->ss_family)
83e11c3f44Smeem 		return (B_FALSE);
84e11c3f44Smeem 
85e11c3f44Smeem 	if (ssp1 == ssp2)
86e11c3f44Smeem 		return (B_TRUE);
87e11c3f44Smeem 
88e11c3f44Smeem 	switch (ssp1->ss_family) {
89e11c3f44Smeem 	case AF_INET:
90e11c3f44Smeem 		addr1 = ((const struct sockaddr_in *)ssp1)->sin_addr;
91e11c3f44Smeem 		addr2 = ((const struct sockaddr_in *)ssp2)->sin_addr;
92e11c3f44Smeem 		return (addr1.s_addr == addr2.s_addr);
93e11c3f44Smeem 	case AF_INET6:
94e11c3f44Smeem 		addr6p1 = &((const struct sockaddr_in6 *)ssp1)->sin6_addr;
95e11c3f44Smeem 		addr6p2 = &((const struct sockaddr_in6 *)ssp2)->sin6_addr;
96e11c3f44Smeem 		return (IN6_ARE_ADDR_EQUAL(addr6p1, addr6p2));
97e11c3f44Smeem 	}
98e11c3f44Smeem 	return (B_FALSE);
99e11c3f44Smeem }
100*6e91bba0SGirish Moodalbail 
101*6e91bba0SGirish Moodalbail /*
102*6e91bba0SGirish Moodalbail  * Stores the netmask in `mask' for the given prefixlen `plen' and also sets
103*6e91bba0SGirish Moodalbail  * `ss_family' in `mask'.
104*6e91bba0SGirish Moodalbail  */
105*6e91bba0SGirish Moodalbail int
106*6e91bba0SGirish Moodalbail plen2mask(uint_t prefixlen, sa_family_t af, struct sockaddr_storage *mask)
107*6e91bba0SGirish Moodalbail {
108*6e91bba0SGirish Moodalbail 	uint8_t	*addr;
109*6e91bba0SGirish Moodalbail 
110*6e91bba0SGirish Moodalbail 	bzero(mask, sizeof (*mask));
111*6e91bba0SGirish Moodalbail 	mask->ss_family = af;
112*6e91bba0SGirish Moodalbail 	if (af == AF_INET) {
113*6e91bba0SGirish Moodalbail 		if (prefixlen > IP_ABITS)
114*6e91bba0SGirish Moodalbail 			return (EINVAL);
115*6e91bba0SGirish Moodalbail 		addr = (uint8_t *)&((struct sockaddr_in *)mask)->
116*6e91bba0SGirish Moodalbail 		    sin_addr.s_addr;
117*6e91bba0SGirish Moodalbail 	} else {
118*6e91bba0SGirish Moodalbail 		if (prefixlen > IPV6_ABITS)
119*6e91bba0SGirish Moodalbail 			return (EINVAL);
120*6e91bba0SGirish Moodalbail 		addr = (uint8_t *)&((struct sockaddr_in6 *)mask)->
121*6e91bba0SGirish Moodalbail 		    sin6_addr.s6_addr;
122*6e91bba0SGirish Moodalbail 	}
123*6e91bba0SGirish Moodalbail 
124*6e91bba0SGirish Moodalbail 	while (prefixlen > 0) {
125*6e91bba0SGirish Moodalbail 		if (prefixlen >= 8) {
126*6e91bba0SGirish Moodalbail 			*addr++ = 0xFF;
127*6e91bba0SGirish Moodalbail 			prefixlen -= 8;
128*6e91bba0SGirish Moodalbail 			continue;
129*6e91bba0SGirish Moodalbail 		}
130*6e91bba0SGirish Moodalbail 		*addr |= 1 << (8 - prefixlen);
131*6e91bba0SGirish Moodalbail 		prefixlen--;
132*6e91bba0SGirish Moodalbail 	}
133*6e91bba0SGirish Moodalbail 	return (0);
134*6e91bba0SGirish Moodalbail }
135*6e91bba0SGirish Moodalbail 
136*6e91bba0SGirish Moodalbail /*
137*6e91bba0SGirish Moodalbail  * Convert a mask to a prefix length.
138*6e91bba0SGirish Moodalbail  * Returns prefix length on success, -1 otherwise.
139*6e91bba0SGirish Moodalbail  */
140*6e91bba0SGirish Moodalbail int
141*6e91bba0SGirish Moodalbail mask2plen(const struct sockaddr_storage *mask)
142*6e91bba0SGirish Moodalbail {
143*6e91bba0SGirish Moodalbail 	int rc = 0;
144*6e91bba0SGirish Moodalbail 	uint8_t last;
145*6e91bba0SGirish Moodalbail 	uint8_t *addr;
146*6e91bba0SGirish Moodalbail 	int limit;
147*6e91bba0SGirish Moodalbail 
148*6e91bba0SGirish Moodalbail 	if (mask->ss_family == AF_INET) {
149*6e91bba0SGirish Moodalbail 		limit = IP_ABITS;
150*6e91bba0SGirish Moodalbail 		addr = (uint8_t *)&((struct sockaddr_in *)mask)->
151*6e91bba0SGirish Moodalbail 		    sin_addr.s_addr;
152*6e91bba0SGirish Moodalbail 	} else {
153*6e91bba0SGirish Moodalbail 		limit = IPV6_ABITS;
154*6e91bba0SGirish Moodalbail 		addr = (uint8_t *)&((struct sockaddr_in6 *)mask)->
155*6e91bba0SGirish Moodalbail 		    sin6_addr.s6_addr;
156*6e91bba0SGirish Moodalbail 	}
157*6e91bba0SGirish Moodalbail 
158*6e91bba0SGirish Moodalbail 	while (*addr == 0xff) {
159*6e91bba0SGirish Moodalbail 		rc += 8;
160*6e91bba0SGirish Moodalbail 		if (rc == limit)
161*6e91bba0SGirish Moodalbail 			return (limit);
162*6e91bba0SGirish Moodalbail 		addr++;
163*6e91bba0SGirish Moodalbail 	}
164*6e91bba0SGirish Moodalbail 
165*6e91bba0SGirish Moodalbail 	last = *addr;
166*6e91bba0SGirish Moodalbail 	while (last != 0) {
167*6e91bba0SGirish Moodalbail 		rc++;
168*6e91bba0SGirish Moodalbail 		last = (last << 1) & 0xff;
169*6e91bba0SGirish Moodalbail 	}
170*6e91bba0SGirish Moodalbail 
171*6e91bba0SGirish Moodalbail 	return (rc);
172*6e91bba0SGirish Moodalbail }
173*6e91bba0SGirish Moodalbail 
174*6e91bba0SGirish Moodalbail /*
175*6e91bba0SGirish Moodalbail  * Returns B_TRUE if the address in `ss' is INADDR_ANY for IPv4 or
176*6e91bba0SGirish Moodalbail  * :: for IPv6. Otherwise, returns B_FALSE.
177*6e91bba0SGirish Moodalbail  */
178*6e91bba0SGirish Moodalbail boolean_t
179*6e91bba0SGirish Moodalbail sockaddrunspec(const struct sockaddr_storage *ss)
180*6e91bba0SGirish Moodalbail {
181*6e91bba0SGirish Moodalbail 	struct sockaddr_storage zeroaddr = {0};
182*6e91bba0SGirish Moodalbail 
183*6e91bba0SGirish Moodalbail 	switch (ss->ss_family) {
184*6e91bba0SGirish Moodalbail 	case AF_INET:
185*6e91bba0SGirish Moodalbail 		return (((struct sockaddr_in *)ss)->sin_addr.s_addr ==
186*6e91bba0SGirish Moodalbail 		    INADDR_ANY);
187*6e91bba0SGirish Moodalbail 	case AF_INET6:
188*6e91bba0SGirish Moodalbail 		return (IN6_IS_ADDR_UNSPECIFIED(
189*6e91bba0SGirish Moodalbail 		    &((struct sockaddr_in6 *)ss)->sin6_addr));
190*6e91bba0SGirish Moodalbail 	}
191*6e91bba0SGirish Moodalbail 
192*6e91bba0SGirish Moodalbail 	return (bcmp(&zeroaddr, ss, sizeof (zeroaddr)) == 0);
193*6e91bba0SGirish Moodalbail }
194