From dfa623250afc47498cccdeaf23a3198e9d052be7 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Thu, 29 Mar 2018 19:41:59 +0300 Subject: [PATCH] helper/validation: IP address and IP address range validation helpers --- helper/validation/validation.go | 46 ++++++++++++++++++++++++++++ helper/validation/validation_test.go | 43 ++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/helper/validation/validation.go b/helper/validation/validation.go index 1fc3a6c095..e9edcd3338 100644 --- a/helper/validation/validation.go +++ b/helper/validation/validation.go @@ -1,6 +1,7 @@ package validation import ( + "bytes" "fmt" "net" "reflect" @@ -180,6 +181,51 @@ func CIDRNetwork(min, max int) schema.SchemaValidateFunc { } } +// SingleIP returns a SchemaValidateFunc which tests if the provided value +// is of type string, and in valid single IP notation +func SingleIP() schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + + ip := net.ParseIP(v) + if ip == nil { + es = append(es, fmt.Errorf( + "expected %s to contain a valid IP, got: %s", k, v)) + } + return + } +} + +// IPRange returns a SchemaValidateFunc which tests if the provided value +// is of type string, and in valid IP range notation +func IPRange() schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + + ips := strings.Split(v, "-") + if len(ips) != 2 { + es = append(es, fmt.Errorf( + "expected %s to contain a valid IP range, got: %s", k, v)) + return + } + ip1 := net.ParseIP(ips[0]) + ip2 := net.ParseIP(ips[1]) + if ip1 == nil || ip2 == nil || bytes.Compare(ip1, ip2) > 0 { + es = append(es, fmt.Errorf( + "expected %s to contain a valid IP range, got: %s", k, v)) + } + return + } +} + // ValidateJsonString is a SchemaValidateFunc which tests to make sure the // supplied string is valid JSON. func ValidateJsonString(v interface{}, k string) (ws []string, errors []error) { diff --git a/helper/validation/validation_test.go b/helper/validation/validation_test.go index 0e77006d4c..ea3b703bc5 100644 --- a/helper/validation/validation_test.go +++ b/helper/validation/validation_test.go @@ -144,6 +144,49 @@ func TestValidationRegexp(t *testing.T) { }) } +func TestValidationSingleIP(t *testing.T) { + runTestCases(t, []testCase{ + { + val: "172.10.10.10", + f: SingleIP(), + }, + { + val: "1.1.1", + f: SingleIP(), + expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")), + }, + { + val: "1.1.1.0/20", + f: SingleIP(), + expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")), + }, + { + val: "256.1.1.1", + f: SingleIP(), + expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP, got:")), + }, + }) +} + +func TestValidationIPRange(t *testing.T) { + runTestCases(t, []testCase{ + { + val: "172.10.10.10-172.10.10.12", + f: IPRange(), + }, + { + val: "172.10.10.20", + f: IPRange(), + expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP range, got:")), + }, + { + val: "172.10.10.20-172.10.10.12", + f: IPRange(), + expectedErr: regexp.MustCompile(regexp.QuoteMeta("expected test_property to contain a valid IP range, got:")), + }, + }) +} + func TestValidateRFC3339TimeString(t *testing.T) { runTestCases(t, []testCase{ {