Просмотр исходного кода

Hysteria transport: Support range & random for `interval` in `udphop` as well (#5603)

https://github.com/XTLS/Xray-core/pull/5560#issuecomment-3794621260
LjhAUMEM 4 месяцев назад
Родитель
Сommit
f1aee0b7c5

+ 10 - 3
infra/conf/transport_internet.go

@@ -387,7 +387,7 @@ func (b Bandwidth) Bps() (uint64, error) {
 
 type UdpHop struct {
 	PortList json.RawMessage `json:"port"`
-	Interval int64           `json:"interval"`
+	Interval *Int32Range     `json:"interval"`
 }
 
 type HysteriaConfig struct {
@@ -431,13 +431,19 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
 		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 Bps")
 	}
 	if down > 0 && down < 65536 {
 		return nil, errors.New("Down must be at least 65536 Bps")
 	}
-	if c.UdpHop.Interval != 0 && c.UdpHop.Interval < 5 {
+	if (inertvalMin != 0 && inertvalMin < 5) || (inertvalMax != 0 && inertvalMax < 5) {
 		return nil, errors.New("Interval must be at least 5")
 	}
 
@@ -467,7 +473,8 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
 	config.Up = up
 	config.Down = down
 	config.Ports = hop.Build().Ports()
-	config.Interval = c.UdpHop.Interval
+	config.IntervalMin = inertvalMin
+	config.IntervalMax = inertvalMax
 	config.InitStreamReceiveWindow = c.InitStreamReceiveWindow
 	config.MaxStreamReceiveWindow = c.MaxStreamReceiveWindow
 	config.InitConnReceiveWindow = c.InitConnectionReceiveWindow

+ 30 - 21
transport/internet/hysteria/config.pb.go

@@ -29,14 +29,15 @@ type Config struct {
 	Up                      uint64                 `protobuf:"varint,4,opt,name=up,proto3" json:"up,omitempty"`
 	Down                    uint64                 `protobuf:"varint,5,opt,name=down,proto3" json:"down,omitempty"`
 	Ports                   []uint32               `protobuf:"varint,6,rep,packed,name=ports,proto3" json:"ports,omitempty"`
-	Interval                int64                  `protobuf:"varint,7,opt,name=interval,proto3" json:"interval,omitempty"`
-	InitStreamReceiveWindow uint64                 `protobuf:"varint,8,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
-	MaxStreamReceiveWindow  uint64                 `protobuf:"varint,9,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
-	InitConnReceiveWindow   uint64                 `protobuf:"varint,10,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
-	MaxConnReceiveWindow    uint64                 `protobuf:"varint,11,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
-	MaxIdleTimeout          int64                  `protobuf:"varint,12,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
-	KeepAlivePeriod         int64                  `protobuf:"varint,13,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
-	DisablePathMtuDiscovery bool                   `protobuf:"varint,14,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
+	IntervalMin             int64                  `protobuf:"varint,7,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
+	IntervalMax             int64                  `protobuf:"varint,8,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
+	InitStreamReceiveWindow uint64                 `protobuf:"varint,9,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
+	MaxStreamReceiveWindow  uint64                 `protobuf:"varint,10,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
+	InitConnReceiveWindow   uint64                 `protobuf:"varint,11,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
+	MaxConnReceiveWindow    uint64                 `protobuf:"varint,12,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
+	MaxIdleTimeout          int64                  `protobuf:"varint,13,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
+	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"`
 	unknownFields           protoimpl.UnknownFields
 	sizeCache               protoimpl.SizeCache
 }
@@ -113,9 +114,16 @@ func (x *Config) GetPorts() []uint32 {
 	return nil
 }
 
-func (x *Config) GetInterval() int64 {
+func (x *Config) GetIntervalMin() int64 {
 	if x != nil {
-		return x.Interval
+		return x.IntervalMin
+	}
+	return 0
+}
+
+func (x *Config) GetIntervalMax() int64 {
+	if x != nil {
+		return x.IntervalMax
 	}
 	return 0
 }
@@ -173,7 +181,7 @@ var File_transport_internet_hysteria_config_proto protoreflect.FileDescriptor
 
 const file_transport_internet_hysteria_config_proto_rawDesc = "" +
 	"\n" +
-	"(transport/internet/hysteria/config.proto\x12 xray.transport.internet.hysteria\"\xa7\x04\n" +
+	"(transport/internet/hysteria/config.proto\x12 xray.transport.internet.hysteria\"\xd1\x04\n" +
 	"\x06Config\x12\x18\n" +
 	"\aversion\x18\x01 \x01(\x05R\aversion\x12\x12\n" +
 	"\x04auth\x18\x02 \x01(\tR\x04auth\x12\x1e\n" +
@@ -182,16 +190,17 @@ const file_transport_internet_hysteria_config_proto_rawDesc = "" +
 	"congestion\x12\x0e\n" +
 	"\x02up\x18\x04 \x01(\x04R\x02up\x12\x12\n" +
 	"\x04down\x18\x05 \x01(\x04R\x04down\x12\x14\n" +
-	"\x05ports\x18\x06 \x03(\rR\x05ports\x12\x1a\n" +
-	"\binterval\x18\a \x01(\x03R\binterval\x12;\n" +
-	"\x1ainit_stream_receive_window\x18\b \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
-	"\x19max_stream_receive_window\x18\t \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
-	"\x18init_conn_receive_window\x18\n" +
-	" \x01(\x04R\x15initConnReceiveWindow\x125\n" +
-	"\x17max_conn_receive_window\x18\v \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
-	"\x10max_idle_timeout\x18\f \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
-	"\x11keep_alive_period\x18\r \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
-	"\x1adisable_path_mtu_discovery\x18\x0e \x01(\bR\x17disablePathMtuDiscoveryB\x82\x01\n" +
+	"\x05ports\x18\x06 \x03(\rR\x05ports\x12!\n" +
+	"\finterval_min\x18\a \x01(\x03R\vintervalMin\x12!\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\x17disablePathMtuDiscoveryB\x82\x01\n" +
 	"$com.xray.transport.internet.hysteriaP\x01Z5github.com/xtls/xray-core/transport/internet/hysteria\xaa\x02 Xray.Transport.Internet.Hysteriab\x06proto3"
 
 var (

+ 9 - 8
transport/internet/hysteria/config.proto

@@ -13,14 +13,15 @@ message Config {
   uint64 up = 4;
   uint64 down = 5;
   repeated uint32 ports = 6;
-  int64 interval = 7;
+  int64 interval_min = 7;
+  int64 interval_max = 8;
 
-  uint64 init_stream_receive_window = 8;
-  uint64 max_stream_receive_window = 9;
-  uint64 init_conn_receive_window = 10;
-  uint64 max_conn_receive_window = 11;
-  int64 max_idle_timeout = 12;
-  int64 keep_alive_period = 13;
-  bool disable_path_mtu_discovery = 14;
+  uint64 init_stream_receive_window = 9;
+  uint64 max_stream_receive_window = 10;
+  uint64 init_conn_receive_window = 11;
+  uint64 max_conn_receive_window = 12;
+  int64 max_idle_timeout = 13;
+  int64 keep_alive_period = 14;
+  bool disable_path_mtu_discovery = 15;
 }
 

+ 1 - 1
transport/internet/hysteria/dialer.go

@@ -174,7 +174,7 @@ func (c *client) dial() error {
 			IP:    remote.(*net.UDPAddr).IP,
 			Ports: c.config.Ports,
 		}
-		pktConn, err = udphop.NewUDPHopPacketConn(addr, time.Duration(c.config.Interval)*time.Second, c.udphopDialer, pktConn, index)
+		pktConn, err = udphop.NewUDPHopPacketConn(addr, c.config.IntervalMin, c.config.IntervalMax, c.udphopDialer, pktConn, index)
 		if err != nil {
 			return errors.New("udphop err").Base(err)
 		}

+ 25 - 18
transport/internet/hysteria/udphop/conn.go

@@ -7,6 +7,8 @@ import (
 	"sync"
 	"syscall"
 	"time"
+
+	"github.com/xtls/xray-core/common/crypto"
 )
 
 const (
@@ -17,10 +19,11 @@ const (
 )
 
 type udpHopPacketConn struct {
-	Addr          net.Addr
-	Addrs         []net.Addr
-	HopInterval   time.Duration
-	ListenUDPFunc ListenUDPFunc
+	Addr           net.Addr
+	Addrs          []net.Addr
+	HopIntervalMin int64
+	HopIntervalMax int64
+	ListenUDPFunc  ListenUDPFunc
 
 	connMutex   sync.RWMutex
 	prevConn    net.PacketConn
@@ -46,10 +49,12 @@ type udpPacket struct {
 
 type ListenUDPFunc = func(*net.UDPAddr) (net.PacketConn, error)
 
-func NewUDPHopPacketConn(addr *UDPHopAddr, hopInterval time.Duration, listenUDPFunc ListenUDPFunc, pktConn net.PacketConn, index int) (net.PacketConn, error) {
-	if hopInterval == 0 {
-		hopInterval = defaultHopInterval
-	} else if hopInterval < 5*time.Second {
+func NewUDPHopPacketConn(addr *UDPHopAddr, intervalMin int64, intervalMax int64, listenUDPFunc ListenUDPFunc, pktConn net.PacketConn, index int) (net.PacketConn, error) {
+	if intervalMin == 0 || intervalMax == 0 {
+		intervalMin = int64(defaultHopInterval)
+		intervalMax = int64(defaultHopInterval)
+	}
+	if intervalMin < 5 || intervalMax < 5 {
 		return nil, errors.New("hop interval must be at least 5 seconds")
 	}
 	// if listenUDPFunc == nil {
@@ -69,15 +74,16 @@ func NewUDPHopPacketConn(addr *UDPHopAddr, hopInterval time.Duration, listenUDPF
 	// 	return nil, err
 	// }
 	hConn := &udpHopPacketConn{
-		Addr:          addr,
-		Addrs:         addrs,
-		HopInterval:   hopInterval,
-		ListenUDPFunc: listenUDPFunc,
-		prevConn:      nil,
-		currentConn:   pktConn,
-		addrIndex:     index,
-		recvQueue:     make(chan *udpPacket, packetQueueSize),
-		closeChan:     make(chan struct{}),
+		Addr:           addr,
+		Addrs:          addrs,
+		HopIntervalMin: intervalMin,
+		HopIntervalMax: intervalMax,
+		ListenUDPFunc:  listenUDPFunc,
+		prevConn:       nil,
+		currentConn:    pktConn,
+		addrIndex:      index,
+		recvQueue:      make(chan *udpPacket, packetQueueSize),
+		closeChan:      make(chan struct{}),
 		bufPool: sync.Pool{
 			New: func() interface{} {
 				return make([]byte, udpBufferSize)
@@ -115,12 +121,13 @@ func (u *udpHopPacketConn) recvLoop(conn net.PacketConn) {
 }
 
 func (u *udpHopPacketConn) hopLoop() {
-	ticker := time.NewTicker(u.HopInterval)
+	ticker := time.NewTicker(time.Duration(crypto.RandBetween(u.HopIntervalMin, u.HopIntervalMax)) * time.Second)
 	defer ticker.Stop()
 	for {
 		select {
 		case <-ticker.C:
 			u.hop()
+			ticker.Reset(time.Duration(crypto.RandBetween(u.HopIntervalMin, u.HopIntervalMax)) * time.Second)
 		case <-u.closeChan:
 			return
 		}