Skip to content

tailcat, cmd/tailcat: add exit-node UDP forwarding - #80

Closed
OmarAlaaeldein wants to merge 1 commit into
tailscale:mainfrom
OmarAlaaeldein:feat/exit-node-udp
Closed

tailcat, cmd/tailcat: add exit-node UDP forwarding#80
OmarAlaaeldein wants to merge 1 commit into
tailscale:mainfrom
OmarAlaaeldein:feat/exit-node-udp

Conversation

@OmarAlaaeldein

Copy link
Copy Markdown

Why

Server.OnTCPForward already makes tailcat serve exit-node a TCP exit node. UDP is still a dead end: NetstackDialUDP panics (unreachable from tailcat) and buildFilter never admits ipproto.UDP, so a client TUN cannot send QUIC, DNS, or other datagrams through the tunnel.

AllowProxy is already documented as applying to TCP or UDP, but it was never consulted on the TCP path either.

What

  • Server.OnUDPForward plus GetUDPHandlerForFlow, same NAT64 unwrap as TCP
  • Packet filter admits UDP to any destination when OnUDPForward is set
  • NetstackDialUDPns.DialContextUDP on both server and client
  • Client.DialUDP / HasServerCap / ServerCaps
  • Capability trailer on meowed: CapExitTCP (0x01), CapExitUDP (0x02). Legacy 5-byte meowed still parses as caps=0
  • AllowProxy enforced on both TCP and UDP exit flows
  • CLI serve exit-node copies datagrams (60s idle, 65535-byte buffers)

Caller-defined AllowProxy stays the policy hook; this PR does not bake in loopback/metadata denials.

Tests

  • go test . (includes TestMeowedCapsRoundTrip)
  • go test ./cmd/tailcat -run 'TestServeExitNodeUDP|TestAllowProxyRejection|TestServeExitNode$'
  • go vet ./...

OnTCPForward already turns a server into a TCP exit node, but
NetstackDialUDP panics and the packet filter never admits UDP, so a
client TUN cannot send QUIC, DNS, or other datagrams through
`tailcat serve exit-node`.

Add Server.OnUDPForward, advertise CapExitUDP in the meowed trailer
(legacy 5-byte meowed still parses as caps=0), enforce AllowProxy on
both TCP and UDP, and copy datagrams in the CLI exit-node handler.
@OmarAlaaeldein

Copy link
Copy Markdown
Author

Closing in favor of #25, which is the fuller library design (OnUDP/OnUDPForward, idle timeout, SOCKS UDP) and already has maintainer review.

The two pieces this PR had that #25 does not:

  1. CapExitUDP / CapExitTCP in the meowed trailer so a client can fail closed when the peer is TCP-only, instead of discovering that at DialUDP time.
  2. AllowProxy actually consulted on both TCP and UDP exit flows (the field already exists and is documented for both).

Happy to send those as a follow-up on top of #25 if useful.

@OmarAlaaeldein

Copy link
Copy Markdown
Author

Closing in favor of #25.

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