xref: /freebsd/contrib/ntp/libntp/is_ip_address.c (revision 4990d495)
1*68ba7e87SXin LI /*
2*68ba7e87SXin LI  * is_ip_address
3*68ba7e87SXin LI  *
4*68ba7e87SXin LI  */
5*68ba7e87SXin LI 
6*68ba7e87SXin LI #ifdef HAVE_CONFIG_H
7*68ba7e87SXin LI # include <config.h>
8*68ba7e87SXin LI #endif
9*68ba7e87SXin LI 
10*68ba7e87SXin LI #include "ntp_assert.h"
11*68ba7e87SXin LI #include "ntp_stdlib.h"
12*68ba7e87SXin LI #include "safecast.h"
13*68ba7e87SXin LI 
14*68ba7e87SXin LI /* Don't include ISC's version of IPv6 variables and structures */
15*68ba7e87SXin LI #define ISC_IPV6_H 1
16*68ba7e87SXin LI #include <isc/netaddr.h>
17*68ba7e87SXin LI #include <isc/sockaddr.h>
18*68ba7e87SXin LI 
19*68ba7e87SXin LI 
20*68ba7e87SXin LI /*
21*68ba7e87SXin LI  * Code to tell if we have an IP address
22*68ba7e87SXin LI  * If we have then return the sockaddr structure
23*68ba7e87SXin LI  * and set the return value
24*68ba7e87SXin LI  * see the bind9/getaddresses.c for details
25*68ba7e87SXin LI  */
26*68ba7e87SXin LI int
is_ip_address(const char * host,u_short af,sockaddr_u * addr)27*68ba7e87SXin LI is_ip_address(
28*68ba7e87SXin LI 	const char *	host,
29*68ba7e87SXin LI 	u_short		af,
30*68ba7e87SXin LI 	sockaddr_u *	addr
31*68ba7e87SXin LI 	)
32*68ba7e87SXin LI {
33*68ba7e87SXin LI 	struct in_addr in4;
34*68ba7e87SXin LI 	struct addrinfo hints;
35*68ba7e87SXin LI 	struct addrinfo *result;
36*68ba7e87SXin LI 	struct sockaddr_in6 *resaddr6;
37*68ba7e87SXin LI 	char tmpbuf[128];
38*68ba7e87SXin LI 	char *pch;
39*68ba7e87SXin LI 
40*68ba7e87SXin LI 	REQUIRE(host != NULL);
41*68ba7e87SXin LI 	REQUIRE(addr != NULL);
42*68ba7e87SXin LI 
43*68ba7e87SXin LI 	ZERO_SOCK(addr);
44*68ba7e87SXin LI 
45*68ba7e87SXin LI 	/*
46*68ba7e87SXin LI 	 * Try IPv4, then IPv6.  In order to handle the extended format
47*68ba7e87SXin LI 	 * for IPv6 scoped addresses (address%scope_ID), we'll use a local
48*68ba7e87SXin LI 	 * working buffer of 128 bytes.  The length is an ad-hoc value, but
49*68ba7e87SXin LI 	 * should be enough for this purpose; the buffer can contain a string
50*68ba7e87SXin LI 	 * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
51*68ba7e87SXin LI 	 * addresses (up to 46 bytes), the delimiter character and the
52*68ba7e87SXin LI 	 * terminating NULL character.
53*68ba7e87SXin LI 	 */
54*68ba7e87SXin LI 	if (AF_UNSPEC == af || AF_INET == af)
55*68ba7e87SXin LI 		if (inet_pton(AF_INET, host, &in4) == 1) {
56*68ba7e87SXin LI 			AF(addr) = AF_INET;
57*68ba7e87SXin LI 			SET_ADDR4N(addr, in4.s_addr);
58*68ba7e87SXin LI 
59*68ba7e87SXin LI 			return TRUE;
60*68ba7e87SXin LI 		}
61*68ba7e87SXin LI 
62*68ba7e87SXin LI 	if (AF_UNSPEC == af || AF_INET6 == af)
63*68ba7e87SXin LI 		if (sizeof(tmpbuf) > strlen(host)) {
64*68ba7e87SXin LI 			if ('[' == host[0]) {
65*68ba7e87SXin LI 				strlcpy(tmpbuf, &host[1], sizeof(tmpbuf));
66*68ba7e87SXin LI 				pch = strchr(tmpbuf, ']');
67*68ba7e87SXin LI 				if (pch != NULL)
68*68ba7e87SXin LI 					*pch = '\0';
69*68ba7e87SXin LI 			} else {
70*68ba7e87SXin LI 				strlcpy(tmpbuf, host, sizeof(tmpbuf));
71*68ba7e87SXin LI 			}
72*68ba7e87SXin LI 			ZERO(hints);
73*68ba7e87SXin LI 			hints.ai_family = AF_INET6;
74*68ba7e87SXin LI 			hints.ai_flags |= AI_NUMERICHOST;
75*68ba7e87SXin LI 			if (getaddrinfo(tmpbuf, NULL, &hints, &result) == 0) {
76*68ba7e87SXin LI 				AF(addr) = AF_INET6;
77*68ba7e87SXin LI 				resaddr6 = UA_PTR(struct sockaddr_in6, result->ai_addr);
78*68ba7e87SXin LI 				SET_ADDR6N(addr, resaddr6->sin6_addr);
79*68ba7e87SXin LI 				SET_SCOPE(addr, resaddr6->sin6_scope_id);
80*68ba7e87SXin LI 
81*68ba7e87SXin LI 				freeaddrinfo(result);
82*68ba7e87SXin LI 				return TRUE;
83*68ba7e87SXin LI 			}
84*68ba7e87SXin LI 		}
85*68ba7e87SXin LI 	/*
86*68ba7e87SXin LI 	 * If we got here it was not an IP address
87*68ba7e87SXin LI 	 */
88*68ba7e87SXin LI 	return FALSE;
89*68ba7e87SXin LI }
90