mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-17 13:23:06 +10:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3768cca36 | ||
|
|
0889ddd001 | ||
|
|
f46fbf188a | ||
|
|
f2d15139f5 | ||
|
|
041646b728 | ||
|
|
b990de2e12 | ||
|
|
fe585157d2 | ||
|
|
eed6a36e5d | ||
|
|
eb0f38544c |
Submodule clients/android updated: 7777469b5d...6f09892c71
Submodule clients/apple updated: c19945f65b...f3b4b2238e
@@ -12,6 +12,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Conn) Read(b []byte) (int, error) {
|
func (c *Conn) Read(b []byte) (int, error) {
|
||||||
@@ -229,7 +230,7 @@ func (c *Conn) readRawRecord() (typ uint8, data []byte, err error) {
|
|||||||
record := c.rawConn.RawInput.Next(recordHeaderLen + n)
|
record := c.rawConn.RawInput.Next(recordHeaderLen + n)
|
||||||
data, typ, err = c.rawConn.In.Decrypt(record)
|
data, typ, err = c.rawConn.In.Decrypt(record)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = c.rawConn.In.SetErrorLocked(c.sendAlert(uint8(err.(tls.AlertError))))
|
err = c.rawConn.In.SetErrorLocked(c.sendAlert(*(*uint8)((*[2]unsafe.Pointer)(unsafe.Pointer(&err))[1])))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ type contextKeyConnecting struct{}
|
|||||||
|
|
||||||
var errRecursiveConnectorDial = E.New("recursive connector dial")
|
var errRecursiveConnectorDial = E.New("recursive connector dial")
|
||||||
|
|
||||||
|
type connectorDialResult[T any] struct {
|
||||||
|
connection T
|
||||||
|
cancel context.CancelFunc
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Connector[T]) Get(ctx context.Context) (T, error) {
|
func (c *Connector[T]) Get(ctx context.Context) (T, error) {
|
||||||
var zero T
|
var zero T
|
||||||
for {
|
for {
|
||||||
@@ -100,41 +106,37 @@ func (c *Connector[T]) Get(ctx context.Context) (T, error) {
|
|||||||
return zero, err
|
return zero, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c.connecting = make(chan struct{})
|
connecting := make(chan struct{})
|
||||||
|
c.connecting = connecting
|
||||||
|
dialContext := context.WithValue(ctx, contextKeyConnecting{}, c)
|
||||||
|
dialResult := make(chan connectorDialResult[T], 1)
|
||||||
c.access.Unlock()
|
c.access.Unlock()
|
||||||
|
|
||||||
dialContext := context.WithValue(ctx, contextKeyConnecting{}, c)
|
go func() {
|
||||||
connection, cancel, err := c.dialWithCancellation(dialContext)
|
connection, cancel, err := c.dialWithCancellation(dialContext)
|
||||||
|
dialResult <- connectorDialResult[T]{
|
||||||
|
connection: connection,
|
||||||
|
cancel: cancel,
|
||||||
|
err: err,
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
c.access.Lock()
|
select {
|
||||||
close(c.connecting)
|
case result := <-dialResult:
|
||||||
c.connecting = nil
|
return c.completeDial(ctx, connecting, result)
|
||||||
|
case <-ctx.Done():
|
||||||
if err != nil {
|
go func() {
|
||||||
c.access.Unlock()
|
result := <-dialResult
|
||||||
return zero, err
|
_, _ = c.completeDial(ctx, connecting, result)
|
||||||
}
|
}()
|
||||||
|
return zero, ctx.Err()
|
||||||
if c.closed {
|
case <-c.closeCtx.Done():
|
||||||
cancel()
|
go func() {
|
||||||
c.callbacks.Close(connection)
|
result := <-dialResult
|
||||||
c.access.Unlock()
|
_, _ = c.completeDial(ctx, connecting, result)
|
||||||
|
}()
|
||||||
return zero, ErrTransportClosed
|
return zero, ErrTransportClosed
|
||||||
}
|
}
|
||||||
if err = ctx.Err(); err != nil {
|
|
||||||
cancel()
|
|
||||||
c.callbacks.Close(connection)
|
|
||||||
c.access.Unlock()
|
|
||||||
return zero, err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.connection = connection
|
|
||||||
c.hasConnection = true
|
|
||||||
c.connectionCancel = cancel
|
|
||||||
result := c.connection
|
|
||||||
c.access.Unlock()
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +145,38 @@ func isRecursiveConnectorDial[T any](ctx context.Context, connector *Connector[T
|
|||||||
return loaded && dialConnector == connector
|
return loaded && dialConnector == connector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Connector[T]) completeDial(ctx context.Context, connecting chan struct{}, result connectorDialResult[T]) (T, error) {
|
||||||
|
var zero T
|
||||||
|
|
||||||
|
c.access.Lock()
|
||||||
|
defer c.access.Unlock()
|
||||||
|
defer func() {
|
||||||
|
if c.connecting == connecting {
|
||||||
|
c.connecting = nil
|
||||||
|
}
|
||||||
|
close(connecting)
|
||||||
|
}()
|
||||||
|
|
||||||
|
if result.err != nil {
|
||||||
|
return zero, result.err
|
||||||
|
}
|
||||||
|
if c.closed || c.closeCtx.Err() != nil {
|
||||||
|
result.cancel()
|
||||||
|
c.callbacks.Close(result.connection)
|
||||||
|
return zero, ErrTransportClosed
|
||||||
|
}
|
||||||
|
if err := ctx.Err(); err != nil {
|
||||||
|
result.cancel()
|
||||||
|
c.callbacks.Close(result.connection)
|
||||||
|
return zero, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.connection = result.connection
|
||||||
|
c.hasConnection = true
|
||||||
|
c.connectionCancel = result.cancel
|
||||||
|
return c.connection, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Connector[T]) dialWithCancellation(ctx context.Context) (T, context.CancelFunc, error) {
|
func (c *Connector[T]) dialWithCancellation(ctx context.Context) (T, context.CancelFunc, error) {
|
||||||
var zero T
|
var zero T
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
|
|||||||
@@ -188,13 +188,157 @@ func TestConnectorCanceledRequestDoesNotCacheConnection(t *testing.T) {
|
|||||||
err := <-result
|
err := <-result
|
||||||
require.ErrorIs(t, err, context.Canceled)
|
require.ErrorIs(t, err, context.Canceled)
|
||||||
require.EqualValues(t, 1, dialCount.Load())
|
require.EqualValues(t, 1, dialCount.Load())
|
||||||
require.EqualValues(t, 1, closeCount.Load())
|
require.Eventually(t, func() bool {
|
||||||
|
return closeCount.Load() == 1
|
||||||
|
}, time.Second, 10*time.Millisecond)
|
||||||
|
|
||||||
_, err = connector.Get(context.Background())
|
_, err = connector.Get(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.EqualValues(t, 2, dialCount.Load())
|
require.EqualValues(t, 2, dialCount.Load())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConnectorCanceledRequestReturnsBeforeIgnoredDialCompletes(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
dialCount atomic.Int32
|
||||||
|
closeCount atomic.Int32
|
||||||
|
)
|
||||||
|
dialStarted := make(chan struct{}, 1)
|
||||||
|
releaseDial := make(chan struct{})
|
||||||
|
|
||||||
|
connector := NewConnector(context.Background(), func(ctx context.Context) (*testConnectorConnection, error) {
|
||||||
|
dialCount.Add(1)
|
||||||
|
select {
|
||||||
|
case dialStarted <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
<-releaseDial
|
||||||
|
return &testConnectorConnection{}, nil
|
||||||
|
}, ConnectorCallbacks[*testConnectorConnection]{
|
||||||
|
IsClosed: func(connection *testConnectorConnection) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
Close: func(connection *testConnectorConnection) {
|
||||||
|
closeCount.Add(1)
|
||||||
|
},
|
||||||
|
Reset: func(connection *testConnectorConnection) {},
|
||||||
|
})
|
||||||
|
|
||||||
|
requestContext, cancel := context.WithCancel(context.Background())
|
||||||
|
result := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
_, err := connector.Get(requestContext)
|
||||||
|
result <- err
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-dialStarted
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-result:
|
||||||
|
require.ErrorIs(t, err, context.Canceled)
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("Get did not return after request cancel")
|
||||||
|
}
|
||||||
|
|
||||||
|
require.EqualValues(t, 1, dialCount.Load())
|
||||||
|
require.EqualValues(t, 0, closeCount.Load())
|
||||||
|
|
||||||
|
close(releaseDial)
|
||||||
|
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
return closeCount.Load() == 1
|
||||||
|
}, time.Second, 10*time.Millisecond)
|
||||||
|
|
||||||
|
_, err := connector.Get(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 2, dialCount.Load())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConnectorWaiterDoesNotStartNewDialBeforeCanceledDialCompletes(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
dialCount atomic.Int32
|
||||||
|
closeCount atomic.Int32
|
||||||
|
)
|
||||||
|
firstDialStarted := make(chan struct{}, 1)
|
||||||
|
secondDialStarted := make(chan struct{}, 1)
|
||||||
|
releaseFirstDial := make(chan struct{})
|
||||||
|
|
||||||
|
connector := NewConnector(context.Background(), func(ctx context.Context) (*testConnectorConnection, error) {
|
||||||
|
attempt := dialCount.Add(1)
|
||||||
|
switch attempt {
|
||||||
|
case 1:
|
||||||
|
select {
|
||||||
|
case firstDialStarted <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
<-releaseFirstDial
|
||||||
|
case 2:
|
||||||
|
select {
|
||||||
|
case secondDialStarted <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &testConnectorConnection{}, nil
|
||||||
|
}, ConnectorCallbacks[*testConnectorConnection]{
|
||||||
|
IsClosed: func(connection *testConnectorConnection) bool {
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
Close: func(connection *testConnectorConnection) {
|
||||||
|
closeCount.Add(1)
|
||||||
|
},
|
||||||
|
Reset: func(connection *testConnectorConnection) {},
|
||||||
|
})
|
||||||
|
|
||||||
|
requestContext, cancel := context.WithCancel(context.Background())
|
||||||
|
firstResult := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
_, err := connector.Get(requestContext)
|
||||||
|
firstResult <- err
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-firstDialStarted
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
secondResult := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
_, err := connector.Get(context.Background())
|
||||||
|
secondResult <- err
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-secondDialStarted:
|
||||||
|
t.Fatal("second dial started before first dial completed")
|
||||||
|
case <-time.After(100 * time.Millisecond):
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case err := <-firstResult:
|
||||||
|
require.ErrorIs(t, err, context.Canceled)
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("first Get did not return after request cancel")
|
||||||
|
}
|
||||||
|
|
||||||
|
close(releaseFirstDial)
|
||||||
|
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
return closeCount.Load() == 1
|
||||||
|
}, time.Second, 10*time.Millisecond)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-secondDialStarted:
|
||||||
|
case <-time.After(time.Second):
|
||||||
|
t.Fatal("second dial did not start after first dial completed")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := <-secondResult
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 2, dialCount.Load())
|
||||||
|
}
|
||||||
|
|
||||||
func TestConnectorDialContextNotCanceledByRequestContextAfterDial(t *testing.T) {
|
func TestConnectorDialContextNotCanceledByRequestContextAfterDial(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,30 @@
|
|||||||
icon: material/alert-decagram
|
icon: material/alert-decagram
|
||||||
---
|
---
|
||||||
|
|
||||||
|
#### 1.13.3
|
||||||
|
|
||||||
|
* Add OpenWrt and Alpine APK packages to release **1**
|
||||||
|
* Backport to macOS 10.13 High Sierra **2**
|
||||||
|
* OCM service: Add WebSocket support for Responses API **3**
|
||||||
|
* Fixes and improvements
|
||||||
|
|
||||||
|
**1**:
|
||||||
|
|
||||||
|
Alpine APK files use `linux` in the filename to distinguish from OpenWrt APKs which use the `openwrt` prefix:
|
||||||
|
|
||||||
|
- OpenWrt: `sing-box_{version}_openwrt_{architecture}.apk`
|
||||||
|
- Alpine: `sing-box_{version}_linux_{architecture}.apk`
|
||||||
|
|
||||||
|
**2**:
|
||||||
|
|
||||||
|
Legacy macOS binaries (with `-legacy-macos-10.13` suffix) now support
|
||||||
|
macOS 10.13 High Sierra, built using Go 1.25 with patches
|
||||||
|
from [SagerNet/go](https://github.com/SagerNet/go).
|
||||||
|
|
||||||
|
**3**:
|
||||||
|
|
||||||
|
See [OCM](/configuration/service/ocm).
|
||||||
|
|
||||||
#### 1.13.2
|
#### 1.13.2
|
||||||
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ icon: material/alert-decagram
|
|||||||
!!! warning "与官方 Hysteria2 的区别"
|
!!! warning "与官方 Hysteria2 的区别"
|
||||||
|
|
||||||
官方程序支持一种名为 **userpass** 的验证方式,
|
官方程序支持一种名为 **userpass** 的验证方式,
|
||||||
本质上上是将用户名与密码的组合 `<username>:<password>` 作为实际上的密码,而 sing-box 不提供此别名。
|
本质上是将用户名与密码的组合 `<username>:<password>` 作为实际上的密码,而 sing-box 不提供此别名。
|
||||||
要将 sing-box 与官方程序一起使用, 您需要填写该组合作为实际密码。
|
要将 sing-box 与官方程序一起使用, 您需要填写该组合作为实际密码。
|
||||||
|
|
||||||
### 监听字段
|
### 监听字段
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
icon: material/new-box
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
|
!!! quote "Changes in sing-box 1.13.3"
|
||||||
|
|
||||||
|
:material-alert: [strict_route](#strict_route)
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.13.0"
|
!!! quote "Changes in sing-box 1.13.0"
|
||||||
|
|
||||||
:material-plus: [auto_redirect_reset_mark](#auto_redirect_reset_mark)
|
:material-plus: [auto_redirect_reset_mark](#auto_redirect_reset_mark)
|
||||||
@@ -348,6 +352,9 @@ Enforce strict routing rules when `auto_route` is enabled:
|
|||||||
|
|
||||||
* Let unsupported network unreachable
|
* Let unsupported network unreachable
|
||||||
* For legacy reasons, when neither `strict_route` nor `auto_redirect` are enabled, all ICMP traffic will not go through TUN.
|
* For legacy reasons, when neither `strict_route` nor `auto_redirect` are enabled, all ICMP traffic will not go through TUN.
|
||||||
|
* When `auto_redirect` is enabled, `strict_route` also affects `SO_BINDTODEVICE` traffic:
|
||||||
|
* Enabled: `SO_BINDTODEVICE` traffic is redirected through sing-box.
|
||||||
|
* Disabled: `SO_BINDTODEVICE` traffic bypasses sing-box.
|
||||||
|
|
||||||
*In Windows*:
|
*In Windows*:
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
icon: material/new-box
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.13.3 中的更改"
|
||||||
|
|
||||||
|
:material-alert: [strict_route](#strict_route)
|
||||||
|
|
||||||
!!! quote "sing-box 1.13.0 中的更改"
|
!!! quote "sing-box 1.13.0 中的更改"
|
||||||
|
|
||||||
:material-plus: [auto_redirect_reset_mark](#auto_redirect_reset_mark)
|
:material-plus: [auto_redirect_reset_mark](#auto_redirect_reset_mark)
|
||||||
@@ -347,6 +351,9 @@ tun 接口的 IPv6 前缀。
|
|||||||
|
|
||||||
* 使不支持的网络不可达。
|
* 使不支持的网络不可达。
|
||||||
* 出于历史遗留原因,当未启用 `strict_route` 或 `auto_redirect` 时,所有 ICMP 流量将不会通过 TUN。
|
* 出于历史遗留原因,当未启用 `strict_route` 或 `auto_redirect` 时,所有 ICMP 流量将不会通过 TUN。
|
||||||
|
* 当启用 `auto_redirect` 时,`strict_route` 也影响 `SO_BINDTODEVICE` 流量:
|
||||||
|
* 启用:`SO_BINDTODEVICE` 流量被重定向通过 sing-box。
|
||||||
|
* 禁用:`SO_BINDTODEVICE` 流量绕过 sing-box。
|
||||||
|
|
||||||
*在 Windows 中*:
|
*在 Windows 中*:
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
!!! warning "与官方 Hysteria2 的区别"
|
!!! warning "与官方 Hysteria2 的区别"
|
||||||
|
|
||||||
官方程序支持一种名为 **userpass** 的验证方式,
|
官方程序支持一种名为 **userpass** 的验证方式,
|
||||||
本质上上是将用户名与密码的组合 `<username>:<password>` 作为实际上的密码,而 sing-box 不提供此别名。
|
本质上是将用户名与密码的组合 `<username>:<password>` 作为实际上的密码,而 sing-box 不提供此别名。
|
||||||
要将 sing-box 与官方程序一起使用, 您需要填写该组合作为实际密码。
|
要将 sing-box 与官方程序一起使用, 您需要填写该组合作为实际密码。
|
||||||
|
|
||||||
### 字段
|
### 字段
|
||||||
|
|||||||
4
go.mod
4
go.mod
@@ -39,10 +39,10 @@ require (
|
|||||||
github.com/sagernet/sing-shadowsocks v0.2.8
|
github.com/sagernet/sing-shadowsocks v0.2.8
|
||||||
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.8.2
|
github.com/sagernet/sing-tun v0.8.3
|
||||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1
|
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1
|
||||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1
|
github.com/sagernet/smux v1.5.50-sing-box-mod.1
|
||||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6.0.20260310162543-0c2de366d4de
|
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6.0.20260311131347-f88b27eeb76e
|
||||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c
|
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -248,14 +248,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-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.8.2 h1:rQr/x3eQCHh3oleIaoJdPdJwqzZp4+QWcJLT0Wz2xKY=
|
github.com/sagernet/sing-tun v0.8.3 h1:mozxmuIoRhFdVHnheenLpBaammVj7bZPcnkApaYKDPY=
|
||||||
github.com/sagernet/sing-tun v0.8.2/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs=
|
github.com/sagernet/sing-tun v0.8.3/go.mod h1:pLCo4o+LacXEzz0bhwhJkKBjLlKOGPBNOAZ97ZVZWzs=
|
||||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
|
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1 h1:aSwUNYUkVyVvdmBSufR8/nRFonwJeKSIROxHcm5br9o=
|
||||||
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
|
github.com/sagernet/sing-vmess v0.2.8-0.20250909125414-3aed155119a1/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
|
||||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
|
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
|
||||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
|
github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
|
||||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6.0.20260310162543-0c2de366d4de h1:wsJ0COxUOIvBE+hUho0C/DbMeUe9jtwfh6dECAiTk94=
|
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6.0.20260311131347-f88b27eeb76e h1:Sv1qUhJIidjSTc24XEknovDZnbmVSlAXj8wNVgIfgGo=
|
||||||
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6.0.20260310162543-0c2de366d4de/go.mod h1:m87GAn4UcesHQF3leaPFEINZETO5za1LGn1GJdNDgNc=
|
github.com/sagernet/tailscale v1.92.4-sing-box-1.13-mod.6.0.20260311131347-f88b27eeb76e/go.mod h1:m87GAn4UcesHQF3leaPFEINZETO5za1LGn1GJdNDgNc=
|
||||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c h1:f9cXNB+IOOPnR8DOLMTpr42jf7naxh5Un5Y09BBf5Cg=
|
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c h1:f9cXNB+IOOPnR8DOLMTpr42jf7naxh5Un5Y09BBf5Cg=
|
||||||
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
|
github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20260224074747-506b7631853c/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0=
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||||
|
|||||||
@@ -333,9 +333,6 @@ func (t *Endpoint) Start(stage adapter.StartStage) error {
|
|||||||
t.systemTun = systemTun
|
t.systemTun = systemTun
|
||||||
t.systemDialer = systemDialer
|
t.systemDialer = systemDialer
|
||||||
t.server.TunDevice = wgTunDevice
|
t.server.TunDevice = wgTunDevice
|
||||||
t.server.RouterWrapper = func(inner router.Router) router.Router {
|
|
||||||
return &addressOnlyRouter{Router: inner}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if mark := t.network.AutoRedirectOutputMark(); mark > 0 {
|
if mark := t.network.AutoRedirectOutputMark(); mark > 0 {
|
||||||
controlFunc := t.network.AutoRedirectOutputMarkFunc()
|
controlFunc := t.network.AutoRedirectOutputMarkFunc()
|
||||||
@@ -480,11 +477,12 @@ func (t *Endpoint) Close() error {
|
|||||||
t.fallbackTCPCloser()
|
t.fallbackTCPCloser()
|
||||||
t.fallbackTCPCloser = nil
|
t.fallbackTCPCloser = nil
|
||||||
}
|
}
|
||||||
|
err := common.Close(common.PtrOrNil(t.server))
|
||||||
if t.systemTun != nil {
|
if t.systemTun != nil {
|
||||||
_ = t.systemTun.Close()
|
t.systemTun.Close()
|
||||||
t.systemTun = nil
|
t.systemTun = nil
|
||||||
}
|
}
|
||||||
return common.Close(common.PtrOrNil(t.server))
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Endpoint) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
func (t *Endpoint) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||||
@@ -849,16 +847,3 @@ func (c *dnsConfigurtor) GetBaseConfig() (tsDNS.OSConfig, error) {
|
|||||||
func (c *dnsConfigurtor) Close() error {
|
func (c *dnsConfigurtor) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type addressOnlyRouter struct {
|
|
||||||
router.Router
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *addressOnlyRouter) Set(config *router.Config) error {
|
|
||||||
if config != nil {
|
|
||||||
config = &router.Config{
|
|
||||||
LocalAddrs: config.LocalAddrs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r.Router.Set(config)
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user