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