cmd/tailscale,ipn: add Unix socket support for serve

Based on PR #16700 by @lox, adapted to current codebase.

Adds support for proxying HTTP requests to Unix domain sockets via
tailscale serve unix:/path/to/socket, enabling exposure of services
like Docker, containerd, PHP-FPM over Tailscale without TCP bridging.

The implementation includes reasonable protections against exposure of
tailscaled's own socket.

Adaptations from original PR:
- Use net.Dialer.DialContext instead of net.Dial for context propagation
- Use http.Transport with Protocols API (current h2c approach, not http2.Transport)
- Resolve conflicts with hasScheme variable in ExpandProxyTargetValue

Updates #9771

Signed-off-by: Peter A. <ink.splatters@pm.me>
Co-authored-by: Lachlan Donald <lachlan@ljd.cc>
This commit is contained in:
Peter A.
2025-11-28 23:39:41 +01:00
committed by Brad Fitzpatrick
parent 557457f3c2
commit f4d34f38be
8 changed files with 482 additions and 3 deletions

View File

@@ -10,6 +10,7 @@ import (
"net"
"net/netip"
"net/url"
"runtime"
"slices"
"strconv"
"strings"
@@ -713,6 +714,21 @@ func ExpandProxyTargetValue(target string, supportedSchemes []string, defaultSch
return fmt.Sprintf("%s://%s:%d", defaultScheme, host, port), nil
}
// handle unix: scheme specially - it doesn't use standard URL format
if strings.HasPrefix(target, "unix:") {
if !slices.Contains(supportedSchemes, "unix") {
return "", fmt.Errorf("unix sockets are not supported for this target type")
}
if runtime.GOOS == "windows" {
return "", fmt.Errorf("unix socket serve target is not supported on Windows")
}
path := strings.TrimPrefix(target, "unix:")
if path == "" {
return "", fmt.Errorf("unix socket path cannot be empty")
}
return target, nil
}
hasScheme := true
// prepend scheme if not present
if !strings.Contains(target, "://") {