xref: /minix3/lib/libc/inet/inet_ntop.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: inet_ntop.c,v 1.11 2014/02/10 16:30:54 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*
42fe8fb19SBen Gras  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
52fe8fb19SBen Gras  * Copyright (c) 1996-1999 by Internet Software Consortium.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * Permission to use, copy, modify, and distribute this software for any
82fe8fb19SBen Gras  * purpose with or without fee is hereby granted, provided that the above
92fe8fb19SBen Gras  * copyright notice and this permission notice appear in all copies.
102fe8fb19SBen Gras  *
112fe8fb19SBen Gras  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
122fe8fb19SBen Gras  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
132fe8fb19SBen Gras  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
142fe8fb19SBen Gras  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
152fe8fb19SBen Gras  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
162fe8fb19SBen Gras  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
172fe8fb19SBen Gras  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
182fe8fb19SBen Gras  */
192fe8fb19SBen Gras 
202fe8fb19SBen Gras #include <sys/cdefs.h>
212fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
222fe8fb19SBen Gras #if 0
232fe8fb19SBen Gras static const char rcsid[] = "Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp";
242fe8fb19SBen Gras #else
25*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: inet_ntop.c,v 1.11 2014/02/10 16:30:54 christos Exp $");
262fe8fb19SBen Gras #endif
272fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
282fe8fb19SBen Gras 
292fe8fb19SBen Gras #include "port_before.h"
302fe8fb19SBen Gras 
312fe8fb19SBen Gras #include "namespace.h"
322fe8fb19SBen Gras #include <sys/param.h>
332fe8fb19SBen Gras #include <sys/types.h>
342fe8fb19SBen Gras #include <sys/socket.h>
352fe8fb19SBen Gras 
362fe8fb19SBen Gras #include <netinet/in.h>
372fe8fb19SBen Gras #include <arpa/inet.h>
382fe8fb19SBen Gras #include <arpa/nameser.h>
392fe8fb19SBen Gras 
402fe8fb19SBen Gras #include <assert.h>
412fe8fb19SBen Gras #include <errno.h>
422fe8fb19SBen Gras #include <stdio.h>
432fe8fb19SBen Gras #include <stdlib.h>
442fe8fb19SBen Gras #include <string.h>
452fe8fb19SBen Gras 
462fe8fb19SBen Gras #include "port_after.h"
472fe8fb19SBen Gras 
482fe8fb19SBen Gras #ifdef __weak_alias
492fe8fb19SBen Gras __weak_alias(inet_ntop,_inet_ntop)
502fe8fb19SBen Gras #endif
512fe8fb19SBen Gras 
522fe8fb19SBen Gras /*%
532fe8fb19SBen Gras  * WARNING: Don't even consider trying to compile this on a system where
542fe8fb19SBen Gras  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
552fe8fb19SBen Gras  */
562fe8fb19SBen Gras 
572fe8fb19SBen Gras static const char *inet_ntop4(const u_char *src, char *dst, socklen_t size);
582fe8fb19SBen Gras static const char *inet_ntop6(const u_char *src, char *dst, socklen_t size);
592fe8fb19SBen Gras 
602fe8fb19SBen Gras /* char *
612fe8fb19SBen Gras  * inet_ntop(af, src, dst, size)
622fe8fb19SBen Gras  *	convert a network format address to presentation format.
632fe8fb19SBen Gras  * return:
642fe8fb19SBen Gras  *	pointer to presentation format address (`dst'), or NULL (see errno).
652fe8fb19SBen Gras  * author:
662fe8fb19SBen Gras  *	Paul Vixie, 1996.
672fe8fb19SBen Gras  */
682fe8fb19SBen Gras const char *
inet_ntop(int af,const void * src,char * dst,socklen_t size)69f14fb602SLionel Sambuc inet_ntop(int af, const void *src, char *dst, socklen_t size)
702fe8fb19SBen Gras {
712fe8fb19SBen Gras 
722fe8fb19SBen Gras 	_DIAGASSERT(src != NULL);
732fe8fb19SBen Gras 	_DIAGASSERT(dst != NULL);
742fe8fb19SBen Gras 
752fe8fb19SBen Gras 	switch (af) {
762fe8fb19SBen Gras 	case AF_INET:
77*0a6a1f1dSLionel Sambuc 		return inet_ntop4(src, dst, size);
782fe8fb19SBen Gras 	case AF_INET6:
79*0a6a1f1dSLionel Sambuc 		return inet_ntop6(src, dst, size);
802fe8fb19SBen Gras 	default:
812fe8fb19SBen Gras 		errno = EAFNOSUPPORT;
82*0a6a1f1dSLionel Sambuc 		return NULL;
832fe8fb19SBen Gras 	}
842fe8fb19SBen Gras 	/* NOTREACHED */
852fe8fb19SBen Gras }
862fe8fb19SBen Gras 
872fe8fb19SBen Gras /* const char *
882fe8fb19SBen Gras  * inet_ntop4(src, dst, size)
892fe8fb19SBen Gras  *	format an IPv4 address, more or less like inet_ntoa()
902fe8fb19SBen Gras  * return:
912fe8fb19SBen Gras  *	`dst' (as a const)
922fe8fb19SBen Gras  * notes:
932fe8fb19SBen Gras  *	(1) uses no statics
942fe8fb19SBen Gras  *	(2) takes a u_char* not an in_addr as input
952fe8fb19SBen Gras  * author:
962fe8fb19SBen Gras  *	Paul Vixie, 1996.
972fe8fb19SBen Gras  */
982fe8fb19SBen Gras static const char *
inet_ntop4(const u_char * src,char * dst,socklen_t size)99f14fb602SLionel Sambuc inet_ntop4(const u_char *src, char *dst, socklen_t size)
1002fe8fb19SBen Gras {
1012fe8fb19SBen Gras 	char tmp[sizeof "255.255.255.255"];
1022fe8fb19SBen Gras 	int l;
1032fe8fb19SBen Gras 
1042fe8fb19SBen Gras 	_DIAGASSERT(src != NULL);
1052fe8fb19SBen Gras 	_DIAGASSERT(dst != NULL);
1062fe8fb19SBen Gras 
1072fe8fb19SBen Gras 	l = snprintf(tmp, sizeof(tmp), "%u.%u.%u.%u",
1082fe8fb19SBen Gras 	    src[0], src[1], src[2], src[3]);
109*0a6a1f1dSLionel Sambuc 	if (l <= 0 || (socklen_t) l >= size)
110*0a6a1f1dSLionel Sambuc 		return NULL;
1112fe8fb19SBen Gras 	strlcpy(dst, tmp, size);
112*0a6a1f1dSLionel Sambuc 	return dst;
1132fe8fb19SBen Gras }
1142fe8fb19SBen Gras 
1152fe8fb19SBen Gras /* const char *
1162fe8fb19SBen Gras  * inet_ntop6(src, dst, size)
1172fe8fb19SBen Gras  *	convert IPv6 binary address into presentation (printable) format
1182fe8fb19SBen Gras  * author:
1192fe8fb19SBen Gras  *	Paul Vixie, 1996.
1202fe8fb19SBen Gras  */
1212fe8fb19SBen Gras static const char *
inet_ntop6(const u_char * src,char * dst,socklen_t size)122f14fb602SLionel Sambuc inet_ntop6(const u_char *src, char *dst, socklen_t size)
1232fe8fb19SBen Gras {
1242fe8fb19SBen Gras 	/*
1252fe8fb19SBen Gras 	 * Note that int32_t and int16_t need only be "at least" large enough
1262fe8fb19SBen Gras 	 * to contain a value of the specified size.  On some systems, like
1272fe8fb19SBen Gras 	 * Crays, there is no such thing as an integer variable with 16 bits.
1282fe8fb19SBen Gras 	 * Keep this in mind if you think this function should have been coded
1292fe8fb19SBen Gras 	 * to use pointer overlays.  All the world's not a VAX.
1302fe8fb19SBen Gras 	 */
1312fe8fb19SBen Gras 	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
1322fe8fb19SBen Gras 	char *tp, *ep;
1332fe8fb19SBen Gras 	struct { int base, len; } best, cur;
1342fe8fb19SBen Gras 	u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
1352fe8fb19SBen Gras 	int i;
1362fe8fb19SBen Gras 	int advance;
1372fe8fb19SBen Gras 
1382fe8fb19SBen Gras 	_DIAGASSERT(src != NULL);
1392fe8fb19SBen Gras 	_DIAGASSERT(dst != NULL);
1402fe8fb19SBen Gras 
1412fe8fb19SBen Gras 	/*
1422fe8fb19SBen Gras 	 * Preprocess:
1432fe8fb19SBen Gras 	 *	Copy the input (bytewise) array into a wordwise array.
1442fe8fb19SBen Gras 	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
1452fe8fb19SBen Gras 	 */
1462fe8fb19SBen Gras 	memset(words, '\0', sizeof words);
1472fe8fb19SBen Gras 	for (i = 0; i < NS_IN6ADDRSZ; i++)
1482fe8fb19SBen Gras 		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
1492fe8fb19SBen Gras 	best.base = -1;
1502fe8fb19SBen Gras 	best.len = 0;
1512fe8fb19SBen Gras 	cur.base = -1;
1522fe8fb19SBen Gras 	cur.len = 0;
1532fe8fb19SBen Gras 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
1542fe8fb19SBen Gras 		if (words[i] == 0) {
1552fe8fb19SBen Gras 			if (cur.base == -1)
1562fe8fb19SBen Gras 				cur.base = i, cur.len = 1;
1572fe8fb19SBen Gras 			else
1582fe8fb19SBen Gras 				cur.len++;
1592fe8fb19SBen Gras 		} else {
1602fe8fb19SBen Gras 			if (cur.base != -1) {
1612fe8fb19SBen Gras 				if (best.base == -1 || cur.len > best.len)
1622fe8fb19SBen Gras 					best = cur;
1632fe8fb19SBen Gras 				cur.base = -1;
1642fe8fb19SBen Gras 			}
1652fe8fb19SBen Gras 		}
1662fe8fb19SBen Gras 	}
1672fe8fb19SBen Gras 	if (cur.base != -1) {
1682fe8fb19SBen Gras 		if (best.base == -1 || cur.len > best.len)
1692fe8fb19SBen Gras 			best = cur;
1702fe8fb19SBen Gras 	}
1712fe8fb19SBen Gras 	if (best.base != -1 && best.len < 2)
1722fe8fb19SBen Gras 		best.base = -1;
1732fe8fb19SBen Gras 
1742fe8fb19SBen Gras 	/*
1752fe8fb19SBen Gras 	 * Format the result.
1762fe8fb19SBen Gras 	 */
1772fe8fb19SBen Gras 	tp = tmp;
1782fe8fb19SBen Gras 	ep = tmp + sizeof(tmp);
1792fe8fb19SBen Gras 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
1802fe8fb19SBen Gras 		/* Are we inside the best run of 0x00's? */
1812fe8fb19SBen Gras 		if (best.base != -1 && i >= best.base &&
1822fe8fb19SBen Gras 		    i < (best.base + best.len)) {
1832fe8fb19SBen Gras 			if (i == best.base)
1842fe8fb19SBen Gras 				*tp++ = ':';
1852fe8fb19SBen Gras 			continue;
1862fe8fb19SBen Gras 		}
1872fe8fb19SBen Gras 		/* Are we following an initial run of 0x00s or any real hex? */
1882fe8fb19SBen Gras 		if (i != 0) {
1892fe8fb19SBen Gras 			if (tp + 1 >= ep)
190*0a6a1f1dSLionel Sambuc 				goto out;
1912fe8fb19SBen Gras 			*tp++ = ':';
1922fe8fb19SBen Gras 		}
1932fe8fb19SBen Gras 		/* Is this address an encapsulated IPv4? */
1942fe8fb19SBen Gras 		if (i == 6 && best.base == 0 &&
1952fe8fb19SBen Gras 		    (best.len == 6 ||
1962fe8fb19SBen Gras 		    (best.len == 7 && words[7] != 0x0001) ||
1972fe8fb19SBen Gras 		    (best.len == 5 && words[5] == 0xffff))) {
1982fe8fb19SBen Gras 			if (!inet_ntop4(src + 12, tp, (socklen_t)(ep - tp)))
199*0a6a1f1dSLionel Sambuc 				goto out;
2002fe8fb19SBen Gras 			tp += strlen(tp);
2012fe8fb19SBen Gras 			break;
2022fe8fb19SBen Gras 		}
2032fe8fb19SBen Gras 		advance = snprintf(tp, (size_t)(ep - tp), "%x", words[i]);
2042fe8fb19SBen Gras 		if (advance <= 0 || advance >= ep - tp)
205*0a6a1f1dSLionel Sambuc 			goto out;
2062fe8fb19SBen Gras 		tp += advance;
2072fe8fb19SBen Gras 	}
2082fe8fb19SBen Gras 	/* Was it a trailing run of 0x00's? */
2092fe8fb19SBen Gras 	if (best.base != -1 && (best.base + best.len) ==
2102fe8fb19SBen Gras 	    (NS_IN6ADDRSZ / NS_INT16SZ)) {
2112fe8fb19SBen Gras 		if (tp + 1 >= ep)
212*0a6a1f1dSLionel Sambuc 			goto out;
2132fe8fb19SBen Gras 		*tp++ = ':';
2142fe8fb19SBen Gras 	}
2152fe8fb19SBen Gras 	if (tp + 1 >= ep)
216*0a6a1f1dSLionel Sambuc 		goto out;
2172fe8fb19SBen Gras 	*tp++ = '\0';
2182fe8fb19SBen Gras 
2192fe8fb19SBen Gras 	/*
2202fe8fb19SBen Gras 	 * Check for overflow, copy, and we're done.
2212fe8fb19SBen Gras 	 */
222*0a6a1f1dSLionel Sambuc 	if ((size_t)(tp - tmp) > size)
223*0a6a1f1dSLionel Sambuc 		goto out;
2242fe8fb19SBen Gras 	strlcpy(dst, tmp, size);
225*0a6a1f1dSLionel Sambuc 	return dst;
226*0a6a1f1dSLionel Sambuc out:
227*0a6a1f1dSLionel Sambuc 	errno = ENOSPC;
228*0a6a1f1dSLionel Sambuc 	return NULL;
2292fe8fb19SBen Gras }
2302fe8fb19SBen Gras 
2312fe8fb19SBen Gras /*! \file */
232