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