17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52a9459bdSsangeeta  * Common Development and Distribution License (the "License").
62a9459bdSsangeeta  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21e11c3f44Smeem 
227c478bd9Sstevel@tonic-gate /*
23*64639aafSDarren Reed  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <unistd.h>
277c478bd9Sstevel@tonic-gate #include <netinet/in.h>
287c478bd9Sstevel@tonic-gate #include <libinetutil.h>
296e91bba0SGirish Moodalbail #include <inet/ip.h>
306e91bba0SGirish Moodalbail #include <strings.h>
31*64639aafSDarren Reed #include <stddef.h>
326e91bba0SGirish Moodalbail #include <errno.h>
336e91bba0SGirish Moodalbail #include <libsocket_priv.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate /*
36e11c3f44Smeem  * Internet utility functions.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Given a host-order address, calculate client's default net mask.
417c478bd9Sstevel@tonic-gate  * Consult netmasks database to see if net is further subnetted.
427c478bd9Sstevel@tonic-gate  * We'll only snag the first netmask that matches our criteria.
437c478bd9Sstevel@tonic-gate  * We return the resultant netmask in host order.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate void
get_netmask4(const struct in_addr * n_addrp,struct in_addr * s_addrp)467c478bd9Sstevel@tonic-gate get_netmask4(const struct in_addr *n_addrp, struct in_addr *s_addrp)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate 	struct in_addr	hp, tp;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate 	/*
517c478bd9Sstevel@tonic-gate 	 * First check if VLSM is in use.
527c478bd9Sstevel@tonic-gate 	 */
537c478bd9Sstevel@tonic-gate 	hp.s_addr = htonl(n_addrp->s_addr);
547c478bd9Sstevel@tonic-gate 	if (getnetmaskbyaddr(hp, &tp) == 0) {
557c478bd9Sstevel@tonic-gate 		s_addrp->s_addr = ntohl(tp.s_addr);
567c478bd9Sstevel@tonic-gate 		return;
577c478bd9Sstevel@tonic-gate 	}
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	/*
607c478bd9Sstevel@tonic-gate 	 * Fall back on standard classed networks.
617c478bd9Sstevel@tonic-gate 	 */
627c478bd9Sstevel@tonic-gate 	if (IN_CLASSA(n_addrp->s_addr))
637c478bd9Sstevel@tonic-gate 		s_addrp->s_addr = IN_CLASSA_NET;
647c478bd9Sstevel@tonic-gate 	else if (IN_CLASSB(n_addrp->s_addr))
657c478bd9Sstevel@tonic-gate 		s_addrp->s_addr = IN_CLASSB_NET;
662a9459bdSsangeeta 	else if (IN_CLASSC(n_addrp->s_addr))
677c478bd9Sstevel@tonic-gate 		s_addrp->s_addr = IN_CLASSC_NET;
682a9459bdSsangeeta 	else
692a9459bdSsangeeta 		s_addrp->s_addr = IN_CLASSE_NET;
707c478bd9Sstevel@tonic-gate }
71e11c3f44Smeem 
72e11c3f44Smeem /*
73e11c3f44Smeem  * Checks if the IP addresses `ssp1' and `ssp2' are equal.
74e11c3f44Smeem  */
75e11c3f44Smeem boolean_t
sockaddrcmp(const struct sockaddr_storage * ssp1,const struct sockaddr_storage * ssp2)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 }
1006e91bba0SGirish Moodalbail 
1016e91bba0SGirish Moodalbail /*
1026e91bba0SGirish Moodalbail  * Stores the netmask in `mask' for the given prefixlen `plen' and also sets
103*64639aafSDarren Reed  * `sa_family' in `mask'. Because this function does not require aligned
104*64639aafSDarren Reed  * access to the data inside of the sockaddr_in/6 structures, the code can
105*64639aafSDarren Reed  * use offsetof() to find the right place in the incoming structure. Why is
106*64639aafSDarren Reed  * using that beneficial? Less issues with lint. When using a direct cast
107*64639aafSDarren Reed  * of the struct sockaddr_storage structure to sockaddr_in6, a lint warning
108*64639aafSDarren Reed  * is generated because the former is composed of 16bit & 8bit elements whilst
109*64639aafSDarren Reed  * sockaddr_in6 has a 32bit alignment requirement.
1106e91bba0SGirish Moodalbail  */
1116e91bba0SGirish Moodalbail int
plen2mask(uint_t prefixlen,sa_family_t af,struct sockaddr * mask)112*64639aafSDarren Reed plen2mask(uint_t prefixlen, sa_family_t af, struct sockaddr *mask)
1136e91bba0SGirish Moodalbail {
1146e91bba0SGirish Moodalbail 	uint8_t	*addr;
1156e91bba0SGirish Moodalbail 
1166e91bba0SGirish Moodalbail 	if (af == AF_INET) {
1176e91bba0SGirish Moodalbail 		if (prefixlen > IP_ABITS)
1186e91bba0SGirish Moodalbail 			return (EINVAL);
119*64639aafSDarren Reed 		bzero(mask, sizeof (struct sockaddr_in));
120*64639aafSDarren Reed 		addr = (uint8_t *)mask;
121*64639aafSDarren Reed 		addr += offsetof(struct sockaddr_in, sin_addr);
1226e91bba0SGirish Moodalbail 	} else {
1236e91bba0SGirish Moodalbail 		if (prefixlen > IPV6_ABITS)
1246e91bba0SGirish Moodalbail 			return (EINVAL);
125*64639aafSDarren Reed 		bzero(mask, sizeof (struct sockaddr_in6));
126*64639aafSDarren Reed 		addr = (uint8_t *)mask;
127*64639aafSDarren Reed 		addr += offsetof(struct sockaddr_in6, sin6_addr);
1286e91bba0SGirish Moodalbail 	}
129*64639aafSDarren Reed 	mask->sa_family = af;
1306e91bba0SGirish Moodalbail 
1316e91bba0SGirish Moodalbail 	while (prefixlen > 0) {
1326e91bba0SGirish Moodalbail 		if (prefixlen >= 8) {
1336e91bba0SGirish Moodalbail 			*addr++ = 0xFF;
1346e91bba0SGirish Moodalbail 			prefixlen -= 8;
1356e91bba0SGirish Moodalbail 			continue;
1366e91bba0SGirish Moodalbail 		}
1376e91bba0SGirish Moodalbail 		*addr |= 1 << (8 - prefixlen);
1386e91bba0SGirish Moodalbail 		prefixlen--;
1396e91bba0SGirish Moodalbail 	}
1406e91bba0SGirish Moodalbail 	return (0);
1416e91bba0SGirish Moodalbail }
1426e91bba0SGirish Moodalbail 
1436e91bba0SGirish Moodalbail /*
1446e91bba0SGirish Moodalbail  * Convert a mask to a prefix length.
1456e91bba0SGirish Moodalbail  * Returns prefix length on success, -1 otherwise.
146*64639aafSDarren Reed  * The comments (above) for plen2mask about the use of `mask' also apply
147*64639aafSDarren Reed  * to this function and the choice to use offsetof here too.
1486e91bba0SGirish Moodalbail  */
1496e91bba0SGirish Moodalbail int
mask2plen(const struct sockaddr * mask)150*64639aafSDarren Reed mask2plen(const struct sockaddr *mask)
1516e91bba0SGirish Moodalbail {
1526e91bba0SGirish Moodalbail 	int rc = 0;
1536e91bba0SGirish Moodalbail 	uint8_t last;
1546e91bba0SGirish Moodalbail 	uint8_t *addr;
1556e91bba0SGirish Moodalbail 	int limit;
1566e91bba0SGirish Moodalbail 
157*64639aafSDarren Reed 	if (mask->sa_family == AF_INET) {
1586e91bba0SGirish Moodalbail 		limit = IP_ABITS;
159*64639aafSDarren Reed 		addr = (uint8_t *)mask;
160*64639aafSDarren Reed 		addr += offsetof(struct sockaddr_in, sin_addr);
1616e91bba0SGirish Moodalbail 	} else {
1626e91bba0SGirish Moodalbail 		limit = IPV6_ABITS;
163*64639aafSDarren Reed 		addr = (uint8_t *)mask;
164*64639aafSDarren Reed 		addr += offsetof(struct sockaddr_in6, sin6_addr);
1656e91bba0SGirish Moodalbail 	}
1666e91bba0SGirish Moodalbail 
1676e91bba0SGirish Moodalbail 	while (*addr == 0xff) {
1686e91bba0SGirish Moodalbail 		rc += 8;
1696e91bba0SGirish Moodalbail 		if (rc == limit)
1706e91bba0SGirish Moodalbail 			return (limit);
1716e91bba0SGirish Moodalbail 		addr++;
1726e91bba0SGirish Moodalbail 	}
1736e91bba0SGirish Moodalbail 
1746e91bba0SGirish Moodalbail 	last = *addr;
1756e91bba0SGirish Moodalbail 	while (last != 0) {
1766e91bba0SGirish Moodalbail 		rc++;
1776e91bba0SGirish Moodalbail 		last = (last << 1) & 0xff;
1786e91bba0SGirish Moodalbail 	}
1796e91bba0SGirish Moodalbail 
1806e91bba0SGirish Moodalbail 	return (rc);
1816e91bba0SGirish Moodalbail }
1826e91bba0SGirish Moodalbail 
1836e91bba0SGirish Moodalbail /*
1846e91bba0SGirish Moodalbail  * Returns B_TRUE if the address in `ss' is INADDR_ANY for IPv4 or
1856e91bba0SGirish Moodalbail  * :: for IPv6. Otherwise, returns B_FALSE.
1866e91bba0SGirish Moodalbail  */
1876e91bba0SGirish Moodalbail boolean_t
sockaddrunspec(const struct sockaddr * ss)188*64639aafSDarren Reed sockaddrunspec(const struct sockaddr *ss)
1896e91bba0SGirish Moodalbail {
190*64639aafSDarren Reed 	struct sockaddr_storage data;
1916e91bba0SGirish Moodalbail 
192*64639aafSDarren Reed 	switch (ss->sa_family) {
1936e91bba0SGirish Moodalbail 	case AF_INET:
194*64639aafSDarren Reed 		(void) memcpy(&data, ss, sizeof (struct sockaddr_in));
195*64639aafSDarren Reed 		return (((struct sockaddr_in *)&data)->sin_addr.s_addr ==
1966e91bba0SGirish Moodalbail 		    INADDR_ANY);
1976e91bba0SGirish Moodalbail 	case AF_INET6:
198*64639aafSDarren Reed 		(void) memcpy(&data, ss, sizeof (struct sockaddr_in6));
1996e91bba0SGirish Moodalbail 		return (IN6_IS_ADDR_UNSPECIFIED(
200*64639aafSDarren Reed 		    &((struct sockaddr_in6 *)&data)->sin6_addr));
2016e91bba0SGirish Moodalbail 	}
2026e91bba0SGirish Moodalbail 
203*64639aafSDarren Reed 	return (B_FALSE);
2046e91bba0SGirish Moodalbail }
205