Skip to content

Commit fc532f2

Browse files
fix(dns): fix crash on Windows system DNS
Replace the Windows API, which in a multithreaded environment became a reason for crashes during the DNS resolution process. Co-authored-by: Kamil Gronek <[email protected]>
1 parent ac7016e commit fc532f2

File tree

6 files changed

+104
-56
lines changed

6 files changed

+104
-56
lines changed

.github/workflows/commands-handler.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ jobs:
2424
run: echo -e "\033[38;2;19;181;255mThis is regular commit which should be ignored.\033[0m"
2525
- name: Checkout repository
2626
if: steps.user-check.outputs.expected-user == 'true'
27-
uses: actions/checkout@v4
27+
uses: actions/checkout@v5
2828
with:
2929
token: ${{ secrets.GH_TOKEN }}
3030
- name: Checkout release actions
3131
if: steps.user-check.outputs.expected-user == 'true'
32-
uses: actions/checkout@v4
32+
uses: actions/checkout@v5
3333
with:
3434
repository: pubnub/client-engineering-deployment-tools
3535
ref: v1

.github/workflows/composite/unit-test-framework/action.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ runs:
2727
${{ inputs.os }}-cgreen-${{ inputs.version }}-
2828
- name: Checkout Unit Test framework
2929
if: steps.unit-test-framework.outputs.cache-hit != 'true'
30-
uses: actions/checkout@v4
30+
uses: actions/checkout@v5
3131
with:
3232
repository: cgreen-devs/cgreen
3333
ref: ${{ matrix.cgreen }}

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
release: ${{ steps.check.outputs.ready }}
1616
steps:
1717
- name: Checkout actions
18-
uses: actions/checkout@v4
18+
uses: actions/checkout@v5
1919
with:
2020
repository: pubnub/client-engineering-deployment-tools
2121
ref: v1
@@ -34,13 +34,13 @@ jobs:
3434
group: organization/Default
3535
steps:
3636
- name: Checkout repository
37-
uses: actions/checkout@v4
37+
uses: actions/checkout@v5
3838
with:
3939
# This should be the same as the one specified for on.pull_request.branches
4040
ref: master
4141
token: ${{ secrets.GH_TOKEN }}
4242
- name: Checkout actions
43-
uses: actions/checkout@v4
43+
uses: actions/checkout@v5
4444
with:
4545
repository: pubnub/client-engineering-deployment-tools
4646
ref: v1

.github/workflows/run-tests.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ jobs:
2525
# group: organization/macos-gh
2626
steps:
2727
- name: Checkout project
28-
uses: actions/checkout@v4
28+
uses: actions/checkout@v5
2929
with:
3030
token: ${{ secrets.GH_TOKEN }}
3131
- name: Checkout actions
32-
uses: actions/checkout@v4
32+
uses: actions/checkout@v5
3333
with:
3434
repository: pubnub/client-engineering-deployment-tools
3535
ref: v1
@@ -59,11 +59,11 @@ jobs:
5959
sudo apt-get install -y ninja-build libboost-all-dev libssl-dev libgtest-dev nlohmann-json3-dev libasio-dev libtclap-dev g++ cmake
6060
sudo gem install cucumber
6161
- name: Checkout project
62-
uses: actions/checkout@v4
62+
uses: actions/checkout@v5
6363
with:
6464
token: ${{ secrets.GH_TOKEN }}
6565
- name: Checkout mock-server action
66-
uses: actions/checkout@v4
66+
uses: actions/checkout@v5
6767
with:
6868
repository: pubnub/client-engineering-deployment-tools
6969
ref: v1
@@ -84,7 +84,7 @@ jobs:
8484
${{ runner.os }}-cucumber-cpp-
8585
- name: Checkout Cucumber
8686
if: steps.cucumber-cpp.outputs.cache-hit != 'true'
87-
uses: actions/checkout@v4
87+
uses: actions/checkout@v5
8888
with:
8989
repository: cucumber/cucumber-cpp
9090
ref: c79100eb70fbb34f6ea10030cec051c2cc9f7961

.github/workflows/run-validations.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ jobs:
99
group: organization/Default
1010
steps:
1111
- name: Checkout project
12-
uses: actions/checkout@v4
12+
uses: actions/checkout@v5
1313
- name: Checkout validator action
14-
uses: actions/checkout@v4
14+
uses: actions/checkout@v5
1515
with:
1616
repository: pubnub/client-engineering-deployment-tools
1717
ref: v1

windows/pubnub_dns_system_servers.c

Lines changed: 91 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,116 @@
22
#include "pubnub_internal.h"
33

44
#include "core/pubnub_dns_servers.h"
5-
#include "lib/pubnub_parse_ipv4_addr.h"
65
#include "core/pubnub_assert.h"
76
#include "core/pubnub_log.h"
87

98
#include <winsock2.h>
109
#include <iphlpapi.h>
11-
#include <stdio.h>
1210
#include <windows.h>
13-
11+
#include <string.h>
1412

1513
#pragma comment(lib, "IPHLPAPI.lib")
1614

17-
1815
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
1916
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
2017

