Home | History | Annotate | Line # | Download | only in libntp
      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