tailscale: Revert dialer deprecation and remove control_http_client

This commit is contained in:
世界 2026-05-20 14:50:36 +08:00
parent cf06742014
commit 8785b39b15
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
7 changed files with 55 additions and 120 deletions

View File

@ -2,11 +2,6 @@
icon: material/new-box
---
!!! quote "Changes in sing-box 1.14.0"
:material-plus: [control_http_client](#control_http_client)
:material-delete-clock: [Dial Fields](#dial-fields)
!!! quote "Changes in sing-box 1.13.0"
:material-plus: [relay_server_port](#relay_server_port)
@ -27,7 +22,6 @@ icon: material/new-box
"state_directory": "",
"auth_key": "",
"control_url": "",
"control_http_client": {}, // or ""
"ephemeral": false,
"hostname": "",
"accept_routes": false,
@ -154,18 +148,10 @@ UDP NAT expiration time.
`5m` will be used by default.
#### control_http_client
!!! question "Since sing-box 1.14.0"
HTTP Client for connecting to the Tailscale control plane.
See [HTTP Client Fields](/configuration/shared/http-client/) for details.
### Dial Fields
!!! failure "Deprecated in sing-box 1.14.0"
!!! note
Dial Fields in Tailscale endpoints are deprecated in sing-box 1.14.0 and will be removed in sing-box 1.16.0, use `control_http_client` instead.
Dial Fields in Tailscale endpoints only control how it connects to the control plane and have nothing to do with actual connections.
See [Dial Fields](/configuration/shared/dial/) for details.

View File

@ -2,11 +2,6 @@
icon: material/new-box
---
!!! quote "sing-box 1.14.0 中的更改"
:material-plus: [control_http_client](#control_http_client)
:material-delete-clock: [拨号字段](#拨号字段)
!!! quote "sing-box 1.13.0 中的更改"
:material-plus: [relay_server_port](#relay_server_port)
@ -27,7 +22,6 @@ icon: material/new-box
"state_directory": "",
"auth_key": "",
"control_url": "",
"control_http_client": {}, // 或 ""
"ephemeral": false,
"hostname": "",
"accept_routes": false,
@ -153,18 +147,10 @@ UDP NAT 过期时间。
默认使用 `5m`
#### control_http_client
!!! question "自 sing-box 1.14.0 起"
用于连接 Tailscale 控制平面的 HTTP 客户端。
参阅 [HTTP 客户端字段](/zh/configuration/shared/http-client/) 了解详情。
### 拨号字段
!!! failure "已在 sing-box 1.14.0 废弃"
!!! note
Tailscale 端点中的拨号字段已在 sing-box 1.14.0 废弃且将在 sing-box 1.16.0 中被移除,请使用 `control_http_client` 代替
Tailscale 端点中的拨号字段仅控制它如何连接到控制平面,与实际连接无关。
参阅 [拨号字段](/zh/configuration/shared/dial/) 了解详情。

View File

@ -20,13 +20,6 @@ Configure `http_clients` and `route.default_http_client` explicitly.
Old behavior will be removed in sing-box 1.16.0.
#### Legacy dialer options in Tailscale endpoint
Legacy dialer options in Tailscale endpoints are deprecated,
use `control_http_client` instead.
Old fields will be removed in sing-box 1.16.0.
#### Inline ACME options in TLS
Inline ACME options (`tls.acme`) are deprecated

View File

@ -20,13 +20,6 @@ icon: material/delete-alert
旧行为将在 sing-box 1.16.0 中被移除。
#### Tailscale 端点中的旧版拨号选项
Tailscale 端点中的旧版拨号选项已废弃,
请使用 `control_http_client` 代替。
旧字段将在 sing-box 1.16.0 中被移除。
#### TLS 中的内联 ACME 选项
TLS 中的内联 ACME 选项(`tls.acme`)已废弃,

View File

@ -101,14 +101,6 @@ var OptionLegacyRuleSetDownloadDetour = Note{
EnvName: "LEGACY_RULE_SET_DOWNLOAD_DETOUR",
}
var OptionLegacyTailscaleEndpointDialer = Note{
Name: "legacy-tailscale-endpoint-dialer",
Description: "legacy dialer options in Tailscale endpoint",
DeprecatedVersion: "1.14.0",
ScheduledVersion: "1.16.0",
EnvName: "LEGACY_TAILSCALE_ENDPOINT_DIALER",
}
var OptionRuleSetIPCIDRAcceptEmpty = Note{
Name: "dns-rule-rule-set-ip-cidr-accept-empty",
Description: "Legacy `rule_set_ip_cidr_accept_empty` DNS rule item",
@ -168,7 +160,6 @@ var Options = []Note{
OptionLegacyDomainStrategyOptions,
OptionInlineACME,
OptionLegacyRuleSetDownloadDetour,
OptionLegacyTailscaleEndpointDialer,
OptionRuleSetIPCIDRAcceptEmpty,
OptionLegacyDNSAddressFilter,
OptionLegacyDNSRuleStrategy,

View File

@ -11,12 +11,10 @@ import (
)
type TailscaleEndpointOptions struct {
// Deprecated: use control_http_client instead
DialerOptions
StateDirectory string `json:"state_directory,omitempty"`
AuthKey string `json:"auth_key,omitempty"`
ControlURL string `json:"control_url,omitempty"`
ControlHTTPClient *HTTPClientOptions `json:"control_http_client,omitempty"`
Ephemeral bool `json:"ephemeral,omitempty"`
Hostname string `json:"hostname,omitempty"`
AcceptRoutes bool `json:"accept_routes,omitempty"`

View File

@ -4,6 +4,7 @@ package tailscale
import (
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
@ -27,7 +28,6 @@ import (
"github.com/sagernet/sing-box/adapter/endpoint"
"github.com/sagernet/sing-box/common/dialer"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/experimental/deprecated"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/route/rule"
@ -41,6 +41,7 @@ import (
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/ntp"
"github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/filemanager"
_ "github.com/sagernet/tailscale/feature/relayserver"
@ -116,45 +117,6 @@ type Endpoint struct {
fallbackTCPCloser func()
}
func (t *Endpoint) registerNetstackHandlers() {
netstack := t.server.ExportNetstack()
if netstack == nil {
return
}
previousTCP := netstack.GetTCPHandlerForFlow
netstack.GetTCPHandlerForFlow = func(src, dst netip.AddrPort) (handler func(net.Conn), intercept bool) {
if previousTCP != nil {
handler, intercept = previousTCP(src, dst)
if handler != nil || !intercept {
return handler, intercept
}
}
return func(conn net.Conn) {
ctx := log.ContextWithNewID(t.ctx)
source := M.SocksaddrFrom(src.Addr(), src.Port())
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
t.NewConnectionEx(ctx, conn, source, destination, nil)
}, true
}
previousUDP := netstack.GetUDPHandlerForFlow
netstack.GetUDPHandlerForFlow = func(src, dst netip.AddrPort) (handler func(nettype.ConnPacketConn), intercept bool) {
if previousUDP != nil {
handler, intercept = previousUDP(src, dst)
if handler != nil || !intercept {
return handler, intercept
}
}
return func(conn nettype.ConnPacketConn) {
ctx := log.ContextWithNewID(t.ctx)
source := M.SocksaddrFrom(src.Addr(), src.Port())
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
packetConn := bufio.NewUnbindPacketConnWithAddr(conn, destination)
t.NewPacketConnectionEx(ctx, packetConn, source, destination, nil)
}, true
}
}
func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TailscaleEndpointOptions) (adapter.Endpoint, error) {
stateDirectory := options.StateDirectory
if stateDirectory == "" {
@ -196,19 +158,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
// controlplane.tailscale.com
remoteIsDomain = true
}
hasLegacyDialer := !reflect.DeepEqual(options.DialerOptions, option.DialerOptions{})
hasControlHTTPClient := options.ControlHTTPClient != nil && !options.ControlHTTPClient.IsEmpty()
if hasLegacyDialer && hasControlHTTPClient {
return nil, E.New("control_http_client is conflict with deprecated dialer options")
}
controlHTTPClientOptions := common.PtrValueOrDefault(options.ControlHTTPClient)
if hasLegacyDialer {
deprecated.Report(ctx, deprecated.OptionLegacyTailscaleEndpointDialer)
controlHTTPClientOptions.DialerOptions = options.DialerOptions
}
if remoteIsDomain {
controlHTTPClientOptions.ResolveOnDetour = true
}
outboundDialer, err := dialer.NewWithOptions(dialer.Options{
Context: ctx,
Options: options.DialerOptions,
@ -220,12 +169,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
return nil, err
}
dnsRouter := service.FromContext[adapter.DNSRouter](ctx)
httpClientManager := service.FromContext[adapter.HTTPClientManager](ctx)
controlTransport, err := httpClientManager.ResolveTransport(ctx, logger, controlHTTPClientOptions)
if err != nil {
return nil, E.Cause(err, "create control HTTP client")
}
controlHTTPClient := &http.Client{Transport: controlTransport}
server := &tsnet.Server{
Dir: stateDirectory,
Hostname: hostname,
@ -243,11 +186,22 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
LookupHook: func(ctx context.Context, host string) ([]netip.Addr, error) {
return dnsRouter.Lookup(ctx, host, outboundDialer.(dialer.ResolveDialer).QueryOptions())
},
DNS: &dnsConfigurtor{},
HTTPClient: controlHTTPClient,
DNS: &dnsConfigurtor{},
HTTPClient: &http.Client{
Transport: &http.Transport{
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
return outboundDialer.DialContext(ctx, network, M.ParseSocksaddr(address))
},
TLSClientConfig: &tls.Config{
RootCAs: adapter.RootPoolFromContext(ctx),
Time: ntp.TimeFuncFromContext(ctx),
},
},
},
}
return &Endpoint{
Adapter: endpoint.NewAdapterWithDialerOptions(C.TypeTailscale, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, controlHTTPClientOptions.DialerOptions),
Adapter: endpoint.NewAdapter(C.TypeTailscale, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, nil),
ctx: ctx,
router: router,
logger: logger,
@ -401,7 +355,41 @@ func (t *Endpoint) postStart() error {
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
t.stack = ipStack
t.icmpForwarder = icmpForwarder
t.registerNetstackHandlers()
netstack := t.server.ExportNetstack()
if netstack != nil {
previousTCP := netstack.GetTCPHandlerForFlow
netstack.GetTCPHandlerForFlow = func(src, dst netip.AddrPort) (handler func(net.Conn), intercept bool) {
if previousTCP != nil {
handler, intercept = previousTCP(src, dst)
if handler != nil || !intercept {
return handler, intercept
}
}
return func(conn net.Conn) {
ctx := log.ContextWithNewID(t.ctx)
source := M.SocksaddrFrom(src.Addr(), src.Port())
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
t.NewConnectionEx(ctx, conn, source, destination, nil)
}, true
}
previousUDP := netstack.GetUDPHandlerForFlow
netstack.GetUDPHandlerForFlow = func(src, dst netip.AddrPort) (handler func(nettype.ConnPacketConn), intercept bool) {
if previousUDP != nil {
handler, intercept = previousUDP(src, dst)
if handler != nil || !intercept {
return handler, intercept
}
}
return func(conn nettype.ConnPacketConn) {
ctx := log.ContextWithNewID(t.ctx)
source := M.SocksaddrFrom(src.Addr(), src.Port())
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
packetConn := bufio.NewUnbindPacketConnWithAddr(conn, destination)
t.NewPacketConnectionEx(ctx, packetConn, source, destination, nil)
}, true
}
}
localBackend := t.server.ExportLocalBackend()
perfs := &ipn.MaskedPrefs{