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 }