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