From 0585f6d06579ac546604f015ba4dfa8394816397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 17 Dec 2025 21:45:18 +0800 Subject: [PATCH] Add ECH support for NaiveProxy outbound and tls.ech.query_server_name option - Enable ECH for NaiveProxy outbound with DNS resolver integration - Add query_server_name option to override domain for ECH HTTPS record queries - Update cronet-go dependency and remove windows_386 support --- .github/CRONET_GO_VERSION | 2 +- common/tls/ech.go | 23 ++++-- docs/configuration/outbound/naive.md | 2 +- docs/configuration/outbound/naive.zh.md | 2 +- docs/configuration/shared/tls.md | 12 +++ docs/configuration/shared/tls.zh.md | 12 +++ go.mod | 49 ++++++------- go.sum | 98 ++++++++++++------------- option/tls.go | 7 +- protocol/naive/outbound.go | 50 ++++++++++++- 10 files changed, 167 insertions(+), 90 deletions(-) diff --git a/.github/CRONET_GO_VERSION b/.github/CRONET_GO_VERSION index ad1bced96..399c1b4a7 100644 --- a/.github/CRONET_GO_VERSION +++ b/.github/CRONET_GO_VERSION @@ -1 +1 @@ -78951bf5e641fcb42bc82b73e70bd28d819e5e55 +4f12714a37cc546cbd171765e44988a348ba77fa diff --git a/common/tls/ech.go b/common/tls/ech.go index 5e9fba6d5..37573bf13 100644 --- a/common/tls/ech.go +++ b/common/tls/ech.go @@ -51,6 +51,7 @@ func parseECHClientConfig(ctx context.Context, clientConfig ECHCapableConfig, op return &ECHClientConfig{ ECHCapableConfig: clientConfig, dnsRouter: service.FromContext[adapter.DNSRouter](ctx), + queryServerName: options.ECH.QueryServerName, }, nil } } @@ -108,10 +109,11 @@ func parseECHKeys(echKey []byte) ([]tls.EncryptedClientHelloKey, error) { type ECHClientConfig struct { ECHCapableConfig - access sync.Mutex - dnsRouter adapter.DNSRouter - lastTTL time.Duration - lastUpdate time.Time + access sync.Mutex + dnsRouter adapter.DNSRouter + queryServerName string + lastTTL time.Duration + lastUpdate time.Time } func (s *ECHClientConfig) ClientHandshake(ctx context.Context, conn net.Conn) (aTLS.Conn, error) { @@ -130,13 +132,17 @@ func (s *ECHClientConfig) fetchAndHandshake(ctx context.Context, conn net.Conn) s.access.Lock() defer s.access.Unlock() if len(s.ECHConfigList()) == 0 || s.lastTTL == 0 || time.Since(s.lastUpdate) > s.lastTTL { + queryServerName := s.queryServerName + if queryServerName == "" { + queryServerName = s.ServerName() + } message := &mDNS.Msg{ MsgHdr: mDNS.MsgHdr{ RecursionDesired: true, }, Question: []mDNS.Question{ { - Name: mDNS.Fqdn(s.ServerName()), + Name: mDNS.Fqdn(queryServerName), Qtype: mDNS.TypeHTTPS, Qclass: mDNS.ClassINET, }, @@ -175,7 +181,12 @@ func (s *ECHClientConfig) fetchAndHandshake(ctx context.Context, conn net.Conn) } func (s *ECHClientConfig) Clone() Config { - return &ECHClientConfig{ECHCapableConfig: s.ECHCapableConfig.Clone().(ECHCapableConfig), dnsRouter: s.dnsRouter, lastUpdate: s.lastUpdate} + return &ECHClientConfig{ + ECHCapableConfig: s.ECHCapableConfig.Clone().(ECHCapableConfig), + dnsRouter: s.dnsRouter, + queryServerName: s.queryServerName, + lastUpdate: s.lastUpdate, + } } func UnmarshalECHKeys(raw []byte) ([]tls.EncryptedClientHelloKey, error) { diff --git a/docs/configuration/outbound/naive.md b/docs/configuration/outbound/naive.md index f1042492e..f442a8d4d 100644 --- a/docs/configuration/outbound/naive.md +++ b/docs/configuration/outbound/naive.md @@ -86,7 +86,7 @@ See [UDP Over TCP](/configuration/shared/udp-over-tcp/) for details. TLS configuration, see [TLS](/configuration/shared/tls/#outbound). -Only `server_name`, `certificate`, `certificate_path` and `certificate_public_key_sha256` are supported. +Only `server_name`, `certificate`, `certificate_path`, `certificate_public_key_sha256` and `ech` are supported. ### Dial Fields diff --git a/docs/configuration/outbound/naive.zh.md b/docs/configuration/outbound/naive.zh.md index 26067473a..ec719e242 100644 --- a/docs/configuration/outbound/naive.zh.md +++ b/docs/configuration/outbound/naive.zh.md @@ -86,7 +86,7 @@ UDP over TCP 配置。 TLS 配置, 参阅 [TLS](/zh/configuration/shared/tls/#outbound)。 -只有 `server_name`、`certificate`、`certificate_path` 和 `certificate_public_key_sha256` 是被支持的。 +只有 `server_name`、`certificate`、`certificate_path`、`certificate_public_key_sha256` 和 `ech` 是被支持的。 ### 拨号字段 diff --git a/docs/configuration/shared/tls.md b/docs/configuration/shared/tls.md index b1ec1e668..1350912ff 100644 --- a/docs/configuration/shared/tls.md +++ b/docs/configuration/shared/tls.md @@ -14,6 +14,7 @@ icon: material/new-box :material-plus: [client_key_path](#client_key_path) :material-plus: [client_authentication](#client_authentication) :material-plus: [client_certificate_public_key_sha256](#client_certificate_public_key_sha256) + :material-plus: [ech.query_server_name](#query_server_name) !!! quote "Changes in sing-box 1.12.0" @@ -118,6 +119,7 @@ icon: material/new-box "enabled": false, "config": [], "config_path": "", + "query_server_name": "", // Deprecated "pq_signature_schemes_enabled": false, @@ -514,6 +516,16 @@ The path to ECH configuration, in PEM format. If empty, load from DNS will be attempted. +#### query_server_name + +!!! question "Since sing-box 1.13.0" + +==Client only== + +Overrides the domain name used for ECH HTTPS record queries. + +If empty, `server_name` is used for queries. + #### fragment !!! question "Since sing-box 1.12.0" diff --git a/docs/configuration/shared/tls.zh.md b/docs/configuration/shared/tls.zh.md index 1cc07b320..2d507f8ac 100644 --- a/docs/configuration/shared/tls.zh.md +++ b/docs/configuration/shared/tls.zh.md @@ -14,6 +14,7 @@ icon: material/new-box :material-plus: [client_key_path](#client_key_path) :material-plus: [client_authentication](#client_authentication) :material-plus: [client_certificate_public_key_sha256](#client_certificate_public_key_sha256) + :material-plus: [ech.query_server_name](#query_server_name) !!! quote "sing-box 1.12.0 中的更改" @@ -118,6 +119,7 @@ icon: material/new-box "enabled": false, "config": [], "config_path": "", + "query_server_name": "", // 废弃的 "pq_signature_schemes_enabled": false, @@ -510,6 +512,16 @@ ECH 配置路径,PEM 格式。 如果为空,将尝试从 DNS 加载。 +#### query_server_name + +!!! question "自 sing-box 1.13.0 起" + +==仅客户端== + +覆盖用于 ECH HTTPS 记录查询的域名。 + +如果为空,使用 `server_name` 查询。 + #### fragment !!! question "自 sing-box 1.12.0 起" diff --git a/go.mod b/go.mod index 3ba45e171..7f7b829db 100644 --- a/go.mod +++ b/go.mod @@ -26,8 +26,8 @@ require ( github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/cors v1.2.1 - github.com/sagernet/cronet-go v0.0.0-20251217073804-0aadbdd7485f - github.com/sagernet/cronet-go/all v0.0.0-20251217073804-0aadbdd7485f + github.com/sagernet/cronet-go v0.0.0-20251217133746-1955399f1585 + github.com/sagernet/cronet-go/all v0.0.0-20251217133746-1955399f1585 github.com/sagernet/fswatch v0.1.1 github.com/sagernet/gomobile v0.1.10 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 @@ -108,29 +108,28 @@ require ( github.com/prometheus-community/pro-bing v0.4.0 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect - github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251217073321-98bf559282b1 // indirect - github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251217073321-98bf559282b1 // indirect + github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251217133247-ea405ec61e5f // indirect + github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251217133247-ea405ec61e5f // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect github.com/spf13/pflag v1.0.6 // indirect diff --git a/go.sum b/go.sum index 715ca38cf..a13c708a7 100644 --- a/go.sum +++ b/go.sum @@ -153,56 +153,54 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= -github.com/sagernet/cronet-go v0.0.0-20251217073804-0aadbdd7485f h1:VMlH3aVnoN0bDUUCXHRJ6o8pb3ZJe/XpRLZsUGljrJ0= -github.com/sagernet/cronet-go v0.0.0-20251217073804-0aadbdd7485f/go.mod h1:DzcRxPQdpy5y2bbabpFXotAzPfY2P4HKZ8rQj3dSClo= -github.com/sagernet/cronet-go/all v0.0.0-20251217073804-0aadbdd7485f h1:eZcIuGEbGT9Ldh4QP14UxVzWOeMpwltU8lWCthefaGw= -github.com/sagernet/cronet-go/all v0.0.0-20251217073804-0aadbdd7485f/go.mod h1:qt0I3+OORnNmYDKKg3sN2/JguaNNl3ckgdoYEMeMGSA= -github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251217073321-98bf559282b1 h1:JPrpsOAMZL7WpRfRymdazS/LTguAJVTqTPgIM1hRGSk= -github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251217073321-98bf559282b1/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw= -github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251217073321-98bf559282b1 h1:yKOa/aPDWyB8+Vw2bze3lczwA0T+Jp014F82bb04RZg= -github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM= -github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251217073321-98bf559282b1 h1:bFWOKRv1gadjBtcCj5eSMVITdM/nFAM9WRvHGrFkW2M= -github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251217073321-98bf559282b1/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc= -github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251217073321-98bf559282b1 h1:rwk5kw6tggldlnYkufttjrLgNZ4m2oDj8VPVbUkMIj8= -github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ= -github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251217073321-98bf559282b1 h1:Kz7898MkdKck/F3KhpQ3iSbDvuMcBKgcIT9kblbEAag= -github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs= -github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251217073321-98bf559282b1 h1:Csm66Pf4aFnrKW9SQ7/QAD+ODxrXM1y/1tOsMeWJt2Q= -github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0= -github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251217073321-98bf559282b1 h1:xYt0vGrcBe5E/4S1AhZrXZKqzfyMVv2EJzms+hkyMwE= -github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251217073321-98bf559282b1/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0= -github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251217073321-98bf559282b1 h1:HUIwo+G+gp5xJO7oFLXE8wUBuAMSlZCff7x8BkGwrV8= -github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4= -github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251217073321-98bf559282b1 h1:aM0ZlZyaMsj+ckqffWuwQ/LvlEocp4+8jf0CS3Y7C08= -github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251217073321-98bf559282b1/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo= -github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251217073321-98bf559282b1 h1:vAFYo+d3JZauxyW2fL8Kqqzjx2CoMSNYwS3mj2O3vig= -github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251217073321-98bf559282b1/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ= -github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251217073321-98bf559282b1 h1:vitvkHM3isRtAt6J/hJbi1YEkkmoJQYxCWFyWBzetK0= -github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251217073321-98bf559282b1/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU= -github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251217073321-98bf559282b1 h1:Y5OW7wtkGkAICo1c4TjsSVsRe0YY0rGXBZS3W4kWEMM= -github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI= -github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251217073321-98bf559282b1 h1:U4fj5bK6Bp/Fc3OaQT2+pXioRTC4NkWXD8M+kcJIXx0= -github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251217073321-98bf559282b1/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ= -github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251217073321-98bf559282b1 h1:6aMDLdA+GF0J6CPBAXh6yn8wCJHhmREIU8I/uCVl16w= -github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251217073321-98bf559282b1/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0= -github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251217073321-98bf559282b1 h1:OvZQkFRfs5fhN1ZNEjBRj1foZfwP9EdYhLFzrF23TO4= -github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s= -github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251217073321-98bf559282b1 h1:HJYoVGlafnfo7qwsNgocIwqg/ScCWH3MwC7oqD4Hj3I= -github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251217073321-98bf559282b1/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ= -github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251217073321-98bf559282b1 h1:U/eE0HxhS6iJxBhvt2mmkxvAuwjGQ6SfGz0IZc0NWQE= -github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251217073321-98bf559282b1/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow= -github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251217073321-98bf559282b1 h1:V8mKJHu2iMoHjXH2deNQAY+Itcn9mlTeLDqhrFXkwcY= -github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251217073321-98bf559282b1/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4= -github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251217073321-98bf559282b1 h1:uHy+Un5hEvONSH5+nWHLWisvfhPIAE0EWq8cLjJpAuU= -github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc= -github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251217073321-98bf559282b1 h1:IXNOyK596srcY+OtnrCrUdclKVL5lakKcO30H85Kryc= -github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251217073321-98bf559282b1/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc= -github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251217073321-98bf559282b1 h1:aPMCg3h46G8Mx5WIiYyPTr/1EQ8j4wgCI/HUPGm/occ= -github.com/sagernet/cronet-go/lib/windows_386 v0.0.0-20251217073321-98bf559282b1/go.mod h1:rnS7D+ULJX2PrP0Cy+05GS0mRZ2PP6+gVSroZKt8fjk= -github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251217073321-98bf559282b1 h1:snfESeRYtwkOlfQyoxfHKVNj4N0cpIpxMfsM+y52rw4= -github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8= -github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251217073321-98bf559282b1 h1:weCViGxMO6iajrI1EjHH4hMT/cXwGc+HhXH24xUrVGE= -github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251217073321-98bf559282b1/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw= +github.com/sagernet/cronet-go v0.0.0-20251217133746-1955399f1585 h1:fu/J7Z+umFy5JwIxo2/7ixvuMRouJx93VU0RUXQx8aI= +github.com/sagernet/cronet-go v0.0.0-20251217133746-1955399f1585/go.mod h1:hwFHBEjjthyEquDULbr4c4ucMedp8Drb6Jvm2kt/0Bw= +github.com/sagernet/cronet-go/all v0.0.0-20251217133746-1955399f1585 h1:QN3WvGKiBg9N5vrSVKJzNTmK/BfEVMJNbRZDOlOfUpo= +github.com/sagernet/cronet-go/all v0.0.0-20251217133746-1955399f1585/go.mod h1:JTqmHTkUqWDX5Hz+jnx8kdDKJ07U80QS1hN0Wfe7CTI= +github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251217133247-ea405ec61e5f h1:hjyZ7QZWWxYEW13lBT3+yAk7yENgKBuqhiw5rl/oxng= +github.com/sagernet/cronet-go/lib/android_386 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:XXDwdjX/T8xftoeJxQmbBoYXZp8MAPFR2CwbFuTpEtw= +github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251217133247-ea405ec61e5f h1:RHPD2Opa4kGqlTtHyhtMWhzvr3F1PZsT6GW+IMBaMYs= +github.com/sagernet/cronet-go/lib/android_amd64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:iNiUGoLtnr8/JTuVNj7XJbmpOAp2C6+B81KDrPxwaZM= +github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251217133247-ea405ec61e5f h1:wPrD+ADgFZC7AFFqUDWaKdcElqGODX10WrNpmUywX00= +github.com/sagernet/cronet-go/lib/android_arm v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:19ILNUOGIzRdOqa2mq+iY0JoHxuieB7/lnjYeaA2vEc= +github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251217133247-ea405ec61e5f h1:MC0T2f2SXwai6hdmTkkulE7PlHA11lHp1re7alZCQLo= +github.com/sagernet/cronet-go/lib/android_arm64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:JxzGyQf94Cr6sBShKqODGDyRUlESfJK/Njcz9Lz6qMQ= +github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251217133247-ea405ec61e5f h1:X3RxBK5D5P3fcb+j8HqiEwhXEGMZkCg9ecmGYHo2qpg= +github.com/sagernet/cronet-go/lib/darwin_amd64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:KN+9T9TBycGOLzmKU4QdcHAJEj6Nlx48ifnlTvvHMvs= +github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251217133247-ea405ec61e5f h1:K/CJaXL1djRbHyoVHGNx9nacncZPKE0QkEoO12nWL4s= +github.com/sagernet/cronet-go/lib/darwin_arm64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:kojvtUc29KKnk8hs2QIANynVR59921SnGWA9kXohHc0= +github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251217133247-ea405ec61e5f h1:uN/ay0BtmWWPdaoAsK5yu+bbQfr6iujEUTo7zZhF3a4= +github.com/sagernet/cronet-go/lib/ios_amd64_simulator v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:hkQzRE5GDbaH1/ioqYh0Taho4L6i0yLRCVEZ5xHz5M0= +github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251217133247-ea405ec61e5f h1:vdDIjy2y8DQEu1tVkpS/WOx0fEbK4yjMQv7X1e7MbFU= +github.com/sagernet/cronet-go/lib/ios_arm64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:tzVJFTOm66UxLxy6K0ZN5Ic2PC79e+sKKnt+V9puEa4= +github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251217133247-ea405ec61e5f h1:BElLblhAfW8Yd5ehlI9xk1FhlsGnKIX6oVak3C8cCnc= +github.com/sagernet/cronet-go/lib/ios_arm64_simulator v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:M/pN6m3j0HFU6/y83n0HU6GLYys3tYdr/xTE8hVEGMo= +github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251217133247-ea405ec61e5f h1:vALFH1gx8nLLiAqkTy7tgrT9uLWCPC4e+Ir1UvEQkRw= +github.com/sagernet/cronet-go/lib/linux_386 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:cGh5hO6eljCo6KMQ/Cel8Xgq4+etL0awZLRBDVG1EZQ= +github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251217133247-ea405ec61e5f h1:vQ99pp3CGklVoUGO2x//xne3BkfzSmNKDOzB5V9BoaU= +github.com/sagernet/cronet-go/lib/linux_386_musl v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:JFE0/cxaKkx0wqPMZU7MgaplQlU0zudv82dROJjClKU= +github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251217133247-ea405ec61e5f h1:MqINoyziFNrN8t5d/XCu1z+BZs2CkRLLKKOdx0g6bJ4= +github.com/sagernet/cronet-go/lib/linux_amd64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:vU8VftFeSt7fURCa3JXD6+k6ss1YAX+idQjPvHmJ2tI= +github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251217133247-ea405ec61e5f h1:L7HQmTsLFI7nAzyi2RIkmkuraSY7LRivBYoflIjQcxk= +github.com/sagernet/cronet-go/lib/linux_amd64_musl v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:vCe4OUuL+XOUge9v3MyTD45BnuAXiH+DkjN9quDXJzQ= +github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251217133247-ea405ec61e5f h1:DAswotlvnP6zYlP2KleGfMUy4dIBNNYGg3sh1reS53I= +github.com/sagernet/cronet-go/lib/linux_arm v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:w9amBWrvjtohQzBGCKJ7LCh22LhTIJs4sE7cYaKQzM0= +github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251217133247-ea405ec61e5f h1:b2OhFosX8oUEdOpYkDS4fkbotbEe9WRMCpYGAWWq4VI= +github.com/sagernet/cronet-go/lib/linux_arm64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:TqlsFtcYS/etTeck46kHBeT8Le0Igw1Q/AV88UnMS3s= +github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251217133247-ea405ec61e5f h1:H+GUhGCYe/4wHi+XRw96AgFxETSE3yCDhyAH7G6GbQc= +github.com/sagernet/cronet-go/lib/linux_arm64_musl v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:B6Qd0vys8sv9OKVRN6J9RqDzYRGE938Fb2zrYdBDyTQ= +github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251217133247-ea405ec61e5f h1:ziXSJVeboo4ZiCulyMbbEgG9ArfP98hqN1pALA15XeM= +github.com/sagernet/cronet-go/lib/linux_arm_musl v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:3tXMMFY7AHugOVBZ5Al7cL7JKsnFOe5bMVr0hZPk3ow= +github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251217133247-ea405ec61e5f h1:X9FaZ28M35Hj23agNDRDCklSrR0zb8PZz4K4EBalILE= +github.com/sagernet/cronet-go/lib/tvos_amd64_simulator v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:aaX0YGl8nhGmfRWI8bc3BtDjY8Vzx6O0cS/e1uqxDq4= +github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251217133247-ea405ec61e5f h1:qKlncyWLNJ3YtJrF3hK5YPd2Tb66ZF1iQXjq1mEADhE= +github.com/sagernet/cronet-go/lib/tvos_arm64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:EdzMKA96xITc42QEI+ct4SwqX8Dn3ltKK8wzdkLWpSc= +github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251217133247-ea405ec61e5f h1:qpBg3PtrVx4Tgv+AwwoRgPqYsfEZeZ3Jn+zHfqr7Z1A= +github.com/sagernet/cronet-go/lib/tvos_arm64_simulator v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:qix4kv1TTAJ5tY4lJ9vjhe9EY4mM+B7H5giOhbxDVcc= +github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251217133247-ea405ec61e5f h1:PvjxP4e6qosQrhkPrpW2ZnRm2OKZsvEXIADV29fKWeY= +github.com/sagernet/cronet-go/lib/windows_amd64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:lm9w/oCCRyBiUa3G8lDQTT8x/ONUvgVR2iV9fVzUZB8= +github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251217133247-ea405ec61e5f h1:l3+QN68ENC0KHCxHa0iUO0vMGiG00TJlHgH8+jVrDNU= +github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251217133247-ea405ec61e5f/go.mod h1:n34YyLgapgjWdKa0IoeczjAFCwD3/dxbsH5sucKw0bw= github.com/sagernet/fswatch v0.1.1 h1:YqID+93B7VRfqIH3PArW/XpJv5H4OLEVWDfProGoRQs= github.com/sagernet/fswatch v0.1.1/go.mod h1:nz85laH0mkQqJfaOrqPpkwtU1znMFNVTpT/5oRsVz/o= github.com/sagernet/gomobile v0.1.10 h1:ElqZ0OVDvyQlU91MU0C9cfU0FrILBbc65+NOKzZ1t0c= diff --git a/option/tls.go b/option/tls.go index 1829898a9..60343a15f 100644 --- a/option/tls.go +++ b/option/tls.go @@ -215,9 +215,10 @@ type InboundECHOptions struct { } type OutboundECHOptions struct { - Enabled bool `json:"enabled,omitempty"` - Config badoption.Listable[string] `json:"config,omitempty"` - ConfigPath string `json:"config_path,omitempty"` + Enabled bool `json:"enabled,omitempty"` + Config badoption.Listable[string] `json:"config,omitempty"` + ConfigPath string `json:"config_path,omitempty"` + QueryServerName string `json:"query_server_name,omitempty"` // Deprecated: not supported by stdlib PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"` diff --git a/protocol/naive/outbound.go b/protocol/naive/outbound.go index 963709c0f..bcb77c307 100644 --- a/protocol/naive/outbound.go +++ b/protocol/naive/outbound.go @@ -4,6 +4,7 @@ package naive import ( "context" + "encoding/pem" "net" "os" "strings" @@ -14,6 +15,7 @@ import ( "github.com/sagernet/sing-box/adapter/outbound" "github.com/sagernet/sing-box/common/dialer" C "github.com/sagernet/sing-box/constant" + "github.com/sagernet/sing-box/dns" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing/common" @@ -22,6 +24,9 @@ import ( M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/uot" + "github.com/sagernet/sing/service" + + mDNS "github.com/miekg/dns" ) func RegisterOutbound(registry *outbound.Registry) { @@ -73,9 +78,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL if options.TLS.KernelTx || options.TLS.KernelRx { return nil, E.New("kernel TLS is not supported on naive outbound") } - if options.TLS.ECH != nil && options.TLS.ECH.Enabled { - return nil, E.New("ECH is not currently supported on naive outbound") - } if options.TLS.UTLS != nil && options.TLS.UTLS.Enabled { return nil, E.New("uTLS is not supported on naive outbound") } @@ -121,6 +123,44 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL } } + dnsRouter := service.FromContext[adapter.DNSRouter](ctx) + var dnsResolver cronet.DNSResolverFunc + if dnsRouter != nil { + dnsResolver = func(dnsContext context.Context, request *mDNS.Msg) *mDNS.Msg { + response, err := dnsRouter.Exchange(dnsContext, request, adapter.DNSQueryOptions{}) + if err != nil { + logger.Error("DNS exchange failed: ", err) + return dns.FixedResponseStatus(request, mDNS.RcodeServerFailure) + } + return response + } + } + + var echEnabled bool + var echConfigList []byte + var echQueryServerName string + if options.TLS.ECH != nil && options.TLS.ECH.Enabled { + echEnabled = true + echQueryServerName = options.TLS.ECH.QueryServerName + var echConfig []byte + if len(options.TLS.ECH.Config) > 0 { + echConfig = []byte(strings.Join(options.TLS.ECH.Config, "\n")) + } else if options.TLS.ECH.ConfigPath != "" { + content, err := os.ReadFile(options.TLS.ECH.ConfigPath) + if err != nil { + return nil, E.Cause(err, "read ECH config") + } + echConfig = content + } + if len(echConfig) > 0 { + block, rest := pem.Decode(echConfig) + if block == nil || block.Type != "ECH CONFIGS" || len(rest) > 0 { + return nil, E.New("invalid ECH configs pem") + } + echConfigList = block.Bytes + } + } + client, err := cronet.NewNaiveClient(cronet.NaiveClientConfig{ Context: ctx, ServerAddress: serverAddress, @@ -132,6 +172,10 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL TrustedRootCertificates: trustedRootCertificates, TrustedCertificatePublicKeySHA256: options.TLS.CertificatePublicKeySHA256, Dialer: outboundDialer, + DNSResolver: dnsResolver, + ECHEnabled: echEnabled, + ECHConfigList: echConfigList, + ECHQueryServerName: echQueryServerName, }) if err != nil { return nil, err