Skip to content

Commit da2501f

Browse files
authored
Merge pull request #126 from baranyaib90/fixes-7
Fixes 7
2 parents 750c4db + 6aa3510 commit da2501f

File tree

11 files changed

+117
-72
lines changed

11 files changed

+117
-72
lines changed

.github/workflows/cmake.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
name: CMake
22

3-
on:
4-
push:
5-
branches: [ master ]
6-
pull_request:
7-
branches: [ master ]
3+
on: [push, pull_request]
84

95
jobs:
106
build:
117
# The CMake configure and build commands are platform agnostic and should work equally
128
# well on Windows or Mac. You can convert this to a matrix build if you need
139
# cross-platform coverage.
1410
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
15-
runs-on: ubuntu-latest
11+
runs-on: ubuntu-20.04
1612

1713
strategy:
1814
matrix:
19-
compiler: [gcc, clang]
15+
compiler: [gcc-10, clang-12]
2016

2117
steps:
2218
- uses: actions/checkout@v2
23-
19+
2420
- name: Update APT
2521
run: sudo apt-get update
2622

2723
- name: Setup Dependencies
28-
run: sudo apt-get install cmake libc-ares-dev libcurl4-openssl-dev libev-dev build-essential clang clang-tidy
24+
run: sudo apt-get install cmake libc-ares-dev libcurl4-openssl-dev libev-dev build-essential clang-tidy-12 ${{ matrix.compiler }}
25+
26+
- name: Set clang-tidy
27+
run: sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-12 100
2928

3029
- name: Configure CMake
3130
env:

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ if(NOT CLANG_TIDY_EXE)
5858
message(STATUS "clang-tidy not found.")
5959
else()
6060
message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}")
61-
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-fix" "-checks=*,-clang-analyzer-alpha.*,-misc-unused-parameters,-cert-err34-c,-google-readability-todo,-hicpp-signed-bitwise,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-gnu-folding-constant,-gnu-zero-variadic-macro-arguments")
61+
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-fix" "-checks=*,-clang-analyzer-alpha.*,-misc-unused-parameters,-cert-err34-c,-google-readability-todo,-hicpp-signed-bitwise,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-gnu-folding-constant,-gnu-zero-variadic-macro-arguments,-readability-function-cognitive-complexity,-concurrency-mt-unsafe")
6262
endif()
6363

6464
# The main binary

src/dns_poller.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ static ev_tstamp get_timeout(dns_poller_t *d)
9797
static struct timeval max_tv = {.tv_sec = 5, .tv_usec = 0};
9898
struct timeval tv;
9999
struct timeval *tvp = ares_timeout(d->ares, &max_tv, &tv);
100+
// NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)
100101
ev_tstamp after = tvp->tv_sec + tvp->tv_usec * 1e-6;
101102
return after ? after : 0.1;
102103
}

