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