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