12fe8fb19SBen Gras /*
22fe8fb19SBen Gras * Copyright (c) 1996,1999 by Internet Software Consortium.
32fe8fb19SBen Gras *
42fe8fb19SBen Gras * Permission to use, copy, modify, and distribute this software for any
52fe8fb19SBen Gras * purpose with or without fee is hereby granted, provided that the above
62fe8fb19SBen Gras * copyright notice and this permission notice appear in all copies.
72fe8fb19SBen Gras *
82fe8fb19SBen Gras * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
92fe8fb19SBen Gras * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
102fe8fb19SBen Gras * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
112fe8fb19SBen Gras * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
122fe8fb19SBen Gras * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
132fe8fb19SBen Gras * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
142fe8fb19SBen Gras * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
152fe8fb19SBen Gras * SOFTWARE.
162fe8fb19SBen Gras */
172fe8fb19SBen Gras
182fe8fb19SBen Gras #include <sys/cdefs.h>
192fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
202fe8fb19SBen Gras #ifdef notdef
212fe8fb19SBen Gras static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.1 2002/08/02 02:17:21 marka Exp ";
222fe8fb19SBen Gras #else
23*f14fb602SLionel Sambuc __RCSID("$NetBSD: inet_net_ntop.c,v 1.3 2012/03/20 17:08:13 matt Exp $");
242fe8fb19SBen Gras #endif
252fe8fb19SBen Gras #endif
262fe8fb19SBen Gras
272fe8fb19SBen Gras #include "port_before.h"
282fe8fb19SBen Gras
292fe8fb19SBen Gras #include "namespace.h"
302fe8fb19SBen Gras #include <sys/types.h>
312fe8fb19SBen Gras #include <sys/socket.h>
322fe8fb19SBen Gras #include <netinet/in.h>
332fe8fb19SBen Gras #include <arpa/inet.h>
342fe8fb19SBen Gras
352fe8fb19SBen Gras #include <errno.h>
362fe8fb19SBen Gras #include <stdio.h>
372fe8fb19SBen Gras #include <string.h>
382fe8fb19SBen Gras #include <stdlib.h>
392fe8fb19SBen Gras
402fe8fb19SBen Gras #include "port_after.h"
412fe8fb19SBen Gras
422fe8fb19SBen Gras #ifdef __weak_alias
432fe8fb19SBen Gras __weak_alias(inet_net_ntop,_inet_net_ntop)
442fe8fb19SBen Gras #endif
452fe8fb19SBen Gras
462fe8fb19SBen Gras #ifdef SPRINTF_CHAR
472fe8fb19SBen Gras # define SPRINTF(x) strlen(sprintf/**/x)
482fe8fb19SBen Gras #else
492fe8fb19SBen Gras # define SPRINTF(x) sprintf x
502fe8fb19SBen Gras #endif
512fe8fb19SBen Gras
52*f14fb602SLionel Sambuc static char * inet_net_ntop_ipv4(const u_char *src, int bits,
53*f14fb602SLionel Sambuc char *dst, size_t size);
54*f14fb602SLionel Sambuc static char * inet_net_ntop_ipv6(const u_char *src, int bits,
55*f14fb602SLionel Sambuc char *dst, size_t size);
562fe8fb19SBen Gras
572fe8fb19SBen Gras /*
582fe8fb19SBen Gras * char *
592fe8fb19SBen Gras * inet_net_ntop(af, src, bits, dst, size)
602fe8fb19SBen Gras * convert network number from network to presentation format.
612fe8fb19SBen Gras * generates CIDR style result always.
622fe8fb19SBen Gras * return:
632fe8fb19SBen Gras * pointer to dst, or NULL if an error occurred (check errno).
642fe8fb19SBen Gras * author:
652fe8fb19SBen Gras * Paul Vixie (ISC), July 1996
662fe8fb19SBen Gras */
672fe8fb19SBen Gras char *
inet_net_ntop(int af,const void * src,int bits,char * dst,size_t size)68*f14fb602SLionel Sambuc inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
692fe8fb19SBen Gras {
702fe8fb19SBen Gras switch (af) {
712fe8fb19SBen Gras case AF_INET:
722fe8fb19SBen Gras return (inet_net_ntop_ipv4(src, bits, dst, size));
732fe8fb19SBen Gras case AF_INET6:
742fe8fb19SBen Gras return (inet_net_ntop_ipv6(src, bits, dst, size));
752fe8fb19SBen Gras default:
762fe8fb19SBen Gras errno = EAFNOSUPPORT;
772fe8fb19SBen Gras return (NULL);
782fe8fb19SBen Gras }
792fe8fb19SBen Gras }
802fe8fb19SBen Gras
812fe8fb19SBen Gras /*
822fe8fb19SBen Gras * static char *
832fe8fb19SBen Gras * inet_net_ntop_ipv4(src, bits, dst, size)
842fe8fb19SBen Gras * convert IPv4 network number from network to presentation format.
852fe8fb19SBen Gras * generates CIDR style result always.
862fe8fb19SBen Gras * return:
872fe8fb19SBen Gras * pointer to dst, or NULL if an error occurred (check errno).
882fe8fb19SBen Gras * note:
892fe8fb19SBen Gras * network byte order assumed. this means 192.5.5.240/28 has
902fe8fb19SBen Gras * 0b11110000 in its fourth octet.
912fe8fb19SBen Gras * author:
922fe8fb19SBen Gras * Paul Vixie (ISC), July 1996
932fe8fb19SBen Gras */
942fe8fb19SBen Gras static char *
inet_net_ntop_ipv4(const u_char * src,int bits,char * dst,size_t size)95*f14fb602SLionel Sambuc inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
962fe8fb19SBen Gras {
972fe8fb19SBen Gras char *odst = dst;
982fe8fb19SBen Gras char *t;
992fe8fb19SBen Gras u_int m;
1002fe8fb19SBen Gras int b;
1012fe8fb19SBen Gras
1022fe8fb19SBen Gras if (bits < 0 || bits > 32) {
1032fe8fb19SBen Gras errno = EINVAL;
1042fe8fb19SBen Gras return (NULL);
1052fe8fb19SBen Gras }
1062fe8fb19SBen Gras
1072fe8fb19SBen Gras if (bits == 0) {
1082fe8fb19SBen Gras if (size < sizeof "0")
1092fe8fb19SBen Gras goto emsgsize;
1102fe8fb19SBen Gras *dst++ = '0';
1112fe8fb19SBen Gras size--;
1122fe8fb19SBen Gras *dst = '\0';
1132fe8fb19SBen Gras }
1142fe8fb19SBen Gras
1152fe8fb19SBen Gras /* Format whole octets. */
1162fe8fb19SBen Gras for (b = bits / 8; b > 0; b--) {
1172fe8fb19SBen Gras if (size <= sizeof "255.")
1182fe8fb19SBen Gras goto emsgsize;
1192fe8fb19SBen Gras t = dst;
1202fe8fb19SBen Gras dst += SPRINTF((dst, "%u", *src++));
1212fe8fb19SBen Gras if (b > 1) {
1222fe8fb19SBen Gras *dst++ = '.';
1232fe8fb19SBen Gras *dst = '\0';
1242fe8fb19SBen Gras }
1252fe8fb19SBen Gras size -= (size_t)(dst - t);
1262fe8fb19SBen Gras }
1272fe8fb19SBen Gras
1282fe8fb19SBen Gras /* Format partial octet. */
1292fe8fb19SBen Gras b = bits % 8;
1302fe8fb19SBen Gras if (b > 0) {
1312fe8fb19SBen Gras if (size <= sizeof ".255")
1322fe8fb19SBen Gras goto emsgsize;
1332fe8fb19SBen Gras t = dst;
1342fe8fb19SBen Gras if (dst != odst)
1352fe8fb19SBen Gras *dst++ = '.';
1362fe8fb19SBen Gras m = ((1 << b) - 1) << (8 - b);
1372fe8fb19SBen Gras dst += SPRINTF((dst, "%u", *src & m));
1382fe8fb19SBen Gras size -= (size_t)(dst - t);
1392fe8fb19SBen Gras }
1402fe8fb19SBen Gras
1412fe8fb19SBen Gras /* Format CIDR /width. */
1422fe8fb19SBen Gras if (size <= sizeof "/32")
1432fe8fb19SBen Gras goto emsgsize;
1442fe8fb19SBen Gras dst += SPRINTF((dst, "/%u", bits));
1452fe8fb19SBen Gras return (odst);
1462fe8fb19SBen Gras
1472fe8fb19SBen Gras emsgsize:
1482fe8fb19SBen Gras errno = EMSGSIZE;
1492fe8fb19SBen Gras return (NULL);
1502fe8fb19SBen Gras }
1512fe8fb19SBen Gras
1522fe8fb19SBen Gras /*
1532fe8fb19SBen Gras * static char *
1542fe8fb19SBen Gras * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
1552fe8fb19SBen Gras * convert IPv6 network number from network to presentation format.
1562fe8fb19SBen Gras * generates CIDR style result always. Picks the shortest representation
1572fe8fb19SBen Gras * unless the IP is really IPv4.
1582fe8fb19SBen Gras * always prints specified number of bits (bits).
1592fe8fb19SBen Gras * return:
1602fe8fb19SBen Gras * pointer to dst, or NULL if an error occurred (check errno).
1612fe8fb19SBen Gras * note:
1622fe8fb19SBen Gras * network byte order assumed. this means 192.5.5.240/28 has
1632fe8fb19SBen Gras * 0x11110000 in its fourth octet.
1642fe8fb19SBen Gras * author:
1652fe8fb19SBen Gras * Vadim Kogan (UCB), June 2001
1662fe8fb19SBen Gras * Original version (IPv4) by Paul Vixie (ISC), July 1996
1672fe8fb19SBen Gras */
1682fe8fb19SBen Gras
1692fe8fb19SBen Gras static char *
inet_net_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)170*f14fb602SLionel Sambuc inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
171*f14fb602SLionel Sambuc {
1722fe8fb19SBen Gras u_int m;
1732fe8fb19SBen Gras int b;
1742fe8fb19SBen Gras size_t p;
1752fe8fb19SBen Gras size_t zero_s, zero_l, tmp_zero_s, tmp_zero_l;
1762fe8fb19SBen Gras size_t i;
1772fe8fb19SBen Gras int is_ipv4 = 0;
1782fe8fb19SBen Gras unsigned char inbuf[16];
1792fe8fb19SBen Gras char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
1802fe8fb19SBen Gras char *cp;
1812fe8fb19SBen Gras size_t words;
1822fe8fb19SBen Gras u_char *s;
1832fe8fb19SBen Gras
1842fe8fb19SBen Gras if (bits < 0 || bits > 128) {
1852fe8fb19SBen Gras errno = EINVAL;
1862fe8fb19SBen Gras return (NULL);
1872fe8fb19SBen Gras }
1882fe8fb19SBen Gras
1892fe8fb19SBen Gras cp = outbuf;
1902fe8fb19SBen Gras
1912fe8fb19SBen Gras if (bits == 0) {
1922fe8fb19SBen Gras *cp++ = ':';
1932fe8fb19SBen Gras *cp++ = ':';
1942fe8fb19SBen Gras *cp = '\0';
1952fe8fb19SBen Gras } else {
1962fe8fb19SBen Gras /* Copy src to private buffer. Zero host part. */
1972fe8fb19SBen Gras p = (bits + 7) / 8;
1982fe8fb19SBen Gras memcpy(inbuf, src, p);
1992fe8fb19SBen Gras memset(inbuf + p, 0, 16 - p);
2002fe8fb19SBen Gras b = bits % 8;
2012fe8fb19SBen Gras if (b != 0) {
2022fe8fb19SBen Gras m = ~0 << (8 - b);
2032fe8fb19SBen Gras inbuf[p-1] &= m;
2042fe8fb19SBen Gras }
2052fe8fb19SBen Gras
2062fe8fb19SBen Gras s = inbuf;
2072fe8fb19SBen Gras
2082fe8fb19SBen Gras /* how many words need to be displayed in output */
2092fe8fb19SBen Gras words = (bits + 15) / 16;
2102fe8fb19SBen Gras if (words == 1)
2112fe8fb19SBen Gras words = 2;
2122fe8fb19SBen Gras
2132fe8fb19SBen Gras /* Find the longest substring of zero's */
2142fe8fb19SBen Gras zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
2152fe8fb19SBen Gras for (i = 0; i < (words * 2); i += 2) {
2162fe8fb19SBen Gras if ((s[i] | s[i+1]) == 0) {
2172fe8fb19SBen Gras if (tmp_zero_l == 0)
2182fe8fb19SBen Gras tmp_zero_s = i / 2;
2192fe8fb19SBen Gras tmp_zero_l++;
2202fe8fb19SBen Gras } else {
2212fe8fb19SBen Gras if (tmp_zero_l && zero_l < tmp_zero_l) {
2222fe8fb19SBen Gras zero_s = tmp_zero_s;
2232fe8fb19SBen Gras zero_l = tmp_zero_l;
2242fe8fb19SBen Gras tmp_zero_l = 0;
2252fe8fb19SBen Gras }
2262fe8fb19SBen Gras }
2272fe8fb19SBen Gras }
2282fe8fb19SBen Gras
2292fe8fb19SBen Gras if (tmp_zero_l && zero_l < tmp_zero_l) {
2302fe8fb19SBen Gras zero_s = tmp_zero_s;
2312fe8fb19SBen Gras zero_l = tmp_zero_l;
2322fe8fb19SBen Gras }
2332fe8fb19SBen Gras
2342fe8fb19SBen Gras if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
2352fe8fb19SBen Gras ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
2362fe8fb19SBen Gras ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
2372fe8fb19SBen Gras is_ipv4 = 1;
2382fe8fb19SBen Gras
2392fe8fb19SBen Gras /* Format whole words. */
2402fe8fb19SBen Gras for (p = 0; p < words; p++) {
2412fe8fb19SBen Gras if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
2422fe8fb19SBen Gras /* Time to skip some zeros */
2432fe8fb19SBen Gras if (p == zero_s)
2442fe8fb19SBen Gras *cp++ = ':';
2452fe8fb19SBen Gras if (p == words - 1)
2462fe8fb19SBen Gras *cp++ = ':';
2472fe8fb19SBen Gras s++;
2482fe8fb19SBen Gras s++;
2492fe8fb19SBen Gras continue;
2502fe8fb19SBen Gras }
2512fe8fb19SBen Gras
2522fe8fb19SBen Gras if (is_ipv4 && p > 5 ) {
2532fe8fb19SBen Gras *cp++ = (p == 6) ? ':' : '.';
2542fe8fb19SBen Gras cp += SPRINTF((cp, "%u", *s++));
2552fe8fb19SBen Gras /* we can potentially drop the last octet */
2562fe8fb19SBen Gras if (p != 7 || bits > 120) {
2572fe8fb19SBen Gras *cp++ = '.';
2582fe8fb19SBen Gras cp += SPRINTF((cp, "%u", *s++));
2592fe8fb19SBen Gras }
2602fe8fb19SBen Gras } else {
2612fe8fb19SBen Gras if (cp != outbuf)
2622fe8fb19SBen Gras *cp++ = ':';
2632fe8fb19SBen Gras cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
2642fe8fb19SBen Gras s += 2;
2652fe8fb19SBen Gras }
2662fe8fb19SBen Gras }
2672fe8fb19SBen Gras }
2682fe8fb19SBen Gras /* Format CIDR /width. */
2692fe8fb19SBen Gras (void)SPRINTF((cp, "/%u", bits));
2702fe8fb19SBen Gras if (strlen(outbuf) + 1 > size)
2712fe8fb19SBen Gras goto emsgsize;
2722fe8fb19SBen Gras strcpy(dst, outbuf);
2732fe8fb19SBen Gras
2742fe8fb19SBen Gras return (dst);
2752fe8fb19SBen Gras
2762fe8fb19SBen Gras emsgsize:
2772fe8fb19SBen Gras errno = EMSGSIZE;
2782fe8fb19SBen Gras return (NULL);
2792fe8fb19SBen Gras }
280