diff --git a/component/dialer/bind.go b/component/dialer/bind.go new file mode 100644 index 00000000..34d40ca2 --- /dev/null +++ b/component/dialer/bind.go @@ -0,0 +1,51 @@ +package dialer + +import ( + "net" + "net/netip" + "strings" + + "github.com/Dreamacro/clash/component/iface" +) + +func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) { + ifaceObj, err := iface.ResolveInterface(ifaceName) + if err != nil { + return nil, err + } + + var addr *netip.Prefix + switch network { + case "udp4", "tcp4": + addr, err = ifaceObj.PickIPv4Addr(destination) + case "tcp6", "udp6": + addr, err = ifaceObj.PickIPv6Addr(destination) + default: + if destination.IsValid() { + if destination.Is4() { + addr, err = ifaceObj.PickIPv4Addr(destination) + } else { + addr, err = ifaceObj.PickIPv6Addr(destination) + } + } else { + addr, err = ifaceObj.PickIPv4Addr(destination) + } + } + if err != nil { + return nil, err + } + + if strings.HasPrefix(network, "tcp") { + return &net.TCPAddr{ + IP: addr.Addr().AsSlice(), + Port: port, + }, nil + } else if strings.HasPrefix(network, "udp") { + return &net.UDPAddr{ + IP: addr.Addr().AsSlice(), + Port: port, + }, nil + } + + return nil, iface.ErrAddrNotFound +} diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go index 5cb2fd62..5fd02a66 100644 --- a/component/dialer/bind_others.go +++ b/component/dialer/bind_others.go @@ -7,52 +7,8 @@ import ( "net/netip" "strconv" "strings" - - "github.com/Dreamacro/clash/component/iface" ) -func lookupLocalAddr(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) { - ifaceObj, err := iface.ResolveInterface(ifaceName) - if err != nil { - return nil, err - } - - var addr *netip.Prefix - switch network { - case "udp4", "tcp4": - addr, err = ifaceObj.PickIPv4Addr(destination) - case "tcp6", "udp6": - addr, err = ifaceObj.PickIPv6Addr(destination) - default: - if destination.IsValid() { - if destination.Is4() { - addr, err = ifaceObj.PickIPv4Addr(destination) - } else { - addr, err = ifaceObj.PickIPv6Addr(destination) - } - } else { - addr, err = ifaceObj.PickIPv4Addr(destination) - } - } - if err != nil { - return nil, err - } - - if strings.HasPrefix(network, "tcp") { - return &net.TCPAddr{ - IP: addr.Addr().AsSlice(), - Port: port, - }, nil - } else if strings.HasPrefix(network, "udp") { - return &net.UDPAddr{ - IP: addr.Addr().AsSlice(), - Port: port, - }, nil - } - - return nil, iface.ErrAddrNotFound -} - func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error { if !destination.IsGlobalUnicast() { return nil @@ -66,7 +22,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des } } - addr, err := lookupLocalAddr(ifaceName, network, destination, int(local)) + addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, destination, int(local)) if err != nil { return err } @@ -84,7 +40,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add local, _ := strconv.ParseUint(port, 10, 16) - addr, err := lookupLocalAddr(ifaceName, network, netip.Addr{}, int(local)) + addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, netip.Addr{}, int(local)) if err != nil { return "", err } diff --git a/transport/hysteria/conns/faketcp/tcp_linux.go b/transport/hysteria/conns/faketcp/tcp_linux.go index cdee9fda..1d6f277c 100644 --- a/transport/hysteria/conns/faketcp/tcp_linux.go +++ b/transport/hysteria/conns/faketcp/tcp_linux.go @@ -19,6 +19,8 @@ import ( "github.com/coreos/go-iptables/iptables" "github.com/google/gopacket" "github.com/google/gopacket/layers" + + "github.com/Dreamacro/clash/component/dialer" ) var ( @@ -398,15 +400,27 @@ func Dial(network, address string) (*TCPConn, error) { return nil, err } + var lTcpAddr *net.TCPAddr + var lIpAddr *net.IPAddr + if ifaceName := dialer.DefaultInterface.Load(); len(ifaceName) > 0 { + rAddrPort := raddr.AddrPort() + addr, err := dialer.LookupLocalAddrFromIfaceName(ifaceName, network, rAddrPort.Addr(), int(rAddrPort.Port())) + if err != nil { + return nil, err + } + lTcpAddr = addr.(*net.TCPAddr) + lIpAddr = &net.IPAddr{IP: lTcpAddr.IP} + } + // AF_INET - handle, err := net.DialIP("ip:tcp", nil, &net.IPAddr{IP: raddr.IP}) + handle, err := net.DialIP("ip:tcp", lIpAddr, &net.IPAddr{IP: raddr.IP}) if err != nil { return nil, err } // create an established tcp connection // will hack this tcp connection for packet transmission - tcpconn, err := net.DialTCP(network, nil, raddr) + tcpconn, err := net.DialTCP(network, lTcpAddr, raddr) if err != nil { return nil, err }