nameserv: add support for returning multiple addresses

This commit is contained in:
Miroslav Lichvar 2014-10-21 15:37:16 +02:00
parent 699680807d
commit 4d1a754ec6
8 changed files with 65 additions and 36 deletions

View file

@ -119,7 +119,7 @@ open_io(const char *hostname, int port)
int on_off = 1; int on_off = 1;
/* Note, this call could block for a while */ /* Note, this call could block for a while */
if (DNS_Name2IPAddress(hostname, &ip) != DNS_Success) { if (DNS_Name2IPAddress(hostname, &ip, 1) != DNS_Success) {
fprintf(stderr, "Could not get IP address for %s\n", hostname); fprintf(stderr, "Could not get IP address for %s\n", hostname);
exit(1); exit(1);
} }
@ -233,7 +233,7 @@ read_mask_address(char *line, IPAddr *mask, IPAddr *address)
} }
} }
} else { } else {
if (DNS_Name2IPAddress(p, address) == DNS_Success) { if (DNS_Name2IPAddress(p, address, 1) == DNS_Success) {
bits_to_mask(-1, address->family, mask); bits_to_mask(-1, address->family, mask);
return 1; return 1;
} else { } else {
@ -305,7 +305,7 @@ read_address_integer(char *line, IPAddr *address, int *value)
fprintf(stderr, "Invalid syntax for address value\n"); fprintf(stderr, "Invalid syntax for address value\n");
ok = 0; ok = 0;
} else { } else {
if (DNS_Name2IPAddress(hostname, address) != DNS_Success) { if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n"); fprintf(stderr, "Could not get address for hostname\n");
ok = 0; ok = 0;
} else { } else {
@ -333,7 +333,7 @@ read_address_double(char *line, IPAddr *address, double *value)
fprintf(stderr, "Invalid syntax for address value\n"); fprintf(stderr, "Invalid syntax for address value\n");
ok = 0; ok = 0;
} else { } else {
if (DNS_Name2IPAddress(hostname, address) != DNS_Success) { if (DNS_Name2IPAddress(hostname, address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n"); fprintf(stderr, "Could not get address for hostname\n");
ok = 0; ok = 0;
} else { } else {
@ -660,7 +660,7 @@ parse_allow_deny(CMD_Request *msg, char *line)
(n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) { (n = sscanf(p, "%lu.%lu.%lu.%lu", &a, &b, &c, &d)) == 0) {
/* Try to parse as the name of a machine */ /* Try to parse as the name of a machine */
if (DNS_Name2IPAddress(p, &ip) != DNS_Success) { if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
fprintf(stderr, "Could not read address\n"); fprintf(stderr, "Could not read address\n");
return 0; return 0;
} else { } else {
@ -828,7 +828,7 @@ accheck_getaddr(char *line, IPAddr *addr)
addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d; addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d;
return 1; return 1;
} else { } else {
if (DNS_Name2IPAddress(p, &ip) != DNS_Success) { if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) {
return 0; return 0;
} else { } else {
*addr = ip; *addr = ip;
@ -935,7 +935,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line)
status = CPS_ParseNTPSourceAdd(line, &data); status = CPS_ParseNTPSourceAdd(line, &data);
switch (status) { switch (status) {
case CPS_Success: case CPS_Success:
if (DNS_Name2IPAddress(data.name, &ip_addr) != DNS_Success) { if (DNS_Name2IPAddress(data.name, &ip_addr, 1) != DNS_Success) {
fprintf(stderr, "Invalid host/IP address\n"); fprintf(stderr, "Invalid host/IP address\n");
break; break;
} }
@ -1056,7 +1056,7 @@ process_cmd_delete(CMD_Request *msg, char *line)
fprintf(stderr, "Invalid syntax for address\n"); fprintf(stderr, "Invalid syntax for address\n");
ok = 0; ok = 0;
} else { } else {
if (DNS_Name2IPAddress(hostname, &address) != DNS_Success) { if (DNS_Name2IPAddress(hostname, &address, 1) != DNS_Success) {
fprintf(stderr, "Could not get address for hostname\n"); fprintf(stderr, "Could not get address for hostname\n");
ok = 0; ok = 0;
} else { } else {

4
conf.c
View file

@ -817,7 +817,7 @@ parse_initstepslew(char *line)
hostname = p; hostname = p;
p = CPS_SplitWord(p); p = CPS_SplitWord(p);
if (*hostname) { if (*hostname) {
if (DNS_Name2IPAddress(hostname, &ip_addr) == DNS_Success) { if (DNS_Name2IPAddress(hostname, &ip_addr, 1) == DNS_Success) {
ARR_AppendElement(init_sources, &ip_addr); ARR_AppendElement(init_sources, &ip_addr);
} else { } else {
LOG(LOGS_WARN, LOGF_Configure, "Could not resolve address of initstepslew server %s", hostname); LOG(LOGS_WARN, LOGF_Configure, "Could not resolve address of initstepslew server %s", hostname);
@ -985,7 +985,7 @@ parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
} }
} else { } else {
if (DNS_Name2IPAddress(p, &ip_addr) == DNS_Success) { if (DNS_Name2IPAddress(p, &ip_addr, 1) == DNS_Success) {
new_node = (AllowDeny *)ARR_GetNewElement(restrictions); new_node = (AllowDeny *)ARR_GetNewElement(restrictions);
new_node->allow = allow; new_node->allow = allow;
new_node->all = all; new_node->all = all;

View file

@ -44,11 +44,11 @@ DNS_SetAddressFamily(int family)
} }
DNS_Status DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *addr) DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
{ {
#ifdef HAVE_GETADDRINFO #ifdef HAVE_GETADDRINFO
struct addrinfo hints, *res, *ai; struct addrinfo hints, *res, *ai;
int result; int i, result;
memset(&hints, 0, sizeof (hints)); memset(&hints, 0, sizeof (hints));
hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
@ -64,29 +64,37 @@ DNS_Name2IPAddress(const char *name, IPAddr *addr)
#endif #endif
} }
for (ai = res; !result && ai != NULL; ai = ai->ai_next) { for (ai = res, i = 0; i < max_addrs && ai != NULL; ai = ai->ai_next) {
switch (ai->ai_family) { switch (ai->ai_family) {
case AF_INET: case AF_INET:
addr->family = IPADDR_INET4; if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
addr->addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); continue;
result = 1; ip_addrs[i].family = IPADDR_INET4;
ip_addrs[i].addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr);
i++;
break; break;
#ifdef FEAT_IPV6 #ifdef FEAT_IPV6
case AF_INET6: case AF_INET6:
addr->family = IPADDR_INET6; if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6)
memcpy(&addr->addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, sizeof (addr->addr.in6)); continue;
result = 1; ip_addrs[i].family = IPADDR_INET6;
memcpy(&ip_addrs[i].addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr,
sizeof (ip_addrs->addr.in6));
i++;
break; break;
#endif #endif
} }
if (result && address_family != IPADDR_UNSPEC && address_family != addr->family)
result = 0;
} }
for (; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
freeaddrinfo(res); freeaddrinfo(res);
return result ? DNS_Success : DNS_Failure;
return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure;
#else #else
struct hostent *host; struct hostent *host;
int i;
if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4) if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4)
return DNS_Failure; return DNS_Failure;
@ -100,8 +108,14 @@ DNS_Name2IPAddress(const char *name, IPAddr *addr)
if (host->h_addrtype != AF_INET || !host->h_addr_list[0]) if (host->h_addrtype != AF_INET || !host->h_addr_list[0])
return DNS_Failure; return DNS_Failure;
addr->family = IPADDR_INET4; for (i = 0; host->h_addr_list[i] && i < max_addrs; i++) {
addr->addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[0]); ip_addrs[i].family = IPADDR_INET4;
ip_addrs[i].addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[i]);
}
for (; i < max_addrs; i++)
ip_addrs[i].family = IPADDR_UNSPEC;
return DNS_Success; return DNS_Success;
} }

View file

@ -39,7 +39,7 @@ typedef enum {
/* Resolve names only to selected address family */ /* Resolve names only to selected address family */
extern void DNS_SetAddressFamily(int family); extern void DNS_SetAddressFamily(int family);
extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *addr); extern DNS_Status DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs);
extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len); extern int DNS_IPAddress2Name(IPAddr *ip_addr, char *name, int len);

View file

@ -37,12 +37,14 @@
#ifdef USE_PTHREAD_ASYNCDNS #ifdef USE_PTHREAD_ASYNCDNS
#include <pthread.h> #include <pthread.h>
#define MAX_ADDRESSES 16
/* ================================================== */ /* ================================================== */
struct DNS_Async_Instance { struct DNS_Async_Instance {
const char *name; const char *name;
DNS_Status status; DNS_Status status;
IPAddr addr; IPAddr addresses[MAX_ADDRESSES];
DNS_NameResolveHandler handler; DNS_NameResolveHandler handler;
void *arg; void *arg;
@ -59,7 +61,7 @@ start_resolving(void *anything)
{ {
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything; struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
inst->status = DNS_Name2IPAddress(inst->name, &inst->addr); inst->status = DNS_Name2IPAddress(inst->name, inst->addresses, MAX_ADDRESSES);
/* Notify the main thread that the result is ready */ /* Notify the main thread that the result is ready */
if (write(inst->pipe[1], "", 1) < 0) if (write(inst->pipe[1], "", 1) < 0)
@ -74,6 +76,7 @@ static void
end_resolving(void *anything) end_resolving(void *anything)
{ {
struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything; struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything;
int i;
if (pthread_join(inst->thread, NULL)) { if (pthread_join(inst->thread, NULL)) {
LOG_FATAL(LOGF_Nameserv, "pthread_join() failed"); LOG_FATAL(LOGF_Nameserv, "pthread_join() failed");
@ -85,7 +88,11 @@ end_resolving(void *anything)
close(inst->pipe[0]); close(inst->pipe[0]);
close(inst->pipe[1]); close(inst->pipe[1]);
(inst->handler)(inst->status, &inst->addr, inst->arg); for (i = 0; inst->status == DNS_Success && i < MAX_ADDRESSES &&
inst->addresses[i].family != IPADDR_UNSPEC; i++)
;
(inst->handler)(inst->status, i, inst->addresses, inst->arg);
Free(inst); Free(inst);
} }

View file

@ -31,7 +31,7 @@
#include "nameserv.h" #include "nameserv.h"
/* Function type for callback to process the result */ /* Function type for callback to process the result */
typedef void (*DNS_NameResolveHandler)(DNS_Status status, IPAddr *ip_addr, void *anything); typedef void (*DNS_NameResolveHandler)(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything);
/* Request resolving of a name to IP address. The handler will be /* Request resolving of a name to IP address. The handler will be
called when the result is available, but it may be also called called when the result is available, but it may be also called

View file

@ -300,7 +300,7 @@ NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParam
/* ================================================== */ /* ================================================== */
static void static void
name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything) name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *anything)
{ {
struct UnresolvedSource *us, **i, *next; struct UnresolvedSource *us, **i, *next;
NTP_Remote_Address address; NTP_Remote_Address address;
@ -313,8 +313,8 @@ name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything)
case DNS_TryAgain: case DNS_TryAgain:
break; break;
case DNS_Success: case DNS_Success:
DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(ip_addr)); DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(&ip_addrs[0]));
address.ip_addr = *ip_addr; address.ip_addr = ip_addrs[0];
address.port = us->port; address.port = us->port;
NSR_AddSource(&address, us->type, &us->params); NSR_AddSource(&address, us->type, &us->params);
break; break;

16
stubs.c
View file

@ -41,16 +41,24 @@
#ifndef FEAT_ASYNCDNS #ifndef FEAT_ASYNCDNS
#define MAX_ADDRESSES 16
/* This is a blocking implementation used when asynchronous resolving is not available */ /* This is a blocking implementation used when asynchronous resolving is not available */
void void
DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything) DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything)
{ {
IPAddr addr; IPAddr addrs[MAX_ADDRESSES];
DNS_Status status; DNS_Status status;
int i;
status = DNS_Name2IPAddress(name, &addr); status = DNS_Name2IPAddress(name, addrs, MAX_ADDRESSES);
(handler)(status, &addr, anything);
for (i = 0; status == DNS_Success && i < MAX_ADDRESSES &&
addrs[i].family != IPADDR_UNSPEC; i++)
;
(handler)(status, i, addrs, anything);
} }
#endif /* !FEAT_ASYNCDNS */ #endif /* !FEAT_ASYNCDNS */
@ -267,7 +275,7 @@ DNS_SetAddressFamily(int family)
} }
DNS_Status DNS_Status
DNS_Name2IPAddress(const char *name, IPAddr *addr) DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs)
{ {
return DNS_Failure; return DNS_Failure;
} }