From d89672a660e4894d56763a3946d1fb02b1a7ae25 Mon Sep 17 00:00:00 2001 From: SJCaldwell Date: Fri, 15 Jul 2016 16:32:23 -0400 Subject: [PATCH 1/4] Added skeleton of ipv6 subnetting --- lib/ipaddress/ipv6.rb | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lib/ipaddress/ipv6.rb b/lib/ipaddress/ipv6.rb index 88098bc..05faf00 100644 --- a/lib/ipaddress/ipv6.rb +++ b/lib/ipaddress/ipv6.rb @@ -549,6 +549,38 @@ def network self.class.parse_u128(network_u128, @prefix) end + # + # This method implements the subnetting function + # similar to the one described in RFC3531. + # + # By specifying a new prefix, the method calculates + # the network number for the given IPv6 object + # and calculates the subnets associated to the new + # prefix. + # + # For example, given the following network: + # + # ip = IPAddress "172.16.10.0/24" + # + # we can calculate the subnets with a /26 prefix + # + # ip.subnets(26).map{&:to_string) + # #=> ["172.16.10.0/26", "172.16.10.64/26", + # "172.16.10.128/26", "172.16.10.192/26"] + # + # The resulting number of subnets will of course always be + # a power of two. + # + + def subnet(subprefix) + unless ((@prefix.to_i)..128).include? subprefix + raise ArgumentError, "New prefix must be between #@prefix and 128" + end + Array.new(2**(subprefix-@prefix.to_i)) do |i| + self.class.parse_u128(network_u128+(i*(2**(128-subprefix))), subprefix) + end + end + # # Extract 16 bits groups from a string # From 2ad549273e0c1149a6305a6cc6f52d80e5e838f7 Mon Sep 17 00:00:00 2001 From: SJCaldwell Date: Fri, 15 Jul 2016 17:25:03 -0400 Subject: [PATCH 2/4] Added test for IPv6 subnet code - copying format of ipv4 subnetting code --- test/ipaddress/ipv6_test.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/ipaddress/ipv6_test.rb b/test/ipaddress/ipv6_test.rb index dcfb601..c4fb180 100644 --- a/test/ipaddress/ipv6_test.rb +++ b/test/ipaddress/ipv6_test.rb @@ -142,6 +142,18 @@ def test_method_size assert_equal 2**4, ip.size end + def test_method_subnet + assert_raises(ArgumentError) {@network.subnet(62)} + assert_raises(ArgumentError) {@network.subnet(129)} + arr = ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26", + "172.16.10.192/26"] + assert_equal arr, @network.subnet(26).map {|s| s.to_string} + arr = ["172.16.10.0/25", "172.16.10.128/25"] + assert_equal arr, @network.subnet(25).map {|s| s.to_string} + arr = ["172.16.10.0/24"] + assert_equal arr, @network.subnet(24).map {|s| s.to_string} + end + def test_method_include? assert_equal true, @ip.include?(@ip) # test prefix on same address From 090c54ec9bf11b843c4fe112fb522c86172caf4d Mon Sep 17 00:00:00 2001 From: SJCaldwell Date: Mon, 18 Jul 2016 16:00:04 -0400 Subject: [PATCH 3/4] tests are written correctly, failing as anticipated --- test/ipaddress/ipv6_test.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/ipaddress/ipv6_test.rb b/test/ipaddress/ipv6_test.rb index c4fb180..889a0b0 100644 --- a/test/ipaddress/ipv6_test.rb +++ b/test/ipaddress/ipv6_test.rb @@ -141,17 +141,17 @@ def test_method_size ip = @klass.new("2001:db8::8:800:200c:417a/124") assert_equal 2**4, ip.size end - +####Fill out proper ipv6 values... not sure how to do that math by hand yet. def test_method_subnet assert_raises(ArgumentError) {@network.subnet(62)} assert_raises(ArgumentError) {@network.subnet(129)} - arr = ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26", - "172.16.10.192/26"] - assert_equal arr, @network.subnet(26).map {|s| s.to_string} - arr = ["172.16.10.0/25", "172.16.10.128/25"] - assert_equal arr, @network.subnet(25).map {|s| s.to_string} - arr = ["172.16.10.0/24"] - assert_equal arr, @network.subnet(24).map {|s| s.to_string} + arr = ["2001:db8:8:800::/66", "2001:db8:8:800:4000:/66", "2001:db8:8:800:8000:/66", + "2001:db8:8:800:c000:/66"] + assert_equal arr, @network.subnet(66).map {|s| s.to_string} + arr = ["2001:db8:8:800::/65", "2001:db8:8:800:8000:/65"] + assert_equal arr, @network.subnet(65).map {|s| s.to_string} + arr = ["2001:db8:8:800::/64"] + assert_equal arr, @network.subnet(64).map {|s| s.to_string} end def test_method_include? From b67b05459e0a358b5a089c4f13246eb66771b615 Mon Sep 17 00:00:00 2001 From: SJCaldwell Date: Mon, 18 Jul 2016 16:23:00 -0400 Subject: [PATCH 4/4] tests passing, documentation updated to match tests --- lib/ipaddress/ipv6.rb | 10 +++++----- test/ipaddress/ipv6_test.rb | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/ipaddress/ipv6.rb b/lib/ipaddress/ipv6.rb index 05faf00..cda1c1b 100644 --- a/lib/ipaddress/ipv6.rb +++ b/lib/ipaddress/ipv6.rb @@ -560,13 +560,13 @@ def network # # For example, given the following network: # - # ip = IPAddress "172.16.10.0/24" + # ip = IPAddress "2001:db8:8:800::/64" # - # we can calculate the subnets with a /26 prefix + # we can calculate the subnets with a /66 prefix # - # ip.subnets(26).map{&:to_string) - # #=> ["172.16.10.0/26", "172.16.10.64/26", - # "172.16.10.128/26", "172.16.10.192/26"] + # ip.subnets(66).map{&:to_string) + # #=> ["2001:db8:8:800::/66", "2001:db8:8:800:4000::/66", "2001:db8:8:800:8000::/66", + # "2001:db8:8:800:c000::/66"] # # The resulting number of subnets will of course always be # a power of two. diff --git a/test/ipaddress/ipv6_test.rb b/test/ipaddress/ipv6_test.rb index 889a0b0..b558593 100644 --- a/test/ipaddress/ipv6_test.rb +++ b/test/ipaddress/ipv6_test.rb @@ -145,10 +145,10 @@ def test_method_size def test_method_subnet assert_raises(ArgumentError) {@network.subnet(62)} assert_raises(ArgumentError) {@network.subnet(129)} - arr = ["2001:db8:8:800::/66", "2001:db8:8:800:4000:/66", "2001:db8:8:800:8000:/66", - "2001:db8:8:800:c000:/66"] + arr = ["2001:db8:8:800::/66", "2001:db8:8:800:4000::/66", "2001:db8:8:800:8000::/66", + "2001:db8:8:800:c000::/66"] assert_equal arr, @network.subnet(66).map {|s| s.to_string} - arr = ["2001:db8:8:800::/65", "2001:db8:8:800:8000:/65"] + arr = ["2001:db8:8:800::/65", "2001:db8:8:800:8000::/65"] assert_equal arr, @network.subnet(65).map {|s| s.to_string} arr = ["2001:db8:8:800::/64"] assert_equal arr, @network.subnet(64).map {|s| s.to_string}