1238104Sdes/* From openssh 4.3p2 compat/inet_ntop.c */
2238104Sdes/* Copyright (c) 1996 by Internet Software Consortium.
3238104Sdes *
4238104Sdes * Permission to use, copy, modify, and distribute this software for any
5238104Sdes * purpose with or without fee is hereby granted, provided that the above
6238104Sdes * copyright notice and this permission notice appear in all copies.
7238104Sdes *
8238104Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9238104Sdes * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10238104Sdes * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11238104Sdes * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12238104Sdes * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13238104Sdes * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14238104Sdes * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15238104Sdes * SOFTWARE.
16238104Sdes */
17238104Sdes
18238104Sdes/* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */
19238104Sdes
20238104Sdes#include <ldns/config.h>
21238104Sdes
22238104Sdes#ifndef HAVE_INET_NTOP
23238104Sdes
24238104Sdes#include <sys/param.h>
25238104Sdes#include <sys/types.h>
26238104Sdes#ifdef HAVE_SYS_SOCKET_H
27238104Sdes#include <sys/socket.h>
28238104Sdes#endif
29238104Sdes#ifdef HAVE_NETINET_IN_H
30238104Sdes#include <netinet/in.h>
31238104Sdes#endif
32238104Sdes#include <string.h>
33238104Sdes#include <errno.h>
34238104Sdes#include <stdio.h>
35238104Sdes
36238104Sdes#ifndef IN6ADDRSZ
37238104Sdes#define IN6ADDRSZ   16   /* IPv6 T_AAAA */
38238104Sdes#endif
39238104Sdes
40238104Sdes#ifndef INT16SZ
41238104Sdes#define INT16SZ     2    /* for systems without 16-bit ints */
42238104Sdes#endif
43238104Sdes
44238104Sdes/*
45238104Sdes * WARNING: Don't even consider trying to compile this on a system where
46238104Sdes * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
47238104Sdes */
48238104Sdes
49238104Sdesstatic const char *inet_ntop4(const u_char *src, char *dst, size_t size);
50238104Sdesstatic const char *inet_ntop6(const u_char *src, char *dst, size_t size);
51238104Sdes
52238104Sdes/* char *
53238104Sdes * inet_ntop(af, src, dst, size)
54238104Sdes *	convert a network format address to presentation format.
55238104Sdes * return:
56238104Sdes *	pointer to presentation format address (`dst'), or NULL (see errno).
57238104Sdes * author:
58238104Sdes *	Paul Vixie, 1996.
59238104Sdes */
60238104Sdesconst char *
61238104Sdesinet_ntop(int af, const void *src, char *dst, size_t size)
62238104Sdes{
63238104Sdes	switch (af) {
64238104Sdes	case AF_INET:
65238104Sdes		return (inet_ntop4(src, dst, size));
66238104Sdes	case AF_INET6:
67238104Sdes		return (inet_ntop6(src, dst, size));
68238104Sdes	default:
69238104Sdes#ifdef EAFNOSUPPORT
70238104Sdes		errno = EAFNOSUPPORT;
71238104Sdes#else
72238104Sdes		errno = ENOSYS;
73238104Sdes#endif
74238104Sdes		return (NULL);
75238104Sdes	}
76238104Sdes	/* NOTREACHED */
77238104Sdes}
78238104Sdes
79238104Sdes/* const char *
80238104Sdes * inet_ntop4(src, dst, size)
81238104Sdes *	format an IPv4 address, more or less like inet_ntoa()
82238104Sdes * return:
83238104Sdes *	`dst' (as a const)
84238104Sdes * notes:
85238104Sdes *	(1) uses no statics
86238104Sdes *	(2) takes a u_char* not an in_addr as input
87238104Sdes * author:
88238104Sdes *	Paul Vixie, 1996.
89238104Sdes */
90238104Sdesstatic const char *
91238104Sdesinet_ntop4(const u_char *src, char *dst, size_t size)
92238104Sdes{
93238104Sdes	static const char fmt[] = "%u.%u.%u.%u";
94238104Sdes	char tmp[sizeof "255.255.255.255"];
95238104Sdes	int l;
96238104Sdes
97238104Sdes	l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]);
98238104Sdes	if (l <= 0 || l >= (int)size) {
99238104Sdes		errno = ENOSPC;
100238104Sdes		return (NULL);
101238104Sdes	}
102238104Sdes	strlcpy(dst, tmp, size);
103238104Sdes	return (dst);
104238104Sdes}
105238104Sdes
106238104Sdes/* const char *
107238104Sdes * inet_ntop6(src, dst, size)
108238104Sdes *	convert IPv6 binary address into presentation (printable) format
109238104Sdes * author:
110238104Sdes *	Paul Vixie, 1996.
111238104Sdes */
112238104Sdesstatic const char *
113238104Sdesinet_ntop6(const u_char *src, char *dst, size_t size)
114238104Sdes{
115238104Sdes	/*
116238104Sdes	 * Note that int32_t and int16_t need only be "at least" large enough
117238104Sdes	 * to contain a value of the specified size.  On some systems, like
118238104Sdes	 * Crays, there is no such thing as an integer variable with 16 bits.
119238104Sdes	 * Keep this in mind if you think this function should have been coded
120238104Sdes	 * to use pointer overlays.  All the world's not a VAX.
121238104Sdes	 */
122238104Sdes	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
123238104Sdes	char *tp, *ep;
124238104Sdes	struct { int base, len; } best, cur;
125238104Sdes	u_int words[IN6ADDRSZ / INT16SZ];
126238104Sdes	int i;
127238104Sdes	int advance;
128238104Sdes
129238104Sdes	/*
130238104Sdes	 * Preprocess:
131238104Sdes	 *	Copy the input (bytewise) array into a wordwise array.
132238104Sdes	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
133238104Sdes	 */
134238104Sdes	memset(words, '\0', sizeof words);
135238104Sdes	for (i = 0; i < IN6ADDRSZ; i++)
136238104Sdes		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
137238104Sdes	best.base = -1;
138238104Sdes	best.len = 0;
139238104Sdes	cur.base = -1;
140238104Sdes	cur.len = 0;
141238104Sdes	for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
142238104Sdes		if (words[i] == 0) {
143238104Sdes			if (cur.base == -1)
144238104Sdes				cur.base = i, cur.len = 1;
145238104Sdes			else
146238104Sdes				cur.len++;
147238104Sdes		} else {
148238104Sdes			if (cur.base != -1) {
149238104Sdes				if (best.base == -1 || cur.len > best.len)
150238104Sdes					best = cur;
151238104Sdes				cur.base = -1;
152238104Sdes			}
153238104Sdes		}
154238104Sdes	}
155238104Sdes	if (cur.base != -1) {
156238104Sdes		if (best.base == -1 || cur.len > best.len)
157238104Sdes			best = cur;
158238104Sdes	}
159238104Sdes	if (best.base != -1 && best.len < 2)
160238104Sdes		best.base = -1;
161238104Sdes
162238104Sdes	/*
163238104Sdes	 * Format the result.
164238104Sdes	 */
165238104Sdes	tp = tmp;
166238104Sdes	ep = tmp + sizeof(tmp);
167238104Sdes	for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) {
168238104Sdes		/* Are we inside the best run of 0x00's? */
169238104Sdes		if (best.base != -1 && i >= best.base &&
170238104Sdes		    i < (best.base + best.len)) {
171238104Sdes			if (i == best.base) {
172238104Sdes				if (tp + 1 >= ep)
173238104Sdes					return (NULL);
174238104Sdes				*tp++ = ':';
175238104Sdes			}
176238104Sdes			continue;
177238104Sdes		}
178238104Sdes		/* Are we following an initial run of 0x00s or any real hex? */
179238104Sdes		if (i != 0) {
180238104Sdes			if (tp + 1 >= ep)
181238104Sdes				return (NULL);
182238104Sdes			*tp++ = ':';
183238104Sdes		}
184238104Sdes		/* Is this address an encapsulated IPv4? */
185238104Sdes		if (i == 6 && best.base == 0 &&
186238104Sdes		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
187238104Sdes			if (!inet_ntop4(src+12, tp, (size_t)(ep - tp)))
188238104Sdes				return (NULL);
189238104Sdes			tp += strlen(tp);
190238104Sdes			break;
191238104Sdes		}
192238104Sdes		advance = snprintf(tp, ep - tp, "%x", words[i]);
193238104Sdes		if (advance <= 0 || advance >= ep - tp)
194238104Sdes			return (NULL);
195238104Sdes		tp += advance;
196238104Sdes	}
197238104Sdes	/* Was it a trailing run of 0x00's? */
198238104Sdes	if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) {
199238104Sdes		if (tp + 1 >= ep)
200238104Sdes			return (NULL);
201238104Sdes		*tp++ = ':';
202238104Sdes	}
203238104Sdes	if (tp + 1 >= ep)
204238104Sdes		return (NULL);
205238104Sdes	*tp++ = '\0';
206238104Sdes
207238104Sdes	/*
208238104Sdes	 * Check for overflow, copy, and we're done.
209238104Sdes	 */
210238104Sdes	if ((size_t)(tp - tmp) > size) {
211238104Sdes		errno = ENOSPC;
212238104Sdes		return (NULL);
213238104Sdes	}
214238104Sdes	strlcpy(dst, tmp, size);
215238104Sdes	return (dst);
216238104Sdes}
217238104Sdes
218238104Sdes#endif /* !HAVE_INET_NTOP */
219