1294491Sdelphij/*
2294491Sdelphij * is_ip_address
3294491Sdelphij *
4294491Sdelphij */
5294491Sdelphij
6294491Sdelphij#ifdef HAVE_CONFIG_H
7294491Sdelphij# include <config.h>
8294491Sdelphij#endif
9294491Sdelphij
10294491Sdelphij#include "ntp_assert.h"
11294491Sdelphij#include "ntp_stdlib.h"
12294491Sdelphij#include "safecast.h"
13294491Sdelphij
14294491Sdelphij/* Don't include ISC's version of IPv6 variables and structures */
15294491Sdelphij#define ISC_IPV6_H 1
16294491Sdelphij#include <isc/netaddr.h>
17294491Sdelphij#include <isc/sockaddr.h>
18294491Sdelphij
19294491Sdelphij
20294491Sdelphij/*
21294491Sdelphij * Code to tell if we have an IP address
22294491Sdelphij * If we have then return the sockaddr structure
23294491Sdelphij * and set the return value
24294491Sdelphij * see the bind9/getaddresses.c for details
25294491Sdelphij */
26294491Sdelphijint
27294491Sdelphijis_ip_address(
28294491Sdelphij	const char *	host,
29294491Sdelphij	u_short		af,
30294491Sdelphij	sockaddr_u *	addr
31294491Sdelphij	)
32294491Sdelphij{
33294491Sdelphij	struct in_addr in4;
34294491Sdelphij	struct addrinfo hints;
35294491Sdelphij	struct addrinfo *result;
36294491Sdelphij	struct sockaddr_in6 *resaddr6;
37294491Sdelphij	char tmpbuf[128];
38294491Sdelphij	char *pch;
39294491Sdelphij
40294491Sdelphij	REQUIRE(host != NULL);
41294491Sdelphij	REQUIRE(addr != NULL);
42294491Sdelphij
43294491Sdelphij	ZERO_SOCK(addr);
44294491Sdelphij
45294491Sdelphij	/*
46294491Sdelphij	 * Try IPv4, then IPv6.  In order to handle the extended format
47294491Sdelphij	 * for IPv6 scoped addresses (address%scope_ID), we'll use a local
48294491Sdelphij	 * working buffer of 128 bytes.  The length is an ad-hoc value, but
49294491Sdelphij	 * should be enough for this purpose; the buffer can contain a string
50294491Sdelphij	 * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
51294491Sdelphij	 * addresses (up to 46 bytes), the delimiter character and the
52294491Sdelphij	 * terminating NULL character.
53294491Sdelphij	 */
54294491Sdelphij	if (AF_UNSPEC == af || AF_INET == af)
55294491Sdelphij		if (inet_pton(AF_INET, host, &in4) == 1) {
56294491Sdelphij			AF(addr) = AF_INET;
57294491Sdelphij			SET_ADDR4N(addr, in4.s_addr);
58294491Sdelphij
59294491Sdelphij			return TRUE;
60294491Sdelphij		}
61294491Sdelphij
62294491Sdelphij	if (AF_UNSPEC == af || AF_INET6 == af)
63294491Sdelphij		if (sizeof(tmpbuf) > strlen(host)) {
64294491Sdelphij			if ('[' == host[0]) {
65294491Sdelphij				strlcpy(tmpbuf, &host[1], sizeof(tmpbuf));
66294491Sdelphij				pch = strchr(tmpbuf, ']');
67294491Sdelphij				if (pch != NULL)
68294491Sdelphij					*pch = '\0';
69294491Sdelphij			} else {
70294491Sdelphij				strlcpy(tmpbuf, host, sizeof(tmpbuf));
71294491Sdelphij			}
72294491Sdelphij			ZERO(hints);
73294491Sdelphij			hints.ai_family = AF_INET6;
74294491Sdelphij			hints.ai_flags |= AI_NUMERICHOST;
75294491Sdelphij			if (getaddrinfo(tmpbuf, NULL, &hints, &result) == 0) {
76294491Sdelphij				AF(addr) = AF_INET6;
77294491Sdelphij				resaddr6 = UA_PTR(struct sockaddr_in6, result->ai_addr);
78294491Sdelphij				SET_ADDR6N(addr, resaddr6->sin6_addr);
79294491Sdelphij				SET_SCOPE(addr, resaddr6->sin6_scope_id);
80294491Sdelphij
81294491Sdelphij				freeaddrinfo(result);
82294491Sdelphij				return TRUE;
83294491Sdelphij			}
84294491Sdelphij		}
85294491Sdelphij	/*
86294491Sdelphij	 * If we got here it was not an IP address
87294491Sdelphij	 */
88294491Sdelphij	return FALSE;
89294491Sdelphij}
90