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