mirror of
https://github.com/libevent/libevent.git
synced 2025-01-09 00:56:20 +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
|
||||
evsignal-internal.h
|
||||
evthread-internal.h
|
||||
evdns-internal.h
|
||||
ht-internal.h
|
||||
http-internal.h
|
||||
iocp-internal.h
|
||||
|
@ -333,6 +333,7 @@ noinst_HEADERS += \
|
||||
evrpc-internal.h \
|
||||
evsignal-internal.h \
|
||||
evthread-internal.h \
|
||||
evdns-internal.h \
|
||||
ht-internal.h \
|
||||
http-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 "util-internal.h"
|
||||
#include "evthread-internal.h"
|
||||
#include "evdns-internal.h"
|
||||
#ifdef _WIN32
|
||||
#include <ctype.h>
|
||||
#include <winsock2.h>
|
||||
@ -4621,21 +4622,20 @@ evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
|
||||
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. */
|
||||
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. */
|
||||
FIXED_INFO *fixed;
|
||||
PIP_ADAPTER_ADDRESSES addresses = NULL;
|
||||
HMODULE handle = 0;
|
||||
ULONG size = sizeof(FIXED_INFO);
|
||||
ULONG size = sizeof(IP_ADAPTER_ADDRESSES);
|
||||
void *buf = NULL;
|
||||
int status = 0, r, added_any;
|
||||
IP_ADDR_STRING *ns;
|
||||
GetNetworkParams_fn_t fn;
|
||||
int status = 0, r, added_any = 0;
|
||||
GetAdaptersAddresses_fn_t fn;
|
||||
IP_ADAPTER_DNS_SERVER_ADDRESS *dnsserver = NULL;
|
||||
|
||||
ASSERT_LOCKED(base);
|
||||
if (!(handle = evutil_load_windows_system_library_(
|
||||
@ -4644,7 +4644,7 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
|
||||
status = -1;
|
||||
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.");
|
||||
status = -1;
|
||||
goto done;
|
||||
@ -4652,40 +4652,51 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
|
||||
|
||||
buf = mm_malloc(size);
|
||||
if (!buf) { status = 4; goto done; }
|
||||
fixed = buf;
|
||||
r = fn(fixed, &size);
|
||||
if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
|
||||
addresses = buf;
|
||||
r = fn(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addresses, &size);
|
||||
if (r != NO_ERROR && r != ERROR_BUFFER_OVERFLOW) {
|
||||
status = -1;
|
||||
goto done;
|
||||
}
|
||||
if (r != ERROR_SUCCESS) {
|
||||
if (r != NO_ERROR) {
|
||||
mm_free(buf);
|
||||
buf = mm_malloc(size);
|
||||
if (!buf) { status = 4; goto done; }
|
||||
fixed = buf;
|
||||
r = fn(fixed, &size);
|
||||
if (r != ERROR_SUCCESS) {
|
||||
addresses = buf;
|
||||
r = fn(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addresses, &size);
|
||||
if (r != NO_ERROR) {
|
||||
log(EVDNS_LOG_DEBUG, "fn() failed.");
|
||||
status = -1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
EVUTIL_ASSERT(fixed);
|
||||
added_any = 0;
|
||||
ns = &(fixed->DnsServerList);
|
||||
while (ns) {
|
||||
r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String);
|
||||
if (r) {
|
||||
log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
|
||||
(ns->IpAddress.String),(int)GetLastError());
|
||||
status = r;
|
||||
} else {
|
||||
++added_any;
|
||||
log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
|
||||
}
|
||||
while (addresses) {
|
||||
dnsserver = addresses->FirstDnsServerAddress;
|
||||
while (dnsserver && (addresses->OperStatus == IfOperStatusUp)) {
|
||||
char ip[INET6_ADDRSTRLEN] = {0};
|
||||
if (AF_INET == dnsserver->Address.lpSockaddr->sa_family) {
|
||||
inet_ntop(AF_INET, &((SOCKADDR_IN *)dnsserver->Address.lpSockaddr)->sin_addr, ip, sizeof(ip));
|
||||
} else if (AF_INET6 == dnsserver->Address.lpSockaddr->sa_family) {
|
||||
inet_ntop(AF_INET6, &((SOCKADDR_IN6 *)dnsserver->Address.lpSockaddr)->sin6_addr, ip, sizeof(ip));
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -4704,6 +4715,16 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
|
||||
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
|
||||
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)
|
||||
mm_free(fname);
|
||||
|
||||
if (load_nameservers_with_getnetworkparams(base) == 0) {
|
||||
if (load_nameservers_with_getadaptersaddresses_unlocked(base) == 0) {
|
||||
EVDNS_UNLOCK(base);
|
||||
return 0;
|
||||
}
|
||||
|
@ -78,6 +78,7 @@
|
||||
#include <event2/thread.h>
|
||||
#include "log-internal.h"
|
||||
#include "evthread-internal.h"
|
||||
#include "evdns-internal.h"
|
||||
#include "regress.h"
|
||||
#include "regress_testutils.h"
|
||||
#include "regress_thread.h"
|
||||
@ -1200,6 +1201,47 @@ end:
|
||||
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 =
|
||||
"nameserver 127.0.0.53\n";
|
||||
|
||||
@ -3273,6 +3315,12 @@ struct testcase_t dns_testcases[] = {
|
||||
|
||||
{ "initialize_nameservers", dns_initialize_nameservers_test,
|
||||
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
|
||||
{"initialize_with_one_inactive_nameserver", dns_initialize_inactive_one_nameserver_test,
|
||||
TT_FORK | TT_NEED_BASE, &basic_setup, NULL},
|
||||
|
Loading…
x
Reference in New Issue
Block a user