1 /* 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (c) 1996,1999 by Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #if defined(LIBC_SCCS) && !defined(lint) 19 static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.3.18.2 2006/06/20 02:51:32 marka Exp $"; 20 #endif 21 #include <sys/cdefs.h> 22 __FBSDID("$FreeBSD$"); 23 24 #include "port_before.h" 25 26 #include <sys/types.h> 27 #include <sys/socket.h> 28 #include <netinet/in.h> 29 #include <arpa/inet.h> 30 31 #include <errno.h> 32 #include <stdio.h> 33 #include <string.h> 34 #include <stdlib.h> 35 36 #include "port_after.h" 37 38 #ifdef SPRINTF_CHAR 39 # define SPRINTF(x) strlen(sprintf/**/x) 40 #else 41 # define SPRINTF(x) ((size_t)sprintf x) 42 #endif 43 44 static char * inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, 45 size_t size); 46 static char * inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, 47 size_t size); 48 49 /*% 50 * char * 51 * inet_net_ntop(af, src, bits, dst, size) 52 * convert network number from network to presentation format. 53 * generates CIDR style result always. 54 * return: 55 * pointer to dst, or NULL if an error occurred (check errno). 56 * author: 57 * Paul Vixie (ISC), July 1996 58 */ 59 char * 60 inet_net_ntop(af, src, bits, dst, size) 61 int af; 62 const void *src; 63 int bits; 64 char *dst; 65 size_t size; 66 { 67 switch (af) { 68 case AF_INET: 69 return (inet_net_ntop_ipv4(src, bits, dst, size)); 70 case AF_INET6: 71 return (inet_net_ntop_ipv6(src, bits, dst, size)); 72 default: 73 errno = EAFNOSUPPORT; 74 return (NULL); 75 } 76 } 77 78 /*% 79 * static char * 80 * inet_net_ntop_ipv4(src, bits, dst, size) 81 * convert IPv4 network number from network to presentation format. 82 * generates CIDR style result always. 83 * return: 84 * pointer to dst, or NULL if an error occurred (check errno). 85 * note: 86 * network byte order assumed. this means 192.5.5.240/28 has 87 * 0b11110000 in its fourth octet. 88 * author: 89 * Paul Vixie (ISC), July 1996 90 */ 91 static char * 92 inet_net_ntop_ipv4(src, bits, dst, size) 93 const u_char *src; 94 int bits; 95 char *dst; 96 size_t size; 97 { 98 char *odst = dst; 99 char *t; 100 u_int m; 101 int b; 102 103 if (bits < 0 || bits > 32) { 104 errno = EINVAL; 105 return (NULL); 106 } 107 108 if (bits == 0) { 109 if (size < sizeof "0") 110 goto emsgsize; 111 *dst++ = '0'; 112 size--; 113 *dst = '\0'; 114 } 115 116 /* Format whole octets. */ 117 for (b = bits / 8; b > 0; b--) { 118 if (size <= sizeof "255.") 119 goto emsgsize; 120 t = dst; 121 dst += SPRINTF((dst, "%u", *src++)); 122 if (b > 1) { 123 *dst++ = '.'; 124 *dst = '\0'; 125 } 126 size -= (size_t)(dst - t); 127 } 128 129 /* Format partial octet. */ 130 b = bits % 8; 131 if (b > 0) { 132 if (size <= sizeof ".255") 133 goto emsgsize; 134 t = dst; 135 if (dst != odst) 136 *dst++ = '.'; 137 m = ((1 << b) - 1) << (8 - b); 138 dst += SPRINTF((dst, "%u", *src & m)); 139 size -= (size_t)(dst - t); 140 } 141 142 /* Format CIDR /width. */ 143 if (size <= sizeof "/32") 144 goto emsgsize; 145 dst += SPRINTF((dst, "/%u", bits)); 146 return (odst); 147 148 emsgsize: 149 errno = EMSGSIZE; 150 return (NULL); 151 } 152 153 /*% 154 * static char * 155 * inet_net_ntop_ipv6(src, bits, fakebits, dst, size) 156 * convert IPv6 network number from network to presentation format. 157 * generates CIDR style result always. Picks the shortest representation 158 * unless the IP is really IPv4. 159 * always prints specified number of bits (bits). 160 * return: 161 * pointer to dst, or NULL if an error occurred (check errno). 162 * note: 163 * network byte order assumed. this means 192.5.5.240/28 has 164 * 0b11110000 in its fourth octet. 165 * author: 166 * Vadim Kogan (UCB), June 2001 167 * Original version (IPv4) by Paul Vixie (ISC), July 1996 168 */ 169 170 static char * 171 inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { 172 u_int m; 173 int b; 174 int p; 175 int zero_s, zero_l, tmp_zero_s, tmp_zero_l; 176 int i; 177 int is_ipv4 = 0; 178 unsigned char inbuf[16]; 179 char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; 180 char *cp; 181 int words; 182 u_char *s; 183 184 if (bits < 0 || bits > 128) { 185 errno = EINVAL; 186 return (NULL); 187 } 188 189 cp = outbuf; 190 191 if (bits == 0) { 192 *cp++ = ':'; 193 *cp++ = ':'; 194 *cp = '\0'; 195 } else { 196 /* Copy src to private buffer. Zero host part. */ 197 p = (bits + 7) / 8; 198 memcpy(inbuf, src, p); 199 memset(inbuf + p, 0, 16 - p); 200 b = bits % 8; 201 if (b != 0) { 202 m = ~0 << (8 - b); 203 inbuf[p-1] &= m; 204 } 205 206 s = inbuf; 207 208 /* how many words need to be displayed in output */ 209 words = (bits + 15) / 16; 210 if (words == 1) 211 words = 2; 212 213 /* Find the longest substring of zero's */ 214 zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0; 215 for (i = 0; i < (words * 2); i += 2) { 216 if ((s[i] | s[i+1]) == 0) { 217 if (tmp_zero_l == 0) 218 tmp_zero_s = i / 2; 219 tmp_zero_l++; 220 } else { 221 if (tmp_zero_l && zero_l < tmp_zero_l) { 222 zero_s = tmp_zero_s; 223 zero_l = tmp_zero_l; 224 tmp_zero_l = 0; 225 } 226 } 227 } 228 229 if (tmp_zero_l && zero_l < tmp_zero_l) { 230 zero_s = tmp_zero_s; 231 zero_l = tmp_zero_l; 232 } 233 234 if (zero_l != words && zero_s == 0 && ((zero_l == 6) || 235 ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) || 236 ((zero_l == 7 && s[14] != 0 && s[15] != 1))))) 237 is_ipv4 = 1; 238 239 /* Format whole words. */ 240 for (p = 0; p < words; p++) { 241 if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) { 242 /* Time to skip some zeros */ 243 if (p == zero_s) 244 *cp++ = ':'; 245 if (p == words - 1) 246 *cp++ = ':'; 247 s++; 248 s++; 249 continue; 250 } 251 252 if (is_ipv4 && p > 5 ) { 253 *cp++ = (p == 6) ? ':' : '.'; 254 cp += SPRINTF((cp, "%u", *s++)); 255 /* we can potentially drop the last octet */ 256 if (p != 7 || bits > 120) { 257 *cp++ = '.'; 258 cp += SPRINTF((cp, "%u", *s++)); 259 } 260 } else { 261 if (cp != outbuf) 262 *cp++ = ':'; 263 cp += SPRINTF((cp, "%x", *s * 256 + s[1])); 264 s += 2; 265 } 266 } 267 } 268 /* Format CIDR /width. */ 269 sprintf(cp, "/%u", bits); 270 if (strlen(outbuf) + 1 > size) 271 goto emsgsize; 272 strcpy(dst, outbuf); 273 274 return (dst); 275 276 emsgsize: 277 errno = EMSGSIZE; 278 return (NULL); 279 } 280 281 /* 282 * Weak aliases for applications that use certain private entry points, 283 * and fail to include <arpa/inet.h>. 284 */ 285 #undef inet_net_ntop 286 __weak_reference(__inet_net_ntop, inet_net_ntop); 287 288 /*! \file */ 289