feature, net/tshttpproxy: pull out support for using proxies as a feature

Saves 139 KB.

Also Synology support, which I saw had its own large-ish proxy parsing
support on Linux, but support for proxies without Synology proxy
support is reasonable, so I pulled that out as its own thing.

Updates #12614

Change-Id: I22de285a3def7be77fdcf23e2bec7c83c9655593
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2025-09-30 09:12:42 -07:00
committed by Brad Fitzpatrick
parent 9b997c8f2f
commit 442a3a779d
45 changed files with 267 additions and 79 deletions
@@ -7,7 +7,7 @@
package buildfeatures
// HasOutboundProxy is whether the binary was built with support for modular feature "Outbound localhost HTTP/SOCK5 proxy support".
// HasOutboundProxy is whether the binary was built with support for modular feature "Support running an outbound localhost HTTP/SOCK5 proxy support that sends traffic over Tailscale".
// Specifically, it's whether the binary was NOT built with the "ts_omit_outboundproxy" build tag.
// It's a const so it can be used for dead code elimination.
const HasOutboundProxy = false
@@ -7,7 +7,7 @@
package buildfeatures
// HasOutboundProxy is whether the binary was built with support for modular feature "Outbound localhost HTTP/SOCK5 proxy support".
// HasOutboundProxy is whether the binary was built with support for modular feature "Support running an outbound localhost HTTP/SOCK5 proxy support that sends traffic over Tailscale".
// Specifically, it's whether the binary was NOT built with the "ts_omit_outboundproxy" build tag.
// It's a const so it can be used for dead code elimination.
const HasOutboundProxy = true
@@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build ts_omit_synology
package buildfeatures
// HasSynology is whether the binary was built with support for modular feature "Synology NAS integration (applies to Linux builds only)".
// Specifically, it's whether the binary was NOT built with the "ts_omit_synology" build tag.
// It's a const so it can be used for dead code elimination.
const HasSynology = false
@@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build !ts_omit_synology
package buildfeatures
// HasSynology is whether the binary was built with support for modular feature "Synology NAS integration (applies to Linux builds only)".
// Specifically, it's whether the binary was NOT built with the "ts_omit_synology" build tag.
// It's a const so it can be used for dead code elimination.
const HasSynology = true
@@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build ts_omit_useproxy
package buildfeatures
// HasUseProxy is whether the binary was built with support for modular feature "Support using system proxies as specified by env vars or the system configuration to reach Tailscale servers.".
// Specifically, it's whether the binary was NOT built with the "ts_omit_useproxy" build tag.
// It's a const so it can be used for dead code elimination.
const HasUseProxy = false
@@ -0,0 +1,13 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Code generated by gen.go; DO NOT EDIT.
//go:build !ts_omit_useproxy
package buildfeatures
// HasUseProxy is whether the binary was built with support for modular feature "Support using system proxies as specified by env vars or the system configuration to reach Tailscale servers.".
// Specifically, it's whether the binary was NOT built with the "ts_omit_useproxy" build tag.
// It's a const so it can be used for dead code elimination.
const HasUseProxy = true
+7 -3
View File
@@ -6,9 +6,13 @@
// to ensure all conditional features are registered.
package condregister
// Portmapper is special in that the CLI also needs to link it in,
// so it's pulled out into its own package, rather than using a maybe_*.go
// file in condregister.
import (
// Portmapper is special in that the CLI also needs to link it in,
// so it's pulled out into its own package, rather than using a maybe_*.go
// file in condregister.
_ "tailscale.com/feature/condregister/portmapper"
// HTTP proxy support is also needed by the CLI, and tsnet, so it's its
// own package too.
_ "tailscale.com/feature/condregister/useproxy"
)
+6
View File
@@ -0,0 +1,6 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Package useproxy registers support for using proxies
// if it's not disabled via the ts_omit_useproxy build tag.
package useproxy
@@ -0,0 +1,8 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
//go:build !ts_omit_useproxy
package useproxy
import _ "tailscale.com/feature/useproxy"
+7 -1
View File
@@ -50,7 +50,8 @@ func (h *Hook[Func]) Set(f Func) {
}
// Get returns the hook function, or panics if it hasn't been set.
// Use IsSet to check if it's been set.
// Use IsSet to check if it's been set, or use GetOrNil if you're
// okay with a nil return value.
func (h *Hook[Func]) Get() Func {
if !h.ok {
panic("Get on unset feature hook, without IsSet")
@@ -64,6 +65,11 @@ func (h *Hook[Func]) GetOk() (f Func, ok bool) {
return h.f, h.ok
}
// GetOrNil returns the hook function or nil if it hasn't been set.
func (h *Hook[Func]) GetOrNil() Func {
return h.f
}
// Hooks is a slice of funcs.
//
// As opposed to a single Hook, this is meant to be used when
+10 -2
View File
@@ -121,7 +121,7 @@ var Features = map[FeatureTag]FeatureMeta{
"oauthkey": {"OAuthKey", "OAuth secret-to-authkey resolution support", nil},
"outboundproxy": {
Sym: "OutboundProxy",
Desc: "Outbound localhost HTTP/SOCK5 proxy support",
Desc: "Support running an outbound localhost HTTP/SOCK5 proxy support that sends traffic over Tailscale",
Deps: []FeatureTag{"netstack"},
},
"osrouter": {
@@ -172,6 +172,10 @@ var Features = map[FeatureTag]FeatureMeta{
Desc: "Tailscale SSH support",
Deps: []FeatureTag{"dbus", "netstack"},
},
"synology": {
Sym: "Synology",
Desc: "Synology NAS integration (applies to Linux builds only)",
},
"syspolicy": {"SystemPolicy", "System policy configuration (MDM) support", nil},
"systray": {
Sym: "SysTray",
@@ -182,7 +186,11 @@ var Features = map[FeatureTag]FeatureMeta{
"tailnetlock": {"TailnetLock", "Tailnet Lock support", nil},
"tap": {"Tap", "Experimental Layer 2 (ethernet) support", nil},
"tpm": {"TPM", "TPM support", nil},
"wakeonlan": {"WakeOnLAN", "Wake-on-LAN support", nil},
"useproxy": {
Sym: "UseProxy",
Desc: "Support using system proxies as specified by env vars or the system configuration to reach Tailscale servers.",
},
"wakeonlan": {"WakeOnLAN", "Wake-on-LAN support", nil},
"webclient": {
Sym: "WebClient", Desc: "Web client support",
Deps: []FeatureTag{"serve"},
+25
View File
@@ -3,6 +3,11 @@
package feature
import (
"net/http"
"net/url"
)
// HookCanAutoUpdate is a hook for the clientupdate package
// to conditionally initialize.
var HookCanAutoUpdate Hook[func() bool]
@@ -15,3 +20,23 @@ func CanAutoUpdate() bool {
}
return false
}
// HookProxyFromEnvironment is a hook for feature/useproxy to register
// a function to use as http.ProxyFromEnvironment.
var HookProxyFromEnvironment Hook[func(*http.Request) (*url.URL, error)]
// HookProxyInvalidateCache is a hook for feature/useproxy to register
// [tshttpproxy.InvalidateCache].
var HookProxyInvalidateCache Hook[func()]
// HookProxyGetAuthHeader is a hook for feature/useproxy to register
// [tshttpproxy.GetAuthHeader].
var HookProxyGetAuthHeader Hook[func(*url.URL) (string, error)]
// HookProxySetSelfProxy is a hook for feature/useproxy to register
// [tshttpproxy.SetSelfProxy].
var HookProxySetSelfProxy Hook[func(...string)]
// HookProxySetTransportGetProxyConnectHeader is a hook for feature/useproxy to register
// [tshttpproxy.SetTransportGetProxyConnectHeader].
var HookProxySetTransportGetProxyConnectHeader Hook[func(*http.Transport)]
+18
View File
@@ -0,0 +1,18 @@
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
// Package useproxy registers support for using system proxies.
package useproxy
import (
"tailscale.com/feature"
"tailscale.com/net/tshttpproxy"
)
func init() {
feature.HookProxyFromEnvironment.Set(tshttpproxy.ProxyFromEnvironment)
feature.HookProxyInvalidateCache.Set(tshttpproxy.InvalidateCache)
feature.HookProxyGetAuthHeader.Set(tshttpproxy.GetAuthHeader)
feature.HookProxySetSelfProxy.Set(tshttpproxy.SetSelfProxy)
feature.HookProxySetTransportGetProxyConnectHeader.Set(tshttpproxy.SetTransportGetProxyConnectHeader)
}