18485SPeter.Memishian@Sun.COM /* 28485SPeter.Memishian@Sun.COM * CDDL HEADER START 38485SPeter.Memishian@Sun.COM * 48485SPeter.Memishian@Sun.COM * The contents of this file are subject to the terms of the 58485SPeter.Memishian@Sun.COM * Common Development and Distribution License (the "License"). 68485SPeter.Memishian@Sun.COM * You may not use this file except in compliance with the License. 78485SPeter.Memishian@Sun.COM * 88485SPeter.Memishian@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98485SPeter.Memishian@Sun.COM * or http://www.opensolaris.org/os/licensing. 108485SPeter.Memishian@Sun.COM * See the License for the specific language governing permissions 118485SPeter.Memishian@Sun.COM * and limitations under the License. 128485SPeter.Memishian@Sun.COM * 138485SPeter.Memishian@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148485SPeter.Memishian@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158485SPeter.Memishian@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168485SPeter.Memishian@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178485SPeter.Memishian@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188485SPeter.Memishian@Sun.COM * 198485SPeter.Memishian@Sun.COM * CDDL HEADER END 208485SPeter.Memishian@Sun.COM */ 218485SPeter.Memishian@Sun.COM 228485SPeter.Memishian@Sun.COM /* 23*12016SGirish.Moodalbail@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 248485SPeter.Memishian@Sun.COM * Use is subject to license terms. 258485SPeter.Memishian@Sun.COM */ 268485SPeter.Memishian@Sun.COM 278485SPeter.Memishian@Sun.COM #include <unistd.h> 288485SPeter.Memishian@Sun.COM #include <netinet/in.h> 298485SPeter.Memishian@Sun.COM #include <libinetutil.h> 30*12016SGirish.Moodalbail@Sun.COM #include <inet/ip.h> 31*12016SGirish.Moodalbail@Sun.COM #include <strings.h> 32*12016SGirish.Moodalbail@Sun.COM #include <errno.h> 33*12016SGirish.Moodalbail@Sun.COM #include <libsocket_priv.h> 348485SPeter.Memishian@Sun.COM 358485SPeter.Memishian@Sun.COM /* 368485SPeter.Memishian@Sun.COM * Internet utility functions. 378485SPeter.Memishian@Sun.COM */ 388485SPeter.Memishian@Sun.COM 398485SPeter.Memishian@Sun.COM /* 408485SPeter.Memishian@Sun.COM * Given a host-order address, calculate client's default net mask. 418485SPeter.Memishian@Sun.COM * Consult netmasks database to see if net is further subnetted. 428485SPeter.Memishian@Sun.COM * We'll only snag the first netmask that matches our criteria. 438485SPeter.Memishian@Sun.COM * We return the resultant netmask in host order. 448485SPeter.Memishian@Sun.COM */ 458485SPeter.Memishian@Sun.COM void 468485SPeter.Memishian@Sun.COM get_netmask4(const struct in_addr *n_addrp, struct in_addr *s_addrp) 478485SPeter.Memishian@Sun.COM { 488485SPeter.Memishian@Sun.COM struct in_addr hp, tp; 498485SPeter.Memishian@Sun.COM 508485SPeter.Memishian@Sun.COM /* 518485SPeter.Memishian@Sun.COM * First check if VLSM is in use. 528485SPeter.Memishian@Sun.COM */ 538485SPeter.Memishian@Sun.COM hp.s_addr = htonl(n_addrp->s_addr); 548485SPeter.Memishian@Sun.COM if (getnetmaskbyaddr(hp, &tp) == 0) { 558485SPeter.Memishian@Sun.COM s_addrp->s_addr = ntohl(tp.s_addr); 568485SPeter.Memishian@Sun.COM return; 578485SPeter.Memishian@Sun.COM } 588485SPeter.Memishian@Sun.COM 598485SPeter.Memishian@Sun.COM /* 608485SPeter.Memishian@Sun.COM * Fall back on standard classed networks. 618485SPeter.Memishian@Sun.COM */ 628485SPeter.Memishian@Sun.COM if (IN_CLASSA(n_addrp->s_addr)) 638485SPeter.Memishian@Sun.COM s_addrp->s_addr = IN_CLASSA_NET; 648485SPeter.Memishian@Sun.COM else if (IN_CLASSB(n_addrp->s_addr)) 658485SPeter.Memishian@Sun.COM s_addrp->s_addr = IN_CLASSB_NET; 668485SPeter.Memishian@Sun.COM else if (IN_CLASSC(n_addrp->s_addr)) 678485SPeter.Memishian@Sun.COM s_addrp->s_addr = IN_CLASSC_NET; 688485SPeter.Memishian@Sun.COM else 698485SPeter.Memishian@Sun.COM s_addrp->s_addr = IN_CLASSE_NET; 708485SPeter.Memishian@Sun.COM } 718485SPeter.Memishian@Sun.COM 728485SPeter.Memishian@Sun.COM /* 738485SPeter.Memishian@Sun.COM * Checks if the IP addresses `ssp1' and `ssp2' are equal. 748485SPeter.Memishian@Sun.COM */ 758485SPeter.Memishian@Sun.COM boolean_t 768485SPeter.Memishian@Sun.COM sockaddrcmp(const struct sockaddr_storage *ssp1, 778485SPeter.Memishian@Sun.COM const struct sockaddr_storage *ssp2) 788485SPeter.Memishian@Sun.COM { 798485SPeter.Memishian@Sun.COM struct in_addr addr1, addr2; 808485SPeter.Memishian@Sun.COM const struct in6_addr *addr6p1, *addr6p2; 818485SPeter.Memishian@Sun.COM 828485SPeter.Memishian@Sun.COM if (ssp1->ss_family != ssp2->ss_family) 838485SPeter.Memishian@Sun.COM return (B_FALSE); 848485SPeter.Memishian@Sun.COM 858485SPeter.Memishian@Sun.COM if (ssp1 == ssp2) 868485SPeter.Memishian@Sun.COM return (B_TRUE); 878485SPeter.Memishian@Sun.COM 888485SPeter.Memishian@Sun.COM switch (ssp1->ss_family) { 898485SPeter.Memishian@Sun.COM case AF_INET: 908485SPeter.Memishian@Sun.COM addr1 = ((const struct sockaddr_in *)ssp1)->sin_addr; 918485SPeter.Memishian@Sun.COM addr2 = ((const struct sockaddr_in *)ssp2)->sin_addr; 928485SPeter.Memishian@Sun.COM return (addr1.s_addr == addr2.s_addr); 938485SPeter.Memishian@Sun.COM case AF_INET6: 948485SPeter.Memishian@Sun.COM addr6p1 = &((const struct sockaddr_in6 *)ssp1)->sin6_addr; 958485SPeter.Memishian@Sun.COM addr6p2 = &((const struct sockaddr_in6 *)ssp2)->sin6_addr; 968485SPeter.Memishian@Sun.COM return (IN6_ARE_ADDR_EQUAL(addr6p1, addr6p2)); 978485SPeter.Memishian@Sun.COM } 988485SPeter.Memishian@Sun.COM return (B_FALSE); 998485SPeter.Memishian@Sun.COM } 100*12016SGirish.Moodalbail@Sun.COM 101*12016SGirish.Moodalbail@Sun.COM /* 102*12016SGirish.Moodalbail@Sun.COM * Stores the netmask in `mask' for the given prefixlen `plen' and also sets 103*12016SGirish.Moodalbail@Sun.COM * `ss_family' in `mask'. 104*12016SGirish.Moodalbail@Sun.COM */ 105*12016SGirish.Moodalbail@Sun.COM int 106*12016SGirish.Moodalbail@Sun.COM plen2mask(uint_t prefixlen, sa_family_t af, struct sockaddr_storage *mask) 107*12016SGirish.Moodalbail@Sun.COM { 108*12016SGirish.Moodalbail@Sun.COM uint8_t *addr; 109*12016SGirish.Moodalbail@Sun.COM 110*12016SGirish.Moodalbail@Sun.COM bzero(mask, sizeof (*mask)); 111*12016SGirish.Moodalbail@Sun.COM mask->ss_family = af; 112*12016SGirish.Moodalbail@Sun.COM if (af == AF_INET) { 113*12016SGirish.Moodalbail@Sun.COM if (prefixlen > IP_ABITS) 114*12016SGirish.Moodalbail@Sun.COM return (EINVAL); 115*12016SGirish.Moodalbail@Sun.COM addr = (uint8_t *)&((struct sockaddr_in *)mask)-> 116*12016SGirish.Moodalbail@Sun.COM sin_addr.s_addr; 117*12016SGirish.Moodalbail@Sun.COM } else { 118*12016SGirish.Moodalbail@Sun.COM if (prefixlen > IPV6_ABITS) 119*12016SGirish.Moodalbail@Sun.COM return (EINVAL); 120*12016SGirish.Moodalbail@Sun.COM addr = (uint8_t *)&((struct sockaddr_in6 *)mask)-> 121*12016SGirish.Moodalbail@Sun.COM sin6_addr.s6_addr; 122*12016SGirish.Moodalbail@Sun.COM } 123*12016SGirish.Moodalbail@Sun.COM 124*12016SGirish.Moodalbail@Sun.COM while (prefixlen > 0) { 125*12016SGirish.Moodalbail@Sun.COM if (prefixlen >= 8) { 126*12016SGirish.Moodalbail@Sun.COM *addr++ = 0xFF; 127*12016SGirish.Moodalbail@Sun.COM prefixlen -= 8; 128*12016SGirish.Moodalbail@Sun.COM continue; 129*12016SGirish.Moodalbail@Sun.COM } 130*12016SGirish.Moodalbail@Sun.COM *addr |= 1 << (8 - prefixlen); 131*12016SGirish.Moodalbail@Sun.COM prefixlen--; 132*12016SGirish.Moodalbail@Sun.COM } 133*12016SGirish.Moodalbail@Sun.COM return (0); 134*12016SGirish.Moodalbail@Sun.COM } 135*12016SGirish.Moodalbail@Sun.COM 136*12016SGirish.Moodalbail@Sun.COM /* 137*12016SGirish.Moodalbail@Sun.COM * Convert a mask to a prefix length. 138*12016SGirish.Moodalbail@Sun.COM * Returns prefix length on success, -1 otherwise. 139*12016SGirish.Moodalbail@Sun.COM */ 140*12016SGirish.Moodalbail@Sun.COM int 141*12016SGirish.Moodalbail@Sun.COM mask2plen(const struct sockaddr_storage *mask) 142*12016SGirish.Moodalbail@Sun.COM { 143*12016SGirish.Moodalbail@Sun.COM int rc = 0; 144*12016SGirish.Moodalbail@Sun.COM uint8_t last; 145*12016SGirish.Moodalbail@Sun.COM uint8_t *addr; 146*12016SGirish.Moodalbail@Sun.COM int limit; 147*12016SGirish.Moodalbail@Sun.COM 148*12016SGirish.Moodalbail@Sun.COM if (mask->ss_family == AF_INET) { 149*12016SGirish.Moodalbail@Sun.COM limit = IP_ABITS; 150*12016SGirish.Moodalbail@Sun.COM addr = (uint8_t *)&((struct sockaddr_in *)mask)-> 151*12016SGirish.Moodalbail@Sun.COM sin_addr.s_addr; 152*12016SGirish.Moodalbail@Sun.COM } else { 153*12016SGirish.Moodalbail@Sun.COM limit = IPV6_ABITS; 154*12016SGirish.Moodalbail@Sun.COM addr = (uint8_t *)&((struct sockaddr_in6 *)mask)-> 155*12016SGirish.Moodalbail@Sun.COM sin6_addr.s6_addr; 156*12016SGirish.Moodalbail@Sun.COM } 157*12016SGirish.Moodalbail@Sun.COM 158*12016SGirish.Moodalbail@Sun.COM while (*addr == 0xff) { 159*12016SGirish.Moodalbail@Sun.COM rc += 8; 160*12016SGirish.Moodalbail@Sun.COM if (rc == limit) 161*12016SGirish.Moodalbail@Sun.COM return (limit); 162*12016SGirish.Moodalbail@Sun.COM addr++; 163*12016SGirish.Moodalbail@Sun.COM } 164*12016SGirish.Moodalbail@Sun.COM 165*12016SGirish.Moodalbail@Sun.COM last = *addr; 166*12016SGirish.Moodalbail@Sun.COM while (last != 0) { 167*12016SGirish.Moodalbail@Sun.COM rc++; 168*12016SGirish.Moodalbail@Sun.COM last = (last << 1) & 0xff; 169*12016SGirish.Moodalbail@Sun.COM } 170*12016SGirish.Moodalbail@Sun.COM 171*12016SGirish.Moodalbail@Sun.COM return (rc); 172*12016SGirish.Moodalbail@Sun.COM } 173*12016SGirish.Moodalbail@Sun.COM 174*12016SGirish.Moodalbail@Sun.COM /* 175*12016SGirish.Moodalbail@Sun.COM * Returns B_TRUE if the address in `ss' is INADDR_ANY for IPv4 or 176*12016SGirish.Moodalbail@Sun.COM * :: for IPv6. Otherwise, returns B_FALSE. 177*12016SGirish.Moodalbail@Sun.COM */ 178*12016SGirish.Moodalbail@Sun.COM boolean_t 179*12016SGirish.Moodalbail@Sun.COM sockaddrunspec(const struct sockaddr_storage *ss) 180*12016SGirish.Moodalbail@Sun.COM { 181*12016SGirish.Moodalbail@Sun.COM struct sockaddr_storage zeroaddr = {0}; 182*12016SGirish.Moodalbail@Sun.COM 183*12016SGirish.Moodalbail@Sun.COM switch (ss->ss_family) { 184*12016SGirish.Moodalbail@Sun.COM case AF_INET: 185*12016SGirish.Moodalbail@Sun.COM return (((struct sockaddr_in *)ss)->sin_addr.s_addr == 186*12016SGirish.Moodalbail@Sun.COM INADDR_ANY); 187*12016SGirish.Moodalbail@Sun.COM case AF_INET6: 188*12016SGirish.Moodalbail@Sun.COM return (IN6_IS_ADDR_UNSPECIFIED( 189*12016SGirish.Moodalbail@Sun.COM &((struct sockaddr_in6 *)ss)->sin6_addr)); 190*12016SGirish.Moodalbail@Sun.COM } 191*12016SGirish.Moodalbail@Sun.COM 192*12016SGirish.Moodalbail@Sun.COM return (bcmp(&zeroaddr, ss, sizeof (zeroaddr)) == 0); 193*12016SGirish.Moodalbail@Sun.COM } 194