Hysteria & XHTTP/3: Unified Finalmask's quicParams to set congestion, brutalUp, brutalDown, udpHop (ports & interval), etc. (#5772)

https://github.com/XTLS/Xray-core/pull/5772#issuecomment-4023006179
This commit is contained in:
LjhAUMEM
2026-03-09 20:17:32 +08:00
committed by GitHub
parent 766fa71eb1
commit 0321cdd0d2
13 changed files with 590 additions and 694 deletions

View File

@@ -7,6 +7,7 @@ import (
"encoding/json" "encoding/json"
"math" "math"
"net/url" "net/url"
"os"
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
@@ -500,7 +501,7 @@ func (b Bandwidth) Bps() (uint64, error) {
} }
type UdpHop struct { type UdpHop struct {
PortList json.RawMessage `json:"port"` PortList json.RawMessage `json:"ports"`
Interval *Int32Range `json:"interval"` Interval *Int32Range `json:"interval"`
} }
@@ -519,21 +520,13 @@ type Masquerade struct {
} }
type HysteriaConfig struct { type HysteriaConfig struct {
Version int32 `json:"version"` Version int32 `json:"version"`
Auth string `json:"auth"` Auth string `json:"auth"`
Congestion string `json:"congestion"`
Up Bandwidth `json:"up"`
Down Bandwidth `json:"down"`
UdpHop UdpHop `json:"udphop"`
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"` Congestion *string `json:"congestion"`
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"` Up *Bandwidth `json:"up"`
InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"` Down *Bandwidth `json:"down"`
MaxConnectionReceiveWindow uint64 `json:"maxConnectionReceiveWindow"` UdpHop *UdpHop `json:"udphop"`
MaxIdleTimeout int64 `json:"maxIdleTimeout"`
KeepAlivePeriod int64 `json:"keepAlivePeriod"`
DisablePathMTUDiscovery bool `json:"disablePathMTUDiscovery"`
MaxIncomingStreams int64 `json:"maxIncomingStreams"`
UdpIdleTimeout int64 `json:"udpIdleTimeout"` UdpIdleTimeout int64 `json:"udpIdleTimeout"`
Masquerade Masquerade `json:"masquerade"` Masquerade Masquerade `json:"masquerade"`
@@ -544,62 +537,10 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
return nil, errors.New("version != 2") return nil, errors.New("version != 2")
} }
up, err := c.Up.Bps() if c.Congestion != nil || c.Up != nil || c.Down != nil || c.UdpHop != nil {
if err != nil { errors.LogWarning(context.Background(), "congestion & up & down & udphop move to finalmask/quicParams")
return nil, err
}
down, err := c.Down.Bps()
if err != nil {
return nil, err
} }
c.Congestion = strings.ToLower(c.Congestion)
if c.Congestion == "force-brutal" && up == 0 {
return nil, errors.New("force-brutal require up")
}
var hop *PortList
if err := json.Unmarshal(c.UdpHop.PortList, &hop); err != nil {
hop = &PortList{}
}
var inertvalMin, inertvalMax int64
if c.UdpHop.Interval != nil {
inertvalMin = int64(c.UdpHop.Interval.From)
inertvalMax = int64(c.UdpHop.Interval.To)
}
if up > 0 && up < 65536 {
return nil, errors.New("Up must be at least 65536 bytes per second")
}
if down > 0 && down < 65536 {
return nil, errors.New("Down must be at least 65536 bytes per second")
}
if (inertvalMin != 0 && inertvalMin < 5) || (inertvalMax != 0 && inertvalMax < 5) {
return nil, errors.New("Interval must be at least 5")
}
if c.InitStreamReceiveWindow > 0 && c.InitStreamReceiveWindow < 16384 {
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
}
if c.MaxStreamReceiveWindow > 0 && c.MaxStreamReceiveWindow < 16384 {
return nil, errors.New("MaxStreamReceiveWindow must be at least 16384")
}
if c.InitConnectionReceiveWindow > 0 && c.InitConnectionReceiveWindow < 16384 {
return nil, errors.New("InitConnectionReceiveWindow must be at least 16384")
}
if c.MaxConnectionReceiveWindow > 0 && c.MaxConnectionReceiveWindow < 16384 {
return nil, errors.New("MaxConnectionReceiveWindow must be at least 16384")
}
if c.MaxIdleTimeout != 0 && (c.MaxIdleTimeout < 4 || c.MaxIdleTimeout > 120) {
return nil, errors.New("MaxIdleTimeout must be between 4 and 120")
}
if c.KeepAlivePeriod != 0 && (c.KeepAlivePeriod < 2 || c.KeepAlivePeriod > 60) {
return nil, errors.New("KeepAlivePeriod must be between 2 and 60")
}
if c.MaxIncomingStreams != 0 && c.MaxIncomingStreams < 8 {
return nil, errors.New("MaxIncomingStreams must be at least 8")
}
if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) { if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) {
return nil, errors.New("UdpIdleTimeout must be between 2 and 600") return nil, errors.New("UdpIdleTimeout must be between 2 and 600")
} }
@@ -607,20 +548,6 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
config := &hysteria.Config{} config := &hysteria.Config{}
config.Version = c.Version config.Version = c.Version
config.Auth = c.Auth config.Auth = c.Auth
config.Congestion = c.Congestion
config.Up = up
config.Down = down
config.Ports = hop.Build().Ports()
config.IntervalMin = inertvalMin
config.IntervalMax = inertvalMax
config.InitStreamReceiveWindow = c.InitStreamReceiveWindow
config.MaxStreamReceiveWindow = c.MaxStreamReceiveWindow
config.InitConnReceiveWindow = c.InitConnectionReceiveWindow
config.MaxConnReceiveWindow = c.MaxConnectionReceiveWindow
config.MaxIdleTimeout = c.MaxIdleTimeout
config.KeepAlivePeriod = c.KeepAlivePeriod
config.DisablePathMtuDiscovery = c.DisablePathMTUDiscovery
config.MaxIncomingStreams = c.MaxIncomingStreams
config.UdpIdleTimeout = c.UdpIdleTimeout config.UdpIdleTimeout = c.UdpIdleTimeout
config.MasqType = c.Masquerade.Type config.MasqType = c.Masquerade.Type
config.MasqFile = c.Masquerade.Dir config.MasqFile = c.Masquerade.Dir
@@ -631,27 +558,6 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
config.MasqStringHeaders = c.Masquerade.Headers config.MasqStringHeaders = c.Masquerade.Headers
config.MasqStringStatusCode = c.Masquerade.StatusCode config.MasqStringStatusCode = c.Masquerade.StatusCode
if config.InitStreamReceiveWindow == 0 {
config.InitStreamReceiveWindow = 8388608
}
if config.MaxStreamReceiveWindow == 0 {
config.MaxStreamReceiveWindow = 8388608
}
if config.InitConnReceiveWindow == 0 {
config.InitConnReceiveWindow = 8388608 * 5 / 2
}
if config.MaxConnReceiveWindow == 0 {
config.MaxConnReceiveWindow = 8388608 * 5 / 2
}
if config.MaxIdleTimeout == 0 {
config.MaxIdleTimeout = 30
}
// if config.KeepAlivePeriod == 0 {
// config.KeepAlivePeriod = 10
// }
if config.MaxIncomingStreams == 0 {
config.MaxIncomingStreams = 1024
}
if config.UdpIdleTimeout == 0 { if config.UdpIdleTimeout == 0 {
config.UdpIdleTimeout = 60 config.UdpIdleTimeout = 60
} }
@@ -722,8 +628,19 @@ func (c *TLSCertConfig) Build() (*tls.Certificate, error) {
} }
type QuicParamsConfig struct { type QuicParamsConfig struct {
Congestion string `json:"congestion"` Congestion string `json:"congestion"`
Up Bandwidth `json:"up"` Debug bool `json:"debug"`
BrutalUp Bandwidth `json:"brutalUp"`
BrutalDown Bandwidth `json:"brutalDown"`
UdpHop UdpHop `json:"udpHop"`
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"`
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"`
InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"`
MaxConnectionReceiveWindow uint64 `json:"maxConnectionReceiveWindow"`
MaxIdleTimeout int64 `json:"maxIdleTimeout"`
KeepAlivePeriod int64 `json:"keepAlivePeriod"`
DisablePathMTUDiscovery bool `json:"disablePathMTUDiscovery"`
MaxIncomingStreams int64 `json:"maxIncomingStreams"`
} }
type TLSConfig struct { type TLSConfig struct {
@@ -1918,25 +1835,92 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u)) config.Udpmasks = append(config.Udpmasks, serial.ToTypedMessage(u))
} }
if c.FinalMask.QuicParams != nil { if c.FinalMask.QuicParams != nil {
up, err := c.FinalMask.QuicParams.Up.Bps() up, err := c.FinalMask.QuicParams.BrutalUp.Bps()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if up > 0 && up < 65536 { down, err := c.FinalMask.QuicParams.BrutalDown.Bps()
return nil, errors.New("Up must be at least 65536 bytes per second") if err != nil {
return nil, err
} }
if up > 0 && up < 65536 {
return nil, errors.New("BrutalUp must be at least 65536 bytes per second")
}
if down > 0 && down < 65536 {
return nil, errors.New("BrutalDown must be at least 65536 bytes per second")
}
c.FinalMask.QuicParams.Congestion = strings.ToLower(c.FinalMask.QuicParams.Congestion)
switch c.FinalMask.QuicParams.Congestion { switch c.FinalMask.QuicParams.Congestion {
case "", "bbr", "reno": case "", "brutal", "reno", "bbr":
case "force-brutal": case "force-brutal":
if up == 0 { if up == 0 {
return nil, errors.New("force-brutal requires up") return nil, errors.New("force-brutal requires up")
} }
default: default:
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: bbr, reno, force-brutal") return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
} }
var hop *PortList
if err := json.Unmarshal(c.FinalMask.QuicParams.UdpHop.PortList, &hop); err != nil {
hop = &PortList{}
}
var inertvalMin, inertvalMax int64
if c.FinalMask.QuicParams.UdpHop.Interval != nil {
inertvalMin = int64(c.FinalMask.QuicParams.UdpHop.Interval.From)
inertvalMax = int64(c.FinalMask.QuicParams.UdpHop.Interval.To)
}
if (inertvalMin != 0 && inertvalMin < 5) || (inertvalMax != 0 && inertvalMax < 5) {
return nil, errors.New("Interval must be at least 5")
}
if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 {
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
}
if c.FinalMask.QuicParams.MaxStreamReceiveWindow > 0 && c.FinalMask.QuicParams.MaxStreamReceiveWindow < 16384 {
return nil, errors.New("MaxStreamReceiveWindow must be at least 16384")
}
if c.FinalMask.QuicParams.InitConnectionReceiveWindow > 0 && c.FinalMask.QuicParams.InitConnectionReceiveWindow < 16384 {
return nil, errors.New("InitConnectionReceiveWindow must be at least 16384")
}
if c.FinalMask.QuicParams.MaxConnectionReceiveWindow > 0 && c.FinalMask.QuicParams.MaxConnectionReceiveWindow < 16384 {
return nil, errors.New("MaxConnectionReceiveWindow must be at least 16384")
}
if c.FinalMask.QuicParams.MaxIdleTimeout != 0 && (c.FinalMask.QuicParams.MaxIdleTimeout < 4 || c.FinalMask.QuicParams.MaxIdleTimeout > 120) {
return nil, errors.New("MaxIdleTimeout must be between 4 and 120")
}
if c.FinalMask.QuicParams.KeepAlivePeriod != 0 && (c.FinalMask.QuicParams.KeepAlivePeriod < 2 || c.FinalMask.QuicParams.KeepAlivePeriod > 60) {
return nil, errors.New("KeepAlivePeriod must be between 2 and 60")
}
if c.FinalMask.QuicParams.MaxIncomingStreams != 0 && c.FinalMask.QuicParams.MaxIncomingStreams < 8 {
return nil, errors.New("MaxIncomingStreams must be at least 8")
}
if c.FinalMask.QuicParams.Debug {
os.Setenv("HYSTERIA_BBR_DEBUG", "true")
os.Setenv("HYSTERIA_BRUTAL_DEBUG", "true")
}
config.QuicParams = &internet.QuicParams{ config.QuicParams = &internet.QuicParams{
Congestion: c.FinalMask.QuicParams.Congestion, Congestion: c.FinalMask.QuicParams.Congestion,
Up: up, BrutalUp: up,
BrutalDown: down,
UdpHop: &internet.UdpHop{
Ports: hop.Build().Ports(),
IntervalMin: inertvalMin,
IntervalMax: inertvalMax,
},
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
InitConnReceiveWindow: c.FinalMask.QuicParams.InitConnectionReceiveWindow,
MaxConnReceiveWindow: c.FinalMask.QuicParams.MaxConnectionReceiveWindow,
MaxIdleTimeout: c.FinalMask.QuicParams.MaxIdleTimeout,
KeepAlivePeriod: c.FinalMask.QuicParams.KeepAlivePeriod,
DisablePathMtuDiscovery: c.FinalMask.QuicParams.DisablePathMTUDiscovery,
MaxIncomingStreams: c.FinalMask.QuicParams.MaxIncomingStreams,
} }
} }
} }

