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