diff --git a/config/config.go b/config/config.go index 3f3daeadb..148de8441 100644 --- a/config/config.go +++ b/config/config.go @@ -184,8 +184,10 @@ type DNSProbe struct { } type DNSRRValidator struct { - FailIfMatchesRegexp []string `yaml:"fail_if_matches_regexp,omitempty"` - FailIfNotMatchesRegexp []string `yaml:"fail_if_not_matches_regexp,omitempty"` + FailIfMatchesRegexp []string `yaml:"fail_if_matches_regexp,omitempty"` + FailIfAllMatchRegexp []string `yaml:"fail_if_all_match_regexp,omitempty"` + FailIfNotMatchesRegexp []string `yaml:"fail_if_not_matches_regexp,omitempty"` + FailIfNoneMatchesRegexp []string `yaml:"fail_if_none_matches_regexp,omitempty"` } // UnmarshalYAML implements the yaml.Unmarshaler interface. diff --git a/example.yml b/example.yml index 6c720ff6b..3416c74e8 100644 --- a/example.yml +++ b/example.yml @@ -112,8 +112,12 @@ modules: validate_answer_rrs: fail_if_matches_regexp: - ".*127.0.0.1" + fail_if_all_match_regexp: + - ".*127.0.0.1" fail_if_not_matches_regexp: - "www.prometheus.io.\t300\tIN\tA\t127.0.0.1" + fail_if_none_matches_regexp: + - "127.0.0.1" validate_authority_rrs: fail_if_matches_regexp: - ".*127.0.0.1" diff --git a/prober/dns.go b/prober/dns.go index 00e64673a..7029a6912 100644 --- a/prober/dns.go +++ b/prober/dns.go @@ -29,12 +29,18 @@ import ( // validRRs checks a slice of RRs received from the server against a DNSRRValidator. func validRRs(rrs *[]dns.RR, v *config.DNSRRValidator, logger log.Logger) bool { + var anyMatch bool = false; + var allMatch bool = true; // Fail the probe if there are no RRs of a given type, but a regexp match is required - // (i.e. FailIfNotMatchesRegexp is set). + // (i.e. FailIfNotMatchesRegexp or FailIfNoneMatchesRegexp is set). if len(*rrs) == 0 && len(v.FailIfNotMatchesRegexp) > 0 { level.Error(logger).Log("msg", "fail_if_not_matches_regexp specified but no RRs returned") return false } + if len(*rrs) == 0 && len(v.FailIfNoneMatchesRegexp) > 0 { + level.Error(logger).Log("msg", "fail_if_none_matches_regexp specified but no RRs returned") + return false + } for _, rr := range *rrs { level.Info(logger).Log("msg", "Validating RR", "rr", rr) for _, re := range v.FailIfMatchesRegexp { @@ -44,10 +50,20 @@ func validRRs(rrs *[]dns.RR, v *config.DNSRRValidator, logger log.Logger) bool { return false } if match { - level.Error(logger).Log("msg", "RR matched regexp", "regexp", re, "rr", rr) + level.Error(logger).Log("msg", "At least one RR matched regexp", "regexp", re, "rr", rr) return false } } + for _, re := range v.FailIfAllMatchRegexp { + match, err := regexp.MatchString(re, rr.String()) + if err != nil { + level.Error(logger).Log("msg", "Error matching regexp", "regexp", re, "err", err) + return false + } + if !match { + allMatch = false; + } + } for _, re := range v.FailIfNotMatchesRegexp { match, err := regexp.MatchString(re, rr.String()) if err != nil { @@ -55,11 +71,29 @@ func validRRs(rrs *[]dns.RR, v *config.DNSRRValidator, logger log.Logger) bool { return false } if !match { - level.Error(logger).Log("msg", "RR did not match regexp", "regexp", re, "rr", rr) + level.Error(logger).Log("msg", "At least one RR did not match regexp", "regexp", re, "rr", rr) + return false + } + } + for _, re := range v.FailIfNoneMatchesRegexp { + match, err := regexp.MatchString(re, rr.String()) + if err != nil { + level.Error(logger).Log("msg", "Error matching regexp", "regexp", re, "err", err) return false } + if match { + anyMatch = true; + } } } + if len(v.FailIfAllMatchRegexp) > 0 && ! allMatch { + level.Error(logger).Log("msg", "Not all RRs matched regexp") + return false + } + if len(v.FailIfNoneMatchesRegexp) > 0 && ! anyMatch { + level.Error(logger).Log("msg", "None of the RRs did matched any regexp") + return false + } return true } diff --git a/prober/dns_test.go b/prober/dns_test.go index 9b7b4a6f1..b4f0472c8 100644 --- a/prober/dns_test.go +++ b/prober/dns_test.go @@ -303,6 +303,26 @@ func TestAuthoritativeDNSResponse(t *testing.T) { }, }, false, }, + { + config.DNSProbe{ + IPProtocol: "ip4", + IPProtocolFallback: true, + QueryName: "example.com", + ValidateAdditional: config.DNSRRValidator{ + FailIfAllMatchRegexp: []string{".*127.0.0.*"}, + }, + }, false, + }, + { + config.DNSProbe{ + IPProtocol: "ip4", + IPProtocolFallback: true, + QueryName: "example.com", + ValidateAdditional: config.DNSRRValidator{ + FailIfNoneMatchesRegexp: []string{".*127.0.0.3.*"}, + }, + }, false, + }, } for _, protocol := range PROTOCOLS {