]> git.saurik.com Git - apple/libc.git/blob - net/inet_ntop.c
a5ad5c60f7c6f453c2f619bfbb2f7a9a842ce752
[apple/libc.git] / net / inet_ntop.c
1 /*
2 * Copyright (c) 2003,2005,2006,2011,2012 Apple, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <sys/types.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <stdio.h>
28 #include <stdint.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/socket.h>
32
33 #define MAX_V4_ADDR_LEN 16
34 #define MAX_V6_ADDR_LEN 64
35
36 static const char *hexchars = "0123456789abcdef";
37
38 const char * inet_ntop6(const struct in6_addr *addr, char *dst, socklen_t size);
39 const char * inet_ntop4(const struct in_addr *addr, char *dst, socklen_t size);
40
41 const char *
42 inet_ntop(int af, const void *addr, char *buf, socklen_t len)
43 {
44 if (af == AF_INET6) return inet_ntop6(addr, buf, len);
45 if (af == AF_INET) return inet_ntop4(addr, buf, len);
46
47 errno = EAFNOSUPPORT;
48 return NULL;
49 }
50
51 const char *
52 inet_ntop6(const struct in6_addr *addr, char *dst, socklen_t size)
53 {
54 char hexa[8][5], tmp[MAX_V6_ADDR_LEN];
55 int zr[8];
56 socklen_t len;
57 int32_t i, j, k, skip;
58 uint8_t x8, hx8;
59 uint16_t x16;
60 struct in_addr a4;
61
62 if (addr == NULL)
63 {
64 errno = EAFNOSUPPORT;
65 return NULL;
66 }
67
68 if (dst == NULL)
69 {
70 errno = ENOSPC;
71 return NULL;
72 }
73
74 memset(tmp, 0, MAX_V6_ADDR_LEN);
75
76 /* check for mapped or compat addresses */
77 i = IN6_IS_ADDR_V4MAPPED(addr);
78 j = IN6_IS_ADDR_V4COMPAT(addr);
79 if ((i != 0) || (j != 0))
80 {
81 const char *prefix;
82 socklen_t prefix_len;
83 if (i != 0) {
84 prefix = "::ffff:";
85 prefix_len = 7;
86 } else {
87 prefix = "::";
88 prefix_len = 2;
89 }
90 a4.s_addr = addr->__u6_addr.__u6_addr32[3];
91 inet_ntop4(&a4, tmp, sizeof(tmp));
92 len = strlen(tmp) + 1;
93 if (prefix_len + len > size)
94 {
95 errno = ENOSPC;
96 return NULL;
97 }
98
99 memcpy(dst, prefix, prefix_len);
100 memcpy(dst + prefix_len, tmp, len);
101 return dst;
102 }
103
104 k = 0;
105 for (i = 0; i < 16; i += 2)
106 {
107 j = 0;
108 skip = 1;
109
110 memset(hexa[k], 0, 5);
111
112 x8 = addr->__u6_addr.__u6_addr8[i];
113
114 hx8 = x8 >> 4;
115 if (hx8 != 0)
116 {
117 skip = 0;
118 hexa[k][j++] = hexchars[hx8];
119 }
120
121 hx8 = x8 & 0x0f;
122 if ((skip == 0) || ((skip == 1) && (hx8 != 0)))
123 {
124 skip = 0;
125 hexa[k][j++] = hexchars[hx8];
126 }
127
128 x8 = addr->__u6_addr.__u6_addr8[i + 1];
129
130 hx8 = x8 >> 4;
131 if ((skip == 0) || ((skip == 1) && (hx8 != 0)))
132 {
133 hexa[k][j++] = hexchars[hx8];
134 }
135
136 hx8 = x8 & 0x0f;
137 hexa[k][j++] = hexchars[hx8];
138
139 k++;
140 }
141
142 /* find runs of zeros for :: convention */
143 j = 0;
144 for (i = 7; i >= 0; i--)
145 {
146 zr[i] = j;
147 x16 = addr->__u6_addr.__u6_addr16[i];
148 if (x16 == 0) j++;
149 else j = 0;
150 zr[i] = j;
151 }
152
153 /* find longest run of zeros */
154 k = -1;
155 j = 0;
156 for(i = 0; i < 8; i++)
157 {
158 if (zr[i] > j)
159 {
160 k = i;
161 j = zr[i];
162 }
163 }
164
165 for(i = 0; i < 8; i++)
166 {
167 if (i != k) zr[i] = 0;
168 }
169
170 len = 0;
171 for (i = 0; i < 8; i++)
172 {
173 if (zr[i] != 0)
174 {
175 /* check for leading zero */
176 if (i == 0) tmp[len++] = ':';
177 tmp[len++] = ':';
178 i += (zr[i] - 1);
179 continue;
180 }
181 for (j = 0; hexa[i][j] != '\0'; j++) tmp[len++] = hexa[i][j];
182 if (i != 7) tmp[len++] = ':';
183 }
184
185 /* trailing NULL */
186 len++;
187
188 if (len > size)
189 {
190 errno = ENOSPC;
191 return NULL;
192 }
193
194 memcpy(dst, tmp, len);
195 return dst;
196 }
197
198 const char *
199 inet_ntop4(const struct in_addr *addr, char *dst, socklen_t size)
200 {
201 char tmp[MAX_V4_ADDR_LEN], *p;
202 const u_int8_t *ap = (u_int8_t *)&addr->s_addr;
203 int i, ql, len;
204
205 if (addr == NULL)
206 {
207 errno = EAFNOSUPPORT;
208 return NULL;
209 }
210
211 if (dst == NULL)
212 {
213 errno = ENOSPC;
214 return NULL;
215 }
216
217 memset(tmp, 0, MAX_V4_ADDR_LEN);
218
219 /* 3 dots, trailing nul */
220 len = 4;
221
222 p = tmp;
223
224 for (i = 0; i < 4; i++, ap++)
225 {
226 snprintf(p, 4, "%d", *ap);
227 ql = strlen(p);
228 len += ql;
229 p += ql;
230 if (i < 3) *p++ = '.';
231 }
232
233 if (len > size)
234 {
235 errno = ENOSPC;
236 return NULL;
237 }
238
239 memcpy(dst, tmp, len);
240 return dst;
241 }