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