View File

@@ -206,7 +206,7 @@ func (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber {
// Deprecated: Use SocketConfig_TProxyMode.Descriptor instead. // Deprecated: Use SocketConfig_TProxyMode.Descriptor instead.
func (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) { func (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{5, 0} return file_transport_internet_config_proto_rawDescGZIP(), []int{6, 0}
} }
type TransportConfig struct { type TransportConfig struct {
@@ -382,17 +382,87 @@ func (x *StreamConfig) GetSocketSettings() *SocketConfig {
return nil return nil
} }
type QuicParams struct { type UdpHop struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Congestion string `protobuf:"bytes,1,opt,name=congestion,proto3" json:"congestion,omitempty"` Ports []uint32 `protobuf:"varint,1,rep,packed,name=ports,proto3" json:"ports,omitempty"`
Up uint64 `protobuf:"varint,2,opt,name=up,proto3" json:"up,omitempty"` IntervalMin int64 `protobuf:"varint,2,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
IntervalMax int64 `protobuf:"varint,3,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
func (x *UdpHop) Reset() {
*x = UdpHop{}
mi := &file_transport_internet_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *UdpHop) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*UdpHop) ProtoMessage() {}
func (x *UdpHop) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use UdpHop.ProtoReflect.Descriptor instead.
func (*UdpHop) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{2}
}
func (x *UdpHop) GetPorts() []uint32 {
if x != nil {
return x.Ports
}
return nil
}
func (x *UdpHop) GetIntervalMin() int64 {
if x != nil {
return x.IntervalMin
}
return 0
}
func (x *UdpHop) GetIntervalMax() int64 {
if x != nil {
return x.IntervalMax
}
return 0
}
type QuicParams struct {
state protoimpl.MessageState `protogen:"open.v1"`
Congestion string `protobuf:"bytes,1,opt,name=congestion,proto3" json:"congestion,omitempty"`
BrutalUp uint64 `protobuf:"varint,2,opt,name=brutal_up,json=brutalUp,proto3" json:"brutal_up,omitempty"`
BrutalDown uint64 `protobuf:"varint,3,opt,name=brutal_down,json=brutalDown,proto3" json:"brutal_down,omitempty"`
UdpHop *UdpHop `protobuf:"bytes,4,opt,name=udp_hop,json=udpHop,proto3" json:"udp_hop,omitempty"`
InitStreamReceiveWindow uint64 `protobuf:"varint,5,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
MaxStreamReceiveWindow uint64 `protobuf:"varint,6,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
InitConnReceiveWindow uint64 `protobuf:"varint,7,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
MaxConnReceiveWindow uint64 `protobuf:"varint,8,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
MaxIdleTimeout int64 `protobuf:"varint,9,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
KeepAlivePeriod int64 `protobuf:"varint,10,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
DisablePathMtuDiscovery bool `protobuf:"varint,11,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
MaxIncomingStreams int64 `protobuf:"varint,12,opt,name=max_incoming_streams,json=maxIncomingStreams,proto3" json:"max_incoming_streams,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *QuicParams) Reset() { func (x *QuicParams) Reset() {
*x = QuicParams{} *x = QuicParams{}
mi := &file_transport_internet_config_proto_msgTypes[2] mi := &file_transport_internet_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -404,7 +474,7 @@ func (x *QuicParams) String() string {
func (*QuicParams) ProtoMessage() {} func (*QuicParams) ProtoMessage() {}
func (x *QuicParams) ProtoReflect() protoreflect.Message { func (x *QuicParams) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[2] mi := &file_transport_internet_config_proto_msgTypes[3]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -417,7 +487,7 @@ func (x *QuicParams) ProtoReflect() protoreflect.Message {
// Deprecated: Use QuicParams.ProtoReflect.Descriptor instead. // Deprecated: Use QuicParams.ProtoReflect.Descriptor instead.
func (*QuicParams) Descriptor() ([]byte, []int) { func (*QuicParams) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{2} return file_transport_internet_config_proto_rawDescGZIP(), []int{3}
} }
func (x *QuicParams) GetCongestion() string { func (x *QuicParams) GetCongestion() string {
@@ -427,9 +497,79 @@ func (x *QuicParams) GetCongestion() string {
return "" return ""
} }
func (x *QuicParams) GetUp() uint64 { func (x *QuicParams) GetBrutalUp() uint64 {
if x != nil { if x != nil {
return x.Up return x.BrutalUp
}
return 0
}
func (x *QuicParams) GetBrutalDown() uint64 {
if x != nil {
return x.BrutalDown
}
return 0
}
func (x *QuicParams) GetUdpHop() *UdpHop {
if x != nil {
return x.UdpHop
}
return nil
}
func (x *QuicParams) GetInitStreamReceiveWindow() uint64 {
if x != nil {
return x.InitStreamReceiveWindow
}
return 0
}
func (x *QuicParams) GetMaxStreamReceiveWindow() uint64 {
if x != nil {
return x.MaxStreamReceiveWindow
}
return 0
}
func (x *QuicParams) GetInitConnReceiveWindow() uint64 {
if x != nil {
return x.InitConnReceiveWindow
}
return 0
}
func (x *QuicParams) GetMaxConnReceiveWindow() uint64 {
if x != nil {
return x.MaxConnReceiveWindow
}
return 0
}
func (x *QuicParams) GetMaxIdleTimeout() int64 {
if x != nil {
return x.MaxIdleTimeout
}
return 0
}
func (x *QuicParams) GetKeepAlivePeriod() int64 {
if x != nil {
return x.KeepAlivePeriod
}
return 0
}
func (x *QuicParams) GetDisablePathMtuDiscovery() bool {
if x != nil {
return x.DisablePathMtuDiscovery
}
return false
}
func (x *QuicParams) GetMaxIncomingStreams() int64 {
if x != nil {
return x.MaxIncomingStreams
} }
return 0 return 0
} }
@@ -444,7 +584,7 @@ type ProxyConfig struct {
func (x *ProxyConfig) Reset() { func (x *ProxyConfig) Reset() {
*x = ProxyConfig{} *x = ProxyConfig{}
mi := &file_transport_internet_config_proto_msgTypes[3] mi := &file_transport_internet_config_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -456,7 +596,7 @@ func (x *ProxyConfig) String() string {
func (*ProxyConfig) ProtoMessage() {} func (*ProxyConfig) ProtoMessage() {}
func (x *ProxyConfig) ProtoReflect() protoreflect.Message { func (x *ProxyConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[3] mi := &file_transport_internet_config_proto_msgTypes[4]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -469,7 +609,7 @@ func (x *ProxyConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use ProxyConfig.ProtoReflect.Descriptor instead. // Deprecated: Use ProxyConfig.ProtoReflect.Descriptor instead.
func (*ProxyConfig) Descriptor() ([]byte, []int) { func (*ProxyConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{3} return file_transport_internet_config_proto_rawDescGZIP(), []int{4}
} }
func (x *ProxyConfig) GetTag() string { func (x *ProxyConfig) GetTag() string {
@@ -500,7 +640,7 @@ type CustomSockopt struct {
func (x *CustomSockopt) Reset() { func (x *CustomSockopt) Reset() {
*x = CustomSockopt{} *x = CustomSockopt{}
mi := &file_transport_internet_config_proto_msgTypes[4] mi := &file_transport_internet_config_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -512,7 +652,7 @@ func (x *CustomSockopt) String() string {
func (*CustomSockopt) ProtoMessage() {} func (*CustomSockopt) ProtoMessage() {}
func (x *CustomSockopt) ProtoReflect() protoreflect.Message { func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[4] mi := &file_transport_internet_config_proto_msgTypes[5]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -525,7 +665,7 @@ func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
// Deprecated: Use CustomSockopt.ProtoReflect.Descriptor instead. // Deprecated: Use CustomSockopt.ProtoReflect.Descriptor instead.
func (*CustomSockopt) Descriptor() ([]byte, []int) { func (*CustomSockopt) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{4} return file_transport_internet_config_proto_rawDescGZIP(), []int{5}
} }
func (x *CustomSockopt) GetSystem() string { func (x *CustomSockopt) GetSystem() string {
@@ -607,7 +747,7 @@ type SocketConfig struct {
func (x *SocketConfig) Reset() { func (x *SocketConfig) Reset() {
*x = SocketConfig{} *x = SocketConfig{}
mi := &file_transport_internet_config_proto_msgTypes[5] mi := &file_transport_internet_config_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -619,7 +759,7 @@ func (x *SocketConfig) String() string {
func (*SocketConfig) ProtoMessage() {} func (*SocketConfig) ProtoMessage() {}
func (x *SocketConfig) ProtoReflect() protoreflect.Message { func (x *SocketConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[5] mi := &file_transport_internet_config_proto_msgTypes[6]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -632,7 +772,7 @@ func (x *SocketConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead. // Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead.
func (*SocketConfig) Descriptor() ([]byte, []int) { func (*SocketConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{5} return file_transport_internet_config_proto_rawDescGZIP(), []int{6}
} }
func (x *SocketConfig) GetMark() int32 { func (x *SocketConfig) GetMark() int32 {
@@ -808,7 +948,7 @@ type HappyEyeballsConfig struct {
func (x *HappyEyeballsConfig) Reset() { func (x *HappyEyeballsConfig) Reset() {
*x = HappyEyeballsConfig{} *x = HappyEyeballsConfig{}
mi := &file_transport_internet_config_proto_msgTypes[6] mi := &file_transport_internet_config_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@@ -820,7 +960,7 @@ func (x *HappyEyeballsConfig) String() string {
func (*HappyEyeballsConfig) ProtoMessage() {} func (*HappyEyeballsConfig) ProtoMessage() {}
func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message { func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
mi := &file_transport_internet_config_proto_msgTypes[6] mi := &file_transport_internet_config_proto_msgTypes[7]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@@ -833,7 +973,7 @@ func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
// Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead. // Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead.
func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) { func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) {
return file_transport_internet_config_proto_rawDescGZIP(), []int{6} return file_transport_internet_config_proto_rawDescGZIP(), []int{7}
} }
func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool { func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool {
@@ -884,13 +1024,29 @@ const file_transport_internet_config_proto_rawDesc = "" +
"\btcpmasks\x18\v \x03(\v2 .xray.common.serial.TypedMessageR\btcpmasks\x12D\n" + "\btcpmasks\x18\v \x03(\v2 .xray.common.serial.TypedMessageR\btcpmasks\x12D\n" +
"\vquic_params\x18\f \x01(\v2#.xray.transport.internet.QuicParamsR\n" + "\vquic_params\x18\f \x01(\v2#.xray.transport.internet.QuicParamsR\n" +
"quicParams\x12N\n" + "quicParams\x12N\n" +
"\x0fsocket_settings\x18\x06 \x01(\v2%.xray.transport.internet.SocketConfigR\x0esocketSettings\"<\n" + "\x0fsocket_settings\x18\x06 \x01(\v2%.xray.transport.internet.SocketConfigR\x0esocketSettings\"d\n" +
"\x06UdpHop\x12\x14\n" +
"\x05ports\x18\x01 \x03(\rR\x05ports\x12!\n" +
"\finterval_min\x18\x02 \x01(\x03R\vintervalMin\x12!\n" +
"\finterval_max\x18\x03 \x01(\x03R\vintervalMax\"\xd1\x04\n" +
"\n" + "\n" +
"QuicParams\x12\x1e\n" + "QuicParams\x12\x1e\n" +
"\n" + "\n" +
"congestion\x18\x01 \x01(\tR\n" + "congestion\x18\x01 \x01(\tR\n" +
"congestion\x12\x0e\n" + "congestion\x12\x1b\n" +
"\x02up\x18\x02 \x01(\x04R\x02up\"Q\n" + "\tbrutal_up\x18\x02 \x01(\x04R\bbrutalUp\x12\x1f\n" +
"\vbrutal_down\x18\x03 \x01(\x04R\n" +
"brutalDown\x128\n" +
"\audp_hop\x18\x04 \x01(\v2\x1f.xray.transport.internet.UdpHopR\x06udpHop\x12;\n" +
"\x1ainit_stream_receive_window\x18\x05 \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
"\x19max_stream_receive_window\x18\x06 \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
"\x18init_conn_receive_window\x18\a \x01(\x04R\x15initConnReceiveWindow\x125\n" +
"\x17max_conn_receive_window\x18\b \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
"\x10max_idle_timeout\x18\t \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
"\x11keep_alive_period\x18\n" +
" \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
"\x1adisable_path_mtu_discovery\x18\v \x01(\bR\x17disablePathMtuDiscovery\x120\n" +
"\x14max_incoming_streams\x18\f \x01(\x03R\x12maxIncomingStreams\"Q\n" +
"\vProxyConfig\x12\x10\n" + "\vProxyConfig\x12\x10\n" +
"\x03tag\x18\x01 \x01(\tR\x03tag\x120\n" + "\x03tag\x18\x01 \x01(\tR\x03tag\x120\n" +
"\x13transportLayerProxy\x18\x02 \x01(\bR\x13transportLayerProxy\"\x93\x01\n" + "\x13transportLayerProxy\x18\x02 \x01(\bR\x13transportLayerProxy\"\x93\x01\n" +
@@ -979,40 +1135,42 @@ func file_transport_internet_config_proto_rawDescGZIP() []byte {
} }
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3) var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
var file_transport_internet_config_proto_goTypes = []any{ var file_transport_internet_config_proto_goTypes = []any{
(DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy (DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy
(AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy (AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy
(SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode (SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode
(*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig (*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig
(*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig (*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig
(*QuicParams)(nil), // 5: xray.transport.internet.QuicParams (*UdpHop)(nil), // 5: xray.transport.internet.UdpHop
(*ProxyConfig)(nil), // 6: xray.transport.internet.ProxyConfig (*QuicParams)(nil), // 6: xray.transport.internet.QuicParams
(*CustomSockopt)(nil), // 7: xray.transport.internet.CustomSockopt (*ProxyConfig)(nil), // 7: xray.transport.internet.ProxyConfig
(*SocketConfig)(nil), // 8: xray.transport.internet.SocketConfig (*CustomSockopt)(nil), // 8: xray.transport.internet.CustomSockopt
(*HappyEyeballsConfig)(nil), // 9: xray.transport.internet.HappyEyeballsConfig (*SocketConfig)(nil), // 9: xray.transport.internet.SocketConfig
(*serial.TypedMessage)(nil), // 10: xray.common.serial.TypedMessage (*HappyEyeballsConfig)(nil), // 10: xray.transport.internet.HappyEyeballsConfig
(*net.IPOrDomain)(nil), // 11: xray.common.net.IPOrDomain (*serial.TypedMessage)(nil), // 11: xray.common.serial.TypedMessage
(*net.IPOrDomain)(nil), // 12: xray.common.net.IPOrDomain
} }
var file_transport_internet_config_proto_depIdxs = []int32{ var file_transport_internet_config_proto_depIdxs = []int32{
10, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage 11, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
11, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain 12, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig 3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
10, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage 11, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
10, // 4: xray.transport.internet.StreamConfig.udpmasks:type_name -> xray.common.serial.TypedMessage 11, // 4: xray.transport.internet.StreamConfig.udpmasks:type_name -> xray.common.serial.TypedMessage
10, // 5: xray.transport.internet.StreamConfig.tcpmasks:type_name -> xray.common.serial.TypedMessage 11, // 5: xray.transport.internet.StreamConfig.tcpmasks:type_name -> xray.common.serial.TypedMessage
5, // 6: xray.transport.internet.StreamConfig.quic_params:type_name -> xray.transport.internet.QuicParams 6, // 6: xray.transport.internet.StreamConfig.quic_params:type_name -> xray.transport.internet.QuicParams
8, // 7: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig 9, // 7: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
2, // 8: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode 5, // 8: xray.transport.internet.QuicParams.udp_hop:type_name -> xray.transport.internet.UdpHop
0, // 9: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy 2, // 9: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
7, // 10: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt 0, // 10: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
1, // 11: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy 8, // 11: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
9, // 12: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig 1, // 12: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy
13, // [13:13] is the sub-list for method output_type 10, // 13: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig
13, // [13:13] is the sub-list for method input_type 14, // [14:14] is the sub-list for method output_type
13, // [13:13] is the sub-list for extension type_name 14, // [14:14] is the sub-list for method input_type
13, // [13:13] is the sub-list for extension extendee 14, // [14:14] is the sub-list for extension type_name
0, // [0:13] is the sub-list for field type_name 14, // [14:14] is the sub-list for extension extendee
0, // [0:14] is the sub-list for field type_name
} }
func init() { file_transport_internet_config_proto_init() } func init() { file_transport_internet_config_proto_init() }
@@ -1026,7 +1184,7 @@ func file_transport_internet_config_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_config_proto_rawDesc), len(file_transport_internet_config_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_config_proto_rawDesc), len(file_transport_internet_config_proto_rawDesc)),
NumEnums: 3, NumEnums: 3,
NumMessages: 7, NumMessages: 8,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View File

@@ -64,9 +64,25 @@ message StreamConfig {
SocketConfig socket_settings = 6; SocketConfig socket_settings = 6;
} }
message UdpHop {
repeated uint32 ports = 1;
int64 interval_min = 2;
int64 interval_max = 3;
}
message QuicParams { message QuicParams {
string congestion = 1; string congestion = 1;
uint64 up = 2; uint64 brutal_up = 2;
uint64 brutal_down = 3;
UdpHop udp_hop = 4;
uint64 init_stream_receive_window = 5;
uint64 max_stream_receive_window = 6;
uint64 init_conn_receive_window = 7;
uint64 max_conn_receive_window = 8;
int64 max_idle_timeout = 9;
int64 keep_alive_period = 10;
bool disable_path_mtu_discovery = 11;
int64 max_incoming_streams = 12;
} }
message ProxyConfig { message ProxyConfig {

View File

@@ -372,9 +372,6 @@ func runHysteria2Case(t *testing.T, bin string, mode trafficMode, payloadSize in
Settings: serial.ToTypedMessage(&hytransport.Config{ Settings: serial.ToTypedMessage(&hytransport.Config{
Version: 2, Version: 2,
Auth: auth, Auth: auth,
Congestion: "bbr",
Up: 10 * 1024 * 1024,
Down: 10 * 1024 * 1024,
UdpIdleTimeout: 60, UdpIdleTimeout: 60,
}), }),
}, },
@@ -438,9 +435,6 @@ func runHysteria2Case(t *testing.T, bin string, mode trafficMode, payloadSize in
Settings: serial.ToTypedMessage(&hytransport.Config{ Settings: serial.ToTypedMessage(&hytransport.Config{
Version: 2, Version: 2,
Auth: auth, Auth: auth,
Congestion: "bbr",
Up: 10 * 1024 * 1024,
Down: 10 * 1024 * 1024,
UdpIdleTimeout: 60, UdpIdleTimeout: 60,
}), }),
}, },

View File

@@ -22,34 +22,20 @@ const (
) )
type Config struct { type Config struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
Auth string `protobuf:"bytes,2,opt,name=auth,proto3" json:"auth,omitempty"` Auth string `protobuf:"bytes,2,opt,name=auth,proto3" json:"auth,omitempty"`
Congestion string `protobuf:"bytes,3,opt,name=congestion,proto3" json:"congestion,omitempty"` UdpIdleTimeout int64 `protobuf:"varint,3,opt,name=udp_idle_timeout,json=udpIdleTimeout,proto3" json:"udp_idle_timeout,omitempty"`
Up uint64 `protobuf:"varint,4,opt,name=up,proto3" json:"up,omitempty"` MasqType string `protobuf:"bytes,4,opt,name=masq_type,json=masqType,proto3" json:"masq_type,omitempty"`
Down uint64 `protobuf:"varint,5,opt,name=down,proto3" json:"down,omitempty"` MasqFile string `protobuf:"bytes,5,opt,name=masq_file,json=masqFile,proto3" json:"masq_file,omitempty"`
Ports []uint32 `protobuf:"varint,6,rep,packed,name=ports,proto3" json:"ports,omitempty"` MasqUrl string `protobuf:"bytes,6,opt,name=masq_url,json=masqUrl,proto3" json:"masq_url,omitempty"`
IntervalMin int64 `protobuf:"varint,7,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"` MasqUrlRewriteHost bool `protobuf:"varint,7,opt,name=masq_url_rewrite_host,json=masqUrlRewriteHost,proto3" json:"masq_url_rewrite_host,omitempty"`
IntervalMax int64 `protobuf:"varint,8,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"` MasqUrlInsecure bool `protobuf:"varint,8,opt,name=masq_url_insecure,json=masqUrlInsecure,proto3" json:"masq_url_insecure,omitempty"`
InitStreamReceiveWindow uint64 `protobuf:"varint,9,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"` MasqString string `protobuf:"bytes,9,opt,name=masq_string,json=masqString,proto3" json:"masq_string,omitempty"`
MaxStreamReceiveWindow uint64 `protobuf:"varint,10,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"` MasqStringHeaders map[string]string `protobuf:"bytes,10,rep,name=masq_string_headers,json=masqStringHeaders,proto3" json:"masq_string_headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
InitConnReceiveWindow uint64 `protobuf:"varint,11,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"` MasqStringStatusCode int32 `protobuf:"varint,11,opt,name=masq_string_status_code,json=masqStringStatusCode,proto3" json:"masq_string_status_code,omitempty"`
MaxConnReceiveWindow uint64 `protobuf:"varint,12,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"` unknownFields protoimpl.UnknownFields
MaxIdleTimeout int64 `protobuf:"varint,13,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"` sizeCache protoimpl.SizeCache
KeepAlivePeriod int64 `protobuf:"varint,14,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
DisablePathMtuDiscovery bool `protobuf:"varint,15,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
MaxIncomingStreams int64 `protobuf:"varint,16,opt,name=max_incoming_streams,json=maxIncomingStreams,proto3" json:"max_incoming_streams,omitempty"`
UdpIdleTimeout int64 `protobuf:"varint,17,opt,name=udp_idle_timeout,json=udpIdleTimeout,proto3" json:"udp_idle_timeout,omitempty"`
MasqType string `protobuf:"bytes,18,opt,name=masq_type,json=masqType,proto3" json:"masq_type,omitempty"`
MasqFile string `protobuf:"bytes,19,opt,name=masq_file,json=masqFile,proto3" json:"masq_file,omitempty"`
MasqUrl string `protobuf:"bytes,20,opt,name=masq_url,json=masqUrl,proto3" json:"masq_url,omitempty"`
MasqUrlRewriteHost bool `protobuf:"varint,21,opt,name=masq_url_rewrite_host,json=masqUrlRewriteHost,proto3" json:"masq_url_rewrite_host,omitempty"`
MasqUrlInsecure bool `protobuf:"varint,22,opt,name=masq_url_insecure,json=masqUrlInsecure,proto3" json:"masq_url_insecure,omitempty"`
MasqString string `protobuf:"bytes,23,opt,name=masq_string,json=masqString,proto3" json:"masq_string,omitempty"`
MasqStringHeaders map[string]string `protobuf:"bytes,24,rep,name=masq_string_headers,json=masqStringHeaders,proto3" json:"masq_string_headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
MasqStringStatusCode int32 `protobuf:"varint,25,opt,name=masq_string_status_code,json=masqStringStatusCode,proto3" json:"masq_string_status_code,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
} }
func (x *Config) Reset() { func (x *Config) Reset() {
@@ -96,104 +82,6 @@ func (x *Config) GetAuth() string {
return "" return ""
} }
func (x *Config) GetCongestion() string {
if x != nil {
return x.Congestion
}
return ""
}
func (x *Config) GetUp() uint64 {
if x != nil {
return x.Up
}
return 0
}
func (x *Config) GetDown() uint64 {
if x != nil {
return x.Down
}
return 0
}
func (x *Config) GetPorts() []uint32 {
if x != nil {
return x.Ports
}
return nil
}
func (x *Config) GetIntervalMin() int64 {
if x != nil {
return x.IntervalMin
}
return 0
}
func (x *Config) GetIntervalMax() int64 {
if x != nil {
return x.IntervalMax
}
return 0
}
func (x *Config) GetInitStreamReceiveWindow() uint64 {
if x != nil {
return x.InitStreamReceiveWindow
}
return 0
}
func (x *Config) GetMaxStreamReceiveWindow() uint64 {
if x != nil {
return x.MaxStreamReceiveWindow
}
return 0
}
func (x *Config) GetInitConnReceiveWindow() uint64 {
if x != nil {
return x.InitConnReceiveWindow
}
return 0
}
func (x *Config) GetMaxConnReceiveWindow() uint64 {
if x != nil {
return x.MaxConnReceiveWindow
}
return 0
}
func (x *Config) GetMaxIdleTimeout() int64 {
if x != nil {
return x.MaxIdleTimeout
}
return 0
}
func (x *Config) GetKeepAlivePeriod() int64 {
if x != nil {
return x.KeepAlivePeriod
}
return 0
}
func (x *Config) GetDisablePathMtuDiscovery() bool {
if x != nil {
return x.DisablePathMtuDiscovery
}
return false
}
func (x *Config) GetMaxIncomingStreams() int64 {
if x != nil {
return x.MaxIncomingStreams
}
return 0
}
func (x *Config) GetUdpIdleTimeout() int64 { func (x *Config) GetUdpIdleTimeout() int64 {
if x != nil { if x != nil {
return x.UdpIdleTimeout return x.UdpIdleTimeout
@@ -261,37 +149,21 @@ var File_transport_internet_hysteria_config_proto protoreflect.FileDescriptor
const file_transport_internet_hysteria_config_proto_rawDesc = "" + const file_transport_internet_hysteria_config_proto_rawDesc = "" +
"\n" + "\n" +
"(transport/internet/hysteria/config.proto\x12 xray.transport.internet.hysteria\"\xf0\b\n" + "(transport/internet/hysteria/config.proto\x12 xray.transport.internet.hysteria\"\xa3\x04\n" +
"\x06Config\x12\x18\n" + "\x06Config\x12\x18\n" +
"\aversion\x18\x01 \x01(\x05R\aversion\x12\x12\n" + "\aversion\x18\x01 \x01(\x05R\aversion\x12\x12\n" +
"\x04auth\x18\x02 \x01(\tR\x04auth\x12\x1e\n" + "\x04auth\x18\x02 \x01(\tR\x04auth\x12(\n" +
"\n" + "\x10udp_idle_timeout\x18\x03 \x01(\x03R\x0eudpIdleTimeout\x12\x1b\n" +
"congestion\x18\x03 \x01(\tR\n" + "\tmasq_type\x18\x04 \x01(\tR\bmasqType\x12\x1b\n" +
"congestion\x12\x0e\n" + "\tmasq_file\x18\x05 \x01(\tR\bmasqFile\x12\x19\n" +
"\x02up\x18\x04 \x01(\x04R\x02up\x12\x12\n" + "\bmasq_url\x18\x06 \x01(\tR\amasqUrl\x121\n" +
"\x04down\x18\x05 \x01(\x04R\x04down\x12\x14\n" + "\x15masq_url_rewrite_host\x18\a \x01(\bR\x12masqUrlRewriteHost\x12*\n" +
"\x05ports\x18\x06 \x03(\rR\x05ports\x12!\n" + "\x11masq_url_insecure\x18\b \x01(\bR\x0fmasqUrlInsecure\x12\x1f\n" +
"\finterval_min\x18\a \x01(\x03R\vintervalMin\x12!\n" + "\vmasq_string\x18\t \x01(\tR\n" +
"\finterval_max\x18\b \x01(\x03R\vintervalMax\x12;\n" +
"\x1ainit_stream_receive_window\x18\t \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
"\x19max_stream_receive_window\x18\n" +
" \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
"\x18init_conn_receive_window\x18\v \x01(\x04R\x15initConnReceiveWindow\x125\n" +
"\x17max_conn_receive_window\x18\f \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
"\x10max_idle_timeout\x18\r \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
"\x11keep_alive_period\x18\x0e \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
"\x1adisable_path_mtu_discovery\x18\x0f \x01(\bR\x17disablePathMtuDiscovery\x120\n" +
"\x14max_incoming_streams\x18\x10 \x01(\x03R\x12maxIncomingStreams\x12(\n" +
"\x10udp_idle_timeout\x18\x11 \x01(\x03R\x0eudpIdleTimeout\x12\x1b\n" +
"\tmasq_type\x18\x12 \x01(\tR\bmasqType\x12\x1b\n" +
"\tmasq_file\x18\x13 \x01(\tR\bmasqFile\x12\x19\n" +
"\bmasq_url\x18\x14 \x01(\tR\amasqUrl\x121\n" +
"\x15masq_url_rewrite_host\x18\x15 \x01(\bR\x12masqUrlRewriteHost\x12*\n" +
"\x11masq_url_insecure\x18\x16 \x01(\bR\x0fmasqUrlInsecure\x12\x1f\n" +
"\vmasq_string\x18\x17 \x01(\tR\n" +
"masqString\x12o\n" + "masqString\x12o\n" +
"\x13masq_string_headers\x18\x18 \x03(\v2?.xray.transport.internet.hysteria.Config.MasqStringHeadersEntryR\x11masqStringHeaders\x125\n" + "\x13masq_string_headers\x18\n" +
"\x17masq_string_status_code\x18\x19 \x01(\x05R\x14masqStringStatusCode\x1aD\n" + " \x03(\v2?.xray.transport.internet.hysteria.Config.MasqStringHeadersEntryR\x11masqStringHeaders\x125\n" +
"\x17masq_string_status_code\x18\v \x01(\x05R\x14masqStringStatusCode\x1aD\n" +
"\x16MasqStringHeadersEntry\x12\x10\n" + "\x16MasqStringHeadersEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x82\x01\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x82\x01\n" +

View File

@@ -9,29 +9,14 @@ option java_multiple_files = true;
message Config { message Config {
int32 version = 1; int32 version = 1;
string auth = 2; string auth = 2;
string congestion = 3;
uint64 up = 4;
uint64 down = 5;
repeated uint32 ports = 6;
int64 interval_min = 7;
int64 interval_max = 8;
uint64 init_stream_receive_window = 9; int64 udp_idle_timeout = 3;
uint64 max_stream_receive_window = 10; string masq_type = 4;
uint64 init_conn_receive_window = 11; string masq_file = 5;
uint64 max_conn_receive_window = 12; string masq_url = 6;
int64 max_idle_timeout = 13; bool masq_url_rewrite_host = 7;
int64 keep_alive_period = 14; bool masq_url_insecure = 8;
bool disable_path_mtu_discovery = 15; string masq_string = 9;
int64 max_incoming_streams = 16; map<string, string> masq_string_headers = 10;
int32 masq_string_status_code = 11;
int64 udp_idle_timeout = 17;
string masq_type = 18;
string masq_file = 19;
string masq_url = 20;
bool masq_url_rewrite_host = 21;
bool masq_url_insecure = 22;
string masq_string = 23;
map<string, string> masq_string_headers = 24;
int32 masq_string_status_code = 25;
} }

View File

@@ -120,8 +120,10 @@ type client struct {
tlsConfig *go_tls.Config tlsConfig *go_tls.Config
socketConfig *internet.SocketConfig socketConfig *internet.SocketConfig
udpmaskManager *finalmask.UdpmaskManager udpmaskManager *finalmask.UdpmaskManager
udpSM *udpSessionManagerClient quicParams *internet.QuicParams
mutex sync.Mutex
udpSM *udpSessionManagerClient
mutex sync.Mutex
} }
func (c *client) status() Status { func (c *client) status() Status {
@@ -153,10 +155,18 @@ func (c *client) dial() error {
c.close() c.close()
} }
quicParams := c.quicParams
if quicParams == nil {
quicParams = &internet.QuicParams{}
}
if quicParams.UdpHop == nil {
quicParams.UdpHop = &internet.UdpHop{}
}
var index int var index int
if len(c.config.Ports) > 0 { if len(quicParams.UdpHop.Ports) > 0 {
index = rand.Intn(len(c.config.Ports)) index = rand.Intn(len(quicParams.UdpHop.Ports))
c.dest.Port = net.Port(c.config.Ports[index]) c.dest.Port = net.Port(quicParams.UdpHop.Ports[index])
} }
raw, err := internet.DialSystem(c.ctx, c.dest, c.socketConfig) raw, err := internet.DialSystem(c.ctx, c.dest, c.socketConfig)
@@ -179,7 +189,7 @@ func (c *client) dial() error {
pktConn = fakeConn pktConn = fakeConn
remote = fakeConn.RemoteAddr().(*net.UDPAddr) remote = fakeConn.RemoteAddr().(*net.UDPAddr)
if len(c.config.Ports) > 0 { if len(quicParams.UdpHop.Ports) > 0 {
raw.Close() raw.Close()
return errors.New("udphop requires being at the outermost level") return errors.New("udphop requires being at the outermost level")
} }
@@ -188,12 +198,12 @@ func (c *client) dial() error {
return errors.New("unknown conn ", reflect.TypeOf(conn)) return errors.New("unknown conn ", reflect.TypeOf(conn))
} }
if len(c.config.Ports) > 0 { if len(quicParams.UdpHop.Ports) > 0 {
addr := &udphop.UDPHopAddr{ addr := &udphop.UDPHopAddr{
IP: remote.IP, IP: remote.IP,
Ports: c.config.Ports, Ports: quicParams.UdpHop.Ports,
} }
pktConn, err = udphop.NewUDPHopPacketConn(addr, c.config.IntervalMin, c.config.IntervalMax, c.udphopDialer, pktConn, index) pktConn, err = udphop.NewUDPHopPacketConn(addr, index, quicParams.UdpHop.IntervalMin, quicParams.UdpHop.IntervalMax, c.udphopDialer, pktConn)
if err != nil { if err != nil {
raw.Close() raw.Close()
return errors.New("udphop err").Base(err) return errors.New("udphop err").Base(err)
@@ -208,21 +218,41 @@ func (c *client) dial() error {
} }
} }
quicConfig := &quic.Config{
InitialStreamReceiveWindow: quicParams.InitStreamReceiveWindow,
MaxStreamReceiveWindow: quicParams.MaxStreamReceiveWindow,
InitialConnectionReceiveWindow: quicParams.InitConnReceiveWindow,
MaxConnectionReceiveWindow: quicParams.MaxConnReceiveWindow,
MaxIdleTimeout: time.Duration(quicParams.MaxIdleTimeout) * time.Second,
KeepAlivePeriod: time.Duration(quicParams.KeepAlivePeriod) * time.Second,
DisablePathMTUDiscovery: quicParams.DisablePathMtuDiscovery,
EnableDatagrams: true,
MaxDatagramFrameSize: MaxDatagramFrameSize,
DisablePathManager: true,
}
if quicParams.InitStreamReceiveWindow == 0 {
quicConfig.InitialStreamReceiveWindow = 8388608
}
if quicParams.MaxStreamReceiveWindow == 0 {
quicConfig.MaxStreamReceiveWindow = 8388608
}
if quicParams.InitConnReceiveWindow == 0 {
quicConfig.InitialConnectionReceiveWindow = 8388608 * 5 / 2
}
if quicParams.MaxConnReceiveWindow == 0 {
quicConfig.MaxConnectionReceiveWindow = 8388608 * 5 / 2
}
if quicParams.MaxIdleTimeout == 0 {
quicConfig.MaxIdleTimeout = 30 * time.Second
}
// if quicParams.KeepAlivePeriod == 0 {
// quicConfig.KeepAlivePeriod = 10 * time.Second
// }
var quicConn *quic.Conn var quicConn *quic.Conn
rt := &http3.Transport{ rt := &http3.Transport{
TLSClientConfig: c.tlsConfig, TLSClientConfig: c.tlsConfig,
QUICConfig: &quic.Config{ QUICConfig: quicConfig,
InitialStreamReceiveWindow: c.config.InitStreamReceiveWindow,
MaxStreamReceiveWindow: c.config.MaxStreamReceiveWindow,
InitialConnectionReceiveWindow: c.config.InitConnReceiveWindow,
MaxConnectionReceiveWindow: c.config.MaxConnReceiveWindow,
MaxIdleTimeout: time.Duration(c.config.MaxIdleTimeout) * time.Second,
KeepAlivePeriod: time.Duration(c.config.KeepAlivePeriod) * time.Second,
DisablePathMTUDiscovery: c.config.DisablePathMtuDiscovery,
EnableDatagrams: true,
MaxDatagramFrameSize: MaxDatagramFrameSize,
DisablePathManager: true,
},
Dial: func(ctx context.Context, _ string, tlsCfg *go_tls.Config, cfg *quic.Config) (*quic.Conn, error) { Dial: func(ctx context.Context, _ string, tlsCfg *go_tls.Config, cfg *quic.Config) (*quic.Conn, error) {
qc, err := quic.DialEarly(ctx, pktConn, remote, tlsCfg, cfg) qc, err := quic.DialEarly(ctx, pktConn, remote, tlsCfg, cfg)
if err != nil { if err != nil {
@@ -241,7 +271,7 @@ func (c *client) dial() error {
}, },
Header: http.Header{ Header: http.Header{
RequestHeaderAuth: []string{c.config.Auth}, RequestHeaderAuth: []string{c.config.Auth},
CommonHeaderCCRX: []string{strconv.FormatUint(c.config.Down, 10)}, CommonHeaderCCRX: []string{strconv.FormatUint(quicParams.BrutalDown, 10)},
CommonHeaderPadding: []string{authRequestPadding.String()}, CommonHeaderPadding: []string{authRequestPadding.String()},
}, },
} }
@@ -264,23 +294,23 @@ func (c *client) dial() error {
serverAuto := resp.Header.Get(CommonHeaderCCRX) serverAuto := resp.Header.Get(CommonHeaderCCRX)
serverDown, _ := strconv.ParseUint(serverAuto, 10, 64) serverDown, _ := strconv.ParseUint(serverAuto, 10, 64)
switch c.config.Congestion { switch quicParams.Congestion {
case "reno": case "reno":
errors.LogDebug(c.ctx, "congestion reno") errors.LogDebug(c.ctx, "congestion reno")
case "bbr": case "bbr":
errors.LogDebug(c.ctx, "congestion bbr") errors.LogDebug(c.ctx, "congestion bbr")
congestion.UseBBR(quicConn) congestion.UseBBR(quicConn)
case "brutal", "": case "brutal", "":
if serverAuto == "auto" || c.config.Up == 0 || serverDown == 0 { if serverAuto == "auto" || quicParams.BrutalUp == 0 || serverDown == 0 {
errors.LogDebug(c.ctx, "congestion bbr") errors.LogDebug(c.ctx, "congestion bbr")
congestion.UseBBR(quicConn) congestion.UseBBR(quicConn)
} else { } else {
errors.LogDebug(c.ctx, "congestion brutal bytes per second ", min(c.config.Up, serverDown)) errors.LogDebug(c.ctx, "congestion brutal bytes per second ", min(quicParams.BrutalUp, serverDown))
congestion.UseBrutal(quicConn, min(c.config.Up, serverDown)) congestion.UseBrutal(quicConn, min(quicParams.BrutalUp, serverDown))
} }
case "force-brutal": case "force-brutal":
errors.LogDebug(c.ctx, "congestion brutal bytes per second ", c.config.Up) errors.LogDebug(c.ctx, "congestion brutal bytes per second ", quicParams.BrutalUp)
congestion.UseBrutal(quicConn, c.config.Up) congestion.UseBrutal(quicConn, quicParams.BrutalUp)
default: default:
errors.LogDebug(c.ctx, "congestion reno") errors.LogDebug(c.ctx, "congestion reno")
} }
@@ -359,13 +389,14 @@ func (c *client) udphopDialer(addr *net.UDPAddr) (net.PacketConn, error) {
defer c.mutex.Unlock() defer c.mutex.Unlock()
if c.status() != StatusActive { if c.status() != StatusActive {
errors.LogDebug(c.ctx, "skip hop: disconnected QUIC") errors.LogDebug(context.Background(), "skip hop: disconnected QUIC")
return nil, errors.New() return nil, errors.New()
} }
raw, err := internet.DialSystem(c.ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig) raw, err := internet.DialSystem(c.ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
if err != nil { if err != nil {
errors.LogDebug(c.ctx, "skip hop: failed to dial to dest") errors.LogDebug(context.Background(), "skip hop: failed to dial to dest")
raw.Close()
return nil, errors.New() return nil, errors.New()
} }
@@ -377,10 +408,12 @@ func (c *client) udphopDialer(addr *net.UDPAddr) (net.PacketConn, error) {
case *net.UDPConn: case *net.UDPConn:
pktConn = conn pktConn = conn
case *cnc.Connection: case *cnc.Connection:
errors.LogDebug(c.ctx, "skip hop: udphop requires being at the outermost level") errors.LogDebug(context.Background(), "skip hop: udphop requires being at the outermost level")
raw.Close()
return nil, errors.New() return nil, errors.New()
default: default:
errors.LogDebug(c.ctx, "skip hop: unknown conn ", reflect.TypeOf(conn)) errors.LogDebug(context.Background(), "skip hop: unknown conn ", reflect.TypeOf(conn))
raw.Close()
return nil, errors.New() return nil, errors.New()
} }
@@ -424,6 +457,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
tlsConfig: tlsConfig.GetTLSConfig(), tlsConfig: tlsConfig.GetTLSConfig(),
socketConfig: streamSettings.SocketSettings, socketConfig: streamSettings.SocketSettings,
udpmaskManager: streamSettings.UdpmaskManager, udpmaskManager: streamSettings.UdpmaskManager,
quicParams: streamSettings.QuicParams,
} }
manger.m[addr] = c manger.m[addr] = c
} }

View File

@@ -140,6 +140,7 @@ type httpHandler struct {
addConn internet.ConnHandler addConn internet.ConnHandler
config *Config config *Config
quicParams *internet.QuicParams
validator *account.Validator validator *account.Validator
masqHandler http.Handler masqHandler http.Handler
@@ -155,7 +156,7 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if h.auth { if h.auth {
w.Header().Set(ResponseHeaderUDPEnabled, strconv.FormatBool(hyCtx.RequireDatagramFromContext(h.ctx))) w.Header().Set(ResponseHeaderUDPEnabled, strconv.FormatBool(hyCtx.RequireDatagramFromContext(h.ctx)))
w.Header().Set(CommonHeaderCCRX, strconv.FormatUint(h.config.Down, 10)) w.Header().Set(CommonHeaderCCRX, strconv.FormatUint(h.quicParams.BrutalDown, 10))
w.Header().Set(CommonHeaderPadding, authResponsePadding.String()) w.Header().Set(CommonHeaderPadding, authResponsePadding.String())
w.WriteHeader(StatusAuthOK) w.WriteHeader(StatusAuthOK)
return return
@@ -176,23 +177,23 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.auth = true h.auth = true
h.user = user h.user = user
switch h.config.Congestion { switch h.quicParams.Congestion {
case "reno": case "reno":
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion reno") errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion reno")
case "bbr": case "bbr":
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion bbr") errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion bbr")
congestion.UseBBR(h.conn) congestion.UseBBR(h.conn)
case "brutal", "": case "brutal", "":
if h.config.Up == 0 || clientDown == 0 { if h.quicParams.BrutalUp == 0 || clientDown == 0 {
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion bbr") errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion bbr")
congestion.UseBBR(h.conn) congestion.UseBBR(h.conn)
} else { } else {
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion brutal bytes per second ", min(h.config.Up, clientDown)) errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion brutal bytes per second ", min(h.quicParams.BrutalUp, clientDown))
congestion.UseBrutal(h.conn, min(h.config.Up, clientDown)) congestion.UseBrutal(h.conn, min(h.quicParams.BrutalUp, clientDown))
} }
case "force-brutal": case "force-brutal":
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion brutal bytes per second ", h.config.Up) errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion brutal bytes per second ", h.quicParams.BrutalUp)
congestion.UseBrutal(h.conn, h.config.Up) congestion.UseBrutal(h.conn, h.quicParams.BrutalUp)
default: default:
errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion reno") errors.LogDebug(context.Background(), h.conn.RemoteAddr(), " ", "congestion reno")
} }
@@ -212,7 +213,7 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
w.Header().Set(ResponseHeaderUDPEnabled, strconv.FormatBool(hyCtx.RequireDatagramFromContext(h.ctx))) w.Header().Set(ResponseHeaderUDPEnabled, strconv.FormatBool(hyCtx.RequireDatagramFromContext(h.ctx)))
w.Header().Set(CommonHeaderCCRX, strconv.FormatUint(h.config.Down, 10)) w.Header().Set(CommonHeaderCCRX, strconv.FormatUint(h.quicParams.BrutalDown, 10))
w.Header().Set(CommonHeaderPadding, authResponsePadding.String()) w.Header().Set(CommonHeaderPadding, authResponsePadding.String())
w.WriteHeader(StatusAuthOK) w.WriteHeader(StatusAuthOK)
return return
@@ -253,6 +254,7 @@ type Listener struct {
addConn internet.ConnHandler addConn internet.ConnHandler
config *Config config *Config
quicParams *internet.QuicParams
validator *account.Validator validator *account.Validator
masqHandler http.Handler masqHandler http.Handler
} }
@@ -264,6 +266,7 @@ func (l *Listener) handleClient(conn *quic.Conn) {
addConn: l.addConn, addConn: l.addConn,
config: l.config, config: l.config,
quicParams: l.quicParams,
validator: l.validator, validator: l.validator,
masqHandler: l.masqHandler, masqHandler: l.masqHandler,
} }
@@ -272,8 +275,8 @@ func (l *Listener) handleClient(conn *quic.Conn) {
StreamDispatcher: handler.StreamDispatcher, StreamDispatcher: handler.StreamDispatcher,
} }
err := h3.ServeQUICConn(conn) err := h3.ServeQUICConn(conn)
errors.LogDebug(context.Background(), conn.RemoteAddr(), " disconnected with err ", err)
_ = conn.CloseWithError(closeErrCodeOK, "") _ = conn.CloseWithError(closeErrCodeOK, "")
errors.LogDebug(context.Background(), conn.RemoteAddr(), " disconnected with err ", err)
} }
func (l *Listener) keepAccepting() { func (l *Listener) keepAccepting() {
@@ -377,18 +380,41 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
} }
} }
quicParams := streamSettings.QuicParams
if quicParams == nil {
quicParams = &internet.QuicParams{}
}
quicConfig := &quic.Config{ quicConfig := &quic.Config{
InitialStreamReceiveWindow: config.InitStreamReceiveWindow, InitialStreamReceiveWindow: quicParams.InitStreamReceiveWindow,
MaxStreamReceiveWindow: config.MaxStreamReceiveWindow, MaxStreamReceiveWindow: quicParams.MaxStreamReceiveWindow,
InitialConnectionReceiveWindow: config.InitConnReceiveWindow, InitialConnectionReceiveWindow: quicParams.InitConnReceiveWindow,
MaxConnectionReceiveWindow: config.MaxConnReceiveWindow, MaxConnectionReceiveWindow: quicParams.MaxConnReceiveWindow,
MaxIdleTimeout: time.Duration(config.MaxIdleTimeout) * time.Second, MaxIdleTimeout: time.Duration(quicParams.MaxIdleTimeout) * time.Second,
MaxIncomingStreams: config.MaxIncomingStreams, MaxIncomingStreams: quicParams.MaxIncomingStreams,
DisablePathMTUDiscovery: config.DisablePathMtuDiscovery, DisablePathMTUDiscovery: quicParams.DisablePathMtuDiscovery,
EnableDatagrams: true, EnableDatagrams: true,
MaxDatagramFrameSize: MaxDatagramFrameSize, MaxDatagramFrameSize: MaxDatagramFrameSize,
DisablePathManager: true, DisablePathManager: true,
} }
if quicParams.InitStreamReceiveWindow == 0 {
quicConfig.InitialStreamReceiveWindow = 8388608
}
if quicParams.MaxStreamReceiveWindow == 0 {
quicConfig.MaxStreamReceiveWindow = 8388608
}
if quicParams.InitConnReceiveWindow == 0 {
quicConfig.InitialConnectionReceiveWindow = 8388608 * 5 / 2
}
if quicParams.MaxConnReceiveWindow == 0 {
quicConfig.MaxConnectionReceiveWindow = 8388608 * 5 / 2
}
if quicParams.MaxIdleTimeout == 0 {
quicConfig.MaxIdleTimeout = 30 * time.Second
}
if quicParams.MaxIncomingStreams == 0 {
quicConfig.MaxIncomingStreams = 1024
}
qListener, err := quic.Listen(pktConn, tlsConfig.GetTLSConfig(), quicConfig) qListener, err := quic.Listen(pktConn, tlsConfig.GetTLSConfig(), quicConfig)
if err != nil { if err != nil {
@@ -403,6 +429,7 @@ func Listen(ctx context.Context, address net.Address, port net.Port, streamSetti
addConn: handler, addConn: handler,
config: config, config: config,
quicParams: quicParams,
validator: validator, validator: validator,
masqHandler: masqHandler, masqHandler: masqHandler,
} }

View File

@@ -9,11 +9,12 @@ import (
"time" "time"
"github.com/xtls/xray-core/common/crypto" "github.com/xtls/xray-core/common/crypto"
"github.com/xtls/xray-core/transport/internet/finalmask"
) )
const ( const (
packetQueueSize = 1024 packetQueueSize = 1024
udpBufferSize = 2048 // QUIC packets are at most 1500 bytes long, so 2k should be more than enough udpBufferSize = finalmask.UDPSize
defaultHopInterval = 30 * time.Second defaultHopInterval = 30 * time.Second
) )
@@ -49,7 +50,7 @@ type udpPacket struct {
type ListenUDPFunc = func(*net.UDPAddr) (net.PacketConn, error) type ListenUDPFunc = func(*net.UDPAddr) (net.PacketConn, error)
func NewUDPHopPacketConn(addr *UDPHopAddr, intervalMin int64, intervalMax int64, listenUDPFunc ListenUDPFunc, pktConn net.PacketConn, index int) (net.PacketConn, error) { func NewUDPHopPacketConn(addr *UDPHopAddr, index int, intervalMin int64, intervalMax int64, listenUDPFunc ListenUDPFunc, pktConn net.PacketConn) (net.PacketConn, error) {
if intervalMin == 0 || intervalMax == 0 { if intervalMin == 0 || intervalMax == 0 {
intervalMin = int64(defaultHopInterval) intervalMin = int64(defaultHopInterval)
intervalMax = int64(defaultHopInterval) intervalMax = int64(defaultHopInterval)

View File

@@ -1,107 +0,0 @@
package utils
import (
"sort"
"strconv"
"strings"
)
// PortUnion is a collection of multiple port ranges.
type PortUnion []PortRange
// PortRange represents a range of ports.
// Start and End are inclusive. [Start, End]
type PortRange struct {
Start, End uint16
}
// ParsePortUnion parses a string of comma-separated port ranges (or single ports) into a PortUnion.
// Returns nil if the input is invalid.
// The returned PortUnion is guaranteed to be normalized.
func ParsePortUnion(s string) PortUnion {
if s == "all" || s == "*" {
// Wildcard special case
return PortUnion{PortRange{0, 65535}}
}
var result PortUnion
portStrs := strings.Split(s, ",")
for _, portStr := range portStrs {
if strings.Contains(portStr, "-") {
// Port range
portRange := strings.Split(portStr, "-")
if len(portRange) != 2 {
return nil
}
start, err := strconv.ParseUint(portRange[0], 10, 16)
if err != nil {
return nil
}
end, err := strconv.ParseUint(portRange[1], 10, 16)
if err != nil {
return nil
}
if start > end {
start, end = end, start
}
result = append(result, PortRange{uint16(start), uint16(end)})
} else {
// Single port
port, err := strconv.ParseUint(portStr, 10, 16)
if err != nil {
return nil
}
result = append(result, PortRange{uint16(port), uint16(port)})
}
}
if result == nil {
return nil
}
return result.Normalize()
}
// Normalize normalizes a PortUnion.
// No overlapping ranges, ranges are sorted from low to high.
func (u PortUnion) Normalize() PortUnion {
if len(u) == 0 {
return u
}
sort.Slice(u, func(i, j int) bool {
if u[i].Start == u[j].Start {
return u[i].End < u[j].End
}
return u[i].Start < u[j].Start
})
normalized := PortUnion{u[0]}
for _, current := range u[1:] {
last := &normalized[len(normalized)-1]
if uint32(current.Start) <= uint32(last.End)+1 {
if current.End > last.End {
last.End = current.End
}
} else {
normalized = append(normalized, current)
}
}
return normalized
}
// Ports returns all ports in the PortUnion as a slice.
func (u PortUnion) Ports() []uint16 {
var ports []uint16
for _, r := range u {
for i := uint32(r.Start); i <= uint32(r.End); i++ {
ports = append(ports, uint16(i))
}
}
return ports
}
// Contains returns true if the PortUnion contains the given port.
func (u PortUnion) Contains(port uint16) bool {
for _, r := range u {
if port >= r.Start && port <= r.End {
return true
}
}
return false
}

View File

@@ -1,150 +0,0 @@
package utils
import (
"reflect"
"slices"
"testing"
)
func TestParsePortUnion(t *testing.T) {
tests := []struct {
name string
s string
want PortUnion
}{
{
name: "empty",
s: "",
want: nil,
},
{
name: "all 1",
s: "all",
want: PortUnion{{0, 65535}},
},
{
name: "all 2",
s: "*",
want: PortUnion{{0, 65535}},
},
{
name: "single port",
s: "1234",
want: PortUnion{{1234, 1234}},
},
{
name: "multiple ports (unsorted)",
s: "5678,1234,9012",
want: PortUnion{{1234, 1234}, {5678, 5678}, {9012, 9012}},
},
{
name: "one range",
s: "1234-1240",
want: PortUnion{{1234, 1240}},
},
{
name: "one range (reversed)",
s: "1240-1234",
want: PortUnion{{1234, 1240}},
},
{
name: "multiple ports and ranges (reversed, unsorted, overlapping)",
s: "5678,1200-1236,9100-9012,1234-1240",
want: PortUnion{{1200, 1240}, {5678, 5678}, {9012, 9100}},
},
{
name: "multiple ports and ranges with 65535 (reversed, unsorted, overlapping)",
s: "5678,1200-1236,65531-65535,65532-65534,9100-9012,1234-1240",
want: PortUnion{{1200, 1240}, {5678, 5678}, {9012, 9100}, {65531, 65535}},
},
{
name: "multiple ports and ranges with 65535 (reversed, unsorted, overlapping) 2",
s: "5678,1200-1236,65532-65535,65531-65534,9100-9012,1234-1240",
want: PortUnion{{1200, 1240}, {5678, 5678}, {9012, 9100}, {65531, 65535}},
},
{
name: "invalid 1",
s: "1234-",
want: nil,
},
{
name: "invalid 2",
s: "1234-ggez",
want: nil,
},
{
name: "invalid 3",
s: "233,",
want: nil,
},
{
name: "invalid 4",
s: "1234-1240-1250",
want: nil,
},
{
name: "invalid 5",
s: "-,,",
want: nil,
},
{
name: "invalid 6",
s: "http",
want: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ParsePortUnion(tt.s); !reflect.DeepEqual(got, tt.want) {
t.Errorf("ParsePortUnion() = %v, want %v", got, tt.want)
}
})
}
}
func TestPortUnion_Ports(t *testing.T) {
tests := []struct {
name string
pu PortUnion
want []uint16
}{
{
name: "single port",
pu: PortUnion{{1234, 1234}},
want: []uint16{1234},
},
{
name: "multiple ports",
pu: PortUnion{{1234, 1236}},
want: []uint16{1234, 1235, 1236},
},
{
name: "multiple ports and ranges",
pu: PortUnion{{1234, 1236}, {5678, 5680}, {9000, 9002}},
want: []uint16{1234, 1235, 1236, 5678, 5679, 5680, 9000, 9001, 9002},
},
{
name: "single port 65535",
pu: PortUnion{{65535, 65535}},
want: []uint16{65535},
},
{
name: "port range with 65535",
pu: PortUnion{{65530, 65535}},
want: []uint16{65530, 65531, 65532, 65533, 65534, 65535},
},
{
name: "multiple ports and ranges with 65535",
pu: PortUnion{{65530, 65535}, {1234, 1236}},
want: []uint16{65530, 65531, 65532, 65533, 65534, 65535, 1234, 1235, 1236},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.pu.Ports(); !slices.Equal(got, tt.want) {
t.Errorf("PortUnion.Ports() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -5,9 +5,11 @@ import (
gotls "crypto/tls" gotls "crypto/tls"
"fmt" "fmt"
"io" "io"
"math/rand"
"net/http" "net/http"
"net/http/httptrace" "net/http/httptrace"
"net/url" "net/url"
reflect "reflect"
"strconv" "strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
@@ -24,6 +26,7 @@ import (
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/browser_dialer" "github.com/xtls/xray-core/transport/internet/browser_dialer"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion" "github.com/xtls/xray-core/transport/internet/hysteria/congestion"
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
"github.com/xtls/xray-core/transport/internet/reality" "github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
@@ -153,25 +156,73 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
var transport http.RoundTripper var transport http.RoundTripper
if httpVersion == "3" { if httpVersion == "3" {
if keepAlivePeriod == 0 { quicParams := streamSettings.QuicParams
keepAlivePeriod = net.QuicgoH3KeepAlivePeriod if quicParams == nil {
quicParams = &internet.QuicParams{}
} }
if keepAlivePeriod < 0 { if quicParams.UdpHop == nil {
keepAlivePeriod = 0 quicParams.UdpHop = &internet.UdpHop{}
} }
quicConfig := &quic.Config{
MaxIdleTimeout: net.ConnIdleTimeout,
quicConfig := &quic.Config{
InitialStreamReceiveWindow: quicParams.InitStreamReceiveWindow,
MaxStreamReceiveWindow: quicParams.MaxStreamReceiveWindow,
InitialConnectionReceiveWindow: quicParams.InitConnReceiveWindow,
MaxConnectionReceiveWindow: quicParams.MaxConnReceiveWindow,
MaxIdleTimeout: time.Duration(quicParams.MaxIdleTimeout) * time.Second,
KeepAlivePeriod: time.Duration(quicParams.KeepAlivePeriod) * time.Second,
MaxIncomingStreams: quicParams.MaxIncomingStreams,
DisablePathMTUDiscovery: quicParams.DisablePathMtuDiscovery,
}
if quicParams.MaxIdleTimeout == 0 {
quicConfig.MaxIdleTimeout = net.ConnIdleTimeout
}
if quicParams.KeepAlivePeriod == 0 {
if keepAlivePeriod == 0 {
quicConfig.KeepAlivePeriod = net.QuicgoH3KeepAlivePeriod
}
}
if quicParams.MaxIncomingStreams == 0 {
// these two are defaults of quic-go/http3. the default of quic-go (no // these two are defaults of quic-go/http3. the default of quic-go (no
// http3) is different, so it is hardcoded here for clarity. // http3) is different, so it is hardcoded here for clarity.
// https://github.com/quic-go/quic-go/blob/b8ea5c798155950fb5bbfdd06cad1939c9355878/http3/client.go#L36-L39 // https://github.com/quic-go/quic-go/blob/b8ea5c798155950fb5bbfdd06cad1939c9355878/http3/client.go#L36-L39
MaxIncomingStreams: -1, quicConfig.MaxIncomingStreams = -1
KeepAlivePeriod: keepAlivePeriod,
} }
transport = &http3.Transport{ transport = &http3.Transport{
QUICConfig: quicConfig, QUICConfig: quicConfig,
TLSClientConfig: gotlsConfig, TLSClientConfig: gotlsConfig,
Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (*quic.Conn, error) { Dial: func(ctx context.Context, addr string, tlsCfg *gotls.Config, cfg *quic.Config) (*quic.Conn, error) {
udphopDialer := func(addr *net.UDPAddr) (net.PacketConn, error) {
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), streamSettings.SocketSettings)
if err != nil {
errors.LogDebug(context.Background(), "skip hop: failed to dial to dest")
conn.Close()
return nil, errors.New()
}
var udpConn net.PacketConn
switch c := conn.(type) {
case *internet.PacketConnWrapper:
udpConn = c.PacketConn
case *net.UDPConn:
udpConn = c
default:
errors.LogDebug(context.Background(), "skip hop: udphop requires being at the outermost level ", reflect.TypeOf(c))
conn.Close()
return nil, errors.New()
}
return udpConn, nil
}
var index int
if len(quicParams.UdpHop.Ports) > 0 {
index = rand.Intn(len(quicParams.UdpHop.Ports))
dest.Port = net.Port(quicParams.UdpHop.Ports[index])
}
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -182,54 +233,69 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
switch c := conn.(type) { switch c := conn.(type) {
case *internet.PacketConnWrapper: case *internet.PacketConnWrapper:
var ok bool udpConn = c.PacketConn
udpConn, ok = c.PacketConn.(*net.UDPConn)
if !ok {
return nil, errors.New("PacketConnWrapper does not contain a UDP connection")
}
udpAddr, err = net.ResolveUDPAddr("udp", c.Dest.String()) udpAddr, err = net.ResolveUDPAddr("udp", c.Dest.String())
if err != nil { if err != nil {
conn.Close()
return nil, err return nil, err
} }
case *net.UDPConn: case *net.UDPConn:
udpConn = c udpConn = c
udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String()) udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String())
if err != nil { if err != nil {
conn.Close()
return nil, err return nil, err
} }
default: default:
udpConn = &internet.FakePacketConn{Conn: c} udpConn = &internet.FakePacketConn{Conn: c}
udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String()) udpAddr, err = net.ResolveUDPAddr("udp", c.RemoteAddr().String())
if err != nil { if err != nil {
conn.Close()
return nil, err return nil, err
} }
if len(quicParams.UdpHop.Ports) > 0 {
conn.Close()
return nil, errors.New("udphop requires being at the outermost level ", reflect.TypeOf(c))
}
}
if len(quicParams.UdpHop.Ports) > 0 {
addr := &udphop.UDPHopAddr{
IP: udpAddr.IP,
Ports: quicParams.UdpHop.Ports,
}
udpConn, err = udphop.NewUDPHopPacketConn(addr, index, quicParams.UdpHop.IntervalMin, quicParams.UdpHop.IntervalMax, udphopDialer, udpConn)
if err != nil {
conn.Close()
return nil, errors.New("udphop err").Base(err)
}
} }
if streamSettings.UdpmaskManager != nil { if streamSettings.UdpmaskManager != nil {
pktConn, err := streamSettings.UdpmaskManager.WrapPacketConnClient(udpConn) udpConn, err = streamSettings.UdpmaskManager.WrapPacketConnClient(udpConn)
if err != nil { if err != nil {
udpConn.Close() conn.Close()
return nil, errors.New("mask err").Base(err) return nil, errors.New("mask err").Base(err)
} }
udpConn = pktConn
} }
quicConn, err := quic.DialEarly(ctx, udpConn, udpAddr, tlsCfg, cfg) quicConn, err := quic.DialEarly(ctx, udpConn, udpAddr, tlsCfg, cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if streamSettings.QuicParams != nil {
switch streamSettings.QuicParams.Congestion { switch quicParams.Congestion {
case "force-brutal": case "force-brutal":
congestion.UseBrutal(quicConn, streamSettings.QuicParams.Up) errors.LogDebug(context.Background(), quicConn.RemoteAddr(), " ", "congestion brutal bytes per second ", quicParams.BrutalUp)
case "reno": congestion.UseBrutal(quicConn, quicParams.BrutalUp)
// quic-go default, do nothing case "reno":
default: errors.LogDebug(context.Background(), quicConn.RemoteAddr(), " ", "congestion reno")
congestion.UseBBR(quicConn) default:
} errors.LogDebug(context.Background(), quicConn.RemoteAddr(), " ", "congestion bbr")
} else {
congestion.UseBBR(quicConn) congestion.UseBBR(quicConn)
} }
return quicConn, nil return quicConn, nil
}, },
} }

View File

@@ -20,10 +20,10 @@ import (
"github.com/xtls/xray-core/common" "github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/errors" "github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net" "github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
http_proto "github.com/xtls/xray-core/common/protocol/http" http_proto "github.com/xtls/xray-core/common/protocol/http"
"github.com/xtls/xray-core/common/signal/done" "github.com/xtls/xray-core/common/signal/done"
"github.com/xtls/xray-core/transport/internet" "github.com/xtls/xray-core/transport/internet"
"github.com/xtls/xray-core/transport/internet/hysteria/congestion"
"github.com/xtls/xray-core/transport/internet/reality" "github.com/xtls/xray-core/transport/internet/reality"
"github.com/xtls/xray-core/transport/internet/stat" "github.com/xtls/xray-core/transport/internet/stat"
"github.com/xtls/xray-core/transport/internet/tls" "github.com/xtls/xray-core/transport/internet/tls"
@@ -254,7 +254,7 @@ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Req
dataPlacement := h.config.GetNormalizedUplinkDataPlacement() dataPlacement := h.config.GetNormalizedUplinkDataPlacement()
var headerPayload []byte var headerPayload []byte
if dataPlacement == PlacementAuto || dataPlacement == PlacementHeader { if dataPlacement == PlacementAuto || dataPlacement == PlacementHeader {
var headerPayloadChunks [] string var headerPayloadChunks []string
for i := 0; true; i++ { for i := 0; true; i++ {
chunk := request.Header.Get(fmt.Sprintf("%s-%d", uplinkDataKey, i)) chunk := request.Header.Get(fmt.Sprintf("%s-%d", uplinkDataKey, i))
if chunk == "" { if chunk == "" {
@@ -463,7 +463,6 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
if err != nil { if err != nil {
return nil, errors.New("failed to listen UDP for XHTTP/3 on ", address, ":", port).Base(err) return nil, errors.New("failed to listen UDP for XHTTP/3 on ", address, ":", port).Base(err)
} }
if streamSettings.UdpmaskManager != nil { if streamSettings.UdpmaskManager != nil {
pktConn, err := streamSettings.UdpmaskManager.WrapPacketConnServer(Conn) pktConn, err := streamSettings.UdpmaskManager.WrapPacketConnServer(Conn)
if err != nil { if err != nil {
@@ -473,7 +472,22 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
Conn = pktConn Conn = pktConn
} }
l.h3listener, err = quic.ListenEarly(Conn, tlsConfig, nil) quicParams := streamSettings.QuicParams
if quicParams == nil {
quicParams = &internet.QuicParams{}
}
quicConfig := &quic.Config{
InitialStreamReceiveWindow: quicParams.InitStreamReceiveWindow,
MaxStreamReceiveWindow: quicParams.MaxStreamReceiveWindow,
InitialConnectionReceiveWindow: quicParams.InitConnReceiveWindow,
MaxConnectionReceiveWindow: quicParams.MaxConnReceiveWindow,
MaxIdleTimeout: time.Duration(quicParams.MaxIdleTimeout) * time.Second,
MaxIncomingStreams: quicParams.MaxIncomingStreams,
DisablePathMTUDiscovery: quicParams.DisablePathMtuDiscovery,
}
l.h3listener, err = quic.ListenEarly(Conn, tlsConfig, quicConfig)
if err != nil { if err != nil {
return nil, errors.New("failed to listen QUIC for XHTTP/3 on ", address, ":", port).Base(err) return nil, errors.New("failed to listen QUIC for XHTTP/3 on ", address, ":", port).Base(err)
} }
@@ -491,22 +505,23 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
errors.LogInfoInner(ctx, err, "XHTTP/3 listener closed") errors.LogInfoInner(ctx, err, "XHTTP/3 listener closed")
return return
} }
if streamSettings.QuicParams != nil {
switch streamSettings.QuicParams.Congestion { switch quicParams.Congestion {
case "force-brutal": case "force-brutal":
congestion.UseBrutal(conn, streamSettings.QuicParams.Up) errors.LogDebug(context.Background(), conn.RemoteAddr(), " ", "congestion brutal bytes per second ", quicParams.BrutalUp)
case "reno": congestion.UseBrutal(conn, quicParams.BrutalUp)
// quic-go default, do nothing case "reno":
default: errors.LogDebug(context.Background(), conn.RemoteAddr(), " ", "congestion reno")
congestion.UseBBR(conn) default:
} errors.LogDebug(context.Background(), conn.RemoteAddr(), " ", "congestion bbr")
} else {
congestion.UseBBR(conn) congestion.UseBBR(conn)
} }
go func() { go func() {
if err := l.h3server.ServeQUICConn(conn); err != nil { if err := l.h3server.ServeQUICConn(conn); err != nil {
errors.LogDebugInner(ctx, err, "XHTTP/3 connection ended") errors.LogDebugInner(ctx, err, "XHTTP/3 connection ended")
} }
_ = conn.CloseWithError(0, "")
}() }()
} }
}() }()
@@ -573,6 +588,7 @@ func (ln *Listener) Addr() net.Addr {
func (ln *Listener) Close() error { func (ln *Listener) Close() error {
if ln.h3server != nil { if ln.h3server != nil {
if err := ln.h3server.Close(); err != nil { if err := ln.h3server.Close(); err != nil {
_ = ln.h3listener.Close()
return err return err
} }
return ln.h3listener.Close() return ln.h3listener.Close()