Skip to content

Conversation

@karl82
Copy link
Contributor

@karl82 karl82 commented Feb 12, 2026

Motivation:

PR #196 added the -S flag to bind HTTPS connections to a source address, enabling policy-based routing. However, bootstrap DNS queries (used to resolve DoH server hostnames like "dns.google") were not bound to the source address.

This caused two issues:

  1. Privacy leak: Bootstrap DNS queries go via default route (local ISP), exposing which DoH server you're using
  2. Routing mismatch: HTTPS connection routes via VPN but may fail if resolved IP is unreachable from VPN

Implementation:

  • Bind bootstrap DNS queries using ares_set_local_ip4() and ares_set_local_ip6() from c-ares
  • Validate address family matches proxy mode (-4/-6), warn on mismatch
  • Warn on invalid address literals
  • Robot Framework tests for source binding and validation warnings
  • Docker-based test infrastructure for CI/CD and macOS development

Example Usage:

https_dns_proxy -S 192.168.12.1 -b 1.1.1.1,8.8.8.8 -r https://dns.google/dns-query

With PBR rules routing traffic from source 192.168.12.1 via VPN:

# Route DoH HTTPS (port 443) via VPN
config policy
	option name 'DoH WA via wg_wa'
	option interface 'wg_wa'
	option chain 'output'
	option proto 'tcp'
	option src_addr '192.168.12.1'
	option dest_port '443'

# Route bootstrap DNS (port 53) via VPN
config policy
	option name 'Bootstrap DNS WA via wg_wa'
	option interface 'wg_wa'
	option chain 'output'
	option proto 'udp'
	option src_addr '192.168.12.1'
	option dest_port '53'
	option dest_addr '1.1.1.1 8.8.8.8'

Both rules now match because -S binds both HTTPS and bootstrap DNS to the same source address.

Verification:

Bootstrap DNS bound to source address:

[I] dns_poller.c:163 Using source address: 192.168.12.1
[I] dns_poller.c:208 Received new DNS server IP: 142.250.80.110 for dns.google

Warning on address family mismatch:

[W] dns_poller.c:133 Bootstrap source address '::1' is IPv6, but IPv4-only mode is set

Warning on invalid address:

[W] dns_poller.c:141 Bootstrap source address 'not-an-ip' is not a valid IP literal

Files Modified:

  • src/dns_poller.c: Added set_bootstrap_source_addr() function
  • src/dns_poller.h: Added source_addr parameter to poller init
  • src/main.c: Pass source_addr to dns_poller
  • src/options.c: Fix format string type
  • tests/robot/functional_tests.robot: Source binding and validation tests
  • tests/docker/Dockerfile: Test image with valgrind and ctest integration
  • tests/docker/run_all_tests.sh: Simplified test runner using Dockerfile CMD
  • CMakeLists.txt: Fix robot test WORKING_DIRECTORY, add distclean target
  • README.md: Update Docker test documentation
  • .gitignore: Add build/ directory

Motivation:
-----------
PR aarond10#196 added the `-S` flag to bind HTTPS connections to a source address, enabling policy-based routing. However, bootstrap DNS queries (used to resolve DoH server hostnames like "dns.google") were not bound to the source address.

This caused two issues:
1. **Privacy leak**: Bootstrap DNS queries go via default route (local ISP), exposing which DoH server you're using
2. **Routing mismatch**: HTTPS connection routes via VPN but may fail if resolved IP is unreachable from VPN

Implementation:
---------------
- Bind bootstrap DNS queries using `ares_set_local_ip4()` and `ares_set_local_ip6()` from c-ares
- Validate address family matches proxy mode (`-4`/`-6`), warn on mismatch
- Warn on invalid address literals
- Robot Framework tests for source binding and validation warnings
- Docker-based test infrastructure for CI/CD and macOS development

Example Usage:
--------------
```bash
https_dns_proxy -S 192.168.12.1 -b 1.1.1.1,8.8.8.8 -r https://dns.google/dns-query
```

With PBR rules routing traffic from source 192.168.12.1 via VPN:

```text
# Route DoH HTTPS (port 443) via VPN
config policy
	option name 'DoH WA via wg_wa'
	option interface 'wg_wa'
	option chain 'output'
	option proto 'tcp'
	option src_addr '192.168.12.1'
	option dest_port '443'

# Route bootstrap DNS (port 53) via VPN
config policy
	option name 'Bootstrap DNS WA via wg_wa'
	option interface 'wg_wa'
	option chain 'output'
	option proto 'udp'
	option src_addr '192.168.12.1'
	option dest_port '53'
	option dest_addr '1.1.1.1 8.8.8.8'
```

Both rules now match because `-S` binds both HTTPS and bootstrap DNS to the same source address.

Verification:
-------------
Bootstrap DNS bound to source address:
```
[I] dns_poller.c:163 Using source address: 192.168.12.1
[I] dns_poller.c:208 Received new DNS server IP: 142.250.80.110 for dns.google
```

Warning on address family mismatch:
```
[W] dns_poller.c:133 Bootstrap source address '::1' is IPv6, but IPv4-only mode is set
```

Warning on invalid address:
```
[W] dns_poller.c:141 Bootstrap source address 'not-an-ip' is not a valid IP literal
```

Files Modified:
---------------
- `src/dns_poller.c`: Added `set_bootstrap_source_addr()` function
- `src/dns_poller.h`: Added source_addr parameter to poller init
- `src/main.c`: Pass source_addr to dns_poller
- `src/options.c`: Fix format string type
- `tests/robot/functional_tests.robot`: Source binding and validation tests
- `tests/docker/Dockerfile`: Test image with valgrind and ctest integration
- `tests/docker/run_all_tests.sh`: Simplified test runner using Dockerfile CMD
- `CMakeLists.txt`: Fix robot test WORKING_DIRECTORY, add distclean target
- `README.md`: Update Docker test documentation
- `.gitignore`: Add build/ directory
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant