2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996,1999 by Internet Software Consortium.
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.
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.
20 #if defined(LIBC_SCCS) && !defined(lint)
21 static const char rcsid
[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $";
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
31 #include "utils/builtins.h"
32 #include "utils/inet.h"
35 #define NS_IN6ADDRSZ 16
39 #define SPRINTF(x) strlen(sprintf/**/x)
41 #define SPRINTF(x) ((size_t)sprintf x)
44 static char *inet_net_ntop_ipv4(const u_char
*src
, int bits
,
45 char *dst
, size_t size
);
46 static char *inet_cidr_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 static char *inet_cidr_ntop_ipv6(const u_char
*src
, int bits
,
51 char *dst
, size_t size
);
55 * inet_cidr_ntop(af, src, bits, dst, size)
56 * convert network number from network to presentation format.
57 * generates CIDR style result always.
59 * pointer to dst, or NULL if an error occurred (check errno).
61 * Paul Vixie (ISC), July 1996
64 inet_cidr_ntop(int af
, const void *src
, int bits
, char *dst
, size_t size
)
69 return (inet_cidr_ntop_ipv4(src
, bits
, dst
, size
));
71 return (inet_cidr_ntop_ipv6(src
, bits
, dst
, size
));
81 * inet_cidr_ntop_ipv4(src, bits, dst, size)
82 * convert IPv4 network number from network to presentation format.
83 * generates CIDR style result always.
85 * pointer to dst, or NULL if an error occurred (check errno).
87 * network byte order assumed. this means 192.5.5.240/28 has
88 * 0b11110000 in its fourth octet.
90 * Paul Vixie (ISC), July 1996
93 inet_cidr_ntop_ipv4(const u_char
*src
, int bits
, char *dst
, size_t size
)
100 if (bits
< 0 || bits
> 32)
108 if (size
< sizeof "0")
115 /* Format whole octets. */
116 for (b
= bits
/ 8; b
> 0; b
--)
118 if (size
<= sizeof "255.")
121 dst
+= SPRINTF((dst
, "%u", *src
++));
127 size
-= (size_t) (dst
- t
);
130 /* Format partial octet. */
134 if (size
<= sizeof ".255")
139 m
= ((1 << b
) - 1) << (8 - b
);
140 dst
+= SPRINTF((dst
, "%u", *src
& m
));
141 size
-= (size_t) (dst
- t
);
144 /* Format CIDR /width. */
145 if (size
<= sizeof "/32")
147 dst
+= SPRINTF((dst
, "/%u", bits
));
157 * inet_cidr_ntop_ipv6(src, bits, fakebits, dst, size)
158 * convert IPv6 network number from network to presentation format.
159 * generates CIDR style result always. Picks the shortest representation
160 * unless the IP is really IPv4.
161 * always prints specified number of bits (bits).
163 * pointer to dst, or NULL if an error occurred (check errno).
165 * network byte order assumed. this means 192.5.5.240/28 has
166 * 0x11110000 in its fourth octet.
168 * Vadim Kogan (UCB), June 2001
169 * Original version (IPv4) by Paul Vixie (ISC), July 1996
173 inet_cidr_ntop_ipv6(const u_char
*src
, int bits
, char *dst
, size_t size
)
184 unsigned char inbuf
[16];
185 char outbuf
[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
190 if (bits
< 0 || bits
> 128)
206 /* Copy src to private buffer. Zero host part. */
208 memcpy(inbuf
, src
, p
);
209 memset(inbuf
+ p
, 0, 16 - p
);
219 /* how many words need to be displayed in output */
220 words
= (bits
+ 15) / 16;
224 /* Find the longest substring of zero's */
225 zero_s
= zero_l
= tmp_zero_s
= tmp_zero_l
= 0;
226 for (i
= 0; i
< (words
* 2); i
+= 2)
228 if ((s
[i
] | s
[i
+ 1]) == 0)
236 if (tmp_zero_l
&& zero_l
< tmp_zero_l
)
245 if (tmp_zero_l
&& zero_l
< tmp_zero_l
)
251 if (zero_l
!= words
&& zero_s
== 0 && ((zero_l
== 6) ||
252 ((zero_l
== 5 && s
[10] == 0xff && s
[11] == 0xff) ||
253 ((zero_l
== 7 && s
[14] != 0 && s
[15] != 1)))))
256 /* Format whole words. */
257 for (p
= 0; p
< words
; p
++)
259 if (zero_l
!= 0 && p
>= zero_s
&& p
< zero_s
+ zero_l
)
261 /* Time to skip some zeros */
271 if (is_ipv4
&& p
> 5)
273 *cp
++ = (p
== 6) ? ':' : '.';
274 cp
+= SPRINTF((cp
, "%u", *s
++));
275 /* we can potentially drop the last octet */
276 if (p
!= 7 || bits
> 120)
279 cp
+= SPRINTF((cp
, "%u", *s
++));
286 cp
+= SPRINTF((cp
, "%x", *s
* 256 + s
[1]));
291 /* Format CIDR /width. */
292 (void) SPRINTF((cp
, "/%u", bits
));
293 if (strlen(outbuf
) + 1 > size
)
307 * inet_net_ntop(af, src, bits, dst, size)
308 * convert host/network address from network to presentation format.
309 * "src"'s size is determined from its "af".
311 * pointer to dst, or NULL if an error occurred (check errno).
313 * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
314 * as called for by inet_net_pton() but it can be a host address with
315 * an included netmask.
317 * Paul Vixie (ISC), October 1998
320 inet_net_ntop(int af
, const void *src
, int bits
, char *dst
, size_t size
)
325 return (inet_net_ntop_ipv4(src
, bits
, dst
, size
));
327 return (inet_net_ntop_ipv6(src
, bits
, dst
, size
));
329 errno
= EAFNOSUPPORT
;
336 * inet_net_ntop_ipv4(src, bits, dst, size)
337 * convert IPv4 network address from network to presentation format.
338 * "src"'s size is determined from its "af".
340 * pointer to dst, or NULL if an error occurred (check errno).
342 * network byte order assumed. this means 192.5.5.240/28 has
343 * 0b11110000 in its fourth octet.
345 * Paul Vixie (ISC), October 1998
348 inet_net_ntop_ipv4(const u_char
*src
, int bits
, char *dst
, size_t size
)
355 if (bits
< 0 || bits
> 32)
361 /* Always format all four octets, regardless of mask length. */
362 for (b
= len
; b
> 0; b
--)
364 if (size
<= sizeof ".255")
369 dst
+= SPRINTF((dst
, "%u", *src
++));
370 size
-= (size_t) (dst
- t
);
373 /* don't print masklen if 32 bits */
376 if (size
<= sizeof "/32")
378 dst
+= SPRINTF((dst
, "/%u", bits
));
389 decoct(const u_char
*src
, int bytes
, char *dst
, size_t size
)
395 for (b
= 1; b
<= bytes
; b
++)
397 if (size
<= sizeof "255.")
400 dst
+= SPRINTF((dst
, "%u", *src
++));
406 size
-= (size_t) (dst
- t
);
412 inet_net_ntop_ipv6(const u_char
*src
, int bits
, char *dst
, size_t size
)
415 * Note that int32_t and int16_t need only be "at least" large enough to
416 * contain a value of the specified size. On some systems, like Crays,
417 * there is no such thing as an integer variable with 16 bits. Keep this
418 * in mind if you think this function should have been coded to use
419 * pointer overlays. All the world's not a VAX.
421 char tmp
[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
428 u_int words
[NS_IN6ADDRSZ
/ NS_INT16SZ
];
431 if ((bits
< -1) || (bits
> 128))
438 * Preprocess: Copy the input (bytewise) array into a wordwise array. Find
439 * the longest run of 0x00's in src[] for :: shorthanding.
441 memset(words
, '\0', sizeof words
);
442 for (i
= 0; i
< NS_IN6ADDRSZ
; i
++)
443 words
[i
/ 2] |= (src
[i
] << ((1 - (i
% 2)) << 3));
448 for (i
= 0; i
< (NS_IN6ADDRSZ
/ NS_INT16SZ
); i
++)
453 cur
.base
= i
, cur
.len
= 1;
461 if (best
.base
== -1 || cur
.len
> best
.len
)
469 if (best
.base
== -1 || cur
.len
> best
.len
)
472 if (best
.base
!= -1 && best
.len
< 2)
479 for (i
= 0; i
< (NS_IN6ADDRSZ
/ NS_INT16SZ
); i
++)
481 /* Are we inside the best run of 0x00's? */
482 if (best
.base
!= -1 && i
>= best
.base
&&
483 i
< (best
.base
+ best
.len
))
489 /* Are we following an initial run of 0x00s or any real hex? */
492 /* Is this address an encapsulated IPv4? */
493 if (i
== 6 && best
.base
== 0 && (best
.len
== 6 ||
494 (best
.len
== 7 && words
[7] != 0x0001) ||
495 (best
.len
== 5 && words
[5] == 0xffff)))
499 n
= decoct(src
+ 12, 4, tp
, sizeof tmp
- (tp
- tmp
));
508 tp
+= SPRINTF((tp
, "%x", words
[i
]));
511 /* Was it a trailing run of 0x00's? */
512 if (best
.base
!= -1 && (best
.base
+ best
.len
) ==
513 (NS_IN6ADDRSZ
/ NS_INT16SZ
))
517 if (bits
!= -1 && bits
!= 128)
518 tp
+= SPRINTF((tp
, "/%u", bits
));
521 * Check for overflow, copy, and we're done.
523 if ((size_t) (tp
- tmp
) > size
)