1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <unistd.h> 28 #include <netinet/in.h> 29 #include <libinetutil.h> 30 #include <inet/ip.h> 31 #include <strings.h> 32 #include <errno.h> 33 #include <libsocket_priv.h> 34 35 /* 36 * Internet utility functions. 37 */ 38 39 /* 40 * Given a host-order address, calculate client's default net mask. 41 * Consult netmasks database to see if net is further subnetted. 42 * We'll only snag the first netmask that matches our criteria. 43 * We return the resultant netmask in host order. 44 */ 45 void 46 get_netmask4(const struct in_addr *n_addrp, struct in_addr *s_addrp) 47 { 48 struct in_addr hp, tp; 49 50 /* 51 * First check if VLSM is in use. 52 */ 53 hp.s_addr = htonl(n_addrp->s_addr); 54 if (getnetmaskbyaddr(hp, &tp) == 0) { 55 s_addrp->s_addr = ntohl(tp.s_addr); 56 return; 57 } 58 59 /* 60 * Fall back on standard classed networks. 61 */ 62 if (IN_CLASSA(n_addrp->s_addr)) 63 s_addrp->s_addr = IN_CLASSA_NET; 64 else if (IN_CLASSB(n_addrp->s_addr)) 65 s_addrp->s_addr = IN_CLASSB_NET; 66 else if (IN_CLASSC(n_addrp->s_addr)) 67 s_addrp->s_addr = IN_CLASSC_NET; 68 else 69 s_addrp->s_addr = IN_CLASSE_NET; 70 } 71 72 /* 73 * Checks if the IP addresses `ssp1' and `ssp2' are equal. 74 */ 75 boolean_t 76 sockaddrcmp(const struct sockaddr_storage *ssp1, 77 const struct sockaddr_storage *ssp2) 78 { 79 struct in_addr addr1, addr2; 80 const struct in6_addr *addr6p1, *addr6p2; 81 82 if (ssp1->ss_family != ssp2->ss_family) 83 return (B_FALSE); 84 85 if (ssp1 == ssp2) 86 return (B_TRUE); 87 88 switch (ssp1->ss_family) { 89 case AF_INET: 90 addr1 = ((const struct sockaddr_in *)ssp1)->sin_addr; 91 addr2 = ((const struct sockaddr_in *)ssp2)->sin_addr; 92 return (addr1.s_addr == addr2.s_addr); 93 case AF_INET6: 94 addr6p1 = &((const struct sockaddr_in6 *)ssp1)->sin6_addr; 95 addr6p2 = &((const struct sockaddr_in6 *)ssp2)->sin6_addr; 96 return (IN6_ARE_ADDR_EQUAL(addr6p1, addr6p2)); 97 } 98 return (B_FALSE); 99 } 100 101 /* 102 * Stores the netmask in `mask' for the given prefixlen `plen' and also sets 103 * `ss_family' in `mask'. 104 */ 105 int 106 plen2mask(uint_t prefixlen, sa_family_t af, struct sockaddr_storage *mask) 107 { 108 uint8_t *addr; 109 110 bzero(mask, sizeof (*mask)); 111 mask->ss_family = af; 112 if (af == AF_INET) { 113 if (prefixlen > IP_ABITS) 114 return (EINVAL); 115 addr = (uint8_t *)&((struct sockaddr_in *)mask)-> 116 sin_addr.s_addr; 117 } else { 118 if (prefixlen > IPV6_ABITS) 119 return (EINVAL); 120 addr = (uint8_t *)&((struct sockaddr_in6 *)mask)-> 121 sin6_addr.s6_addr; 122 } 123 124 while (prefixlen > 0) { 125 if (prefixlen >= 8) { 126 *addr++ = 0xFF; 127 prefixlen -= 8; 128 continue; 129 } 130 *addr |= 1 << (8 - prefixlen); 131 prefixlen--; 132 } 133 return (0); 134 } 135 136 /* 137 * Convert a mask to a prefix length. 138 * Returns prefix length on success, -1 otherwise. 139 */ 140 int 141 mask2plen(const struct sockaddr_storage *mask) 142 { 143 int rc = 0; 144 uint8_t last; 145 uint8_t *addr; 146 int limit; 147 148 if (mask->ss_family == AF_INET) { 149 limit = IP_ABITS; 150 addr = (uint8_t *)&((struct sockaddr_in *)mask)-> 151 sin_addr.s_addr; 152 } else { 153 limit = IPV6_ABITS; 154 addr = (uint8_t *)&((struct sockaddr_in6 *)mask)-> 155 sin6_addr.s6_addr; 156 } 157 158 while (*addr == 0xff) { 159 rc += 8; 160 if (rc == limit) 161 return (limit); 162 addr++; 163 } 164 165 last = *addr; 166 while (last != 0) { 167 rc++; 168 last = (last << 1) & 0xff; 169 } 170 171 return (rc); 172 } 173 174 /* 175 * Returns B_TRUE if the address in `ss' is INADDR_ANY for IPv4 or 176 * :: for IPv6. Otherwise, returns B_FALSE. 177 */ 178 boolean_t 179 sockaddrunspec(const struct sockaddr_storage *ss) 180 { 181 struct sockaddr_storage zeroaddr = {0}; 182 183 switch (ss->ss_family) { 184 case AF_INET: 185 return (((struct sockaddr_in *)ss)->sin_addr.s_addr == 186 INADDR_ANY); 187 case AF_INET6: 188 return (IN6_IS_ADDR_UNSPECIFIED( 189 &((struct sockaddr_in6 *)ss)->sin6_addr)); 190 } 191 192 return (bcmp(&zeroaddr, ss, sizeof (zeroaddr)) == 0); 193 } 194