Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ define_file_basename_for_sources("https_dns_proxy")

if(SW_VERSION)
set_source_files_properties(
src/options.c
src/main.c
PROPERTIES COMPILE_FLAGS "-DSW_VERSION='\"${SW_VERSION}\"'")
endif()

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ only makes sense if you trust your DoH provider.

## Build

Depends on `c-ares (>=1.11.0)`, `libcurl (>=7.65.0)`, `libev (>=4.25)`.
Depends on `c-ares (>=1.11.0)`, `libcurl (>=7.66.0)`, `libev (>=4.25)`.

On Debian-derived systems those are libc-ares-dev,
libcurl4-{openssl,nss,gnutls}-dev and libev-dev respectively.
Expand Down Expand Up @@ -208,7 +208,7 @@ Usage: ./https_dns_proxy [-a <listen_addr>] [-p <listen_port>]
-F log_limit Flight recorder: storing desired amount of logs from all levels
in memory and dumping them on fatal error or on SIGUSR2 signal.
(Default: 0, Disabled: 0, Min: 100, Max: 100000)
-V Print version and exit.
-V Print versions and exit.
-h Print help and exit.
```

Expand Down
20 changes: 7 additions & 13 deletions src/https_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ static int closesocket_callback(void __attribute__((unused)) *clientp, curl_sock
}

static void https_log_data(enum LogSeverity level, struct https_fetch_ctx *ctx,
char *ptr, size_t size)
const char * prefix, char *ptr, size_t size)
{
const size_t width = 0x10;

Expand Down Expand Up @@ -167,7 +167,7 @@ static void https_log_data(enum LogSeverity level, struct https_fetch_ctx *ctx,
}
}

LOG_REQ(level, "%4.4lx: %s%s", (long)i, hex, str);
LOG_REQ(level, "%s%4.4lx: %s%s", prefix, (long)i, hex, str);
}
}

Expand All @@ -191,10 +191,8 @@ int https_curl_debug(CURL __attribute__((unused)) * handle, curl_infotype type,
// not dumping DNS packets because of privacy
case CURLINFO_DATA_OUT:
case CURLINFO_DATA_IN:
// uncomment, to dump
/* DLOG_REQ("data %s", type == CURLINFO_DATA_IN ? "IN" : "OUT");
* https_log_data(LOG_DEBUG, ctx, data, size);
* return 0; */
https_log_data(LOG_DEBUG, ctx, (type == CURLINFO_DATA_IN ? "< " : "> "), data, size);
return 0;
// uninformative
case CURLINFO_SSL_DATA_OUT:
case CURLINFO_SSL_DATA_IN:
Expand All @@ -206,7 +204,7 @@ int https_curl_debug(CURL __attribute__((unused)) * handle, curl_infotype type,

// for extra debugging purpose
// if (type != CURLINFO_TEXT) {
// https_log_data(LOG_DEBUG, ctx, data, size);
// https_log_data(LOG_DEBUG, ctx, "", data, size);
// }

// process lines one-by one
Expand All @@ -217,7 +215,7 @@ int https_curl_debug(CURL __attribute__((unused)) * handle, curl_infotype type,
// skip empty string and curl info Expire
if (start != NULL && (pos - start) > 0 &&
strncmp(start, "Expire", sizeof("Expire") - 1) != 0) {
// https_log_data(LOG_DEBUG, ctx, start, pos - start);
// https_log_data(LOG_DEBUG, ctx, "", start, pos - start);
DLOG_REQ("%s%.*s", prefix, pos - start, start);
start = NULL;
}
Expand All @@ -237,10 +235,8 @@ static const char * http_version_str(const long version) {
case CURL_HTTP_VERSION_2_0: // fallthrough
case CURL_HTTP_VERSION_2TLS:
return "2";
#ifdef CURL_VERSION_HTTP3
case CURL_HTTP_VERSION_3:
return "3";
#endif
default:
FLOG("Unsupported HTTP version: %d", version);
}
Expand All @@ -257,9 +253,7 @@ static void https_set_request_version(https_client_t *client,
case 2:
break;
case 3:
#ifdef CURL_VERSION_HTTP3
http_version_int = CURL_HTTP_VERSION_3;
#endif
break;
default:
FLOG_REQ("Invalid HTTP version: %d", client->opt->use_http_version);
Expand Down Expand Up @@ -394,7 +388,7 @@ static int https_fetch_ctx_process_response(https_client_t *client,
} else {
WLOG_REQ("curl response code: %d, content length: %zu", long_resp, ctx->buflen);
if (ctx->buflen > 0) {
https_log_data(LOG_WARNING, ctx, ctx->buf, ctx->buflen);
https_log_data(LOG_WARNING, ctx, "", ctx->buf, ctx->buflen);
}
}
}
Expand Down
68 changes: 55 additions & 13 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,38 +205,80 @@ static int proxy_supports_name_resolution(const char *proxy)
return 0;
}

static const char * sw_version(void) {
#ifdef SW_VERSION
return SW_VERSION;
#else
return "2025.5.10-atLeast"; // update date sometimes, like 1-2 times a year
#endif
}

int main(int argc, char *argv[]) {
struct Options opt;
options_init(&opt);
if (options_parse_args(&opt, argc, argv)) {
options_show_usage(argc, argv);
exit(1);
switch (options_parse_args(&opt, argc, argv)) {
case OPR_SUCCESS:
break;
case OPR_HELP:
options_show_usage(argc, argv);
exit(0); // asking for help is not a problem
case OPR_VERSION: {
printf("%s\n", sw_version());
CURLcode init_res = curl_global_init(CURL_GLOBAL_DEFAULT);
curl_version_info_data *curl_ver = curl_version_info(CURLVERSION_NOW);
if (init_res == CURLE_OK && curl_ver != NULL) {
printf("Using: ev/%d.%d c-ares/%s %s\n",
ev_version_major(), ev_version_minor(),
ares_version(NULL), curl_version());
printf("Features: %s%s%s%s\n",
curl_ver->features & CURL_VERSION_HTTP2 ? "HTTP2 " : "",
curl_ver->features & CURL_VERSION_HTTP3 ? "HTTP3 " : "",
curl_ver->features & CURL_VERSION_HTTPS_PROXY ? "HTTPS-proxy " : "",
curl_ver->features & CURL_VERSION_IPV6 ? "IPv6" : "");
exit(0);
} else {
printf("\nFailed to get curl version info!\n");
exit(1);
}
}
case OPR_PARSING_ERROR:
printf("Failed to parse options!\n");
// fallthrough
case OPR_OPTION_ERROR:
printf("\n");
options_show_usage(argc, argv);
exit(1);
default:
abort(); // must not happen
}

logging_init(opt.logfd, opt.loglevel, opt.flight_recorder_size);

ILOG("Version: %s", options_sw_version());
ILOG("Version: %s", sw_version());
ILOG("Built: " __DATE__ " " __TIME__);
ILOG("System c-ares: %s", ares_version(NULL));
ILOG("System libcurl: %s", curl_version());
ILOG("System ev library: %d.%d", ev_version_major(), ev_version_minor());
ILOG("System c-ares library: %s", ares_version(NULL));
ILOG("System curl library: %s", curl_version());

// Note: curl intentionally uses uninitialized stack variables and similar
// tricks to increase it's entropy pool. This confuses valgrind and leaks
// through to errors about use of uninitialized values in our code. :(
curl_global_init(CURL_GLOBAL_DEFAULT);
CURLcode code = curl_global_init(CURL_GLOBAL_DEFAULT);
if (code != CURLE_OK) {
FLOG("Failed to initialize curl, error code %d: %s",
code, curl_easy_strerror(code));
}

curl_version_info_data *curl_ver = curl_version_info(CURLVERSION_NOW);
if (curl_ver == NULL) {
FLOG("Failed to get curl version info!");
}
if (!(curl_ver->features & CURL_VERSION_HTTP2)) {
WLOG("HTTP/2 is not supported by current libcurl");
}
#ifdef CURL_VERSION_HTTP3
if (!(curl_ver->features & CURL_VERSION_HTTP3))
{
if (!(curl_ver->features & CURL_VERSION_HTTP3)) {
WLOG("HTTP/3 is not supported by current libcurl");
}
#else
WLOG("HTTP/3 was not available at build time, it will not work at all");
#endif
if (!(curl_ver->features & CURL_VERSION_IPV6)) {
WLOG("IPv6 is not supported by current libcurl");
}
Expand Down
46 changes: 17 additions & 29 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,6 @@ enum {
DEFAULT_HTTP_VERSION = 2
};


const char * options_sw_version(void) {
#ifdef SW_VERSION
return SW_VERSION;
#else
return "2023.10.10-atLeast"; // update date sometimes, like 1-2 times a year
#endif
}

void options_init(struct Options *opt) {
opt->listen_addr = "127.0.0.1";
opt->listen_port = 5053;
Expand All @@ -53,7 +44,7 @@ void options_init(struct Options *opt) {
opt->flight_recorder_size = 0;
}

int options_parse_args(struct Options *opt, int argc, char **argv) {
enum OptionsParseResult options_parse_args(struct Options *opt, int argc, char **argv) {
int c = 0;
while ((c = getopt(argc, argv, "a:c:p:du:g:b:i:4r:e:t:l:vxqm:s:C:F:hV")) != -1) {
switch (c) {
Expand Down Expand Up @@ -105,7 +96,7 @@ int options_parse_args(struct Options *opt, int argc, char **argv) {
} else {
printf("HTTP version already set to: HTTP/%s\n",
opt->use_http_version == 1 ? "1.1" : "3");
return -1;
return OPR_OPTION_ERROR;
}
break;
case 'm':
Expand All @@ -120,38 +111,35 @@ int options_parse_args(struct Options *opt, int argc, char **argv) {
case 'F': // Flight recorder size
opt->flight_recorder_size = atoi(optarg);
break;
case '?':
printf("Unknown option '-%c'\n", c);
// fallthrough
case 'h':
return -1;
return OPR_HELP;
case 'V': // version
printf("%s\n", options_sw_version());
exit(0);
return OPR_VERSION;
case '?':
default:
printf("Unknown state!");
exit(EXIT_FAILURE);
return OPR_PARSING_ERROR;
}
}

if (opt->user) {
struct passwd *p = getpwnam(opt->user);
if (!p || !p->pw_uid) {
printf("Username (%s) invalid.\n", opt->user);
return -1;
return OPR_OPTION_ERROR;
}
opt->uid = p->pw_uid;
}
if (opt->group) {
struct group *g = getgrnam(opt->group);
if (!g || !g->gr_gid) {
printf("Group (%s) invalid.\n", opt->group);
return -1;
return OPR_OPTION_ERROR;
}
opt->gid = g->gr_gid;
}
if (opt->dscp < 0 || opt->dscp >63) {
printf("DSCP code (%d) invalid:[0-63]\n", opt->dscp);
return -1;
return OPR_OPTION_ERROR;
}
opt->dscp <<= 2;
// Get noisy about bad security practices.
Expand All @@ -174,28 +162,28 @@ int options_parse_args(struct Options *opt, int argc, char **argv) {
strncmp(opt->resolver_url, "https://", 8) != 0) {
printf("Resolver prefix (%s) must be a https:// address.\n",
opt->resolver_url);
return -1;
return OPR_OPTION_ERROR;
}
if (opt->bootstrap_dns_polling_interval < 5 ||
opt->bootstrap_dns_polling_interval > 3600) {
printf("DNS servers polling interval must be between 5 and 3600.\n");
return -1;
return OPR_OPTION_ERROR;
}
if (opt->max_idle_time < 0 ||
opt->max_idle_time > 3600) {
printf("Maximum idle time must be between 0 and 3600.\n");
return -1;
return OPR_OPTION_ERROR;
}
if (opt->stats_interval < 0 || opt->stats_interval > 3600) {
printf("Statistic interval must be between 0 and 3600.\n");
return -1;
return OPR_OPTION_ERROR;
}
if (opt->flight_recorder_size != 0 &&
(opt->flight_recorder_size < 100 || opt->flight_recorder_size > 100000)) {
printf("Flight recorder limit must be between 100 and 100000.\n");
return -1;
return OPR_OPTION_ERROR;
}
return 0;
return OPR_SUCCESS;
}

void options_show_usage(int __attribute__((unused)) argc, char **argv) {
Expand Down Expand Up @@ -254,7 +242,7 @@ void options_show_usage(int __attribute__((unused)) argc, char **argv) {
" in memory and dumping them on fatal error or on SIGUSR2 signal.\n"
" (Default: %u, Disabled: 0, Min: 100, Max: 100000)\n",
defaults.flight_recorder_size);
printf(" -V Print version and exit.\n");
printf(" -V Print versions and exit.\n");
printf(" -h Print help and exit.\n");
options_cleanup(&defaults);
}
Expand Down
11 changes: 9 additions & 2 deletions src/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,19 @@ struct Options {
} __attribute__((aligned(128)));
typedef struct Options options_t;

enum OptionsParseResult {
OPR_SUCCESS,
OPR_HELP,
OPR_VERSION,
OPR_OPTION_ERROR,
OPR_PARSING_ERROR
};

#ifdef __cplusplus
extern "C" {
#endif
const char * options_sw_version(void);
void options_init(struct Options *opt);
int options_parse_args(struct Options *opt, int argc, char **argv);
enum OptionsParseResult options_parse_args(struct Options *opt, int argc, char **argv);
void options_show_usage(int argc, char **argv);
void options_cleanup(struct Options *opt);
#ifdef __cplusplus
Expand Down
6 changes: 3 additions & 3 deletions src/ring_buffer.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef _FR_H_
#define _FR_H_
#ifndef _RING_BUFFER_H_
#define _RING_BUFFER_H_

#ifdef __cplusplus
extern "C" {
Expand All @@ -18,4 +18,4 @@ void ring_buffer_push_back(struct ring_buffer *rb, char* data, uint32_t size);
}
#endif

#endif // _FR_H_
#endif // RING_BUFFER_H_