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