mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-12-01 19:06:43 +00:00
121 lines
3.9 KiB
Go
121 lines
3.9 KiB
Go
package qtls
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net"
|
|
"net/http"
|
|
|
|
"github.com/sagernet/quic-go"
|
|
"github.com/sagernet/quic-go/http3"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
aTLS "github.com/sagernet/sing/common/tls"
|
|
)
|
|
|
|
type QUICConfig interface {
|
|
Dial(ctx context.Context, conn net.PacketConn, addr net.Addr, config *quic.Config) (quic.Connection, error)
|
|
DialEarly(ctx context.Context, conn net.PacketConn, addr net.Addr, config *quic.Config) (quic.EarlyConnection, error)
|
|
CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, quicConfig *quic.Config, enableDatagrams bool) http.RoundTripper
|
|
}
|
|
|
|
type QUICServerConfig interface {
|
|
Listen(conn net.PacketConn, config *quic.Config) (QUICListener, error)
|
|
ListenEarly(conn net.PacketConn, config *quic.Config) (QUICEarlyListener, error)
|
|
ConfigureHTTP3()
|
|
}
|
|
|
|
type QUICListener interface {
|
|
Accept(ctx context.Context) (quic.Connection, error)
|
|
Close() error
|
|
Addr() net.Addr
|
|
}
|
|
|
|
type QUICEarlyListener interface {
|
|
Accept(ctx context.Context) (quic.EarlyConnection, error)
|
|
Close() error
|
|
Addr() net.Addr
|
|
}
|
|
|
|
func Dial(ctx context.Context, conn net.PacketConn, addr net.Addr, config aTLS.Config, quicConfig *quic.Config) (quic.Connection, error) {
|
|
if quicTLSConfig, isQUICConfig := config.(QUICConfig); isQUICConfig {
|
|
return quicTLSConfig.Dial(ctx, conn, addr, quicConfig)
|
|
}
|
|
tlsConfig, err := config.Config()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return quic.Dial(ctx, conn, addr, tlsConfig, quicConfig)
|
|
}
|
|
|
|
func DialEarly(ctx context.Context, conn net.PacketConn, addr net.Addr, config aTLS.Config, quicConfig *quic.Config) (quic.EarlyConnection, error) {
|
|
if quicTLSConfig, isQUICConfig := config.(QUICConfig); isQUICConfig {
|
|
return quicTLSConfig.DialEarly(ctx, conn, addr, quicConfig)
|
|
}
|
|
tlsConfig, err := config.Config()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return quic.DialEarly(ctx, conn, addr, tlsConfig, quicConfig)
|
|
}
|
|
|
|
func CreateTransport(conn net.PacketConn, quicConnPtr *quic.EarlyConnection, serverAddr M.Socksaddr, config aTLS.Config, quicConfig *quic.Config, enableDatagrams bool) (http.RoundTripper, error) {
|
|
if quicTLSConfig, isQUICConfig := config.(QUICConfig); isQUICConfig {
|
|
return quicTLSConfig.CreateTransport(conn, quicConnPtr, serverAddr, quicConfig, enableDatagrams), nil
|
|
}
|
|
tlsConfig, err := config.Config()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &http3.RoundTripper{
|
|
TLSClientConfig: tlsConfig,
|
|
QuicConfig: quicConfig,
|
|
EnableDatagrams: enableDatagrams,
|
|
Dial: func(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (quic.EarlyConnection, error) {
|
|
quicConn, err := quic.DialEarly(ctx, conn, serverAddr.UDPAddr(), tlsCfg, cfg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
*quicConnPtr = quicConn
|
|
return quicConn, nil
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func Listen(conn net.PacketConn, config aTLS.ServerConfig, quicConfig *quic.Config) (QUICListener, error) {
|
|
if quicTLSConfig, isQUICConfig := config.(QUICServerConfig); isQUICConfig {
|
|
return quicTLSConfig.Listen(conn, quicConfig)
|
|
}
|
|
tlsConfig, err := config.Config()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return quic.Listen(conn, tlsConfig, quicConfig)
|
|
}
|
|
|
|
func ListenEarly(conn net.PacketConn, config aTLS.ServerConfig, quicConfig *quic.Config) (QUICEarlyListener, error) {
|
|
if quicTLSConfig, isQUICConfig := config.(QUICServerConfig); isQUICConfig {
|
|
return quicTLSConfig.ListenEarly(conn, quicConfig)
|
|
}
|
|
tlsConfig, err := config.Config()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return quic.ListenEarly(conn, tlsConfig, quicConfig)
|
|
}
|
|
|
|
func ConfigureHTTP3(config aTLS.ServerConfig) error {
|
|
if len(config.NextProtos()) == 0 {
|
|
config.SetNextProtos([]string{http3.NextProtoH3})
|
|
}
|
|
if quicTLSConfig, isQUICConfig := config.(QUICServerConfig); isQUICConfig {
|
|
quicTLSConfig.ConfigureHTTP3()
|
|
return nil
|
|
}
|
|
tlsConfig, err := config.Config()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
http3.ConfigureTLSConfig(tlsConfig)
|
|
return nil
|
|
}
|