summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Ceresa <ceresa@gmail.com>2010-02-03 17:51:49 +0000
committerMarco Ceresa <ceresa@gmail.com>2010-02-03 17:51:49 +0000
commit48045a5857123dc3e5067bb457e4fd2c337c98df (patch)
treedc964be23548320efeaeb6b18811926e5befe486
parent9030d410a3757558ef23ac2317f2fb82d5a1e324 (diff)
downloadipaddress-48045a5857123dc3e5067bb457e4fd2c337c98df.tar.gz
added IPv4#+ and many new IPv6 methods and tests
-rw-r--r--lib/ipaddress/ipv4.rb27
-rw-r--r--lib/ipaddress/ipv6.rb75
-rw-r--r--lib/ipaddress/prefix.rb6
-rw-r--r--test/ipaddress/ipv4_test.rb11
-rw-r--r--test/ipaddress/ipv6_test.rb79
5 files changed, 168 insertions, 30 deletions
diff --git a/lib/ipaddress/ipv4.rb b/lib/ipaddress/ipv4.rb
index 5621a97..23dec91 100644
--- a/lib/ipaddress/ipv4.rb
+++ b/lib/ipaddress/ipv4.rb
@@ -225,7 +225,7 @@ module IPAddress;
# a.puts binary_data
#
def data
- @octets.pack("CCCC")
+ @octets.pack("C4")
end
#
@@ -588,6 +588,25 @@ module IPAddress;
end
#
+ # Returns a new IPv4 object which is the result
+ # of the summarization, if possible, of the two
+ # objects
+ #
+ # Example:
+ #
+ # ip1 = IPAddress("172.16.10.1/24")
+ # ip2 = IPAddress("172.16.11.2/24")
+ # puts ip1 + ip2
+ # #=>"172.16.10.0/23"
+ #
+ # If the networks are not contiguous, returns
+ # the two network numbers from the objects
+ #
+ def +(oth)
+ self.class.summarize(self,oth)
+ end
+
+ #
# Creates a new IPv4 object from an
# unsigned 32bits integer.
#
@@ -603,7 +622,7 @@ module IPAddress;
# #=> "10.0.0.0/8"
#
def self.parse_u32(u32, prefix=nil)
- ip = [u32].pack("N").unpack("CCCC").join(".")
+ ip = [u32].pack("N").unpack("C4").join(".")
if prefix
IPAddress::IPv4.new(ip+"/#{prefix}")
else
@@ -616,7 +635,7 @@ module IPAddress;
# TODO
#
def self.parse_data(str)
- self.new str.unpack("CCCC").join(".")
+ self.new str.unpack("C4").join(".")
end
#
@@ -712,7 +731,7 @@ module IPAddress;
private
def bits_from_address(ip)
- ip.split(".").map{|i| i.to_i}.pack("CCCC").unpack("B*").first
+ ip.split(".").map{|i| i.to_i}.pack("C4").unpack("B*").first
end
def prefix_from_ip(ip)
diff --git a/lib/ipaddress/ipv6.rb b/lib/ipaddress/ipv6.rb
index ebb2d03..01e2f04 100644
--- a/lib/ipaddress/ipv6.rb
+++ b/lib/ipaddress/ipv6.rb
@@ -36,12 +36,14 @@ module IPAddress;
raise ArgumentError, "Invalid IP #{ip.inspect}"
end
- # Check the prefix
- if netmask =~ /^\d{1,3}$/
- @prefix = Prefix128.new(netmask.to_i)
- else
- @prefix = Prefix128.new(128)
- end
+# # Check the prefix
+# if netmask =~ /^\d{1,3}$/
+# @prefix = Prefix128.new(netmask.to_i)
+# else
+# @prefix = Prefix128.new(128)
+# end
+
+ @prefix = Prefix128.new(netmask ? netmask : 128)
end # def initialize
@@ -58,6 +60,27 @@ module IPAddress;
@prefix
end
+ #
+ # Set a new prefix number for the object
+ #
+ # This is useful if you want to change the prefix
+ # to an object created with IPv6::parse_u128 or
+ # if the object was created using the default prefix
+ # of 128 bits.
+ #
+ # ip = IPAddress("2001:db8::8:800:200c:417a")
+ # puts ip
+ # #=> 2001:db8::8:800:200c:417a/128
+ #
+ # ip.prefix = 64
+ # puts ip
+ # #=> 2001:db8::8:800:200c:417a/64
+ #
+ def prefix=(num)
+ @prefix = Prefix128.new(num)
+ end
+
+
def to_string
"#@address/#@prefix"
end
@@ -69,6 +92,25 @@ module IPAddress;
def to_i
to_hex.hex
end
+ alias_method :to_u128, :to_i
+
+ #
+ # Returns the 16-bits value specified by index
+ #
+ # ip = IPAddress("2001:db8::8:800:200c:417a/64")
+ # ip[0]
+ # #=> 8193
+ # ip[1]
+ # #=> 3512
+ # ip[2]
+ # #=> 0
+ # ip[3]
+ # #=> 0
+ #
+ def [](index)
+ @groups[index]
+ end
+ alias_method :group, :[]
def to_hex
hexs.to_s
@@ -93,6 +135,18 @@ module IPAddress;
def loopback?
@prefix == 128 and @compressed == "::1"
end
+
+ #
+ # Returns the address portion of an IP in binary format,
+ # as a string containing a sequence of 0 and 1
+ #
+ # ip = IPAddress("2001:db8::8:800:200c:417a")
+ # ip.bits
+ # #=> "01111111000000000000000000000001"
+ #
+ def bits
+ data.unpack("B*").first
+ end
#
# Expands an IPv6 address in the canocical form
@@ -120,6 +174,15 @@ module IPAddress;
def self.parse_data(str)
self.new(IN6FORMAT % str.unpack("n8"))
end
+
+ def self.parse_u128(u128, prefix=128)
+ str = IN6FORMAT % (0..7).map{|i| (u128>>(112-16*i))&0xffff}
+ self.new(str + "/#{prefix}")
+ end
+
+ def self.parse_hex(hex, prefix=128)
+ self.parse_u128(hex.hex, prefix)
+ end
private
diff --git a/lib/ipaddress/prefix.rb b/lib/ipaddress/prefix.rb
index 5726272..b2fa07b 100644
--- a/lib/ipaddress/prefix.rb
+++ b/lib/ipaddress/prefix.rb
@@ -69,11 +69,11 @@ module IPAddress
class Prefix128 < Prefix
- def initialize(num)
- unless (1..128).include? num
+ def initialize(num=128)
+ unless (1..128).include? num.to_i
raise ArgumentError, "Prefix must be in range 1..128, got: #{num}"
end
- super(num)
+ super(num.to_i)
end
def bits
diff --git a/test/ipaddress/ipv4_test.rb b/test/ipaddress/ipv4_test.rb
index e8b299f..70c9c9c 100644
--- a/test/ipaddress/ipv4_test.rb
+++ b/test/ipaddress/ipv4_test.rb
@@ -134,7 +134,7 @@ class IPv4Test < Test::Unit::TestCase
def test_method_bits
ip = @klass.new("127.0.0.1")
- assert_equal ip.bits, "01111111000000000000000000000001"
+ assert_equal "01111111000000000000000000000001", ip.bits
end
def test_method_first
@@ -255,6 +255,15 @@ class IPv4Test < Test::Unit::TestCase
assert_equal 9, ip1 - ip2
end
+ def test_method_plus
+ ip1 = @klass.new("172.16.10.1/24")
+ ip2 = @klass.new("172.16.11.2/24")
+ assert_equal "172.16.10.0/23", (ip1 + ip2).to_s
+ ip2 = @klass.new("172.16.12.2/24")
+ assert_equal [ip1.network.to_s,ip2.network.to_s], (ip1 + ip2).map{|i| i.to_s}
+ end
+
+
def test_method_netmask_equal
ip = @klass.new("10.1.1.1/16")
assert_equal 16, ip.prefix.to_i
diff --git a/test/ipaddress/ipv6_test.rb b/test/ipaddress/ipv6_test.rb
index afc3b45..6549442 100644
--- a/test/ipaddress/ipv6_test.rb
+++ b/test/ipaddress/ipv6_test.rb
@@ -11,8 +11,28 @@ class IPv6Test < Test::Unit::TestCase
"ff01:0:0:0:0:0:0:101" => "ff01::101",
"0:0:0:0:0:0:0:1" => "::1",
"0:0:0:0:0:0:0:0" => "::"}
+
+ @valid_ipv6 = { # Kindly taken from the python IPy library
+ "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210" => 338770000845734292534325025077361652240,
+ "1080:0000:0000:0000:0008:0800:200C:417A" => 21932261930451111902915077091070067066,
+ "1080:0:0:0:8:800:200C:417A" => 21932261930451111902915077091070067066,
+ "1080:0::8:800:200C:417A" => 21932261930451111902915077091070067066,
+ "1080::8:800:200C:417A" => 21932261930451111902915077091070067066,
+ "FF01:0:0:0:0:0:0:43" => 338958331222012082418099330867817087043,
+ "FF01:0:0::0:0:43" => 338958331222012082418099330867817087043,
+ "FF01::43" => 338958331222012082418099330867817087043,
+ "0:0:0:0:0:0:0:1" => 1,
+ "0:0:0::0:0:1" => 1,
+ "::1" => 1,
+ "0:0:0:0:0:0:0:0" => 0,
+ "0:0:0::0:0:0" => 0,
+ "::" => 0,
+ "1080:0:0:0:8:800:200C:417A" => 21932261930451111902915077091070067066,
+ "1080::8:800:200C:417A" => 21932261930451111902915077091070067066}
+
@ip = @klass.new "2001:db8::8:800:200c:417a/64"
+ @arr = [8193,3512,0,0,8,2048,8204,16762]
end
@@ -27,8 +47,7 @@ class IPv6Test < Test::Unit::TestCase
end
def test_attribute_groups
- arr = [8193,3512,0,0,8,2048,8204,16762]
- assert_equal arr, @ip.groups
+ assert_equal @arr, @ip.groups
end
def test_method_hexs
@@ -37,8 +56,30 @@ class IPv6Test < Test::Unit::TestCase
end
def test_method_to_i
- bigint = 42540766411282592856906245548098208122
- assert_equal bigint, @ip.to_i
+ @valid_ipv6.each do |ip,num|
+ assert_equal num, @klass.new(ip).to_i
+ end
+ end
+
+ def test_method_bits
+ bits = "0010000000000001000011011011100000000000000000000" +
+ "000000000000000000000000000100000001000000000000010000" +
+ "0000011000100000101111010"
+ assert_equal bits, @ip.bits
+ end
+
+ def test_method_prefix=()
+ ip = @klass.new "2001:db8::8:800:200c:417a"
+ assert_equal 128, ip.prefix
+ ip.prefix = 64
+ assert_equal 64, ip.prefix
+ assert_equal "2001:db8::8:800:200c:417a/64", ip.to_s
+ end
+
+ def test_method_group
+ @arr.each_with_index do |val,index|
+ assert_equal val, @ip[index]
+ end
end
def test_method_to_hex
@@ -68,16 +109,16 @@ class IPv6Test < Test::Unit::TestCase
assert_equal "1::1", @klass.new("1:0:0:0:0:0:0:1").compressed
end
- def test_method_unspecified?
- assert_equal true, @klass.new("::").unspecified?
- assert_equal false, @ip.unspecified?
- end
-
- def test_method_loopback?
- assert_equal true, @klass.new("::1").loopback?
- assert_equal false, @ip.loopback?
- end
-
+ def test_method_unspecified?
+ assert_equal true, @klass.new("::").unspecified?
+ assert_equal false, @ip.unspecified?
+ end
+
+ def test_method_loopback?
+ assert_equal true, @klass.new("::1").loopback?
+ assert_equal false, @ip.loopback?
+ end
+
def test_classmethod_expand
compressed = "2001:db8:0:cd30::"
expanded = "2001:0db8:0000:cd30:0000:0000:0000:0000"
@@ -86,7 +127,7 @@ class IPv6Test < Test::Unit::TestCase
assert_not_equal expanded, @klass.expand("2001:0db8::cd30")
assert_not_equal expanded, @klass.expand("2001:0db8::cd3")
end
-
+
def test_classmethod_compress
compressed = "2001:db8:0:cd30::"
expanded = "2001:0db8:0000:cd30:0000:0000:0000:0000"
@@ -119,7 +160,13 @@ class IPv6Test < Test::Unit::TestCase
assert_equal "2001:0db8:0000:0000:0008:0800:200c:417a", ip.address
assert_equal "2001:db8::8:800:200c:417a/128", ip.to_s
end
-
+
+ def test_classhmethod_parse_u128
+ @valid_ipv6.each do |ip,num|
+ assert_equal @klass.new(ip).to_s, @klass.parse_u128(num).to_s
+ end
+ end
+
end # class IPv4Test