1 /* 2 * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1998,1999 by Internet Software Consortium. 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 14 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 16 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 17 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 18 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 19 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20 * SOFTWARE. 21 */ 22 23 #pragma ident "%Z%%M% %I% %E% SMI" 24 25 #if defined(LIBC_SCCS) && !defined(lint) 26 static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 8.7 2001/09/28 05:19:36 marka Exp $"; 27 #endif 28 29 #include "port_before.h" 30 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <arpa/nameser.h> 35 #include <arpa/inet.h> 36 37 #include <errno.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <stdlib.h> 41 42 #include "port_after.h" 43 44 #ifdef SPRINTF_CHAR 45 # define SPRINTF(x) strlen(sprintf/**/x) 46 #else 47 # define SPRINTF(x) ((size_t)sprintf x) 48 #endif 49 50 static char * inet_cidr_ntop_ipv4 __P((const u_char *src, int bits, 51 char *dst, size_t size)); 52 static char * inet_cidr_ntop_ipv6 __P((const u_char *src, int bits, 53 char *dst, size_t size)); 54 55 /* 56 * char * 57 * inet_cidr_ntop(af, src, bits, dst, size) 58 * convert network address from network to presentation format. 59 * "src"'s size is determined from its "af". 60 * return: 61 * pointer to dst, or NULL if an error occurred (check errno). 62 * note: 63 * 192.5.5.1/28 has a nonzero host part, which means it isn't a network 64 * as called for by inet_net_ntop() but it can be a host address with 65 * an included netmask. 66 * author: 67 * Paul Vixie (ISC), October 1998 68 */ 69 char * 70 inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) { 71 switch (af) { 72 case AF_INET: 73 return (inet_cidr_ntop_ipv4(src, bits, dst, size)); 74 case AF_INET6: 75 return (inet_cidr_ntop_ipv6(src, bits, dst, size)); 76 default: 77 errno = EAFNOSUPPORT; 78 return (NULL); 79 } 80 } 81 82 static int 83 decoct(const u_char *src, int bytes, char *dst, size_t size) { 84 char *odst = dst; 85 char *t; 86 int b; 87 88 for (b = 1; b <= bytes; b++) { 89 if (size < sizeof "255.") 90 return (0); 91 t = dst; 92 dst += SPRINTF((dst, "%u", *src++)); 93 if (b != bytes) { 94 *dst++ = '.'; 95 *dst = '\0'; 96 } 97 size -= (size_t)(dst - t); 98 } 99 return (dst - odst); 100 } 101 102 /* 103 * static char * 104 * inet_cidr_ntop_ipv4(src, bits, dst, size) 105 * convert IPv4 network address from network to presentation format. 106 * "src"'s size is determined from its "af". 107 * return: 108 * pointer to dst, or NULL if an error occurred (check errno). 109 * note: 110 * network byte order assumed. this means 192.5.5.240/28 has 111 * 0b11110000 in its fourth octet. 112 * author: 113 * Paul Vixie (ISC), October 1998 114 */ 115 static char * 116 inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) { 117 char *odst = dst; 118 size_t len = 4; 119 size_t b; 120 size_t bytes; 121 122 if ((bits < -1) || (bits > 32)) { 123 errno = EINVAL; 124 return (NULL); 125 } 126 127 /* Find number of significant bytes in address. */ 128 if (bits == -1) 129 len = 4; 130 else 131 for (len = 1, b = 1 ; b < 4; b++) 132 if (*(src + b)) 133 len = b + 1; 134 135 /* Format whole octets plus nonzero trailing octets. */ 136 bytes = (((bits <= 0) ? 1 : bits) + 7) / 8; 137 if (len > bytes) 138 bytes = len; 139 b = decoct(src, bytes, dst, size); 140 if (b == 0) 141 goto emsgsize; 142 dst += b; 143 size -= b; 144 145 if (bits != -1) { 146 /* Format CIDR /width. */ 147 if (size < sizeof "/32") 148 goto emsgsize; 149 dst += SPRINTF((dst, "/%u", bits)); 150 } 151 152 return (odst); 153 154 emsgsize: 155 errno = EMSGSIZE; 156 return (NULL); 157 } 158 159 static char * 160 inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { 161 /* 162 * Note that int32_t and int16_t need only be "at least" large enough 163 * to contain a value of the specified size. On some systems, like 164 * Crays, there is no such thing as an integer variable with 16 bits. 165 * Keep this in mind if you think this function should have been coded 166 * to use pointer overlays. All the world's not a VAX. 167 */ 168 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"]; 169 char *tp; 170 struct { int base, len; } best, cur; 171 u_int words[NS_IN6ADDRSZ / NS_INT16SZ]; 172 int i; 173 174 if ((bits < -1) || (bits > 128)) { 175 errno = EINVAL; 176 return (NULL); 177 } 178 179 /* 180 * Preprocess: 181 * Copy the input (bytewise) array into a wordwise array. 182 * Find the longest run of 0x00's in src[] for :: shorthanding. 183 */ 184 memset(words, '\0', sizeof words); 185 for (i = 0; i < NS_IN6ADDRSZ; i++) 186 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 187 best.base = -1; 188 cur.base = -1; 189 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { 190 if (words[i] == 0) { 191 if (cur.base == -1) 192 cur.base = i, cur.len = 1; 193 else 194 cur.len++; 195 } else { 196 if (cur.base != -1) { 197 if (best.base == -1 || cur.len > best.len) 198 best = cur; 199 cur.base = -1; 200 } 201 } 202 } 203 if (cur.base != -1) { 204 if (best.base == -1 || cur.len > best.len) 205 best = cur; 206 } 207 if (best.base != -1 && best.len < 2) 208 best.base = -1; 209 210 /* 211 * Format the result. 212 */ 213 tp = tmp; 214 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { 215 /* Are we inside the best run of 0x00's? */ 216 if (best.base != -1 && i >= best.base && 217 i < (best.base + best.len)) { 218 if (i == best.base) 219 *tp++ = ':'; 220 continue; 221 } 222 /* Are we following an initial run of 0x00s or any real hex? */ 223 if (i != 0) 224 *tp++ = ':'; 225 /* Is this address an encapsulated IPv4? */ 226 if (i == 6 && best.base == 0 && (best.len == 6 || 227 (best.len == 7 && words[7] != 0x0001) || 228 (best.len == 5 && words[5] == 0xffff))) { 229 int n; 230 231 if (src[15] || bits == -1 || bits > 120) 232 n = 4; 233 else if (src[14] || bits > 112) 234 n = 3; 235 else 236 n = 2; 237 n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp)); 238 if (n == 0) { 239 errno = EMSGSIZE; 240 return (NULL); 241 } 242 tp += strlen(tp); 243 break; 244 } 245 tp += SPRINTF((tp, "%x", words[i])); 246 } 247 248 /* Was it a trailing run of 0x00's? */ 249 if (best.base != -1 && (best.base + best.len) == 250 (NS_IN6ADDRSZ / NS_INT16SZ)) 251 *tp++ = ':'; 252 *tp = '\0'; 253 254 if (bits != -1) 255 tp += SPRINTF((tp, "/%u", bits)); 256 257 /* 258 * Check for overflow, copy, and we're done. 259 */ 260 if ((size_t)(tp - tmp) > size) { 261 errno = EMSGSIZE; 262 return (NULL); 263 } 264 strcpy(dst, tmp); 265 return (dst); 266 } 267