src/dns_server.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ static void watcher_cb(struct ev_loop __attribute__((unused)) *loop,
6565
struct sockaddr_storage raddr;
6666
/* recvfrom can write to addrlen */
6767
socklen_t tmp_addrlen = d->addrlen;
68-
int len = recvfrom(w->fd, buf, REQUEST_MAX, 0, (struct sockaddr*)&raddr,
69-
&tmp_addrlen);
68+
ssize_t len = recvfrom(w->fd, buf, REQUEST_MAX, 0, (struct sockaddr*)&raddr,
69+
&tmp_addrlen);
7070
if (len < 0) {
7171
ELOG("recvfrom failed: %s", strerror(errno));
7272
return;
@@ -96,7 +96,7 @@ void dns_server_init(dns_server_t *d, struct ev_loop *loop,
9696
}
9797

9898
void dns_server_respond(dns_server_t *d, struct sockaddr *raddr, char *buf,
99-
int blen) {
99+
size_t blen) {
100100
ssize_t len = sendto(d->sock, buf, blen, 0, raddr, d->addrlen);
101101
if(len == -1) {
102102
DLOG("sendto failed: %s", strerror(errno));

src/dns_server.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void dns_server_init(dns_server_t *d, struct ev_loop *loop,
2626

2727
// Sends a DNS response 'buf' of length 'blen' to 'raddr'.
2828
void dns_server_respond(dns_server_t *d, struct sockaddr *raddr, char *buf,
29-
int blen);
29+
size_t blen);
3030

3131
void dns_server_stop(dns_server_t *d);
3232

src/https_client.c

Lines changed: 79 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
#include <stdio.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
77
#include <string.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
88
#include <sys/socket.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
9-
#include <unistd.h>
9+
#include <unistd.h> // NOLINT(llvmlibc-restrict-system-libc-headers)
1010

1111
#include "https_client.h"
1212
#include "logging.h"
1313
#include "options.h"
1414

1515
#define DOH_CONTENT_TYPE "application/dns-message"
16+
#define DOH_MAX_RESPONSE_SIZE 65535
1617

1718
// the following macros require to have ctx pointer to https_fetch_ctx structure
1819
// else: compilation failure will occur
@@ -47,28 +48,37 @@
4748

4849
static size_t write_buffer(void *buf, size_t size, size_t nmemb, void *userp) {
4950
GET_PTR(struct https_fetch_ctx, ctx, userp);
50-
char *new_buf = (char *)realloc(
51-
ctx->buf, ctx->buflen + size * nmemb + 1);
51+
size_t write_size = size * nmemb;
52+
size_t new_size = ctx->buflen + write_size;
53+
if (new_size > DOH_MAX_RESPONSE_SIZE) {
54+
WLOG_REQ("Response size is too large!");
55+
return 0;
56+
}
57+
char *new_buf = (char *)realloc(ctx->buf, new_size + 1);
5258
if (new_buf == NULL) {
5359
ELOG_REQ("Out of memory!");
5460
return 0;
5561
}
5662
ctx->buf = new_buf;
5763
// NOLINTNEXTLINE(clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling)
58-
memcpy(&(ctx->buf[ctx->buflen]), buf, size * nmemb);
59-
ctx->buflen += size * nmemb;
64+
memcpy(&(ctx->buf[ctx->buflen]), buf, write_size);
65+
ctx->buflen = new_size;
6066
// We always expect to receive valid non-null ASCII but just to be safe...
6167
ctx->buf[ctx->buflen] = '\0';
62-
return size * nmemb;
68+
return write_size;
6369
}
6470

6571
static curl_socket_t opensocket_callback(void *clientp, curlsocktype purpose,
6672
struct curl_sockaddr *addr) {
6773
GET_PTR(https_client_t, client, clientp);
6874

6975
curl_socket_t sock = socket(addr->family, addr->socktype, addr->protocol);
70-
71-
DLOG("curl opened socket: %d", sock);
76+
if (sock != -1) {
77+
DLOG("curl opened socket: %d", sock);
78+
} else {
79+
ELOG("Could not open curl socket %d:%s", errno, strerror(errno));
80+
return CURL_SOCKET_BAD;
81+
}
7282

7383
if (client->stat) {
7484
stat_connection_opened(client->stat);
@@ -79,18 +89,16 @@ static curl_socket_t opensocket_callback(void *clientp, curlsocktype purpose,
7989
return sock;
8090
}
8191

82-
if (sock != -1) {
83-
if (addr->family == AF_INET) {
84-
setsockopt(sock, IPPROTO_IP, IP_TOS,
85-
&client->opt->dscp, sizeof(client->opt->dscp));
86-
}
92+
if (addr->family == AF_INET) {
93+
setsockopt(sock, IPPROTO_IP, IP_TOS,
94+
&client->opt->dscp, sizeof(client->opt->dscp));
95+
}
8796
#if defined(IPV6_TCLASS)
88-
else if (addr->family == AF_INET6) {
89-
setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
90-
&client->opt->dscp, sizeof(client->opt->dscp));
91-
}
92-
#endif
97+
else if (addr->family == AF_INET6) {
98+
setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS,
99+
&client->opt->dscp, sizeof(client->opt->dscp));
93100
}
101+
#endif
94102
#endif
95103

96104
return sock;
@@ -103,7 +111,8 @@ static int closesocket_callback(void __attribute__((unused)) *clientp, curl_sock
103111
if (close(sock) == 0) {
104112
DLOG("curl closed socket: %d", sock);
105113
} else {
106-
FLOG("Could not close curl socket %d:%s", errno, strerror(errno));
114+
ELOG("Could not close curl socket %d:%s", errno, strerror(errno));
115+
return 1;
107116
}
108117

109118
if (client->stat) {
@@ -225,6 +234,7 @@ static void https_fetch_ctx_init(https_client_t *client,
225234
CURL_HTTP_VERSION_1_1 :
226235
CURL_HTTP_VERSION_2_0);
227236
if (easy_code != CURLE_OK) {
237+
// hopefully errors will be logged once
228238
ELOG_REQ("CURLOPT_HTTP_VERSION error %d: %s",
229239
easy_code, curl_easy_strerror(easy_code));
230240
if (!client->opt->use_http_1_1) {
@@ -264,6 +274,7 @@ static void https_fetch_ctx_init(https_client_t *client,
264274
ASSERT_CURL_EASY_SETOPT(ctx, CURLOPT_TIMEOUT, 10 /* seconds */);
265275
// We know Google supports this, so force it.
266276
ASSERT_CURL_EASY_SETOPT(ctx, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
277+
ASSERT_CURL_EASY_SETOPT(ctx, CURLOPT_ERRORBUFFER, ctx->curl_errbuf); // zeroed by calloc
267278
if (client->opt->curl_proxy) {
268279
DLOG_REQ("Using curl proxy: %s", client->opt->curl_proxy);
269280
ASSERT_CURL_EASY_SETOPT(ctx, CURLOPT_PROXY, client->opt->curl_proxy);
@@ -276,40 +287,57 @@ static void https_fetch_ctx_init(https_client_t *client,
276287
}
277288

278289
static int https_fetch_ctx_process_response(https_client_t *client,
279-
struct https_fetch_ctx *ctx)
290+
struct https_fetch_ctx *ctx,
291+
int curl_result_code)
280292
{
281293
CURLcode res = 0;
282294
long long_resp = 0;
283295
char *str_resp = NULL;
284296
int faulty_response = 1;
285297

298+
switch (curl_result_code) {
299+
case CURLE_OK:
300+
DLOG_REQ("curl request succeeded");
301+
faulty_response = 0;
302+
break;
303+
case CURLE_WRITE_ERROR:
304+
WLOG_REQ("Response content was too large");
305+
break;
306+
default:
307+
WLOG_REQ("curl request failed with %d: %s", res, curl_easy_strerror(res));
308+
if (ctx->curl_errbuf[0] != 0) {
309+
WLOG_REQ("curl error message: %s", ctx->curl_errbuf);
310+
}
311+
}
312+
286313
if ((res = curl_easy_getinfo(
287314
ctx->curl, CURLINFO_RESPONSE_CODE, &long_resp)) != CURLE_OK) {
288315
ELOG_REQ("CURLINFO_RESPONSE_CODE: %s", curl_easy_strerror(res));
289-
} else {
290-
if (long_resp == 200) {
291-
faulty_response = 0;
292-
} else if (long_resp == 0) {
316+
faulty_response = 1;
317+
} else if (long_resp != 200) {
318+
faulty_response = 1;
319+
if (long_resp == 0) {
293320
curl_off_t uploaded_bytes = 0;
294321
if (curl_easy_getinfo(ctx->curl, CURLINFO_SIZE_UPLOAD_T, &uploaded_bytes) == CURLE_OK &&
295322
uploaded_bytes > 0) {
296-
ELOG_REQ("Connecting and sending request to resolver was successful, "
323+
WLOG_REQ("Connecting and sending request to resolver was successful, "
297324
"but no response was sent back");
298325
if (client->opt->use_http_1_1) {
299326
// for example Unbound DoH servers does not support HTTP/1.x, only HTTP/2
300-
ELOG("Resolver may not support current HTTP/1.1 protocol version");
327+
WLOG("Resolver may not support current HTTP/1.1 protocol version");
301328
}
302329
} else {
303330
// in case of HTTP/1.1 this can happen very often depending on DNS query frequency
304331
// example: server side closes the connection or curl force closes connections
305332
// that have been opened a long time ago (if CURLOPT_MAXAGE_CONN can not be increased
306333
// it is 118 seconds)
334+
// also: when no internet connection, this floods the log for every failed request
307335
WLOG_REQ("No response (probably connection has been closed or timed out)");
308336
}
309337
} else {
310-
ELOG_REQ("curl response code: %d, content length: %zu", long_resp, ctx->buflen);
338+
WLOG_REQ("curl response code: %d, content length: %zu", long_resp, ctx->buflen);
311339
if (ctx->buflen > 0) {
312-
https_log_data(LOG_ERROR, ctx, ctx->buf, ctx->buflen);
340+
https_log_data(LOG_WARNING, ctx, ctx->buf, ctx->buflen);
313341
}
314342
}
315343
}
@@ -319,12 +347,10 @@ static int https_fetch_ctx_process_response(https_client_t *client,
319347
if ((res = curl_easy_getinfo(
320348
ctx->curl, CURLINFO_CONTENT_TYPE, &str_resp)) != CURLE_OK) {
321349
ELOG_REQ("CURLINFO_CONTENT_TYPE: %s", curl_easy_strerror(res));
322-
} else {
323-
if (str_resp == NULL ||
324-
strncmp(str_resp, DOH_CONTENT_TYPE, sizeof(DOH_CONTENT_TYPE) - 1) != 0) { // at least, start with it
325-
ELOG_REQ("Invalid response Content-Type: %s", str_resp ? str_resp : "UNSET");
326-
faulty_response = 1;
327-
}
350+
} else if (str_resp == NULL ||
351+
strncmp(str_resp, DOH_CONTENT_TYPE, sizeof(DOH_CONTENT_TYPE) - 1) != 0) { // at least, start with it
352+
WLOG_REQ("Invalid response Content-Type: %s", str_resp ? str_resp : "UNSET");
353+
faulty_response = 1;
328354
}
329355
}
330356

@@ -333,24 +359,25 @@ static int https_fetch_ctx_process_response(https_client_t *client,
333359
ctx->curl, CURLINFO_REDIRECT_URL, &str_resp)) != CURLE_OK) {
334360
ELOG_REQ("CURLINFO_REDIRECT_URL: %s", curl_easy_strerror(res));
335361
} else if (str_resp != NULL) {
336-
ELOG_REQ("Request would be redirected to: %s", str_resp);
362+
WLOG_REQ("Request would be redirected to: %s", str_resp);
337363
if (strcmp(str_resp, client->opt->resolver_url) != 0) {
338-
ELOG("Please update Resolver URL to avoid redirection!");
364+
WLOG("Please update Resolver URL to avoid redirection!");
339365
}
340366
}
341367
if ((res = curl_easy_getinfo(
342368
ctx->curl, CURLINFO_SSL_VERIFYRESULT, &long_resp)) != CURLE_OK) {
343369
ELOG_REQ("CURLINFO_SSL_VERIFYRESULT: %s", curl_easy_strerror(res));
344370
} else if (long_resp != CURLE_OK) {
345-
ELOG_REQ("CURLINFO_SSL_VERIFYRESULT: %s", curl_easy_strerror(long_resp));
371+
WLOG_REQ("CURLINFO_SSL_VERIFYRESULT: %s", curl_easy_strerror(long_resp));
346372
}
347373
if ((res = curl_easy_getinfo(
348374
ctx->curl, CURLINFO_OS_ERRNO, &long_resp)) != CURLE_OK) {
349375
ELOG_REQ("CURLINFO_OS_ERRNO: %s", curl_easy_strerror(res));
350376
} else if (long_resp != 0) {
351-
ELOG_REQ("CURLINFO_OS_ERRNO: %d %s", long_resp, strerror(long_resp));
377+
WLOG_REQ("CURLINFO_OS_ERRNO: %d %s", long_resp, strerror(long_resp));
352378
if (long_resp == ENETUNREACH && !client->opt->ipv4) {
353-
ELOG("Try to run application with -4 argument!");
379+
// this can't be fixed here with option overwrite because of dns_poller
380+
WLOG("Try to run application with -4 argument!");
354381
}
355382
}
356383
}
@@ -429,7 +456,8 @@ static int https_fetch_ctx_process_response(https_client_t *client,
429456
}
430457

431458
static void https_fetch_ctx_cleanup(https_client_t *client,
432-
struct https_fetch_ctx *ctx) {
459+
struct https_fetch_ctx *ctx,
460+
int curl_result_code) {
433461
struct https_fetch_ctx *last = NULL;
434462
struct https_fetch_ctx *cur = client->fetches;
435463
while (cur) {
@@ -438,8 +466,15 @@ static void https_fetch_ctx_cleanup(https_client_t *client,
438466
if (code != CURLM_OK) {
439467
FLOG_REQ("curl_multi_remove_handle error %d: %s", code, curl_multi_strerror(code));
440468
}
441-
if (https_fetch_ctx_process_response(client, ctx) != 0) {
469+
int drop_reply = 0;
470+
if (curl_result_code < 0) {
471+
WLOG_REQ("Request was aborted.");
472+
drop_reply = 1;
473+
} else if (https_fetch_ctx_process_response(client, ctx, curl_result_code) != 0) {
442474
ILOG_REQ("Response was faulty, skipping DNS reply.");
475+
drop_reply = 1;
476+
}
477+
if (drop_reply) {
443478
free(ctx->buf);
444479
ctx->buf = NULL;
445480
ctx->buflen = 0;
@@ -469,7 +504,7 @@ static void check_multi_info(https_client_t *c) {
469504
struct https_fetch_ctx *n = c->fetches;
470505
while (n) {
471506
if (n->curl == msg->easy_handle) {
472-
https_fetch_ctx_cleanup(c, n);
507+
https_fetch_ctx_cleanup(c, n, msg->data.result);
473508
break;
474509
}
475510
n = n->next;
@@ -570,10 +605,7 @@ void https_client_init(https_client_t *c, options_t *opt,
570605
c->opt = opt;
571606
c->stat = stat;
572607

573-
ASSERT_CURL_MULTI_SETOPT(c->curlm, CURLMOPT_PIPELINING,
574-
c->opt->use_http_1_1 ?
575-
CURLPIPE_HTTP1 :
576-
CURLPIPE_MULTIPLEX);
608+
ASSERT_CURL_MULTI_SETOPT(c->curlm, CURLMOPT_PIPELINING, CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX);
577609
ASSERT_CURL_MULTI_SETOPT(c->curlm, CURLMOPT_MAX_TOTAL_CONNECTIONS, MAX_TOTAL_CONNECTIONS);
578610
ASSERT_CURL_MULTI_SETOPT(c->curlm, CURLMOPT_SOCKETDATA, c);
579611
ASSERT_CURL_MULTI_SETOPT(c->curlm, CURLMOPT_SOCKETFUNCTION, multi_sock_cb);
@@ -603,7 +635,7 @@ void https_client_reset(https_client_t *c) {
603635

604636
void https_client_cleanup(https_client_t *c) {
605637
while (c->fetches) {
606-
https_fetch_ctx_cleanup(c, c->fetches);
638+
https_fetch_ctx_cleanup(c, c->fetches, -1);
607639
}
608640
curl_slist_free_all(c->header_list);
609641
curl_multi_cleanup(c->curlm);

src/https_client.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ typedef void (*https_response_cb)(void *data, char *buf, size_t buflen);
1414
// Internal: Holds state on an individual transfer.
1515
struct https_fetch_ctx {
1616
CURL *curl;
17+
char curl_errbuf[CURL_ERROR_SIZE];
1718

1819
uint16_t id;
1920

src/logging.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ static FILE *logf = NULL; // NOLINT(cppcoreguidelines-avoid-non-const-glo
1212
static int loglevel = LOG_ERROR; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
1313
static ev_timer logging_timer; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
1414

15-
static const char *SeverityStr[] = {
15+
static const char * const SeverityStr[] = {
1616
"[D]",
1717
"[I]",
1818
"[W]",
@@ -63,6 +63,7 @@ int logging_debug_enabled() {
6363
return loglevel <= LOG_DEBUG;
6464
}
6565

66+
// NOLINTNEXTLINE(misc-no-recursion) because of severity check
6667
void _log(const char *file, int line, int severity, const char *fmt, ...) {
6768
if (severity < loglevel) {
6869
return;

0 commit comments

Comments
 (0)