2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley/*
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 1996-2001, 2003-2005, 2007, 2016 Internet Systems Consortium, Inc. ("ISC")
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * This Source Code Form is subject to the terms of the Mozilla Public
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * License, v. 2.0. If a copy of the MPL was not distributed with this
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * file, You can obtain one at http://mozilla.org/MPL/2.0/.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein/*! \file lwinetntop.c
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#if defined(LIBC_SCCS) && !defined(lint)
ed019cabc1cc75d4412010c331876e4ae5080a4dDavid Lawrencestatic char rcsid[] =
70e5a7403f0e0a3bd292b8287c5fed5772c15270Automatic Updater "$Id: lwinetntop.c,v 1.18 2007/06/19 23:47:22 tbox Exp $";
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#endif /* LIBC_SCCS and not lint */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#include <config.h>
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#include <errno.h>
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#include <stdio.h>
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#include <string.h>
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#include <lwres/net.h>
16a68807e13caea3183a41a5292f1b3f48b81a26Mark Andrews#include "print_p.h"
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#define NS_INT16SZ 2
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#define NS_IN6ADDRSZ 16
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley/*
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * WARNING: Don't even consider trying to compile this on a system where
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halleystatic const char *inet_ntop4(const unsigned char *src, char *dst,
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley size_t size);
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#ifdef AF_INET6
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halleystatic const char *inet_ntop6(const unsigned char *src, char *dst,
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley size_t size);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#endif
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein/*! char *
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * lwres_net_ntop(af, src, dst, size)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * convert a network format address to presentation format.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * return:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * pointer to presentation format address (`dst'), or NULL (see errno).
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * author:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Paul Vixie, 1996.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halleyconst char *
ed019cabc1cc75d4412010c331876e4ae5080a4dDavid Lawrencelwres_net_ntop(int af, const void *src, char *dst, size_t size) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley switch (af) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley case AF_INET:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley return (inet_ntop4(src, dst, size));
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#ifdef AF_INET6
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley case AF_INET6:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley return (inet_ntop6(src, dst, size));
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#endif
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley default:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley errno = EAFNOSUPPORT;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley return (NULL);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley /* NOTREACHED */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley}
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein/*! const char *
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * inet_ntop4(src, dst, size)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * format an IPv4 address
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * return:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * `dst' (as a const)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * notes:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * (1) uses no statics
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * (2) takes a unsigned char* not an in_addr as input
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * author:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Paul Vixie, 1996.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halleystatic const char *
ed019cabc1cc75d4412010c331876e4ae5080a4dDavid Lawrenceinet_ntop4(const unsigned char *src, char *dst, size_t size) {
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafsson static const char fmt[] = "%u.%u.%u.%u";
91cd0f93ad34d23e8b09dca337120f64fbe8f0a1Andreas Gustafsson char tmp[sizeof("255.255.255.255")];
806c235ecf533b98d068b3f8df9d7abbe1e30cf9Mark Andrews size_t len;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
806c235ecf533b98d068b3f8df9d7abbe1e30cf9Mark Andrews len = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
806c235ecf533b98d068b3f8df9d7abbe1e30cf9Mark Andrews if (len >= size) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley errno = ENOSPC;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley return (NULL);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley strcpy(dst, tmp);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley return (dst);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley}
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein/*! const char *
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * inet_ntop6(src, dst, size)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * convert IPv6 binary address into presentation (printable) format
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * author:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Paul Vixie, 1996.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#ifdef AF_INET6
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halleystatic const char *
ed019cabc1cc75d4412010c331876e4ae5080a4dDavid Lawrenceinet_ntop6(const unsigned char *src, char *dst, size_t size) {
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein /*!
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Note that int32_t and int16_t need only be "at least" large enough
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * to contain a value of the specified size. On some systems, like
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Crays, there is no such thing as an integer variable with 16 bits.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Keep this in mind if you think this function should have been coded
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * to use pointer overlays. All the world's not a VAX.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
91cd0f93ad34d23e8b09dca337120f64fbe8f0a1Andreas Gustafsson char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")], *tp;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley struct { int base, len; } best, cur;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley int i;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley /*
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Preprocess:
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Copy the input (bytewise) array into a wordwise array.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Find the longest run of 0x00's in src[] for :: shorthanding.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
91cd0f93ad34d23e8b09dca337120f64fbe8f0a1Andreas Gustafsson memset(words, '\0', sizeof(words));
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley for (i = 0; i < NS_IN6ADDRSZ; i++)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley best.base = -1;
c481327e758487ba66e34f6d1e91fec11377a4edMark Andrews best.len = 0;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley cur.base = -1;
c481327e758487ba66e34f6d1e91fec11377a4edMark Andrews cur.len = 0;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (words[i] == 0) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (cur.base == -1)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley cur.base = i, cur.len = 1;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley else
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley cur.len++;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley } else {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (cur.base != -1) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (best.base == -1 || cur.len > best.len)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley best = cur;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley cur.base = -1;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (cur.base != -1) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (best.base == -1 || cur.len > best.len)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley best = cur;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (best.base != -1 && best.len < 2)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley best.base = -1;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley /*
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Format the result.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley tp = tmp;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley /* Are we inside the best run of 0x00's? */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (best.base != -1 && i >= best.base &&
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley i < (best.base + best.len)) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (i == best.base)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley *tp++ = ':';
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley continue;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley /* Are we following an initial run of 0x00s or any real hex? */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (i != 0)
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley *tp++ = ':';
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley /* Is this address an encapsulated IPv4? */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (i == 6 && best.base == 0 &&
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley if (!inet_ntop4(src+12, tp,
91cd0f93ad34d23e8b09dca337120f64fbe8f0a1Andreas Gustafsson sizeof(tmp) - (tp - tmp)))
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley return (NULL);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley tp += strlen(tp);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley break;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
806c235ecf533b98d068b3f8df9d7abbe1e30cf9Mark Andrews tp += sprintf(tp, "%x", words[i]); /* XXX */
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley /* Was it a trailing run of 0x00's? */
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence if (best.base != -1 && (best.base + best.len) ==
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley (NS_IN6ADDRSZ / NS_INT16SZ))
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley *tp++ = ':';
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley *tp++ = '\0';
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley /*
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley * Check for overflow, copy, and we're done.
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley */
b586eb44084ba19b82d26ce20b7d741ac19d5331Andreas Gustafsson if ((size_t)(tp - tmp) > size) {
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley errno = ENOSPC;
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley return (NULL);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley }
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley strcpy(dst, tmp);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley return (dst);
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley}
2ba9ea4e1e5ce8d54a24b66ef69e6cdf96cfb667Bob Halley#endif /* AF_INET6 */