mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
Windows platform supports reading IPv6 addresses for DNS server. (#1701)
When using libevent on the Windows platform in an IPv6 environment, I found that libevent could not read the DNS server address for IPv6 addresses during DNS initialization, resulting in constant DNS resolution failures. Then, on MSDN, I discovered that the GetNetworkParams interface does not support obtaining IPv6 addresses, and they provided another interface, GetAdaptersAddresses, to obtain both IPv4 and IPv6 addresses. Therefore, I replaced the GetNetworkParams interface with the GetAdaptersAddresses interface. Please review whether this modification can be merged into the master branch. Reference MSDN documentation: https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getnetworkparams https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses Co-authored-by: alphacheng <alphacheng@tencent.com> Co-authored-by: Azat Khuzhin <azat@libevent.org> Co-authored-by: Azat Khuzhin <a3at.mail@gmail.com>
This commit is contained in:
parent
ffe913b9f9
commit
d6dbd7f818
@ -830,6 +830,7 @@ set(HDR_PRIVATE
|
|||||||
evrpc-internal.h
|
evrpc-internal.h
|
||||||
evsignal-internal.h
|
evsignal-internal.h
|
||||||
evthread-internal.h
|
evthread-internal.h
|
||||||
|
evdns-internal.h
|
||||||
ht-internal.h
|
ht-internal.h
|
||||||
http-internal.h
|
http-internal.h
|
||||||
iocp-internal.h
|
iocp-internal.h
|
||||||
|
@ -333,6 +333,7 @@ noinst_HEADERS += \
|
|||||||
evrpc-internal.h \
|
evrpc-internal.h \
|
||||||
evsignal-internal.h \
|
evsignal-internal.h \
|
||||||
evthread-internal.h \
|
evthread-internal.h \
|
||||||
|
evdns-internal.h \
|
||||||
ht-internal.h \
|
ht-internal.h \
|
||||||
http-internal.h \
|
http-internal.h \
|
||||||
iocp-internal.h \
|
iocp-internal.h \
|
||||||
|
22
evdns-internal.h
Normal file
22
evdns-internal.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef EVDNS_INTERNAL_H_INCLUDED_
|
||||||
|
#define EVDNS_INTERNAL_H_INCLUDED_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "event2/event_struct.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
EVENT2_EXPORT_SYMBOL
|
||||||
|
int load_nameservers_with_getadaptersaddresses(struct evdns_base *base);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
85
evdns.c
85
evdns.c
@ -104,6 +104,7 @@
|
|||||||
#include "ipv6-internal.h"
|
#include "ipv6-internal.h"
|
||||||
#include "util-internal.h"
|
#include "util-internal.h"
|
||||||
#include "evthread-internal.h"
|
#include "evthread-internal.h"
|
||||||
|
#include "evdns-internal.h"
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
@ -4621,21 +4622,20 @@ evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
|
typedef DWORD(WINAPI *GetAdaptersAddresses_fn_t)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
|
||||||
|
|
||||||
/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
|
/* Use the windows GetAdaptersAddresses interface in iphlpapi.dll to */
|
||||||
/* figure out what our nameservers are. */
|
/* figure out what our nameservers are. */
|
||||||
static int
|
static int
|
||||||
load_nameservers_with_getnetworkparams(struct evdns_base *base)
|
load_nameservers_with_getadaptersaddresses_unlocked(struct evdns_base *base)
|
||||||
{
|
{
|
||||||
/* Based on MSDN examples and inspection of c-ares code. */
|
PIP_ADAPTER_ADDRESSES addresses = NULL;
|
||||||
FIXED_INFO *fixed;
|
|
||||||
HMODULE handle = 0;
|
HMODULE handle = 0;
|
||||||
ULONG size = sizeof(FIXED_INFO);
|
ULONG size = sizeof(IP_ADAPTER_ADDRESSES);
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
int status = 0, r, added_any;
|
int status = 0, r, added_any = 0;
|
||||||
IP_ADDR_STRING *ns;
|
GetAdaptersAddresses_fn_t fn;
|
||||||
GetNetworkParams_fn_t fn;
|
IP_ADAPTER_DNS_SERVER_ADDRESS *dnsserver = NULL;
|
||||||
|
|
||||||
ASSERT_LOCKED(base);
|
ASSERT_LOCKED(base);
|
||||||
if (!(handle = evutil_load_windows_system_library_(
|
if (!(handle = evutil_load_windows_system_library_(
|
||||||
@ -4644,7 +4644,7 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
|
|||||||
status = -1;
|
status = -1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
|
if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(handle, "GetAdaptersAddresses"))) {
|
||||||
log(EVDNS_LOG_WARN, "Could not get address of function.");
|
log(EVDNS_LOG_WARN, "Could not get address of function.");
|
||||||
status = -1;
|
status = -1;
|
||||||
goto done;
|
goto done;
|
||||||
@ -4652,40 +4652,51 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
|
|||||||
|
|
||||||
buf = mm_malloc(size);
|
buf = mm_malloc(size);
|
||||||
if (!buf) { status = 4; goto done; }
|
if (!buf) { status = 4; goto done; }
|
||||||
fixed = buf;
|
addresses = buf;
|
||||||
r = fn(fixed, &size);
|
r = fn(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addresses, &size);
|
||||||
if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
|
if (r != NO_ERROR && r != ERROR_BUFFER_OVERFLOW) {
|
||||||
status = -1;
|
status = -1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (r != ERROR_SUCCESS) {
|
if (r != NO_ERROR) {
|
||||||
mm_free(buf);
|
mm_free(buf);
|
||||||
buf = mm_malloc(size);
|
buf = mm_malloc(size);
|
||||||
if (!buf) { status = 4; goto done; }
|
if (!buf) { status = 4; goto done; }
|
||||||
fixed = buf;
|
addresses = buf;
|
||||||
r = fn(fixed, &size);
|
r = fn(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addresses, &size);
|
||||||
if (r != ERROR_SUCCESS) {
|
if (r != NO_ERROR) {
|
||||||
log(EVDNS_LOG_DEBUG, "fn() failed.");
|
log(EVDNS_LOG_DEBUG, "fn() failed.");
|
||||||
status = -1;
|
status = -1;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EVUTIL_ASSERT(fixed);
|
while (addresses) {
|
||||||
added_any = 0;
|
dnsserver = addresses->FirstDnsServerAddress;
|
||||||
ns = &(fixed->DnsServerList);
|
while (dnsserver && (addresses->OperStatus == IfOperStatusUp)) {
|
||||||
while (ns) {
|
char ip[INET6_ADDRSTRLEN] = {0};
|
||||||
r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String);
|
if (AF_INET == dnsserver->Address.lpSockaddr->sa_family) {
|
||||||
if (r) {
|
inet_ntop(AF_INET, &((SOCKADDR_IN *)dnsserver->Address.lpSockaddr)->sin_addr, ip, sizeof(ip));
|
||||||
log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
|
} else if (AF_INET6 == dnsserver->Address.lpSockaddr->sa_family) {
|
||||||
(ns->IpAddress.String),(int)GetLastError());
|
inet_ntop(AF_INET6, &((SOCKADDR_IN6 *)dnsserver->Address.lpSockaddr)->sin6_addr, ip, sizeof(ip));
|
||||||
status = r;
|
}
|
||||||
} else {
|
|
||||||
++added_any;
|
|
||||||
log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
|
|
||||||
}
|
|
||||||
|
|
||||||
ns = ns->Next;
|
dnsserver = dnsserver->Next;
|
||||||
|
if (strncmp(ip, "fec0:", 5) == 0) { /* remove ipv6 reserved address */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = evdns_base_nameserver_ip_add(base, ip);
|
||||||
|
if (r) {
|
||||||
|
log(EVDNS_LOG_DEBUG, "Could not add nameserver %s to list, error: %d", ip, r);
|
||||||
|
status = r;
|
||||||
|
} else {
|
||||||
|
++added_any;
|
||||||
|
log(EVDNS_LOG_DEBUG, "Successfully added %s as nameserver", ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addresses = addresses->Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!added_any) {
|
if (!added_any) {
|
||||||
@ -4704,6 +4715,16 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
load_nameservers_with_getadaptersaddresses(struct evdns_base *base)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
EVDNS_LOCK(base);
|
||||||
|
r = load_nameservers_with_getadaptersaddresses_unlocked(base);
|
||||||
|
EVDNS_UNLOCK(base);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey)
|
config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey)
|
||||||
{
|
{
|
||||||
@ -4803,7 +4824,7 @@ evdns_base_config_windows_nameservers(struct evdns_base *base)
|
|||||||
if (fname)
|
if (fname)
|
||||||
mm_free(fname);
|
mm_free(fname);
|
||||||
|
|
||||||
if (load_nameservers_with_getnetworkparams(base) == 0) {
|
if (load_nameservers_with_getadaptersaddresses_unlocked(base) == 0) {
|
||||||
EVDNS_UNLOCK(base);
|
EVDNS_UNLOCK(base);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
#include <event2/thread.h>
|
#include <event2/thread.h>
|
||||||
#include "log-internal.h"
|
#include "log-internal.h"
|
||||||
#include "evthread-internal.h"
|
#include "evthread-internal.h"
|
||||||
|
#include "evdns-internal.h"
|
||||||
#include "regress.h"
|
#include "regress.h"
|
||||||
#include "regress_testutils.h"
|
#include "regress_testutils.h"
|
||||||
#include "regress_thread.h"
|
#include "regress_thread.h"
|
||||||
@ -1200,6 +1201,47 @@ end:
|
|||||||
evdns_base_free(dns, 0);
|
evdns_base_free(dns, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static void
|
||||||
|
windows_dns_initialize_ipv6_nameservers_test(void *arg)
|
||||||
|
{
|
||||||
|
struct basic_test_data *data = arg;
|
||||||
|
struct event_base *base = data->base;
|
||||||
|
struct evdns_base *dns = NULL;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
int i = 0, count = 0, ipv6_count = 0, size = 0;
|
||||||
|
int sockfd = 0;
|
||||||
|
|
||||||
|
dns = evdns_base_new(base, 0);
|
||||||
|
tt_assert(dns);
|
||||||
|
|
||||||
|
tt_int_op(load_nameservers_with_getadaptersaddresses(dns), ==, 0);
|
||||||
|
count = evdns_base_count_nameservers(dns);
|
||||||
|
tt_int_op(count, >, 0);
|
||||||
|
|
||||||
|
sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
event_warn("socket(AF_INET6) failed. Skipping test.");
|
||||||
|
tt_skip();
|
||||||
|
}
|
||||||
|
evutil_closesocket(sockfd);
|
||||||
|
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
size = evdns_base_get_nameserver_addr(dns, i, (struct sockaddr *)&ss, sizeof(ss));
|
||||||
|
tt_int_op(size, >, 0);
|
||||||
|
if (ss.ss_family == AF_INET6) {
|
||||||
|
ipv6_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* CI environment does not have IPv6 addresses, so we cannot assert on this one */
|
||||||
|
TT_BLATHER(("Found %i IPv6 addresses", ipv6_count));
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (dns)
|
||||||
|
evdns_base_free(dns, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *dns_resolvconf_with_one_nameserver =
|
static const char *dns_resolvconf_with_one_nameserver =
|
||||||
"nameserver 127.0.0.53\n";
|
"nameserver 127.0.0.53\n";
|
||||||
|
|
||||||
@ -3273,6 +3315,12 @@ struct testcase_t dns_testcases[] = {
|
|||||||
|
|
||||||
{ "initialize_nameservers", dns_initialize_nameservers_test,
|
{ "initialize_nameservers", dns_initialize_nameservers_test,
|
||||||
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
|
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
{ "windows_initialize_ipv6_nameservers", windows_dns_initialize_ipv6_nameservers_test,
|
||||||
|
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
{"initialize_with_one_inactive_nameserver", dns_initialize_inactive_one_nameserver_test,
|
{"initialize_with_one_inactive_nameserver", dns_initialize_inactive_one_nameserver_test,
|
||||||
TT_FORK | TT_NEED_BASE, &basic_setup, NULL},
|
TT_FORK | TT_NEED_BASE, &basic_setup, NULL},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user