13fa54233Schristos /*
23fa54233Schristos * Copyright (c) 1996,1999 by Internet Software Consortium.
33fa54233Schristos *
43fa54233Schristos * Permission to use, copy, modify, and distribute this software for any
53fa54233Schristos * purpose with or without fee is hereby granted, provided that the above
63fa54233Schristos * copyright notice and this permission notice appear in all copies.
73fa54233Schristos *
83fa54233Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
93fa54233Schristos * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
103fa54233Schristos * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
113fa54233Schristos * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
123fa54233Schristos * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
133fa54233Schristos * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
143fa54233Schristos * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
153fa54233Schristos * SOFTWARE.
163fa54233Schristos */
173fa54233Schristos
183fa54233Schristos #include <sys/cdefs.h>
193fa54233Schristos #if defined(LIBC_SCCS) && !defined(lint)
203fa54233Schristos #ifdef notdef
213fa54233Schristos static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.1 2002/08/02 02:17:21 marka Exp ";
223fa54233Schristos #else
23*9c26aa2eSmaya __RCSID("$NetBSD: inet_net_ntop.c,v 1.4 2017/05/09 02:56:44 maya Exp $");
243fa54233Schristos #endif
253fa54233Schristos #endif
263fa54233Schristos
273fa54233Schristos #include "port_before.h"
283fa54233Schristos
293fa54233Schristos #include "namespace.h"
303fa54233Schristos #include <sys/types.h>
313fa54233Schristos #include <sys/socket.h>
323fa54233Schristos #include <netinet/in.h>
333fa54233Schristos #include <arpa/inet.h>
343fa54233Schristos
353fa54233Schristos #include <errno.h>
363fa54233Schristos #include <stdio.h>
373fa54233Schristos #include <string.h>
383fa54233Schristos #include <stdlib.h>
393fa54233Schristos
403fa54233Schristos #include "port_after.h"
413fa54233Schristos
423fa54233Schristos #ifdef __weak_alias
433fa54233Schristos __weak_alias(inet_net_ntop,_inet_net_ntop)
443fa54233Schristos #endif
453fa54233Schristos
463fa54233Schristos #ifdef SPRINTF_CHAR
473fa54233Schristos # define SPRINTF(x) strlen(sprintf/**/x)
483fa54233Schristos #else
493fa54233Schristos # define SPRINTF(x) sprintf x
503fa54233Schristos #endif
513fa54233Schristos
521f043722Smatt static char * inet_net_ntop_ipv4(const u_char *src, int bits,
531f043722Smatt char *dst, size_t size);
541f043722Smatt static char * inet_net_ntop_ipv6(const u_char *src, int bits,
551f043722Smatt char *dst, size_t size);
563fa54233Schristos
573fa54233Schristos /*
583fa54233Schristos * char *
593fa54233Schristos * inet_net_ntop(af, src, bits, dst, size)
603fa54233Schristos * convert network number from network to presentation format.
613fa54233Schristos * generates CIDR style result always.
623fa54233Schristos * return:
633fa54233Schristos * pointer to dst, or NULL if an error occurred (check errno).
643fa54233Schristos * author:
653fa54233Schristos * Paul Vixie (ISC), July 1996
663fa54233Schristos */
673fa54233Schristos char *
inet_net_ntop(int af,const void * src,int bits,char * dst,size_t size)681f043722Smatt inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
693fa54233Schristos {
703fa54233Schristos switch (af) {
713fa54233Schristos case AF_INET:
723fa54233Schristos return (inet_net_ntop_ipv4(src, bits, dst, size));
733fa54233Schristos case AF_INET6:
743fa54233Schristos return (inet_net_ntop_ipv6(src, bits, dst, size));
753fa54233Schristos default:
763fa54233Schristos errno = EAFNOSUPPORT;
773fa54233Schristos return (NULL);
783fa54233Schristos }
793fa54233Schristos }
803fa54233Schristos
813fa54233Schristos /*
823fa54233Schristos * static char *
833fa54233Schristos * inet_net_ntop_ipv4(src, bits, dst, size)
843fa54233Schristos * convert IPv4 network number from network to presentation format.
853fa54233Schristos * generates CIDR style result always.
863fa54233Schristos * return:
873fa54233Schristos * pointer to dst, or NULL if an error occurred (check errno).
883fa54233Schristos * note:
893fa54233Schristos * network byte order assumed. this means 192.5.5.240/28 has
903fa54233Schristos * 0b11110000 in its fourth octet.
913fa54233Schristos * author:
923fa54233Schristos * Paul Vixie (ISC), July 1996
933fa54233Schristos */
943fa54233Schristos static char *
inet_net_ntop_ipv4(const u_char * src,int bits,char * dst,size_t size)951f043722Smatt inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
963fa54233Schristos {
973fa54233Schristos char *odst = dst;
983fa54233Schristos char *t;
993fa54233Schristos u_int m;
1003fa54233Schristos int b;
1013fa54233Schristos
1023fa54233Schristos if (bits < 0 || bits > 32) {
1033fa54233Schristos errno = EINVAL;
1043fa54233Schristos return (NULL);
1053fa54233Schristos }
1063fa54233Schristos
1073fa54233Schristos if (bits == 0) {
1083fa54233Schristos if (size < sizeof "0")
1093fa54233Schristos goto emsgsize;
1103fa54233Schristos *dst++ = '0';
1113fa54233Schristos size--;
1123fa54233Schristos *dst = '\0';
1133fa54233Schristos }
1143fa54233Schristos
1153fa54233Schristos /* Format whole octets. */
1163fa54233Schristos for (b = bits / 8; b > 0; b--) {
1173fa54233Schristos if (size <= sizeof "255.")
1183fa54233Schristos goto emsgsize;
1193fa54233Schristos t = dst;
1203fa54233Schristos dst += SPRINTF((dst, "%u", *src++));
1213fa54233Schristos if (b > 1) {
1223fa54233Schristos *dst++ = '.';
1233fa54233Schristos *dst = '\0';
1243fa54233Schristos }
1253fa54233Schristos size -= (size_t)(dst - t);
1263fa54233Schristos }
1273fa54233Schristos
1283fa54233Schristos /* Format partial octet. */
1293fa54233Schristos b = bits % 8;
1303fa54233Schristos if (b > 0) {
1313fa54233Schristos if (size <= sizeof ".255")
1323fa54233Schristos goto emsgsize;
1333fa54233Schristos t = dst;
1343fa54233Schristos if (dst != odst)
1353fa54233Schristos *dst++ = '.';
1363fa54233Schristos m = ((1 << b) - 1) << (8 - b);
1373fa54233Schristos dst += SPRINTF((dst, "%u", *src & m));
1383fa54233Schristos size -= (size_t)(dst - t);
1393fa54233Schristos }
1403fa54233Schristos
1413fa54233Schristos /* Format CIDR /width. */
1423fa54233Schristos if (size <= sizeof "/32")
1433fa54233Schristos goto emsgsize;
1443fa54233Schristos dst += SPRINTF((dst, "/%u", bits));
1453fa54233Schristos return (odst);
1463fa54233Schristos
1473fa54233Schristos emsgsize:
1483fa54233Schristos errno = EMSGSIZE;
1493fa54233Schristos return (NULL);
1503fa54233Schristos }
1513fa54233Schristos
1523fa54233Schristos /*
1533fa54233Schristos * static char *
1543fa54233Schristos * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
1553fa54233Schristos * convert IPv6 network number from network to presentation format.
1563fa54233Schristos * generates CIDR style result always. Picks the shortest representation
1573fa54233Schristos * unless the IP is really IPv4.
1583fa54233Schristos * always prints specified number of bits (bits).
1593fa54233Schristos * return:
1603fa54233Schristos * pointer to dst, or NULL if an error occurred (check errno).
1613fa54233Schristos * note:
1623fa54233Schristos * network byte order assumed. this means 192.5.5.240/28 has
1633fa54233Schristos * 0x11110000 in its fourth octet.
1643fa54233Schristos * author:
1653fa54233Schristos * Vadim Kogan (UCB), June 2001
1663fa54233Schristos * Original version (IPv4) by Paul Vixie (ISC), July 1996
1673fa54233Schristos */
1683fa54233Schristos
1693fa54233Schristos static char *
inet_net_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)1701f043722Smatt inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
1711f043722Smatt {
1723fa54233Schristos u_int m;
1733fa54233Schristos int b;
1743fa54233Schristos size_t p;
17553e9163aSlukem size_t zero_s, zero_l, tmp_zero_s, tmp_zero_l;
17653e9163aSlukem size_t i;
1773fa54233Schristos int is_ipv4 = 0;
1783fa54233Schristos unsigned char inbuf[16];
1793fa54233Schristos char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
1803fa54233Schristos char *cp;
18153e9163aSlukem size_t words;
1823fa54233Schristos u_char *s;
1833fa54233Schristos
1843fa54233Schristos if (bits < 0 || bits > 128) {
1853fa54233Schristos errno = EINVAL;
1863fa54233Schristos return (NULL);
1873fa54233Schristos }
1883fa54233Schristos
1893fa54233Schristos cp = outbuf;
1903fa54233Schristos
1913fa54233Schristos if (bits == 0) {
1923fa54233Schristos *cp++ = ':';
1933fa54233Schristos *cp++ = ':';
1943fa54233Schristos *cp = '\0';
1953fa54233Schristos } else {
1963fa54233Schristos /* Copy src to private buffer. Zero host part. */
1973fa54233Schristos p = (bits + 7) / 8;
1983fa54233Schristos memcpy(inbuf, src, p);
1993fa54233Schristos memset(inbuf + p, 0, 16 - p);
2003fa54233Schristos b = bits % 8;
2013fa54233Schristos if (b != 0) {
202*9c26aa2eSmaya m = ~0u << (8 - b);
2033fa54233Schristos inbuf[p-1] &= m;
2043fa54233Schristos }
2053fa54233Schristos
2063fa54233Schristos s = inbuf;
2073fa54233Schristos
2083fa54233Schristos /* how many words need to be displayed in output */
2093fa54233Schristos words = (bits + 15) / 16;
2103fa54233Schristos if (words == 1)
2113fa54233Schristos words = 2;
2123fa54233Schristos
2133fa54233Schristos /* Find the longest substring of zero's */
2143fa54233Schristos zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
2153fa54233Schristos for (i = 0; i < (words * 2); i += 2) {
2163fa54233Schristos if ((s[i] | s[i+1]) == 0) {
2173fa54233Schristos if (tmp_zero_l == 0)
2183fa54233Schristos tmp_zero_s = i / 2;
2193fa54233Schristos tmp_zero_l++;
2203fa54233Schristos } else {
2213fa54233Schristos if (tmp_zero_l && zero_l < tmp_zero_l) {
2223fa54233Schristos zero_s = tmp_zero_s;
2233fa54233Schristos zero_l = tmp_zero_l;
2243fa54233Schristos tmp_zero_l = 0;
2253fa54233Schristos }
2263fa54233Schristos }
2273fa54233Schristos }
2283fa54233Schristos
2293fa54233Schristos if (tmp_zero_l && zero_l < tmp_zero_l) {
2303fa54233Schristos zero_s = tmp_zero_s;
2313fa54233Schristos zero_l = tmp_zero_l;
2323fa54233Schristos }
2333fa54233Schristos
2343fa54233Schristos if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
2353fa54233Schristos ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
2363fa54233Schristos ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
2373fa54233Schristos is_ipv4 = 1;
2383fa54233Schristos
2393fa54233Schristos /* Format whole words. */
2403fa54233Schristos for (p = 0; p < words; p++) {
2413fa54233Schristos if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
2423fa54233Schristos /* Time to skip some zeros */
2433fa54233Schristos if (p == zero_s)
2443fa54233Schristos *cp++ = ':';
2453fa54233Schristos if (p == words - 1)
2463fa54233Schristos *cp++ = ':';
2473fa54233Schristos s++;
2483fa54233Schristos s++;
2493fa54233Schristos continue;
2503fa54233Schristos }
2513fa54233Schristos
2523fa54233Schristos if (is_ipv4 && p > 5 ) {
2533fa54233Schristos *cp++ = (p == 6) ? ':' : '.';
2543fa54233Schristos cp += SPRINTF((cp, "%u", *s++));
2553fa54233Schristos /* we can potentially drop the last octet */
2563fa54233Schristos if (p != 7 || bits > 120) {
2573fa54233Schristos *cp++ = '.';
2583fa54233Schristos cp += SPRINTF((cp, "%u", *s++));
2593fa54233Schristos }
2603fa54233Schristos } else {
2613fa54233Schristos if (cp != outbuf)
2623fa54233Schristos *cp++ = ':';
2633fa54233Schristos cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
2643fa54233Schristos s += 2;
2653fa54233Schristos }
2663fa54233Schristos }
2673fa54233Schristos }
2683fa54233Schristos /* Format CIDR /width. */
2693fa54233Schristos (void)SPRINTF((cp, "/%u", bits));
2703fa54233Schristos if (strlen(outbuf) + 1 > size)
2713fa54233Schristos goto emsgsize;
2723fa54233Schristos strcpy(dst, outbuf);
2733fa54233Schristos
2743fa54233Schristos return (dst);
2753fa54233Schristos
2763fa54233Schristos emsgsize:
2773fa54233Schristos errno = EMSGSIZE;
2783fa54233Schristos return (NULL);
2793fa54233Schristos }
280