fix: hysteria faketcp loopback in tun mode
This commit is contained in:
parent
1a44dcee55
commit
4e46cbfbde
3 changed files with 69 additions and 48 deletions
51
component/dialer/bind.go
Normal file
51
component/dialer/bind.go
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -7,52 +7,8 @@ import (
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"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 {
|
func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error {
|
||||||
if !destination.IsGlobalUnicast() {
|
if !destination.IsGlobalUnicast() {
|
||||||
return nil
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -84,7 +40,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add
|
||||||
|
|
||||||
local, _ := strconv.ParseUint(port, 10, 16)
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,8 @@ import (
|
||||||
"github.com/coreos/go-iptables/iptables"
|
"github.com/coreos/go-iptables/iptables"
|
||||||
"github.com/google/gopacket"
|
"github.com/google/gopacket"
|
||||||
"github.com/google/gopacket/layers"
|
"github.com/google/gopacket/layers"
|
||||||
|
|
||||||
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -398,15 +400,27 @@ func Dial(network, address string) (*TCPConn, error) {
|
||||||
return nil, err
|
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
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create an established tcp connection
|
// create an established tcp connection
|
||||||
// will hack this tcp connection for packet transmission
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue