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