Skip to content

cmd/tailcat: add --dns to resolve SOCKS hostnames via the exit node - #148

Open
imcom wants to merge 1 commit into
tailscale:mainfrom
imcom:socks-remote-dns
Open

imcom wants to merge 1 commit into
tailscale:mainfrom
imcom:socks-remote-dns

Conversation

@imcom

@imcom imcom commented Oct 8, 2026

Copy link
Copy Markdown

The socks subcommand resolves exit-node destination hostnames with the local resolver and only sends the resulting IP through the tunnel. That doesn't work well when the client and the exit node see different DNS:

  • Names that exist only on the exit node's network (intranet or VPN split-DNS names) can't be resolved at all from the client side.
  • On hosts whose resolver answers every name with a fake IP for a transparent proxy (common in sandboxes and some corporate networks), the proxy dials the fake IP through the exit node, where it means nothing.

Add a --dns flag (with a TAILCAT_SOCKS_DNS environment variable default, like --derpmap-url's TAILCAT_DERPMAP_URL) listing DNS servers to resolve those hostnames with instead. The servers are queried with Go's resolver over TCP connections made with the client's DialTCP, so the queries travel through the exit node and names resolve as they do on its network. The servers are tried in order, each bounded by a 4-second timeout so a dead server leaves time in the SOCKS dial budget to fall back to the next; a definitive NXDOMAIN is returned without asking the rest. The local hosts file still applies first, and the RFC 6761 localhost names always resolve to loopback. Errors name the server actually queried rather than the local resolv.conf one.

--dns requires a argument, and a bad value is a usage error reported before connecting. Without the flag, hostnames resolve locally exactly as before.

The socks subcommand resolves exit-node destination hostnames with the
local resolver and only sends the resulting IP through the tunnel.
That doesn't work well when the client and the exit node see different
DNS:

  - Names that exist only on the exit node's network (intranet or VPN
    split-DNS names) can't be resolved at all from the client side.
  - On hosts whose resolver answers every name with a fake IP for a
    transparent proxy (common in sandboxes and some corporate
    networks), the proxy dials the fake IP through the exit node,
    where it means nothing.

Add a --dns flag (with a TAILCAT_SOCKS_DNS environment variable
default, like --derpmap-url's TAILCAT_DERPMAP_URL) listing DNS servers
to resolve those hostnames with instead. The servers are queried with
Go's resolver over TCP connections made with the client's DialTCP, so
the queries travel through the exit node and names resolve as they do
on its network. The servers are tried in order, each bounded by a
4-second timeout so a dead server leaves time in the SOCKS dial budget
to fall back to the next; a definitive NXDOMAIN is returned without
asking the rest. The local hosts file still applies first, and the
RFC 6761 localhost names always resolve to loopback. Errors name the
server actually queried rather than the local resolv.conf one.

--dns requires a <tc-addr> argument, and a bad value is a usage error
reported before connecting. Without the flag, hostnames resolve
locally exactly as before.

Signed-off-by: imcom <jinyu.bjut@gmail.com>

This branch has not been deployed

No deployments
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