17c478bd9Sstevel@tonic-gate /*
29525b14bSRao Shoaib * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
37c478bd9Sstevel@tonic-gate * Copyright (c) 1996,1999 by Internet Software Consortium.
47c478bd9Sstevel@tonic-gate *
57c478bd9Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any
67c478bd9Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above
77c478bd9Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies.
87c478bd9Sstevel@tonic-gate *
99525b14bSRao Shoaib * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
109525b14bSRao Shoaib * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119525b14bSRao Shoaib * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
129525b14bSRao Shoaib * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139525b14bSRao Shoaib * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149525b14bSRao Shoaib * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
159525b14bSRao Shoaib * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
167c478bd9Sstevel@tonic-gate */
177c478bd9Sstevel@tonic-gate
187c478bd9Sstevel@tonic-gate #if defined(LIBC_SCCS) && !defined(lint)
199525b14bSRao Shoaib static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.5 2006/06/20 02:50:14 marka Exp $";
207c478bd9Sstevel@tonic-gate #endif
217c478bd9Sstevel@tonic-gate
227c478bd9Sstevel@tonic-gate #include "port_before.h"
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate #include <sys/types.h>
257c478bd9Sstevel@tonic-gate #include <sys/socket.h>
267c478bd9Sstevel@tonic-gate #include <netinet/in.h>
277c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include <errno.h>
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
33*7a478aebSToomas Soome #include <limits.h>
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate #include "port_after.h"
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #ifdef SPRINTF_CHAR
387c478bd9Sstevel@tonic-gate # define SPRINTF(x) strlen(sprintf/**/x)
397c478bd9Sstevel@tonic-gate #else
407c478bd9Sstevel@tonic-gate # define SPRINTF(x) ((size_t)sprintf x)
417c478bd9Sstevel@tonic-gate #endif
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate static char * inet_net_ntop_ipv4 __P((const u_char *src, int bits,
447c478bd9Sstevel@tonic-gate char *dst, size_t size));
457c478bd9Sstevel@tonic-gate static char * inet_net_ntop_ipv6 __P((const u_char *src, int bits,
467c478bd9Sstevel@tonic-gate char *dst, size_t size));
477c478bd9Sstevel@tonic-gate
489525b14bSRao Shoaib /*%
497c478bd9Sstevel@tonic-gate * char *
507c478bd9Sstevel@tonic-gate * inet_net_ntop(af, src, bits, dst, size)
517c478bd9Sstevel@tonic-gate * convert network number from network to presentation format.
527c478bd9Sstevel@tonic-gate * generates CIDR style result always.
537c478bd9Sstevel@tonic-gate * return:
547c478bd9Sstevel@tonic-gate * pointer to dst, or NULL if an error occurred (check errno).
557c478bd9Sstevel@tonic-gate * author:
567c478bd9Sstevel@tonic-gate * Paul Vixie (ISC), July 1996
577c478bd9Sstevel@tonic-gate */
587c478bd9Sstevel@tonic-gate char *
inet_net_ntop(af,src,bits,dst,size)597c478bd9Sstevel@tonic-gate inet_net_ntop(af, src, bits, dst, size)
607c478bd9Sstevel@tonic-gate int af;
617c478bd9Sstevel@tonic-gate const void *src;
627c478bd9Sstevel@tonic-gate int bits;
637c478bd9Sstevel@tonic-gate char *dst;
647c478bd9Sstevel@tonic-gate size_t size;
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate switch (af) {
677c478bd9Sstevel@tonic-gate case AF_INET:
687c478bd9Sstevel@tonic-gate return (inet_net_ntop_ipv4(src, bits, dst, size));
697c478bd9Sstevel@tonic-gate case AF_INET6:
707c478bd9Sstevel@tonic-gate return (inet_net_ntop_ipv6(src, bits, dst, size));
717c478bd9Sstevel@tonic-gate default:
727c478bd9Sstevel@tonic-gate errno = EAFNOSUPPORT;
737c478bd9Sstevel@tonic-gate return (NULL);
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate
779525b14bSRao Shoaib /*%
787c478bd9Sstevel@tonic-gate * static char *
797c478bd9Sstevel@tonic-gate * inet_net_ntop_ipv4(src, bits, dst, size)
807c478bd9Sstevel@tonic-gate * convert IPv4 network number from network to presentation format.
817c478bd9Sstevel@tonic-gate * generates CIDR style result always.
827c478bd9Sstevel@tonic-gate * return:
837c478bd9Sstevel@tonic-gate * pointer to dst, or NULL if an error occurred (check errno).
847c478bd9Sstevel@tonic-gate * note:
857c478bd9Sstevel@tonic-gate * network byte order assumed. this means 192.5.5.240/28 has
867c478bd9Sstevel@tonic-gate * 0b11110000 in its fourth octet.
877c478bd9Sstevel@tonic-gate * author:
887c478bd9Sstevel@tonic-gate * Paul Vixie (ISC), July 1996
897c478bd9Sstevel@tonic-gate */
907c478bd9Sstevel@tonic-gate static char *
inet_net_ntop_ipv4(src,bits,dst,size)917c478bd9Sstevel@tonic-gate inet_net_ntop_ipv4(src, bits, dst, size)
927c478bd9Sstevel@tonic-gate const u_char *src;
937c478bd9Sstevel@tonic-gate int bits;
947c478bd9Sstevel@tonic-gate char *dst;
957c478bd9Sstevel@tonic-gate size_t size;
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate char *odst = dst;
987c478bd9Sstevel@tonic-gate char *t;
997c478bd9Sstevel@tonic-gate u_int m;
1007c478bd9Sstevel@tonic-gate int b;
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate if (bits < 0 || bits > 32) {
1037c478bd9Sstevel@tonic-gate errno = EINVAL;
1047c478bd9Sstevel@tonic-gate return (NULL);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate if (bits == 0) {
1087c478bd9Sstevel@tonic-gate if (size < sizeof "0")
1097c478bd9Sstevel@tonic-gate goto emsgsize;
1107c478bd9Sstevel@tonic-gate *dst++ = '0';
1117c478bd9Sstevel@tonic-gate size--;
1127c478bd9Sstevel@tonic-gate *dst = '\0';
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate /* Format whole octets. */
1167c478bd9Sstevel@tonic-gate for (b = bits / 8; b > 0; b--) {
1177c478bd9Sstevel@tonic-gate if (size <= sizeof "255.")
1187c478bd9Sstevel@tonic-gate goto emsgsize;
1197c478bd9Sstevel@tonic-gate t = dst;
1207c478bd9Sstevel@tonic-gate dst += SPRINTF((dst, "%u", *src++));
1217c478bd9Sstevel@tonic-gate if (b > 1) {
1227c478bd9Sstevel@tonic-gate *dst++ = '.';
1237c478bd9Sstevel@tonic-gate *dst = '\0';
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate size -= (size_t)(dst - t);
1267c478bd9Sstevel@tonic-gate }
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate /* Format partial octet. */
1297c478bd9Sstevel@tonic-gate b = bits % 8;
1307c478bd9Sstevel@tonic-gate if (b > 0) {
1317c478bd9Sstevel@tonic-gate if (size <= sizeof ".255")
1327c478bd9Sstevel@tonic-gate goto emsgsize;
1337c478bd9Sstevel@tonic-gate t = dst;
1347c478bd9Sstevel@tonic-gate if (dst != odst)
1357c478bd9Sstevel@tonic-gate *dst++ = '.';
1367c478bd9Sstevel@tonic-gate m = ((1 << b) - 1) << (8 - b);
1377c478bd9Sstevel@tonic-gate dst += SPRINTF((dst, "%u", *src & m));
1387c478bd9Sstevel@tonic-gate size -= (size_t)(dst - t);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate /* Format CIDR /width. */
1427c478bd9Sstevel@tonic-gate if (size <= sizeof "/32")
1437c478bd9Sstevel@tonic-gate goto emsgsize;
1447c478bd9Sstevel@tonic-gate dst += SPRINTF((dst, "/%u", bits));
1457c478bd9Sstevel@tonic-gate return (odst);
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate emsgsize:
1487c478bd9Sstevel@tonic-gate errno = EMSGSIZE;
1497c478bd9Sstevel@tonic-gate return (NULL);
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate
1529525b14bSRao Shoaib /*%
1537c478bd9Sstevel@tonic-gate * static char *
1547c478bd9Sstevel@tonic-gate * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
1557c478bd9Sstevel@tonic-gate * convert IPv6 network number from network to presentation format.
1567c478bd9Sstevel@tonic-gate * generates CIDR style result always. Picks the shortest representation
1577c478bd9Sstevel@tonic-gate * unless the IP is really IPv4.
1587c478bd9Sstevel@tonic-gate * always prints specified number of bits (bits).
1597c478bd9Sstevel@tonic-gate * return:
1607c478bd9Sstevel@tonic-gate * pointer to dst, or NULL if an error occurred (check errno).
1617c478bd9Sstevel@tonic-gate * note:
1627c478bd9Sstevel@tonic-gate * network byte order assumed. this means 192.5.5.240/28 has
1639525b14bSRao Shoaib * 0x11110000 in its fourth octet.
1647c478bd9Sstevel@tonic-gate * author:
1657c478bd9Sstevel@tonic-gate * Vadim Kogan (UCB), June 2001
1667c478bd9Sstevel@tonic-gate * Original version (IPv4) by Paul Vixie (ISC), July 1996
1677c478bd9Sstevel@tonic-gate */
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gate static char *
inet_net_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)1707c478bd9Sstevel@tonic-gate inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
1717c478bd9Sstevel@tonic-gate u_int m;
1727c478bd9Sstevel@tonic-gate int b;
1737c478bd9Sstevel@tonic-gate int p;
1747c478bd9Sstevel@tonic-gate int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
1757c478bd9Sstevel@tonic-gate int i;
1767c478bd9Sstevel@tonic-gate int is_ipv4 = 0;
1777c478bd9Sstevel@tonic-gate unsigned char inbuf[16];
1787c478bd9Sstevel@tonic-gate char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
1797c478bd9Sstevel@tonic-gate char *cp;
1807c478bd9Sstevel@tonic-gate int words;
1817c478bd9Sstevel@tonic-gate u_char *s;
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate if (bits < 0 || bits > 128) {
1847c478bd9Sstevel@tonic-gate errno = EINVAL;
1857c478bd9Sstevel@tonic-gate return (NULL);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate cp = outbuf;
1897c478bd9Sstevel@tonic-gate
1907c478bd9Sstevel@tonic-gate if (bits == 0) {
1917c478bd9Sstevel@tonic-gate *cp++ = ':';
1927c478bd9Sstevel@tonic-gate *cp++ = ':';
1937c478bd9Sstevel@tonic-gate *cp = '\0';
1947c478bd9Sstevel@tonic-gate } else {
19555fea89dSDan Cross /* Copy src to private buffer. Zero host part. */
1967c478bd9Sstevel@tonic-gate p = (bits + 7) / 8;
1977c478bd9Sstevel@tonic-gate memcpy(inbuf, src, p);
1987c478bd9Sstevel@tonic-gate memset(inbuf + p, 0, 16 - p);
1997c478bd9Sstevel@tonic-gate b = bits % 8;
2007c478bd9Sstevel@tonic-gate if (b != 0) {
201*7a478aebSToomas Soome m = UINT_MAX << (8 - b);
2027c478bd9Sstevel@tonic-gate inbuf[p-1] &= m;
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate
2057c478bd9Sstevel@tonic-gate s = inbuf;
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate /* how many words need to be displayed in output */
2087c478bd9Sstevel@tonic-gate words = (bits + 15) / 16;
2097c478bd9Sstevel@tonic-gate if (words == 1)
2107c478bd9Sstevel@tonic-gate words = 2;
21155fea89dSDan Cross
2127c478bd9Sstevel@tonic-gate /* Find the longest substring of zero's */
2137c478bd9Sstevel@tonic-gate zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
2147c478bd9Sstevel@tonic-gate for (i = 0; i < (words * 2); i += 2) {
2157c478bd9Sstevel@tonic-gate if ((s[i] | s[i+1]) == 0) {
2167c478bd9Sstevel@tonic-gate if (tmp_zero_l == 0)
2177c478bd9Sstevel@tonic-gate tmp_zero_s = i / 2;
2187c478bd9Sstevel@tonic-gate tmp_zero_l++;
2197c478bd9Sstevel@tonic-gate } else {
2207c478bd9Sstevel@tonic-gate if (tmp_zero_l && zero_l < tmp_zero_l) {
2217c478bd9Sstevel@tonic-gate zero_s = tmp_zero_s;
2227c478bd9Sstevel@tonic-gate zero_l = tmp_zero_l;
2237c478bd9Sstevel@tonic-gate tmp_zero_l = 0;
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate
2287c478bd9Sstevel@tonic-gate if (tmp_zero_l && zero_l < tmp_zero_l) {
2297c478bd9Sstevel@tonic-gate zero_s = tmp_zero_s;
2307c478bd9Sstevel@tonic-gate zero_l = tmp_zero_l;
2317c478bd9Sstevel@tonic-gate }
2327c478bd9Sstevel@tonic-gate
2337c478bd9Sstevel@tonic-gate if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
2347c478bd9Sstevel@tonic-gate ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
2357c478bd9Sstevel@tonic-gate ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
2367c478bd9Sstevel@tonic-gate is_ipv4 = 1;
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gate /* Format whole words. */
2397c478bd9Sstevel@tonic-gate for (p = 0; p < words; p++) {
2407c478bd9Sstevel@tonic-gate if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
2417c478bd9Sstevel@tonic-gate /* Time to skip some zeros */
2427c478bd9Sstevel@tonic-gate if (p == zero_s)
2437c478bd9Sstevel@tonic-gate *cp++ = ':';
2447c478bd9Sstevel@tonic-gate if (p == words - 1)
2457c478bd9Sstevel@tonic-gate *cp++ = ':';
2467c478bd9Sstevel@tonic-gate s++;
2477c478bd9Sstevel@tonic-gate s++;
2487c478bd9Sstevel@tonic-gate continue;
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate
2517c478bd9Sstevel@tonic-gate if (is_ipv4 && p > 5 ) {
2527c478bd9Sstevel@tonic-gate *cp++ = (p == 6) ? ':' : '.';
2537c478bd9Sstevel@tonic-gate cp += SPRINTF((cp, "%u", *s++));
2547c478bd9Sstevel@tonic-gate /* we can potentially drop the last octet */
2557c478bd9Sstevel@tonic-gate if (p != 7 || bits > 120) {
2567c478bd9Sstevel@tonic-gate *cp++ = '.';
2577c478bd9Sstevel@tonic-gate cp += SPRINTF((cp, "%u", *s++));
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate } else {
2607c478bd9Sstevel@tonic-gate if (cp != outbuf)
2617c478bd9Sstevel@tonic-gate *cp++ = ':';
2627c478bd9Sstevel@tonic-gate cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
2637c478bd9Sstevel@tonic-gate s += 2;
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate /* Format CIDR /width. */
2689525b14bSRao Shoaib sprintf(cp, "/%u", bits);
2697c478bd9Sstevel@tonic-gate if (strlen(outbuf) + 1 > size)
2707c478bd9Sstevel@tonic-gate goto emsgsize;
2717c478bd9Sstevel@tonic-gate strcpy(dst, outbuf);
27255fea89dSDan Cross
2737c478bd9Sstevel@tonic-gate return (dst);
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate emsgsize:
2767c478bd9Sstevel@tonic-gate errno = EMSGSIZE;
2777c478bd9Sstevel@tonic-gate return (NULL);
2787c478bd9Sstevel@tonic-gate }
2799525b14bSRao Shoaib
2809525b14bSRao Shoaib /*! \file */
281