Skip to content

Commit d6dbd7f

Browse files
Cxd2014alphachengazat
authored
Windows platform supports reading IPv6 addresses for DNS server. (libevent#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 <[email protected]> Co-authored-by: Azat Khuzhin <[email protected]> Co-authored-by: Azat Khuzhin <[email protected]>
1 parent ffe913b commit d6dbd7f

File tree

5 files changed

+125
-32
lines changed

5 files changed

+125
-32
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ set(HDR_PRIVATE
830830
evrpc-internal.h
831831
evsignal-internal.h
832832
evthread-internal.h
833+
evdns-internal.h
833834
ht-internal.h
834835
http-internal.h
835836
iocp-internal.h

Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ noinst_HEADERS += \
333333
evrpc-internal.h \
334334
evsignal-internal.h \
335335
evthread-internal.h \
336+
evdns-internal.h \
336337
ht-internal.h \
337338
http-internal.h \
338339
iocp-internal.h \

evdns-internal.h

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#ifndef EVDNS_INTERNAL_H_INCLUDED_
2+
#define EVDNS_INTERNAL_H_INCLUDED_
3+
4+
#ifdef __cplusplus
5+
extern "C" {
6+
#endif
7+
8+
#include "event2/event_struct.h"
9+
10+
#ifdef _WIN32
11+
12+
EVENT2_EXPORT_SYMBOL
13+
int load_nameservers_with_getadaptersaddresses(struct evdns_base *base);
14+
15+
#endif
16+
17+
#ifdef __cplusplus
18+
}
19+
#endif
20+
21+
#endif
22+

evdns.c

+53-32
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
#include "ipv6-internal.h"
105105
#include "util-internal.h"
106106
#include "evthread-internal.h"
107+
#include "evdns-internal.h"
107108
#ifdef _WIN32
108109
#include <ctype.h>
109110
#include <winsock2.h>
@@ -4621,21 +4622,20 @@ evdns_nameserver_ip_add_line(struct evdns_base *base, const char *ips) {
46214622
return 0;
46224623
}
46234624

4624-
typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
4625+
typedef DWORD(WINAPI *GetAdaptersAddresses_fn_t)(ULONG, ULONG, PVOID, PIP_ADAPTER_ADDRESSES, PULONG);
46254626

4626-
/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
4627+
/* Use the windows GetAdaptersAddresses interface in iphlpapi.dll to */
46274628
/* figure out what our nameservers are. */
46284629
static int
4629-
load_nameservers_with_getnetworkparams(struct evdns_base *base)
4630+
load_nameservers_with_getadaptersaddresses_unlocked(struct evdns_base *base)
46304631
{
4631-
/* Based on MSDN examples and inspection of c-ares code. */
4632-
FIXED_INFO *fixed;
4632+
PIP_ADAPTER_ADDRESSES addresses = NULL;
46334633
HMODULE handle = 0;
4634-
ULONG size = sizeof(FIXED_INFO);
4634+
ULONG size = sizeof(IP_ADAPTER_ADDRESSES);
46354635
void *buf = NULL;
4636-
int status = 0, r, added_any;
4637-
IP_ADDR_STRING *ns;
4638-
GetNetworkParams_fn_t fn;
4636+
int status = 0, r, added_any = 0;
4637+
GetAdaptersAddresses_fn_t fn;
4638+
IP_ADAPTER_DNS_SERVER_ADDRESS *dnsserver = NULL;
46394639

46404640
ASSERT_LOCKED(base);
46414641
if (!(handle = evutil_load_windows_system_library_(
@@ -4644,48 +4644,59 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
46444644
status = -1;
46454645
goto done;
46464646
}
4647-
if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
4647+
if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(handle, "GetAdaptersAddresses"))) {
46484648
log(EVDNS_LOG_WARN, "Could not get address of function.");
46494649
status = -1;
46504650
goto done;
46514651
}
46524652

46534653
buf = mm_malloc(size);
46544654
if (!buf) { status = 4; goto done; }
4655-
fixed = buf;
4656-
r = fn(fixed, &size);
4657-
if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
4655+
addresses = buf;
4656+
r = fn(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addresses, &size);
4657+
if (r != NO_ERROR && r != ERROR_BUFFER_OVERFLOW) {
46584658
status = -1;
46594659
goto done;
46604660
}
4661-
if (r != ERROR_SUCCESS) {
4661+
if (r != NO_ERROR) {
46624662
mm_free(buf);
46634663
buf = mm_malloc(size);
46644664
if (!buf) { status = 4; goto done; }
4665-
fixed = buf;
4666-
r = fn(fixed, &size);
4667-
if (r != ERROR_SUCCESS) {
4665+
addresses = buf;
4666+
r = fn(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addresses, &size);
4667+
if (r != NO_ERROR) {
46684668
log(EVDNS_LOG_DEBUG, "fn() failed.");
46694669
status = -1;
46704670
goto done;
46714671
}
46724672
}
46734673

4674-
EVUTIL_ASSERT(fixed);
4675-
added_any = 0;
4676-
ns = &(fixed->DnsServerList);
4677-
while (ns) {
4678-
r = evdns_nameserver_ip_add_line(base, ns->IpAddress.String);
4679-
if (r) {
4680-
log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
4681-
(ns->IpAddress.String),(int)GetLastError());
4682-
status = r;
4683-
} else {
4684-
++added_any;
4685-
log(EVDNS_LOG_DEBUG,"Successfully added %s as nameserver",ns->IpAddress.String);
4686-
}
4674+
while (addresses) {
4675+
dnsserver = addresses->FirstDnsServerAddress;
4676+
while (dnsserver && (addresses->OperStatus == IfOperStatusUp)) {
4677+
char ip[INET6_ADDRSTRLEN] = {0};
4678+
if (AF_INET == dnsserver->Address.lpSockaddr->sa_family) {
4679+
inet_ntop(AF_INET, &((SOCKADDR_IN *)dnsserver->Address.lpSockaddr)->sin_addr, ip, sizeof(ip));
4680+
} else if (AF_INET6 == dnsserver->Address.lpSockaddr->sa_family) {
4681+
inet_ntop(AF_INET6, &((SOCKADDR_IN6 *)dnsserver->Address.lpSockaddr)->sin6_addr, ip, sizeof(ip));
4682+
}
46874683

4688-
ns = ns->Next;
4684+
dnsserver = dnsserver->Next;
4685+
if (strncmp(ip, "fec0:", 5) == 0) { /* remove ipv6 reserved address */
4686+
continue;
4687+
}
4688+
4689+
r = evdns_base_nameserver_ip_add(base, ip);
4690+
if (r) {
4691+
log(EVDNS_LOG_DEBUG, "Could not add nameserver %s to list, error: %d", ip, r);
4692+
status = r;
4693+
} else {
4694+
++added_any;
4695+
log(EVDNS_LOG_DEBUG, "Successfully added %s as nameserver", ip);
4696+
}
4697+
}
4698+
4699+
addresses = addresses->Next;
46894700
}
46904701

46914702
if (!added_any) {
@@ -4704,6 +4715,16 @@ load_nameservers_with_getnetworkparams(struct evdns_base *base)
47044715
return status;
47054716
}
47064717

4718+
int
4719+
load_nameservers_with_getadaptersaddresses(struct evdns_base *base)
4720+
{
4721+
int r;
4722+
EVDNS_LOCK(base);
4723+
r = load_nameservers_with_getadaptersaddresses_unlocked(base);
4724+
EVDNS_UNLOCK(base);
4725+
return r;
4726+
}
4727+
47074728
static int
47084729
config_nameserver_from_reg_key(struct evdns_base *base, HKEY key, const TCHAR *subkey)
47094730
{
@@ -4803,7 +4824,7 @@ evdns_base_config_windows_nameservers(struct evdns_base *base)
48034824
if (fname)
48044825
mm_free(fname);
48054826

4806-
if (load_nameservers_with_getnetworkparams(base) == 0) {
4827+
if (load_nameservers_with_getadaptersaddresses_unlocked(base) == 0) {
48074828
EVDNS_UNLOCK(base);
48084829
return 0;
48094830
}

test/regress_dns.c

+48
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
#include <event2/thread.h>
7979
#include "log-internal.h"
8080
#include "evthread-internal.h"
81+
#include "evdns-internal.h"
8182
#include "regress.h"
8283
#include "regress_testutils.h"
8384
#include "regress_thread.h"
@@ -1200,6 +1201,47 @@ dns_initialize_nameservers_test(void *arg)
12001201
evdns_base_free(dns, 0);
12011202
}
12021203

1204+
#ifdef _WIN32
1205+
static void
1206+
windows_dns_initialize_ipv6_nameservers_test(void *arg)
1207+
{
1208+
struct basic_test_data *data = arg;
1209+
struct event_base *base = data->base;
1210+
struct evdns_base *dns = NULL;
1211+
struct sockaddr_storage ss;
1212+
int i = 0, count = 0, ipv6_count = 0, size = 0;
1213+
int sockfd = 0;
1214+
1215+
dns = evdns_base_new(base, 0);
1216+
tt_assert(dns);
1217+
1218+
tt_int_op(load_nameservers_with_getadaptersaddresses(dns), ==, 0);
1219+
count = evdns_base_count_nameservers(dns);
1220+
tt_int_op(count, >, 0);
1221+
1222+
sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
1223+
if (sockfd < 0) {
1224+
event_warn("socket(AF_INET6) failed. Skipping test.");
1225+
tt_skip();
1226+
}
1227+
evutil_closesocket(sockfd);
1228+
1229+
for (i = 0; i < count; ++i) {
1230+
size = evdns_base_get_nameserver_addr(dns, i, (struct sockaddr *)&ss, sizeof(ss));
1231+
tt_int_op(size, >, 0);
1232+
if (ss.ss_family == AF_INET6) {
1233+
ipv6_count++;
1234+
}
1235+
}
1236+
/* CI environment does not have IPv6 addresses, so we cannot assert on this one */
1237+
TT_BLATHER(("Found %i IPv6 addresses", ipv6_count));
1238+
1239+
end:
1240+
if (dns)
1241+
evdns_base_free(dns, 0);
1242+
}
1243+
#endif
1244+
12031245
static const char *dns_resolvconf_with_one_nameserver =
12041246
"nameserver 127.0.0.53\n";
12051247

@@ -3273,6 +3315,12 @@ struct testcase_t dns_testcases[] = {
32733315

32743316
{ "initialize_nameservers", dns_initialize_nameservers_test,
32753317
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
3318+
3319+
#ifdef _WIN32
3320+
{ "windows_initialize_ipv6_nameservers", windows_dns_initialize_ipv6_nameservers_test,
3321+
TT_FORK|TT_NEED_BASE, &basic_setup, NULL },
3322+
#endif
3323+
32763324
#ifndef _WIN32
32773325
{"initialize_with_one_inactive_nameserver", dns_initialize_inactive_one_nameserver_test,
32783326
TT_FORK | TT_NEED_BASE, &basic_setup, NULL},

0 commit comments

Comments
 (0)