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