Hysteria & XHTTP/3 clients: udpHop supports dialerProxy (#6320)

https://github.com/XTLS/Xray-core/pull/6320#issuecomment-4725679616

Fixes https://github.com/XTLS/Xray-core/pull/6320#issuecomment-4699599655

---------

Co-authored-by: LjhAUMEM <llnu14702@gmail.com>
This commit is contained in:
Hossin Asaadi
2026-06-16 22:49:35 +01:00
committed by RPRX
parent 862631172d
commit 829d54d7be
3 changed files with 49 additions and 67 deletions
+23 -27
View File
@@ -126,6 +126,8 @@ func (c *client) dial(ctx context.Context) error {
switch c := conn.(type) { switch c := conn.(type) {
case *internet.PacketConnWrapper: case *internet.PacketConnWrapper:
pktConn = c.PacketConn pktConn = c.PacketConn
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
default: default:
panic(reflect.TypeOf(c)) panic(reflect.TypeOf(c))
} }
@@ -135,36 +137,30 @@ func (c *client) dial(ctx context.Context) error {
var pktConn net.PacketConn var pktConn net.PacketConn
var udpAddr *net.UDPAddr var udpAddr *net.UDPAddr
var index int
if len(quicParams.UdpHop.Ports) > 0 { if len(quicParams.UdpHop.Ports) > 0 {
index := rand.Intn(len(quicParams.UdpHop.Ports)) index = rand.Intn(len(quicParams.UdpHop.Ports))
c.dest.Port = net.Port(quicParams.UdpHop.Ports[index]) c.dest.Port = net.Port(quicParams.UdpHop.Ports[index])
conn, err := internet.DialSystem(ctx, c.dest, c.socketConfig) }
if err != nil {
return errors.New("failed to dial to dest").Base(err) raw, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
} if err != nil {
switch c := conn.(type) { return errors.New("failed to dial to dest").Base(err)
case *internet.PacketConnWrapper: }
pktConn = c.PacketConn switch c := raw.(type) {
udpAddr = conn.RemoteAddr().(*net.UDPAddr) case *internet.PacketConnWrapper:
default: pktConn = c.PacketConn
panic(reflect.TypeOf(c)) udpAddr = raw.RemoteAddr().(*net.UDPAddr)
} case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
default:
panic(reflect.TypeOf(c))
}
if len(quicParams.UdpHop.Ports) > 0 {
pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index) pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index)
} else {
conn, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
if err != nil {
return errors.New("failed to dial to dest").Base(err)
}
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
udpAddr = c.RemoteAddr().(*net.UDPAddr)
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
default:
panic(reflect.TypeOf(c))
}
} }
if c.udpmaskManager != nil { if c.udpmaskManager != nil {
+3 -13
View File
@@ -5,7 +5,6 @@ import (
"math/rand" "math/rand"
"net" "net"
"sync" "sync"
"syscall"
"time" "time"
"github.com/xtls/xray-core/transport/internet/finalmask" "github.com/xtls/xray-core/transport/internet/finalmask"
@@ -138,8 +137,8 @@ func (u *UdpHopPacketConn) hop() {
if u.closed { if u.closed {
return return
} }
u.addrIndex = rand.Intn(len(u.Addrs)) addrIndex := rand.Intn(len(u.Addrs))
newConn, err := u.ListenUDPFunc(u.Addrs[u.addrIndex].(*net.UDPAddr)) newConn, err := u.ListenUDPFunc(u.Addrs[addrIndex].(*net.UDPAddr))
if err != nil { if err != nil {
return return
} }
@@ -147,6 +146,7 @@ func (u *UdpHopPacketConn) hop() {
_ = u.prevConn.Close() _ = u.prevConn.Close()
} }
u.prevConn = u.currentConn u.prevConn = u.currentConn
u.addrIndex = addrIndex
u.currentConn = newConn u.currentConn = newConn
if !u.deadline.IsZero() { if !u.deadline.IsZero() {
_ = u.currentConn.SetDeadline(u.deadline) _ = u.currentConn.SetDeadline(u.deadline)
@@ -241,16 +241,6 @@ func (u *UdpHopPacketConn) SetWriteDeadline(t time.Time) error {
return u.currentConn.SetWriteDeadline(t) return u.currentConn.SetWriteDeadline(t)
} }
func (u *UdpHopPacketConn) SyscallConn() (syscall.RawConn, error) {
u.connMutex.RLock()
defer u.connMutex.RUnlock()
sc, ok := u.currentConn.(syscall.Conn)
if !ok {
return nil, errors.New("not supported")
}
return sc.SyscallConn()
}
func ToAddrs(ip net.IP, ports []uint32) []net.Addr { func ToAddrs(ip net.IP, ports []uint32) []net.Addr {
var addrs []net.Addr var addrs []net.Addr
for _, port := range ports { for _, port := range ports {
+23 -27
View File
@@ -209,6 +209,8 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
switch c := conn.(type) { switch c := conn.(type) {
case *internet.PacketConnWrapper: case *internet.PacketConnWrapper:
pktConn = c.PacketConn pktConn = c.PacketConn
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
default: default:
panic(reflect.TypeOf(c)) panic(reflect.TypeOf(c))
} }
@@ -218,36 +220,30 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
var pktConn net.PacketConn var pktConn net.PacketConn
var udpAddr *net.UDPAddr var udpAddr *net.UDPAddr
var index int
if len(quicParams.UdpHop.Ports) > 0 { if len(quicParams.UdpHop.Ports) > 0 {
index := rand.Intn(len(quicParams.UdpHop.Ports)) index = rand.Intn(len(quicParams.UdpHop.Ports))
dest.Port = net.Port(quicParams.UdpHop.Ports[index]) dest.Port = net.Port(quicParams.UdpHop.Ports[index])
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings) }
if err != nil {
return nil, errors.New("failed to dial to dest").Base(err) raw, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
} if err != nil {
switch c := conn.(type) { return nil, errors.New("failed to dial to dest").Base(err)
case *internet.PacketConnWrapper: }
pktConn = c.PacketConn switch c := raw.(type) {
udpAddr = conn.RemoteAddr().(*net.UDPAddr) case *internet.PacketConnWrapper:
default: pktConn = c.PacketConn
panic(reflect.TypeOf(c)) udpAddr = raw.RemoteAddr().(*net.UDPAddr)
} case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
default:
panic(reflect.TypeOf(c))
}
if len(quicParams.UdpHop.Ports) > 0 {
pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index) pktConn = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer, pktConn, index)
} else {
conn, err := internet.DialSystem(ctx, dest, streamSettings.SocketSettings)
if err != nil {
return nil, errors.New("failed to dial to dest").Base(err)
}
switch c := conn.(type) {
case *internet.PacketConnWrapper:
pktConn = c.PacketConn
udpAddr = c.RemoteAddr().(*net.UDPAddr)
case *cnc.Connection:
pktConn = &internet.FakePacketConn{Conn: c}
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
default:
panic(reflect.TypeOf(c))
}
} }
if streamSettings.UdpmaskManager != nil { if streamSettings.UdpmaskManager != nil {