Line data Source code
1 : /* $OpenBSD: inet_ntop.c,v 1.4 2016/09/04 17:05:24 claudio 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/systm.h>
21 : #include <sys/socket.h>
22 :
23 : #include <netinet/in.h>
24 :
25 : #define IN6ADDRSZ 16
26 : #define INT16SZ 2
27 :
28 : /*
29 : * WARNING: Don't even consider trying to compile this on a system where
30 : * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
31 : */
32 :
33 : static const char *inet_ntop4(const u_char *src, char *dst, size_t size);
34 : #ifdef INET6
35 : static const char *inet_ntop6(const u_char *src, char *dst, size_t size);
36 : #endif /* INET6 */
37 :
38 : /* char *
39 : * inet_ntop(af, src, dst, size)
40 : * convert a network format address to presentation format.
41 : * return:
42 : * pointer to presentation format address (`dst'), or NULL (see errno).
43 : * author:
44 : * Paul Vixie, 1996.
45 : */
46 : const char *
47 0 : inet_ntop(int af, const void *src, char *dst, socklen_t size)
48 : {
49 0 : switch (af) {
50 : case AF_INET:
51 0 : return (inet_ntop4(src, dst, (size_t)size));
52 : #ifdef INET6
53 : case AF_INET6:
54 0 : return (inet_ntop6(src, dst, (size_t)size));
55 : #endif /* INET6 */
56 : default:
57 0 : return (NULL);
58 : }
59 : /* NOTREACHED */
60 0 : }
61 :
62 : const char *
63 0 : sockaddr_ntop(struct sockaddr *sa, char *dst, size_t size)
64 : {
65 : u_int8_t l;
66 : size_t n;
67 :
68 0 : if (sa->sa_len < 2)
69 0 : return "bad sa";
70 0 : switch (sa->sa_family) {
71 : case AF_INET:
72 0 : return inet_ntop4((u_char *)&satosin(sa)->sin_addr, dst, size);
73 : #ifdef INET6
74 : case AF_INET6:
75 0 : return inet_ntop6((u_char *)&satosin6(sa)->sin6_addr, dst, size);
76 : #endif
77 : default:
78 0 : n = snprintf(dst, size, "%d ", sa->sa_family);
79 0 : for (l = 0; l < sa->sa_len - offsetof(struct sockaddr, sa_data); l++) {
80 0 : int r = snprintf(dst + n, size - n, "%02x", sa->sa_data[l]);
81 0 : if (r == -1)
82 0 : return "bad sa";
83 0 : n += r;
84 0 : if (n > size)
85 0 : n = size;
86 0 : }
87 0 : return (dst);
88 : }
89 0 : }
90 :
91 : /* const char *
92 : * inet_ntop4(src, dst, size)
93 : * format an IPv4 address, more or less like inet_ntoa()
94 : * return:
95 : * `dst' (as a const)
96 : * notes:
97 : * (1) uses no statics
98 : * (2) takes a u_char* not an in_addr as input
99 : * author:
100 : * Paul Vixie, 1996.
101 : */
102 : static const char *
103 0 : inet_ntop4(const u_char *src, char *dst, size_t size)
104 : {
105 0 : char tmp[sizeof "255.255.255.255"];
106 : int l;
107 :
108 0 : l = snprintf(tmp, sizeof(tmp), "%u.%u.%u.%u",
109 0 : src[0], src[1], src[2], src[3]);
110 0 : if (l <= 0 || l >= size) {
111 0 : return (NULL);
112 : }
113 0 : strlcpy(dst, tmp, size);
114 0 : return (dst);
115 0 : }
116 :
117 : #ifdef INET6
118 : /* const char *
119 : * inet_ntop6(src, dst, size)
120 : * convert IPv6 binary address into presentation (printable) format
121 : * author:
122 : * Paul Vixie, 1996.
123 : */
124 : static const char *
125 0 : inet_ntop6(const u_char *src, char *dst, size_t size)
126 : {
127 : /*
128 : * Note that int32_t and int16_t need only be "at least" large enough
129 : * to contain a value of the specified size. On some systems, like
130 : * Crays, there is no such thing as an integer variable with 16 bits.
131 : * Keep this in mind if you think this function should have been coded
132 : * to use pointer overlays. All the world's not a VAX.
133 : */
134 0 : char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
135 : char *tp, *ep;
136 : struct { int base, len; } best, cur;
137 0 : u_int words[IN6ADDRSZ / INT16SZ];
138 : int i;
139 : int advance;
140 :
141 : /*
142 : * Preprocess:
143 : * Copy the input (bytewise) array into a wordwise array.
144 : * Find the longest run of 0x00's in src[] for :: shorthanding.
145 : */
146 0 : memset(words, '\0', sizeof words);
147 0 : for (i = 0; i < IN6ADDRSZ; i++)
148 0 : words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
149 : best.base = -1;
150 : cur.base = -1;
151 0 : for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
152 0 : if (words[i] == 0) {
153 0 : if (cur.base == -1)
154 0 : cur.base = i, cur.len = 1;
155 : else
156 0 : cur.len++;
157 : } else {
158 0 : if (cur.base != -1) {
159 0 : if (best.base == -1 || cur.len > best.len)
160 0 : best = cur;
161 : cur.base = -1;
162 0 : }
163 : }
164 : }
165 0 : if (cur.base != -1) {
166 0 : if (best.base == -1 || cur.len > best.len)
167 0 : best = cur;
168 : }
169 0 : if (best.base != -1 && best.len < 2)
170 0 : best.base = -1;
171 :
172 : /*
173 : * Format the result.
174 : */
175 0 : tp = tmp;
176 0 : ep = tmp + sizeof(tmp);
177 0 : for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) {
178 : /* Are we inside the best run of 0x00's? */
179 0 : if (best.base != -1 && i >= best.base &&
180 0 : i < (best.base + best.len)) {
181 0 : if (i == best.base) {
182 0 : if (tp + 1 >= ep)
183 0 : return (NULL);
184 0 : *tp++ = ':';
185 0 : }
186 : continue;
187 : }
188 : /* Are we following an initial run of 0x00s or any real hex? */
189 0 : if (i != 0) {
190 0 : if (tp + 1 >= ep)
191 0 : return (NULL);
192 0 : *tp++ = ':';
193 0 : }
194 : /* Is this address an encapsulated IPv4? */
195 0 : if (i == 6 && best.base == 0 &&
196 0 : (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
197 0 : if (!inet_ntop4(src+12, tp, (size_t)(ep - tp)))
198 0 : return (NULL);
199 0 : tp += strlen(tp);
200 0 : break;
201 : }
202 0 : advance = snprintf(tp, ep - tp, "%x", words[i]);
203 0 : if (advance <= 0 || advance >= ep - tp)
204 0 : return (NULL);
205 0 : tp += advance;
206 0 : }
207 : /* Was it a trailing run of 0x00's? */
208 0 : if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) {
209 0 : if (tp + 1 >= ep)
210 0 : return (NULL);
211 0 : *tp++ = ':';
212 0 : }
213 0 : if (tp + 1 >= ep)
214 0 : return (NULL);
215 0 : *tp++ = '\0';
216 :
217 : /*
218 : * Check for overflow, copy, and we're done.
219 : */
220 0 : if ((size_t)(tp - tmp) > size) {
221 0 : return (NULL);
222 : }
223 0 : strlcpy(dst, tmp, size);
224 0 : return (dst);
225 0 : }
226 : #endif /* INET6 */
|