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