diff --git a/service/resolver/main.go b/service/resolver/main.go index 693797b5..3cd178be 100644 --- a/service/resolver/main.go +++ b/service/resolver/main.go @@ -233,6 +233,9 @@ func AddToDebugInfo(di *debug.Info) { if len(resolver.Search) > 0 { content = append(content, fmt.Sprintf(" Search Domains: %v", strings.Join(resolver.Search, ", "))) } + if resolver.LinkLocalUnavailable { + content = append(content, " Link-local, but not available: ignoring") + } content = append(content, fmt.Sprintf(" Failing: %v", resolver.Conn.IsFailing())) // Add a empty line for all but the last entry. diff --git a/service/resolver/resolve.go b/service/resolver/resolve.go index fe3e11ff..0e35f791 100644 --- a/service/resolver/resolve.go +++ b/service/resolver/resolve.go @@ -422,6 +422,12 @@ func resolveAndCache(ctx context.Context, q *Query, oldCache *RRCache) (rrCache continue } + // Skip unreachable link-local resolvers. + if resolver.LinkLocalUnavailable { + log.Tracer(ctx).Tracef("resolver: skipping resolver %s, because it is link-local and not available", resolver) + continue + } + // resolve log.Tracer(ctx).Tracef("resolver: sending query for %s to %s", q.ID(), resolver.Info.ID()) rrCache, err = resolver.Conn.Query(ctx, q) diff --git a/service/resolver/resolver.go b/service/resolver/resolver.go index 3474fd30..a7821ede 100644 --- a/service/resolver/resolver.go +++ b/service/resolver/resolver.go @@ -67,6 +67,8 @@ type Resolver struct { Search []string SearchOnly bool Path string + // Special States + LinkLocalUnavailable bool // logic interface Conn ResolverConn `json:"-"` diff --git a/service/resolver/resolvers.go b/service/resolver/resolvers.go index 93edf2a1..4c548ff0 100644 --- a/service/resolver/resolvers.go +++ b/service/resolver/resolvers.go @@ -34,6 +34,7 @@ const ( parameterBlockedIf = "blockedif" parameterSearch = "search" parameterSearchOnly = "search-only" + parameterLinkLocal = "link-local" ) var ( @@ -179,6 +180,21 @@ func createResolver(resolverURL, source string) (*Resolver, bool, error) { } } + // Check if this is a link-local resolver. + if query.Has(parameterLinkLocal) { + if query.Get(parameterLinkLocal) != "" { + return nil, false, fmt.Errorf("%s may only be used as an empty parameter", parameterLinkLocal) + } + // Check if resolver IP is link-local. + resolverNet, err := netenv.GetLocalNetwork(newResolver.Info.IP) + switch { + case err != nil: + newResolver.LinkLocalUnavailable = true + case resolverNet == nil: + newResolver.LinkLocalUnavailable = true + } + } + newResolver.Conn = resolverConnFactory(newResolver) return newResolver, false, nil } @@ -208,7 +224,8 @@ func checkAndSetResolverParamters(u *url.URL, resolver *Resolver) error { parameterIP, parameterBlockedIf, parameterSearch, - parameterSearchOnly: + parameterSearchOnly, + parameterLinkLocal: // Known key, continue. default: // Unknown key, abort.