Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a proper --all-nameservers implementation #485

Merged
merged 29 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
96a721e
add domain name to root servers default
phillip-stephens Nov 26, 2024
0461fe9
start the all nameservers, for a single layer
phillip-stephens Nov 26, 2024
aae77d0
working for google.com
phillip-stephens Dec 11, 2024
6b90b7a
example.com working
phillip-stephens Dec 11, 2024
1ee507c
external lookups working
phillip-stephens Dec 12, 2024
539a89e
gate --all-nameservers for all specialty CLI modules and add comments
phillip-stephens Dec 12, 2024
3560621
Clarify behavior in --help for all-nameservers and --name-servers
phillip-stephens Dec 12, 2024
0a95c87
handle endless loop with next layer
phillip-stephens Dec 12, 2024
04d3dec
add integration test
phillip-stephens Dec 13, 2024
7c5bda9
fixed up comments
phillip-stephens Dec 13, 2024
ff63bd6
fixed up comments
phillip-stephens Dec 13, 2024
c179870
added context to function defs
phillip-stephens Dec 16, 2024
4adff9f
First unit test passing
phillip-stephens Dec 16, 2024
501dafc
added another unit test, 2 .com NSes and one fails
phillip-stephens Dec 16, 2024
a7f3798
fixed up another test
phillip-stephens Dec 16, 2024
45a7842
handle the extra sibling NS case that issue 352 brings up
phillip-stephens Dec 16, 2024
6cff29f
remove comment
phillip-stephens Dec 16, 2024
2882d83
bug fixes, query for all leaf NSes first, then followup with original…
phillip-stephens Dec 16, 2024
6b6e93d
lint/tests
phillip-stephens Dec 16, 2024
12ba0ae
integration tests
phillip-stephens Dec 16, 2024
e065f93
fix over-zealous replace operation
phillip-stephens Dec 16, 2024
524dc06
sort for consistent unit test
phillip-stephens Dec 16, 2024
d2d8625
add timeout error to all-nameservers
phillip-stephens Dec 16, 2024
6583c6f
handle de-duplicating nameservers by name, ensureing we only query on…
phillip-stephens Dec 18, 2024
05179af
Merge branch 'main' into phillip/362-all-nameservers
phillip-stephens Dec 18, 2024
a1c4e8b
PR cleanup
phillip-stephens Dec 18, 2024
d4885d2
don't error for CNAME referrals, we won't implement this
phillip-stephens Dec 18, 2024
657ddf7
cleanup
phillip-stephens Dec 18, 2024
82f146e
up timeouts on integration tests
phillip-stephens Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions examples/all_nameservers_lookup/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/* ZDNS Copyright 2024 Regents of the University of Michigan
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package main

import (
"net"
"time"

"github.com/miekg/dns"
log "github.com/sirupsen/logrus"

"github.com/zmap/zdns/examples/utils"
"github.com/zmap/zdns/src/zdns"
)

func main() {
// Perform the lookup
domain := "google.com"
dnsQuestion := &zdns.Question{Name: domain, Type: dns.TypeA, Class: dns.ClassINET}
resolver := initializeResolver()
// LookupAllNameserversIterative will query all root nameservers, and then all TLD nameservers, and then all authoritative nameservers for the domain.
result, _, status, err := resolver.LookupAllNameserversIterative(dnsQuestion, nil)
if err != nil {
log.Fatal("Error looking up domain: ", err)
}
log.Warnf("Result: %v", result)
log.Warnf("Status: %v", status)
log.Info("We can also specify which root nameservers to use by setting the argument.")

result, _, status, err = resolver.LookupAllNameserversIterative(dnsQuestion, []zdns.NameServer{{IP: net.ParseIP("198.41.0.4"), Port: 53}}) // a.root-servers.net
if err != nil {
log.Fatal("Error looking up domain: ", err)
}
log.Warnf("Result: %v", result)
log.Warnf("Status: %v", status)

log.Info("You can query multiple recursive resolvers as well")

externalResult, _, status, err := resolver.LookupAllNameserversExternal(dnsQuestion, []zdns.NameServer{{IP: net.ParseIP("1.1.1.1"), Port: 53}, {IP: net.ParseIP("8.8.8.8"), Port: 53}}) // Cloudflare and Google recursive resolvers, respectively
if err != nil {
log.Fatal("Error looking up domain: ", err)
}
log.Warnf("Result: %v", externalResult)
log.Warnf("Status: %v", status)
resolver.Close()
}

func initializeResolver() *zdns.Resolver {
localAddr, err := utils.GetLocalIPByConnecting()
if err != nil {
log.Fatal("Error getting local IP: ", err)
}
// Create a ResolverConfig object
resolverConfig := zdns.NewResolverConfig()
// Set any desired options on the ResolverConfig object
resolverConfig.LogLevel = log.InfoLevel
resolverConfig.LocalAddrsV4 = []net.IP{localAddr}
resolverConfig.ExternalNameServersV4 = []zdns.NameServer{{IP: net.ParseIP("1.1.1.1"), Port: 53}}
resolverConfig.RootNameServersV4 = zdns.RootServersV4
resolverConfig.IPVersionMode = zdns.IPv4Only
resolverConfig.Timeout = time.Minute
resolverConfig.IterativeTimeout = time.Minute
// Create a new Resolver object with the ResolverConfig object, it will retain all settings set on the ResolverConfig object
resolver, err := zdns.InitResolver(resolverConfig)
if err != nil {
log.Fatal("Error initializing resolver: ", err)
}
return resolver
}
5 changes: 3 additions & 2 deletions examples/multi_thread_lookup/multi_threaded.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package main

import (
"context"
"net"
"sync"

Expand Down Expand Up @@ -44,15 +45,15 @@ func main() {
wg.Add(2)
go func() {
defer wg.Done()
result1, _, _, err1 := resolver1.IterativeLookup(dnsQuestion1)
result1, _, _, err1 := resolver1.IterativeLookup(context.Background(), dnsQuestion1)
if err1 != nil {
log.Fatal("Error looking up domain: ", err1)
}
log.Warnf("Result: %v", result1)
}()
go func() {
defer wg.Done()
result2, _, _, err2 := resolver2.IterativeLookup(dnsQuestion2)
result2, _, _, err2 := resolver2.IterativeLookup(context.Background(), dnsQuestion2)
if err2 != nil {
log.Fatal("Error looking up domain: ", err2)
}
Expand Down
5 changes: 3 additions & 2 deletions examples/single_lookup/simple.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package main

import (
"context"
"encoding/json"
"net"

Expand All @@ -30,7 +31,7 @@ func main() {
dnsQuestion := &zdns.Question{Name: domain, Type: dns.TypeA, Class: dns.ClassINET}
resolver := initializeResolver()

result, _, status, err := resolver.ExternalLookup(dnsQuestion, &zdns.NameServer{IP: net.ParseIP("1.1.1.1"), Port: 53})
result, _, status, err := resolver.ExternalLookup(context.Background(), dnsQuestion, &zdns.NameServer{IP: net.ParseIP("1.1.1.1"), Port: 53})
if err != nil {
log.Fatal("Error looking up domain: ", err)
}
Expand All @@ -44,7 +45,7 @@ func main() {

log.Warn("\n\n This lookup just used the Cloudflare recursive resolver, let's run our own recursion.")
// Iterative Lookups start at the root nameservers and follow the chain of referrals to the authoritative nameservers.
result, trace, status, err := resolver.IterativeLookup(&zdns.Question{Name: domain, Type: dns.TypeA, Class: dns.ClassINET})
result, trace, status, err := resolver.IterativeLookup(context.Background(), &zdns.Question{Name: domain, Type: dns.TypeA, Class: dns.ClassINET})
if err != nil {
log.Fatal("Error looking up domain: ", err)
}
Expand Down
4 changes: 2 additions & 2 deletions src/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ type StatusHandler interface {
// GeneralOptions core options for all ZDNS modules
// Order here is the order they'll be printed to the user, so preserve alphabetical order
type GeneralOptions struct {
LookupAllNameServers bool `long:"all-nameservers" description:"Perform the lookup via all the nameservers for the domain."`
LookupAllNameServers bool `long:"all-nameservers" description:"Behavior is dependent on --iterative. In --iterative, --all-name-servers will query all root servers, then all gtld servers, etc. recording the responses at each layer. In non-iterative mode, the query will be sent to all external resolvers specified in --name-servers."`
CacheSize int `long:"cache-size" default:"10000" description:"how many items can be stored in internal recursive cache"`
GoMaxProcs int `long:"go-processes" default:"0" description:"number of OS processes (GOMAXPROCS by default)"`
IterationTimeout int `long:"iteration-timeout" default:"8" description:"timeout for a single iterative step in an iterative query, in seconds. Only applicable with --iterative"`
IterativeResolution bool `long:"iterative" description:"Perform own iteration instead of relying on recursive resolver"`
MaxDepth int `long:"max-depth" default:"10" description:"how deep should we recurse when performing iterative lookups"`
NameServerMode bool `long:"name-server-mode" description:"Treats input as nameservers to query with a static query rather than queries to send to a static name server"`
NameServersString string `long:"name-servers" description:"List of DNS servers to use. Can be passed as comma-delimited string or via @/path/to/file. If no port is specified, defaults to 53."`
NameServersString string `long:"name-servers" description:"List of DNS servers to use. Can be passed as comma-delimited string or via @/path/to/file. If no port is specified, defaults to 53. If not provided, defaults to either the default root servers in --iterative or the recursive resolvers specified in /etc/resolv.conf or OS equivalent."`
UseNanoseconds bool `long:"nanoseconds" description:"Use nanosecond resolution timestamps in output"`
NetworkTimeout int `long:"network-timeout" default:"2" description:"timeout for round trip network operations, in seconds"`
DisableFollowCNAMEs bool `long:"no-follow-cnames" description:"do not follow CNAMEs/DNAMEs in the lookup process"`
Expand Down
4 changes: 0 additions & 4 deletions src/cli/config_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,6 @@ func validateClientSubnetString(gc *CLIConf) error {
}

func parseNameServers(gc *CLIConf) error {
if gc.LookupAllNameServers && gc.NameServersString != "" {
log.Fatal("name servers cannot be specified in --all-nameservers mode.")
}

if gc.NameServersString != "" {
if gc.NameServerMode {
log.Fatal("name servers cannot be specified on command line in --name-server-mode")
Expand Down
16 changes: 13 additions & 3 deletions src/cli/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package cli

import (
"context"
"fmt"

"github.com/miekg/dns"
Expand Down Expand Up @@ -165,14 +166,23 @@ func (lm *BasicLookupModule) NewFlags() interface{} {
return lm
}

// Lookup performs a DNS lookup using the given resolver and lookupName.
// The behavior with respect to the nameServers is determined by the LookupAllNameServers and IsIterative fields.
// non-Iterative + all-Nameservers query -> we'll send a query to each of the resolver's external nameservers
// non-Iterative query -> we'll send a query to the nameserver provided. If none provided, a random nameserver from the resolver's external nameservers will be used
// iterative + all-Nameservers query -> we'll send a query to each root NS and query all nameservers down the chain.
// iterative query -> we'll send a query to a random root NS and query all nameservers down the chain.
func (lm *BasicLookupModule) Lookup(resolver *zdns.Resolver, lookupName string, nameServer *zdns.NameServer) (interface{}, zdns.Trace, zdns.Status, error) {
if lm.LookupAllNameServers && lm.IsIterative {
return resolver.LookupAllNameserversIterative(&zdns.Question{Name: lookupName, Type: lm.DNSType, Class: lm.DNSClass}, nil)
}
if lm.LookupAllNameServers {
return resolver.LookupAllNameservers(&zdns.Question{Name: lookupName, Type: lm.DNSType, Class: lm.DNSClass}, nameServer)
return resolver.LookupAllNameserversExternal(&zdns.Question{Name: lookupName, Type: lm.DNSType, Class: lm.DNSClass}, nil)
}
if lm.IsIterative {
return resolver.IterativeLookup(&zdns.Question{Name: lookupName, Type: lm.DNSType, Class: lm.DNSClass})
return resolver.IterativeLookup(context.Background(), &zdns.Question{Name: lookupName, Type: lm.DNSType, Class: lm.DNSClass})
}
return resolver.ExternalLookup(&zdns.Question{Type: lm.DNSType, Class: lm.DNSClass, Name: lookupName}, nameServer)
return resolver.ExternalLookup(context.Background(), &zdns.Question{Type: lm.DNSType, Class: lm.DNSClass, Name: lookupName}, nameServer)
}

func GetLookupModule(name string) (LookupModule, error) {
Expand Down
4 changes: 2 additions & 2 deletions src/internal/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ func IsStringValidDomainName(domain string) bool {
}

// HasCtxExpired checks if the context has expired. Common function used in various places.
func HasCtxExpired(ctx *context.Context) bool {
func HasCtxExpired(ctx context.Context) bool {
select {
case <-(*ctx).Done():
case <-(ctx).Done():
return true
default:
return false
Expand Down
3 changes: 3 additions & 0 deletions src/modules/alookup/a_lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ func init() {

// CLIInit initializes the ALookupModule with the given parameters, used to call ALOOKUP from the command line
func (aMod *ALookupModule) CLIInit(gc *cli.CLIConf, resolverConfig *zdns.ResolverConfig) error {
if gc.LookupAllNameServers {
return errors.New("ALOOKUP module does not support --all-nameservers")
}
aMod.Init(aMod.IPv4Lookup, aMod.IPv6Lookup)
err := aMod.baseModule.CLIInit(gc, resolverConfig)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions src/modules/axfr/axfr.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ func (axfrMod *AxfrLookupModule) CLIInit(gc *cli.CLIConf, rc *zdns.ResolverConfi
if gc.IterativeResolution {
log.Fatal("AXFR module does not support iterative resolution")
}
if gc.LookupAllNameServers {
return errors.New("AXFR module does not support --all-nameservers")
}
var err error
if axfrMod.BlacklistPath != "" {
axfrMod.Blacklist = safeblacklist.New()
Expand Down
10 changes: 8 additions & 2 deletions src/modules/bindversion/bindversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
package bindversion

import (
"context"

"github.com/miekg/dns"
"github.com/pkg/errors"

"github.com/zmap/zdns/src/cli"
"github.com/zmap/zdns/src/zdns"
Expand All @@ -42,6 +45,9 @@ func init() {

// CLIInit initializes the BindVersion lookup module
func (bindVersionMod *BindVersionLookupModule) CLIInit(gc *cli.CLIConf, rc *zdns.ResolverConfig) error {
if gc.LookupAllNameServers {
return errors.New("AXFR module does not support --all-nameservers")
}
return bindVersionMod.BasicLookupModule.CLIInit(gc, rc)
}

Expand All @@ -51,9 +57,9 @@ func (bindVersionMod *BindVersionLookupModule) Lookup(r *zdns.Resolver, lookupNa
var status zdns.Status
var err error
if bindVersionMod.IsIterative {
innerRes, trace, status, err = r.IterativeLookup(&zdns.Question{Name: BindVersionQueryName, Type: dns.TypeTXT, Class: dns.ClassCHAOS})
innerRes, trace, status, err = r.IterativeLookup(context.Background(), &zdns.Question{Name: BindVersionQueryName, Type: dns.TypeTXT, Class: dns.ClassCHAOS})
} else {
innerRes, trace, status, err = r.ExternalLookup(&zdns.Question{Name: BindVersionQueryName, Type: dns.TypeTXT, Class: dns.ClassCHAOS}, nameServer)
innerRes, trace, status, err = r.ExternalLookup(context.Background(), &zdns.Question{Name: BindVersionQueryName, Type: dns.TypeTXT, Class: dns.ClassCHAOS}, nameServer)
}
resString, resStatus, err := zdns.CheckTxtRecords(innerRes, status, nil, err)
res := Result{BindVersion: resString}
Expand Down
3 changes: 2 additions & 1 deletion src/modules/bindversion/bindversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package bindversion

import (
"context"
"net"
"testing"

Expand All @@ -35,7 +36,7 @@ var queries []QueryRecord
// DoSingleDstServerLookup(r *Resolver, q Question, nameServer string, isIterative bool) (*SingleQueryResult, Trace, Status, error)
type MockLookup struct{}

func (ml MockLookup) DoDstServersLookup(r *zdns.Resolver, question zdns.Question, nameServers []zdns.NameServer, isIterative bool) (*zdns.SingleQueryResult, zdns.Trace, zdns.Status, error) {
func (ml MockLookup) DoDstServersLookup(ctx context.Context, r *zdns.Resolver, question zdns.Question, nameServers []zdns.NameServer, isIterative bool) (*zdns.SingleQueryResult, zdns.Trace, zdns.Status, error) {
queries = append(queries, QueryRecord{q: question, NameServer: &nameServers[0]})
if res, ok := mockResults[question.Name]; ok {
return res, nil, zdns.StatusNoError, nil
Expand Down
3 changes: 3 additions & 0 deletions src/modules/dmarc/dmarc.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ type DmarcLookupModule struct {

// CLIInit initializes the DMARC lookup module
func (dmarcMod *DmarcLookupModule) CLIInit(gc *cli.CLIConf, rc *zdns.ResolverConfig) error {
if gc.LookupAllNameServers {
return errors.New("DMARC module does not support --all-nameservers")
}
dmarcMod.re = regexp.MustCompile(dmarcPrefixRegexp)
dmarcMod.BasicLookupModule.DNSType = dns.TypeTXT
dmarcMod.BasicLookupModule.DNSClass = dns.ClassINET
Expand Down
3 changes: 2 additions & 1 deletion src/modules/dmarc/dmarc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package dmarc

import (
"context"
"net"
"testing"

Expand All @@ -35,7 +36,7 @@ var queries []QueryRecord

type MockLookup struct{}

func (ml MockLookup) DoDstServersLookup(r *zdns.Resolver, question zdns.Question, nameServers []zdns.NameServer, isIterative bool) (*zdns.SingleQueryResult, zdns.Trace, zdns.Status, error) {
func (ml MockLookup) DoDstServersLookup(ctx context.Context, r *zdns.Resolver, question zdns.Question, nameServers []zdns.NameServer, isIterative bool) (*zdns.SingleQueryResult, zdns.Trace, zdns.Status, error) {
queries = append(queries, QueryRecord{question, &nameServers[0]})
if res, ok := mockResults[question.Name]; ok {
return res, nil, zdns.StatusNoError, nil
Expand Down
8 changes: 6 additions & 2 deletions src/modules/mxlookup/mx_lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package mxlookup

import (
"context"
"strings"

"github.com/miekg/dns"
Expand Down Expand Up @@ -56,6 +57,9 @@ type MXLookupModule struct {

// CLIInit initializes the MXLookupModule with the given parameters, used to call MXLookup from the command line
func (mxMod *MXLookupModule) CLIInit(gc *cli.CLIConf, rc *zdns.ResolverConfig) error {
if gc.LookupAllNameServers {
return errors.New("MXLOOKUP module does not support --all-nameservers")
}
if !mxMod.IPv4Lookup && !mxMod.IPv6Lookup {
// need to use one of the two
mxMod.IPv4Lookup = true
Expand Down Expand Up @@ -92,9 +96,9 @@ func (mxMod *MXLookupModule) Lookup(r *zdns.Resolver, lookupName string, nameSer
var status zdns.Status
var err error
if mxMod.BasicLookupModule.IsIterative {
res, trace, status, err = r.IterativeLookup(&zdns.Question{Name: lookupName, Type: dns.TypeMX, Class: dns.ClassINET})
res, trace, status, err = r.IterativeLookup(context.Background(), &zdns.Question{Name: lookupName, Type: dns.TypeMX, Class: dns.ClassINET})
} else {
res, trace, status, err = r.ExternalLookup(&zdns.Question{Name: lookupName, Type: dns.TypeMX, Class: dns.ClassINET}, nameServer)
res, trace, status, err = r.ExternalLookup(context.Background(), &zdns.Question{Name: lookupName, Type: dns.TypeMX, Class: dns.ClassINET}, nameServer)
}
if status != zdns.StatusNoError || err != nil {
return nil, trace, status, err
Expand Down
3 changes: 3 additions & 0 deletions src/modules/nslookup/ns_lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ type NSLookupModule struct {

// CLIInit initializes the NSLookupModule with the given parameters, used to call NSLookup from the command line
func (nsMod *NSLookupModule) CLIInit(gc *cli.CLIConf, resolverConf *zdns.ResolverConfig) error {
if gc.LookupAllNameServers {
return errors.New("NSLOOKUP module does not support --all-nameservers")
}
if !nsMod.IPv4Lookup && !nsMod.IPv6Lookup {
log.Debug("NSModule: neither --ipv4-lookup nor --ipv6-lookup specified, will only request A records for each NS server")
nsMod.IPv4Lookup = true
Expand Down
3 changes: 3 additions & 0 deletions src/modules/spf/spf.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ type SpfLookupModule struct {

// CLIInit initializes the SPF lookup module
func (spfMod *SpfLookupModule) CLIInit(gc *cli.CLIConf, rc *zdns.ResolverConfig) error {
if gc.LookupAllNameServers {
return errors.New("SPF module does not support --all-nameservers")
}
spfMod.re = regexp.MustCompile(spfPrefixRegexp)
spfMod.BasicLookupModule.DNSType = dns.TypeTXT
spfMod.BasicLookupModule.DNSClass = dns.ClassINET
Expand Down
3 changes: 2 additions & 1 deletion src/modules/spf/spf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package spf

import (
"context"
"net"
"testing"

Expand All @@ -35,7 +36,7 @@ var queries []QueryRecord

type MockLookup struct{}

func (ml MockLookup) DoDstServersLookup(r *zdns.Resolver, question zdns.Question, nameServers []zdns.NameServer, isIterative bool) (*zdns.SingleQueryResult, zdns.Trace, zdns.Status, error) {
func (ml MockLookup) DoDstServersLookup(ctx context.Context, r *zdns.Resolver, question zdns.Question, nameServers []zdns.NameServer, isIterative bool) (*zdns.SingleQueryResult, zdns.Trace, zdns.Status, error) {
queries = append(queries, QueryRecord{question, &nameServers[0]})
if res, ok := mockResults[question.Name]; ok {
return res, nil, zdns.StatusNoError, nil
Expand Down
Loading
Loading