diff --git a/config/config.go b/config/config.go index a10d9d6..76a4bc3 100644 --- a/config/config.go +++ b/config/config.go @@ -69,6 +69,7 @@ type DNS struct { FakeIPRange *fakeip.Pool Hosts *trie.DomainTrie NameServerPolicy map[string]dns.NameServer + SearchDomains []string } // FallbackFilter config @@ -117,6 +118,7 @@ type RawDNS struct { FakeIPFilter []string `yaml:"fake-ip-filter"` DefaultNameserver []string `yaml:"default-nameserver"` NameServerPolicy map[string]string `yaml:"nameserver-policy"` + SearchDomains []string `yaml:"search-domains"` } type RawFallbackFilter struct { @@ -702,6 +704,18 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie) (*DNS, error) { dnsCfg.Hosts = hosts } + if len(cfg.SearchDomains) != 0 { + for _, domain := range cfg.SearchDomains { + if strings.HasPrefix(domain, ".") || strings.HasSuffix(domain, ".") { + return nil, errors.New("search domains should not start or end with '.'") + } + if strings.Contains(domain, ":") { + return nil, errors.New("search domains are for ipv4 only and should not contain ports") + } + } + dnsCfg.SearchDomains = cfg.SearchDomains + } + return dnsCfg, nil } diff --git a/dns/resolver.go b/dns/resolver.go index 4d3634a..96da175 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -39,6 +39,7 @@ type Resolver struct { group singleflight.Group lruCache *cache.LruCache policy *trie.DomainTrie + searchDomains []string } // LookupIP request with TypeA and TypeAAAA, priority return TypeA @@ -285,16 +286,33 @@ func (r *Resolver) lookupIP(ctx context.Context, host string, dnsType uint16) ([ query := &D.Msg{} query.SetQuestion(D.Fqdn(host), dnsType) - msg, err := r.Exchange(query) + msg, err := r.ExchangeContext(ctx, query) if err != nil { return nil, err } ips := msgToIP(msg) - if len(ips) == 0 { + if len(ips) != 0 { + return ips, nil + } else if len(r.searchDomains) == 0 { return nil, resolver.ErrIPNotFound } - return ips, nil + + // query provided search domains serially + for _, domain := range r.searchDomains { + q := &D.Msg{} + q.SetQuestion(D.Fqdn(fmt.Sprintf("%s.%s", host, domain)), dnsType) + msg, err := r.ExchangeContext(ctx, q) + if err != nil { + return nil, err + } + ips := msgToIP(msg) + if len(ips) != 0 { + return ips, nil + } + } + + return nil, resolver.ErrIPNotFound } func (r *Resolver) msgToDomain(msg *D.Msg) string { @@ -336,6 +354,7 @@ type Config struct { Pool *fakeip.Pool Hosts *trie.DomainTrie Policy map[string]NameServer + SearchDomains []string } func NewResolver(config Config) *Resolver { @@ -345,10 +364,11 @@ func NewResolver(config Config) *Resolver { } r := &Resolver{ - ipv6: config.IPv6, - main: transform(config.Main, defaultResolver), - lruCache: cache.New(cache.WithSize(4096), cache.WithStale(true)), - hosts: config.Hosts, + ipv6: config.IPv6, + main: transform(config.Main, defaultResolver), + lruCache: cache.New(cache.WithSize(4096), cache.WithStale(true)), + hosts: config.Hosts, + searchDomains: config.SearchDomains, } if len(config.Fallback) != 0 { diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 447bfcd..aaf5ba6 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -129,8 +129,9 @@ func updateDNS(c *config.DNS) { IPCIDR: c.FallbackFilter.IPCIDR, Domain: c.FallbackFilter.Domain, }, - Default: c.DefaultNameserver, - Policy: c.NameServerPolicy, + Default: c.DefaultNameserver, + Policy: c.NameServerPolicy, + SearchDomains: c.SearchDomains, } r := dns.NewResolver(cfg)