github.com/grafana/synthetic-monitoring-agent@v0.64.2/internal/prober/dns/dns.go (about)

     1  package dns
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/grafana/synthetic-monitoring-agent/internal/model"
    10  	"github.com/grafana/synthetic-monitoring-agent/internal/prober/dns/internal/bbe/config"
    11  	bbeprober "github.com/grafana/synthetic-monitoring-agent/internal/prober/dns/internal/bbe/prober"
    12  	"github.com/grafana/synthetic-monitoring-agent/internal/prober/logger"
    13  	sm "github.com/grafana/synthetic-monitoring-agent/pkg/pb/synthetic_monitoring"
    14  	"github.com/prometheus/client_golang/prometheus"
    15  )
    16  
    17  var errUnsupportedCheck = errors.New("unsupported check")
    18  
    19  type Prober struct {
    20  	target       string
    21  	config       config.Module
    22  	experimental bool
    23  }
    24  
    25  func NewProber(check model.Check) (Prober, error) {
    26  	if check.Settings.Dns == nil {
    27  		return Prober{}, errUnsupportedCheck
    28  	}
    29  
    30  	cfg := settingsToModule(check.Settings.Dns, check.Target)
    31  	cfg.Timeout = time.Duration(check.Timeout) * time.Millisecond
    32  
    33  	return Prober{
    34  		target: check.Settings.Dns.Server,
    35  		config: cfg,
    36  	}, nil
    37  }
    38  
    39  func NewExperimentalProber(check model.Check) (Prober, error) {
    40  	p, err := NewProber(check)
    41  	if err != nil {
    42  		return p, err
    43  	}
    44  
    45  	p.experimental = true
    46  
    47  	return p, nil
    48  }
    49  
    50  func (p Prober) Name() string {
    51  	return "dns"
    52  }
    53  
    54  func (p Prober) Probe(ctx context.Context, target string, registry *prometheus.Registry, logger logger.Logger, _ string) (bool, float64) {
    55  	cfg := p.config
    56  
    57  	if p.experimental {
    58  		const (
    59  			cutoff  = 15 * time.Second
    60  			retries = 3
    61  		)
    62  
    63  		if deadline, found := ctx.Deadline(); found {
    64  			budget := time.Until(deadline)
    65  			if budget >= cutoff {
    66  				cfg.DNS.Retries = retries
    67  				// Split 99% of the budget between three retries. For a
    68  				// budget of 15s, this allows for 150 ms per retry for
    69  				// other operations.
    70  				cfg.DNS.RetryTimeout = budget * 99 / (retries * 100)
    71  			}
    72  		}
    73  
    74  		_ = logger.Log("msg", "probing DNS", "target", target, "retries", cfg.DNS.Retries, "retry_timeout", cfg.DNS.RetryTimeout)
    75  	}
    76  
    77  	// The target of the BBE DNS check is the _DNS server_, while
    78  	// the target of the SM DNS check is the _query_, so we need
    79  	// pass the server as the target parameter, and ignore the
    80  	// _target_ paramater that is passed to this function.
    81  
    82  	return bbeprober.ProbeDNS(ctx, p.target, cfg, registry, logger), 0
    83  }
    84  
    85  func settingsToModule(settings *sm.DnsSettings, target string) config.Module {
    86  	var m config.Module
    87  
    88  	m.Prober = sm.CheckTypeDns.String()
    89  	m.DNS.IPProtocol, m.DNS.IPProtocolFallback = settings.IpVersion.ToIpProtocol()
    90  
    91  	// BBE dns_probe actually tests the DNS server, so we
    92  	// need to pass the query (e.g. www.grafana.com) as part
    93  	// of the configuration and the server as the target
    94  	// parameter.
    95  	m.DNS.QueryName = target
    96  	m.DNS.QueryType = settings.RecordType.String()
    97  	m.DNS.SourceIPAddress = settings.SourceIpAddress
    98  	// In the protobuffer definition the protocol is either
    99  	// "TCP" or "UDP", but blackbox-exporter wants "tcp" or
   100  	// "udp".
   101  	m.DNS.TransportProtocol = strings.ToLower(settings.Protocol.String())
   102  
   103  	m.DNS.Recursion = true
   104  
   105  	m.DNS.ValidRcodes = settings.ValidRCodes
   106  
   107  	if settings.ValidateAnswer != nil {
   108  		m.DNS.ValidateAnswer.FailIfMatchesRegexp = settings.ValidateAnswer.FailIfMatchesRegexp
   109  		m.DNS.ValidateAnswer.FailIfNotMatchesRegexp = settings.ValidateAnswer.FailIfNotMatchesRegexp
   110  	}
   111  
   112  	if settings.ValidateAuthority != nil {
   113  		m.DNS.ValidateAuthority.FailIfMatchesRegexp = settings.ValidateAuthority.FailIfMatchesRegexp
   114  		m.DNS.ValidateAuthority.FailIfNotMatchesRegexp = settings.ValidateAuthority.FailIfNotMatchesRegexp
   115  	}
   116  
   117  	if settings.ValidateAdditional != nil {
   118  		m.DNS.ValidateAdditional.FailIfMatchesRegexp = settings.ValidateAdditional.FailIfMatchesRegexp
   119  		m.DNS.ValidateAdditional.FailIfNotMatchesRegexp = settings.ValidateAdditional.FailIfNotMatchesRegexp
   120  	}
   121  
   122  	return m
   123  }