diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index 5dd4148d..9a024529 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -1,13 +1,13 @@ package inbound import ( + "github.com/Dreamacro/clash/common/nnip" "net" "net/http" "net/netip" "strconv" "strings" - "github.com/Dreamacro/clash/common/nnip" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -26,7 +26,8 @@ func parseSocksAddr(target socks5.Addr) *C.Metadata { metadata.DstIP = nnip.IpToAddr(net.IP(target[1 : 1+net.IPv4len])) metadata.DstPort = strconv.Itoa((int(target[1+net.IPv4len]) << 8) | int(target[1+net.IPv4len+1])) case socks5.AtypIPv6: - metadata.DstIP = nnip.IpToAddr(net.IP(target[1 : 1+net.IPv6len])) + ip6, _ := netip.AddrFromSlice(target[1 : 1+net.IPv6len]) + metadata.DstIP = ip6.Unmap() metadata.DstPort = strconv.Itoa((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1])) } diff --git a/tunnel/connection.go b/tunnel/connection.go index 0384e805..c63bab78 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -3,26 +3,17 @@ package tunnel import ( "errors" "net" + "net/netip" "time" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" ) func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error { defer packet.Drop() - // local resolve UDP dns - if !metadata.Resolved() { - ip, err := resolver.ResolveIP(metadata.Host) - if err != nil { - return err - } - metadata.DstIP = ip - } - addr := metadata.UDPAddr() if addr == nil { return errors.New("udp addr invalid") @@ -32,29 +23,36 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata return err } // reset timeout - pc.SetReadDeadline(time.Now().Add(udpTimeout)) + _ = pc.SetReadDeadline(time.Now().Add(udpTimeout)) return nil } -func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, fAddr net.Addr) { +func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, fAddr netip.Addr) { buf := pool.Get(pool.UDPBufferSize) - defer pool.Put(buf) - defer natTable.Delete(key) - defer pc.Close() + defer func() { + _ = pc.Close() + natTable.Delete(key) + _ = pool.Put(buf) + }() for { - pc.SetReadDeadline(time.Now().Add(udpTimeout)) + _ = pc.SetReadDeadline(time.Now().Add(udpTimeout)) n, from, err := pc.ReadFrom(buf) if err != nil { return } - if fAddr != nil { - from = fAddr + fromUDPAddr := from.(*net.UDPAddr) + if fAddr.IsValid() { + fromAddr, _ := netip.AddrFromSlice(fromUDPAddr.IP) + fromAddr.Unmap() + if oAddr == fromAddr { + fromUDPAddr.IP = fAddr.AsSlice() + } } - _, err = packet.WriteBack(buf[:n], from) + _, err = packet.WriteBack(buf[:n], fromUDPAddr) if err != nil { return } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index dbe48ee6..b0ec5789 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -209,9 +209,9 @@ func handleUDPConn(packet *inbound.PacketAdapter) { } // make a fAddr if request ip is fakeip - var fAddr net.Addr + var fAddr netip.Addr if resolver.IsExistFakeIP(metadata.DstIP) { - fAddr = metadata.UDPAddr() + fAddr = metadata.DstIP } if err := preHandleMetadata(metadata); err != nil { @@ -219,6 +219,15 @@ func handleUDPConn(packet *inbound.PacketAdapter) { return } + // local resolve UDP dns + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(metadata.Host) + if err != nil { + return + } + metadata.DstIP = ip + } + key := packet.LocalAddr().String() handle := func() bool { @@ -288,7 +297,8 @@ func handleUDPConn(packet *inbound.PacketAdapter) { log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) } - go handleUDPToLocal(packet.UDPPacket, pc, key, fAddr) + oAddr := metadata.DstIP + go handleUDPToLocal(packet.UDPPacket, pc, key, oAddr, fAddr) natTable.Set(key, pc) handle()