diff --git a/docs/configuration/shared/listen.md b/docs/configuration/shared/listen.md index f20d42a3..8b2e5ad1 100644 --- a/docs/configuration/shared/listen.md +++ b/docs/configuration/shared/listen.md @@ -8,6 +8,7 @@ "udp_fragment": false, "sniff": false, "sniff_override_destination": false, + "sniff_override_fallback": false, "sniff_timeout": "300ms", "domain_strategy": "prefer_ipv6", "udp_timeout": 300, @@ -58,6 +59,12 @@ Override the connection destination address with the sniffed domain. If the domain name is invalid (like tor), this will not work. +#### sniff_override_fallback + +If the sniffed domain fails to be resolved when `sniff_override_destination` is enabled, use the original destination address as fallback. + +Helpful when using customized domain. + #### sniff_timeout Timeout for sniffing. diff --git a/docs/configuration/shared/listen.zh.md b/docs/configuration/shared/listen.zh.md index f9f469d2..f0e415d4 100644 --- a/docs/configuration/shared/listen.zh.md +++ b/docs/configuration/shared/listen.zh.md @@ -8,6 +8,7 @@ "udp_fragment": false, "sniff": false, "sniff_override_destination": false, + "sniff_override_fallback": false, "sniff_timeout": "300ms", "domain_strategy": "prefer_ipv6", "udp_timeout": 300, @@ -59,6 +60,12 @@ 如果域名无效(如 Tor),将不生效。 +#### sniff_override_fallback + +当 `sniff_override_destination` 开启且探测出的域名解析失败时,回退使用原连接目标地址。 + +当使用自定义域名时有帮助。 + #### sniff_timeout 探测超时时间。 diff --git a/option/inbound.go b/option/inbound.go index 9533532b..d95f533b 100644 --- a/option/inbound.go +++ b/option/inbound.go @@ -112,6 +112,7 @@ func (h *Inbound) UnmarshalJSON(bytes []byte) error { type InboundOptions struct { SniffEnabled bool `json:"sniff,omitempty"` SniffOverrideDestination bool `json:"sniff_override_destination,omitempty"` + SniffOverrideFallback bool `json:"sniff_override_fallback,omitempty"` SniffTimeout Duration `json:"sniff_timeout,omitempty"` DomainStrategy DomainStrategy `json:"domain_strategy,omitempty"` } diff --git a/route/router.go b/route/router.go index c23c8a45..bc995413 100644 --- a/route/router.go +++ b/route/router.go @@ -645,6 +645,9 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad metadata.Protocol = sniffMetadata.Protocol metadata.Domain = sniffMetadata.Domain if metadata.InboundOptions.SniffOverrideDestination && M.IsDomainName(metadata.Domain) { + if metadata.InboundOptions.SniffOverrideFallback && metadata.Destination.Addr.IsValid() { + metadata.DestinationAddresses = []netip.Addr{metadata.Destination.Addr} + } metadata.Destination = M.Socksaddr{ Fqdn: metadata.Domain, Port: metadata.Destination.Port, @@ -676,10 +679,14 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad if metadata.Destination.IsFqdn() && dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS { addresses, err := r.Lookup(adapter.WithContext(ctx, &metadata), metadata.Destination.Fqdn, dns.DomainStrategy(metadata.InboundOptions.DomainStrategy)) if err != nil { - return err + if len(metadata.DestinationAddresses) == 0 { + return err + } + r.logger.WarnContext(ctx, "using original destination [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") + } else { + metadata.DestinationAddresses = addresses + r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") } - metadata.DestinationAddresses = addresses - r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") } ctx, matchedRule, detour, err := r.match(ctx, &metadata, r.defaultOutboundForConnection) if err != nil { @@ -784,10 +791,14 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m if metadata.Destination.IsFqdn() && dns.DomainStrategy(metadata.InboundOptions.DomainStrategy) != dns.DomainStrategyAsIS { addresses, err := r.Lookup(adapter.WithContext(ctx, &metadata), metadata.Destination.Fqdn, dns.DomainStrategy(metadata.InboundOptions.DomainStrategy)) if err != nil { - return err + if len(metadata.DestinationAddresses) == 0 { + return err + } + r.logger.WarnContext(ctx, "using original destination [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") + } else { + metadata.DestinationAddresses = addresses + r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") } - metadata.DestinationAddresses = addresses - r.dnsLogger.DebugContext(ctx, "resolved [", strings.Join(F.MapToString(metadata.DestinationAddresses), " "), "]") } ctx, matchedRule, detour, err := r.match(ctx, &metadata, r.defaultOutboundForPacketConnection) if err != nil {