mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-19 15:54:24 +00:00
fix: Wait for trusttunnel client connection and add disable_path_mtu_discovery
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
"quic": true,
|
||||
"congestion_controller": "bbr", // bbr, bbr_standard, bbr2, bbr2_variant, cubic, reno
|
||||
"cwnd": 32,
|
||||
"disable_path_mtu_discovery": false, // QUIC only
|
||||
"multiplex": {
|
||||
"enabled": true,
|
||||
"max_connections": 8,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
],
|
||||
"congestion_controller": "bbr", // bbr, bbr_standard, bbr2, bbr2_variant, cubic, reno
|
||||
"cwnd": 32,
|
||||
"disable_path_mtu_discovery": false, // QUIC only
|
||||
"tls": {
|
||||
"enabled": true,
|
||||
"alpn": ["h2", "h3"],
|
||||
|
||||
+14
-12
@@ -3,10 +3,11 @@ package option
|
||||
type TrustTunnelInboundOptions struct {
|
||||
ListenOptions
|
||||
InboundTLSOptionsContainer
|
||||
Users []TrustTunnelUser `json:"users,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
CongestionController string `json:"congestion_controller,omitempty"`
|
||||
CWND int `json:"cwnd,omitempty"`
|
||||
Users []TrustTunnelUser `json:"users,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
CongestionController string `json:"congestion_controller,omitempty"`
|
||||
CWND int `json:"cwnd,omitempty"`
|
||||
DisablePathMTUDiscovery bool `json:"disable_path_mtu_discovery,omitempty"`
|
||||
}
|
||||
|
||||
type TrustTunnelUser struct {
|
||||
@@ -25,12 +26,13 @@ type TrustTunnelOutboundOptions struct {
|
||||
DialerOptions
|
||||
ServerOptions
|
||||
OutboundTLSOptionsContainer
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
HealthCheck bool `json:"health_check,omitempty"`
|
||||
QUIC bool `json:"quic,omitempty"`
|
||||
CongestionController string `json:"congestion_controller,omitempty"`
|
||||
CWND int `json:"cwnd,omitempty"`
|
||||
Multiplex *TrustTunnelMultiplexOptions `json:"multiplex,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
Network NetworkList `json:"network,omitempty"`
|
||||
HealthCheck bool `json:"health_check,omitempty"`
|
||||
QUIC bool `json:"quic,omitempty"`
|
||||
CongestionController string `json:"congestion_controller,omitempty"`
|
||||
CWND int `json:"cwnd,omitempty"`
|
||||
DisablePathMTUDiscovery bool `json:"disable_path_mtu_discovery,omitempty"`
|
||||
Multiplex *TrustTunnelMultiplexOptions `json:"multiplex,omitempty"`
|
||||
}
|
||||
|
||||
@@ -157,9 +157,10 @@ func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
},
|
||||
}
|
||||
quicListener, err := qtls.ListenEarly(udpConn, h.http3TLSConfig, &quic.Config{
|
||||
MaxIdleTimeout: trusttunnel.DefaultSessionTimeout * 2,
|
||||
MaxIncomingStreams: 1 << 60,
|
||||
Allow0RTT: true,
|
||||
MaxIdleTimeout: trusttunnel.DefaultSessionTimeout * 2,
|
||||
MaxIncomingStreams: 1 << 60,
|
||||
Allow0RTT: true,
|
||||
DisablePathMTUDiscovery: h.options.DisablePathMTUDiscovery,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -45,16 +45,17 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
return nil, err
|
||||
}
|
||||
clientOpts := trusttunnel.ClientOptions{
|
||||
Dialer: outboundDialer,
|
||||
TLSConfig: tlsConfig,
|
||||
Server: serverAddr,
|
||||
Username: options.Username,
|
||||
Password: options.Password,
|
||||
QUIC: options.QUIC,
|
||||
CongestionControl: options.CongestionController,
|
||||
CWND: options.CWND,
|
||||
Logger: logger,
|
||||
HealthCheck: options.HealthCheck,
|
||||
Dialer: outboundDialer,
|
||||
TLSConfig: tlsConfig,
|
||||
Server: serverAddr,
|
||||
Username: options.Username,
|
||||
Password: options.Password,
|
||||
QUIC: options.QUIC,
|
||||
DisablePathMTUDiscovery: options.DisablePathMTUDiscovery,
|
||||
CongestionControl: options.CongestionController,
|
||||
CWND: options.CWND,
|
||||
Logger: logger,
|
||||
HealthCheck: options.HealthCheck,
|
||||
}
|
||||
var client trusttunnel.Dialer
|
||||
if options.Multiplex != nil && options.Multiplex.Enabled {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"sync"
|
||||
@@ -17,6 +18,7 @@ import (
|
||||
"github.com/sagernet/sing-box/common/congestion"
|
||||
"github.com/sagernet/sing-box/common/tls"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -43,19 +45,20 @@ type Dialer interface {
|
||||
}
|
||||
|
||||
type ClientOptions struct {
|
||||
Dialer N.Dialer
|
||||
TLSConfig tls.Config
|
||||
Server M.Socksaddr
|
||||
Username string
|
||||
Password string
|
||||
QUIC bool
|
||||
CongestionControl string
|
||||
CWND int
|
||||
Logger logger.Logger
|
||||
HealthCheck bool
|
||||
MaxConnections int
|
||||
MinStreams int
|
||||
MaxStreams int
|
||||
Dialer N.Dialer
|
||||
TLSConfig tls.Config
|
||||
Server M.Socksaddr
|
||||
Username string
|
||||
Password string
|
||||
QUIC bool
|
||||
DisablePathMTUDiscovery bool
|
||||
CongestionControl string
|
||||
CWND int
|
||||
Logger logger.Logger
|
||||
HealthCheck bool
|
||||
MaxConnections int
|
||||
MinStreams int
|
||||
MaxStreams int
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
@@ -92,8 +95,9 @@ func NewClient(ctx context.Context, options ClientOptions) (*Client, error) {
|
||||
}
|
||||
client.roundTripper = &http3.Transport{
|
||||
QUICConfig: &quic.Config{
|
||||
MaxIdleTimeout: DefaultSessionTimeout * 2,
|
||||
KeepAlivePeriod: DefaultHealthCheckTimeout,
|
||||
MaxIdleTimeout: DefaultSessionTimeout * 2,
|
||||
KeepAlivePeriod: DefaultHealthCheckTimeout,
|
||||
DisablePathMTUDiscovery: options.DisablePathMTUDiscovery,
|
||||
},
|
||||
Dial: func(ctx context.Context, addr string, tlsCfg *stdtls.Config, cfg *quic.Config) (*quic.Conn, error) {
|
||||
udpConn, err := options.Dialer.DialContext(ctx, N.NetworkUDP, client.server)
|
||||
@@ -151,27 +155,38 @@ func (c *Client) resetHealthCheckTimer() {
|
||||
c.healthCheckTimer.Reset(DefaultHealthCheckTimeout)
|
||||
}
|
||||
|
||||
func (c *Client) roundTrip(request *http.Request, conn *httpConn) {
|
||||
func (c *Client) roundTrip(ctx context.Context, request *http.Request, conn *httpConn) error {
|
||||
c.startOnce.Do(c.start)
|
||||
pipeReader, pipeWriter := io.Pipe()
|
||||
request.Body = pipeReader
|
||||
*conn = httpConn{writer: pipeWriter, created: make(chan struct{})}
|
||||
c.count.Add(1)
|
||||
conn.closeFn = sync.OnceFunc(func() { c.count.Add(-1) })
|
||||
ctx, cancel := context.WithCancel(c.ctx)
|
||||
requestCtx, cancel := context.WithCancel(c.ctx)
|
||||
conn.cancelFn = cancel
|
||||
gotConn := make(chan bool, 1)
|
||||
streamCtx := httptrace.WithClientTrace(requestCtx, &httptrace.ClientTrace{
|
||||
GotConn: func(info httptrace.GotConnInfo) {
|
||||
select {
|
||||
case gotConn <- true:
|
||||
default:
|
||||
}
|
||||
},
|
||||
})
|
||||
var requestErr common.TypedValue[error]
|
||||
go func() {
|
||||
timeout := time.AfterFunc(C.TCPTimeout, cancel)
|
||||
defer timeout.Stop()
|
||||
request = request.WithContext(ctx)
|
||||
request = request.WithContext(streamCtx)
|
||||
response, err := c.roundTripper.RoundTrip(request)
|
||||
if err != nil {
|
||||
requestErr.Store(err)
|
||||
close(gotConn)
|
||||
_ = pipeWriter.CloseWithError(err)
|
||||
_ = pipeReader.CloseWithError(err)
|
||||
conn.setup(nil, err)
|
||||
} else if response.StatusCode != http.StatusOK {
|
||||
_ = response.Body.Close()
|
||||
err = fmt.Errorf("unexpected status code: %d", response.StatusCode)
|
||||
requestErr.Store(err)
|
||||
_ = pipeWriter.CloseWithError(err)
|
||||
_ = pipeReader.CloseWithError(err)
|
||||
conn.setup(nil, err)
|
||||
@@ -180,6 +195,12 @@ func (c *Client) roundTrip(request *http.Request, conn *httpConn) {
|
||||
conn.setup(response.Body, nil)
|
||||
}
|
||||
}()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-gotConn:
|
||||
return requestErr.Load()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) newConnectRequest(host, userAgent string) *http.Request {
|
||||
@@ -196,13 +217,21 @@ func (c *Client) newConnectRequest(host, userAgent string) *http.Request {
|
||||
|
||||
func (c *Client) Dial(ctx context.Context, host string) (net.Conn, error) {
|
||||
conn := &tcpConn{}
|
||||
c.roundTrip(c.newConnectRequest(host, tcpUserAgent), &conn.httpConn)
|
||||
err := c.roundTrip(ctx, c.newConnectRequest(host, tcpUserAgent), &conn.httpConn)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (c *Client) ListenPacket(ctx context.Context) (net.PacketConn, error) {
|
||||
conn := &clientPacketConn{}
|
||||
c.roundTrip(c.newConnectRequest(UDPMagicAddress, udpUserAgent), &conn.httpConn)
|
||||
err := c.roundTrip(ctx, c.newConnectRequest(UDPMagicAddress, udpUserAgent), &conn.httpConn)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user