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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <unistd.h> 27 #include <netinet/in.h> 28 #include <libinetutil.h> 29 #include <inet/ip.h> 30 #include <strings.h> 31 #include <stddef.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 * `sa_family' in `mask'. Because this function does not require aligned 104 * access to the data inside of the sockaddr_in/6 structures, the code can 105 * use offsetof() to find the right place in the incoming structure. Why is 106 * using that beneficial? Less issues with lint. When using a direct cast 107 * of the struct sockaddr_storage structure to sockaddr_in6, a lint warning 108 * is generated because the former is composed of 16bit & 8bit elements whilst 109 * sockaddr_in6 has a 32bit alignment requirement. 110 */ 111 int 112 plen2mask(uint_t prefixlen, sa_family_t af, struct sockaddr *mask) 113 { 114 uint8_t *addr; 115 116 if (af == AF_INET) { 117 if (prefixlen > IP_ABITS) 118 return (EINVAL); 119 bzero(mask, sizeof (struct sockaddr_in)); 120 addr = (uint8_t *)mask; 121 addr += offsetof(struct sockaddr_in, sin_addr); 122 } else { 123 if (prefixlen > IPV6_ABITS) 124 return (EINVAL); 125 bzero(mask, sizeof (struct sockaddr_in6)); 126 addr = (uint8_t *)mask; 127 addr += offsetof(struct sockaddr_in6, sin6_addr); 128 } 129 mask->sa_family = af; 130 131 while (prefixlen > 0) { 132 if (prefixlen >= 8) { 133 *addr++ = 0xFF; 134 prefixlen -= 8; 135 continue; 136 } 137 *addr |= 1 << (8 - prefixlen); 138 prefixlen--; 139 } 140 return (0); 141 } 142 143 /* 144 * Convert a mask to a prefix length. 145 * Returns prefix length on success, -1 otherwise. 146 * The comments (above) for plen2mask about the use of `mask' also apply 147 * to this function and the choice to use offsetof here too. 148 */ 149 int 150 mask2plen(const struct sockaddr *mask) 151 { 152 int rc = 0; 153 uint8_t last; 154 uint8_t *addr; 155 int limit; 156 157 if (mask->sa_family == AF_INET) { 158 limit = IP_ABITS; 159 addr = (uint8_t *)mask; 160 addr += offsetof(struct sockaddr_in, sin_addr); 161 } else { 162 limit = IPV6_ABITS; 163 addr = (uint8_t *)mask; 164 addr += offsetof(struct sockaddr_in6, sin6_addr); 165 } 166 167 while (*addr == 0xff) { 168 rc += 8; 169 if (rc == limit) 170 return (limit); 171 addr++; 172 } 173 174 last = *addr; 175 while (last != 0) { 176 rc++; 177 last = (last << 1) & 0xff; 178 } 179 180 return (rc); 181 } 182 183 /* 184 * Returns B_TRUE if the address in `ss' is INADDR_ANY for IPv4 or 185 * :: for IPv6. Otherwise, returns B_FALSE. 186 */ 187 boolean_t 188 sockaddrunspec(const struct sockaddr *ss) 189 { 190 struct sockaddr_storage data; 191 192 switch (ss->sa_family) { 193 case AF_INET: 194 (void) memcpy(&data, ss, sizeof (struct sockaddr_in)); 195 return (((struct sockaddr_in *)&data)->sin_addr.s_addr == 196 INADDR_ANY); 197 case AF_INET6: 198 (void) memcpy(&data, ss, sizeof (struct sockaddr_in6)); 199 return (IN6_IS_ADDR_UNSPECIFIED( 200 &((struct sockaddr_in6 *)&data)->sin6_addr)); 201 } 202 203 return (B_FALSE); 204 } 205