1240075Sdes/*	$OpenBSD: inet_ntop.c,v 1.8 2008/12/09 19:38:38 otto Exp $	*/
2126274Sdes
398937Sdes/* Copyright (c) 1996 by Internet Software Consortium.
498937Sdes *
598937Sdes * Permission to use, copy, modify, and distribute this software for any
698937Sdes * purpose with or without fee is hereby granted, provided that the above
798937Sdes * copyright notice and this permission notice appear in all copies.
898937Sdes *
998937Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
1098937Sdes * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
1198937Sdes * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
1298937Sdes * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
1398937Sdes * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
1498937Sdes * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
1598937Sdes * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
1698937Sdes * SOFTWARE.
1798937Sdes */
1898937Sdes
19157016Sdes/* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */
20157016Sdes
21106121Sdes#include "includes.h"
2298937Sdes
2398937Sdes#ifndef HAVE_INET_NTOP
2498937Sdes
2598937Sdes#include <sys/param.h>
2698937Sdes#include <sys/types.h>
2798937Sdes#include <sys/socket.h>
2898937Sdes#include <netinet/in.h>
2998937Sdes#include <arpa/inet.h>
3098937Sdes#include <arpa/nameser.h>
3198937Sdes#include <string.h>
3298937Sdes#include <errno.h>
3398937Sdes#include <stdio.h>
3498937Sdes
3598937Sdes#ifndef IN6ADDRSZ
3698937Sdes#define IN6ADDRSZ   16   /* IPv6 T_AAAA */
3798937Sdes#endif
3898937Sdes
3998937Sdes#ifndef INT16SZ
4098937Sdes#define INT16SZ     2    /* for systems without 16-bit ints */
4198937Sdes#endif
4298937Sdes
4398937Sdes/*
4498937Sdes * WARNING: Don't even consider trying to compile this on a system where
4598937Sdes * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
4698937Sdes */
4798937Sdes
48106121Sdesstatic const char *inet_ntop4(const u_char *src, char *dst, size_t size);
49106121Sdesstatic const char *inet_ntop6(const u_char *src, char *dst, size_t size);
5098937Sdes
5198937Sdes/* char *
5298937Sdes * inet_ntop(af, src, dst, size)
5398937Sdes *	convert a network format address to presentation format.
5498937Sdes * return:
5598937Sdes *	pointer to presentation format address (`dst'), or NULL (see errno).
5698937Sdes * author:
5798937Sdes *	Paul Vixie, 1996.
5898937Sdes */
5998937Sdesconst char *
60240075Sdesinet_ntop(int af, const void *src, char *dst, socklen_t size)
6198937Sdes{
6298937Sdes	switch (af) {
6398937Sdes	case AF_INET:
64240075Sdes		return (inet_ntop4(src, dst, (size_t)size));
6598937Sdes	case AF_INET6:
66240075Sdes		return (inet_ntop6(src, dst, (size_t)size));
6798937Sdes	default:
6898937Sdes		errno = EAFNOSUPPORT;
6998937Sdes		return (NULL);
7098937Sdes	}
7198937Sdes	/* NOTREACHED */
7298937Sdes}
7398937Sdes
7498937Sdes/* const char *
7598937Sdes * inet_ntop4(src, dst, size)
7698937Sdes *	format an IPv4 address, more or less like inet_ntoa()
7798937Sdes * return:
7898937Sdes *	`dst' (as a const)
7998937Sdes * notes:
8098937Sdes *	(1) uses no statics
8198937Sdes *	(2) takes a u_char* not an in_addr as input
8298937Sdes * author:
8398937Sdes *	Paul Vixie, 1996.
8498937Sdes */
8598937Sdesstatic const char *
86157016Sdesinet_ntop4(const u_char *src, char *dst, size_t size)
8798937Sdes{
8898937Sdes	static const char fmt[] = "%u.%u.%u.%u";
8998937Sdes	char tmp[sizeof "255.255.255.255"];
90106121Sdes	int l;
9198937Sdes
92106121Sdes	l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]);
93106121Sdes	if (l <= 0 || l >= size) {
9498937Sdes		errno = ENOSPC;
9598937Sdes		return (NULL);
9698937Sdes	}
97106121Sdes	strlcpy(dst, tmp, size);
9898937Sdes	return (dst);
9998937Sdes}
10098937Sdes
10198937Sdes/* const char *
10298937Sdes * inet_ntop6(src, dst, size)
10398937Sdes *	convert IPv6 binary address into presentation (printable) format
10498937Sdes * author:
10598937Sdes *	Paul Vixie, 1996.
10698937Sdes */
10798937Sdesstatic const char *
108157016Sdesinet_ntop6(const u_char *src, char *dst, size_t size)
10998937Sdes{
11098937Sdes	/*
11198937Sdes	 * Note that int32_t and int16_t need only be "at least" large enough
11298937Sdes	 * to contain a value of the specified size.  On some systems, like
11398937Sdes	 * Crays, there is no such thing as an integer variable with 16 bits.
11498937Sdes	 * Keep this in mind if you think this function should have been coded
11598937Sdes	 * to use pointer overlays.  All the world's not a VAX.
11698937Sdes	 */
117106121Sdes	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
118106121Sdes	char *tp, *ep;
11998937Sdes	struct { int base, len; } best, cur;
12098937Sdes	u_int words[IN6ADDRSZ / INT16SZ];
12198937Sdes	int i;
122106121Sdes	int advance;
12398937Sdes
12498937Sdes	/*
12598937Sdes	 * Preprocess:
12698937Sdes	 *	Copy the input (bytewise) array into a wordwise array.
12798937Sdes	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
12898937Sdes	 */
12998937Sdes	memset(words, '\0', sizeof words);
13098937Sdes	for (i = 0; i < IN6ADDRSZ; i++)
13198937Sdes		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
13298937Sdes	best.base = -1;
13398937Sdes	cur.base = -1;
13498937Sdes	for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
13598937Sdes		if (words[i] == 0) {
13698937Sdes			if (cur.base == -1)
13798937Sdes				cur.base = i, cur.len = 1;
13898937Sdes			else
13998937Sdes				cur.len++;
14098937Sdes		} else {
14198937Sdes			if (cur.base != -1) {
14298937Sdes				if (best.base == -1 || cur.len > best.len)
14398937Sdes					best = cur;
14498937Sdes				cur.base = -1;
14598937Sdes			}
14698937Sdes		}
14798937Sdes	}
14898937Sdes	if (cur.base != -1) {
14998937Sdes		if (best.base == -1 || cur.len > best.len)
15098937Sdes			best = cur;
15198937Sdes	}
15298937Sdes	if (best.base != -1 && best.len < 2)
15398937Sdes		best.base = -1;
15498937Sdes
15598937Sdes	/*
15698937Sdes	 * Format the result.
15798937Sdes	 */
15898937Sdes	tp = tmp;
159106121Sdes	ep = tmp + sizeof(tmp);
160106121Sdes	for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) {
16198937Sdes		/* Are we inside the best run of 0x00's? */
16298937Sdes		if (best.base != -1 && i >= best.base &&
16398937Sdes		    i < (best.base + best.len)) {
164106121Sdes			if (i == best.base) {
165106121Sdes				if (tp + 1 >= ep)
166106121Sdes					return (NULL);
16798937Sdes				*tp++ = ':';
168106121Sdes			}
16998937Sdes			continue;
17098937Sdes		}
17198937Sdes		/* Are we following an initial run of 0x00s or any real hex? */
172106121Sdes		if (i != 0) {
173106121Sdes			if (tp + 1 >= ep)
174106121Sdes				return (NULL);
17598937Sdes			*tp++ = ':';
176106121Sdes		}
17798937Sdes		/* Is this address an encapsulated IPv4? */
17898937Sdes		if (i == 6 && best.base == 0 &&
17998937Sdes		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
180106121Sdes			if (!inet_ntop4(src+12, tp, (size_t)(ep - tp)))
18198937Sdes				return (NULL);
18298937Sdes			tp += strlen(tp);
18398937Sdes			break;
18498937Sdes		}
185106121Sdes		advance = snprintf(tp, ep - tp, "%x", words[i]);
186106121Sdes		if (advance <= 0 || advance >= ep - tp)
187106121Sdes			return (NULL);
188106121Sdes		tp += advance;
18998937Sdes	}
19098937Sdes	/* Was it a trailing run of 0x00's? */
191106121Sdes	if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) {
192106121Sdes		if (tp + 1 >= ep)
193106121Sdes			return (NULL);
19498937Sdes		*tp++ = ':';
195106121Sdes	}
196106121Sdes	if (tp + 1 >= ep)
197106121Sdes		return (NULL);
19898937Sdes	*tp++ = '\0';
19998937Sdes
20098937Sdes	/*
20198937Sdes	 * Check for overflow, copy, and we're done.
20298937Sdes	 */
20398937Sdes	if ((size_t)(tp - tmp) > size) {
20498937Sdes		errno = ENOSPC;
20598937Sdes		return (NULL);
20698937Sdes	}
207106121Sdes	strlcpy(dst, tmp, size);
20898937Sdes	return (dst);
20998937Sdes}
21098937Sdes
21198937Sdes#endif /* !HAVE_INET_NTOP */
212