mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
Compare commits
72 Commits
1c36072120
...
f6cea5cc1e
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f6cea5cc1e | ||
![]() |
f6cd6b52d1 | ||
![]() |
f393b1fd3f | ||
![]() |
64c8d8ffda | ||
![]() |
afa31b7e60 | ||
![]() |
f9e8299c0e | ||
![]() |
c83d8acd8b | ||
![]() |
5f8c55b011 | ||
![]() |
d5838a1d8f | ||
![]() |
761598885d | ||
![]() |
b4f126ed7d | ||
![]() |
6388c2e213 | ||
![]() |
c7d76c1a2f | ||
![]() |
86362ed8fd | ||
![]() |
63980c491f | ||
![]() |
772f43633b | ||
![]() |
dc6ffbfb45 | ||
![]() |
e8e5aa25ba | ||
![]() |
8d0a758cac | ||
![]() |
eb30c72ecd | ||
![]() |
1a836e2658 | ||
![]() |
057ecd243c | ||
![]() |
6504309d1a | ||
![]() |
ad03f8a294 | ||
![]() |
62418e8562 | ||
![]() |
6daafc3f34 | ||
![]() |
be27a43c02 | ||
![]() |
1db007c4ae | ||
![]() |
2c5e277a49 | ||
![]() |
a048092b1d | ||
![]() |
7216d7c7de | ||
![]() |
38d79fa3f9 | ||
![]() |
d3bb8c5971 | ||
![]() |
d81fdd8401 | ||
![]() |
f292280ff5 | ||
![]() |
452ca55091 | ||
![]() |
866b726b77 | ||
![]() |
29ecb715e9 | ||
![]() |
cf1c7c3138 | ||
![]() |
c14a04f6cf | ||
![]() |
e5d9f40e78 | ||
![]() |
c81cb83d22 | ||
![]() |
c22ea80cb2 | ||
![]() |
825a9cd726 | ||
![]() |
7c3263688f | ||
![]() |
22185ffd5b | ||
![]() |
d53dae1793 | ||
![]() |
a36bd4c25d | ||
![]() |
e93033914b | ||
![]() |
17cd4efc8d | ||
![]() |
2ddc11918c | ||
![]() |
6e4d92b9dd | ||
![]() |
a1e6f4ee55 | ||
![]() |
7040d8de98 | ||
![]() |
d004f3c5d4 | ||
![]() |
79c8141422 | ||
![]() |
1295212910 | ||
![]() |
324b437e74 | ||
![]() |
6071b5690c | ||
![]() |
5bb58c49e2 | ||
![]() |
c10ef770da | ||
![]() |
6d410cc676 | ||
![]() |
097d2984ef | ||
![]() |
4cb528c747 | ||
![]() |
52561dba46 | ||
![]() |
686e21035c | ||
![]() |
a66454f45f | ||
![]() |
8689358c63 | ||
![]() |
942a45da98 | ||
![]() |
5f1b064234 | ||
![]() |
eb7caa2d5e | ||
![]() |
99c5fde40d |
@ -74,7 +74,6 @@ type InboundContext struct {
|
|||||||
UDPTimeout time.Duration
|
UDPTimeout time.Duration
|
||||||
TLSFragment bool
|
TLSFragment bool
|
||||||
TLSFragmentFallbackDelay time.Duration
|
TLSFragmentFallbackDelay time.Duration
|
||||||
TLSRecordFragment bool
|
|
||||||
|
|
||||||
NetworkStrategy *C.NetworkStrategy
|
NetworkStrategy *C.NetworkStrategy
|
||||||
NetworkType []C.InterfaceType
|
NetworkType []C.InterfaceType
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
package tf
|
package tf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
@ -19,19 +17,17 @@ type Conn struct {
|
|||||||
tcpConn *net.TCPConn
|
tcpConn *net.TCPConn
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
firstPacketWritten bool
|
firstPacketWritten bool
|
||||||
splitRecord bool
|
|
||||||
fallbackDelay time.Duration
|
fallbackDelay time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConn(conn net.Conn, ctx context.Context, splitRecord bool, fallbackDelay time.Duration) *Conn {
|
func NewConn(conn net.Conn, ctx context.Context, fallbackDelay time.Duration) (*Conn, error) {
|
||||||
tcpConn, _ := N.UnwrapReader(conn).(*net.TCPConn)
|
tcpConn, _ := N.UnwrapReader(conn).(*net.TCPConn)
|
||||||
return &Conn{
|
return &Conn{
|
||||||
Conn: conn,
|
Conn: conn,
|
||||||
tcpConn: tcpConn,
|
tcpConn: tcpConn,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
splitRecord: splitRecord,
|
|
||||||
fallbackDelay: fallbackDelay,
|
fallbackDelay: fallbackDelay,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) Write(b []byte) (n int, err error) {
|
func (c *Conn) Write(b []byte) (n int, err error) {
|
||||||
@ -41,14 +37,12 @@ func (c *Conn) Write(b []byte) (n int, err error) {
|
|||||||
}()
|
}()
|
||||||
serverName := indexTLSServerName(b)
|
serverName := indexTLSServerName(b)
|
||||||
if serverName != nil {
|
if serverName != nil {
|
||||||
if !c.splitRecord {
|
|
||||||
if c.tcpConn != nil {
|
if c.tcpConn != nil {
|
||||||
err = c.tcpConn.SetNoDelay(true)
|
err = c.tcpConn.SetNoDelay(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
splits := strings.Split(serverName.ServerName, ".")
|
splits := strings.Split(serverName.ServerName, ".")
|
||||||
currentIndex := serverName.Index
|
currentIndex := serverName.Index
|
||||||
if publicSuffix := publicsuffix.List.PublicSuffix(serverName.ServerName); publicSuffix != "" {
|
if publicSuffix := publicsuffix.List.PublicSuffix(serverName.ServerName); publicSuffix != "" {
|
||||||
@ -67,25 +61,16 @@ func (c *Conn) Write(b []byte) (n int, err error) {
|
|||||||
currentIndex++
|
currentIndex++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var buffer bytes.Buffer
|
|
||||||
for i := 0; i <= len(splitIndexes); i++ {
|
for i := 0; i <= len(splitIndexes); i++ {
|
||||||
var payload []byte
|
var payload []byte
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
payload = b[:splitIndexes[i]]
|
payload = b[:splitIndexes[i]]
|
||||||
if c.splitRecord {
|
|
||||||
payload = payload[recordLayerHeaderLen:]
|
|
||||||
}
|
|
||||||
} else if i == len(splitIndexes) {
|
} else if i == len(splitIndexes) {
|
||||||
payload = b[splitIndexes[i-1]:]
|
payload = b[splitIndexes[i-1]:]
|
||||||
} else {
|
} else {
|
||||||
payload = b[splitIndexes[i-1]:splitIndexes[i]]
|
payload = b[splitIndexes[i-1]:splitIndexes[i]]
|
||||||
}
|
}
|
||||||
if c.splitRecord {
|
if c.tcpConn != nil && i != len(splitIndexes) {
|
||||||
payloadLen := uint16(len(payload))
|
|
||||||
buffer.Write(b[:3])
|
|
||||||
binary.Write(&buffer, binary.BigEndian, payloadLen)
|
|
||||||
buffer.Write(payload)
|
|
||||||
} else if c.tcpConn != nil && i != len(splitIndexes) {
|
|
||||||
err = writeAndWaitAck(c.ctx, c.tcpConn, payload, c.fallbackDelay)
|
err = writeAndWaitAck(c.ctx, c.tcpConn, payload, c.fallbackDelay)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -97,19 +82,12 @@ func (c *Conn) Write(b []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if c.splitRecord {
|
|
||||||
_, err = c.tcpConn.Write(buffer.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if c.tcpConn != nil {
|
if c.tcpConn != nil {
|
||||||
err = c.tcpConn.SetNoDelay(false)
|
err = c.tcpConn.SetNoDelay(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return len(b), nil
|
return len(b), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package tf_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"net"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
tf "github.com/sagernet/sing-box/common/tlsfragment"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTLSFragment(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
tcpConn, err := net.Dial("tcp", "1.1.1.1:443")
|
|
||||||
require.NoError(t, err)
|
|
||||||
tlsConn := tls.Client(tf.NewConn(tcpConn, context.Background(), false, 0), &tls.Config{
|
|
||||||
ServerName: "www.cloudflare.com",
|
|
||||||
})
|
|
||||||
require.NoError(t, tlsConn.Handshake())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTLSRecordFragment(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
tcpConn, err := net.Dial("tcp", "1.1.1.1:443")
|
|
||||||
require.NoError(t, err)
|
|
||||||
tlsConn := tls.Client(tf.NewConn(tcpConn, context.Background(), true, 0), &tls.Config{
|
|
||||||
ServerName: "www.cloudflare.com",
|
|
||||||
})
|
|
||||||
require.NoError(t, tlsConn.Handshake())
|
|
||||||
}
|
|
@ -2,20 +2,10 @@
|
|||||||
icon: material/alert-decagram
|
icon: material/alert-decagram
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 1.12.0-beta.13
|
#### 1.12.0-beta.12
|
||||||
|
|
||||||
* Add TLS record fragment route options **1**
|
|
||||||
* Add missing `accept_routes` option for Tailscale **2**
|
|
||||||
* Fixes and improvements
|
* Fixes and improvements
|
||||||
|
|
||||||
**1**:
|
|
||||||
|
|
||||||
See [Route Action](/configuration/route/rule_action/#tls_record_fragment).
|
|
||||||
|
|
||||||
**2**:
|
|
||||||
|
|
||||||
See [Tailscale](/configuration/endpoint/tailscale/#accept_routes).
|
|
||||||
|
|
||||||
#### 1.12.0-beta.10
|
#### 1.12.0-beta.10
|
||||||
|
|
||||||
* Add control options for listeners **1**
|
* Add control options for listeners **1**
|
||||||
|
@ -15,7 +15,6 @@ icon: material/new-box
|
|||||||
"control_url": "",
|
"control_url": "",
|
||||||
"ephemeral": false,
|
"ephemeral": false,
|
||||||
"hostname": "",
|
"hostname": "",
|
||||||
"accept_routes": false,
|
|
||||||
"exit_node": "",
|
"exit_node": "",
|
||||||
"exit_node_allow_lan_access": false,
|
"exit_node_allow_lan_access": false,
|
||||||
"advertise_routes": [],
|
"advertise_routes": [],
|
||||||
@ -63,10 +62,6 @@ System hostname is used by default.
|
|||||||
|
|
||||||
Example: `localhost`
|
Example: `localhost`
|
||||||
|
|
||||||
#### accept_routes
|
|
||||||
|
|
||||||
Indicates whether the node should accept routes advertised by other nodes.
|
|
||||||
|
|
||||||
#### exit_node
|
#### exit_node
|
||||||
|
|
||||||
The exit node name or IP address to use.
|
The exit node name or IP address to use.
|
||||||
|
@ -6,7 +6,6 @@ icon: material/new-box
|
|||||||
|
|
||||||
:material-plus: [tls_fragment](#tls_fragment)
|
:material-plus: [tls_fragment](#tls_fragment)
|
||||||
:material-plus: [tls_fragment_fallback_delay](#tls_fragment_fallback_delay)
|
:material-plus: [tls_fragment_fallback_delay](#tls_fragment_fallback_delay)
|
||||||
:material-plus: [tls_record_fragment](#tls_record_fragment)
|
|
||||||
:material-plus: [resolve.disable_cache](#disable_cache)
|
:material-plus: [resolve.disable_cache](#disable_cache)
|
||||||
:material-plus: [resolve.rewrite_ttl](#rewrite_ttl)
|
:material-plus: [resolve.rewrite_ttl](#rewrite_ttl)
|
||||||
:material-plus: [resolve.client_subnet](#client_subnet)
|
:material-plus: [resolve.client_subnet](#client_subnet)
|
||||||
@ -92,8 +91,7 @@ Not available when `method` is set to drop.
|
|||||||
"udp_connect": false,
|
"udp_connect": false,
|
||||||
"udp_timeout": "",
|
"udp_timeout": "",
|
||||||
"tls_fragment": false,
|
"tls_fragment": false,
|
||||||
"tls_fragment_fallback_delay": "",
|
"tls_fragment_fallback_delay": ""
|
||||||
"tls_record_fragment": ""
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -166,19 +164,13 @@ If no protocol is sniffed, the following ports will be recognized as protocols b
|
|||||||
|
|
||||||
Fragment TLS handshakes to bypass firewalls.
|
Fragment TLS handshakes to bypass firewalls.
|
||||||
|
|
||||||
This feature is intended to circumvent simple firewalls based on **plaintext packet matching**,
|
This feature is intended to circumvent simple firewalls based on **plaintext packet matching**, and should not be used to circumvent real censorship.
|
||||||
and should not be used to circumvent real censorship.
|
|
||||||
|
|
||||||
Due to poor performance, try `tls_record_fragment` first, and only apply to server names known to be blocked.
|
Since it is not designed for performance, it should not be applied to all connections, but only to server names that are known to be blocked.
|
||||||
|
|
||||||
On Linux, Apple platforms, (administrator privileges required) Windows,
|
On Linux, Apple platforms, (administrator privileges required) Windows, the wait time can be automatically detected, otherwise it will fall back to waiting for a fixed time specified by `tls_fragment_fallback_delay`.
|
||||||
the wait time can be automatically detected, otherwise it will fall back to
|
|
||||||
waiting for a fixed time specified by `tls_fragment_fallback_delay`.
|
|
||||||
|
|
||||||
In addition, if the actual wait time is less than 20ms, it will also fall back to waiting for a fixed time,
|
In addition, if the actual wait time is less than 20ms, it will also fall back to waiting for a fixed time, because the target is considered to be local or behind a transparent proxy.
|
||||||
because the target is considered to be local or behind a transparent proxy.
|
|
||||||
|
|
||||||
Conflict with `tls_record_fragment`.
|
|
||||||
|
|
||||||
#### tls_fragment_fallback_delay
|
#### tls_fragment_fallback_delay
|
||||||
|
|
||||||
@ -188,17 +180,6 @@ The fallback value used when TLS segmentation cannot automatically determine the
|
|||||||
|
|
||||||
`500ms` is used by default.
|
`500ms` is used by default.
|
||||||
|
|
||||||
#### tls_record_fragment
|
|
||||||
|
|
||||||
!!! question "Since sing-box 1.12.0"
|
|
||||||
|
|
||||||
Fragment TLS handshake into multiple TLS records to bypass firewalls.
|
|
||||||
|
|
||||||
This feature is intended to circumvent simple firewalls based on **plaintext packet matching**,
|
|
||||||
and should not be used to circumvent real censorship.
|
|
||||||
|
|
||||||
Conflict with `tls_fragment`.
|
|
||||||
|
|
||||||
### sniff
|
### sniff
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
@ -6,10 +6,6 @@ icon: material/new-box
|
|||||||
|
|
||||||
:material-plus: [tls_fragment](#tls_fragment)
|
:material-plus: [tls_fragment](#tls_fragment)
|
||||||
:material-plus: [tls_fragment_fallback_delay](#tls_fragment_fallback_delay)
|
:material-plus: [tls_fragment_fallback_delay](#tls_fragment_fallback_delay)
|
||||||
:material-plus: [tls_record_fragment](#tls_record_fragment)
|
|
||||||
:material-plus: [resolve.disable_cache](#disable_cache)
|
|
||||||
:material-plus: [resolve.rewrite_ttl](#rewrite_ttl)
|
|
||||||
:material-plus: [resolve.client_subnet](#client_subnet)
|
|
||||||
|
|
||||||
## 最终动作
|
## 最终动作
|
||||||
|
|
||||||
@ -163,15 +159,12 @@ UDP 连接超时时间。
|
|||||||
|
|
||||||
此功能旨在规避基于**明文数据包匹配**的简单防火墙,不应该用于规避真的审查。
|
此功能旨在规避基于**明文数据包匹配**的简单防火墙,不应该用于规避真的审查。
|
||||||
|
|
||||||
由于性能不佳,请首先尝试 `tls_record_fragment`,且仅应用于已知被阻止的服务器名称。
|
由于它不是为性能设计的,不应被应用于所有连接,而仅应用于已知被阻止的服务器名称。
|
||||||
|
|
||||||
在 Linux、Apple 平台和需要管理员权限的 Windows 系统上,可自动检测等待时间。
|
在 Linux、Apple 平台和需要管理员权限的 Windows 系统上,可自动检测等待时间。若无法自动检测,将回退使用 `tls_fragment_fallback_delay` 指定的固定等待时间。
|
||||||
若无法自动检测,将回退使用 `tls_fragment_fallback_delay` 指定的固定等待时间。
|
|
||||||
|
|
||||||
此外,若实际等待时间小于 20 毫秒,同样会回退至固定等待时间模式,因为此时判定目标处于本地或透明代理之后。
|
此外,若实际等待时间小于 20 毫秒,同样会回退至固定等待时间模式,因为此时判定目标处于本地或透明代理之后。
|
||||||
|
|
||||||
与 `tls_record_fragment` 冲突。
|
|
||||||
|
|
||||||
#### tls_fragment_fallback_delay
|
#### tls_fragment_fallback_delay
|
||||||
|
|
||||||
!!! question "自 sing-box 1.12.0 起"
|
!!! question "自 sing-box 1.12.0 起"
|
||||||
@ -180,16 +173,6 @@ UDP 连接超时时间。
|
|||||||
|
|
||||||
默认使用 `500ms`。
|
默认使用 `500ms`。
|
||||||
|
|
||||||
#### tls_record_fragment
|
|
||||||
|
|
||||||
!!! question "自 sing-box 1.12.0 起"
|
|
||||||
|
|
||||||
通过分段 TLS 握手数据包到多个 TLS 记录来绕过防火墙检测。
|
|
||||||
|
|
||||||
此功能旨在规避基于**明文数据包匹配**的简单防火墙,不应该用于规避真的审查。
|
|
||||||
|
|
||||||
与 `tls_fragment` 冲突。
|
|
||||||
|
|
||||||
### sniff
|
### sniff
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
5
go.mod
5
go.mod
@ -28,15 +28,14 @@ require (
|
|||||||
github.com/sagernet/quic-go v0.51.0-beta.5
|
github.com/sagernet/quic-go v0.51.0-beta.5
|
||||||
github.com/sagernet/sing v0.6.10-0.20250505040842-ba62fee9470f
|
github.com/sagernet/sing v0.6.10-0.20250505040842-ba62fee9470f
|
||||||
github.com/sagernet/sing-mux v0.3.2
|
github.com/sagernet/sing-mux v0.3.2
|
||||||
github.com/sagernet/sing-quic v0.4.1-0.20250511050139-d459f561c9c3
|
github.com/sagernet/sing-quic v0.4.1-0.20250507070325-d2fb1cb09565
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7
|
github.com/sagernet/sing-shadowsocks v0.2.7
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||||
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.2-0.20250503051933-9b4cf17393f8
|
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.4
|
||||||
github.com/sagernet/utls v1.6.7
|
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.7
|
github.com/sagernet/wireguard-go v0.0.1-beta.7
|
||||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||||
github.com/spf13/cobra v1.9.1
|
github.com/spf13/cobra v1.9.1
|
||||||
|
10
go.sum
10
go.sum
@ -172,8 +172,8 @@ github.com/sagernet/sing v0.6.10-0.20250505040842-ba62fee9470f h1:lttLhNtFuMItQc
|
|||||||
github.com/sagernet/sing v0.6.10-0.20250505040842-ba62fee9470f/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.6.10-0.20250505040842-ba62fee9470f/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.4.1-0.20250511050139-d459f561c9c3 h1:1J+s1yyZ8+YAYaClI+az8YuFgV9NGXUUCZnriKmos6w=
|
github.com/sagernet/sing-quic v0.4.1-0.20250507070325-d2fb1cb09565 h1:svvkxc3NtONBrvB2rrNVmFmFYoBv+jORDOFX6tvFDjY=
|
||||||
github.com/sagernet/sing-quic v0.4.1-0.20250511050139-d459f561c9c3/go.mod h1:Mv7CdSyLepmqoLT8rd88Qn3QMv5AbsgjEm3DvEhDVNE=
|
github.com/sagernet/sing-quic v0.4.1-0.20250507070325-d2fb1cb09565/go.mod h1:6K3ESuaXFTjz2Dv6/PNQqg5UK0J1ZO49rqrU2ScZBKg=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE=
|
||||||
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wKFHi+8XwgADg=
|
||||||
@ -186,10 +186,8 @@ github.com/sagernet/sing-vmess v0.2.2-0.20250503051933-9b4cf17393f8 h1:zW+zAOCxU
|
|||||||
github.com/sagernet/sing-vmess v0.2.2-0.20250503051933-9b4cf17393f8/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.4.0.20250512093633-e1bc1888c814 h1:B6ejgOuM1BrX4TzWvm1h/LQAOZW1T1jP4PSZe8b/49o=
|
github.com/sagernet/tailscale v1.80.3-mod.4 h1:9UgYq8m9mwX5dbTbueVxbRh+bq7AayxemJGM2PkJQnE=
|
||||||
github.com/sagernet/tailscale v1.80.3-mod.4.0.20250512093633-e1bc1888c814/go.mod h1:EBxXsWu4OH2ELbQLq32WoBeIubG8KgDrg4/Oaxjs6lI=
|
github.com/sagernet/tailscale v1.80.3-mod.4/go.mod h1:EBxXsWu4OH2ELbQLq32WoBeIubG8KgDrg4/Oaxjs6lI=
|
||||||
github.com/sagernet/tailscale v1.80.3-mod.5 h1:7V7z+p2C//TGtff20pPnDCt3qP6uFyY62peJoKF9z/A=
|
|
||||||
github.com/sagernet/tailscale v1.80.3-mod.5/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 h1:ltgBwYHfr+9Wz1eG59NiWnHrYEkDKHG7otNZvu85DXI=
|
||||||
github.com/sagernet/wireguard-go v0.0.1-beta.7/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo=
|
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=
|
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||||
|
@ -158,7 +158,6 @@ type RawRouteOptionsActionOptions struct {
|
|||||||
|
|
||||||
TLSFragment bool `json:"tls_fragment,omitempty"`
|
TLSFragment bool `json:"tls_fragment,omitempty"`
|
||||||
TLSFragmentFallbackDelay badoption.Duration `json:"tls_fragment_fallback_delay,omitempty"`
|
TLSFragmentFallbackDelay badoption.Duration `json:"tls_fragment_fallback_delay,omitempty"`
|
||||||
TLSRecordFragment bool `json:"tls_record_fragment,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RouteOptionsActionOptions RawRouteOptionsActionOptions
|
type RouteOptionsActionOptions RawRouteOptionsActionOptions
|
||||||
@ -171,9 +170,6 @@ func (r *RouteOptionsActionOptions) UnmarshalJSON(data []byte) error {
|
|||||||
if *r == (RouteOptionsActionOptions{}) {
|
if *r == (RouteOptionsActionOptions{}) {
|
||||||
return E.New("empty route option action")
|
return E.New("empty route option action")
|
||||||
}
|
}
|
||||||
if r.TLSFragment && r.TLSRecordFragment {
|
|
||||||
return E.New("`tls_fragment` and `tls_record_fragment` are mutually exclusive")
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ type TailscaleEndpointOptions struct {
|
|||||||
ControlURL string `json:"control_url,omitempty"`
|
ControlURL string `json:"control_url,omitempty"`
|
||||||
Ephemeral bool `json:"ephemeral,omitempty"`
|
Ephemeral bool `json:"ephemeral,omitempty"`
|
||||||
Hostname string `json:"hostname,omitempty"`
|
Hostname string `json:"hostname,omitempty"`
|
||||||
AcceptRoutes bool `json:"accept_routes,omitempty"`
|
|
||||||
ExitNode string `json:"exit_node,omitempty"`
|
ExitNode string `json:"exit_node,omitempty"`
|
||||||
ExitNodeAllowLANAccess bool `json:"exit_node_allow_lan_access,omitempty"`
|
ExitNodeAllowLANAccess bool `json:"exit_node_allow_lan_access,omitempty"`
|
||||||
AdvertiseRoutes []netip.Prefix `json:"advertise_routes,omitempty"`
|
AdvertiseRoutes []netip.Prefix `json:"advertise_routes,omitempty"`
|
||||||
|
@ -72,7 +72,6 @@ type Endpoint struct {
|
|||||||
filter *atomic.Pointer[filter.Filter]
|
filter *atomic.Pointer[filter.Filter]
|
||||||
onReconfig wgengine.ReconfigListener
|
onReconfig wgengine.ReconfigListener
|
||||||
|
|
||||||
acceptRoutes bool
|
|
||||||
exitNode string
|
exitNode string
|
||||||
exitNodeAllowLANAccess bool
|
exitNodeAllowLANAccess bool
|
||||||
advertiseRoutes []netip.Prefix
|
advertiseRoutes []netip.Prefix
|
||||||
@ -171,7 +170,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
|||||||
network: service.FromContext[adapter.NetworkManager](ctx),
|
network: service.FromContext[adapter.NetworkManager](ctx),
|
||||||
platformInterface: service.FromContext[platform.Interface](ctx),
|
platformInterface: service.FromContext[platform.Interface](ctx),
|
||||||
server: server,
|
server: server,
|
||||||
acceptRoutes: options.AcceptRoutes,
|
|
||||||
exitNode: options.ExitNode,
|
exitNode: options.ExitNode,
|
||||||
exitNodeAllowLANAccess: options.ExitNodeAllowLANAccess,
|
exitNodeAllowLANAccess: options.ExitNodeAllowLANAccess,
|
||||||
advertiseRoutes: options.AdvertiseRoutes,
|
advertiseRoutes: options.AdvertiseRoutes,
|
||||||
@ -228,10 +226,6 @@ func (t *Endpoint) Start(stage adapter.StartStage) error {
|
|||||||
|
|
||||||
localBackend := t.server.ExportLocalBackend()
|
localBackend := t.server.ExportLocalBackend()
|
||||||
perfs := &ipn.MaskedPrefs{
|
perfs := &ipn.MaskedPrefs{
|
||||||
Prefs: ipn.Prefs{
|
|
||||||
RouteAll: t.acceptRoutes,
|
|
||||||
},
|
|
||||||
RouteAllSet: true,
|
|
||||||
ExitNodeIPSet: true,
|
ExitNodeIPSet: true,
|
||||||
AdvertiseRoutesSet: true,
|
AdvertiseRoutesSet: true,
|
||||||
}
|
}
|
||||||
|
@ -95,9 +95,15 @@ func (m *ConnectionManager) NewConnection(ctx context.Context, this N.Dialer, co
|
|||||||
if fallbackDelay == 0 {
|
if fallbackDelay == 0 {
|
||||||
fallbackDelay = C.TLSFragmentFallbackDelay
|
fallbackDelay = C.TLSFragmentFallbackDelay
|
||||||
}
|
}
|
||||||
remoteConn = tf.NewConn(remoteConn, ctx, false, fallbackDelay)
|
var newConn *tf.Conn
|
||||||
} else if metadata.TLSRecordFragment {
|
newConn, err = tf.NewConn(remoteConn, ctx, fallbackDelay)
|
||||||
remoteConn = tf.NewConn(remoteConn, ctx, true, 0)
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
|
remoteConn.Close()
|
||||||
|
m.logger.ErrorContext(ctx, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
remoteConn = newConn
|
||||||
}
|
}
|
||||||
m.access.Lock()
|
m.access.Lock()
|
||||||
element := m.connections.PushBack(conn)
|
element := m.connections.PushBack(conn)
|
||||||
|
@ -40,7 +40,6 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
|
|||||||
UDPConnect: action.RouteOptions.UDPConnect,
|
UDPConnect: action.RouteOptions.UDPConnect,
|
||||||
TLSFragment: action.RouteOptions.TLSFragment,
|
TLSFragment: action.RouteOptions.TLSFragment,
|
||||||
TLSFragmentFallbackDelay: time.Duration(action.RouteOptions.TLSFragmentFallbackDelay),
|
TLSFragmentFallbackDelay: time.Duration(action.RouteOptions.TLSFragmentFallbackDelay),
|
||||||
TLSRecordFragment: action.RouteOptions.TLSRecordFragment,
|
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
case C.RuleActionTypeRouteOptions:
|
case C.RuleActionTypeRouteOptions:
|
||||||
@ -54,7 +53,6 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
|
|||||||
UDPTimeout: time.Duration(action.RouteOptionsOptions.UDPTimeout),
|
UDPTimeout: time.Duration(action.RouteOptionsOptions.UDPTimeout),
|
||||||
TLSFragment: action.RouteOptionsOptions.TLSFragment,
|
TLSFragment: action.RouteOptionsOptions.TLSFragment,
|
||||||
TLSFragmentFallbackDelay: time.Duration(action.RouteOptionsOptions.TLSFragmentFallbackDelay),
|
TLSFragmentFallbackDelay: time.Duration(action.RouteOptionsOptions.TLSFragmentFallbackDelay),
|
||||||
TLSRecordFragment: action.RouteOptionsOptions.TLSRecordFragment,
|
|
||||||
}, nil
|
}, nil
|
||||||
case C.RuleActionTypeDirect:
|
case C.RuleActionTypeDirect:
|
||||||
directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions), false)
|
directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions), false)
|
||||||
@ -154,7 +152,15 @@ func (r *RuleActionRoute) Type() string {
|
|||||||
func (r *RuleActionRoute) String() string {
|
func (r *RuleActionRoute) String() string {
|
||||||
var descriptions []string
|
var descriptions []string
|
||||||
descriptions = append(descriptions, r.Outbound)
|
descriptions = append(descriptions, r.Outbound)
|
||||||
descriptions = append(descriptions, r.Descriptions()...)
|
if r.UDPDisableDomainUnmapping {
|
||||||
|
descriptions = append(descriptions, "udp-disable-domain-unmapping")
|
||||||
|
}
|
||||||
|
if r.UDPConnect {
|
||||||
|
descriptions = append(descriptions, "udp-connect")
|
||||||
|
}
|
||||||
|
if r.TLSFragment {
|
||||||
|
descriptions = append(descriptions, "tls-fragment")
|
||||||
|
}
|
||||||
return F.ToString("route(", strings.Join(descriptions, ","), ")")
|
return F.ToString("route(", strings.Join(descriptions, ","), ")")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +176,6 @@ type RuleActionRouteOptions struct {
|
|||||||
UDPTimeout time.Duration
|
UDPTimeout time.Duration
|
||||||
TLSFragment bool
|
TLSFragment bool
|
||||||
TLSFragmentFallbackDelay time.Duration
|
TLSFragmentFallbackDelay time.Duration
|
||||||
TLSRecordFragment bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RuleActionRouteOptions) Type() string {
|
func (r *RuleActionRouteOptions) Type() string {
|
||||||
@ -178,10 +183,6 @@ func (r *RuleActionRouteOptions) Type() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RuleActionRouteOptions) String() string {
|
func (r *RuleActionRouteOptions) String() string {
|
||||||
return F.ToString("route-options(", strings.Join(r.Descriptions(), ","), ")")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RuleActionRouteOptions) Descriptions() []string {
|
|
||||||
var descriptions []string
|
var descriptions []string
|
||||||
if r.OverrideAddress.IsValid() {
|
if r.OverrideAddress.IsValid() {
|
||||||
descriptions = append(descriptions, F.ToString("override-address=", r.OverrideAddress.AddrString()))
|
descriptions = append(descriptions, F.ToString("override-address=", r.OverrideAddress.AddrString()))
|
||||||
@ -210,16 +211,7 @@ func (r *RuleActionRouteOptions) Descriptions() []string {
|
|||||||
if r.UDPTimeout > 0 {
|
if r.UDPTimeout > 0 {
|
||||||
descriptions = append(descriptions, "udp-timeout")
|
descriptions = append(descriptions, "udp-timeout")
|
||||||
}
|
}
|
||||||
if r.TLSFragment {
|
return F.ToString("route-options(", strings.Join(descriptions, ","), ")")
|
||||||
descriptions = append(descriptions, "tls-fragment")
|
|
||||||
}
|
|
||||||
if r.TLSFragmentFallbackDelay > 0 {
|
|
||||||
descriptions = append(descriptions, F.ToString("tls-fragment-fallback-delay=", r.TLSFragmentFallbackDelay.String()))
|
|
||||||
}
|
|
||||||
if r.TLSRecordFragment {
|
|
||||||
descriptions = append(descriptions, "tls-record-fragment")
|
|
||||||
}
|
|
||||||
return descriptions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RuleActionDNSRoute struct {
|
type RuleActionDNSRoute struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user