From fa687f77fdb96bbbd13285f184c93fc15a464eb4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Romain=20Tarti=C3=A8re?= <romain@blogreen.org>
Date: Fri, 1 Sep 2017 08:54:01 +0200
Subject: [PATCH] Add IPv6 subnet validation

---
 lib/ipaddress.rb       | 28 ++++++++++++++++++++++++++--
 test/ipaddress_test.rb | 10 ++++++++++
 2 files changed, 36 insertions(+), 2 deletions(-)

diff --git a/lib/ipaddress.rb b/lib/ipaddress.rb
index 88d80a2..99591d7 100644
--- a/lib/ipaddress.rb
+++ b/lib/ipaddress.rb
@@ -121,7 +121,7 @@ module IPAddress
   #     #=> false
   #
   def self.valid?(addr)
-    valid_ip?(addr) || valid_ipv4_subnet?(addr)
+    valid_ip?(addr) || valid_ipv4_subnet?(addr) || valid_ipv6_subnet?(addr)
   end
 
   # 
@@ -159,7 +159,31 @@ module IPAddress
 
     valid_ipv4?(ip) && (!(netmask =~ /\A([12]?\d|3[0-2])\z/).nil? || valid_ipv4_netmask?(netmask))
   end
-  
+
+  #
+  # Checks if the given string is a valid IPv6 subnet
+  #
+  # Example:
+  #
+  #   IPAdress::valid_ipv6_subnet? "::/0"
+  #     #=> true
+  #
+  #   IPAdress::valid_ipv6_subnet? "dead:beef:cafe:babe::/64"
+  #     #=> true
+  #
+  #   IPAdress::valid_ipv6_subnet? "2001::1/129"
+  #     #=> false
+  #
+  def self.valid_ipv6_subnet?(addr)
+    ip, netmask = addr.split("/")
+
+    netmask = Integer(netmask, 10)
+
+    valid_ipv6?(ip) && netmask >= 0 && netmask <= 128
+  rescue ArgumentError
+    false
+  end
+
   #
   # Checks if the given string is a valid IPv4 address
   #
diff --git a/test/ipaddress_test.rb b/test/ipaddress_test.rb
index 44ecba0..d5bdf60 100644
--- a/test/ipaddress_test.rb
+++ b/test/ipaddress_test.rb
@@ -63,6 +63,10 @@ class IPAddressTest < Minitest::Test
     assert_equal true, IPAddress::valid?("10.0.0.0/255.255.255.0")
     assert_equal false, IPAddress::valid?("10.0.0.0/64")
     assert_equal false, IPAddress::valid?("10.0.0.0/255.255.255.256")
+    assert_equal true, IPAddress::valid?("::/0")
+    assert_equal true, IPAddress::valid?("2002::1/128")
+    assert_equal true, IPAddress::valid?("dead:beef:cafe:babe::/64")
+    assert_equal false, IPAddress::valid?("2002::1/129")
   end
 
   def test_module_method_valid_ip?
@@ -94,6 +98,12 @@ class IPAddressTest < Minitest::Test
     assert_equal false, IPAddress::valid_ipv4_subnet?("10.0.0.0/255.255.255.256")
   end
 
+  def test_module_method_valid_ipv6_subnet?
+    assert_equal true, IPAddress::valid_ipv6_subnet?("::/0")
+    assert_equal true, IPAddress::valid_ipv6_subnet?("2002::1/128")
+    assert_equal true, IPAddress::valid_ipv6_subnet?("dead:beef:cafe:babe::/64")
+    assert_equal false, IPAddress::valid_ipv6_subnet?("2002::1/129")
+  end
 end
 
 
-- 
GitLab