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