Skip to content

Commit 49a094a

Browse files
committed
🦈 conn, service: support MPTCP with explicit option
Unlike Go std's default, enabled, disabled states, our option explicitly enables/disables MPTCP.
1 parent 00a1171 commit 49a094a

3 files changed

Lines changed: 53 additions & 2 deletions

File tree

conn/conn.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ type ListenerSocketOptions struct {
101101
// Available on Linux, macOS, FreeBSD, and Windows.
102102
TCPFastOpen bool
103103

104+
// MultipathTCP enables multipath TCP on the listener.
105+
//
106+
// Unlike Go std, we make MPTCP strictly opt-in.
107+
// That is, if this field is false, MPTCP will be explicitly disabled.
108+
// This ensures that if Go std suddenly decides to enable MPTCP by default,
109+
// existing configurations won't encounter issues due to missing features in the kernel MPTCP stack,
110+
// such as TCP keepalive (as of Linux 6.5), and failed connect attempts won't always be retried once.
111+
//
112+
// Available on platforms supported by Go std's MPTCP implementation.
113+
MultipathTCP bool
114+
104115
// ReceivePacketInfo enables the reception of packet information control messages on the listener.
105116
//
106117
// Available on Linux, macOS, and Windows.
@@ -114,12 +125,14 @@ type ListenerSocketOptions struct {
114125

115126
// ListenConfig returns a [ListenConfig] with a control function that sets the socket options.
116127
func (lso ListenerSocketOptions) ListenConfig() ListenConfig {
117-
return ListenConfig{
128+
lc := ListenConfig{
118129
ListenConfig: net.ListenConfig{
119130
Control: lso.buildSetFns().controlFunc(),
120131
},
121132
DisableTFO: !lso.TCPFastOpen,
122133
}
134+
lc.SetMultipathTCP(lso.MultipathTCP)
135+
return lc
123136
}
124137

125138
var (
@@ -186,16 +199,29 @@ type DialerSocketOptions struct {
186199
//
187200
// Available on Linux, macOS, FreeBSD, and Windows.
188201
TCPFastOpen bool
202+
203+
// MultipathTCP enables multipath TCP on the dialer.
204+
//
205+
// Unlike Go std, we make MPTCP strictly opt-in.
206+
// That is, if this field is false, MPTCP will be explicitly disabled.
207+
// This ensures that if Go std suddenly decides to enable MPTCP by default,
208+
// existing configurations won't encounter issues due to missing features in the kernel MPTCP stack,
209+
// such as TCP keepalive (as of Linux 6.5), and failed connect attempts won't always be retried once.
210+
//
211+
// Available on platforms supported by Go std's MPTCP implementation.
212+
MultipathTCP bool
189213
}
190214

191215
// Dialer returns a [Dialer] with a control function that sets the socket options.
192216
func (dso DialerSocketOptions) Dialer() Dialer {
193-
return Dialer{
217+
d := Dialer{
194218
Dialer: net.Dialer{
195219
ControlContext: dso.buildSetFns().controlContextFunc(),
196220
},
197221
DisableTFO: !dso.TCPFastOpen,
198222
}
223+
d.SetMultipathTCP(dso.MultipathTCP)
224+
return d
199225
}
200226

201227
var (

service/client.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ type ClientConfig struct {
4545
EnableTCP bool `json:"enableTCP"`
4646
DialerTFO bool `json:"dialerTFO"`
4747

48+
// MultipathTCP enables multipath TCP on the client.
49+
//
50+
// Unlike Go std, we make MPTCP strictly opt-in.
51+
// That is, if this field is false, MPTCP will be explicitly disabled.
52+
// This ensures that if Go std suddenly decides to enable MPTCP by default,
53+
// existing configurations won't encounter issues due to missing features in the kernel MPTCP stack,
54+
// such as TCP keepalive (as of Linux 6.5), and failed connect attempts won't always be retried once.
55+
//
56+
// Available on platforms supported by Go std's MPTCP implementation.
57+
MultipathTCP bool `json:"multipathTCP"`
58+
4859
// AllowSegmentedFixedLengthHeader disables the requirement that
4960
// the fixed-length header must be read in a single read call.
5061
//
@@ -147,6 +158,7 @@ func (cc *ClientConfig) TCPClient() (zerocopy.TCPClient, error) {
147158
Fwmark: cc.DialerFwmark,
148159
TrafficClass: cc.DialerTrafficClass,
149160
TCPFastOpen: cc.DialerTFO,
161+
MultipathTCP: cc.MultipathTCP,
150162
})
151163

152164
switch cc.Protocol {
@@ -193,6 +205,7 @@ func (cc *ClientConfig) UDPClient() (zerocopy.UDPClient, error) {
193205
Fwmark: cc.DialerFwmark,
194206
TrafficClass: cc.DialerTrafficClass,
195207
TCPFastOpen: cc.DialerTFO,
208+
MultipathTCP: cc.MultipathTCP,
196209
})
197210
return direct.NewSocks5UDPClient(cc.logger, cc.Name, cc.UDPAddress.String(), dialer, cc.MTU, listenConfig), nil
198211
case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":

service/server.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ type TCPListenerConfig struct {
5454
// Available on Linux, macOS, FreeBSD, and Windows.
5555
FastOpen bool `json:"fastOpen"`
5656

57+
// Multipath enables multipath TCP on the listener.
58+
//
59+
// Unlike Go std, we make MPTCP strictly opt-in.
60+
// That is, if this field is false, MPTCP will be explicitly disabled.
61+
// This ensures that if Go std suddenly decides to enable MPTCP by default,
62+
// existing configurations won't encounter issues due to missing features in the kernel MPTCP stack,
63+
// such as TCP keepalive (as of Linux 6.5), and failed connect attempts won't always be retried once.
64+
//
65+
// Available on platforms supported by Go std's MPTCP implementation.
66+
Multipath bool `json:"multipath"`
67+
5768
// DisableInitialPayloadWait disables the brief wait for initial payload.
5869
// Setting it to true is useful when the listener only relays server-speaks-first protocols.
5970
DisableInitialPayloadWait bool `json:"disableInitialPayloadWait"`
@@ -100,6 +111,7 @@ func (lnc *TCPListenerConfig) Configure(listenConfigCache conn.ListenConfigCache
100111
ReusePort: lnc.ReusePort,
101112
Transparent: transparent,
102113
TCPFastOpen: lnc.FastOpen,
114+
MultipathTCP: lnc.Multipath,
103115
}),
104116
waitForInitialPayload: !serverNativeInitialPayload && !lnc.DisableInitialPayloadWait,
105117
initialPayloadWaitTimeout: initialPayloadWaitTimeout,

0 commit comments

Comments
 (0)