diff options
author | Marco Ceresa <ceresa@gmail.com> | 2010-01-19 11:42:16 +0000 |
---|---|---|
committer | Marco Ceresa <ceresa@gmail.com> | 2010-01-19 11:42:16 +0000 |
commit | 9030d410a3757558ef23ac2317f2fb82d5a1e324 (patch) | |
tree | a943e29731d8976f314a8876dec0049cf171d4f0 /lib | |
parent | a6c67904f9daf29142f3e6f989445edd1390f579 (diff) | |
download | ipaddress-9030d410a3757558ef23ac2317f2fb82d5a1e324.tar.gz |
Added IPv6 support
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ipaddress.rb | 2 | ||||
-rw-r--r-- | lib/ipaddress/ipv4.rb | 29 | ||||
-rw-r--r-- | lib/ipaddress/ipv6.rb | 162 | ||||
-rw-r--r-- | lib/ipaddress/prefix.rb | 34 |
4 files changed, 205 insertions, 22 deletions
diff --git a/lib/ipaddress.rb b/lib/ipaddress.rb index a6fe2da..4752e01 100644 --- a/lib/ipaddress.rb +++ b/lib/ipaddress.rb @@ -3,7 +3,7 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')) require 'ipaddress/ipbase' require 'ipaddress/ipv4' - +require 'ipaddress/ipv6' def IPAddress(str) if str.include? "-" diff --git a/lib/ipaddress/ipv4.rb b/lib/ipaddress/ipv4.rb index 2ca0d49..5621a97 100644 --- a/lib/ipaddress/ipv4.rb +++ b/lib/ipaddress/ipv4.rb @@ -33,7 +33,6 @@ module IPAddress; /^10./ => 16, # Class B, from 128.0.0.0 to 191.255.255.255 /^110/ => 24 # Class C, D and E, from 192.0.0.0 to 255.255.255.254 } - # # Creates a new IPv4 address object. @@ -203,18 +202,30 @@ module IPAddress; # ip.to_u32 # #=> 167772160 # + def to_u32 + data.unpack("N").first + end + alias_method :to_i, :to_u32 + + # Returns the address portion of an IPv4 object + # in a network byte order format. + # + # ip = IPAddress("172.16.10.1/24") + # ip.data + # #=> "\254\020\n\001" + # # It is usually used to include an IP address # in a data packet to be sent over a socket # # a = Socket.open(params) # socket details here # ip = IPAddress("10.1.1.0/24") - # binary_data = ["Address: "].pack("a*") + ip.to_u32 + # binary_data = ["Address: "].pack("a*") + ip.data # # # Send binary data # a.puts binary_data # - def to_u32 - @octets.pack("CCCC").unpack("N").first + def data + @octets.pack("CCCC") end # @@ -244,7 +255,7 @@ module IPAddress; # #=> "01111111000000000000000000000001" # def bits - @octets.pack("CCCC").unpack("B*").first + data.unpack("B*").first end # @@ -601,6 +612,14 @@ module IPAddress; end # + # Docs here + # TODO + # + def self.parse_data(str) + self.new str.unpack("CCCC").join(".") + end + + # # Summarization (or aggregation) is the process when two or more # networks are taken together to check if a supernet, including all # and only these networks, exists. If it exists then this supernet diff --git a/lib/ipaddress/ipv6.rb b/lib/ipaddress/ipv6.rb new file mode 100644 index 0000000..ebb2d03 --- /dev/null +++ b/lib/ipaddress/ipv6.rb @@ -0,0 +1,162 @@ +require 'ipaddress/ipbase' +require 'ipaddress/prefix' + +# +# =Name +# +# IPAddress::IPv6 - IP version 6 address manipulation library +# +# =Synopsis +# +# require 'ipaddress' +# +# =Description +# +# This library provides a complete +# +# +module IPAddress; + class IPv6 < IPBase + + include IPAddress + include Enumerable + include Comparable + + IN6FORMAT = ("%.4x:"*8).chop + + def initialize(str) + ip, netmask = str.split("/") + + # Check the ip and remove white space + if IPAddress.valid_ipv6?(ip) + @groups = self.class.groups(ip) + @address = IN6FORMAT % @groups + @compressed = compress_address + else + 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 + + end # def initialize + + + def address + @address + end + + def groups + @groups + end + + def prefix + @prefix + end + + def to_string + "#@address/#@prefix" + end + + def to_s + "#{compressed}/#@prefix" + end + + def to_i + to_hex.hex + end + + def to_hex + hexs.to_s + end + + def data + @groups.pack("n8") + end + + def hexs + @address.split(":") + end + + def compressed + @compressed + end + + def unspecified? + @prefix == 128 and @compressed == "::" + end + + def loopback? + @prefix == 128 and @compressed == "::1" + end + + # + # Expands an IPv6 address in the canocical form + # + # IPAddress::IPv6.expand "2001:0DB8:0:CD30::" + # #=> "2001:0DB8:0000:CD30:0000:0000:0000:0000" + # + def self.expand(str) + self.new(str).address + end + + def self.compress(str) + self.new(str).compressed + end + + def self.groups(str) + l, r = if str =~ /^(.*)::(.*)$/ + [$1,$2].map {|i| i.split ":"} + else + [str.split(":"),[]] + end + (l + Array.new(8-l.size-r.size, '0') + r).map {|i| i.hex} + end + + def self.parse_data(str) + self.new(IN6FORMAT % str.unpack("n8")) + end + + private + + def compress_address + str = @groups.map{|i| i.to_s 16}.join ":" + loop do + break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::') + break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':') + break if str.sub!(/\b0:0:0:0:0:0\b/, ':') + break if str.sub!(/\b0:0:0:0:0\b/, ':') + break if str.sub!(/\b0:0:0:0\b/, ':') + break if str.sub!(/\b0:0:0\b/, ':') + break if str.sub!(/\b0:0\b/, ':') + break + end + str.sub(/:{3,}/, '::') + end + + end # class IPv6 + +class IPAddress::IPv6::Unspecified < IPAddress::IPv6 + def initialize + @address = ("0000:"*8).chop + @groups = Array.new(8,0) + @prefix = Prefix128.new(128) + end +end + +class IPAddress::IPv6::Loopback < IPAddress::IPv6 + def initialize + @address = ("0000:"*7)+"0001" + @groups = Array.new(7,0).push(1) + @prefix = Prefix128.new(128) + end +end + + + +end # module IPAddress + diff --git a/lib/ipaddress/prefix.rb b/lib/ipaddress/prefix.rb index 61109ff..5726272 100644 --- a/lib/ipaddress/prefix.rb +++ b/lib/ipaddress/prefix.rb @@ -1,4 +1,5 @@ module IPAddress + class Prefix include Comparable @@ -9,11 +10,6 @@ module IPAddress @prefix = num.to_i end - def bits - "1" * @prefix + "0" * (@size - @prefix) - #sprintf "%0#@sizeb",(@mask & ~(@mask >> @prefix)) - end - def to_s "#@prefix" end @@ -29,15 +25,20 @@ module IPAddress end # class Prefix + class Prefix32 < Prefix def initialize(num) - raise ArgumentError unless (1..32).include? num - @mask = 0xffffffff - @size = 32 + unless (1..32).include? num + raise ArgumentError, "Prefix must be in range 1..128, got: #{num}" + end super(num) end + def bits + "1" * @prefix + "0" * (32 - @prefix) + end + def to_ip [bits].pack("B*").unpack("CCCC").join(".") end @@ -69,19 +70,20 @@ module IPAddress class Prefix128 < Prefix def initialize(num) - raise ArgumentError unless (1..128).include? num - @mask = 0xffffffffffffffffffffffffffffffff - @size = 128 + unless (1..128).include? num + raise ArgumentError, "Prefix must be in range 1..128, got: #{num}" + end super(num) end + def bits + "1" * @prefix + "0" * (128 - @prefix) + end + def to_u128 - [bits].pack("B*").unpack("N4").first + eval "0b#{bits}.to_i" end - - end - - + end # class Prefix123 < Prefix end # module IPAddress |