Skip to content

feat(net): support host.docker.internal DNS and gateway-to-localhost translation#157

Merged
AprilNEA merged 2 commits intomasterfrom
feat/host-docker-internal
Apr 1, 2026
Merged

feat(net): support host.docker.internal DNS and gateway-to-localhost translation#157
AprilNEA merged 2 commits intomasterfrom
feat/host-docker-internal

Conversation

@AprilNEA
Copy link
Copy Markdown
Member

@AprilNEA AprilNEA commented Apr 1, 2026

Summary

  • Register host.docker.internal and gateway.docker.internal in the shared DNS LocalHostsTable at daemon startup, resolving to the gateway IP
  • Translate gateway-IP-destined TCP (in TcpBridge::gate_syns) and UDP (in UdpProxy::proxy_udp) connections to 127.0.0.1 so they reach host services
  • Previously, host.docker.internal returned NXDOMAIN and even manually resolved gateway connections failed because 10.0.2.1 doesn't exist as a real interface on the host

Context

host.docker.internal is a Docker Desktop compatibility feature used by many containerized applications to reach host services (databases, API servers, dev tools). ArcBox had zero support — two independent bugs:

  1. DNS: No entry existed. Queries passed through guest DNS → gateway DNS → upstream → NXDOMAIN.
  2. Data path: The TCP bridge called TcpStream::connect(10.0.2.1:port) on the host OS, where 10.0.2.1 only exists in user-space smoltcp. The UDP proxy had the same issue.

The fix resolves both: DNS returns the gateway IP, and the bridge/proxy translate gateway IP → 127.0.0.1 before connecting. This matches Docker Desktop's effective behavior (vpnkit routes gateway connections to host loopback).

Test plan

  • cargo clippy and cargo test pass (verified locally, 2 pre-existing pool test flakes excluded)
  • Manual: start a TCP server on host port N, run docker run --rm alpine wget -qO- http://host.docker.internal:N — should succeed
  • Verify gateway.docker.internal also resolves correctly
  • Verify UDP to host.docker.internal works (e.g. DNS client targeting host DNS)

…translation

Containers need to access services running on the host machine via the
standard Docker hostname `host.docker.internal`. This was completely
missing — DNS returned NXDOMAIN, and even if resolved, TCP/UDP
connections to the gateway IP failed because the host OS has no route
to 10.0.2.1 (it only exists in user-space smoltcp).

Two fixes:

1. Register `host.docker.internal` and `gateway.docker.internal` in the
   shared DNS LocalHostsTable at daemon startup, resolving to the
   gateway IP. Queries flow: container → guest DNS → gateway DNS →
   LocalHostsTable hit → response.

2. Translate gateway-IP-destined connections to 127.0.0.1 in the TCP
   bridge (gate_syns) and UDP proxy (proxy_udp). The gateway IS the
   host process, so loopback reaches any service on 0.0.0.0 or
   127.0.0.1 — matching Docker Desktop's effective behavior.
Copilot AI review requested due to automatic review settings April 1, 2026 08:06
Copy link
Copy Markdown
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 Docker Desktop–compatible host.docker.internal / gateway.docker.internal support by ensuring those names resolve inside the VM and by translating gateway-IP–destined traffic to host loopback so connections actually reach host services.

Changes:

  • Register host.docker.internal and gateway.docker.internal DNS entries at daemon startup, pointing to the VM gateway IP.
  • Translate outbound TCP gateway-IP connections to 127.0.0.1 in TcpBridge::gate_syns.
  • Translate outbound UDP gateway-IP flows to 127.0.0.1 in UdpProxy::proxy_udp.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
virt/arcbox-net/src/darwin/tcp_bridge.rs Adds gateway-IP→loopback translation for TCP connects; updates constructor/tests accordingly.
virt/arcbox-net/src/darwin/socket_proxy.rs Adds gateway-IP→loopback translation for UDP flow sockets; updates constructor/callers/tests.
virt/arcbox-net/src/darwin/datapath_loop.rs Wires the gateway IP into the TcpBridge constructor.
app/arcbox-daemon/src/services.rs Registers Docker compatibility DNS names (host.docker.internal, gateway.docker.internal) to the gateway IP.

Address review feedback:

- Force proxy_target=None when dst_ip==gateway_ip so the loopback
  translation is never bypassed by a configured system proxy.
- Add TCP test: SYN to GW_IP connects successfully via loopback.
- Add UDP test: datagram to GW_IP is delivered to a loopback listener.
@AprilNEA AprilNEA merged commit 925897d into master Apr 1, 2026
4 checks passed
@AprilNEA AprilNEA deleted the feat/host-docker-internal branch April 1, 2026 08:20
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.

2 participants