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 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