diff --git a/README.md b/README.md index 2c3fc35..86effb0 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ func IsHost(str string) bool func IsIP(str string) bool func IsIPv4(str string) bool func IsIPv6(str string) bool +func IsPrivateIP(ip string) bool func IsISBN(str string, version int) bool func IsISBN10(str string) bool func IsISBN13(str string) bool @@ -370,6 +371,7 @@ Here is a list of available validators for struct fields (validator - used funct "base64": IsBase64, "datauri": IsDataURI, "ip": IsIP, +"ip": IsPrivateIP "port": IsPort, "ipv4": IsIPv4, "ipv6": IsIPv6, diff --git a/validator.go b/validator.go index 46ecfc8..cace32d 100644 --- a/validator.go +++ b/validator.go @@ -69,6 +69,44 @@ func IsEmail(str string) bool { return rxEmail.MatchString(str) } +// private ip lists +var aPrivateIP []*net.IPNet + +// IsPrivateIP check if the string is an private IP +func IsPrivateIP(ip string) bool { + if 0 == len(aPrivateIP) { + for _, cidr := range []string{ + "127.0.0.0/8", // IPv4 loopback + "10.0.0.0/8", // RFC1918 + "172.16.0.0/12", // RFC1918 + "192.168.0.0/16", // RFC1918 + "169.254.0.0/16", // RFC3927 link-local + "::1/128", // IPv6 loopback + "fe80::/10", // IPv6 link-local + "fc00::/7", // IPv6 unique local addr + } { + _, block, err := net.ParseCIDR(cidr) + if err != nil { + continue + } + aPrivateIP = append(aPrivateIP, block) + } + } + oIp := net.ParseIP(ip) + if oIp == nil { + return false + } + if oIp.IsLoopback() || oIp.IsLinkLocalUnicast() || oIp.IsLinkLocalMulticast() || oIp.IsPrivate() { + return true + } + for _, s := range aPrivateIP { + if s.Contains(oIp) { + return true + } + } + return false +} + // IsExistingEmail checks if the string is an email of existing domain func IsExistingEmail(email string) bool { diff --git a/validator_test.go b/validator_test.go index bff8613..044587e 100644 --- a/validator_test.go +++ b/validator_test.go @@ -3865,3 +3865,30 @@ func TestIsE164(t *testing.T) { } } } + +func TestIsPrivateIP(t *testing.T) { + t.Parallel() + // Without version + var tests = []struct { + param string + expected bool + }{ + {"", false}, + {"127.0.0.1", true}, + {"127.0.2.1", true}, + {"172.16.0.19", true}, + {"fe80::b8:6771:9e7c:f6f1", true}, + {"ee80::b8:6771:9e7c:f6f1", false}, + {"fe80::1", true}, + {"192.168.10.1", true}, + {"::1", true}, + {"2001:db8:0000:1:1:1:1:1", false}, + {"300.0.0.0", false}, + } + for _, test := range tests { + actual := IsPrivateIP(test.param) + if actual != test.expected { + t.Errorf("Expected IsPrivateIP(%q) to be %v, got %v", test.param, test.expected, actual) + } + } +}