xref: /netbsd-src/external/bsd/libbind/dist/inet/inet_ntop.c (revision 5bbd2a12505d72a8177929a37b5cee489d0a1cfd)
1*5bbd2a12Schristos /*	$NetBSD: inet_ntop.c,v 1.1.1.2 2012/09/09 16:07:50 christos Exp $	*/
2b5677b36Schristos 
3b5677b36Schristos /*
4b5677b36Schristos  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5b5677b36Schristos  * Copyright (c) 1996-1999 by Internet Software Consortium.
6b5677b36Schristos  *
7b5677b36Schristos  * Permission to use, copy, modify, and distribute this software for any
8b5677b36Schristos  * purpose with or without fee is hereby granted, provided that the above
9b5677b36Schristos  * copyright notice and this permission notice appear in all copies.
10b5677b36Schristos  *
11b5677b36Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12b5677b36Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13b5677b36Schristos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14b5677b36Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15b5677b36Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16b5677b36Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17b5677b36Schristos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b5677b36Schristos  */
19b5677b36Schristos 
20b5677b36Schristos #if defined(LIBC_SCCS) && !defined(lint)
21b5677b36Schristos static const char rcsid[] = "Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp ";
22b5677b36Schristos #endif /* LIBC_SCCS and not lint */
23b5677b36Schristos 
24b5677b36Schristos #include "port_before.h"
25b5677b36Schristos 
26b5677b36Schristos #include <sys/param.h>
27b5677b36Schristos #include <sys/types.h>
28b5677b36Schristos #include <sys/socket.h>
29b5677b36Schristos 
30b5677b36Schristos #include <netinet/in.h>
31b5677b36Schristos #include <arpa/inet.h>
32b5677b36Schristos #include <arpa/nameser.h>
33b5677b36Schristos 
34b5677b36Schristos #include <errno.h>
35b5677b36Schristos #include <stdio.h>
36b5677b36Schristos #include <string.h>
37b5677b36Schristos 
38b5677b36Schristos #include "port_after.h"
39b5677b36Schristos 
40b5677b36Schristos #ifdef SPRINTF_CHAR
41b5677b36Schristos # define SPRINTF(x) strlen(sprintf/**/x)
42b5677b36Schristos #else
43b5677b36Schristos # define SPRINTF(x) ((size_t)sprintf x)
44b5677b36Schristos #endif
45b5677b36Schristos 
46b5677b36Schristos /*%
47b5677b36Schristos  * WARNING: Don't even consider trying to compile this on a system where
48b5677b36Schristos  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
49b5677b36Schristos  */
50b5677b36Schristos 
51b5677b36Schristos static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size));
52b5677b36Schristos static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
53b5677b36Schristos 
54b5677b36Schristos /* char *
55b5677b36Schristos  * inet_ntop(af, src, dst, size)
56b5677b36Schristos  *	convert a network format address to presentation format.
57b5677b36Schristos  * return:
58b5677b36Schristos  *	pointer to presentation format address (`dst'), or NULL (see errno).
59b5677b36Schristos  * author:
60b5677b36Schristos  *	Paul Vixie, 1996.
61b5677b36Schristos  */
62b5677b36Schristos const char *
inet_ntop(af,src,dst,size)63b5677b36Schristos inet_ntop(af, src, dst, size)
64b5677b36Schristos 	int af;
65b5677b36Schristos 	const void *src;
66b5677b36Schristos 	char *dst;
67b5677b36Schristos 	size_t size;
68b5677b36Schristos {
69b5677b36Schristos 	switch (af) {
70b5677b36Schristos 	case AF_INET:
71b5677b36Schristos 		return (inet_ntop4(src, dst, size));
72b5677b36Schristos 	case AF_INET6:
73b5677b36Schristos 		return (inet_ntop6(src, dst, size));
74b5677b36Schristos 	default:
75b5677b36Schristos 		errno = EAFNOSUPPORT;
76b5677b36Schristos 		return (NULL);
77b5677b36Schristos 	}
78b5677b36Schristos 	/* NOTREACHED */
79b5677b36Schristos }
80b5677b36Schristos 
81b5677b36Schristos /* const char *
82b5677b36Schristos  * inet_ntop4(src, dst, size)
83b5677b36Schristos  *	format an IPv4 address
84b5677b36Schristos  * return:
85b5677b36Schristos  *	`dst' (as a const)
86b5677b36Schristos  * notes:
87b5677b36Schristos  *	(1) uses no statics
88b5677b36Schristos  *	(2) takes a u_char* not an in_addr as input
89b5677b36Schristos  * author:
90b5677b36Schristos  *	Paul Vixie, 1996.
91b5677b36Schristos  */
92b5677b36Schristos static const char *
inet_ntop4(src,dst,size)93b5677b36Schristos inet_ntop4(src, dst, size)
94b5677b36Schristos 	const u_char *src;
95b5677b36Schristos 	char *dst;
96b5677b36Schristos 	size_t size;
97b5677b36Schristos {
98b5677b36Schristos 	static const char fmt[] = "%u.%u.%u.%u";
99b5677b36Schristos 	char tmp[sizeof "255.255.255.255"];
100b5677b36Schristos 
101b5677b36Schristos 	if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
102b5677b36Schristos 		errno = ENOSPC;
103b5677b36Schristos 		return (NULL);
104b5677b36Schristos 	}
105b5677b36Schristos 	strcpy(dst, tmp);
106b5677b36Schristos 	return (dst);
107b5677b36Schristos }
108b5677b36Schristos 
109b5677b36Schristos /* const char *
110b5677b36Schristos  * inet_ntop6(src, dst, size)
111b5677b36Schristos  *	convert IPv6 binary address into presentation (printable) format
112b5677b36Schristos  * author:
113b5677b36Schristos  *	Paul Vixie, 1996.
114b5677b36Schristos  */
115b5677b36Schristos static const char *
inet_ntop6(src,dst,size)116b5677b36Schristos inet_ntop6(src, dst, size)
117b5677b36Schristos 	const u_char *src;
118b5677b36Schristos 	char *dst;
119b5677b36Schristos 	size_t size;
120b5677b36Schristos {
121b5677b36Schristos 	/*
122b5677b36Schristos 	 * Note that int32_t and int16_t need only be "at least" large enough
123b5677b36Schristos 	 * to contain a value of the specified size.  On some systems, like
124b5677b36Schristos 	 * Crays, there is no such thing as an integer variable with 16 bits.
125b5677b36Schristos 	 * Keep this in mind if you think this function should have been coded
126b5677b36Schristos 	 * to use pointer overlays.  All the world's not a VAX.
127b5677b36Schristos 	 */
128b5677b36Schristos 	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
129b5677b36Schristos 	struct { int base, len; } best, cur;
130b5677b36Schristos 	u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
131b5677b36Schristos 	int i;
132b5677b36Schristos 
133b5677b36Schristos 	/*
134b5677b36Schristos 	 * Preprocess:
135b5677b36Schristos 	 *	Copy the input (bytewise) array into a wordwise array.
136b5677b36Schristos 	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
137b5677b36Schristos 	 */
138b5677b36Schristos 	memset(words, '\0', sizeof words);
139b5677b36Schristos 	for (i = 0; i < NS_IN6ADDRSZ; i++)
140b5677b36Schristos 		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
141b5677b36Schristos 	best.base = -1;
142b5677b36Schristos 	best.len = 0;
143b5677b36Schristos 	cur.base = -1;
144b5677b36Schristos 	cur.len = 0;
145b5677b36Schristos 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
146b5677b36Schristos 		if (words[i] == 0) {
147b5677b36Schristos 			if (cur.base == -1)
148b5677b36Schristos 				cur.base = i, cur.len = 1;
149b5677b36Schristos 			else
150b5677b36Schristos 				cur.len++;
151b5677b36Schristos 		} else {
152b5677b36Schristos 			if (cur.base != -1) {
153b5677b36Schristos 				if (best.base == -1 || cur.len > best.len)
154b5677b36Schristos 					best = cur;
155b5677b36Schristos 				cur.base = -1;
156b5677b36Schristos 			}
157b5677b36Schristos 		}
158b5677b36Schristos 	}
159b5677b36Schristos 	if (cur.base != -1) {
160b5677b36Schristos 		if (best.base == -1 || cur.len > best.len)
161b5677b36Schristos 			best = cur;
162b5677b36Schristos 	}
163b5677b36Schristos 	if (best.base != -1 && best.len < 2)
164b5677b36Schristos 		best.base = -1;
165b5677b36Schristos 
166b5677b36Schristos 	/*
167b5677b36Schristos 	 * Format the result.
168b5677b36Schristos 	 */
169b5677b36Schristos 	tp = tmp;
170b5677b36Schristos 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
171b5677b36Schristos 		/* Are we inside the best run of 0x00's? */
172b5677b36Schristos 		if (best.base != -1 && i >= best.base &&
173b5677b36Schristos 		    i < (best.base + best.len)) {
174b5677b36Schristos 			if (i == best.base)
175b5677b36Schristos 				*tp++ = ':';
176b5677b36Schristos 			continue;
177b5677b36Schristos 		}
178b5677b36Schristos 		/* Are we following an initial run of 0x00s or any real hex? */
179b5677b36Schristos 		if (i != 0)
180b5677b36Schristos 			*tp++ = ':';
181b5677b36Schristos 		/* Is this address an encapsulated IPv4? */
182b5677b36Schristos 		if (i == 6 && best.base == 0 && (best.len == 6 ||
183b5677b36Schristos 		    (best.len == 7 && words[7] != 0x0001) ||
184b5677b36Schristos 		    (best.len == 5 && words[5] == 0xffff))) {
185b5677b36Schristos 			if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
186b5677b36Schristos 				return (NULL);
187b5677b36Schristos 			tp += strlen(tp);
188b5677b36Schristos 			break;
189b5677b36Schristos 		}
190b5677b36Schristos 		tp += SPRINTF((tp, "%x", words[i]));
191b5677b36Schristos 	}
192b5677b36Schristos 	/* Was it a trailing run of 0x00's? */
193b5677b36Schristos 	if (best.base != -1 && (best.base + best.len) ==
194b5677b36Schristos 	    (NS_IN6ADDRSZ / NS_INT16SZ))
195b5677b36Schristos 		*tp++ = ':';
196b5677b36Schristos 	*tp++ = '\0';
197b5677b36Schristos 
198b5677b36Schristos 	/*
199b5677b36Schristos 	 * Check for overflow, copy, and we're done.
200b5677b36Schristos 	 */
201b5677b36Schristos 	if ((size_t)(tp - tmp) > size) {
202b5677b36Schristos 		errno = ENOSPC;
203b5677b36Schristos 		return (NULL);
204b5677b36Schristos 	}
205b5677b36Schristos 	strcpy(dst, tmp);
206b5677b36Schristos 	return (dst);
207b5677b36Schristos }
208b5677b36Schristos 
209b5677b36Schristos /*! \file */
210