github.com/thanos-io/thanos@v0.32.5/pkg/discovery/dns/miekgdns/resolver.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package miekgdns 5 6 import ( 7 "context" 8 "net" 9 10 "github.com/miekg/dns" 11 "github.com/pkg/errors" 12 ) 13 14 // DefaultResolvConfPath is a common, default resolv.conf file present on linux server. 15 const DefaultResolvConfPath = "/etc/resolv.conf" 16 17 // Resolver is a drop-in Resolver for *part* of std lib Golang net.DefaultResolver methods. 18 type Resolver struct { 19 ResolvConf string 20 } 21 22 func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error) { 23 return r.lookupSRV(service, proto, name, 1, 8) 24 } 25 26 func (r *Resolver) lookupSRV(service, proto, name string, currIteration, maxIterations int) (cname string, addrs []*net.SRV, err error) { 27 // We want to protect from infinite loops when resolving DNS records recursively. 28 if currIteration > maxIterations { 29 return "", nil, errors.Errorf("maximum number of recursive iterations reached (%d)", maxIterations) 30 } 31 var target string 32 if service == "" && proto == "" { 33 target = name 34 } else { 35 target = "_" + service + "._" + proto + "." + name 36 } 37 38 response, err := r.lookupWithSearchPath(target, dns.Type(dns.TypeSRV)) 39 if err != nil { 40 return "", nil, err 41 } 42 43 for _, record := range response.Answer { 44 switch addr := record.(type) { 45 case *dns.SRV: 46 addrs = append(addrs, &net.SRV{ 47 Weight: addr.Weight, 48 Target: addr.Target, 49 Priority: addr.Priority, 50 Port: addr.Port, 51 }) 52 case *dns.CNAME: 53 // Recursively resolve it. 54 _, resp, err := r.lookupSRV("", "", addr.Target, currIteration+1, maxIterations) 55 if err != nil { 56 return "", nil, errors.Wrapf(err, "recursively resolve %s", addr.Target) 57 } 58 addrs = append(addrs, resp...) 59 default: 60 return "", nil, errors.Errorf("invalid SRV response record %s", record) 61 } 62 } 63 64 return "", addrs, nil 65 } 66 67 func (r *Resolver) LookupIPAddr(_ context.Context, host string) ([]net.IPAddr, error) { 68 return r.lookupIPAddr(host, 1, 8) 69 } 70 71 func (r *Resolver) lookupIPAddr(host string, currIteration, maxIterations int) ([]net.IPAddr, error) { 72 // We want to protect from infinite loops when resolving DNS records recursively. 73 if currIteration > maxIterations { 74 return nil, errors.Errorf("maximum number of recursive iterations reached (%d)", maxIterations) 75 } 76 77 response, err := r.lookupWithSearchPath(host, dns.Type(dns.TypeAAAA)) 78 if err != nil || len(response.Answer) == 0 { 79 // Ugly fallback to A lookup. 80 response, err = r.lookupWithSearchPath(host, dns.Type(dns.TypeA)) 81 if err != nil { 82 return nil, err 83 } 84 } 85 86 var resp []net.IPAddr 87 for _, record := range response.Answer { 88 switch addr := record.(type) { 89 case *dns.A: 90 resp = append(resp, net.IPAddr{IP: addr.A}) 91 case *dns.AAAA: 92 resp = append(resp, net.IPAddr{IP: addr.AAAA}) 93 case *dns.CNAME: 94 // Recursively resolve it. 95 addrs, err := r.lookupIPAddr(addr.Target, currIteration+1, maxIterations) 96 if err != nil { 97 return nil, errors.Wrapf(err, "recursively resolve %s", addr.Target) 98 } 99 resp = append(resp, addrs...) 100 default: 101 return nil, errors.Errorf("invalid A, AAAA or CNAME response record %s", record) 102 } 103 } 104 return resp, nil 105 } 106 107 func (r *Resolver) IsNotFound(err error) bool { 108 return errors.Is(errors.Cause(err), ErrNoSuchHost) 109 }