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