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