Skip to content

Commit 1019ecf

Browse files
committed
Add TCP MultiPath support
1 parent 81b847f commit 1019ecf

33 files changed

Lines changed: 225 additions & 43 deletions

common/dialer/default.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type DefaultDialer struct {
2626
udpAddr6 string
2727
}
2828

29-
func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDialer {
29+
func NewDefault(router adapter.Router, options option.DialerOptions) (*DefaultDialer, error) {
3030
var dialer net.Dialer
3131
var listener net.ListenConfig
3232
if options.BindInterface != "" {
@@ -93,6 +93,12 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
9393
udpDialer6.LocalAddr = &net.UDPAddr{IP: bindAddr.AsSlice()}
9494
udpAddr6 = M.SocksaddrFrom(bindAddr, 0).String()
9595
}
96+
if options.TCPMultiPath {
97+
if !multipathTCPAvailable {
98+
return nil, E.New("MultiPath TCP requires go1.21, please recompile your binary.")
99+
}
100+
setMultiPathTCP(&dialer4)
101+
}
96102
return &DefaultDialer{
97103
tfo.Dialer{Dialer: dialer4, DisableTFO: !options.TCPFastOpen},
98104
tfo.Dialer{Dialer: dialer6, DisableTFO: !options.TCPFastOpen},
@@ -101,7 +107,7 @@ func NewDefault(router adapter.Router, options option.DialerOptions) *DefaultDia
101107
listener,
102108
udpAddr4,
103109
udpAddr6,
104-
}
110+
}, nil
105111
}
106112