18+
19+
/* Check if an IPv4 address already exists in the array */
20+
static int ipv4_already_exists(
21+
const struct pubnub_ipv4_address* array,
22+
const size_t count,
23+
const unsigned char new_ip[4])
24+
{
25+
for (size_t i = 0; i < count; i++) {
26+
if (memcmp(array[i].ipv4, new_ip, 4) == 0) {
27+
return 1; /* Found duplicate */
28+
}
29+
}
30+
return 0; /* Not found */
31+
}
32+
2133
int pubnub_dns_read_system_servers_ipv4(struct pubnub_ipv4_address* o_ipv4, size_t n)
2234
{
23-
FIXED_INFO* pFixedInfo;
24-
ULONG ulOutBufLen;
25-
DWORD dwRetVal;
26-
IP_ADDR_STRING* pIPAddr;
27-
unsigned j;
28-
29-
pFixedInfo = (FIXED_INFO*)MALLOC(sizeof(FIXED_INFO));
30-
if (pFixedInfo == NULL) {
31-
PUBNUB_LOG_ERROR(
32-
"Error allocating memory needed to call GetNetworkParams\n");
33-
return -1;
35+
ULONG buflen;
36+
DWORD ret;
37+
IP_ADAPTER_ADDRESSES* addrs;
38+
IP_ADAPTER_ADDRESSES* aa;
39+
IP_ADAPTER_DNS_SERVER_ADDRESS* ds;
40+
const struct sockaddr_in* sin;
41+
DWORD net_addr;
42+
unsigned j;
43+
unsigned char temp_ip[4];
44+
45+
if (!o_ipv4 || n == 0) {
46+
return 0;
3447
}
35-
ulOutBufLen = sizeof(FIXED_INFO);
36-
37-
// Make an initial call to GetAdaptersInfo to get
38-
// the necessary size into the ulOutBufLen variable
39-
if (GetNetworkParams(pFixedInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
40-
FREE(pFixedInfo);
41-
pFixedInfo = (FIXED_INFO*)MALLOC(ulOutBufLen);
42-
if (pFixedInfo == NULL) {
43-
PUBNUB_LOG_ERROR(
44-
"Error allocating memory needed to call GetNetworkParams\n");
45-
return -1;
46-
}
48+
49+
buflen = 0;
50+
j = 0;
51+
52+
/* Get required buffer size */
53+
ret = GetAdaptersAddresses(
54+
AF_INET,
55+
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, /* keep DNS servers */
56+
NULL, NULL, &buflen
57+
);
58+
59+
if (ret != ERROR_BUFFER_OVERFLOW || buflen == 0) {
60+
PUBNUB_LOG_ERROR("GetAdaptersAddresses preflight failed: %lu\n", (unsigned long)ret);
61+
return -1;
4762
}
48-
dwRetVal = GetNetworkParams(pFixedInfo, &ulOutBufLen);
49-
if (NO_ERROR == dwRetVal) {
50-
j = 0;
51-
pIPAddr = &pFixedInfo->DnsServerList;
52-
while ((j < n) && pIPAddr) {
53-
struct pubnub_ipv4_address addr;
54-
if (pubnub_parse_ipv4_addr(pIPAddr->IpAddress.String, &addr) == 0) {
55-
memcpy(o_ipv4[j++].ipv4, addr.ipv4, sizeof o_ipv4[0].ipv4);
56-
}
57-
pIPAddr = pIPAddr->Next;
58-
}
63+
64+
addrs = (IP_ADAPTER_ADDRESSES*)MALLOC(buflen);
65+
if (!addrs) {
66+
PUBNUB_LOG_ERROR("OOM allocating %lu for GetAdaptersAddresses\n", (unsigned long)buflen);
67+
return -1;
5968
}
60-
else {
61-
PUBNUB_LOG_ERROR("GetNetworkParams failed with error: %d\n", dwRetVal);
62-
FREE(pFixedInfo);
69+
70+
/* Get adapter information */
71+
ret = GetAdaptersAddresses(
72+
AF_INET,
73+
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST, /* keep DNS servers */
74+
NULL, addrs, &buflen
75+
);
76+
if (ret != NO_ERROR) {
77+
PUBNUB_LOG_ERROR("GetAdaptersAddresses failed: %lu\n", (unsigned long)ret);
78+
FREE(addrs);
6379
return -1;
6480
}
6581

66-
FREE(pFixedInfo);
82+
/* Enumerate adapters and collect unique DNS servers */
83+
for (aa = addrs; aa && j < n; aa = aa->Next) {
84+
for (ds = aa->FirstDnsServerAddress; ds && j < n; ds = ds->Next) {
85+
if (!ds->Address.lpSockaddr ||
86+
ds->Address.lpSockaddr->sa_family != AF_INET) {
87+
continue;
88+
}
89+
90+
sin = (const struct sockaddr_in*)ds->Address.lpSockaddr;
91+
net_addr = sin->sin_addr.S_un.S_addr;
92+
if (net_addr == 0) {
93+
continue; /* skip 0.0.0.0 */
94+
}
95+
96+
/* Convert from network order to host order, then extract bytes */
97+
{
98+
DWORD host_addr = ntohl(net_addr);
99+
temp_ip[0] = (unsigned char)((host_addr >> 24) & 0xFF);
100+
temp_ip[1] = (unsigned char)((host_addr >> 16) & 0xFF);
101+
temp_ip[2] = (unsigned char)((host_addr >> 8) & 0xFF);
102+
temp_ip[3] = (unsigned char)( host_addr & 0xFF);
103+
}
104+
105+
if (!ipv4_already_exists(o_ipv4, j, temp_ip)) {
106+
o_ipv4[j].ipv4[0] = temp_ip[0];
107+
o_ipv4[j].ipv4[1] = temp_ip[1];
108+
o_ipv4[j].ipv4[2] = temp_ip[2];
109+
o_ipv4[j].ipv4[3] = temp_ip[3];
110+
++j;
111+
}
112+
}
113+
}
67114

68-
return j;
115+
FREE(addrs);
116+
return (int)j;
69117
}

0 commit comments

Comments
 (0)