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