tools/llvm: Do not build with symbols
[minix3.git] / lib / libc / inet / inet_net_pton.c
blob57b978289e8bfcbccbdf32a737181ca39957a58c
1 /*
2 * Copyright (c) 1996,1999 by Internet Software Consortium.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
18 #include <sys/cdefs.h>
19 #if defined(LIBC_SCCS) && !defined(lint)
20 #if 0
21 static const char rcsid[] = "Id: inet_net_pton.c,v 1.4.2.1 2002/08/02 02:17:21 marka Exp ";
22 #else
23 __RCSID("$NetBSD: inet_net_pton.c,v 1.4 2012/03/20 17:08:13 matt Exp $");
24 #endif
25 #endif
27 #include "port_before.h"
29 #include "namespace.h"
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/nameser.h>
34 #include <arpa/inet.h>
36 #include <isc/assertions.h>
37 #include <stddef.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <stdlib.h>
44 #include "port_after.h"
46 #ifdef __weak_alias
47 __weak_alias(inet_net_pton,_inet_net_pton)
48 #endif
50 #ifdef SPRINTF_CHAR
51 # define SPRINTF(x) strlen(sprintf/**/x)
52 #else
53 # define SPRINTF(x) ((size_t)sprintf x)
54 #endif
58 * static int
59 * inet_net_pton_ipv4(src, dst, size)
60 * convert IPv4 network number from presentation to network format.
61 * accepts hex octets, hex strings, decimal octets, and /CIDR.
62 * "size" is in bytes and describes "dst".
63 * return:
64 * number of bits, either imputed classfully or specified with /CIDR,
65 * or -1 if some failure occurred (check errno). ENOENT means it was
66 * not an IPv4 network specification.
67 * note:
68 * network byte order assumed. this means 192.5.5.240/28 has
69 * 0b11110000 in its fourth octet.
70 * author:
71 * Paul Vixie (ISC), June 1996
73 static int
74 inet_net_pton_ipv4(const char *src, u_char *dst, size_t size)
76 static const char xdigits[] = "0123456789abcdef";
77 static const char digits[] = "0123456789";
78 int ch, dirty, bits;
79 ptrdiff_t n, tmp;
80 const u_char *odst = dst;
82 tmp = 0;
83 ch = *src++;
84 if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
85 && isascii((u_char)(src[1]))
86 && isxdigit((u_char)(src[1]))) {
87 /* Hexadecimal: Eat nybble string. */
88 if (size == 0)
89 goto emsgsize;
90 dirty = 0;
91 src++; /* skip x or X. */
92 while ((ch = *src++) != '\0' && isascii((u_char)ch)
93 && isxdigit((u_char)ch)) {
94 if (isupper((u_char)ch))
95 ch = tolower((u_char)ch);
96 n = strchr(xdigits, ch) - xdigits;
97 INSIST(n >= 0 && n <= 15);
98 if (dirty == 0)
99 tmp = n;
100 else
101 tmp = (tmp << 4) | n;
102 if (++dirty == 2) {
103 if (size-- == 0)
104 goto emsgsize;
105 *dst++ = (u_char) tmp;
106 dirty = 0;
109 if (dirty) { /* Odd trailing nybble? */
110 if (size-- == 0)
111 goto emsgsize;
112 *dst++ = (u_char) (tmp << 4);
114 } else if (isascii((u_char)ch) && isdigit((u_char)ch)) {
115 /* Decimal: eat dotted digit string. */
116 for (;;) {
117 tmp = 0;
118 do {
119 n = strchr(digits, ch) - digits;
120 INSIST(n >= 0 && n <= 9);
121 tmp *= 10;
122 tmp += n;
123 if (tmp > 255)
124 goto enoent;
125 } while ((ch = *src++) != '\0' &&
126 isascii((u_char)ch) && isdigit((u_char)ch));
127 if (size-- == 0)
128 goto emsgsize;
129 *dst++ = (u_char) tmp;
130 if (ch == '\0' || ch == '/')
131 break;
132 if (ch != '.')
133 goto enoent;
134 ch = *src++;
135 if (!isascii((u_char)ch) || !isdigit((u_char)ch))
136 goto enoent;
138 } else
139 goto enoent;
141 bits = -1;
142 if (ch == '/' && isascii((u_char)(src[0])) &&
143 isdigit((u_char)(src[0])) && dst > odst) {
144 /* CIDR width specifier. Nothing can follow it. */
145 ch = *src++; /* Skip over the /. */
146 bits = 0;
147 do {
148 n = strchr(digits, ch) - digits;
149 INSIST(n >= 0 && n <= 9);
150 bits *= 10;
151 bits += (int)n;
152 if (bits > 32)
153 goto emsgsize;
154 } while ((ch = *src++) != '\0' && isascii((u_char)ch)
155 && isdigit((u_char)ch));
156 if (ch != '\0')
157 goto enoent;
160 /* Firey death and destruction unless we prefetched EOS. */
161 if (ch != '\0')
162 goto enoent;
164 /* If nothing was written to the destination, we found no address. */
165 if (dst == odst)
166 goto enoent;
167 /* If no CIDR spec was given, infer width from net class. */
168 if (bits == -1) {
169 if (*odst >= 240) /* Class E */
170 bits = 32;
171 else if (*odst >= 224) /* Class D */
172 bits = 4;
173 else if (*odst >= 192) /* Class C */
174 bits = 24;
175 else if (*odst >= 128) /* Class B */
176 bits = 16;
177 else /* Class A */
178 bits = 8;
179 /* If imputed mask is narrower than specified octets, widen. */
180 if (bits >= 8 && bits < ((dst - odst) * 8))
181 bits = (int)(dst - odst) * 8;
183 /* Extend network to cover the actual mask. */
184 while (bits > ((dst - odst) * 8)) {
185 if (size-- == 0)
186 goto emsgsize;
187 *dst++ = '\0';
189 return (bits);
191 enoent:
192 errno = ENOENT;
193 return (-1);
195 emsgsize:
196 errno = EMSGSIZE;
197 return (-1);
200 static int
201 getbits(const char *src, int *bitsp)
203 static const char digits[] = "0123456789";
204 int n;
205 int val;
206 char ch;
208 val = 0;
209 n = 0;
210 while ((ch = *src++) != '\0') {
211 const char *pch;
213 pch = strchr(digits, ch);
214 if (pch != NULL) {
215 if (n++ != 0 && val == 0) /* no leading zeros */
216 return (0);
217 val *= 10;
218 val += (int)(pch - digits);
219 if (val > 128) /* range */
220 return (0);
221 continue;
223 return (0);
225 if (n == 0)
226 return (0);
227 *bitsp = val;
228 return (1);
231 static int
232 getv4(const char *src, u_char *dst, int *bitsp)
234 static const char digits[] = "0123456789";
235 u_char *odst = dst;
236 int n;
237 u_int val;
238 char ch;
240 val = 0;
241 n = 0;
242 while ((ch = *src++) != '\0') {
243 const char *pch;
245 pch = strchr(digits, ch);
246 if (pch != NULL) {
247 if (n++ != 0 && val == 0) /* no leading zeros */
248 return (0);
249 val *= 10;
250 val += (int)(pch - digits);
251 if (val > 255) /* range */
252 return (0);
253 continue;
255 if (ch == '.' || ch == '/') {
256 if (dst - odst > 3) /* too many octets? */
257 return (0);
258 *dst++ = val;
259 if (ch == '/')
260 return (getbits(src, bitsp));
261 val = 0;
262 n = 0;
263 continue;
265 return (0);
267 if (n == 0)
268 return (0);
269 if (dst - odst > 3) /* too many octets? */
270 return (0);
271 *dst++ = val;
272 return (1);
275 static int
276 inet_net_pton_ipv6(const char *src, u_char *dst, size_t size)
278 static const char xdigits_l[] = "0123456789abcdef",
279 xdigits_u[] = "0123456789ABCDEF";
280 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
281 const char *xdigits, *curtok;
282 int ch, saw_xdigit;
283 u_int val;
284 int digits;
285 int bits;
286 size_t bytes;
287 int words;
288 int ipv4;
290 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
291 endp = tp + NS_IN6ADDRSZ;
292 colonp = NULL;
293 /* Leading :: requires some special handling. */
294 if (*src == ':')
295 if (*++src != ':')
296 goto enoent;
297 curtok = src;
298 saw_xdigit = 0;
299 val = 0;
300 digits = 0;
301 bits = -1;
302 ipv4 = 0;
303 while ((ch = *src++) != '\0') {
304 const char *pch;
306 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
307 pch = strchr((xdigits = xdigits_u), ch);
308 if (pch != NULL) {
309 val <<= 4;
310 val |= (int)(pch - xdigits);
311 if (++digits > 4)
312 goto enoent;
313 saw_xdigit = 1;
314 continue;
316 if (ch == ':') {
317 curtok = src;
318 if (!saw_xdigit) {
319 if (colonp)
320 goto enoent;
321 colonp = tp;
322 continue;
323 } else if (*src == '\0')
324 goto enoent;
325 if (tp + NS_INT16SZ > endp)
326 return (0);
327 *tp++ = (u_char) (val >> 8) & 0xff;
328 *tp++ = (u_char) val & 0xff;
329 saw_xdigit = 0;
330 digits = 0;
331 val = 0;
332 continue;
334 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
335 getv4(curtok, tp, &bits) > 0) {
336 tp += NS_INADDRSZ;
337 saw_xdigit = 0;
338 ipv4 = 1;
339 break; /* '\0' was seen by inet_pton4(). */
341 if (ch == '/' && getbits(src, &bits) > 0)
342 break;
343 goto enoent;
345 if (saw_xdigit) {
346 if (tp + NS_INT16SZ > endp)
347 goto enoent;
348 *tp++ = (u_char) (val >> 8) & 0xff;
349 *tp++ = (u_char) val & 0xff;
351 if (bits == -1)
352 bits = 128;
354 words = (bits + 15) / 16;
355 if (words < 2)
356 words = 2;
357 if (ipv4)
358 words = 8;
359 endp = tmp + 2 * words;
361 if (colonp != NULL) {
363 * Since some memmove()'s erroneously fail to handle
364 * overlapping regions, we'll do the shift by hand.
366 const ptrdiff_t n = tp - colonp;
367 int i;
369 if (tp == endp)
370 goto enoent;
371 for (i = 1; i <= n; i++) {
372 endp[- i] = colonp[n - i];
373 colonp[n - i] = 0;
375 tp = endp;
377 if (tp != endp)
378 goto enoent;
380 bytes = (bits + 7) / 8;
381 if (bytes > size)
382 goto emsgsize;
383 memcpy(dst, tmp, bytes);
384 return (bits);
386 enoent:
387 errno = ENOENT;
388 return (-1);
390 emsgsize:
391 errno = EMSGSIZE;
392 return (-1);
396 * int
397 * inet_net_pton(af, src, dst, size)
398 * convert network number from presentation to network format.
399 * accepts hex octets, hex strings, decimal octets, and /CIDR.
400 * "size" is in bytes and describes "dst".
401 * return:
402 * number of bits, either imputed classfully or specified with /CIDR,
403 * or -1 if some failure occurred (check errno). ENOENT means it was
404 * not a valid network specification.
405 * author:
406 * Paul Vixie (ISC), June 1996
409 inet_net_pton(int af, const char *src, void *dst, size_t size)
411 switch (af) {
412 case AF_INET:
413 return (inet_net_pton_ipv4(src, dst, size));
414 case AF_INET6:
415 return (inet_net_pton_ipv6(src, dst, size));
416 default:
417 errno = EAFNOSUPPORT;
418 return (-1);