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