mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-14 10:03:58 +00:00
masque: Use custom QUIC transport with configurable connection ID length
This commit is contained in:
@@ -94,7 +94,7 @@ func ConnectTunnel(ctx context.Context, dialer N.Dialer, tlsConfig aTLS.Config,
|
||||
conn, err := qtls.Dial(
|
||||
ctx,
|
||||
bufio.NewBindPacketConn(udpConn, quicEndpoint),
|
||||
tlsConfig,
|
||||
NewTLSConfig(tlsConfig, 20),
|
||||
quicConfig,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
package masque
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/sagernet/quic-go"
|
||||
"github.com/sagernet/quic-go/http3"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
aTLS "github.com/sagernet/sing/common/tls"
|
||||
)
|
||||
|
||||
type TLSConfig struct {
|
||||
aTLS.Config
|
||||
connectionIDLength int
|
||||
}
|
||||
|
||||
func NewTLSConfig(config aTLS.Config, connectionIDLength int) aTLS.Config {
|
||||
return &TLSConfig{config, connectionIDLength}
|
||||
}
|
||||
|
||||
func (c *TLSConfig) Clone() aTLS.Config {
|
||||
return NewTLSConfig(c.Config.Clone(), c.connectionIDLength)
|
||||
}
|
||||
|
||||
func (c *TLSConfig) Dial(ctx context.Context, conn net.Conn, quicConfig *quic.Config) (*quic.Conn, error) {
|
||||
return c.dial(ctx, conn, quicConfig, false)
|
||||
}
|
||||
|
||||
func (c *TLSConfig) DialEarly(ctx context.Context, conn net.Conn, quicConfig *quic.Config) (*quic.Conn, error) {
|
||||
return c.dial(ctx, conn, quicConfig, true)
|
||||
}
|
||||
|
||||
func (c *TLSConfig) CreateTransport(conn net.Conn, quicConnPtr **quic.Conn, quicConfig *quic.Config) http.RoundTripper {
|
||||
packetConn, isPacketConn := common.Cast[net.PacketConn](conn)
|
||||
if !isPacketConn {
|
||||
return roundTripperError{E.New("masque: underlying connection does not support a custom QUIC transport")}
|
||||
}
|
||||
return c.CreatePacketTransport(packetConn, conn.RemoteAddr(), quicConnPtr, quicConfig)
|
||||
}
|
||||
|
||||
func (c *TLSConfig) CreatePacketTransport(packetConn net.PacketConn, remoteAddr net.Addr, quicConnPtr **quic.Conn, quicConfig *quic.Config) http.RoundTripper {
|
||||
stdConfig, err := c.STDConfig()
|
||||
if err != nil {
|
||||
return roundTripperError{err}
|
||||
}
|
||||
transport := c.newTransport(packetConn)
|
||||
return &http3.Transport{
|
||||
TLSClientConfig: stdConfig,
|
||||
QUICConfig: quicConfig,
|
||||
Dial: func(ctx context.Context, addr string, tlsConfig *tls.Config, config *quic.Config) (*quic.Conn, error) {
|
||||
quicConn, dialErr := transport.DialEarly(ctx, remoteAddr, tlsConfig, config)
|
||||
if dialErr != nil {
|
||||
return nil, dialErr
|
||||
}
|
||||
*quicConnPtr = quicConn
|
||||
return quicConn, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *TLSConfig) dial(ctx context.Context, conn net.Conn, quicConfig *quic.Config, early bool) (*quic.Conn, error) {
|
||||
packetConn, isPacketConn := common.Cast[net.PacketConn](conn)
|
||||
if !isPacketConn {
|
||||
return nil, E.New("masque: underlying connection does not support a custom QUIC transport")
|
||||
}
|
||||
stdConfig, err := c.STDConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
transport := c.newTransport(packetConn)
|
||||
var quicConn *quic.Conn
|
||||
if early {
|
||||
quicConn, err = transport.DialEarly(ctx, conn.RemoteAddr(), stdConfig, quicConfig)
|
||||
} else {
|
||||
quicConn, err = transport.Dial(ctx, conn.RemoteAddr(), stdConfig, quicConfig)
|
||||
}
|
||||
if err != nil {
|
||||
_ = transport.Close()
|
||||
return nil, err
|
||||
}
|
||||
return quicConn, nil
|
||||
}
|
||||
|
||||
func (c *TLSConfig) newTransport(packetConn net.PacketConn) *quic.Transport {
|
||||
transport := &quic.Transport{
|
||||
Conn: packetConn,
|
||||
ConnectionIDLength: c.connectionIDLength,
|
||||
}
|
||||
transport.SetSingleUse(true)
|
||||
return transport
|
||||
}
|
||||
|
||||
type roundTripperError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (r roundTripperError) RoundTrip(*http.Request) (*http.Response, error) {
|
||||
return nil, r.err
|
||||
}
|
||||
Reference in New Issue
Block a user