mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-12 21:18:03 +08:00
chore: dialer will consider the routing of the local interface when auto-detect-interface in tun is enabled
for #1881 #1819
This commit is contained in:
parent
00e6466153
commit
4bd3ae52bd
@ -88,6 +88,15 @@ func ListenPacket(ctx context.Context, network, address string, rAddrPort netip.
|
|||||||
if DefaultSocketHook != nil { // ignore interfaceName, routingMark when DefaultSocketHook not null (in CMFA)
|
if DefaultSocketHook != nil { // ignore interfaceName, routingMark when DefaultSocketHook not null (in CMFA)
|
||||||
socketHookToListenConfig(lc)
|
socketHookToListenConfig(lc)
|
||||||
} else {
|
} else {
|
||||||
|
if cfg.interfaceName == "" {
|
||||||
|
if finder := DefaultInterfaceFinder.Load(); finder != nil {
|
||||||
|
cfg.interfaceName = finder.FindInterfaceName(rAddrPort.Addr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rAddrPort.Addr().Unmap().IsLoopback() {
|
||||||
|
// avoid "The requested address is not valid in its context."
|
||||||
|
cfg.interfaceName = ""
|
||||||
|
}
|
||||||
if cfg.interfaceName != "" {
|
if cfg.interfaceName != "" {
|
||||||
bind := bindIfaceToListenConfig
|
bind := bindIfaceToListenConfig
|
||||||
if cfg.fallbackBind {
|
if cfg.fallbackBind {
|
||||||
@ -153,6 +162,11 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po
|
|||||||
if DefaultSocketHook != nil { // ignore interfaceName, routingMark and tfo when DefaultSocketHook not null (in CMFA)
|
if DefaultSocketHook != nil { // ignore interfaceName, routingMark and tfo when DefaultSocketHook not null (in CMFA)
|
||||||
socketHookToToDialer(dialer)
|
socketHookToToDialer(dialer)
|
||||||
} else {
|
} else {
|
||||||
|
if opt.interfaceName == "" {
|
||||||
|
if finder := DefaultInterfaceFinder.Load(); finder != nil {
|
||||||
|
opt.interfaceName = finder.FindInterfaceName(destination)
|
||||||
|
}
|
||||||
|
}
|
||||||
if opt.interfaceName != "" {
|
if opt.interfaceName != "" {
|
||||||
bind := bindIfaceToDialer
|
bind := bindIfaceToDialer
|
||||||
if opt.fallbackBind {
|
if opt.fallbackBind {
|
||||||
@ -373,12 +387,7 @@ func (d Dialer) DialContext(ctx context.Context, network, address string) (net.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) {
|
func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) {
|
||||||
opt := d.Opt // make a copy
|
return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, rAddrPort, WithOption(d.Opt))
|
||||||
if rAddrPort.Addr().Unmap().IsLoopback() {
|
|
||||||
// avoid "The requested address is not valid in its context."
|
|
||||||
WithInterface("")(&opt)
|
|
||||||
}
|
|
||||||
return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, rAddrPort, WithOption(opt))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDialer(options ...Option) Dialer {
|
func NewDialer(options ...Option) Dialer {
|
||||||
|
@ -3,6 +3,7 @@ package dialer
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/common/atomic"
|
"github.com/metacubex/mihomo/common/atomic"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
"github.com/metacubex/mihomo/component/resolver"
|
||||||
@ -12,8 +13,14 @@ var (
|
|||||||
DefaultOptions []Option
|
DefaultOptions []Option
|
||||||
DefaultInterface = atomic.NewTypedValue[string]("")
|
DefaultInterface = atomic.NewTypedValue[string]("")
|
||||||
DefaultRoutingMark = atomic.NewInt32(0)
|
DefaultRoutingMark = atomic.NewInt32(0)
|
||||||
|
|
||||||
|
DefaultInterfaceFinder = atomic.NewTypedValue[InterfaceFinder](nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type InterfaceFinder interface {
|
||||||
|
FindInterfaceName(destination netip.Addr) string
|
||||||
|
}
|
||||||
|
|
||||||
type NetDialer interface {
|
type NetDialer interface {
|
||||||
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
DialContext(ctx context.Context, network, address string) (net.Conn, error)
|
||||||
}
|
}
|
||||||
|
@ -512,9 +512,6 @@ func ReCreateTun(tunConf LC.Tun, tunnel C.Tunnel) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
if tunConf.Equal(LastTunConf) {
|
if tunConf.Equal(LastTunConf) {
|
||||||
if tunLister != nil {
|
|
||||||
tunLister.FlushDefaultInterface()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,8 @@ type Listener struct {
|
|||||||
autoRedirect tun.AutoRedirect
|
autoRedirect tun.AutoRedirect
|
||||||
autoRedirectOutputMark int32
|
autoRedirectOutputMark int32
|
||||||
|
|
||||||
|
cDialerInterfaceFinder dialer.InterfaceFinder
|
||||||
|
|
||||||
ruleUpdateCallbackCloser io.Closer
|
ruleUpdateCallbackCloser io.Closer
|
||||||
ruleUpdateMutex sync.Mutex
|
ruleUpdateMutex sync.Mutex
|
||||||
routeAddressMap map[string]*netipx.IPSet
|
routeAddressMap map[string]*netipx.IPSet
|
||||||
@ -290,13 +292,25 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis
|
|||||||
}
|
}
|
||||||
l.defaultInterfaceMonitor = defaultInterfaceMonitor
|
l.defaultInterfaceMonitor = defaultInterfaceMonitor
|
||||||
defaultInterfaceMonitor.RegisterCallback(func(event int) {
|
defaultInterfaceMonitor.RegisterCallback(func(event int) {
|
||||||
l.FlushDefaultInterface()
|
iface.FlushCache()
|
||||||
|
resolver.ResetConnection() // reset resolver's connection after default interface changed
|
||||||
})
|
})
|
||||||
err = defaultInterfaceMonitor.Start()
|
err = defaultInterfaceMonitor.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = E.Cause(err, "start DefaultInterfaceMonitor")
|
err = E.Cause(err, "start DefaultInterfaceMonitor")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if options.AutoDetectInterface {
|
||||||
|
l.cDialerInterfaceFinder = &cDialerInterfaceFinder{
|
||||||
|
tunName: tunName,
|
||||||
|
defaultInterfaceMonitor: defaultInterfaceMonitor,
|
||||||
|
}
|
||||||
|
if !dialer.DefaultInterfaceFinder.CompareAndSwap(nil, l.cDialerInterfaceFinder) {
|
||||||
|
err = E.New("don't allowed two tun listener using auto-detect-interface")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tunOptions := tun.Options{
|
tunOptions := tun.Options{
|
||||||
@ -503,27 +517,25 @@ func (l *Listener) updateRule(ruleProvider provider.RuleProvider, exclude bool,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Listener) FlushDefaultInterface() {
|
type cDialerInterfaceFinder struct {
|
||||||
if l.options.AutoDetectInterface && l.defaultInterfaceMonitor != nil {
|
tunName string
|
||||||
for _, destination := range []netip.Addr{netip.IPv4Unspecified(), netip.IPv6Unspecified(), netip.MustParseAddr("1.1.1.1")} {
|
defaultInterfaceMonitor tun.DefaultInterfaceMonitor
|
||||||
autoDetectInterfaceName := l.defaultInterfaceMonitor.DefaultInterfaceName(destination)
|
}
|
||||||
if autoDetectInterfaceName == l.tunName {
|
|
||||||
log.Warnln("[TUN] Auto detect interface by %s get same name with tun", destination.String())
|
func (d *cDialerInterfaceFinder) FindInterfaceName(destination netip.Addr) string {
|
||||||
} else if autoDetectInterfaceName == "" || autoDetectInterfaceName == "<nil>" {
|
for _, dest := range []netip.Addr{destination, netip.IPv4Unspecified(), netip.IPv6Unspecified()} {
|
||||||
log.Warnln("[TUN] Auto detect interface by %s get empty name.", destination.String())
|
autoDetectInterfaceName := d.defaultInterfaceMonitor.DefaultInterfaceName(dest)
|
||||||
} else {
|
if autoDetectInterfaceName == d.tunName {
|
||||||
if old := dialer.DefaultInterface.Swap(autoDetectInterfaceName); old != autoDetectInterfaceName {
|
log.Warnln("[TUN] Auto detect interface for %s get same name with tun", destination.String())
|
||||||
log.Warnln("[TUN] default interface changed by monitor, %s => %s", old, autoDetectInterfaceName)
|
} else if autoDetectInterfaceName == "" || autoDetectInterfaceName == "<nil>" {
|
||||||
iface.FlushCache()
|
log.Warnln("[TUN] Auto detect interface for %s get empty name.", destination.String())
|
||||||
resolver.ResetConnection() // reset resolver's connection after default interface changed
|
} else {
|
||||||
}
|
log.Debugln("[TUN] Auto detect interface for %s --> %s", destination, autoDetectInterfaceName)
|
||||||
return
|
return autoDetectInterfaceName
|
||||||
}
|
|
||||||
}
|
|
||||||
if dialer.DefaultInterface.CompareAndSwap("", "<invalid>") {
|
|
||||||
log.Warnln("[TUN] Auto detect interface failed, set '<invalid>' to DefaultInterface to avoid lookback")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Warnln("[TUN] Auto detect interface for %s failed, return '<invalid>' to avoid lookback", destination)
|
||||||
|
return "<invalid>"
|
||||||
}
|
}
|
||||||
|
|
||||||
func uidToRange(uidList []uint32) []ranges.Range[uint32] {
|
func uidToRange(uidList []uint32) []ranges.Range[uint32] {
|
||||||
@ -564,6 +576,9 @@ func (l *Listener) Close() error {
|
|||||||
if l.autoRedirectOutputMark != 0 {
|
if l.autoRedirectOutputMark != 0 {
|
||||||
dialer.DefaultRoutingMark.CompareAndSwap(l.autoRedirectOutputMark, 0)
|
dialer.DefaultRoutingMark.CompareAndSwap(l.autoRedirectOutputMark, 0)
|
||||||
}
|
}
|
||||||
|
if l.cDialerInterfaceFinder != nil {
|
||||||
|
dialer.DefaultInterfaceFinder.CompareAndSwap(l.cDialerInterfaceFinder, nil)
|
||||||
|
}
|
||||||
return common.Close(
|
return common.Close(
|
||||||
l.ruleUpdateCallbackCloser,
|
l.ruleUpdateCallbackCloser,
|
||||||
l.tunStack,
|
l.tunStack,
|
||||||
|
@ -404,8 +404,14 @@ func Dial(network, address string) (*TCPConn, error) {
|
|||||||
|
|
||||||
var lTcpAddr *net.TCPAddr
|
var lTcpAddr *net.TCPAddr
|
||||||
var lIpAddr *net.IPAddr
|
var lIpAddr *net.IPAddr
|
||||||
if ifaceName := dialer.DefaultInterface.Load(); len(ifaceName) > 0 {
|
rAddrPort := raddr.AddrPort()
|
||||||
rAddrPort := raddr.AddrPort()
|
ifaceName := dialer.DefaultInterface.Load()
|
||||||
|
if ifaceName == "" {
|
||||||
|
if finder := dialer.DefaultInterfaceFinder.Load(); finder != nil {
|
||||||
|
ifaceName = finder.FindInterfaceName(rAddrPort.Addr())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(ifaceName) > 0 {
|
||||||
addr, err := dialer.LookupLocalAddrFromIfaceName(ifaceName, network, rAddrPort.Addr(), int(rAddrPort.Port()))
|
addr, err := dialer.LookupLocalAddrFromIfaceName(ifaceName, network, rAddrPort.Addr(), int(rAddrPort.Port()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
Loading…
Reference in New Issue
Block a user