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