https_dns_proxy icon indicating copy to clipboard operation
https_dns_proxy copied to clipboard

Add -S flag for configurable source address on outbound connections

Open karl82 opened this issue 1 month ago • 4 comments

Motivation:

Enable routing DNS-over-HTTPS traffic through different network paths per instance. Primary use case: running multiple https_dns_proxy instances on a router where each WiFi LAN gateway routes through a different WireGuard tunnel to different geographic locations. This allows DNS traffic from different WiFi networks to exit via different VPN endpoints.

Implementation:

  • Added source_addr field to struct Options
  • New -S command-line flag to specify source IPv4/v6 address
  • Uses CURLOPT_INTERFACE to bind outbound HTTPS connections
  • Backward compatible: without -S, uses system default routing
  • Logs Using source address: X at debug level when configured

Example Usage:

Instance 1: WiFi LAN 1 gateway (routes via WireGuard to US)

https_dns_proxy -a 192.168.1.1 -p 53 -S 192.168.1.1 \
  -r https://security.cloudflare-dns.com/dns-query \
  -b 1.1.1.2,1.0.0.2

Instance 2: WiFi LAN 2 gateway (routes via WireGuard to EU)

https_dns_proxy -a 192.168.2.1 -p 53 -S 192.168.2.1 \
  -r https://security.cloudflare-dns.com/dns-query \
  -b 1.1.1.2,1.0.0.2

Each instance binds to its WiFi interface address for both listening and outbound HTTPS, ensuring traffic routes through the correct WireGuard tunnel configured for that interface.

Verification:

With -S flag, CURL binds to specified source address:

  [D] https_client.c:260 F0C1: Requesting HTTP/2
  [D] https_client.c:324 F0C1: Using source address: 192.168.1.1
  [D] https_client.c:218 F0C1: * Added security.cloudflare-dns.com:443:1.0.0.2,1.1.1.2,... to DNS cache
  [D] https_client.c:218 F0C1: * Hostname security.cloudflare-dns.com was found in DNS cache
  [D] https_client.c:94 curl opened socket: 9
  [D] https_client.c:218 F0C1: *   Trying 1.0.0.2:443...
  [D] https_client.c:218 F0C1: * Name '192.168.1.1' family 2 resolved to '192.168.1.1' family 2
  [D] https_client.c:218 F0C1: * Local port: 0
  [D] https_client.c:639 Reserved new io event: 0xffffc0ed3568
  [D] https_client.c:218 F0C1: * Connected to security.cloudflare-dns.com (1.0.0.2) port 443 (#0)

Without -S flag, no source binding (backward compatible):

  [D] https_client.c:260 39BF: Requesting HTTP/2
  [D] https_client.c:218 39BF: * Added security.cloudflare-dns.com:443:1.1.1.2,1.0.0.2,... to DNS cache
  [D] https_client.c:218 39BF: * Hostname security.cloudflare-dns.com was found in DNS cache
  [D] https_client.c:94 curl opened socket: 9
  [D] https_client.c:218 39BF: *   Trying 1.1.1.2:443...
  [D] https_client.c:639 Reserved new io event: 0xffffe69a0f18
  [D] https_client.c:218 39BF: * Connected to security.cloudflare-dns.com (1.1.1.2) port 443 (#0)

Note the presence of Using source address and Name '192.168.1.1' ... resolved lines only when -S is specified.

Files Modified:

  • src/options.h: Added source_addr field
  • src/options.c: Added -S flag parsing and help text
  • src/https_client.c: Implemented CURLOPT_INTERFACE binding
  • tests/robot/functional_tests.robot: Added test case
  • README.md: Updated documentation

karl82 avatar Nov 23 '25 18:11 karl82