Skip to content

feat(cli): add DNS-over-HTTPS support via --dns-over-https flag#1280

Merged
Mossaka merged 3 commits intomainfrom
feat/094-dns-over-https
Mar 13, 2026
Merged

feat(cli): add DNS-over-HTTPS support via --dns-over-https flag#1280
Mossaka merged 3 commits intomainfrom
feat/094-dns-over-https

Conversation

@Mossaka
Copy link
Collaborator

@Mossaka Mossaka commented Mar 13, 2026

Summary

  • Add --dns-over-https [resolver-url] CLI flag that deploys a cloudflare/cloudflared sidecar container as a DoH proxy
  • Agent DNS queries are encrypted over HTTPS, preventing DNS spoofing and interception
  • Legacy UDP DNS to external servers is blocked when DoH is enabled
  • Default resolver: https://dns.google/dns-query

Fixes #307

Changes

  • src/types.ts: Add dnsOverHttps config property
  • src/cli.ts: Add --dns-over-https flag with validation
  • src/docker-manager.ts: Add doh-proxy sidecar service (IP 172.30.0.40) with security hardening
  • src/host-iptables.ts: Allow DoH proxy HTTPS outbound access
  • src/cli-workflow.ts: Pass dohProxyIp to host-iptables setup
  • containers/agent/setup-iptables.sh: Route DNS through DoH proxy when enabled
  • containers/agent/entrypoint.sh: Configure resolv.conf for DoH proxy
  • Tests: 14 new unit tests for DoH configuration

Test plan

  • npm run build passes
  • npm test passes (967 tests)
  • npm run lint passes (0 errors)
  • CI integration tests pass
  • Manual test: sudo awf --dns-over-https --allow-domains github.com -- curl https://api.github.com

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings March 13, 2026 01:10
@Mossaka Mossaka enabled auto-merge (squash) March 13, 2026 01:10
@github-actions
Copy link
Contributor

⚠️ Coverage Regression Detected

This PR decreases test coverage. Please add tests to maintain coverage levels.

Overall Coverage

