diff --git a/client.c b/client.c index 7c01435..2e1866c 100644 --- a/client.c +++ b/client.c @@ -119,7 +119,7 @@ open_io(const char *hostname, int port) int on_off = 1; /* 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); exit(1); } @@ -233,7 +233,7 @@ read_mask_address(char *line, IPAddr *mask, IPAddr *address) } } } else { - if (DNS_Name2IPAddress(p, address) == DNS_Success) { + if (DNS_Name2IPAddress(p, address, 1) == DNS_Success) { bits_to_mask(-1, address->family, mask); return 1; } else { @@ -305,7 +305,7 @@ read_address_integer(char *line, IPAddr *address, int *value) fprintf(stderr, "Invalid syntax for address value\n"); ok = 0; } 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"); ok = 0; } else { @@ -333,7 +333,7 @@ read_address_double(char *line, IPAddr *address, double *value) fprintf(stderr, "Invalid syntax for address value\n"); ok = 0; } 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"); ok = 0; } 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) { /* 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"); return 0; } else { @@ -828,7 +828,7 @@ accheck_getaddr(char *line, IPAddr *addr) addr->addr.in4 = (a<<24) | (b<<16) | (c<<8) | d; return 1; } else { - if (DNS_Name2IPAddress(p, &ip) != DNS_Success) { + if (DNS_Name2IPAddress(p, &ip, 1) != DNS_Success) { return 0; } else { *addr = ip; @@ -935,7 +935,7 @@ process_cmd_add_server_or_peer(CMD_Request *msg, char *line) status = CPS_ParseNTPSourceAdd(line, &data); switch (status) { 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"); break; } @@ -1056,7 +1056,7 @@ process_cmd_delete(CMD_Request *msg, char *line) fprintf(stderr, "Invalid syntax for address\n"); ok = 0; } 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"); ok = 0; } else { diff --git a/conf.c b/conf.c index d14c53e..d29118d 100644 --- a/conf.c +++ b/conf.c @@ -817,7 +817,7 @@ parse_initstepslew(char *line) hostname = p; p = CPS_SplitWord(p); 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); } else { 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 { - 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->allow = allow; new_node->all = all; diff --git a/nameserv.c b/nameserv.c index 8134342..bb9309e 100644 --- a/nameserv.c +++ b/nameserv.c @@ -44,11 +44,11 @@ DNS_SetAddressFamily(int family) } DNS_Status -DNS_Name2IPAddress(const char *name, IPAddr *addr) +DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs) { #ifdef HAVE_GETADDRINFO struct addrinfo hints, *res, *ai; - int result; + int i, result; memset(&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; @@ -64,29 +64,37 @@ DNS_Name2IPAddress(const char *name, IPAddr *addr) #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) { case AF_INET: - addr->family = IPADDR_INET4; - addr->addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); - result = 1; + if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4) + continue; + ip_addrs[i].family = IPADDR_INET4; + ip_addrs[i].addr.in4 = ntohl(((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr); + i++; break; #ifdef FEAT_IPV6 case AF_INET6: - addr->family = IPADDR_INET6; - memcpy(&addr->addr.in6, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr.s6_addr, sizeof (addr->addr.in6)); - result = 1; + if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET6) + continue; + 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; #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); - return result ? DNS_Success : DNS_Failure; + + return !max_addrs || ip_addrs[0].family != IPADDR_UNSPEC ? DNS_Success : DNS_Failure; #else struct hostent *host; + int i; if (address_family != IPADDR_UNSPEC && address_family != IPADDR_INET4) 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]) return DNS_Failure; - addr->family = IPADDR_INET4; - addr->addr.in4 = ntohl(*(uint32_t *)host->h_addr_list[0]); + for (i = 0; host->h_addr_list[i] && i < max_addrs; i++) { + 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; } diff --git a/nameserv.h b/nameserv.h index 3980c1b..341a609 100644 --- a/nameserv.h +++ b/nameserv.h @@ -39,7 +39,7 @@ typedef enum { /* Resolve names only to selected address 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); diff --git a/nameserv_async.c b/nameserv_async.c index 82b2f7b..1ceeb28 100644 --- a/nameserv_async.c +++ b/nameserv_async.c @@ -37,12 +37,14 @@ #ifdef USE_PTHREAD_ASYNCDNS #include +#define MAX_ADDRESSES 16 + /* ================================================== */ struct DNS_Async_Instance { const char *name; DNS_Status status; - IPAddr addr; + IPAddr addresses[MAX_ADDRESSES]; DNS_NameResolveHandler handler; void *arg; @@ -59,7 +61,7 @@ start_resolving(void *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 */ if (write(inst->pipe[1], "", 1) < 0) @@ -74,6 +76,7 @@ static void end_resolving(void *anything) { struct DNS_Async_Instance *inst = (struct DNS_Async_Instance *)anything; + int i; if (pthread_join(inst->thread, NULL)) { LOG_FATAL(LOGF_Nameserv, "pthread_join() failed"); @@ -85,7 +88,11 @@ end_resolving(void *anything) close(inst->pipe[0]); 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); } diff --git a/nameserv_async.h b/nameserv_async.h index 5c1704e..cea2d82 100644 --- a/nameserv_async.h +++ b/nameserv_async.h @@ -31,7 +31,7 @@ #include "nameserv.h" /* 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 called when the result is available, but it may be also called diff --git a/ntp_sources.c b/ntp_sources.c index a638f8c..1e5acff 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -300,7 +300,7 @@ NSR_AddSource(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParam /* ================================================== */ 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; NTP_Remote_Address address; @@ -313,8 +313,8 @@ name_resolve_handler(DNS_Status status, IPAddr *ip_addr, void *anything) case DNS_TryAgain: break; case DNS_Success: - DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(ip_addr)); - address.ip_addr = *ip_addr; + DEBUG_LOG(LOGF_NtpSources, "%s resolved to %s", us->name, UTI_IPToString(&ip_addrs[0])); + address.ip_addr = ip_addrs[0]; address.port = us->port; NSR_AddSource(&address, us->type, &us->params); break; diff --git a/stubs.c b/stubs.c index aafd6d2..f8e7304 100644 --- a/stubs.c +++ b/stubs.c @@ -41,16 +41,24 @@ #ifndef FEAT_ASYNCDNS +#define MAX_ADDRESSES 16 + /* This is a blocking implementation used when asynchronous resolving is not available */ void DNS_Name2IPAddressAsync(const char *name, DNS_NameResolveHandler handler, void *anything) { - IPAddr addr; + IPAddr addrs[MAX_ADDRESSES]; DNS_Status status; + int i; - status = DNS_Name2IPAddress(name, &addr); - (handler)(status, &addr, anything); + status = DNS_Name2IPAddress(name, addrs, MAX_ADDRESSES); + + for (i = 0; status == DNS_Success && i < MAX_ADDRESSES && + addrs[i].family != IPADDR_UNSPEC; i++) + ; + + (handler)(status, i, addrs, anything); } #endif /* !FEAT_ASYNCDNS */ @@ -267,7 +275,7 @@ DNS_SetAddressFamily(int family) } DNS_Status -DNS_Name2IPAddress(const char *name, IPAddr *addr) +DNS_Name2IPAddress(const char *name, IPAddr *ip_addrs, int max_addrs) { return DNS_Failure; }