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