mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-10 12:24:13 +08:00
Compare commits
95 Commits
dev-next
...
v1.12.0-be
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b9092f666e | ||
![]() |
9b6a27ccdc | ||
![]() |
465c498e8c | ||
![]() |
7e6d7949cf | ||
![]() |
6162fcbe8c | ||
![]() |
be50f24079 | ||
![]() |
63eb6a03dd | ||
![]() |
9ae2c9ecd0 | ||
![]() |
0327f94012 | ||
![]() |
3b2ba01b44 | ||
![]() |
2c25257b3d | ||
![]() |
e4824d7bc2 | ||
![]() |
f21d686e95 | ||
![]() |
3e7569fff3 | ||
![]() |
7e883f67f6 | ||
![]() |
a49d566cda | ||
![]() |
3608c41789 | ||
![]() |
d1a12e1ce9 | ||
![]() |
e5b6b503f5 | ||
![]() |
0131d8b9f4 | ||
![]() |
2a407ccb71 | ||
![]() |
2b5abde151 | ||
![]() |
639211d3e0 | ||
![]() |
b93a6ff261 | ||
![]() |
057e5f3cab | ||
![]() |
46a3fabca2 | ||
![]() |
2d923b4825 | ||
![]() |
843d591a17 | ||
![]() |
c4ca146a4c | ||
![]() |
f4e9c33a0b | ||
![]() |
df00507025 | ||
![]() |
0a1e135839 | ||
![]() |
13b4b72ac6 | ||
![]() |
fc425b802b | ||
![]() |
a31bbf35c2 | ||
![]() |
0c0374c749 | ||
![]() |
cb95a1bd30 | ||
![]() |
1669eaf7c0 | ||
![]() |
f59a14c5f2 | ||
![]() |
14c08adcf8 | ||
![]() |
6d7a4bde5c | ||
![]() |
45b7f2a93f | ||
![]() |
cd26a95509 | ||
![]() |
8dc129ef11 | ||
![]() |
c223a6edf6 | ||
![]() |
c416326cb1 | ||
![]() |
f269eb9db5 | ||
![]() |
76ffe82e89 | ||
![]() |
2dc99d86be | ||
![]() |
691c03ab0a | ||
![]() |
d21800acf7 | ||
![]() |
eeaedfeb9a | ||
![]() |
adf68261e7 | ||
![]() |
6cc7b4466f | ||
![]() |
4096b0b0e2 | ||
![]() |
45024d08b1 | ||
![]() |
76c182e76d | ||
![]() |
1be40e6cd1 | ||
![]() |
020463ee09 | ||
![]() |
95111d2e36 | ||
![]() |
f2c95ba744 | ||
![]() |
a2f4ea2850 | ||
![]() |
524636c159 | ||
![]() |
b929e75e3a | ||
![]() |
b5edc19f77 | ||
![]() |
0cbaff46a3 | ||
![]() |
86514a5f3e | ||
![]() |
0b55fda8a3 | ||
![]() |
b5363a3a9f | ||
![]() |
ae3c198a75 | ||
![]() |
2fbf415fac | ||
![]() |
00d3807839 | ||
![]() |
fdaa1d32d3 | ||
![]() |
f8bbebb3f1 | ||
![]() |
448cdbcfda | ||
![]() |
9299b990d2 | ||
![]() |
4cb1b54c96 | ||
![]() |
04f026ad0b | ||
![]() |
e6e1cec803 | ||
![]() |
16ea554a65 | ||
![]() |
8617660fb1 | ||
![]() |
2ee29daa85 | ||
![]() |
b0bc94f07c | ||
![]() |
587846b7f8 | ||
![]() |
0c20db66bf | ||
![]() |
86c4563c4e | ||
![]() |
5939fafca3 | ||
![]() |
4687f6cf0b | ||
![]() |
f5dfacf32b | ||
![]() |
3d18687f1a | ||
![]() |
8dff9752d9 | ||
![]() |
9dc93e97c5 | ||
![]() |
b93a07b6b8 | ||
![]() |
7c55973b99 | ||
![]() |
f62318f092 |
@ -8,7 +8,6 @@
|
|||||||
--deb-field "Bug: https://github.com/SagerNet/sing-box/issues"
|
--deb-field "Bug: https://github.com/SagerNet/sing-box/issues"
|
||||||
--no-deb-generate-changes
|
--no-deb-generate-changes
|
||||||
--config-files /etc/sing-box/config.json
|
--config-files /etc/sing-box/config.json
|
||||||
--after-install release/config/sing-box.postinst
|
|
||||||
|
|
||||||
release/config/config.json=/etc/sing-box/config.json
|
release/config/config.json=/etc/sing-box/config.json
|
||||||
|
|
||||||
|
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@ -46,7 +46,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24.4
|
go-version: ^1.24.3
|
||||||
- name: Check input version
|
- name: Check input version
|
||||||
if: github.event_name == 'workflow_dispatch'
|
if: github.event_name == 'workflow_dispatch'
|
||||||
run: |-
|
run: |-
|
||||||
@ -109,7 +109,7 @@ jobs:
|
|||||||
if: ${{ ! matrix.legacy_go }}
|
if: ${{ ! matrix.legacy_go }}
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24.4
|
go-version: ^1.24.3
|
||||||
- name: Cache Legacy Go
|
- name: Cache Legacy Go
|
||||||
if: matrix.require_legacy_go
|
if: matrix.require_legacy_go
|
||||||
id: cache-legacy-go
|
id: cache-legacy-go
|
||||||
@ -294,7 +294,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24.4
|
go-version: ^1.24.3
|
||||||
- name: Setup Android NDK
|
- name: Setup Android NDK
|
||||||
id: setup-ndk
|
id: setup-ndk
|
||||||
uses: nttld/setup-ndk@v1
|
uses: nttld/setup-ndk@v1
|
||||||
@ -374,7 +374,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24.4
|
go-version: ^1.24.3
|
||||||
- name: Setup Android NDK
|
- name: Setup Android NDK
|
||||||
id: setup-ndk
|
id: setup-ndk
|
||||||
uses: nttld/setup-ndk@v1
|
uses: nttld/setup-ndk@v1
|
||||||
@ -472,7 +472,7 @@ jobs:
|
|||||||
if: matrix.if
|
if: matrix.if
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24.4
|
go-version: ^1.24.3
|
||||||
- name: Setup Xcode stable
|
- name: Setup Xcode stable
|
||||||
if: matrix.if && github.ref == 'refs/heads/main-next'
|
if: matrix.if && github.ref == 'refs/heads/main-next'
|
||||||
run: |-
|
run: |-
|
||||||
|
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24.4
|
go-version: ^1.24.3
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v6
|
uses: golangci/golangci-lint-action@v6
|
||||||
with:
|
with:
|
||||||
|
4
.github/workflows/linux.yml
vendored
4
.github/workflows/linux.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24.4
|
go-version: ^1.24.3
|
||||||
- name: Check input version
|
- name: Check input version
|
||||||
if: github.event_name == 'workflow_dispatch'
|
if: github.event_name == 'workflow_dispatch'
|
||||||
run: |-
|
run: |-
|
||||||
@ -66,7 +66,7 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v5
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: ^1.24.4
|
go-version: ^1.24.3
|
||||||
- name: Setup Android NDK
|
- name: Setup Android NDK
|
||||||
if: matrix.os == 'android'
|
if: matrix.os == 'android'
|
||||||
uses: nttld/setup-ndk@v1
|
uses: nttld/setup-ndk@v1
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 320170a1077ea5c93872b3e055b96b8836615ef0
|
Subproject commit cec05bf6935eca219a722883212ae8880d2e863e
|
@ -97,6 +97,10 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
|||||||
} else if networkManager.AutoDetectInterface() {
|
} else if networkManager.AutoDetectInterface() {
|
||||||
if platformInterface != nil {
|
if platformInterface != nil {
|
||||||
networkStrategy = (*C.NetworkStrategy)(options.NetworkStrategy)
|
networkStrategy = (*C.NetworkStrategy)(options.NetworkStrategy)
|
||||||
|
if networkStrategy == nil {
|
||||||
|
networkStrategy = common.Ptr(C.NetworkStrategyDefault)
|
||||||
|
defaultNetworkStrategy = true
|
||||||
|
}
|
||||||
networkType = common.Map(options.NetworkType, option.InterfaceType.Build)
|
networkType = common.Map(options.NetworkType, option.InterfaceType.Build)
|
||||||
fallbackNetworkType = common.Map(options.FallbackNetworkType, option.InterfaceType.Build)
|
fallbackNetworkType = common.Map(options.FallbackNetworkType, option.InterfaceType.Build)
|
||||||
if networkStrategy == nil && len(networkType) == 0 && len(fallbackNetworkType) == 0 {
|
if networkStrategy == nil && len(networkType) == 0 && len(fallbackNetworkType) == 0 {
|
||||||
@ -108,10 +112,6 @@ func NewDefault(ctx context.Context, options option.DialerOptions) (*DefaultDial
|
|||||||
if networkFallbackDelay == 0 && defaultOptions.FallbackDelay != 0 {
|
if networkFallbackDelay == 0 && defaultOptions.FallbackDelay != 0 {
|
||||||
networkFallbackDelay = defaultOptions.FallbackDelay
|
networkFallbackDelay = defaultOptions.FallbackDelay
|
||||||
}
|
}
|
||||||
if networkStrategy == nil {
|
|
||||||
networkStrategy = common.Ptr(C.NetworkStrategyDefault)
|
|
||||||
defaultNetworkStrategy = true
|
|
||||||
}
|
|
||||||
bindFunc := networkManager.ProtectFunc()
|
bindFunc := networkManager.ProtectFunc()
|
||||||
dialer.Control = control.Append(dialer.Control, bindFunc)
|
dialer.Control = control.Append(dialer.Control, bindFunc)
|
||||||
listener.Control = control.Append(listener.Control, bindFunc)
|
listener.Control = control.Append(listener.Control, bindFunc)
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
@ -75,11 +76,10 @@ func (c *slowOpenConn) Write(b []byte) (n int, err error) {
|
|||||||
return c.conn.Write(b)
|
return c.conn.Write(b)
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
conn, err := c.dialer.DialContext(c.ctx, c.network, c.destination.String(), b)
|
c.conn, err = c.dialer.DialContext(c.ctx, c.network, c.destination.String(), b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.err = err
|
c.conn = nil
|
||||||
} else {
|
c.err = E.Cause(err, "dial tcp fast open")
|
||||||
c.conn = conn
|
|
||||||
}
|
}
|
||||||
n = len(b)
|
n = len(b)
|
||||||
close(c.create)
|
close(c.create)
|
||||||
|
@ -56,7 +56,7 @@ func (l *Listener) ListenTCP() (net.Listener, error) {
|
|||||||
if l.tproxy {
|
if l.tproxy {
|
||||||
listenConfig.Control = control.Append(listenConfig.Control, func(network, address string, conn syscall.RawConn) error {
|
listenConfig.Control = control.Append(listenConfig.Control, func(network, address string, conn syscall.RawConn) error {
|
||||||
return control.Raw(conn, func(fd uintptr) error {
|
return control.Raw(conn, func(fd uintptr) error {
|
||||||
return redir.TProxy(fd, !M.ParseSocksaddr(address).IsIPv4(), false)
|
return redir.TProxy(fd, M.ParseSocksaddr(address).IsIPv6(), false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ func (l *Listener) ListenUDP() (net.PacketConn, error) {
|
|||||||
if l.tproxy {
|
if l.tproxy {
|
||||||
listenConfig.Control = control.Append(listenConfig.Control, func(network, address string, conn syscall.RawConn) error {
|
listenConfig.Control = control.Append(listenConfig.Control, func(network, address string, conn syscall.RawConn) error {
|
||||||
return control.Raw(conn, func(fd uintptr) error {
|
return control.Raw(conn, func(fd uintptr) error {
|
||||||
return redir.TProxy(fd, !M.ParseSocksaddr(address).IsIPv4(), true)
|
return redir.TProxy(fd, M.ParseSocksaddr(address).IsIPv6(), true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
package sniff
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NTP(ctx context.Context, metadata *adapter.InboundContext, packet []byte) error {
|
|
||||||
// NTP packets must be at least 48 bytes long (standard NTP header size).
|
|
||||||
pLen := len(packet)
|
|
||||||
if pLen < 48 {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
// Check the LI (Leap Indicator) and Version Number (VN) in the first byte.
|
|
||||||
// We'll primarily focus on ensuring the version is valid for NTP.
|
|
||||||
// Many NTP versions are used, but let's check for generally accepted ones (3 & 4 for IPv4, plus potential extensions/customizations)
|
|
||||||
firstByte := packet[0]
|
|
||||||
li := (firstByte >> 6) & 0x03 // Extract LI
|
|
||||||
vn := (firstByte >> 3) & 0x07 // Extract VN
|
|
||||||
mode := firstByte & 0x07 // Extract Mode
|
|
||||||
|
|
||||||
// Leap Indicator should be a valid value (0-3).
|
|
||||||
if li > 3 {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version Check (common NTP versions are 3 and 4)
|
|
||||||
if vn != 3 && vn != 4 {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the Mode field for a client request (Mode 3). This validates it *is* a request.
|
|
||||||
if mode != 3 {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Root Delay and Root Dispersion. While not strictly *required* for a request,
|
|
||||||
// we can check if they appear to be reasonable values (not excessively large).
|
|
||||||
rootDelay := binary.BigEndian.Uint32(packet[4:8])
|
|
||||||
rootDispersion := binary.BigEndian.Uint32(packet[8:12])
|
|
||||||
|
|
||||||
// Check for unreasonably large root delay and dispersion. NTP RFC specifies max values of approximately 16 seconds.
|
|
||||||
// Convert to milliseconds for easy comparison. Each unit is 1/2^16 seconds.
|
|
||||||
if float64(rootDelay)/65536.0 > 16.0 {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
if float64(rootDispersion)/65536.0 > 16.0 {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata.Protocol = C.ProtocolNTP
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
package sniff_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/hex"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
|
||||||
"github.com/sagernet/sing-box/common/sniff"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSniffNTP(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
packet, err := hex.DecodeString("1b0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
||||||
require.NoError(t, err)
|
|
||||||
var metadata adapter.InboundContext
|
|
||||||
err = sniff.NTP(context.Background(), &metadata, packet)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, metadata.Protocol, C.ProtocolNTP)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSniffNTPFailed(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
packet, err := hex.DecodeString("400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
|
|
||||||
require.NoError(t, err)
|
|
||||||
var metadata adapter.InboundContext
|
|
||||||
err = sniff.NTP(context.Background(), &metadata, packet)
|
|
||||||
require.ErrorIs(t, err, os.ErrInvalid)
|
|
||||||
}
|
|
@ -34,7 +34,6 @@ type Client struct {
|
|||||||
disableCache bool
|
disableCache bool
|
||||||
disableExpire bool
|
disableExpire bool
|
||||||
independentCache bool
|
independentCache bool
|
||||||
clientSubnet netip.Prefix
|
|
||||||
rdrc adapter.RDRCStore
|
rdrc adapter.RDRCStore
|
||||||
initRDRCFunc func() adapter.RDRCStore
|
initRDRCFunc func() adapter.RDRCStore
|
||||||
logger logger.ContextLogger
|
logger logger.ContextLogger
|
||||||
@ -48,7 +47,6 @@ type ClientOptions struct {
|
|||||||
DisableExpire bool
|
DisableExpire bool
|
||||||
IndependentCache bool
|
IndependentCache bool
|
||||||
CacheCapacity uint32
|
CacheCapacity uint32
|
||||||
ClientSubnet netip.Prefix
|
|
||||||
RDRC func() adapter.RDRCStore
|
RDRC func() adapter.RDRCStore
|
||||||
Logger logger.ContextLogger
|
Logger logger.ContextLogger
|
||||||
}
|
}
|
||||||
@ -59,7 +57,6 @@ func NewClient(options ClientOptions) *Client {
|
|||||||
disableCache: options.DisableCache,
|
disableCache: options.DisableCache,
|
||||||
disableExpire: options.DisableExpire,
|
disableExpire: options.DisableExpire,
|
||||||
independentCache: options.IndependentCache,
|
independentCache: options.IndependentCache,
|
||||||
clientSubnet: options.ClientSubnet,
|
|
||||||
initRDRCFunc: options.RDRC,
|
initRDRCFunc: options.RDRC,
|
||||||
logger: options.Logger,
|
logger: options.Logger,
|
||||||
}
|
}
|
||||||
@ -107,12 +104,8 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m
|
|||||||
return &responseMessage, nil
|
return &responseMessage, nil
|
||||||
}
|
}
|
||||||
question := message.Question[0]
|
question := message.Question[0]
|
||||||
clientSubnet := options.ClientSubnet
|
if options.ClientSubnet.IsValid() {
|
||||||
if !clientSubnet.IsValid() {
|
message = SetClientSubnet(message, options.ClientSubnet)
|
||||||
clientSubnet = c.clientSubnet
|
|
||||||
}
|
|
||||||
if clientSubnet.IsValid() {
|
|
||||||
message = SetClientSubnet(message, clientSubnet)
|
|
||||||
}
|
}
|
||||||
isSimpleRequest := len(message.Question) == 1 &&
|
isSimpleRequest := len(message.Question) == 1 &&
|
||||||
len(message.Ns) == 0 &&
|
len(message.Ns) == 0 &&
|
||||||
|
@ -55,7 +55,6 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.DNSOp
|
|||||||
DisableExpire: options.DNSClientOptions.DisableExpire,
|
DisableExpire: options.DNSClientOptions.DisableExpire,
|
||||||
IndependentCache: options.DNSClientOptions.IndependentCache,
|
IndependentCache: options.DNSClientOptions.IndependentCache,
|
||||||
CacheCapacity: options.DNSClientOptions.CacheCapacity,
|
CacheCapacity: options.DNSClientOptions.CacheCapacity,
|
||||||
ClientSubnet: options.DNSClientOptions.ClientSubnet.Build(netip.Prefix{}),
|
|
||||||
RDRC: func() adapter.RDRCStore {
|
RDRC: func() adapter.RDRCStore {
|
||||||
cacheFile := service.FromContext[adapter.CacheFile](ctx)
|
cacheFile := service.FromContext[adapter.CacheFile](ctx)
|
||||||
if cacheFile == nil {
|
if cacheFile == nil {
|
||||||
|
@ -2,28 +2,10 @@
|
|||||||
icon: material/alert-decagram
|
icon: material/alert-decagram
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 1.12.0-beta.22
|
#### 1.12.0-beta.19
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
#### 1.12.0-beta.21
|
|
||||||
|
|
||||||
* Fix missing `home` option for DERP service **1**
|
|
||||||
* Fixes and improvements
|
|
||||||
|
|
||||||
**1**:
|
|
||||||
|
|
||||||
You can now choose what the DERP home page shows, just like with derper's `-home` flag.
|
|
||||||
|
|
||||||
See [DERP](/configuration/service/derp/#home).
|
|
||||||
|
|
||||||
### 1.11.13
|
|
||||||
|
|
||||||
* Fixes and improvements
|
|
||||||
|
|
||||||
_We are temporarily unable to update sing-box apps on the App Store because the reviewer mistakenly found that we
|
|
||||||
violated the rules (TestFlight users are not affected)._
|
|
||||||
|
|
||||||
#### 1.12.0-beta.17
|
#### 1.12.0-beta.17
|
||||||
|
|
||||||
* Update quic-go to v0.52.0
|
* Update quic-go to v0.52.0
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
---
|
---
|
||||||
icon: material/alert-decagram
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.12.0"
|
|
||||||
|
|
||||||
:material-decagram: [servers](#servers)
|
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.11.0"
|
!!! quote "Changes in sing-box 1.11.0"
|
||||||
|
|
||||||
:material-plus: [cache_capacity](#cache_capacity)
|
:material-plus: [cache_capacity](#cache_capacity)
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
---
|
---
|
||||||
icon: material/alert-decagram
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
!!! quote "sing-box 1.12.0 中的更改"
|
|
||||||
|
|
||||||
:material-decagram: [servers](#servers)
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.11.0 中的更改"
|
!!! quote "sing-box 1.11.0 中的更改"
|
||||||
|
|
||||||
:material-plus: [cache_capacity](#cache_capacity)
|
:material-plus: [cache_capacity](#cache_capacity)
|
||||||
|
@ -398,11 +398,11 @@ UDP NAT 过期时间。
|
|||||||
|
|
||||||
TCP/IP 栈。
|
TCP/IP 栈。
|
||||||
|
|
||||||
| 栈 | 描述 |
|
| 栈 | 描述 |
|
||||||
|----------|-------------------------------------------------------------------------------------------------------|
|
|--------|------------------------------------------------------------------|
|
||||||
| `system` | 基于系统网络栈执行 L3 到 L4 转换 |
|
| system | 基于系统网络栈执行 L3 到 L4 转换 |
|
||||||
| `gvisor` | 基于 [gVisor](https://github.com/google/gvisor) 虚拟网络栈执行 L3 到 L4 转换 |
|
| gVisor | 基于 [gVisor](https://github.com/google/gvisor) 虚拟网络栈执行 L3 到 L4 转换 |
|
||||||
| `mixed` | 混合 `system` TCP 栈与 `gvisor` UDP 栈 |
|
| mixed | 混合 `system` TCP 栈与 `gvisor` UDP 栈 |
|
||||||
|
|
||||||
默认使用 `mixed` 栈如果 gVisor 构建标记已启用,否则默认使用 `system` 栈。
|
默认使用 `mixed` 栈如果 gVisor 构建标记已启用,否则默认使用 `system` 栈。
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ If enabled in the inbound, the protocol and domain name (if present) of by the c
|
|||||||
| UDP | `dtls` | / | / |
|
| UDP | `dtls` | / | / |
|
||||||
| TCP | `ssh` | / | SSH Client Name |
|
| TCP | `ssh` | / | SSH Client Name |
|
||||||
| TCP | `rdp` | / | / |
|
| TCP | `rdp` | / | / |
|
||||||
| UDP | `ntp` | / | / |
|
|
||||||
|
|
||||||
| QUIC Client | Type |
|
| QUIC Client | Type |
|
||||||
|:------------------------:|:----------:|
|
|:------------------------:|:----------:|
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
| UDP | `dtls` | / | / |
|
| UDP | `dtls` | / | / |
|
||||||
| TCP | `ssh` | / | SSH 客户端名称 |
|
| TCP | `ssh` | / | SSH 客户端名称 |
|
||||||
| TCP | `rdp` | / | / |
|
| TCP | `rdp` | / | / |
|
||||||
| UDP | `ntp` | / | / |
|
|
||||||
|
|
||||||
| QUIC 客户端 | 类型 |
|
| QUIC 客户端 | 类型 |
|
||||||
|:------------------------:|:----------:|
|
|:------------------------:|:----------:|
|
||||||
|
@ -20,7 +20,6 @@ DERP service is a Tailscale DERP server, similar to [derper](https://pkg.go.dev/
|
|||||||
"config_path": "",
|
"config_path": "",
|
||||||
"verify_client_endpoint": [],
|
"verify_client_endpoint": [],
|
||||||
"verify_client_url": [],
|
"verify_client_url": [],
|
||||||
"home": "",
|
|
||||||
"mesh_with": [],
|
"mesh_with": [],
|
||||||
"mesh_psk": "",
|
"mesh_psk": "",
|
||||||
"mesh_psk_file": "",
|
"mesh_psk_file": "",
|
||||||
@ -70,10 +69,6 @@ Setting Array value to a string `__URL__` is equivalent to configuring:
|
|||||||
{ "url": __URL__ }
|
{ "url": __URL__ }
|
||||||
```
|
```
|
||||||
|
|
||||||
#### home
|
|
||||||
|
|
||||||
What to serve at the root path. It may be left empty (the default, for a default homepage), `blank` for a blank page, or a URL to redirect to
|
|
||||||
|
|
||||||
#### mesh_with
|
#### mesh_with
|
||||||
|
|
||||||
Mesh with other DERP servers.
|
Mesh with other DERP servers.
|
||||||
|
@ -10,7 +10,7 @@ icon: material/new-box
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"services": [
|
"endpoints": [
|
||||||
{
|
{
|
||||||
"type": "",
|
"type": "",
|
||||||
"tag": ""
|
"tag": ""
|
||||||
@ -25,7 +25,6 @@ icon: material/new-box
|
|||||||
|------------|------------------------|
|
|------------|------------------------|
|
||||||
| `derp` | [DERP](./derp) |
|
| `derp` | [DERP](./derp) |
|
||||||
| `resolved` | [Resolved](./resolved) |
|
| `resolved` | [Resolved](./resolved) |
|
||||||
| `ssm-api` | [SSM API](./ssm-api) |
|
|
||||||
|
|
||||||
#### tag
|
#### tag
|
||||||
|
|
||||||
|
6
go.mod
6
go.mod
@ -30,12 +30,12 @@ require (
|
|||||||
github.com/sagernet/quic-go v0.52.0-beta.1
|
github.com/sagernet/quic-go v0.52.0-beta.1
|
||||||
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b
|
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b
|
||||||
github.com/sagernet/sing-mux v0.3.2
|
github.com/sagernet/sing-mux v0.3.2
|
||||||
github.com/sagernet/sing-quic v0.5.0-beta.2
|
github.com/sagernet/sing-quic v0.5.0-beta.1
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
github.com/sagernet/sing-shadowsocks2 v0.2.1
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11
|
||||||
github.com/sagernet/sing-tun v0.6.6-0.20250428031943-0686f8c4f210
|
github.com/sagernet/sing-tun v0.6.6-0.20250428031943-0686f8c4f210
|
||||||
github.com/sagernet/sing-vmess v0.2.4-0.20250605032146-38cc72672c88
|
github.com/sagernet/sing-vmess v0.2.2-0.20250503051933-9b4cf17393f8
|
||||||
github.com/sagernet/smux v1.5.34-mod.2
|
github.com/sagernet/smux v1.5.34-mod.2
|
||||||
github.com/sagernet/tailscale v1.80.3-mod.5
|
github.com/sagernet/tailscale v1.80.3-mod.5
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.7
|
github.com/sagernet/wireguard-go v0.0.1-beta.7
|
||||||
|
12
go.sum
12
go.sum
@ -172,18 +172,18 @@ github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b h1:ZjTCYPb5f7aHdf
|
|||||||
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.6.11-0.20250521033217-30d675ea099b/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE=
|
github.com/sagernet/sing-mux v0.3.2 h1:meZVFiiStvHThb/trcpAkCrmtJOuItG5Dzl1RRP5/NE=
|
||||||
github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
github.com/sagernet/sing-mux v0.3.2/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA=
|
||||||
github.com/sagernet/sing-quic v0.5.0-beta.2 h1:j7KAbBuGmsKwSxVAQL5soJ+wDqxim4/llK2kxB0hSKk=
|
github.com/sagernet/sing-quic v0.5.0-beta.1 h1:nC0i/s8LhlZB8ev6laZCXF/uiwAE4kRdT4PcDdE4rI4=
|
||||||
github.com/sagernet/sing-quic v0.5.0-beta.2/go.mod h1:SAv/qdeDN+75msGG5U5ZIwG+3Ua50jVIKNrRSY8pkx0=
|
github.com/sagernet/sing-quic v0.5.0-beta.1/go.mod h1:SAv/qdeDN+75msGG5U5ZIwG+3Ua50jVIKNrRSY8pkx0=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
|
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI=
|
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo=
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
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 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w=
|
||||||
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA=
|
||||||
github.com/sagernet/sing-tun v0.6.6-0.20250428031943-0686f8c4f210 h1:6H4BZaTqKI3YcDMyTV3E576LuJM4S4wY99xoq2T1ECw=
|
github.com/sagernet/sing-tun v0.6.6-0.20250428031943-0686f8c4f210 h1:6H4BZaTqKI3YcDMyTV3E576LuJM4S4wY99xoq2T1ECw=
|
||||||
github.com/sagernet/sing-tun v0.6.6-0.20250428031943-0686f8c4f210/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
github.com/sagernet/sing-tun v0.6.6-0.20250428031943-0686f8c4f210/go.mod h1:fisFCbC4Vfb6HqQNcwPJi2CDK2bf0Xapyz3j3t4cnHE=
|
||||||
github.com/sagernet/sing-vmess v0.2.4-0.20250605032146-38cc72672c88 h1:0pVm8sPOel+BoiCddW3pV3cKDKEaSioVTYDdTSKjyFI=
|
github.com/sagernet/sing-vmess v0.2.2-0.20250503051933-9b4cf17393f8 h1:zW+zAOCxUIqBCgnZiPovt1uQ3S+zBS+w0NGp+1zITGA=
|
||||||
github.com/sagernet/sing-vmess v0.2.4-0.20250605032146-38cc72672c88/go.mod h1:IL8Rr+EGwuqijszZkNrEFTQDKhilEpkqFqOlvdpS6/w=
|
github.com/sagernet/sing-vmess v0.2.2-0.20250503051933-9b4cf17393f8/go.mod h1:IL8Rr+EGwuqijszZkNrEFTQDKhilEpkqFqOlvdpS6/w=
|
||||||
github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4=
|
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/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc=
|
||||||
github.com/sagernet/tailscale v1.80.3-mod.5 h1:7V7z+p2C//TGtff20pPnDCt3qP6uFyY62peJoKF9z/A=
|
github.com/sagernet/tailscale v1.80.3-mod.5 h1:7V7z+p2C//TGtff20pPnDCt3qP6uFyY62peJoKF9z/A=
|
||||||
|
@ -36,7 +36,6 @@ type DERPServiceOptions struct {
|
|||||||
ConfigPath string `json:"config_path,omitempty"`
|
ConfigPath string `json:"config_path,omitempty"`
|
||||||
VerifyClientEndpoint badoption.Listable[string] `json:"verify_client_endpoint,omitempty"`
|
VerifyClientEndpoint badoption.Listable[string] `json:"verify_client_endpoint,omitempty"`
|
||||||
VerifyClientURL badoption.Listable[*DERPVerifyClientURLOptions] `json:"verify_client_url,omitempty"`
|
VerifyClientURL badoption.Listable[*DERPVerifyClientURLOptions] `json:"verify_client_url,omitempty"`
|
||||||
Home string `json:"home,omitempty"`
|
|
||||||
MeshWith badoption.Listable[*DERPMeshOptions] `json:"mesh_with,omitempty"`
|
MeshWith badoption.Listable[*DERPMeshOptions] `json:"mesh_with,omitempty"`
|
||||||
MeshPSK string `json:"mesh_psk,omitempty"`
|
MeshPSK string `json:"mesh_psk,omitempty"`
|
||||||
MeshPSKFile string `json:"mesh_psk_file,omitempty"`
|
MeshPSKFile string `json:"mesh_psk_file,omitempty"`
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
systemd-sysusers sing-box.conf
|
|
12
route/dns.go
12
route/dns.go
@ -36,7 +36,7 @@ func (r *Router) hijackDNSStream(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetBuffers []*N.PacketBuffer, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) error {
|
func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetBuffers []*N.PacketBuffer, metadata adapter.InboundContext) error {
|
||||||
if natConn, isNatConn := conn.(udpnat.Conn); isNatConn {
|
if natConn, isNatConn := conn.(udpnat.Conn); isNatConn {
|
||||||
metadata.Destination = M.Socksaddr{}
|
metadata.Destination = M.Socksaddr{}
|
||||||
for _, packet := range packetBuffers {
|
for _, packet := range packetBuffers {
|
||||||
@ -51,12 +51,10 @@ func (r *Router) hijackDNSPacket(ctx context.Context, conn N.PacketConn, packetB
|
|||||||
conn: conn,
|
conn: conn,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
onClose: onClose,
|
|
||||||
})
|
})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err := dnsOutbound.NewDNSPacketConnection(ctx, r.dns, conn, packetBuffers, metadata)
|
err := dnsOutbound.NewDNSPacketConnection(ctx, r.dns, conn, packetBuffers, metadata)
|
||||||
N.CloseOnHandshakeFailure(conn, onClose, err)
|
|
||||||
if err != nil && !E.IsClosedOrCanceled(err) {
|
if err != nil && !E.IsClosedOrCanceled(err) {
|
||||||
return E.Cause(err, "process DNS packet")
|
return E.Cause(err, "process DNS packet")
|
||||||
}
|
}
|
||||||
@ -95,16 +93,8 @@ type dnsHijacker struct {
|
|||||||
conn N.PacketConn
|
conn N.PacketConn
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
metadata adapter.InboundContext
|
metadata adapter.InboundContext
|
||||||
onClose N.CloseHandlerFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *dnsHijacker) NewPacketEx(buffer *buf.Buffer, destination M.Socksaddr) {
|
func (h *dnsHijacker) NewPacketEx(buffer *buf.Buffer, destination M.Socksaddr) {
|
||||||
go ExchangeDNSPacket(h.ctx, h.router, h.logger, h.conn, buffer, h.metadata, destination)
|
go ExchangeDNSPacket(h.ctx, h.router, h.logger, h.conn, buffer, h.metadata, destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *dnsHijacker) Close() error {
|
|
||||||
if h.onClose != nil {
|
|
||||||
h.onClose(nil)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -117,8 +117,7 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
|
|||||||
for _, buffer := range buffers {
|
for _, buffer := range buffers {
|
||||||
conn = bufio.NewCachedConn(conn, buffer)
|
conn = bufio.NewCachedConn(conn, buffer)
|
||||||
}
|
}
|
||||||
N.CloseOnHandshakeFailure(conn, onClose, r.hijackDNSStream(ctx, conn, metadata))
|
return r.hijackDNSStream(ctx, conn, metadata)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if selectedRule == nil {
|
if selectedRule == nil {
|
||||||
@ -229,7 +228,8 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
|
|||||||
N.ReleaseMultiPacketBuffer(packetBuffers)
|
N.ReleaseMultiPacketBuffer(packetBuffers)
|
||||||
return action.Error(ctx)
|
return action.Error(ctx)
|
||||||
case *rule.RuleActionHijackDNS:
|
case *rule.RuleActionHijackDNS:
|
||||||
return r.hijackDNSPacket(ctx, conn, packetBuffers, metadata, onClose)
|
return r.hijackDNSPacket(ctx, conn, packetBuffers, metadata)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if selectedRule == nil || selectReturn {
|
if selectedRule == nil || selectReturn {
|
||||||
@ -564,7 +564,6 @@ func (r *Router) actionSniff(
|
|||||||
sniff.UTP,
|
sniff.UTP,
|
||||||
sniff.UDPTracker,
|
sniff.UDPTracker,
|
||||||
sniff.DTLSRecord,
|
sniff.DTLSRecord,
|
||||||
sniff.NTP,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
|
@ -379,8 +379,6 @@ func (r *RuleActionSniff) build() error {
|
|||||||
r.StreamSniffers = append(r.StreamSniffers, sniff.SSH)
|
r.StreamSniffers = append(r.StreamSniffers, sniff.SSH)
|
||||||
case C.ProtocolRDP:
|
case C.ProtocolRDP:
|
||||||
r.StreamSniffers = append(r.StreamSniffers, sniff.RDP)
|
r.StreamSniffers = append(r.StreamSniffers, sniff.RDP)
|
||||||
case C.ProtocolNTP:
|
|
||||||
r.PacketSniffers = append(r.PacketSniffers, sniff.NTP)
|
|
||||||
default:
|
default:
|
||||||
return E.New("unknown sniffer: ", name)
|
return E.New("unknown sniffer: ", name)
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,6 @@ func NewService(ctx context.Context, logger log.ContextLogger, tag string, optio
|
|||||||
configPath: configPath,
|
configPath: configPath,
|
||||||
verifyClientEndpoint: options.VerifyClientEndpoint,
|
verifyClientEndpoint: options.VerifyClientEndpoint,
|
||||||
verifyClientURL: options.VerifyClientURL,
|
verifyClientURL: options.VerifyClientURL,
|
||||||
home: options.Home,
|
|
||||||
meshKey: options.MeshPSK,
|
meshKey: options.MeshPSK,
|
||||||
meshKeyPath: options.MeshPSKFile,
|
meshKeyPath: options.MeshPSKFile,
|
||||||
meshWith: options.MeshWith,
|
meshWith: options.MeshWith,
|
||||||
|
@ -47,7 +47,6 @@ func NewServer(ctx context.Context, logger logger.ContextLogger, options option.
|
|||||||
server := &Server{
|
server := &Server{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
tlsConfig: tlsConfig,
|
tlsConfig: tlsConfig,
|
||||||
logger: logger,
|
|
||||||
handler: handler,
|
handler: handler,
|
||||||
h2Server: &http2.Server{
|
h2Server: &http2.Server{
|
||||||
IdleTimeout: time.Duration(options.IdleTimeout),
|
IdleTimeout: time.Duration(options.IdleTimeout),
|
||||||
|
@ -3,7 +3,6 @@ package v2raywebsocket
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@ -68,10 +67,9 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !E.IsMulti(err, io.EOF, wsutil.ErrNoFrameAdvance) {
|
if !E.IsMulti(err, io.EOF, wsutil.ErrNoFrameAdvance) {
|
||||||
err = wrapWsError(err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
header, err = wrapWsError0(c.reader.NextFrame())
|
header, err = c.reader.NextFrame()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -80,14 +78,14 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) {
|
|||||||
err = wsutil.ErrFrameTooLarge
|
err = wsutil.ErrFrameTooLarge
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = wrapWsError(c.controlHandler(header, c.reader))
|
err = c.controlHandler(header, c.reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if header.OpCode&ws.OpBinary == 0 {
|
if header.OpCode&ws.OpBinary == 0 {
|
||||||
err = wrapWsError(c.reader.Discard())
|
err = c.reader.Discard()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -97,7 +95,7 @@ func (c *WebsocketConn) Read(b []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *WebsocketConn) Write(p []byte) (n int, err error) {
|
func (c *WebsocketConn) Write(p []byte) (n int, err error) {
|
||||||
err = wrapWsError(wsutil.WriteMessage(c.Conn, c.state, ws.OpBinary, p))
|
err = wsutil.WriteMessage(c.Conn, c.state, ws.OpBinary, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -148,7 +146,7 @@ func (c *EarlyWebsocketConn) Read(b []byte) (n int, err error) {
|
|||||||
return 0, c.err
|
return 0, c.err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return wrapWsError0(c.conn.Read(b))
|
return c.conn.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *EarlyWebsocketConn) writeRequest(content []byte) error {
|
func (c *EarlyWebsocketConn) writeRequest(content []byte) error {
|
||||||
@ -193,7 +191,7 @@ func (c *EarlyWebsocketConn) writeRequest(content []byte) error {
|
|||||||
|
|
||||||
func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
||||||
if c.conn != nil {
|
if c.conn != nil {
|
||||||
return wrapWsError0(c.conn.Write(b))
|
return c.conn.Write(b)
|
||||||
}
|
}
|
||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
defer c.access.Unlock()
|
defer c.access.Unlock()
|
||||||
@ -201,7 +199,7 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
|||||||
return 0, c.err
|
return 0, c.err
|
||||||
}
|
}
|
||||||
if c.conn != nil {
|
if c.conn != nil {
|
||||||
return wrapWsError0(c.conn.Write(b))
|
return c.conn.Write(b)
|
||||||
}
|
}
|
||||||
err = c.writeRequest(b)
|
err = c.writeRequest(b)
|
||||||
c.err = err
|
c.err = err
|
||||||
@ -214,12 +212,12 @@ func (c *EarlyWebsocketConn) Write(b []byte) (n int, err error) {
|
|||||||
|
|
||||||
func (c *EarlyWebsocketConn) WriteBuffer(buffer *buf.Buffer) error {
|
func (c *EarlyWebsocketConn) WriteBuffer(buffer *buf.Buffer) error {
|
||||||
if c.conn != nil {
|
if c.conn != nil {
|
||||||
return wrapWsError(c.conn.WriteBuffer(buffer))
|
return c.conn.WriteBuffer(buffer)
|
||||||
}
|
}
|
||||||
c.access.Lock()
|
c.access.Lock()
|
||||||
defer c.access.Unlock()
|
defer c.access.Unlock()
|
||||||
if c.conn != nil {
|
if c.conn != nil {
|
||||||
return wrapWsError(c.conn.WriteBuffer(buffer))
|
return c.conn.WriteBuffer(buffer)
|
||||||
}
|
}
|
||||||
if c.err != nil {
|
if c.err != nil {
|
||||||
return c.err
|
return c.err
|
||||||
@ -274,23 +272,3 @@ func (c *EarlyWebsocketConn) Upstream() any {
|
|||||||
func (c *EarlyWebsocketConn) LazyHeadroom() bool {
|
func (c *EarlyWebsocketConn) LazyHeadroom() bool {
|
||||||
return c.conn == nil
|
return c.conn == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapWsError(err error) error {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var closedErr wsutil.ClosedError
|
|
||||||
if errors.As(err, &closedErr) {
|
|
||||||
if closedErr.Code == ws.StatusNormalClosure {
|
|
||||||
err = io.EOF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func wrapWsError0[T any](value T, err error) (T, error) {
|
|
||||||
if err == nil {
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
return value, wrapWsError(err)
|
|
||||||
}
|
|
||||||
|
22
transport/v2raywebsocket/deadline.go
Normal file
22
transport/v2raywebsocket/deadline.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package v2raywebsocket
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type deadConn struct {
|
||||||
|
net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *deadConn) SetDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *deadConn) SetReadDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *deadConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return nil
|
||||||
|
}
|
@ -66,7 +66,7 @@ func (w *Writer) WriteBuffer(buffer *buf.Buffer) error {
|
|||||||
ws.Cipher(data, *(*[4]byte)(header[1+payloadBitLength:]), 0)
|
ws.Cipher(data, *(*[4]byte)(header[1+payloadBitLength:]), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
return wrapWsError(w.writer.WriteBuffer(buffer))
|
return w.writer.WriteBuffer(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Writer) FrontHeadroom() int {
|
func (w *Writer) FrontHeadroom() int {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user