diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 5b6ef705..0d6cdb8c 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -93,6 +93,11 @@ func (b *Base) SupportTFO() bool { return b.tfo } +// IsL3Protocol implements C.ProxyAdapter +func (b *Base) IsL3Protocol(metadata *C.Metadata) bool { + return false +} + // MarshalJSON implements C.ProxyAdapter func (b *Base) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]string{ diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 0070ce46..a2634be4 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -401,3 +401,8 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat } return newPacketConn(CN.NewRefPacketConn(pc, w), w), nil } + +// IsL3Protocol implements C.ProxyAdapter +func (w *WireGuard) IsL3Protocol(metadata *C.Metadata) bool { + return true +} diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 02ba0ac6..c79d9871 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -70,6 +70,11 @@ func (f *Fallback) SupportUDP() bool { return proxy.SupportUDP() } +// IsL3Protocol implements C.ProxyAdapter +func (f *Fallback) IsL3Protocol(metadata *C.Metadata) bool { + return f.findAliveProxy(false).IsL3Protocol(metadata) +} + // MarshalJSON implements C.ProxyAdapter func (f *Fallback) MarshalJSON() ([]byte, error) { all := []string{} diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 15e17a13..607d4f4f 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -124,6 +124,11 @@ func (lb *LoadBalance) SupportUDP() bool { return !lb.disableUDP } +// IsL3Protocol implements C.ProxyAdapter +func (lb *LoadBalance) IsL3Protocol(metadata *C.Metadata) bool { + return lb.Unwrap(metadata, false).IsL3Protocol(metadata) +} + func strategyRoundRobin() strategyFn { idx := 0 idxMutex := sync.Mutex{} diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go index 6356d10e..b5b1cfa3 100644 --- a/adapter/outboundgroup/selector.go +++ b/adapter/outboundgroup/selector.go @@ -44,6 +44,11 @@ func (s *Selector) SupportUDP() bool { return s.selectedProxy(false).SupportUDP() } +// IsL3Protocol implements C.ProxyAdapter +func (s *Selector) IsL3Protocol(metadata *C.Metadata) bool { + return s.selectedProxy(false).IsL3Protocol(metadata) +} + // MarshalJSON implements C.ProxyAdapter func (s *Selector) MarshalJSON() ([]byte, error) { all := []string{} diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index f3426a3e..6f10f78b 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -147,6 +147,11 @@ func (u *URLTest) SupportUDP() bool { return u.fast(false).SupportUDP() } +// IsL3Protocol implements C.ProxyAdapter +func (u *URLTest) IsL3Protocol(metadata *C.Metadata) bool { + return u.fast(false).IsL3Protocol(metadata) +} + // MarshalJSON implements C.ProxyAdapter func (u *URLTest) MarshalJSON() ([]byte, error) { all := []string{} diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index f5872ad7..3b5426d8 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -48,6 +48,7 @@ type Resolver interface { ResolveIPv4(ctx context.Context, host string) (ip netip.Addr, err error) ResolveIPv6(ctx context.Context, host string) (ip netip.Addr, err error) ExchangeContext(ctx context.Context, m *dns.Msg) (msg *dns.Msg, err error) + Invalid() bool } // LookupIPv4WithResolver same as LookupIPv4, but with a resolver @@ -68,7 +69,7 @@ func LookupIPv4WithResolver(ctx context.Context, host string, r Resolver) ([]net return []netip.Addr{}, ErrIPVersion } - if r != nil { + if r != nil && r.Invalid() { return r.LookupIPv4(ctx, host) } @@ -124,7 +125,7 @@ func LookupIPv6WithResolver(ctx context.Context, host string, r Resolver) ([]net return nil, ErrIPVersion } - if r != nil { + if r != nil && r.Invalid() { return r.LookupIPv6(ctx, host) } @@ -164,7 +165,7 @@ func LookupIPWithResolver(ctx context.Context, host string, r Resolver) ([]netip return node.IPs, nil } - if r != nil { + if r != nil && r.Invalid() { if DisableIPv6 { return r.LookupIPv4(ctx, host) } diff --git a/constant/adapters.go b/constant/adapters.go index 3b401734..2a2c68c1 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -124,6 +124,9 @@ type ProxyAdapter interface { DialContextWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (Conn, error) ListenPacketWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (PacketConn, error) + // IsL3Protocol return ProxyAdapter working in L3 (tell dns module not pass the domain to avoid loopback) + IsL3Protocol(metadata *Metadata) bool + // Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract. Unwrap(metadata *Metadata, touch bool) Proxy } diff --git a/dns/resolver.go b/dns/resolver.go index 25bfedf0..467e9f14 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -412,8 +412,11 @@ func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D return ch } -// HasProxyServer has proxy server dns client -func (r *Resolver) HasProxyServer() bool { +// Invalid return this resolver can or can't be used +func (r *Resolver) Invalid() bool { + if r == nil { + return false + } return len(r.main) > 0 } diff --git a/dns/util.go b/dns/util.go index 2fe85931..9df4482b 100644 --- a/dns/util.go +++ b/dns/util.go @@ -170,6 +170,14 @@ func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, Host: host, DstPort: port, } + if proxyAdapter.IsL3Protocol(metadata) { + dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r) + if err != nil { + return nil, err + } + metadata.Host = "" + metadata.DstIP = dstIP + } if proxyAdapter != nil { return proxyAdapter.DialContext(ctx, metadata, opts...) } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 8ca844d2..3598d873 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -239,7 +239,7 @@ func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, gen resolver.DefaultHostMapper = m resolver.DefaultLocalServer = dns.NewLocalServer(r, m) - if pr.HasProxyServer() { + if pr.Invalid() { resolver.ProxyServerHostResolver = pr }