Skip to content

Commit 9720a57

Browse files
authored
Hysteria transport: Support range & random for interval in udphop as well (XTLS#5603)
XTLS#5560 (comment)
1 parent 71c5519 commit 9720a57

5 files changed

Lines changed: 75 additions & 51 deletions

File tree

infra/conf/transport_internet.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ func (b Bandwidth) Bps() (uint64, error) {
387387

388388
type UdpHop struct {
389389
PortList json.RawMessage `json:"port"`
390-
Interval int64 `json:"interval"`
390+
Interval *Int32Range `json:"interval"`
391391
}
392392

393393
type HysteriaConfig struct {
@@ -431,13 +431,19 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
431431
hop = &PortList{}
432432
}
433433

434+
var inertvalMin, inertvalMax int64
435+
if c.UdpHop.Interval != nil {
436+
inertvalMin = int64(c.UdpHop.Interval.From)
437+
inertvalMax = int64(c.UdpHop.Interval.To)
438+
}
439+
434440
if up > 0 && up < 65536 {
435441
return nil, errors.New("Up must be at least 65536 Bps")
436442
}
437443
if down > 0 && down < 65536 {
438444
return nil, errors.New("Down must be at least 65536 Bps")
439445
}
440-
if c.UdpHop.Interval != 0 && c.UdpHop.Interval < 5 {
446+
if (inertvalMin != 0 && inertvalMin < 5) || (inertvalMax != 0 && inertvalMax < 5) {
441447
return nil, errors.New("Interval must be at least 5")
442448
}
443449

@@ -467,7 +473,8 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
467473
config.Up = up
468474
config.Down = down
469475
config.Ports = hop.Build().Ports()
470-
config.Interval = c.UdpHop.Interval
476+
config.IntervalMin = inertvalMin
477+
config.IntervalMax = inertvalMax
471478
config.InitStreamReceiveWindow = c.InitStreamReceiveWindow
472479
config.MaxStreamReceiveWindow = c.MaxStreamReceiveWindow
473480
config.InitConnReceiveWindow = c.InitConnectionReceiveWindow

transport/internet/hysteria/config.pb.go

Lines changed: 30 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

transport/internet/hysteria/config.proto

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ message Config {
1313
uint64 up = 4;
1414
uint64 down = 5;
1515
repeated uint32 ports = 6;
16-
int64 interval = 7;
16+
int64 interval_min = 7;
17+
int64 interval_max = 8;
1718

18-
uint64 init_stream_receive_window = 8;
19-
uint64 max_stream_receive_window = 9;
20-
uint64 init_conn_receive_window = 10;
21-
uint64 max_conn_receive_window = 11;
22-
int64 max_idle_timeout = 12;
23-
int64 keep_alive_period = 13;
24-
bool disable_path_mtu_discovery = 14;
19+
uint64 init_stream_receive_window = 9;
20+
uint64 max_stream_receive_window = 10;
21+
uint64 init_conn_receive_window = 11;
22+
uint64 max_conn_receive_window = 12;
23+
int64 max_idle_timeout = 13;
24+
int64 keep_alive_period = 14;
25+
bool disable_path_mtu_discovery = 15;
2526
}
2627

transport/internet/hysteria/dialer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func (c *client) dial() error {
174174
IP: remote.(*net.UDPAddr).IP,
175175
Ports: c.config.Ports,
176176
}
177-
pktConn, err = udphop.NewUDPHopPacketConn(addr, time.Duration(c.config.Interval)*time.Second, c.udphopDialer, pktConn, index)
177+
pktConn, err = udphop.NewUDPHopPacketConn(addr, c.config.IntervalMin, c.config.IntervalMax, c.udphopDialer, pktConn, index)
178178
if err != nil {
179179
return errors.New("udphop err").Base(err)
180180
}

transport/internet/hysteria/udphop/conn.go

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"sync"
88
"syscall"
99
"time"
10+
11+
"github.com/xtls/xray-core/common/crypto"
1012
)
1113

1214
const (
@@ -17,10 +19,11 @@ const (
1719
)
1820

1921
type udpHopPacketConn struct {
20-
Addr net.Addr
21-
Addrs []net.Addr
22-
HopInterval time.Duration
23-
ListenUDPFunc ListenUDPFunc
22+
Addr net.Addr
23+
Addrs []net.Addr
24+
HopIntervalMin int64
25+
HopIntervalMax int64
26+
ListenUDPFunc ListenUDPFunc
2427

2528
connMutex sync.RWMutex
2629
prevConn net.PacketConn
@@ -46,10 +49,12 @@ type udpPacket struct {
4649

4750
type ListenUDPFunc = func(*net.UDPAddr) (net.PacketConn, error)
4851

49-
func NewUDPHopPacketConn(addr *UDPHopAddr, hopInterval time.Duration, listenUDPFunc ListenUDPFunc, pktConn net.PacketConn, index int) (net.PacketConn, error) {
50-
if hopInterval == 0 {
51-
hopInterval = defaultHopInterval
52-
} else if hopInterval < 5*time.Second {
52+
func NewUDPHopPacketConn(addr *UDPHopAddr, intervalMin int64, intervalMax int64, listenUDPFunc ListenUDPFunc, pktConn net.PacketConn, index int) (net.PacketConn, error) {
53+
if intervalMin == 0 || intervalMax == 0 {
54+
intervalMin = int64(defaultHopInterval)
55+
intervalMax = int64(defaultHopInterval)
56+
}
57+
if intervalMin < 5 || intervalMax < 5 {
5358
return nil, errors.New("hop interval must be at least 5 seconds")
5459
}
5560
// if listenUDPFunc == nil {
@@ -69,15 +74,16 @@ func NewUDPHopPacketConn(addr *UDPHopAddr, hopInterval time.Duration, listenUDPF
6974
// return nil, err
7075
// }
7176
hConn := &udpHopPacketConn{
72-
Addr: addr,
73-
Addrs: addrs,
74-
HopInterval: hopInterval,
75-
ListenUDPFunc: listenUDPFunc,
76-
prevConn: nil,
77-
currentConn: pktConn,
78-
addrIndex: index,
79-
recvQueue: make(chan *udpPacket, packetQueueSize),
80-
closeChan: make(chan struct{}),
77+
Addr: addr,
78+
Addrs: addrs,
79+
HopIntervalMin: intervalMin,
80+
HopIntervalMax: intervalMax,
81+
ListenUDPFunc: listenUDPFunc,
82+
prevConn: nil,
83+
currentConn: pktConn,
84+
addrIndex: index,
85+
recvQueue: make(chan *udpPacket, packetQueueSize),
86+
closeChan: make(chan struct{}),
8187
bufPool: sync.Pool{
8288
New: func() interface{} {
8389
return make([]byte, udpBufferSize)
@@ -115,12 +121,13 @@ func (u *udpHopPacketConn) recvLoop(conn net.PacketConn) {
115121
}
116122

117123
func (u *udpHopPacketConn) hopLoop() {
118-
ticker := time.NewTicker(u.HopInterval)
124+
ticker := time.NewTicker(time.Duration(crypto.RandBetween(u.HopIntervalMin, u.HopIntervalMax)) * time.Second)
119125
defer ticker.Stop()
120126
for {
121127
select {
122128
case <-ticker.C:
123129
u.hop()
130+
ticker.Reset(time.Duration(crypto.RandBetween(u.HopIntervalMin, u.HopIntervalMax)) * time.Second)
124131
case <-u.closeChan:
125132
return
126133
}

0 commit comments

Comments
 (0)