mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-05-14 10:00:34 +00:00
Hysteria client: Fix sendThrough (#6063)
And fixes https://github.com/XTLS/Xray-core/issues/6046
This commit is contained in:
@@ -730,8 +730,6 @@ type SocketConfig struct {
|
|||||||
// ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket
|
// ReceiveOriginalDestAddress is for enabling IP_RECVORIGDSTADDR socket
|
||||||
// option. This option is for UDP only.
|
// option. This option is for UDP only.
|
||||||
ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"`
|
ReceiveOriginalDestAddress bool `protobuf:"varint,4,opt,name=receive_original_dest_address,json=receiveOriginalDestAddress,proto3" json:"receive_original_dest_address,omitempty"`
|
||||||
BindAddress []byte `protobuf:"bytes,5,opt,name=bind_address,json=bindAddress,proto3" json:"bind_address,omitempty"`
|
|
||||||
BindPort uint32 `protobuf:"varint,6,opt,name=bind_port,json=bindPort,proto3" json:"bind_port,omitempty"`
|
|
||||||
AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"`
|
AcceptProxyProtocol bool `protobuf:"varint,7,opt,name=accept_proxy_protocol,json=acceptProxyProtocol,proto3" json:"accept_proxy_protocol,omitempty"`
|
||||||
DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
DomainStrategy DomainStrategy `protobuf:"varint,8,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.transport.internet.DomainStrategy" json:"domain_strategy,omitempty"`
|
||||||
DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"`
|
DialerProxy string `protobuf:"bytes,9,opt,name=dialer_proxy,json=dialerProxy,proto3" json:"dialer_proxy,omitempty"`
|
||||||
@@ -811,20 +809,6 @@ func (x *SocketConfig) GetReceiveOriginalDestAddress() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SocketConfig) GetBindAddress() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.BindAddress
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SocketConfig) GetBindPort() uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.BindPort
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SocketConfig) GetAcceptProxyProtocol() bool {
|
func (x *SocketConfig) GetAcceptProxyProtocol() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.AcceptProxyProtocol
|
return x.AcceptProxyProtocol
|
||||||
@@ -1066,14 +1050,12 @@ const file_transport_internet_config_proto_rawDesc = "" +
|
|||||||
"\x05level\x18\x03 \x01(\tR\x05level\x12\x10\n" +
|
"\x05level\x18\x03 \x01(\tR\x05level\x12\x10\n" +
|
||||||
"\x03opt\x18\x04 \x01(\tR\x03opt\x12\x14\n" +
|
"\x03opt\x18\x04 \x01(\tR\x03opt\x12\x14\n" +
|
||||||
"\x05value\x18\x05 \x01(\tR\x05value\x12\x12\n" +
|
"\x05value\x18\x05 \x01(\tR\x05value\x12\x12\n" +
|
||||||
"\x04type\x18\x06 \x01(\tR\x04type\"\x89\t\n" +
|
"\x04type\x18\x06 \x01(\tR\x04type\"\xc9\b\n" +
|
||||||
"\fSocketConfig\x12\x12\n" +
|
"\fSocketConfig\x12\x12\n" +
|
||||||
"\x04mark\x18\x01 \x01(\x05R\x04mark\x12\x10\n" +
|
"\x04mark\x18\x01 \x01(\x05R\x04mark\x12\x10\n" +
|
||||||
"\x03tfo\x18\x02 \x01(\x05R\x03tfo\x12H\n" +
|
"\x03tfo\x18\x02 \x01(\x05R\x03tfo\x12H\n" +
|
||||||
"\x06tproxy\x18\x03 \x01(\x0e20.xray.transport.internet.SocketConfig.TProxyModeR\x06tproxy\x12A\n" +
|
"\x06tproxy\x18\x03 \x01(\x0e20.xray.transport.internet.SocketConfig.TProxyModeR\x06tproxy\x12A\n" +
|
||||||
"\x1dreceive_original_dest_address\x18\x04 \x01(\bR\x1areceiveOriginalDestAddress\x12!\n" +
|
"\x1dreceive_original_dest_address\x18\x04 \x01(\bR\x1areceiveOriginalDestAddress\x122\n" +
|
||||||
"\fbind_address\x18\x05 \x01(\fR\vbindAddress\x12\x1b\n" +
|
|
||||||
"\tbind_port\x18\x06 \x01(\rR\bbindPort\x122\n" +
|
|
||||||
"\x15accept_proxy_protocol\x18\a \x01(\bR\x13acceptProxyProtocol\x12P\n" +
|
"\x15accept_proxy_protocol\x18\a \x01(\bR\x13acceptProxyProtocol\x12P\n" +
|
||||||
"\x0fdomain_strategy\x18\b \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0edomainStrategy\x12!\n" +
|
"\x0fdomain_strategy\x18\b \x01(\x0e2'.xray.transport.internet.DomainStrategyR\x0edomainStrategy\x12!\n" +
|
||||||
"\fdialer_proxy\x18\t \x01(\tR\vdialerProxy\x125\n" +
|
"\fdialer_proxy\x18\t \x01(\tR\vdialerProxy\x125\n" +
|
||||||
|
|||||||
@@ -124,10 +124,6 @@ message SocketConfig {
|
|||||||
// option. This option is for UDP only.
|
// option. This option is for UDP only.
|
||||||
bool receive_original_dest_address = 4;
|
bool receive_original_dest_address = 4;
|
||||||
|
|
||||||
bytes bind_address = 5;
|
|
||||||
|
|
||||||
uint32 bind_port = 6;
|
|
||||||
|
|
||||||
bool accept_proxy_protocol = 7;
|
bool accept_proxy_protocol = 7;
|
||||||
|
|
||||||
DomainStrategy domain_strategy = 8;
|
DomainStrategy domain_strategy = 8;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package hysteria
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
go_tls "crypto/tls"
|
go_tls "crypto/tls"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -64,7 +65,7 @@ func (c *client) close() {
|
|||||||
c.udpSM = nil
|
c.udpSM = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) dial() error {
|
func (c *client) dial(ctx context.Context) error {
|
||||||
status := c.status()
|
status := c.status()
|
||||||
if status == StatusActive {
|
if status == StatusActive {
|
||||||
return nil
|
return nil
|
||||||
@@ -113,30 +114,54 @@ func (c *client) dial() error {
|
|||||||
// quicConfig.KeepAlivePeriod = 10 * time.Second
|
// quicConfig.KeepAlivePeriod = 10 * time.Second
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
udpHopDialer := func(addr *net.UDPAddr) (net.PacketConn, error) {
|
||||||
|
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
|
||||||
|
if err != nil {
|
||||||
|
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
||||||
|
return nil, errors.New("")
|
||||||
|
}
|
||||||
|
|
||||||
|
var pktConn net.PacketConn
|
||||||
|
|
||||||
|
switch c := conn.(type) {
|
||||||
|
case *internet.PacketConnWrapper:
|
||||||
|
pktConn = c.PacketConn
|
||||||
|
default:
|
||||||
|
panic(reflect.TypeOf(c))
|
||||||
|
}
|
||||||
|
|
||||||
|
return pktConn, nil
|
||||||
|
}
|
||||||
|
|
||||||
var pktConn net.PacketConn
|
var pktConn net.PacketConn
|
||||||
var udpAddr *net.UDPAddr
|
var udpAddr *net.UDPAddr
|
||||||
var err error
|
|
||||||
udpAddr, err = net.ResolveUDPAddr("udp", c.dest.NetAddr())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(quicParams.UdpHop.Ports) > 0 {
|
if len(quicParams.UdpHop.Ports) > 0 {
|
||||||
pktConn, err = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, c.udpHopDialer)
|
index := rand.Intn(len(quicParams.UdpHop.Ports))
|
||||||
|
c.dest.Port = net.Port(quicParams.UdpHop.Ports[index])
|
||||||
|
conn, err := internet.DialSystem(ctx, c.dest, c.socketConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return errors.New("failed to dial to dest").Base(err)
|
||||||
}
|
|
||||||
} else {
|
|
||||||
conn, err := internet.DialSystem(context.Background(), c.dest, c.socketConfig)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
switch c := conn.(type) {
|
switch c := conn.(type) {
|
||||||
case *internet.PacketConnWrapper:
|
case *internet.PacketConnWrapper:
|
||||||
pktConn = c.PacketConn
|
pktConn = c.PacketConn
|
||||||
case *net.UDPConn:
|
udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
||||||
pktConn = c
|
default:
|
||||||
|
panic(reflect.TypeOf(c))
|
||||||
|
}
|
||||||
|
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:
|
case *cnc.Connection:
|
||||||
pktConn = &internet.FakePacketConn{Conn: c}
|
pktConn = &internet.FakePacketConn{Conn: c}
|
||||||
|
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||||
default:
|
default:
|
||||||
panic(reflect.TypeOf(c))
|
panic(reflect.TypeOf(c))
|
||||||
}
|
}
|
||||||
@@ -228,11 +253,11 @@ func (c *client) dial() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) tcp() (stat.Connection, error) {
|
func (c *client) tcp(ctx context.Context) (stat.Connection, error) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
err := c.dial()
|
err := c.dial(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -251,11 +276,11 @@ func (c *client) tcp() (stat.Connection, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) udp() (stat.Connection, error) {
|
func (c *client) udp(ctx context.Context) (stat.Connection, error) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
err := c.dial()
|
err := c.dial(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -271,29 +296,6 @@ func (c *client) clean() {
|
|||||||
c.Unlock()
|
c.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) udpHopDialer(addr *net.UDPAddr) (net.PacketConn, error) {
|
|
||||||
conn, err := internet.DialSystem(context.Background(), net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), c.socketConfig)
|
|
||||||
if err != nil {
|
|
||||||
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
|
||||||
return nil, errors.New("failed to dial to dest").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var pktConn net.PacketConn
|
|
||||||
|
|
||||||
switch c := conn.(type) {
|
|
||||||
case *internet.PacketConnWrapper:
|
|
||||||
pktConn = c.PacketConn
|
|
||||||
case *net.UDPConn:
|
|
||||||
pktConn = c
|
|
||||||
default:
|
|
||||||
errors.LogInfo(context.Background(), "skip hop: invalid conn ", reflect.TypeOf(c))
|
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("invalid conn ", reflect.TypeOf(c))
|
|
||||||
}
|
|
||||||
|
|
||||||
return pktConn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type dialerConf struct {
|
type dialerConf struct {
|
||||||
net.Destination
|
net.Destination
|
||||||
*internet.MemoryStreamConfig
|
*internet.MemoryStreamConfig
|
||||||
@@ -356,9 +358,9 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *internet.Me
|
|||||||
}
|
}
|
||||||
|
|
||||||
if datagram {
|
if datagram {
|
||||||
return c.udp()
|
return c.udp(ctx)
|
||||||
}
|
}
|
||||||
return c.tcp()
|
return c.tcp(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ type udpPacket struct {
|
|||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopIntervalMax time.Duration, listenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error)) (net.PacketConn, error) {
|
func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopIntervalMax time.Duration, listenUDPFunc func(addr *net.UDPAddr) (net.PacketConn, error), currentConn net.PacketConn, addrIndex int) net.PacketConn {
|
||||||
if len(addrs) == 0 {
|
if len(addrs) == 0 {
|
||||||
panic("len(addrs) == 0")
|
panic("len(addrs) == 0")
|
||||||
}
|
}
|
||||||
@@ -75,8 +75,8 @@ func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopInte
|
|||||||
HopIntervalMax: hopIntervalMax,
|
HopIntervalMax: hopIntervalMax,
|
||||||
ListenUDPFunc: listenUDPFunc,
|
ListenUDPFunc: listenUDPFunc,
|
||||||
prevConn: nil,
|
prevConn: nil,
|
||||||
currentConn: nil,
|
currentConn: currentConn,
|
||||||
addrIndex: rand.Intn(len(addrs)),
|
addrIndex: addrIndex,
|
||||||
recvQueue: make(chan *udpPacket, packetQueueSize),
|
recvQueue: make(chan *udpPacket, packetQueueSize),
|
||||||
closeChan: make(chan struct{}),
|
closeChan: make(chan struct{}),
|
||||||
bufPool: sync.Pool{
|
bufPool: sync.Pool{
|
||||||
@@ -85,14 +85,9 @@ func NewUDPHopPacketConn(addrs []net.Addr, hopIntervalMin time.Duration, hopInte
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
var err error
|
|
||||||
hConn.currentConn, err = listenUDPFunc(hConn.Addrs[hConn.addrIndex].(*net.UDPAddr))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
go hConn.recvLoop(hConn.currentConn)
|
go hConn.recvLoop(hConn.currentConn)
|
||||||
go hConn.hopLoop()
|
go hConn.hopLoop()
|
||||||
return hConn, nil
|
return hConn
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *UdpHopPacketConn) recvLoop(conn net.PacketConn) {
|
func (u *UdpHopPacketConn) recvLoop(conn net.PacketConn) {
|
||||||
|
|||||||
@@ -58,14 +58,14 @@ func DialKCP(ctx context.Context, dest net.Destination, streamSettings *internet
|
|||||||
|
|
||||||
if streamSettings.UdpmaskManager != nil {
|
if streamSettings.UdpmaskManager != nil {
|
||||||
var pktConn net.PacketConn
|
var pktConn net.PacketConn
|
||||||
var udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
var udpAddr *net.UDPAddr
|
||||||
switch c := conn.(type) {
|
switch c := conn.(type) {
|
||||||
case *internet.PacketConnWrapper:
|
case *internet.PacketConnWrapper:
|
||||||
pktConn = c.PacketConn
|
pktConn = c.PacketConn
|
||||||
case *net.UDPConn:
|
udpAddr = c.RemoteAddr().(*net.UDPAddr)
|
||||||
pktConn = c
|
|
||||||
case *cnc.Connection:
|
case *cnc.Connection:
|
||||||
pktConn = &internet.FakePacketConn{Conn: c}
|
pktConn = &internet.FakePacketConn{Conn: c}
|
||||||
|
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||||
default:
|
default:
|
||||||
panic(reflect.TypeOf(c))
|
panic(reflect.TypeOf(c))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,32 +288,6 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindAddr(fd uintptr, address []byte, port uint32) error {
|
|
||||||
setReuseAddr(fd)
|
|
||||||
setReusePort(fd)
|
|
||||||
|
|
||||||
var sockaddr unix.Sockaddr
|
|
||||||
|
|
||||||
switch len(address) {
|
|
||||||
case net.IPv4len:
|
|
||||||
a4 := &unix.SockaddrInet4{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a4.Addr[:], address)
|
|
||||||
sockaddr = a4
|
|
||||||
case net.IPv6len:
|
|
||||||
a6 := &unix.SockaddrInet6{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a6.Addr[:], address)
|
|
||||||
sockaddr = a6
|
|
||||||
default:
|
|
||||||
return errors.New("unexpected length of ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
return unix.Bind(int(fd), sockaddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setReuseAddr(fd uintptr) error {
|
func setReuseAddr(fd uintptr) error {
|
||||||
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
|
if err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
|
||||||
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
||||||
|
|||||||
@@ -222,32 +222,6 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
|
||||||
setReuseAddr(fd)
|
|
||||||
setReusePort(fd)
|
|
||||||
|
|
||||||
var sockaddr syscall.Sockaddr
|
|
||||||
|
|
||||||
switch len(ip) {
|
|
||||||
case net.IPv4len:
|
|
||||||
a4 := &syscall.SockaddrInet4{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a4.Addr[:], ip)
|
|
||||||
sockaddr = a4
|
|
||||||
case net.IPv6len:
|
|
||||||
a6 := &syscall.SockaddrInet6{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a6.Addr[:], ip)
|
|
||||||
sockaddr = a6
|
|
||||||
default:
|
|
||||||
return errors.New("unexpected length of ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
return syscall.Bind(int(fd), sockaddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func setReuseAddr(fd uintptr) error {
|
func setReuseAddr(fd uintptr) error {
|
||||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
||||||
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
return errors.New("failed to set SO_REUSEADDR").Base(err).AtWarning()
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package internet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -12,32 +11,6 @@ import (
|
|||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
|
||||||
setReuseAddr(fd)
|
|
||||||
setReusePort(fd)
|
|
||||||
|
|
||||||
var sockaddr syscall.Sockaddr
|
|
||||||
|
|
||||||
switch len(ip) {
|
|
||||||
case net.IPv4len:
|
|
||||||
a4 := &syscall.SockaddrInet4{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a4.Addr[:], ip)
|
|
||||||
sockaddr = a4
|
|
||||||
case net.IPv6len:
|
|
||||||
a6 := &syscall.SockaddrInet6{
|
|
||||||
Port: int(port),
|
|
||||||
}
|
|
||||||
copy(a6.Addr[:], ip)
|
|
||||||
sockaddr = a6
|
|
||||||
default:
|
|
||||||
return errors.New("unexpected length of ip")
|
|
||||||
}
|
|
||||||
|
|
||||||
return syscall.Bind(int(fd), sockaddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyOutboundSocketOptions applies socket options for outbound connection.
|
// applyOutboundSocketOptions applies socket options for outbound connection.
|
||||||
// note that unlike other part of Xray, this function needs network with speified network stack(tcp4/tcp6/udp4/udp6)
|
// note that unlike other part of Xray, this function needs network with speified network stack(tcp4/tcp6/udp4/udp6)
|
||||||
func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
|
func applyOutboundSocketOptions(network string, address string, fd uintptr, config *SocketConfig) error {
|
||||||
|
|||||||
@@ -11,10 +11,6 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setReuseAddr(fd uintptr) error {
|
func setReuseAddr(fd uintptr) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,10 +181,6 @@ func applyInboundSocketOptions(network string, fd uintptr, config *SocketConfig)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindAddr(fd uintptr, ip []byte, port uint32) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func setReuseAddr(fd uintptr) error {
|
func setReuseAddr(fd uintptr) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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"
|
||||||
@@ -199,7 +200,7 @@ func createHTTPClient(dest net.Destination, streamSettings *internet.MemoryStrea
|
|||||||
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), streamSettings.SocketSettings)
|
conn, err := internet.DialSystem(ctx, net.UDPDestination(net.IPAddress(addr.IP), net.Port(addr.Port)), streamSettings.SocketSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
errors.LogInfoInner(context.Background(), err, "skip hop: failed to dial to dest")
|
||||||
return nil, errors.New("failed to dial to dest").Base(err)
|
return nil, errors.New("")
|
||||||
}
|
}
|
||||||
|
|
||||||
var pktConn net.PacketConn
|
var pktConn net.PacketConn
|
||||||
@@ -207,12 +208,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 *net.UDPConn:
|
|
||||||
pktConn = c
|
|
||||||
default:
|
default:
|
||||||
errors.LogInfo(context.Background(), "skip hop: invalid conn ", reflect.TypeOf(c))
|
panic(reflect.TypeOf(c))
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("invalid conn ", reflect.TypeOf(c))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pktConn, nil
|
return pktConn, nil
|
||||||
@@ -220,28 +217,33 @@ 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 err error
|
|
||||||
udpAddr, err = net.ResolveUDPAddr("udp", dest.NetAddr())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(quicParams.UdpHop.Ports) > 0 {
|
if len(quicParams.UdpHop.Ports) > 0 {
|
||||||
pktConn, err = udphop.NewUDPHopPacketConn(udphop.ToAddrs(udpAddr.IP, quicParams.UdpHop.Ports), time.Duration(quicParams.UdpHop.IntervalMin)*time.Second, time.Duration(quicParams.UdpHop.IntervalMax)*time.Second, udpHopDialer)
|
index := rand.Intn(len(quicParams.UdpHop.Ports))
|
||||||
if err != nil {
|
dest.Port = net.Port(quicParams.UdpHop.Ports[index])
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
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, errors.New("failed to dial to dest").Base(err)
|
||||||
}
|
}
|
||||||
switch c := conn.(type) {
|
switch c := conn.(type) {
|
||||||
case *internet.PacketConnWrapper:
|
case *internet.PacketConnWrapper:
|
||||||
pktConn = c.PacketConn
|
pktConn = c.PacketConn
|
||||||
case *net.UDPConn:
|
udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
||||||
pktConn = c
|
default:
|
||||||
|
panic(reflect.TypeOf(c))
|
||||||
|
}
|
||||||
|
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:
|
case *cnc.Connection:
|
||||||
pktConn = &internet.FakePacketConn{Conn: c}
|
pktConn = &internet.FakePacketConn{Conn: c}
|
||||||
|
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||||
default:
|
default:
|
||||||
panic(reflect.TypeOf(c))
|
panic(reflect.TypeOf(c))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,7 +441,7 @@ type Listener struct {
|
|||||||
server http.Server
|
server http.Server
|
||||||
h3server *http3.Server
|
h3server *http3.Server
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
h3listener Qface
|
h3listener http3.QUICListener
|
||||||
config *Config
|
config *Config
|
||||||
addConn internet.ConnHandler
|
addConn internet.ConnHandler
|
||||||
isH3 bool
|
isH3 bool
|
||||||
@@ -519,8 +519,8 @@ func ListenXH(ctx context.Context, address net.Address, port net.Port, streamSet
|
|||||||
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)
|
||||||
}
|
}
|
||||||
l.h3listener = &QListener{
|
l.h3listener = &QListener{
|
||||||
Qface: l.h3listener,
|
QUICListener: l.h3listener,
|
||||||
quicParams: quicParams,
|
quicParams: quicParams,
|
||||||
}
|
}
|
||||||
errors.LogInfo(ctx, "listening QUIC for XHTTP/3 on ", address, ":", port)
|
errors.LogInfo(ctx, "listening QUIC for XHTTP/3 on ", address, ":", port)
|
||||||
|
|
||||||
@@ -615,21 +615,13 @@ func init() {
|
|||||||
common.Must(internet.RegisterTransportListener(protocolName, ListenXH))
|
common.Must(internet.RegisterTransportListener(protocolName, ListenXH))
|
||||||
}
|
}
|
||||||
|
|
||||||
type Qface interface {
|
|
||||||
Accept(ctx context.Context) (*quic.Conn, error)
|
|
||||||
Addr() net.Addr
|
|
||||||
Close() error
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ Qface = (*quic.EarlyListener)(nil)
|
|
||||||
|
|
||||||
type QListener struct {
|
type QListener struct {
|
||||||
Qface
|
http3.QUICListener
|
||||||
quicParams *internet.QuicParams
|
quicParams *internet.QuicParams
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *QListener) Accept(ctx context.Context) (*quic.Conn, error) {
|
func (l *QListener) Accept(ctx context.Context) (*quic.Conn, error) {
|
||||||
conn, err := l.Qface.Accept(ctx)
|
conn, err := l.QUICListener.Accept(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,14 +44,10 @@ func resolveSrcAddr(network net.Network, src net.Address) net.Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasBindAddr(sockopt *SocketConfig) bool {
|
|
||||||
return sockopt != nil && len(sockopt.BindAddress) > 0 && sockopt.BindPort > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
|
func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest net.Destination, sockopt *SocketConfig) (net.Conn, error) {
|
||||||
errors.LogDebug(ctx, "dialing to "+dest.String())
|
errors.LogDebug(ctx, "dialing to "+dest.String())
|
||||||
|
|
||||||
if dest.Network == net.Network_UDP && !hasBindAddr(sockopt) {
|
if dest.Network == net.Network_UDP {
|
||||||
srcAddr := resolveSrcAddr(net.Network_UDP, src)
|
srcAddr := resolveSrcAddr(net.Network_UDP, src)
|
||||||
if srcAddr == nil {
|
if srcAddr == nil {
|
||||||
srcAddr = &net.UDPAddr{
|
srcAddr = &net.UDPAddr{
|
||||||
@@ -132,11 +128,6 @@ func (d *DefaultSystemDialer) Dial(ctx context.Context, src net.Address, dest ne
|
|||||||
if err := applyOutboundSocketOptions(network, address, fd, sockopt); err != nil {
|
if err := applyOutboundSocketOptions(network, address, fd, sockopt); err != nil {
|
||||||
errors.LogInfoInner(ctx, err, "failed to apply socket options")
|
errors.LogInfoInner(ctx, err, "failed to apply socket options")
|
||||||
}
|
}
|
||||||
if dest.Network == net.Network_UDP && hasBindAddr(sockopt) {
|
|
||||||
if err := bindAddr(fd, sockopt.BindAddress, sockopt.BindPort); err != nil {
|
|
||||||
errors.LogInfoInner(ctx, err, "failed to bind source address to ", sockopt.BindAddress)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -228,7 +219,7 @@ type FakePacketConn struct {
|
|||||||
|
|
||||||
func (c *FakePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
func (c *FakePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||||
n, err = c.Read(p)
|
n, err = c.Read(p)
|
||||||
return n, c.RemoteAddr(), err
|
return n, &net.UDPAddr{IP: c.Conn.RemoteAddr().(*net.TCPAddr).IP, Port: c.Conn.RemoteAddr().(*net.TCPAddr).Port}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *FakePacketConn) WriteTo(p []byte, _ net.Addr) (n int, err error) {
|
func (c *FakePacketConn) WriteTo(p []byte, _ net.Addr) (n int, err error) {
|
||||||
@@ -236,15 +227,5 @@ func (c *FakePacketConn) WriteTo(p []byte, _ net.Addr) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *FakePacketConn) LocalAddr() net.Addr {
|
func (c *FakePacketConn) LocalAddr() net.Addr {
|
||||||
return &net.UDPAddr{
|
return &net.UDPAddr{IP: c.Conn.LocalAddr().(*net.TCPAddr).IP, Port: c.Conn.LocalAddr().(*net.TCPAddr).Port}
|
||||||
IP: []byte{0, 0, 0, 0},
|
|
||||||
Port: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *FakePacketConn) RemoteAddr() net.Addr {
|
|
||||||
return &net.UDPAddr{
|
|
||||||
IP: []byte{0, 0, 0, 0},
|
|
||||||
Port: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ func init() {
|
|||||||
|
|
||||||
if streamSettings != nil && streamSettings.UdpmaskManager != nil {
|
if streamSettings != nil && streamSettings.UdpmaskManager != nil {
|
||||||
var pktConn net.PacketConn
|
var pktConn net.PacketConn
|
||||||
var udpAddr = conn.RemoteAddr().(*net.UDPAddr)
|
var udpAddr *net.UDPAddr
|
||||||
switch c := conn.(type) {
|
switch c := conn.(type) {
|
||||||
case *internet.PacketConnWrapper:
|
case *internet.PacketConnWrapper:
|
||||||
pktConn = c.PacketConn
|
pktConn = c.PacketConn
|
||||||
case *net.UDPConn:
|
udpAddr = c.RemoteAddr().(*net.UDPAddr)
|
||||||
pktConn = c
|
|
||||||
case *cnc.Connection:
|
case *cnc.Connection:
|
||||||
pktConn = &internet.FakePacketConn{Conn: c}
|
pktConn = &internet.FakePacketConn{Conn: c}
|
||||||
|
udpAddr = &net.UDPAddr{IP: c.RemoteAddr().(*net.TCPAddr).IP, Port: c.RemoteAddr().(*net.TCPAddr).Port}
|
||||||
default:
|
default:
|
||||||
panic(reflect.TypeOf(c))
|
panic(reflect.TypeOf(c))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user