xref: /freebsd/lib/libc/inet/inet_pton.c (revision dc36d6f9bb1753f3808552f3afd30eda9a7b206a)
1*6e778a7eSPedro F. Giffuni /*-
2*6e778a7eSPedro F. Giffuni  * SPDX-License-Identifier: ISC
3*6e778a7eSPedro F. Giffuni  *
465e96449SHajimu UMEMOTO  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
565e96449SHajimu UMEMOTO  * Copyright (c) 1996,1999 by Internet Software Consortium.
665e96449SHajimu UMEMOTO  *
765e96449SHajimu UMEMOTO  * Permission to use, copy, modify, and distribute this software for any
865e96449SHajimu UMEMOTO  * purpose with or without fee is hereby granted, provided that the above
965e96449SHajimu UMEMOTO  * copyright notice and this permission notice appear in all copies.
1065e96449SHajimu UMEMOTO  *
1165e96449SHajimu UMEMOTO  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
1265e96449SHajimu UMEMOTO  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1365e96449SHajimu UMEMOTO  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
1465e96449SHajimu UMEMOTO  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1565e96449SHajimu UMEMOTO  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1665e96449SHajimu UMEMOTO  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
1765e96449SHajimu UMEMOTO  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1865e96449SHajimu UMEMOTO  */
1965e96449SHajimu UMEMOTO 
2065e96449SHajimu UMEMOTO #include "port_before.h"
2165e96449SHajimu UMEMOTO #include <sys/param.h>
2265e96449SHajimu UMEMOTO #include <sys/socket.h>
2365e96449SHajimu UMEMOTO #include <netinet/in.h>
2465e96449SHajimu UMEMOTO #include <arpa/inet.h>
2565e96449SHajimu UMEMOTO #include <arpa/nameser.h>
2665e96449SHajimu UMEMOTO #include <string.h>
2765e96449SHajimu UMEMOTO #include <errno.h>
2865e96449SHajimu UMEMOTO #include "port_after.h"
2965e96449SHajimu UMEMOTO 
30dde4a85dSHajimu UMEMOTO /*%
3165e96449SHajimu UMEMOTO  * WARNING: Don't even consider trying to compile this on a system where
3265e96449SHajimu UMEMOTO  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
3365e96449SHajimu UMEMOTO  */
3465e96449SHajimu UMEMOTO 
35ab96eeabSHajimu UMEMOTO static int	inet_pton4(const char *src, u_char *dst);
36ab96eeabSHajimu UMEMOTO static int	inet_pton6(const char *src, u_char *dst);
3765e96449SHajimu UMEMOTO 
3865e96449SHajimu UMEMOTO /* int
3965e96449SHajimu UMEMOTO  * inet_pton(af, src, dst)
4065e96449SHajimu UMEMOTO  *	convert from presentation format (which usually means ASCII printable)
4165e96449SHajimu UMEMOTO  *	to network format (which is usually some kind of binary format).
4265e96449SHajimu UMEMOTO  * return:
4365e96449SHajimu UMEMOTO  *	1 if the address was valid for the specified address family
4465e96449SHajimu UMEMOTO  *	0 if the address wasn't valid (`dst' is untouched in this case)
4565e96449SHajimu UMEMOTO  *	-1 if some other error occurred (`dst' is untouched in this case, too)
4665e96449SHajimu UMEMOTO  * author:
4765e96449SHajimu UMEMOTO  *	Paul Vixie, 1996.
4865e96449SHajimu UMEMOTO  */
4965e96449SHajimu UMEMOTO int
inet_pton(int af,const char * __restrict src,void * __restrict dst)50ab96eeabSHajimu UMEMOTO inet_pton(int af, const char * __restrict src, void * __restrict dst)
5165e96449SHajimu UMEMOTO {
5265e96449SHajimu UMEMOTO 	switch (af) {
5365e96449SHajimu UMEMOTO 	case AF_INET:
5465e96449SHajimu UMEMOTO 		return (inet_pton4(src, dst));
5565e96449SHajimu UMEMOTO 	case AF_INET6:
5665e96449SHajimu UMEMOTO 		return (inet_pton6(src, dst));
5765e96449SHajimu UMEMOTO 	default:
5865e96449SHajimu UMEMOTO 		errno = EAFNOSUPPORT;
5965e96449SHajimu UMEMOTO 		return (-1);
6065e96449SHajimu UMEMOTO 	}
6165e96449SHajimu UMEMOTO 	/* NOTREACHED */
6265e96449SHajimu UMEMOTO }
6365e96449SHajimu UMEMOTO 
6465e96449SHajimu UMEMOTO /* int
6565e96449SHajimu UMEMOTO  * inet_pton4(src, dst)
6665e96449SHajimu UMEMOTO  *	like inet_aton() but without all the hexadecimal and shorthand.
6765e96449SHajimu UMEMOTO  * return:
6865e96449SHajimu UMEMOTO  *	1 if `src' is a valid dotted quad, else 0.
6965e96449SHajimu UMEMOTO  * notice:
7065e96449SHajimu UMEMOTO  *	does not touch `dst' unless it's returning 1.
7165e96449SHajimu UMEMOTO  * author:
7265e96449SHajimu UMEMOTO  *	Paul Vixie, 1996.
7365e96449SHajimu UMEMOTO  */
7465e96449SHajimu UMEMOTO static int
inet_pton4(const char * src,u_char * dst)75ab96eeabSHajimu UMEMOTO inet_pton4(const char *src, u_char *dst)
7665e96449SHajimu UMEMOTO {
7765e96449SHajimu UMEMOTO 	static const char digits[] = "0123456789";
7865e96449SHajimu UMEMOTO 	int saw_digit, octets, ch;
7965e96449SHajimu UMEMOTO 	u_char tmp[NS_INADDRSZ], *tp;
8065e96449SHajimu UMEMOTO 
8165e96449SHajimu UMEMOTO 	saw_digit = 0;
8265e96449SHajimu UMEMOTO 	octets = 0;
8365e96449SHajimu UMEMOTO 	*(tp = tmp) = 0;
8465e96449SHajimu UMEMOTO 	while ((ch = *src++) != '\0') {
8565e96449SHajimu UMEMOTO 		const char *pch;
8665e96449SHajimu UMEMOTO 
8765e96449SHajimu UMEMOTO 		if ((pch = strchr(digits, ch)) != NULL) {
8865e96449SHajimu UMEMOTO 			u_int new = *tp * 10 + (pch - digits);
8965e96449SHajimu UMEMOTO 
9065e96449SHajimu UMEMOTO 			if (saw_digit && *tp == 0)
9165e96449SHajimu UMEMOTO 				return (0);
9265e96449SHajimu UMEMOTO 			if (new > 255)
9365e96449SHajimu UMEMOTO 				return (0);
9465e96449SHajimu UMEMOTO 			*tp = new;
9565e96449SHajimu UMEMOTO 			if (!saw_digit) {
9665e96449SHajimu UMEMOTO 				if (++octets > 4)
9765e96449SHajimu UMEMOTO 					return (0);
9865e96449SHajimu UMEMOTO 				saw_digit = 1;
9965e96449SHajimu UMEMOTO 			}
10065e96449SHajimu UMEMOTO 		} else if (ch == '.' && saw_digit) {
10165e96449SHajimu UMEMOTO 			if (octets == 4)
10265e96449SHajimu UMEMOTO 				return (0);
10365e96449SHajimu UMEMOTO 			*++tp = 0;
10465e96449SHajimu UMEMOTO 			saw_digit = 0;
10565e96449SHajimu UMEMOTO 		} else
10665e96449SHajimu UMEMOTO 			return (0);
10765e96449SHajimu UMEMOTO 	}
10865e96449SHajimu UMEMOTO 	if (octets < 4)
10965e96449SHajimu UMEMOTO 		return (0);
11065e96449SHajimu UMEMOTO 	memcpy(dst, tmp, NS_INADDRSZ);
11165e96449SHajimu UMEMOTO 	return (1);
11265e96449SHajimu UMEMOTO }
11365e96449SHajimu UMEMOTO 
11465e96449SHajimu UMEMOTO /* int
11565e96449SHajimu UMEMOTO  * inet_pton6(src, dst)
11665e96449SHajimu UMEMOTO  *	convert presentation level address to network order binary form.
11765e96449SHajimu UMEMOTO  * return:
11865e96449SHajimu UMEMOTO  *	1 if `src' is a valid [RFC1884 2.2] address, else 0.
11965e96449SHajimu UMEMOTO  * notice:
12065e96449SHajimu UMEMOTO  *	(1) does not touch `dst' unless it's returning 1.
12165e96449SHajimu UMEMOTO  *	(2) :: in a full address is silently ignored.
12265e96449SHajimu UMEMOTO  * credit:
12365e96449SHajimu UMEMOTO  *	inspired by Mark Andrews.
12465e96449SHajimu UMEMOTO  * author:
12565e96449SHajimu UMEMOTO  *	Paul Vixie, 1996.
12665e96449SHajimu UMEMOTO  */
12765e96449SHajimu UMEMOTO static int
inet_pton6(const char * src,u_char * dst)128ab96eeabSHajimu UMEMOTO inet_pton6(const char *src, u_char *dst)
12965e96449SHajimu UMEMOTO {
13065e96449SHajimu UMEMOTO 	static const char xdigits_l[] = "0123456789abcdef",
13165e96449SHajimu UMEMOTO 			  xdigits_u[] = "0123456789ABCDEF";
13265e96449SHajimu UMEMOTO 	u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
13365e96449SHajimu UMEMOTO 	const char *xdigits, *curtok;
13465e96449SHajimu UMEMOTO 	int ch, seen_xdigits;
13565e96449SHajimu UMEMOTO 	u_int val;
13665e96449SHajimu UMEMOTO 
13765e96449SHajimu UMEMOTO 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
13865e96449SHajimu UMEMOTO 	endp = tp + NS_IN6ADDRSZ;
13965e96449SHajimu UMEMOTO 	colonp = NULL;
14065e96449SHajimu UMEMOTO 	/* Leading :: requires some special handling. */
14165e96449SHajimu UMEMOTO 	if (*src == ':')
14265e96449SHajimu UMEMOTO 		if (*++src != ':')
14365e96449SHajimu UMEMOTO 			return (0);
14465e96449SHajimu UMEMOTO 	curtok = src;
14565e96449SHajimu UMEMOTO 	seen_xdigits = 0;
14665e96449SHajimu UMEMOTO 	val = 0;
14765e96449SHajimu UMEMOTO 	while ((ch = *src++) != '\0') {
14865e96449SHajimu UMEMOTO 		const char *pch;
14965e96449SHajimu UMEMOTO 
15065e96449SHajimu UMEMOTO 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
15165e96449SHajimu UMEMOTO 			pch = strchr((xdigits = xdigits_u), ch);
15265e96449SHajimu UMEMOTO 		if (pch != NULL) {
15365e96449SHajimu UMEMOTO 			val <<= 4;
15465e96449SHajimu UMEMOTO 			val |= (pch - xdigits);
15565e96449SHajimu UMEMOTO 			if (++seen_xdigits > 4)
15665e96449SHajimu UMEMOTO 				return (0);
15765e96449SHajimu UMEMOTO 			continue;
15865e96449SHajimu UMEMOTO 		}
15965e96449SHajimu UMEMOTO 		if (ch == ':') {
16065e96449SHajimu UMEMOTO 			curtok = src;
16165e96449SHajimu UMEMOTO 			if (!seen_xdigits) {
16265e96449SHajimu UMEMOTO 				if (colonp)
16365e96449SHajimu UMEMOTO 					return (0);
16465e96449SHajimu UMEMOTO 				colonp = tp;
16565e96449SHajimu UMEMOTO 				continue;
16665e96449SHajimu UMEMOTO 			} else if (*src == '\0') {
16765e96449SHajimu UMEMOTO 				return (0);
16865e96449SHajimu UMEMOTO 			}
16965e96449SHajimu UMEMOTO 			if (tp + NS_INT16SZ > endp)
17065e96449SHajimu UMEMOTO 				return (0);
17165e96449SHajimu UMEMOTO 			*tp++ = (u_char) (val >> 8) & 0xff;
17265e96449SHajimu UMEMOTO 			*tp++ = (u_char) val & 0xff;
17365e96449SHajimu UMEMOTO 			seen_xdigits = 0;
17465e96449SHajimu UMEMOTO 			val = 0;
17565e96449SHajimu UMEMOTO 			continue;
17665e96449SHajimu UMEMOTO 		}
17765e96449SHajimu UMEMOTO 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
17865e96449SHajimu UMEMOTO 		    inet_pton4(curtok, tp) > 0) {
17965e96449SHajimu UMEMOTO 			tp += NS_INADDRSZ;
18065e96449SHajimu UMEMOTO 			seen_xdigits = 0;
181dde4a85dSHajimu UMEMOTO 			break;	/*%< '\\0' was seen by inet_pton4(). */
18265e96449SHajimu UMEMOTO 		}
18365e96449SHajimu UMEMOTO 		return (0);
18465e96449SHajimu UMEMOTO 	}
18565e96449SHajimu UMEMOTO 	if (seen_xdigits) {
18665e96449SHajimu UMEMOTO 		if (tp + NS_INT16SZ > endp)
18765e96449SHajimu UMEMOTO 			return (0);
18865e96449SHajimu UMEMOTO 		*tp++ = (u_char) (val >> 8) & 0xff;
18965e96449SHajimu UMEMOTO 		*tp++ = (u_char) val & 0xff;
19065e96449SHajimu UMEMOTO 	}
19165e96449SHajimu UMEMOTO 	if (colonp != NULL) {
19265e96449SHajimu UMEMOTO 		/*
19365e96449SHajimu UMEMOTO 		 * Since some memmove()'s erroneously fail to handle
19465e96449SHajimu UMEMOTO 		 * overlapping regions, we'll do the shift by hand.
19565e96449SHajimu UMEMOTO 		 */
19665e96449SHajimu UMEMOTO 		const int n = tp - colonp;
19765e96449SHajimu UMEMOTO 		int i;
19865e96449SHajimu UMEMOTO 
19965e96449SHajimu UMEMOTO 		if (tp == endp)
20065e96449SHajimu UMEMOTO 			return (0);
20165e96449SHajimu UMEMOTO 		for (i = 1; i <= n; i++) {
20265e96449SHajimu UMEMOTO 			endp[- i] = colonp[n - i];
20365e96449SHajimu UMEMOTO 			colonp[n - i] = 0;
20465e96449SHajimu UMEMOTO 		}
20565e96449SHajimu UMEMOTO 		tp = endp;
20665e96449SHajimu UMEMOTO 	}
20765e96449SHajimu UMEMOTO 	if (tp != endp)
20865e96449SHajimu UMEMOTO 		return (0);
20965e96449SHajimu UMEMOTO 	memcpy(dst, tmp, NS_IN6ADDRSZ);
21065e96449SHajimu UMEMOTO 	return (1);
21165e96449SHajimu UMEMOTO }
212ab96eeabSHajimu UMEMOTO 
213ab96eeabSHajimu UMEMOTO /*
214ab96eeabSHajimu UMEMOTO  * Weak aliases for applications that use certain private entry points,
215ab96eeabSHajimu UMEMOTO  * and fail to include <arpa/inet.h>.
216ab96eeabSHajimu UMEMOTO  */
217ab96eeabSHajimu UMEMOTO #undef inet_pton
218ab96eeabSHajimu UMEMOTO __weak_reference(__inet_pton, inet_pton);
219dde4a85dSHajimu UMEMOTO 
220dde4a85dSHajimu UMEMOTO /*! \file */
221