Metric Base PR Delta
Lines 84.37% 84.35% 📉 -0.02%
Statements 84.32% 84.30% 📉 -0.02%
Functions 84.88% 84.88% ➡️ +0.00%
Branches 77.40% 77.35% 📉 -0.05%
📁 Per-file Coverage Changes (3 files)
File Lines (Before → After) Statements (Before → After)
src/cli.ts 56.3% → 55.5% (-0.80%) 56.8% → 56.0% (-0.79%)
src/host-iptables.ts 81.0% → 81.6% (+0.58%) 81.2% → 81.7% (+0.57%)
src/docker-manager.ts 86.9% → 87.6% (+0.69%) 86.2% → 86.9% (+0.67%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

@Mossaka Mossaka changed the title feat(dns): add DNS-over-HTTPS support via --dns-over-https flag feat(cli): add DNS-over-HTTPS support via --dns-over-https flag Mar 13, 2026
@github-actions
Copy link
Contributor

Smoke Test Results — PASS

✅ GitHub MCP: #1273 feat(ci): add documentation preview environment for PRs, #1244 fix(cli): fix secure_getenv() bypass of one-shot token protection
✅ Playwright: github.com title contains "GitHub"
✅ File Write: /tmp/gh-aw/agent/smoke-test-claude-23031566911.txt created
✅ Bash: File content verified

💥 [THE END] — Illustrated by Smoke Claude for issue #1280

@github-actions

This comment has been minimized.

@github-actions
Copy link
Contributor

Smoke test results for run 23031566901@Mossaka

✅ GitHub MCP: Last 2 merged PRs: #1273 "feat(ci): add documentation preview environment for PRs", #1272 "feat(ci): add weekly performance monitoring workflow"
✅ Playwright: github.com title contains "GitHub"
✅ File Write: /tmp/gh-aw/agent/smoke-test-copilot-23031566901.txt created
✅ Bash: File verified via cat

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot for issue #1280

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an optional DNS-over-HTTPS (DoH) mode to the firewall wrapper by introducing a DoH proxy sidecar and wiring it through CLI/config, Docker Compose generation, and host/container iptables.

Changes:

  • Add dnsOverHttps to WrapperConfig plus a new --dns-over-https CLI flag.
  • Generate a doh-proxy (cloudflared) sidecar in docker-compose and pass agent env/DNS settings to route DNS via it.
  • Extend host/agent iptables and tests to allow DoH proxy traffic (DNS to the proxy, HTTPS egress from the proxy).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/types.ts Adds dnsOverHttps config and documentation.
src/cli.ts Adds --dns-over-https flag and validation; plumbs into config.
src/cli-workflow.ts Passes DoH proxy IP into host iptables setup when enabled.
src/docker-manager.ts Adds DoH sidecar service + agent DNS/env wiring in docker-compose generation.
src/docker-manager.test.ts Unit tests for DoH sidecar + agent DNS/env behavior.
src/host-iptables.ts Allows DoH proxy DNS (53) and DoH proxy HTTPS egress (443).
src/host-iptables.test.ts Tests host iptables rule insertion for DoH mode.
containers/agent/entrypoint.sh Writes resolv.conf differently in DoH mode.
containers/agent/setup-iptables.sh Adjusts agent iptables rules to allow DNS to DoH proxy in DoH mode.
Comments suppressed due to low confidence (1)

containers/agent/setup-iptables.sh:309

  • Even when DoH mode is enabled, the agent still explicitly allows DNS to Docker embedded DNS (127.0.0.11). Since 127.0.0.11 can resolve external domains by forwarding to upstream resolvers, this leaves a plaintext DNS path and undermines the DoH threat model. If DoH is intended to be enforced, consider removing external-resolution capability via 127.0.0.11 in DoH mode (e.g., stop using embedded DNS for service discovery by switching internal service references to fixed IPs / /etc/hosts).
# Allow localhost traffic
iptables -A OUTPUT -o lo -j ACCEPT

# Allow DNS queries to trusted servers (or DoH proxy)
if [ "$AWF_DOH_ENABLED" = "true" ] && [ -n "$AWF_DOH_PROXY_IP" ]; then
  iptables -A OUTPUT -p udp -d "$AWF_DOH_PROXY_IP" --dport 53 -j ACCEPT
  iptables -A OUTPUT -p tcp -d "$AWF_DOH_PROXY_IP" --dport 53 -j ACCEPT
else
  for dns_server in "${IPV4_DNS_SERVERS[@]}"; do
    iptables -A OUTPUT -p udp -d "$dns_server" --dport 53 -j ACCEPT
    iptables -A OUTPUT -p tcp -d "$dns_server" --dport 53 -j ACCEPT
  done
fi

# Allow DNS to Docker's embedded DNS server
iptables -A OUTPUT -p udp -d 127.0.0.11 --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp -d 127.0.0.11 --dport 53 -j ACCEPT

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1181 to +1182
// Security hardening: Drop all capabilities
cap_drop: ['ALL'],
Comment on lines +1166 to +1168
container_name: 'awf-doh-proxy',
image: 'cloudflare/cloudflared:latest',
networks: {
Comment on lines +1174 to +1180
healthcheck: {
test: ['CMD', 'nslookup', '-port=53', 'cloudflare.com', '127.0.0.1'],
interval: '5s',
timeout: '3s',
retries: 5,
start_period: '10s',
},
Comment on lines +77 to +86
# DNS-over-HTTPS mode: use DoH proxy as the DNS resolver
{
echo "# Generated by awf entrypoint (DNS-over-HTTPS mode)"
echo "# Docker embedded DNS for service name resolution (squid-proxy, etc.)"
echo "nameserver 127.0.0.11"
echo "# DNS-over-HTTPS proxy for encrypted internet domain resolution"
echo "nameserver $AWF_DOH_PROXY_IP"
echo "options ndots:0"
} > /etc/resolv.conf
echo "[entrypoint] DNS configured with Docker embedded DNS (127.0.0.11) and DoH proxy ($AWF_DOH_PROXY_IP)"
Comment on lines +502 to +515
// 5a. Allow DNS traffic to DoH proxy sidecar (when enabled)
if (dohProxyIp) {
logger.debug(`Allowing DNS traffic to DoH proxy sidecar at ${dohProxyIp}:53`);
await execa('iptables', [
'-t', 'filter', '-A', CHAIN_NAME,
'-p', 'udp', '-d', dohProxyIp, '--dport', '53',
'-j', 'ACCEPT',
]);
await execa('iptables', [
'-t', 'filter', '-A', CHAIN_NAME,
'-p', 'tcp', '-d', dohProxyIp, '--dport', '53',
'-j', 'ACCEPT',
]);
}
Comment on lines +50 to +52
// When DoH is enabled, the DoH proxy needs direct HTTPS access to the resolver
const dohProxyIp = config.dnsOverHttps ? '172.30.0.40' : undefined;
await dependencies.setupHostIptables(networkConfig.squidIp, 3128, dnsServers, apiProxyIp, dohProxyIp);
Comment on lines +298 to +304
* When specified, a DoH proxy sidecar is deployed that encrypts DNS queries
* over HTTPS, preventing DNS spoofing and interception. The agent container's
* DNS is routed through this proxy instead of using unencrypted UDP DNS.
*
* The DoH proxy runs as a separate container on the awf-net network and has
* direct HTTPS access to the DoH resolver (bypassing Squid).
*
@github-actions
Copy link
Contributor

Smoke test results
PR titles: feat(cli): add DNS-over-HTTPS support via --dns-over-https flag | feat(cli): add --ruleset-file for YAML domain rule configuration
GitHub MCP (merged PRs): ✅
safeinputs-gh pr list: ✅
Playwright github.com title: ✅
Tavily search: ❌ (tool unavailable)
File write+cat: ✅
Discussion comment: ✅
Build npm ci && npm run build: ✅
Overall: FAIL

🔮 The oracle has spoken through Smoke Codex for issue #1280

@github-actions
Copy link
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3 ❌ NO
Node.js v24.14.0 v20.20.1 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Overall: ❌ FAILED — Python and Node.js versions differ between host and chroot environment.

Tested by Smoke Chroot for issue #1280

@Mossaka Mossaka force-pushed the feat/094-dns-over-https branch from e50e49c to fff744d Compare March 13, 2026 01:39
@github-actions
Copy link
Contributor

github-actions bot commented Mar 13, 2026

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 84.58% 84.61% 📈 +0.03%
Statements 84.53% 84.56% 📈 +0.03%
Functions 85.28% 85.34% 📈 +0.06%
Branches 77.45% 77.50% 📈 +0.05%
📁 Per-file Coverage Changes (3 files)
File Lines (Before → After) Statements (Before → After)
src/cli.ts 56.0% → 55.9% (-0.07%) 56.5% → 56.4% (-0.09%)
src/host-iptables.ts 81.0% → 81.6% (+0.58%) 81.2% → 81.7% (+0.57%)
src/docker-manager.ts 87.0% → 87.7% (+0.68%) 86.4% → 87.0% (+0.66%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

@github-actions
Copy link
Contributor

Smoke Test (Codex) — PR #1280
Merged PR titles: feat(cli): add --enable-dind flag to opt-in to Docker socket access | feat(ci): add documentation preview environment for PRs
GitHub MCP merged PRs ✅ ; safeinputs-gh pr list ✅ ; Playwright title ✅
Tavily web search ❌ (tool unavailable)
File write ✅ ; cat verify ✅
Discussion query+comment ✅
Build ✅
Overall: FAIL

🔮 The oracle has spoken through Smoke Codex for issue #1280

@github-actions
Copy link
Contributor

Smoke test results for @Mossaka's PR:

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot for issue #1280

@github-actions
Copy link
Contributor

Smoke Test Results ✅ PASS

Test Result
GitHub MCP: #1276 feat(cli): add --enable-dind flag, #1273 feat(ci): add documentation preview
Playwright: github.com title contains "GitHub"
File write: smoke-test-claude-23032289010.txt created
Bash verify: file contents confirmed

💥 [THE END] — Illustrated by Smoke Claude for issue #1280

@github-actions
Copy link
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.12 Python 3.12.3 ❌ NO
Node.js v24.14.0 v20.20.0 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Result: FAILED — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot for issue #1280

@github-actions

This comment has been minimized.

Mossaka and others added 3 commits March 13, 2026 02:42
Deploy a cloudflare/cloudflared sidecar container as a DoH proxy when
--dns-over-https is used. Agent DNS queries are routed through the DoH
proxy, which encrypts them over HTTPS to prevent DNS spoofing and
interception. Legacy UDP DNS to external servers is blocked.

- Add --dns-over-https [resolver-url] CLI flag (default: dns.google)
- Add doh-proxy sidecar service with security hardening
- Update host-iptables to allow DoH proxy HTTPS access
- Update setup-iptables.sh to route DNS through DoH proxy
- Update entrypoint.sh to configure resolv.conf for DoH
- Add 14 unit tests for DoH configuration

Fixes #307

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract DNS-over-HTTPS validation into testable parseDnsOverHttps()
function and add 5 unit tests covering: undefined input, flag without
argument (default resolver), custom URL, non-https URL error, and
plain string error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Mossaka Mossaka force-pushed the feat/094-dns-over-https branch from fff744d to e961b69 Compare March 13, 2026 02:43
@github-actions
Copy link
Contributor

Smoke Test: PASS

✅ GitHub MCP: #1279 feat(cli): add --ruleset-file for YAML domain rule configuration; #1276 feat(cli): add --enable-dind flag to opt-in to Docker socket access
✅ Playwright: github.com title contains "GitHub"
✅ File write: /tmp/gh-aw/agent/smoke-test-claude-23033826882.txt created
✅ Bash verify: file contents confirmed

💥 [THE END] — Illustrated by Smoke Claude for issue #1280

@github-actions
Copy link
Contributor

Smoke test results for run 23033826912@Mossaka

✅ GitHub MCP: Last 2 merged PRs: #1279 feat(cli): add --ruleset-file for YAML domain rule configuration, #1276 feat(cli): add --enable-dind flag to opt-in to Docker socket access
✅ Playwright: github.com title contains "GitHub"
✅ File write: /tmp/gh-aw/agent/smoke-test-copilot-23033826912.txt created
✅ Bash: file contents verified

Overall: PASS

📰 BREAKING: Report filed by Smoke Copilot for issue #1280

@github-actions
Copy link
Contributor

Titles (last 2 merged):
feat(cli): add --ruleset-file for YAML domain rule configuration
feat(cli): add --enable-dind flag to opt-in to Docker socket access
GitHub MCP merged PRs: ✅
safeinputs-gh PR list: ✅
Playwright title check: ✅
Tavily search: ❌ (tool unavailable)
File write+cat: ✅; Discussion comment: ✅; Build: ✅
Overall: FAIL

🔮 The oracle has spoken through Smoke Codex for issue #1280

@github-actions
Copy link
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.12 Python 3.12.3 ❌ NO
Node.js v24.14.0 v20.20.0 ❌ NO
Go go1.22.12 go1.22.12 ✅ YES

Result: ❌ Not all versions matched — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot for issue #1280

@github-actions
Copy link
Contributor

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color 1/1 passed ✅ PASS
Go env 1/1 passed ✅ PASS
Go uuid 1/1 passed ✅ PASS
Java gson N/A ❌ FAIL
Java caffeine N/A ❌ FAIL
Node.js clsx All passed ✅ PASS
Node.js execa All passed ✅ PASS
Node.js p-limit All passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 7/8 ecosystems passed — ❌ FAIL


❌ Failure Details

Java (gson, caffeine) — Maven dependency download failed: network unreachable to repo.maven.apache.org.

The JAVA_TOOL_OPTIONS env var is set to route traffic through squid-proxy:3128, but that host does not resolve in this environment. Without proxy settings, direct HTTPS to Maven Central is also blocked (Network is unreachable).

[ERROR] Could not transfer artifact org.apache.maven.plugins:maven-resources-plugin:pom:3.4.0
        from/to central (https://repo.maven.apache.org/maven2): Network is unreachable

Both gson and caffeine fail at mvn compile before any tests can run. This is an infrastructure issue — Maven Central access requires either a working Squid proxy or an allowlisted direct connection.

Generated by Build Test Suite for issue #1280 ·

@Mossaka Mossaka merged commit 221cc8f into main Mar 13, 2026
61 checks passed
@Mossaka Mossaka deleted the feat/094-dns-over-https branch March 13, 2026 03:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[plan] implement dns-over-https support

2 participants