xref: /onnv-gate/usr/src/lib/libresolv2/common/inet/inet_cidr_ntop.c (revision 11038:74b12212b8a2)
10Sstevel@tonic-gate /*
2*11038SRao.Shoaib@Sun.COM  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
30Sstevel@tonic-gate  * Copyright (c) 1998,1999 by Internet Software Consortium.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
60Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
70Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
80Sstevel@tonic-gate  *
9*11038SRao.Shoaib@Sun.COM  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10*11038SRao.Shoaib@Sun.COM  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*11038SRao.Shoaib@Sun.COM  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12*11038SRao.Shoaib@Sun.COM  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*11038SRao.Shoaib@Sun.COM  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*11038SRao.Shoaib@Sun.COM  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*11038SRao.Shoaib@Sun.COM  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160Sstevel@tonic-gate  */
170Sstevel@tonic-gate 
180Sstevel@tonic-gate #if defined(LIBC_SCCS) && !defined(lint)
19*11038SRao.Shoaib@Sun.COM static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.7 2006/10/11 02:18:18 marka Exp $";
200Sstevel@tonic-gate #endif
210Sstevel@tonic-gate 
220Sstevel@tonic-gate #include "port_before.h"
230Sstevel@tonic-gate 
240Sstevel@tonic-gate #include <sys/types.h>
250Sstevel@tonic-gate #include <sys/socket.h>
260Sstevel@tonic-gate #include <netinet/in.h>
270Sstevel@tonic-gate #include <arpa/nameser.h>
280Sstevel@tonic-gate #include <arpa/inet.h>
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "port_after.h"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #ifdef SPRINTF_CHAR
380Sstevel@tonic-gate # define SPRINTF(x) strlen(sprintf/**/x)
390Sstevel@tonic-gate #else
400Sstevel@tonic-gate # define SPRINTF(x) ((size_t)sprintf x)
410Sstevel@tonic-gate #endif
420Sstevel@tonic-gate 
43*11038SRao.Shoaib@Sun.COM static char *
44*11038SRao.Shoaib@Sun.COM inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size);
45*11038SRao.Shoaib@Sun.COM static char *
46*11038SRao.Shoaib@Sun.COM inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size);
470Sstevel@tonic-gate 
48*11038SRao.Shoaib@Sun.COM /*%
490Sstevel@tonic-gate  * char *
500Sstevel@tonic-gate  * inet_cidr_ntop(af, src, bits, dst, size)
510Sstevel@tonic-gate  *	convert network address from network to presentation format.
520Sstevel@tonic-gate  *	"src"'s size is determined from its "af".
530Sstevel@tonic-gate  * return:
540Sstevel@tonic-gate  *	pointer to dst, or NULL if an error occurred (check errno).
550Sstevel@tonic-gate  * note:
560Sstevel@tonic-gate  *	192.5.5.1/28 has a nonzero host part, which means it isn't a network
570Sstevel@tonic-gate  *	as called for by inet_net_ntop() but it can be a host address with
580Sstevel@tonic-gate  *	an included netmask.
590Sstevel@tonic-gate  * author:
600Sstevel@tonic-gate  *	Paul Vixie (ISC), October 1998
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate char *
inet_cidr_ntop(int af,const void * src,int bits,char * dst,size_t size)630Sstevel@tonic-gate inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
640Sstevel@tonic-gate 	switch (af) {
650Sstevel@tonic-gate 	case AF_INET:
660Sstevel@tonic-gate 		return (inet_cidr_ntop_ipv4(src, bits, dst, size));
670Sstevel@tonic-gate 	case AF_INET6:
680Sstevel@tonic-gate 		return (inet_cidr_ntop_ipv6(src, bits, dst, size));
690Sstevel@tonic-gate 	default:
700Sstevel@tonic-gate 		errno = EAFNOSUPPORT;
710Sstevel@tonic-gate 		return (NULL);
720Sstevel@tonic-gate 	}
730Sstevel@tonic-gate }
740Sstevel@tonic-gate 
750Sstevel@tonic-gate static int
decoct(const u_char * src,int bytes,char * dst,size_t size)760Sstevel@tonic-gate decoct(const u_char *src, int bytes, char *dst, size_t size) {
770Sstevel@tonic-gate 	char *odst = dst;
780Sstevel@tonic-gate 	char *t;
790Sstevel@tonic-gate 	int b;
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	for (b = 1; b <= bytes; b++) {
820Sstevel@tonic-gate 		if (size < sizeof "255.")
830Sstevel@tonic-gate 			return (0);
840Sstevel@tonic-gate 		t = dst;
850Sstevel@tonic-gate 		dst += SPRINTF((dst, "%u", *src++));
860Sstevel@tonic-gate 		if (b != bytes) {
870Sstevel@tonic-gate 			*dst++ = '.';
880Sstevel@tonic-gate 			*dst = '\0';
890Sstevel@tonic-gate 		}
900Sstevel@tonic-gate 		size -= (size_t)(dst - t);
910Sstevel@tonic-gate 	}
920Sstevel@tonic-gate 	return (dst - odst);
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
95*11038SRao.Shoaib@Sun.COM /*%
960Sstevel@tonic-gate  * static char *
970Sstevel@tonic-gate  * inet_cidr_ntop_ipv4(src, bits, dst, size)
980Sstevel@tonic-gate  *	convert IPv4 network address from network to presentation format.
990Sstevel@tonic-gate  *	"src"'s size is determined from its "af".
1000Sstevel@tonic-gate  * return:
1010Sstevel@tonic-gate  *	pointer to dst, or NULL if an error occurred (check errno).
1020Sstevel@tonic-gate  * note:
1030Sstevel@tonic-gate  *	network byte order assumed.  this means 192.5.5.240/28 has
1040Sstevel@tonic-gate  *	0b11110000 in its fourth octet.
1050Sstevel@tonic-gate  * author:
1060Sstevel@tonic-gate  *	Paul Vixie (ISC), October 1998
1070Sstevel@tonic-gate  */
1080Sstevel@tonic-gate static char *
inet_cidr_ntop_ipv4(const u_char * src,int bits,char * dst,size_t size)1090Sstevel@tonic-gate inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
1100Sstevel@tonic-gate 	char *odst = dst;
1110Sstevel@tonic-gate 	size_t len = 4;
1120Sstevel@tonic-gate 	size_t b;
1130Sstevel@tonic-gate 	size_t bytes;
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 	if ((bits < -1) || (bits > 32)) {
1160Sstevel@tonic-gate 		errno = EINVAL;
1170Sstevel@tonic-gate 		return (NULL);
1180Sstevel@tonic-gate 	}
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/* Find number of significant bytes in address. */
1210Sstevel@tonic-gate 	if (bits == -1)
1220Sstevel@tonic-gate 		len = 4;
1230Sstevel@tonic-gate 	else
124*11038SRao.Shoaib@Sun.COM 		for (len = 1, b = 1 ; b < 4U; b++)
1250Sstevel@tonic-gate 			if (*(src + b))
1260Sstevel@tonic-gate 				len = b + 1;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	/* Format whole octets plus nonzero trailing octets. */
1290Sstevel@tonic-gate 	bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
1300Sstevel@tonic-gate 	if (len > bytes)
1310Sstevel@tonic-gate 		bytes = len;
1320Sstevel@tonic-gate 	b = decoct(src, bytes, dst, size);
133*11038SRao.Shoaib@Sun.COM 	if (b == 0U)
1340Sstevel@tonic-gate 		goto emsgsize;
1350Sstevel@tonic-gate 	dst += b;
1360Sstevel@tonic-gate 	size -= b;
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	if (bits != -1) {
1390Sstevel@tonic-gate 		/* Format CIDR /width. */
1400Sstevel@tonic-gate 		if (size < sizeof "/32")
1410Sstevel@tonic-gate 			goto emsgsize;
1420Sstevel@tonic-gate 		dst += SPRINTF((dst, "/%u", bits));
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	return (odst);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate  emsgsize:
1480Sstevel@tonic-gate 	errno = EMSGSIZE;
1490Sstevel@tonic-gate 	return (NULL);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate static char *
inet_cidr_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)1530Sstevel@tonic-gate inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
1540Sstevel@tonic-gate 	/*
1550Sstevel@tonic-gate 	 * Note that int32_t and int16_t need only be "at least" large enough
1560Sstevel@tonic-gate 	 * to contain a value of the specified size.  On some systems, like
1570Sstevel@tonic-gate 	 * Crays, there is no such thing as an integer variable with 16 bits.
1580Sstevel@tonic-gate 	 * Keep this in mind if you think this function should have been coded
1590Sstevel@tonic-gate 	 * to use pointer overlays.  All the world's not a VAX.
1600Sstevel@tonic-gate 	 */
1610Sstevel@tonic-gate 	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
1620Sstevel@tonic-gate 	char *tp;
1630Sstevel@tonic-gate 	struct { int base, len; } best, cur;
1640Sstevel@tonic-gate 	u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
1650Sstevel@tonic-gate 	int i;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	if ((bits < -1) || (bits > 128)) {
1680Sstevel@tonic-gate 		errno = EINVAL;
1690Sstevel@tonic-gate 		return (NULL);
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	/*
1730Sstevel@tonic-gate 	 * Preprocess:
1740Sstevel@tonic-gate 	 *	Copy the input (bytewise) array into a wordwise array.
1750Sstevel@tonic-gate 	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
1760Sstevel@tonic-gate 	 */
1770Sstevel@tonic-gate 	memset(words, '\0', sizeof words);
1780Sstevel@tonic-gate 	for (i = 0; i < NS_IN6ADDRSZ; i++)
1790Sstevel@tonic-gate 		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
1800Sstevel@tonic-gate 	best.base = -1;
181*11038SRao.Shoaib@Sun.COM 	best.len = 0;
1820Sstevel@tonic-gate 	cur.base = -1;
183*11038SRao.Shoaib@Sun.COM 	cur.len = 0;
1840Sstevel@tonic-gate 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
1850Sstevel@tonic-gate 		if (words[i] == 0) {
1860Sstevel@tonic-gate 			if (cur.base == -1)
1870Sstevel@tonic-gate 				cur.base = i, cur.len = 1;
1880Sstevel@tonic-gate 			else
1890Sstevel@tonic-gate 				cur.len++;
1900Sstevel@tonic-gate 		} else {
1910Sstevel@tonic-gate 			if (cur.base != -1) {
1920Sstevel@tonic-gate 				if (best.base == -1 || cur.len > best.len)
1930Sstevel@tonic-gate 					best = cur;
1940Sstevel@tonic-gate 				cur.base = -1;
1950Sstevel@tonic-gate 			}
1960Sstevel@tonic-gate 		}
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 	if (cur.base != -1) {
1990Sstevel@tonic-gate 		if (best.base == -1 || cur.len > best.len)
2000Sstevel@tonic-gate 			best = cur;
2010Sstevel@tonic-gate 	}
2020Sstevel@tonic-gate 	if (best.base != -1 && best.len < 2)
2030Sstevel@tonic-gate 		best.base = -1;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	/*
2060Sstevel@tonic-gate 	 * Format the result.
2070Sstevel@tonic-gate 	 */
2080Sstevel@tonic-gate 	tp = tmp;
2090Sstevel@tonic-gate 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
2100Sstevel@tonic-gate 		/* Are we inside the best run of 0x00's? */
2110Sstevel@tonic-gate 		if (best.base != -1 && i >= best.base &&
2120Sstevel@tonic-gate 		    i < (best.base + best.len)) {
2130Sstevel@tonic-gate 			if (i == best.base)
2140Sstevel@tonic-gate 				*tp++ = ':';
2150Sstevel@tonic-gate 			continue;
2160Sstevel@tonic-gate 		}
2170Sstevel@tonic-gate 		/* Are we following an initial run of 0x00s or any real hex? */
2180Sstevel@tonic-gate 		if (i != 0)
2190Sstevel@tonic-gate 			*tp++ = ':';
2200Sstevel@tonic-gate 		/* Is this address an encapsulated IPv4? */
2210Sstevel@tonic-gate 		if (i == 6 && best.base == 0 && (best.len == 6 ||
2220Sstevel@tonic-gate 		    (best.len == 7 && words[7] != 0x0001) ||
2230Sstevel@tonic-gate 		    (best.len == 5 && words[5] == 0xffff))) {
2240Sstevel@tonic-gate 			int n;
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate 			if (src[15] || bits == -1 || bits > 120)
2270Sstevel@tonic-gate 				n = 4;
2280Sstevel@tonic-gate 			else if (src[14] || bits > 112)
2290Sstevel@tonic-gate 				n = 3;
2300Sstevel@tonic-gate 			else
2310Sstevel@tonic-gate 				n = 2;
2320Sstevel@tonic-gate 			n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
2330Sstevel@tonic-gate 			if (n == 0) {
2340Sstevel@tonic-gate 				errno = EMSGSIZE;
2350Sstevel@tonic-gate 				return (NULL);
2360Sstevel@tonic-gate 			}
2370Sstevel@tonic-gate 			tp += strlen(tp);
2380Sstevel@tonic-gate 			break;
2390Sstevel@tonic-gate 		}
2400Sstevel@tonic-gate 		tp += SPRINTF((tp, "%x", words[i]));
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	/* Was it a trailing run of 0x00's? */
2440Sstevel@tonic-gate 	if (best.base != -1 && (best.base + best.len) ==
2450Sstevel@tonic-gate 	    (NS_IN6ADDRSZ / NS_INT16SZ))
2460Sstevel@tonic-gate 		*tp++ = ':';
2470Sstevel@tonic-gate 	*tp = '\0';
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate 	if (bits != -1)
2500Sstevel@tonic-gate 		tp += SPRINTF((tp, "/%u", bits));
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	/*
2530Sstevel@tonic-gate 	 * Check for overflow, copy, and we're done.
2540Sstevel@tonic-gate 	 */
2550Sstevel@tonic-gate 	if ((size_t)(tp - tmp) > size) {
2560Sstevel@tonic-gate 		errno = EMSGSIZE;
2570Sstevel@tonic-gate 		return (NULL);
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate 	strcpy(dst, tmp);
2600Sstevel@tonic-gate 	return (dst);
2610Sstevel@tonic-gate }
262*11038SRao.Shoaib@Sun.COM 
263*11038SRao.Shoaib@Sun.COM /*! \file */
264