diff --git a/README.md b/README.md index 08573af..4cc2790 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ Just run it as a daemon and point traffic at it. Commandline flags are: ``` Usage: ./https_dns_proxy [-a ] [-p ] [-T ] [-b ] [-i ] [-4] - [-r ] [-t ] [-x] [-q] [-C ] [-c ] + [-r ] [-t ] [-S ] [-x] [-q] [-C ] [-c ] [-d] [-u ] [-g ] [-v]+ [-l ] [-s ] [-F ] [-V] [-h] @@ -187,6 +187,8 @@ Usage: ./https_dns_proxy [-a ] [-p ] [-T opt->curl_proxy); ASSERT_CURL_EASY_SETOPT(ctx, CURLOPT_PROXY, client->opt->curl_proxy); } + if (client->opt->source_addr) { + DLOG_REQ("Using source address: %s", client->opt->source_addr); + ASSERT_CURL_EASY_SETOPT(ctx, CURLOPT_INTERFACE, client->opt->source_addr); + } if (client->opt->ca_info) { ASSERT_CURL_EASY_SETOPT(ctx, CURLOPT_CAINFO, client->opt->ca_info); } diff --git a/src/options.c b/src/options.c index fa003dc..3630d11 100644 --- a/src/options.c +++ b/src/options.c @@ -39,6 +39,7 @@ void options_init(struct Options *opt) { opt->ipv4 = 0; opt->resolver_url = "https://dns.google/dns-query"; opt->curl_proxy = NULL; + opt->source_addr = NULL; opt->use_http_version = DEFAULT_HTTP_VERSION; opt->max_idle_time = 118; opt->conn_loss_time = 15; @@ -58,7 +59,7 @@ int parse_int(char * str) { enum OptionsParseResult options_parse_args(struct Options *opt, int argc, char **argv) { int c = 0; - while ((c = getopt(argc, argv, "a:c:p:T:du:g:b:i:4r:e:t:l:vxqm:L:s:C:F:hV")) != -1) { + while ((c = getopt(argc, argv, "a:c:p:T:du:g:b:i:4r:e:t:l:vxqm:L:s:S:C:F:hV")) != -1) { switch (c) { case 'a': // listen_addr opt->listen_addr = optarg; @@ -123,6 +124,9 @@ enum OptionsParseResult options_parse_args(struct Options *opt, int argc, char * case 's': // stats interval opt->stats_interval = parse_int(optarg); break; + case 'S': // source address + opt->source_addr = optarg; + break; case 'C': // CA info opt->ca_info = optarg; break; @@ -222,7 +226,7 @@ void options_show_usage(int __attribute__((unused)) argc, char **argv) { options_init(&defaults); printf("Usage: %s [-a ] [-p ] [-T ]\n", argv[0]); printf(" [-b ] [-i ] [-4]\n"); - printf(" [-r ] [-t ] [-x] [-q] [-C ] [-c ]\n"); + printf(" [-r ] [-t ] [-S ] [-x] [-q] [-C ] [-c ]\n"); printf(" [-d] [-u ] [-g ] \n"); printf(" [-v]+ [-l ] [-s ] [-F ] [-V] [-h]\n"); printf("\n DNS server\n"); @@ -250,6 +254,8 @@ void options_show_usage(int __attribute__((unused)) argc, char **argv) { printf(" supports it (http, https, socks4a, socks5h), otherwise\n"); printf(" initial DNS resolution will still be done via the\n"); printf(" bootstrap DNS servers.\n"); + printf(" -S source_addr Source IPv4/v6 address for outbound HTTPS connections.\n"); + printf(" (Default: system default)\n"); printf(" -x Use HTTP/1.1 instead of HTTP/2. Useful with broken\n" " or limited builds of libcurl.\n"); printf(" -q Use HTTP/3 (QUIC) only.\n"); diff --git a/src/options.h b/src/options.h index 9320b50..6d0a9d3 100644 --- a/src/options.h +++ b/src/options.h @@ -43,6 +43,9 @@ struct Options { // e.g. "socks5://127.0.0.1:1080" const char *curl_proxy; + // Source address for outbound HTTPS connections + const char *source_addr; + // 1 = Use only HTTP/1.1 for limited OpenWRT libcurl (which is not built with HTTP/2 support) // 2 = Use only HTTP/2 default // 3 = Use only HTTP/3 QUIC diff --git a/tests/robot/functional_tests.robot b/tests/robot/functional_tests.robot index 7241f5c..84e2cf1 100644 --- a/tests/robot/functional_tests.robot +++ b/tests/robot/functional_tests.robot @@ -201,3 +201,10 @@ Truncate UDP Impossible Wait Until Keyword Succeeds 5x 200ms # the only TXT answer record has to be dropped to met limit ... Verify Truncation txtfill4096.test.dnscheck.tools 4096 12 100 ANSWER: 0 + +Source Address Binding + [Documentation] Test source address binding with -S flag + ${eth0_ip} = Run ip -4 addr show eth0 | grep inet | awk '{print $2}' | cut -d/ -f1 | tr -d '\\n' + Start Proxy -S ${eth0_ip} + Set To Dictionary ${expected_logs} Using source address=1 + Run Dig