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 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 } 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 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 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 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