diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 14bd96b0..e2ed24c2 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -12,6 +12,7 @@ import ( "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" + "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/restls" obfs "github.com/Dreamacro/clash/transport/simple-obfs" @@ -184,12 +185,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - destination := M.ParseSocksaddr(metadata.RemoteAddress()) - if ss.option.UDPOverTCPVersion == 1 { - return newPacketConn(uot.NewConn(tcpConn, uot.Request{Destination: destination}), ss), nil - } else { - return newPacketConn(uot.NewLazyConn(tcpConn, uot.Request{Destination: destination}), ss), nil - } + return ss.ListenPacketOnStreamConn(ctx, tcpConn, metadata) } addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) if err != nil { @@ -210,9 +206,18 @@ func (ss *ShadowSocks) SupportWithDialer() C.NetWork { } // ListenPacketOnStreamConn implements C.ProxyAdapter -func (ss *ShadowSocks) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { +func (ss *ShadowSocks) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { if ss.option.UDPOverTCP { - destination := M.ParseSocksaddr(metadata.RemoteAddress()) + // ss uot use stream-oriented udp with a special address, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + + destination := M.SocksaddrFromNet(metadata.UDPAddr()) if ss.option.UDPOverTCPVersion == uot.LegacyVersion { return newPacketConn(uot.NewConn(c, uot.Request{Destination: destination}), ss), nil } else { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index b7a22245..ecfa1a13 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -169,7 +169,34 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { return nil, err } - return v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) + return v.streamConn(c, metadata) +} + +func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) { + metadata = &C.Metadata{ // a clear metadata only contains ip + NetWork: metadata.NetWork, + DstIP: metadata.DstIP, + DstPort: metadata.DstPort, + } + if metadata.NetWork == C.UDP { + if v.option.PacketAddr { + metadata = &C.Metadata{ + NetWork: C.UDP, + Host: packetaddr.SeqPacketMagicAddress, + DstPort: "443", + } + } + conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) + if v.option.PacketAddr { + conn = packetaddr.NewBindConn(conn) + } + } else { + conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, false)) + } + if err != nil { + conn = nil + } + return } func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) { @@ -271,7 +298,6 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o } metadata.DstIP = ip } - var c net.Conn // gun transport if v.transport != nil && len(opts) == 0 { @@ -283,21 +309,12 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o safeConnClose(c, err) }(c) - if v.option.PacketAddr { - packetAddrMetadata := *metadata // make a copy - packetAddrMetadata.Host = packetaddr.SeqPacketMagicAddress - packetAddrMetadata.DstPort = "443" - - c, err = v.client.StreamConn(c, parseVlessAddr(&packetAddrMetadata, false)) - } else { - c, err = v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) - } - + c, err = v.streamConn(c, metadata) if err != nil { return nil, fmt.Errorf("new vless client error: %v", err) } - return v.ListenPacketOnStreamConn(c, metadata) + return v.ListenPacketOnStreamConn(ctx, c, metadata) } return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.Base.DialOptions(opts...)...), metadata) } @@ -310,6 +327,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met return nil, err } } + // vless use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) @@ -318,6 +336,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met } metadata.DstIP = ip } + c, err := dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) @@ -327,21 +346,12 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - if v.option.PacketAddr { - packetAddrMetadata := *metadata // make a copy - packetAddrMetadata.Host = packetaddr.SeqPacketMagicAddress - packetAddrMetadata.DstPort = "443" - - c, err = v.StreamConn(c, &packetAddrMetadata) - } else { - c, err = v.StreamConn(c, metadata) - } - + c, err = v.streamConn(c, metadata) if err != nil { return nil, fmt.Errorf("new vless client error: %v", err) } - return v.ListenPacketOnStreamConn(c, metadata) + return v.ListenPacketOnStreamConn(ctx, c, metadata) } // SupportWithDialer implements C.ProxyAdapter @@ -350,7 +360,16 @@ func (v *Vless) SupportWithDialer() C.NetWork { } // ListenPacketOnStreamConn implements C.ProxyAdapter -func (v *Vless) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { +func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { + // vless use stream-oriented udp with a special address, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + if v.option.XUDP { return newPacketConn(&threadSafePacketConn{ PacketConn: vmessSing.NewXUDPConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), @@ -517,6 +536,9 @@ func NewVless(option VlessOption) (*Vless, error) { option.XUDP = true } } + if option.XUDP { + option.PacketAddr = false + } client, err := vless.NewClient(option.UUID, addons, option.FlowShow) if err != nil { diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 710e19bb..8901f3d5 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -217,27 +217,42 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { if err != nil { return nil, err } + return v.streamConn(c, metadata) +} + +func (v *Vmess) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) { if metadata.NetWork == C.UDP { if v.option.XUDP { if N.NeedHandshake(c) { - return v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + conn = v.client.DialEarlyXUDPPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) } else { - return v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + conn, err = v.client.DialXUDPPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) } + } else if v.option.PacketAddr { + if N.NeedHandshake(c) { + conn = v.client.DialEarlyPacketConn(c, M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443)) + } else { + conn, err = v.client.DialPacketConn(c, M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443)) + } + conn = packetaddr.NewBindConn(conn) } else { if N.NeedHandshake(c) { - return v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + conn = v.client.DialEarlyPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) } else { - return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + conn, err = v.client.DialPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) } } } else { if N.NeedHandshake(c) { - return v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + conn = v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) } else { - return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + conn, err = v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) } } + if err != nil { + conn = nil + } + return } // DialContext implements C.ProxyAdapter @@ -293,14 +308,6 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o } metadata.DstIP = ip } - - if v.option.PacketAddr { - _metadata := *metadata // make a copy - metadata = &_metadata - metadata.Host = packetaddr.SeqPacketMagicAddress - metadata.DstPort = "443" - } - var c net.Conn // gun transport if v.transport != nil && len(opts) == 0 { @@ -312,24 +319,11 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o safeConnClose(c, err) }(c) - if v.option.XUDP { - if N.NeedHandshake(c) { - c = v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) - } else { - c, err = v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) - } - } else { - if N.NeedHandshake(c) { - c = v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) - } else { - c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) - } - } - + c, err = v.streamConn(c, metadata) if err != nil { return nil, fmt.Errorf("new vmess client error: %v", err) } - return v.ListenPacketOnStreamConn(c, metadata) + return v.ListenPacketOnStreamConn(ctx, c, metadata) } return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.Base.DialOptions(opts...)...), metadata) } @@ -342,6 +336,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met return nil, err } } + // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) @@ -364,7 +359,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met if err != nil { return nil, fmt.Errorf("new vmess client error: %v", err) } - return v.ListenPacketOnStreamConn(c, metadata) + return v.ListenPacketOnStreamConn(ctx, c, metadata) } // SupportWithDialer implements C.ProxyAdapter @@ -373,10 +368,17 @@ func (v *Vmess) SupportWithDialer() C.NetWork { } // ListenPacketOnStreamConn implements C.ProxyAdapter -func (v *Vmess) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { - if v.option.PacketAddr { - return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindConn(c)}, v), nil - } else if pc, ok := c.(net.PacketConn); ok { +func (v *Vmess) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { + // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + + if pc, ok := c.(net.PacketConn); ok { return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil } return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index e215ff0f..fc5cb294 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -2,6 +2,7 @@ package proxydialer import ( "context" + "errors" "fmt" "net" "net/netip" @@ -9,6 +10,7 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel/statistic" @@ -38,17 +40,18 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( return nil, err } if strings.Contains(network, "udp") { // using in wireguard outbound + if !currentMeta.Resolved() { + ip, err := resolver.ResolveIP(ctx, currentMeta.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + currentMeta.DstIP = ip + } pc, err := p.listenPacket(ctx, currentMeta) if err != nil { return nil, err } - var rAddr net.Addr - if udpAddr := currentMeta.UDPAddr(); udpAddr != nil { - rAddr = udpAddr - } else { // the domain name was not resolved, will appear in not stream-oriented udp like Shadowsocks/Tuic - rAddr = N.NewCustomAddr("udp", currentMeta.RemoteAddress(), nil) - } - return N.NewBindPacketConn(pc, rAddr), nil + return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil } var conn C.Conn var err error