107113
func (d *DefaultDialer) DialContext(ctx context.Context, network string, address M.Socksaddr) (net.Conn, error) {

common/dialer/default_go1.21.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build go1.21
2+
3+
package dialer
4+
5+
import "net"
6+
7+
const multipathTCPAvailable = true
8+
9+
func setMultiPathTCP(dialer *net.Dialer) {
10+
dialer.SetMultipathTCP(true)
11+
}

common/dialer/default_nongo1.21.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//go:build !go1.21
2+
3+
package dialer
4+
5+
import (
6+
"net"
7+
)
8+
9+
const multipathTCPAvailable = false
10+
11+
func setMultiPathTCP(dialer *net.Dialer) {
12+
}

common/dialer/dialer.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,30 @@ import (
66
"github.com/sagernet/sing-box/adapter"
77
"github.com/sagernet/sing-box/option"
88
"github.com/sagernet/sing-dns"
9+
"github.com/sagernet/sing/common"
910
N "github.com/sagernet/sing/common/network"
1011
)
1112

12-
func New(router adapter.Router, options option.DialerOptions) N.Dialer {
13-
var dialer N.Dialer
13+
func MustNew(router adapter.Router, options option.DialerOptions) N.Dialer {
14+
return common.Must1(New(router, options))
15+
}
16+
17+
func New(router adapter.Router, options option.DialerOptions) (N.Dialer, error) {
18+
var (
19+
dialer N.Dialer
20+
err error
21+
)
1422
if options.Detour == "" {
15-
dialer = NewDefault(router, options)
23+
dialer, err = NewDefault(router, options)
24+
if err != nil {
25+
return nil, err
26+
}
1627
} else {
1728
dialer = NewDetour(router, options.Detour)
1829
}
1930
domainStrategy := dns.DomainStrategy(options.DomainStrategy)
2031
if domainStrategy != dns.DomainStrategyAsIS || options.Detour == "" {
2132
dialer = NewResolveDialer(router, dialer, domainStrategy, time.Duration(options.FallbackDelay))
2233
}
23-
return dialer
34+
return dialer, nil
2435
}

common/tls/reality_server.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,10 @@ func NewRealityServer(ctx context.Context, router adapter.Router, logger log.Log
101101
tlsConfig.ShortIds[shortID] = true
102102
}
103103

104-
handshakeDialer := dialer.New(router, options.Reality.Handshake.DialerOptions)
104+
handshakeDialer, err := dialer.New(router, options.Reality.Handshake.DialerOptions)
105+
if err != nil {
106+
return nil, err
107+
}
105108
tlsConfig.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
106109
return handshakeDialer.DialContext(ctx, network, M.ParseSocksaddr(addr))
107110
}

docs/configuration/shared/dial.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"reuse_addr": false,
1111
"connect_timeout": "5s",
1212
"tcp_fast_open": false,
13+
"tcp_multi_path": false,
1314
"udp_fragment": false,
1415
"domain_strategy": "prefer_ipv6",
1516
"fallback_delay": "300ms"
@@ -18,9 +19,9 @@
1819

1920
### Fields
2021

21-
| Field | Available Context |
22-
|----------------------------------------------------------------------------------------------------------------------|-------------------|
23-
| `bind_interface` /`*bind_address` /`routing_mark` /`reuse_addr` / `tcp_fast_open`/ `udp_fragment` /`connect_timeout` | `detour` not set |
22+
| Field | Available Context |
23+
|------------------------------------------------------------------------------------------------------------------------------------------|-------------------|
24+
| `bind_interface` /`*bind_address` /`routing_mark` /`reuse_addr` / `tcp_fast_open` / `tcp_multi_path` / `udp_fragment` /`connect_timeout` | `detour` not set |
2425

2526
#### detour
2627

@@ -54,6 +55,14 @@ Reuse listener address.
5455

5556
Enable TCP Fast Open.
5657

58+
#### tcp_multi_path
59+
60+
!!! warning ""
61+
62+
Go 1.21 required.
63+
64+
Enable TCP Multi Path.
65+
5766
#### udp_fragment
5867

5968
Enable UDP fragmentation.

docs/configuration/shared/dial.zh.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"reuse_addr": false,
1111
"connect_timeout": "5s",
1212
"tcp_fast_open": false,
13+
"tcp_multi_path": false,
1314
"udp_fragment": false,
1415
"domain_strategy": "prefer_ipv6",
1516
"fallback_delay": "300ms"
@@ -18,9 +19,9 @@
1819

1920
### 字段
2021

21-
| 字段 | 可用上下文 |
22-
|----------------------------------------------------------------------------------------------------------------------|--------------|
23-
| `bind_interface` /`*bind_address` /`routing_mark` /`reuse_addr` / `tcp_fast_open`/ `udp_fragment` /`connect_timeout` | `detour` 未设置 |
22+
| 字段 | 可用上下文 |
23+
|------------------------------------------------------------------------------------------------------------------------------------------|--------------|
24+
| `bind_interface` /`*bind_address` /`routing_mark` /`reuse_addr` / `tcp_fast_open` / `tcp_mutli_path` / `udp_fragment` /`connect_timeout` | `detour` 未设置 |
2425

2526

2627
#### detour
@@ -57,6 +58,14 @@
5758

5859
启用 TCP Fast Open。
5960

61+
#### tcp_multi_path
62+
63+
!!! warning ""
64+
65+
需要 Go 1.21。
66+
67+
启用 TCP Multi Path。
68+
6069
#### udp_fragment
6170

6271
启用 UDP 分段。

docs/configuration/shared/listen.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"listen": "::",
66
"listen_port": 5353,
77
"tcp_fast_open": false,
8+
"tcp_multi_path": false,
89
"udp_fragment": false,
910
"sniff": false,
1011
"sniff_override_destination": false,
@@ -24,6 +25,7 @@
2425
| `listen` | Needs to listen on TCP or UDP. |
2526
| `listen_port` | Needs to listen on TCP or UDP. |
2627
| `tcp_fast_open` | Needs to listen on TCP. |
28+
| `tcp_multi_path` | Needs to listen on TCP. |
2729
| `udp_timeout` | Needs to assemble UDP connections, currently Tun and Shadowsocks. |
2830
| `proxy_protocol` | Needs to listen on TCP. |
2931
| `proxy_protocol_accept_no_header` | When `proxy_protocol` enabled |
@@ -42,6 +44,14 @@ Listen port.
4244

4345
Enable TCP Fast Open.
4446

47+
#### tcp_multi_path
48+
49+
!!! warning ""
50+
51+
Go 1.21 required.
52+
53+
Enable TCP Multi Path.
54+
4555
#### udp_fragment
4656

4757
Enable UDP fragmentation.

docs/configuration/shared/listen.zh.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"listen": "::",
66
"listen_port": 5353,
77
"tcp_fast_open": false,
8+
"tcp_multi_path": false,
89
"udp_fragment": false,
910
"sniff": false,
1011
"sniff_override_destination": false,
@@ -23,6 +24,7 @@
2324
| `listen` | 需要监听 TCP 或 UDP。 |
2425
| `listen_port` | 需要监听 TCP 或 UDP。 |
2526
| `tcp_fast_open` | 需要监听 TCP。 |
27+
| `tcp_multi_path` | 需要监听 TCP。 |
2628
| `udp_timeout` | 需要组装 UDP 连接, 当前为 Tun 和 Shadowsocks。 |
2729
| `proxy_protocol` | 需要监听 TCP。 |
2830
| `proxy_protocol_accept_no_header` | `proxy_protocol` 启用时 |
@@ -43,6 +45,14 @@
4345

4446
启用 TCP Fast Open。
4547

48+
#### tcp_multi_path
49+
50+
!!! warning ""
51+
52+
需要 Go 1.21。
53+
54+
启用 TCP Multi Path。
55+
4656
#### udp_fragment
4757

4858
启用 UDP 分段。

inbound/default_tcp.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,14 @@ func (a *myInboundAdapter) ListenTCP() (net.Listener, error) {
1818
bindAddr := M.SocksaddrFrom(a.listenOptions.Listen.Build(), a.listenOptions.ListenPort)
1919
var tcpListener net.Listener
2020
if !a.listenOptions.TCPFastOpen {
21-
tcpListener, err = net.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr())
21+
var listenConfig net.ListenConfig
22+
if a.listenOptions.TCPMultiPath {
23+
if !multipathTCPAvailable {
24+
return nil, E.New("MultiPath TCP requires go1.21, please recompile your binary.")
25+
}
26+
setMultiPathTCP(&listenConfig)
27+
}
28+
tcpListener, err = listenConfig.Listen(a.ctx, M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.String())
2229
} else {
2330
tcpListener, err = tfo.ListenTCP(M.NetworkFromNetAddr(N.NetworkTCP, bindAddr.Addr), bindAddr.TCPAddr())
2431
}

0 commit comments

Comments
 (0)