From 3a08e67780bcb728a42cbf00ba03e0bd363a8e8e Mon Sep 17 00:00:00 2001 From: Paul Wood Date: Thu, 21 Nov 2019 15:13:04 +0000 Subject: [PATCH] Add none/all matches to DNS RRset validation (#552) Signed-off-by: Paul Wood --- CONFIGURATION.md | 18 ++++++++++++++++++ config/config.go | 6 ++++-- example.yml | 4 ++++ prober/dns.go | 40 +++++++++++++++++++++++++++++++++++++--- prober/dns_test.go | 20 ++++++++++++++++++++ 5 files changed, 83 insertions(+), 5 deletions(-) diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 7610bd4..93d3bb8 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -165,25 +165,43 @@ validate_answer_rrs: fail_if_matches_regexp: [ - , ... ] + fail_if_all_match_regexp: + [ - , ... ] + fail_if_not_matches_regexp: [ - , ... ] + fail_if_none_matches_regexp: + [ - , ... ] + validate_authority_rrs: fail_if_matches_regexp: [ - , ... ] + fail_if_all_match_regexp: + [ - , ... ] + fail_if_not_matches_regexp: [ - , ... ] + fail_if_none_matches_regexp: + [ - , ... ] + validate_additional_rrs: fail_if_matches_regexp: [ - , ... ] + fail_if_all_match_regexp: + [ - , ... ] + fail_if_not_matches_regexp: [ - , ... ] + fail_if_none_matches_regexp: + [ - , ... ] + ``` ### diff --git a/config/config.go b/config/config.go index 3f3daea..148de84 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 6c720ff..3416c74 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 00e6467..9c26c9b 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 9b7b4a6..b4f0472 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 { -- 2.25.1