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