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*64639aafSDarren Reed * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24e11c3f44Smeem */
25e11c3f44Smeem
26e11c3f44Smeem #include <unistd.h>
27e11c3f44Smeem #include <netinet/in.h>
28e11c3f44Smeem #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>
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
get_netmask4(const struct in_addr * n_addrp,struct in_addr * s_addrp)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
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