1294904Sdelphij/*
2294904Sdelphij * is_ip_address
3294904Sdelphij *
4294904Sdelphij */
5294904Sdelphij
6294904Sdelphij#ifdef HAVE_CONFIG_H
7294904Sdelphij# include <config.h>
8294904Sdelphij#endif
9294904Sdelphij
10294904Sdelphij#include "ntp_assert.h"
11294904Sdelphij#include "ntp_stdlib.h"
12294904Sdelphij#include "safecast.h"
13294904Sdelphij
14294904Sdelphij/* Don't include ISC's version of IPv6 variables and structures */
15294904Sdelphij#define ISC_IPV6_H 1
16294904Sdelphij#include <isc/netaddr.h>
17294904Sdelphij#include <isc/sockaddr.h>
18294904Sdelphij
19294904Sdelphij
20294904Sdelphij/*
21294904Sdelphij * Code to tell if we have an IP address
22294904Sdelphij * If we have then return the sockaddr structure
23294904Sdelphij * and set the return value
24294904Sdelphij * see the bind9/getaddresses.c for details
25294904Sdelphij */
26294904Sdelphijint
27294904Sdelphijis_ip_address(
28294904Sdelphij	const char *	host,
29294904Sdelphij	u_short		af,
30294904Sdelphij	sockaddr_u *	addr
31294904Sdelphij	)
32294904Sdelphij{
33294904Sdelphij	struct in_addr in4;
34294904Sdelphij	struct addrinfo hints;
35294904Sdelphij	struct addrinfo *result;
36294904Sdelphij	struct sockaddr_in6 *resaddr6;
37294904Sdelphij	char tmpbuf[128];
38294904Sdelphij	char *pch;
39294904Sdelphij
40294904Sdelphij	REQUIRE(host != NULL);
41294904Sdelphij	REQUIRE(addr != NULL);
42294904Sdelphij
43294904Sdelphij	ZERO_SOCK(addr);
44294904Sdelphij
45294904Sdelphij	/*
46294904Sdelphij	 * Try IPv4, then IPv6.  In order to handle the extended format
47294904Sdelphij	 * for IPv6 scoped addresses (address%scope_ID), we'll use a local
48294904Sdelphij	 * working buffer of 128 bytes.  The length is an ad-hoc value, but
49294904Sdelphij	 * should be enough for this purpose; the buffer can contain a string
50294904Sdelphij	 * of at least 80 bytes for scope_ID in addition to any IPv6 numeric
51294904Sdelphij	 * addresses (up to 46 bytes), the delimiter character and the
52294904Sdelphij	 * terminating NULL character.
53294904Sdelphij	 */
54294904Sdelphij	if (AF_UNSPEC == af || AF_INET == af)
55294904Sdelphij		if (inet_pton(AF_INET, host, &in4) == 1) {
56294904Sdelphij			AF(addr) = AF_INET;
57294904Sdelphij			SET_ADDR4N(addr, in4.s_addr);
58294904Sdelphij
59294904Sdelphij			return TRUE;
60294904Sdelphij		}
61294904Sdelphij
62294904Sdelphij	if (AF_UNSPEC == af || AF_INET6 == af)
63294904Sdelphij		if (sizeof(tmpbuf) > strlen(host)) {
64294904Sdelphij			if ('[' == host[0]) {
65294904Sdelphij				strlcpy(tmpbuf, &host[1], sizeof(tmpbuf));
66294904Sdelphij				pch = strchr(tmpbuf, ']');
67294904Sdelphij				if (pch != NULL)
68294904Sdelphij					*pch = '\0';
69294904Sdelphij			} else {
70294904Sdelphij				strlcpy(tmpbuf, host, sizeof(tmpbuf));
71294904Sdelphij			}
72294904Sdelphij			ZERO(hints);
73294904Sdelphij			hints.ai_family = AF_INET6;
74294904Sdelphij			hints.ai_flags |= AI_NUMERICHOST;
75294904Sdelphij			if (getaddrinfo(tmpbuf, NULL, &hints, &result) == 0) {
76294904Sdelphij				AF(addr) = AF_INET6;
77294904Sdelphij				resaddr6 = UA_PTR(struct sockaddr_in6, result->ai_addr);
78294904Sdelphij				SET_ADDR6N(addr, resaddr6->sin6_addr);
79294904Sdelphij				SET_SCOPE(addr, resaddr6->sin6_scope_id);
80294904Sdelphij
81294904Sdelphij				freeaddrinfo(result);
82294904Sdelphij				return TRUE;
83294904Sdelphij			}
84294904Sdelphij		}
85294904Sdelphij	/*
86294904Sdelphij	 * If we got here it was not an IP address
87294904Sdelphij	 */
88294904Sdelphij	return FALSE;
89294904Sdelphij}
90