mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-12 01:57:18 +10:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54ed58499d | ||
|
|
b1bdc18c85 | ||
|
|
a38030cc0b | ||
|
|
4626aa2cb0 | ||
|
|
5a40b673a4 | ||
|
|
541f63fee4 | ||
|
|
5de6f4a14f | ||
|
|
5658830077 | ||
|
|
0e50edc009 | ||
|
|
444f454810 | ||
|
|
d0e1fd6c7e | ||
|
|
17b4d1e010 | ||
|
|
06791470c9 | ||
|
|
ef14c8ca0e | ||
|
|
36dc883c7c | ||
|
|
6557bd7029 | ||
|
|
41b30c91d9 | ||
|
|
0f767d5ce1 | ||
|
|
328a6de797 | ||
|
|
886be6414d | ||
|
|
9362d3cab3 | ||
|
|
ced2e39dbf | ||
|
|
2159d8877b | ||
|
|
cb7dba3eff | ||
|
|
d9d7f7880d | ||
|
|
a031aaf2c0 | ||
|
|
4bca951773 | ||
|
|
140735dbde | ||
|
|
714a68bba1 |
@@ -1,25 +1,27 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
VERSION="1.23.12"
|
||||
VERSION="1.25.3"
|
||||
|
||||
mkdir -p $HOME/go
|
||||
cd $HOME/go
|
||||
wget "https://dl.google.com/go/go${VERSION}.linux-amd64.tar.gz"
|
||||
tar -xzf "go${VERSION}.linux-amd64.tar.gz"
|
||||
mv go go_legacy
|
||||
cd go_legacy
|
||||
mv go go_win7
|
||||
cd go_win7
|
||||
|
||||
# modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557
|
||||
# this patch file only works on golang1.23.x
|
||||
# that means after golang1.24 release it must be changed
|
||||
# see: https://github.com/MetaCubeX/go/commits/release-branch.go1.23/
|
||||
# this patch file only works on golang1.25.x
|
||||
# that means after golang1.26 release it must be changed
|
||||
# see: https://github.com/MetaCubeX/go/commits/release-branch.go1.25/
|
||||
# revert:
|
||||
# 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng"
|
||||
# 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7"
|
||||
# 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround"
|
||||
# a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries"
|
||||
|
||||
curl https://github.com/MetaCubeX/go/commit/9ac42137ef6730e8b7daca016ece831297a1d75b.diff | patch --verbose -p 1
|
||||
curl https://github.com/MetaCubeX/go/commit/21290de8a4c91408de7c2b5b68757b1e90af49dd.diff | patch --verbose -p 1
|
||||
curl https://github.com/MetaCubeX/go/commit/6a31d3fa8e47ddabc10bd97bff10d9a85f4cfb76.diff | patch --verbose -p 1
|
||||
curl https://github.com/MetaCubeX/go/commit/69e2eed6dd0f6d815ebf15797761c13f31213dd6.diff | patch --verbose -p 1
|
||||
alias curl='curl -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"'
|
||||
|
||||
curl https://github.com/MetaCubeX/go/commit/8cb5472d94c34b88733a81091bd328e70ee565a4.diff | patch --verbose -p 1
|
||||
curl https://github.com/MetaCubeX/go/commit/6788c4c6f9fafb56729bad6b660f7ee2272d699f.diff | patch --verbose -p 1
|
||||
curl https://github.com/MetaCubeX/go/commit/a5b2168bb836ed9d6601c626f95e56c07923f906.diff | patch --verbose -p 1
|
||||
curl https://github.com/MetaCubeX/go/commit/f56f1e23507e646c85243a71bde7b9629b2f970c.diff | patch --verbose -p 1
|
||||
38
.github/workflows/build.yml
vendored
38
.github/workflows/build.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.1
|
||||
go-version: ^1.25.3
|
||||
- name: Check input version
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: |-
|
||||
@@ -88,9 +88,9 @@ jobs:
|
||||
- { os: linux, arch: loong64, debian: loongarch64, rpm: loongarch64, openwrt: "loongarch64_generic" }
|
||||
|
||||
- { os: windows, arch: amd64 }
|
||||
- { os: windows, arch: amd64, legacy_go123: true, legacy_name: "windows-7" }
|
||||
- { os: windows, arch: amd64, legacy_win7: true, legacy_name: "windows-7" }
|
||||
- { os: windows, arch: "386" }
|
||||
- { os: windows, arch: "386", legacy_go123: true, legacy_name: "windows-7" }
|
||||
- { os: windows, arch: "386", legacy_win7: true, legacy_name: "windows-7" }
|
||||
- { os: windows, arch: arm64 }
|
||||
|
||||
- { os: darwin, arch: amd64 }
|
||||
@@ -110,29 +110,29 @@ jobs:
|
||||
if: ${{ ! (matrix.legacy_go123 || matrix.legacy_go124) }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.1
|
||||
go-version: ^1.25.3
|
||||
- name: Setup Go 1.24
|
||||
if: matrix.legacy_go124
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ~1.24.6
|
||||
- name: Cache Go 1.23
|
||||
if: matrix.legacy_go123
|
||||
id: cache-legacy-go
|
||||
- name: Cache Go for Windows 7
|
||||
if: matrix.legacy_win7
|
||||
id: cache-go-for-windows7
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/go/go_legacy
|
||||
key: go_legacy_12312
|
||||
- name: Setup Go 1.23
|
||||
if: matrix.legacy_go123 && steps.cache-legacy-go.outputs.cache-hit != 'true'
|
||||
~/go/go_win7
|
||||
key: go_win7_1253
|
||||
- name: Setup Go for Windows 7
|
||||
if: matrix.legacy_win7 && steps.cache-go-for-windows7.outputs.cache-hit != 'true'
|
||||
run: |-
|
||||
.github/setup_legacy_go.sh
|
||||
- name: Setup Go 1.23
|
||||
if: matrix.legacy_go123
|
||||
.github/setup_go_for_windows7.sh
|
||||
- name: Setup Go for Windows 7
|
||||
if: matrix.legacy_win7
|
||||
run: |-
|
||||
echo "PATH=$HOME/go/go_legacy/bin:$PATH" >> $GITHUB_ENV
|
||||
echo "GOROOT=$HOME/go/go_legacy" >> $GITHUB_ENV
|
||||
echo "PATH=$HOME/go/go_win7/bin:$PATH" >> $GITHUB_ENV
|
||||
echo "GOROOT=$HOME/go/go_win7" >> $GITHUB_ENV
|
||||
- name: Setup Android NDK
|
||||
if: matrix.os == 'android'
|
||||
uses: nttld/setup-ndk@v1
|
||||
@@ -300,7 +300,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.1
|
||||
go-version: ^1.25.3
|
||||
- name: Setup Android NDK
|
||||
id: setup-ndk
|
||||
uses: nttld/setup-ndk@v1
|
||||
@@ -380,7 +380,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.1
|
||||
go-version: ^1.25.3
|
||||
- name: Setup Android NDK
|
||||
id: setup-ndk
|
||||
uses: nttld/setup-ndk@v1
|
||||
@@ -479,7 +479,7 @@ jobs:
|
||||
if: matrix.if
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.1
|
||||
go-version: ^1.25.3
|
||||
- name: Set tag
|
||||
if: matrix.if
|
||||
run: |-
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v8
|
||||
with:
|
||||
version: latest
|
||||
version: v2.4.0
|
||||
args: --timeout=30m
|
||||
install-mode: binary
|
||||
verify: false
|
||||
|
||||
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.1
|
||||
go-version: ^1.25.3
|
||||
- name: Check input version
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
run: |-
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ^1.25.1
|
||||
go-version: ^1.25.3
|
||||
- name: Setup Android NDK
|
||||
if: matrix.os == 'android'
|
||||
uses: nttld/setup-ndk@v1
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,4 +15,6 @@
|
||||
.DS_Store
|
||||
/config.d/
|
||||
/venv/
|
||||
|
||||
CLAUDE.md
|
||||
AGENTS.md
|
||||
/.claude/
|
||||
|
||||
4
Makefile
4
Makefile
@@ -38,7 +38,7 @@ fmt:
|
||||
@gci write --custom-order -s standard -s "prefix(github.com/sagernet/)" -s "default" .
|
||||
|
||||
fmt_install:
|
||||
go install -v mvdan.cc/gofumpt@latest
|
||||
go install -v mvdan.cc/gofumpt@v0.8.0
|
||||
go install -v github.com/daixiang0/gci@latest
|
||||
|
||||
lint:
|
||||
@@ -49,7 +49,7 @@ lint:
|
||||
GOOS=freebsd golangci-lint run ./...
|
||||
|
||||
lint_install:
|
||||
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||
go install -v github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.4.0
|
||||
|
||||
proto:
|
||||
@go run ./cmd/internal/protogen
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
> Sponsored by [Warp](https://go.warp.dev/sing-box), built for coding with multiple AI agents
|
||||
|
||||
<a href="https://go.warp.dev/sing-box">
|
||||
<img alt="Warp sponsorship" width="400" src="https://github.com/warpdotdev/brand-assets/raw/refs/heads/main/Github/Sponsor/Warp-Github-LG-02.png">
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
# sing-box
|
||||
|
||||
The universal proxy platform.
|
||||
|
||||
Submodule clients/android updated: cd8ac376f6...a4e3c00f0f
Submodule clients/apple updated: 96bee16bf0...84d8cf1757
@@ -134,6 +134,7 @@ func publishTestflight(ctx context.Context) error {
|
||||
asc.PlatformTVOS,
|
||||
}
|
||||
}
|
||||
waitingForProcess := false
|
||||
for _, platform := range platforms {
|
||||
log.Info(string(platform), " list builds")
|
||||
for {
|
||||
@@ -145,12 +146,13 @@ func publishTestflight(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
build := builds.Data[0]
|
||||
if common.Contains(buildIDs, build.ID) || time.Since(build.Attributes.UploadedDate.Time) > 30*time.Minute {
|
||||
if !waitingForProcess && (common.Contains(buildIDs, build.ID) || time.Since(build.Attributes.UploadedDate.Time) > 30*time.Minute) {
|
||||
log.Info(string(platform), " ", tag, " waiting for process")
|
||||
time.Sleep(15 * time.Second)
|
||||
continue
|
||||
}
|
||||
if *build.Attributes.ProcessingState != "VALID" {
|
||||
waitingForProcess = true
|
||||
log.Info(string(platform), " ", tag, " waiting for process: ", *build.Attributes.ProcessingState)
|
||||
time.Sleep(15 * time.Second)
|
||||
continue
|
||||
|
||||
@@ -53,26 +53,48 @@ func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, e
|
||||
return tlsConn, nil
|
||||
}
|
||||
|
||||
type Dialer struct {
|
||||
type Dialer interface {
|
||||
N.Dialer
|
||||
DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error)
|
||||
}
|
||||
|
||||
type defaultDialer struct {
|
||||
dialer N.Dialer
|
||||
config Config
|
||||
}
|
||||
|
||||
func NewDialer(dialer N.Dialer, config Config) N.Dialer {
|
||||
return &Dialer{dialer, config}
|
||||
func NewDialer(dialer N.Dialer, config Config) Dialer {
|
||||
return &defaultDialer{dialer, config}
|
||||
}
|
||||
|
||||
func (d *Dialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
if network != N.NetworkTCP {
|
||||
func (d *defaultDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
if N.NetworkName(network) != N.NetworkTCP {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
conn, err := d.dialer.DialContext(ctx, network, destination)
|
||||
return d.DialTLSContext(ctx, destination)
|
||||
}
|
||||
|
||||
func (d *defaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
|
||||
func (d *defaultDialer) DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error) {
|
||||
return d.dialContext(ctx, destination)
|
||||
}
|
||||
|
||||
func (d *defaultDialer) dialContext(ctx context.Context, destination M.Socksaddr) (Conn, error) {
|
||||
conn, err := d.dialer.DialContext(ctx, N.NetworkTCP, destination)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ClientHandshake(ctx, conn, d.config)
|
||||
tlsConn, err := aTLS.ClientHandshake(ctx, conn, d.config)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return tlsConn, nil
|
||||
}
|
||||
|
||||
func (d *Dialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
return nil, os.ErrInvalid
|
||||
func (d *defaultDialer) Upstream() any {
|
||||
return d.dialer
|
||||
}
|
||||
|
||||
@@ -95,6 +95,20 @@ func (c *Client) Start() {
|
||||
}
|
||||
}
|
||||
|
||||
func extractNegativeTTL(response *dns.Msg) (uint32, bool) {
|
||||
for _, record := range response.Ns {
|
||||
if soa, isSOA := record.(*dns.SOA); isSOA {
|
||||
soaTTL := soa.Header().Ttl
|
||||
soaMinimum := soa.Minttl
|
||||
if soaTTL < soaMinimum {
|
||||
return soaTTL, true
|
||||
}
|
||||
return soaMinimum, true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, message *dns.Msg, options adapter.DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error) {
|
||||
if len(message.Question) == 0 {
|
||||
if c.logger != nil {
|
||||
@@ -214,7 +228,7 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
|
||||
response.Answer = append(response.Answer, validResponse.Answer...)
|
||||
}
|
||||
}*/
|
||||
disableCache = disableCache || response.Rcode != dns.RcodeSuccess || len(response.Answer) == 0
|
||||
disableCache = disableCache || (response.Rcode != dns.RcodeSuccess && response.Rcode != dns.RcodeNameError)
|
||||
if responseChecker != nil {
|
||||
var rejected bool
|
||||
// TODO: add accept_any rule and support to check response instead of addresses
|
||||
@@ -251,10 +265,17 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
|
||||
}
|
||||
}
|
||||
var timeToLive uint32
|
||||
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
|
||||
for _, record := range recordList {
|
||||
if timeToLive == 0 || record.Header().Ttl > 0 && record.Header().Ttl < timeToLive {
|
||||
timeToLive = record.Header().Ttl
|
||||
if len(response.Answer) == 0 {
|
||||
if soaTTL, hasSOA := extractNegativeTTL(response); hasSOA {
|
||||
timeToLive = soaTTL
|
||||
}
|
||||
}
|
||||
if timeToLive == 0 {
|
||||
for _, recordList := range [][]dns.RR{response.Answer, response.Ns, response.Extra} {
|
||||
for _, record := range recordList {
|
||||
if timeToLive == 0 || record.Header().Ttl > 0 && record.Header().Ttl < timeToLive {
|
||||
timeToLive = record.Header().Ttl
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,14 +385,18 @@ func (c *Client) LookupCache(domain string, strategy C.DomainStrategy) ([]netip.
|
||||
Qtype: dns.TypeA,
|
||||
Qclass: dns.ClassINET,
|
||||
}, nil)
|
||||
if response4 == nil {
|
||||
return nil, false
|
||||
}
|
||||
response6, _ := c.loadResponse(dns.Question{
|
||||
Name: dnsName,
|
||||
Qtype: dns.TypeAAAA,
|
||||
Qclass: dns.ClassINET,
|
||||
}, nil)
|
||||
if response4 != nil || response6 != nil {
|
||||
return sortAddresses(MessageToAddresses(response4), MessageToAddresses(response6), strategy), true
|
||||
if response6 == nil {
|
||||
return nil, false
|
||||
}
|
||||
return sortAddresses(MessageToAddresses(response4), MessageToAddresses(response6), strategy), true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ func TruncateDNSMessage(request *dns.Msg, response *dns.Msg, headroom int) (*buf
|
||||
}
|
||||
responseLen := response.Len()
|
||||
if responseLen > maxLen {
|
||||
copyResponse := *response
|
||||
response = ©Response
|
||||
response = response.Copy()
|
||||
response.Truncate(maxLen)
|
||||
}
|
||||
buffer := buf.NewSize(headroom*2 + 1 + responseLen)
|
||||
|
||||
@@ -386,12 +386,7 @@ func (r *Router) Lookup(ctx context.Context, domain string, options adapter.DNSQ
|
||||
if rule != nil {
|
||||
switch action := rule.Action().(type) {
|
||||
case *R.RuleActionReject:
|
||||
switch action.Method {
|
||||
case C.RuleActionRejectMethodDefault:
|
||||
return nil, nil
|
||||
case C.RuleActionRejectMethodDrop:
|
||||
return nil, tun.ErrDrop
|
||||
}
|
||||
return nil, &R.RejectedError{Cause: action.Error(ctx)}
|
||||
case *R.RuleActionPredefined:
|
||||
if action.Rcode != mDNS.RcodeSuccess {
|
||||
err = RcodeError(action.Rcode)
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
aTLS "github.com/sagernet/sing/common/tls"
|
||||
sHTTP "github.com/sagernet/sing/protocol/http"
|
||||
|
||||
mDNS "github.com/miekg/dns"
|
||||
@@ -47,7 +46,7 @@ type HTTPSTransport struct {
|
||||
destination *url.URL
|
||||
headers http.Header
|
||||
transportAccess sync.Mutex
|
||||
transport *http.Transport
|
||||
transport *HTTPSTransportWrapper
|
||||
transportResetAt time.Time
|
||||
}
|
||||
|
||||
@@ -62,11 +61,8 @@ func NewHTTPS(ctx context.Context, logger log.ContextLogger, tag string, options
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if common.Error(tlsConfig.Config()) == nil && !common.Contains(tlsConfig.NextProtos(), http2.NextProtoTLS) {
|
||||
tlsConfig.SetNextProtos(append(tlsConfig.NextProtos(), http2.NextProtoTLS))
|
||||
}
|
||||
if !common.Contains(tlsConfig.NextProtos(), "http/1.1") {
|
||||
tlsConfig.SetNextProtos(append(tlsConfig.NextProtos(), "http/1.1"))
|
||||
if len(tlsConfig.NextProtos()) == 0 {
|
||||
tlsConfig.SetNextProtos([]string{http2.NextProtoTLS, "http/1.1"})
|
||||
}
|
||||
headers := options.Headers.Build()
|
||||
host := headers.Get("Host")
|
||||
@@ -124,37 +120,13 @@ func NewHTTPSRaw(
|
||||
serverAddr M.Socksaddr,
|
||||
tlsConfig tls.Config,
|
||||
) *HTTPSTransport {
|
||||
var transport *http.Transport
|
||||
if tlsConfig != nil {
|
||||
transport = &http.Transport{
|
||||
ForceAttemptHTTP2: true,
|
||||
DialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
tcpConn, hErr := dialer.DialContext(ctx, network, serverAddr)
|
||||
if hErr != nil {
|
||||
return nil, hErr
|
||||
}
|
||||
tlsConn, hErr := aTLS.ClientHandshake(ctx, tcpConn, tlsConfig)
|
||||
if hErr != nil {
|
||||
tcpConn.Close()
|
||||
return nil, hErr
|
||||
}
|
||||
return tlsConn, nil
|
||||
},
|
||||
}
|
||||
} else {
|
||||
transport = &http.Transport{
|
||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return dialer.DialContext(ctx, network, serverAddr)
|
||||
},
|
||||
}
|
||||
}
|
||||
return &HTTPSTransport{
|
||||
TransportAdapter: adapter,
|
||||
logger: logger,
|
||||
dialer: dialer,
|
||||
destination: destination,
|
||||
headers: headers,
|
||||
transport: transport,
|
||||
transport: NewHTTPSTransportWrapper(tls.NewDialer(dialer, tlsConfig), serverAddr),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
80
dns/transport/https_transport.go
Normal file
80
dns/transport/https_transport.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/sagernet/sing-box/common/tls"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
var errFallback = E.New("fallback to HTTP/1.1")
|
||||
|
||||
type HTTPSTransportWrapper struct {
|
||||
http2Transport *http2.Transport
|
||||
httpTransport *http.Transport
|
||||
fallback *atomic.Bool
|
||||
}
|
||||
|
||||
func NewHTTPSTransportWrapper(dialer tls.Dialer, serverAddr M.Socksaddr) *HTTPSTransportWrapper {
|
||||
var fallback atomic.Bool
|
||||
return &HTTPSTransportWrapper{
|
||||
http2Transport: &http2.Transport{
|
||||
DialTLSContext: func(ctx context.Context, _, _ string, _ *tls.STDConfig) (net.Conn, error) {
|
||||
tlsConn, err := dialer.DialTLSContext(ctx, serverAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state := tlsConn.ConnectionState()
|
||||
if state.NegotiatedProtocol == http2.NextProtoTLS {
|
||||
return tlsConn, nil
|
||||
}
|
||||
tlsConn.Close()
|
||||
fallback.Store(true)
|
||||
return nil, errFallback
|
||||
},
|
||||
},
|
||||
httpTransport: &http.Transport{
|
||||
DialTLSContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
|
||||
return dialer.DialTLSContext(ctx, serverAddr)
|
||||
},
|
||||
},
|
||||
fallback: &fallback,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HTTPSTransportWrapper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
if h.fallback.Load() {
|
||||
return h.httpTransport.RoundTrip(request)
|
||||
} else {
|
||||
response, err := h.http2Transport.RoundTrip(request)
|
||||
if err != nil {
|
||||
if errors.Is(err, errFallback) {
|
||||
return h.httpTransport.RoundTrip(request)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HTTPSTransportWrapper) CloseIdleConnections() {
|
||||
h.http2Transport.CloseIdleConnections()
|
||||
h.httpTransport.CloseIdleConnections()
|
||||
}
|
||||
|
||||
func (h *HTTPSTransportWrapper) Clone() *HTTPSTransportWrapper {
|
||||
return &HTTPSTransportWrapper{
|
||||
httpTransport: h.httpTransport,
|
||||
http2Transport: &http2.Transport{
|
||||
DialTLSContext: h.http2Transport.DialTLSContext,
|
||||
},
|
||||
fallback: h.fallback,
|
||||
}
|
||||
}
|
||||
@@ -54,18 +54,17 @@ func (t *Transport) Close() error {
|
||||
|
||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
question := message.Question[0]
|
||||
domain := dns.FqdnToDomain(question.Name)
|
||||
if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
|
||||
addresses := t.hosts.Lookup(domain)
|
||||
addresses := t.hosts.Lookup(dns.FqdnToDomain(question.Name))
|
||||
if len(addresses) > 0 {
|
||||
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
|
||||
}
|
||||
}
|
||||
systemConfig := getSystemDNSConfig(t.ctx)
|
||||
if systemConfig.singleRequest || !(message.Question[0].Qtype == mDNS.TypeA || message.Question[0].Qtype == mDNS.TypeAAAA) {
|
||||
return t.exchangeSingleRequest(ctx, systemConfig, message, domain)
|
||||
return t.exchangeSingleRequest(ctx, systemConfig, message, question.Name)
|
||||
} else {
|
||||
return t.exchangeParallel(ctx, systemConfig, message, domain)
|
||||
return t.exchangeParallel(ctx, systemConfig, message, question.Name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,6 @@ func (f *FallbackTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*m
|
||||
return f.DNSTransport.Exchange(ctx, message)
|
||||
}
|
||||
question := message.Question[0]
|
||||
domain := dns.FqdnToDomain(question.Name)
|
||||
if question.Qtype == mDNS.TypeA || question.Qtype == mDNS.TypeAAAA {
|
||||
var network string
|
||||
if question.Qtype == mDNS.TypeA {
|
||||
@@ -75,7 +74,7 @@ func (f *FallbackTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*m
|
||||
} else {
|
||||
network = "ip6"
|
||||
}
|
||||
addresses, err := f.resolver.LookupNetIP(ctx, network, domain)
|
||||
addresses, err := f.resolver.LookupNetIP(ctx, network, question.Name)
|
||||
if err != nil {
|
||||
var dnsError *net.DNSError
|
||||
if errors.As(err, &dnsError) && dnsError.IsNotFound {
|
||||
@@ -85,7 +84,7 @@ func (f *FallbackTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*m
|
||||
}
|
||||
return dns.FixedResponse(message.Id, question, addresses, C.DefaultDNSTTL), nil
|
||||
} else if question.Qtype == mDNS.TypeNS {
|
||||
records, err := f.resolver.LookupNS(ctx, domain)
|
||||
records, err := f.resolver.LookupNS(ctx, question.Name)
|
||||
if err != nil {
|
||||
var dnsError *net.DNSError
|
||||
if errors.As(err, &dnsError) && dnsError.IsNotFound {
|
||||
@@ -114,7 +113,7 @@ func (f *FallbackTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*m
|
||||
}
|
||||
return response, nil
|
||||
} else if question.Qtype == mDNS.TypeCNAME {
|
||||
cname, err := f.resolver.LookupCNAME(ctx, domain)
|
||||
cname, err := f.resolver.LookupCNAME(ctx, question.Name)
|
||||
if err != nil {
|
||||
var dnsError *net.DNSError
|
||||
if errors.As(err, &dnsError) && dnsError.IsNotFound {
|
||||
@@ -142,7 +141,7 @@ func (f *FallbackTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*m
|
||||
},
|
||||
}, nil
|
||||
} else if question.Qtype == mDNS.TypeTXT {
|
||||
records, err := f.resolver.LookupTXT(ctx, domain)
|
||||
records, err := f.resolver.LookupTXT(ctx, question.Name)
|
||||
if err != nil {
|
||||
var dnsError *net.DNSError
|
||||
if errors.As(err, &dnsError) && dnsError.IsNotFound {
|
||||
@@ -170,7 +169,7 @@ func (f *FallbackTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*m
|
||||
},
|
||||
}, nil
|
||||
} else if question.Qtype == mDNS.TypeMX {
|
||||
records, err := f.resolver.LookupMX(ctx, domain)
|
||||
records, err := f.resolver.LookupMX(ctx, question.Name)
|
||||
if err != nil {
|
||||
var dnsError *net.DNSError
|
||||
if errors.As(err, &dnsError) && dnsError.IsNotFound {
|
||||
|
||||
@@ -2,6 +2,28 @@
|
||||
icon: material/alert-decagram
|
||||
---
|
||||
|
||||
#### 1.12.12
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.11
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.10
|
||||
|
||||
* Update uTLS to v1.8.1 **1**
|
||||
* Fixes and improvements
|
||||
|
||||
**1**:
|
||||
|
||||
This update fixes an critical issue that could cause simulated Chrome fingerprints to be detected,
|
||||
see https://github.com/refraction-networking/utls/pull/375.
|
||||
|
||||
#### 1.12.9
|
||||
|
||||
* Fixes and improvements
|
||||
|
||||
#### 1.12.8
|
||||
|
||||
* Fixes and improvements
|
||||
@@ -92,7 +114,8 @@ See [Tailscale](/configuration/endpoint/tailscale/).
|
||||
|
||||
Due to maintenance difficulties, sing-box 1.12.0 requires at least Go 1.23 to compile.
|
||||
|
||||
For Windows 7 users, legacy binaries now continue to compile with Go 1.23 and patches from [MetaCubeX/go](https://github.com/MetaCubeX/go).
|
||||
For Windows 7 users, legacy binaries now continue to compile with Go 1.23 and patches
|
||||
from [MetaCubeX/go](https://github.com/MetaCubeX/go).
|
||||
|
||||
**7**:
|
||||
|
||||
@@ -154,7 +177,8 @@ See [Tun](/configuration/inbound/tun/#loopback_address).
|
||||
|
||||
We have significantly improved the performance of tun inbound on Apple platforms, especially in the gVisor stack.
|
||||
|
||||
The following data was tested using [tun_bench](https://github.com/SagerNet/sing-box/blob/dev-next/cmd/internal/tun_bench/main.go) on M4 MacBook pro.
|
||||
The following data was tested
|
||||
using [tun_bench](https://github.com/SagerNet/sing-box/blob/dev-next/cmd/internal/tun_bench/main.go) on M4 MacBook pro.
|
||||
|
||||
| Version | Stack | MTU | Upload | Download |
|
||||
|-------------|--------|-------|--------|----------|
|
||||
@@ -173,8 +197,8 @@ The following data was tested using [tun_bench](https://github.com/SagerNet/sing
|
||||
|
||||
**18**:
|
||||
|
||||
We continue to experience issues updating our sing-box apps on the App Store and Play Store.
|
||||
Until we rewrite and resubmit the apps, they are considered irrecoverable.
|
||||
We continue to experience issues updating our sing-box apps on the App Store and Play Store.
|
||||
Until we rewrite and resubmit the apps, they are considered irrecoverable.
|
||||
Therefore, after this release, we will not be repeating this notice unless there is new information.
|
||||
|
||||
### 1.11.15
|
||||
@@ -455,7 +479,8 @@ See [AnyTLS Inbound](/configuration/inbound/anytls/) and [AnyTLS Outbound](/conf
|
||||
|
||||
**2**:
|
||||
|
||||
`resolve` route action now accepts `disable_cache` and other options like in DNS route actions, see [Route Action](/configuration/route/rule_action).
|
||||
`resolve` route action now accepts `disable_cache` and other options like in DNS route actions,
|
||||
see [Route Action](/configuration/route/rule_action).
|
||||
|
||||
**3**:
|
||||
|
||||
@@ -486,7 +511,8 @@ See [Tailscale](/configuration/endpoint/tailscale/).
|
||||
|
||||
Due to maintenance difficulties, sing-box 1.12.0 requires at least Go 1.23 to compile.
|
||||
|
||||
For Windows 7 users, legacy binaries now continue to compile with Go 1.23 and patches from [MetaCubeX/go](https://github.com/MetaCubeX/go).
|
||||
For Windows 7 users, legacy binaries now continue to compile with Go 1.23 and patches
|
||||
from [MetaCubeX/go](https://github.com/MetaCubeX/go).
|
||||
|
||||
### 1.11.3
|
||||
|
||||
|
||||
@@ -11,16 +11,22 @@ the project maintainer via [GitHub Sponsors](https://github.com/sponsors/nekohas
|
||||
|
||||

|
||||
|
||||
### Special Sponsors
|
||||
## Commercial Sponsors
|
||||
|
||||
**Viral Tech, Inc.**
|
||||
> [Warp](https://go.warp.dev/sing-box), Built for coding with multiple AI agents.
|
||||
|
||||
[](https://go.warp.dev/sing-box)
|
||||
|
||||
## Special Sponsors
|
||||
|
||||
> Viral Tech, Inc.
|
||||
|
||||
Helping us re-list sing-box apps on the Apple Store.
|
||||
|
||||
---
|
||||
|
||||
[](https://www.jetbrains.com)
|
||||
> [JetBrains](https://www.jetbrains.com)
|
||||
|
||||
Free license for the amazing IDEs.
|
||||
|
||||
---
|
||||
[](https://www.jetbrains.com)
|
||||
|
||||
@@ -12,9 +12,7 @@ type iOSPauseFields struct {
|
||||
|
||||
func (s *BoxService) Pause() {
|
||||
s.pauseManager.DevicePause()
|
||||
if !C.IsIos {
|
||||
s.instance.Router().ResetNetwork()
|
||||
} else {
|
||||
if C.IsIos {
|
||||
if s.endPauseTimer == nil {
|
||||
s.endPauseTimer = time.AfterFunc(time.Minute, s.pauseManager.DeviceWake)
|
||||
} else {
|
||||
@@ -26,7 +24,6 @@ func (s *BoxService) Pause() {
|
||||
func (s *BoxService) Wake() {
|
||||
if !C.IsIos {
|
||||
s.pauseManager.DeviceWake()
|
||||
s.instance.Router().ResetNetwork()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
14
go.mod
14
go.mod
@@ -3,7 +3,7 @@ module github.com/sagernet/sing-box
|
||||
go 1.23.1
|
||||
|
||||
require (
|
||||
github.com/anytls/sing-anytls v0.0.8
|
||||
github.com/anytls/sing-anytls v0.0.11
|
||||
github.com/caddyserver/certmagic v0.23.0
|
||||
github.com/coder/websocket v1.8.13
|
||||
github.com/cretz/bine v0.2.0
|
||||
@@ -15,8 +15,8 @@ require (
|
||||
github.com/libdns/alidns v1.0.5-libdns.v1.beta1
|
||||
github.com/libdns/cloudflare v0.2.2-0.20250708034226-c574dccb31a6
|
||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4
|
||||
github.com/metacubex/utls v1.8.0
|
||||
github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0
|
||||
github.com/metacubex/utls v1.8.3
|
||||
github.com/mholt/acmez/v3 v3.1.2
|
||||
github.com/miekg/dns v1.1.67
|
||||
github.com/oschwald/maxminddb-golang v1.13.1
|
||||
@@ -26,17 +26,17 @@ require (
|
||||
github.com/sagernet/fswatch v0.1.1
|
||||
github.com/sagernet/gomobile v0.1.8
|
||||
github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1
|
||||
github.com/sagernet/sing v0.7.10
|
||||
github.com/sagernet/quic-go v0.52.0-sing-box-mod.3
|
||||
github.com/sagernet/sing v0.7.13
|
||||
github.com/sagernet/sing-mux v0.3.3
|
||||
github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb
|
||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||
github.com/sagernet/sing-tun v0.7.2
|
||||
github.com/sagernet/sing-tun v0.7.3
|
||||
github.com/sagernet/sing-vmess v0.2.7
|
||||
github.com/sagernet/smux v1.5.34-mod.2
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.1
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.2
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||
github.com/spf13/cobra v1.9.1
|
||||
|
||||
28
go.sum
28
go.sum
@@ -8,8 +8,8 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V
|
||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/anytls/sing-anytls v0.0.8 h1:1u/fnH1HoeeMV5mX7/eUOjLBvPdkd1UJRmXiRi6Vymc=
|
||||
github.com/anytls/sing-anytls v0.0.8/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
|
||||
github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc=
|
||||
github.com/anytls/sing-anytls v0.0.11/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8=
|
||||
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU=
|
||||
@@ -122,10 +122,10 @@ github.com/mdlayher/sdnotify v1.0.0 h1:Ma9XeLVN/l0qpyx1tNeMSeTjCPH6NtuD6/N9XdTlQ
|
||||
github.com/mdlayher/sdnotify v1.0.0/go.mod h1:HQUmpM4XgYkhDLtd+Uad8ZFK1T9D5+pNxnXQjCeJlGE=
|
||||
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac=
|
||||
github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0 h1:Ui+/2s5Qz0lSnDUBmEL12M5Oi/PzvFxGTNohm8ZcsmE=
|
||||
github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw=
|
||||
github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4=
|
||||
github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko=
|
||||
github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc=
|
||||
github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ=
|
||||
github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0=
|
||||
@@ -164,11 +164,11 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I=
|
||||
github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1 h1:hWkojLg64zjV+MJOvJU/kOeWndm3tiEfBLx5foisszs=
|
||||
github.com/sagernet/quic-go v0.52.0-beta.1/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/quic-go v0.52.0-sing-box-mod.3 h1:ySqffGm82rPqI1TUPqmtHIYd12pfEGScygnOxjTL56w=
|
||||
github.com/sagernet/quic-go v0.52.0-sing-box-mod.3/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4=
|
||||
github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.7.10 h1:2yPhZFx+EkyHPH8hXNezgyRSHyGY12CboId7CtwLROw=
|
||||
github.com/sagernet/sing v0.7.10/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing v0.7.13 h1:XNYgd8e3cxMULs/LLJspdn/deHrnPWyrrglNHeCUAYM=
|
||||
github.com/sagernet/sing v0.7.13/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||
github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw=
|
||||
github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
||||
github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb h1:5Wx3XeTiKrrrcrAky7Hc1bO3CGxrvho2Vu5b/adlEIM=
|
||||
@@ -179,14 +179,14 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||
github.com/sagernet/sing-tun v0.7.2 h1:uJkAZM0KBqIYzrq077QGqdvj/+4i/pMOx6Pnx0jYqAs=
|
||||
github.com/sagernet/sing-tun v0.7.2/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM=
|
||||
github.com/sagernet/sing-tun v0.7.3 h1:MFnAir+l24ElEyxdfwtY8mqvUUL9nPnL9TDYLkOmVes=
|
||||
github.com/sagernet/sing-tun v0.7.3/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM=
|
||||
github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk=
|
||||
github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs=
|
||||
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
|
||||
github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc=
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.1 h1:gMC0q+0VvZBotZMZ9G0R8ZMEIT/Q6KnXbw0/OgMjmdk=
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.1/go.mod h1:EBxXsWu4OH2ELbQLq32WoBeIubG8KgDrg4/Oaxjs6lI=
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.2 h1:MO7s4ni2bSfAOhcan2rdQSWCztkMXmqyg6jYPZp8bEE=
|
||||
github.com/sagernet/tailscale v1.80.3-sing-box-1.12-mod.2/go.mod h1:EBxXsWu4OH2ELbQLq32WoBeIubG8KgDrg4/Oaxjs6lI=
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7 h1:ltgBwYHfr+9Wz1eG59NiWnHrYEkDKHG7otNZvu85DXI=
|
||||
github.com/sagernet/wireguard-go v0.0.1-beta.7/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/uot"
|
||||
@@ -43,6 +44,13 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
if options.TLS == nil || !options.TLS.Enabled {
|
||||
return nil, C.ErrTLSRequired
|
||||
}
|
||||
// TCP Fast Open is incompatible with anytls because TFO creates a lazy connection
|
||||
// that only establishes on first write. The lazy connection returns an empty address
|
||||
// before establishment, but anytls SOCKS wrapper tries to access the remote address
|
||||
// during handshake, causing a null pointer dereference crash.
|
||||
if options.DialerOptions.TCPFastOpen {
|
||||
return nil, E.New("tcp_fast_open is not supported with anytls outbound")
|
||||
}
|
||||
|
||||
tlsConfig, err := tls.NewClient(ctx, options.Server, common.PtrValueOrDefault(options.TLS))
|
||||
if err != nil {
|
||||
|
||||
@@ -291,7 +291,7 @@ func wrapWsError(err error) error {
|
||||
}
|
||||
var closedErr wsutil.ClosedError
|
||||
if errors.As(err, &closedErr) {
|
||||
if closedErr.Code == ws.StatusNormalClosure {
|
||||
if closedErr.Code == ws.StatusNormalClosure || closedErr.Code == ws.StatusNoStatusRcvd {
|
||||
err = io.EOF
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user