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  }