Add none/all matches to DNS RRset validation (#552)
authorPaul Wood <pauwood@ebay.com>
Thu, 21 Nov 2019 15:13:04 +0000 (15:13 +0000)
committerBrian Brazil <brian.brazil@robustperception.io>
Thu, 21 Nov 2019 15:13:04 +0000 (15:13 +0000)
Signed-off-by: Paul Wood <pauwood@ebay.com>
CONFIGURATION.md
config/config.go
example.yml
prober/dns.go
prober/dns_test.go

index 7610bd4cf295c1dd05bdb5b46f2203d56a309218..93d3bb8ea01a8741eea1447ffcf833a5b46fb3da 100644 (file)
@@ -165,25 +165,43 @@ validate_answer_rrs:
   fail_if_matches_regexp:
     [ - <regex>, ... ]
 
+  fail_if_all_match_regexp:
+    [ - <regex>, ... ]
+
   fail_if_not_matches_regexp:
     [ - <regex>, ... ]
 
+  fail_if_none_matches_regexp:
+    [ - <regex>, ... ]
+
 validate_authority_rrs:
 
   fail_if_matches_regexp:
     [ - <regex>, ... ]
 
+  fail_if_all_match_regexp:
+    [ - <regex>, ... ]
+
   fail_if_not_matches_regexp:
     [ - <regex>, ... ]
 
+  fail_if_none_matches_regexp:
+    [ - <regex>, ... ]
+
 validate_additional_rrs:
 
   fail_if_matches_regexp:
     [ - <regex>, ... ]
 
+  fail_if_all_match_regexp:
+    [ - <regex>, ... ]
+
   fail_if_not_matches_regexp:
     [ - <regex>, ... ]
 
+  fail_if_none_matches_regexp:
+    [ - <regex>, ... ]
+
 ```
 
 ### <icmp_probe>
index 3f3daeadb371766f39c62a37167bdc95626104ea..148de8441f09e762b57149fcf9e710016df6f4da 100644 (file)
@@ -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.
index 6c720ff6b457074f8d2512f87810dbf0c67bc475..3416c74e821f8f14fbe98dfc83f8915d0c1d77a0 100644 (file)
@@ -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"
index 00e64673acd858f881124e02e9969438b7f0c81f..9c26c9bbfc992900a326a391e8bef64140bbb559 100644 (file)
@@ -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
 }
 
index 9b7b4a6f177674c52c3793c4e7f0536c76b67e11..b4f0472c81e0b9e553e2cc2c19fc8a484b510904 100644 (file)
@@ -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 {