Add QUIC support for naiveproxy

This commit is contained in:
世界
2025-12-18 17:08:36 +08:00
parent daef974c32
commit a150b7fffc
15 changed files with 553 additions and 199 deletions

View File

@@ -29,7 +29,7 @@ import (
"golang.org/x/net/http2/h2c"
)
var ConfigureHTTP3ListenerFunc func(listener *listener.Listener, handler http.Handler, tlsConfig tls.ServerConfig, logger logger.Logger) (io.Closer, error)
var ConfigureHTTP3ListenerFunc func(ctx context.Context, logger logger.Logger, listener *listener.Listener, handler http.Handler, tlsConfig tls.ServerConfig, options option.NaiveInboundOptions) (io.Closer, error)
func RegisterInbound(registry *inbound.Registry) {
inbound.Register[option.NaiveInboundOptions](registry, C.TypeNaive, NewInbound)
@@ -40,6 +40,7 @@ type Inbound struct {
ctx context.Context
router adapter.ConnectionRouterEx
logger logger.ContextLogger
options option.NaiveInboundOptions
listener *listener.Listener
network []string
networkIsDefault bool
@@ -121,7 +122,7 @@ func (n *Inbound) Start(stage adapter.StartStage) error {
}
if common.Contains(n.network, N.NetworkUDP) {
http3Server, err := ConfigureHTTP3ListenerFunc(n.listener, n, n.tlsConfig, n.logger)
http3Server, err := ConfigureHTTP3ListenerFunc(n.ctx, n.logger, n.listener, n, n.tlsConfig, n.options)
if err == nil {
n.h3Server = http3Server
} else if len(n.network) > 1 {

View File

@@ -160,7 +160,21 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
echConfigList = block.Bytes
}
}
var quicCongestionControl cronet.QUICCongestionControl
switch options.QUICCongestionControl {
case "":
quicCongestionControl = cronet.QUICCongestionControlDefault
case "bbr":
quicCongestionControl = cronet.QUICCongestionControlBBR
case "bbr2":
quicCongestionControl = cronet.QUICCongestionControlBBRv2
case "cubic":
quicCongestionControl = cronet.QUICCongestionControlCubic
case "reno":
quicCongestionControl = cronet.QUICCongestionControlReno
default:
return nil, E.New("unknown quic congestion control: ", options.QUICCongestionControl)
}
client, err := cronet.NewNaiveClient(cronet.NaiveClientConfig{
Context: ctx,
ServerAddress: serverAddress,
@@ -176,11 +190,12 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
ECHEnabled: echEnabled,
ECHConfigList: echConfigList,
ECHQueryServerName: echQueryServerName,
QUIC: options.QUIC,
QUICCongestionControl: quicCongestionControl,
})
if err != nil {
return nil, err
}
var uotClient *uot.Client
uotOptions := common.PtrValueOrDefault(options.UDPOverTCP)
if uotOptions.Enabled {

View File

@@ -1,21 +1,29 @@
package quic
import (
"context"
"io"
"net/http"
"github.com/sagernet/quic-go"
"github.com/sagernet/quic-go/congestion"
"github.com/sagernet/quic-go/http3"
"github.com/sagernet/sing-box/common/listener"
"github.com/sagernet/sing-box/common/tls"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-box/protocol/naive"
"github.com/sagernet/sing-quic"
"github.com/sagernet/sing-quic/congestion_bbr1"
"github.com/sagernet/sing-quic/congestion_bbr2"
congestion_meta1 "github.com/sagernet/sing-quic/congestion_meta1"
congestion_meta2 "github.com/sagernet/sing-quic/congestion_meta2"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
"github.com/sagernet/sing/common/ntp"
)
func init() {
naive.ConfigureHTTP3ListenerFunc = func(listener *listener.Listener, handler http.Handler, tlsConfig tls.ServerConfig, logger logger.Logger) (io.Closer, error) {
naive.ConfigureHTTP3ListenerFunc = func(ctx context.Context, logger logger.Logger, listener *listener.Listener, handler http.Handler, tlsConfig tls.ServerConfig, options option.NaiveInboundOptions) (io.Closer, error) {
err := qtls.ConfigureHTTP3(tlsConfig)
if err != nil {
return nil, err
@@ -26,9 +34,67 @@ func init() {
return nil, err
}
var congestionControl func(conn *quic.Conn) congestion.CongestionControl
switch options.QUICCongestionControl {
case "", "bbr":
congestionControl = func(conn *quic.Conn) congestion.CongestionControl {
return congestion_meta2.NewBbrSender(
congestion_meta2.DefaultClock{TimeFunc: ntp.TimeFuncFromContext(ctx)},
congestion.ByteCount(conn.Config().InitialPacketSize),
congestion.ByteCount(congestion_meta1.InitialCongestionWindow),
)
}
case "bbr_standard":
congestionControl = func(conn *quic.Conn) congestion.CongestionControl {
return congestion_bbr1.NewBbrSender(
congestion_bbr1.DefaultClock{TimeFunc: ntp.TimeFuncFromContext(ctx)},
congestion.ByteCount(conn.Config().InitialPacketSize),
congestion_bbr1.InitialCongestionWindowPackets,
congestion_bbr1.MaxCongestionWindowPackets,
)
}
case "bbr2":
congestionControl = func(conn *quic.Conn) congestion.CongestionControl {
return congestion_bbr2.NewBBR2Sender(
congestion_bbr2.DefaultClock{TimeFunc: ntp.TimeFuncFromContext(ctx)},
congestion.ByteCount(conn.Config().InitialPacketSize),
0,
false,
)
}
case "bbr2_variant":
congestionControl = func(conn *quic.Conn) congestion.CongestionControl {
return congestion_bbr2.NewBBR2Sender(
congestion_bbr2.DefaultClock{TimeFunc: ntp.TimeFuncFromContext(ctx)},
congestion.ByteCount(conn.Config().InitialPacketSize),
32*congestion.ByteCount(conn.Config().InitialPacketSize),
true,
)
}
case "cubic":
congestionControl = func(conn *quic.Conn) congestion.CongestionControl {
return congestion_meta1.NewCubicSender(
congestion_meta1.DefaultClock{TimeFunc: ntp.TimeFuncFromContext(ctx)},
congestion.ByteCount(conn.Config().InitialPacketSize),
false,
)
}
case "reno":
congestionControl = func(conn *quic.Conn) congestion.CongestionControl {
return congestion_meta1.NewCubicSender(
congestion_meta1.DefaultClock{TimeFunc: ntp.TimeFuncFromContext(ctx)},
congestion.ByteCount(conn.Config().InitialPacketSize),
true,
)
}
default:
return nil, E.New("unknown quic congestion control: ", options.QUICCongestionControl)
}
quicListener, err := qtls.ListenEarly(udpConn, tlsConfig, &quic.Config{
MaxIncomingStreams: 1 << 60,
Allow0RTT: true,
MaxIncomingStreams: 1 << 60,
Allow0RTT: true,
GetCongestionControl: congestionControl,
})
if err != nil {
udpConn.Close()