diff options
Diffstat (limited to 'lib/ipaddress')
-rw-r--r-- | lib/ipaddress/ipv4.rb | 126 | ||||
-rw-r--r-- | lib/ipaddress/ipv6.rb | 18 | ||||
-rw-r--r-- | lib/ipaddress/mongoid.rb | 75 | ||||
-rw-r--r-- | lib/ipaddress/prefix.rb | 12 | ||||
-rw-r--r-- | lib/ipaddress/version.rb | 3 |
5 files changed, 214 insertions, 20 deletions
diff --git a/lib/ipaddress/ipv4.rb b/lib/ipaddress/ipv4.rb index e99aea2..19ab14c 100644 --- a/lib/ipaddress/ipv4.rb +++ b/lib/ipaddress/ipv4.rb @@ -61,6 +61,7 @@ module IPAddress; # IPAddress::IPv4.new "10.0.0.1/255.0.0.0" # def initialize(str) + raise ArgumentError, "Nil IP" unless str ip, netmask = str.split("/") # Check the ip and remove white space @@ -231,6 +232,21 @@ module IPAddress; alias_method :to_u32, :u32 # + # Returns the address portion in + # hex + # + # ip = IPAddress("10.0.0.0") + # + # ip.to_h + # #=> 0a000000 + # + def hex(space=true) + "%.4x%.4x" % [to_u32].pack("N").unpack("nn") + end + alias_method :to_h, :hex + alias_method :to_hex, :hex + + # # Returns the address portion of an IPv4 object # in a network byte order format. # @@ -271,6 +287,21 @@ module IPAddress; @octets[index] end alias_method :octet, :[] + + # + # Updated the octet specified at index + # + # ip = IPAddress("172.16.100.50/24") + # ip[2] = 200 + # + # #=> #<IPAddress::IPv4:0x00000000000000 @address="172.16.200.1", + # #=> @prefix=32, @octets=[172, 16, 200, 1], @u32=2886780929> + # + def []=(index, value) + @octets[index] = value.to_i + initialize("#{@octets.join('.')}/#{prefix}") + end + alias_method :octet=, :[]= # # Returns the address portion of an IP in binary format, @@ -294,7 +325,14 @@ module IPAddress; # #=> "172.16.10.255" # def broadcast - self.class.parse_u32(broadcast_u32, @prefix) + case + when prefix <= 30 + self.class.parse_u32(broadcast_u32, @prefix) + when prefix == 31 + self.class.parse_u32(-1, @prefix) + when prefix == 32 + return self + end end # @@ -311,7 +349,7 @@ module IPAddress; # #=> true # def network? - @u32 | @prefix.to_u32 == @prefix.to_u32 + (@prefix < 32) && (@u32 | @prefix.to_u32 == @prefix.to_u32) end # @@ -348,7 +386,14 @@ module IPAddress; # #=> "192.168.100.1" # def first - self.class.parse_u32(network_u32+1, @prefix) + case + when prefix <= 30 + self.class.parse_u32(network_u32+1, @prefix) + when prefix == 31 + self.class.parse_u32(network_u32, @prefix) + when prefix == 32 + return self + end end # @@ -373,7 +418,14 @@ module IPAddress; # #=> "192.168.100.254" # def last - self.class.parse_u32(broadcast_u32-1, @prefix) + case + when prefix <= 30 + self.class.parse_u32(broadcast_u32-1, @prefix) + when prefix == 31 + self.class.parse_u32(broadcast_u32, @prefix) + when prefix == 32 + return self + end end # @@ -458,6 +510,7 @@ module IPAddress; # #=> ["10.100.100.1/8","10.100.100.1/16","172.16.0.1/16"] # def <=>(oth) + return nil unless oth.is_a?(self.class) return prefix <=> oth.prefix if to_u32 == oth.to_u32 to_u32 <=> oth.to_u32 end @@ -570,6 +623,34 @@ module IPAddress; end # + # Checks if an IPv4 address objects belongs + # to a multicast network RFC3171 + # + # Example: + # + # ip = IPAddress "224.0.0.0/4" + # ip.multicast? + # #=> true + # + def multicast? + [self.class.new("224.0.0.0/4")].any? {|i| i.include? self} + end + + # + # Checks if an IPv4 address objects belongs + # to a loopback network RFC1122 + # + # Example: + # + # ip = IPAddress "127.0.0.1" + # ip.loopback? + # #=> true + # + def loopback? + [self.class.new("127.0.0.0/8")].any? {|i| i.include? self} + end + + # # Returns the IP address in in-addr.arpa format # for DNS lookups # @@ -584,6 +665,26 @@ module IPAddress; alias_method :arpa, :reverse # + # Return a list of IP's between @address + # and the supplied IP + # + # ip = IPAddress("172.16.100.51/32") + # + # ip.to("172.16.100.100") + # #=> ["172.16.100.51", + # #=> "172.16.100.52", + # #=> ... + # #=> "172.16.100.99", + # #=> "172.16.100.100"] + # + def to(e) + unless e.is_a? IPAddress::IPv4 + e = IPv4.new(e) + end + + Range.new(@u32, e.to_u32).map{|i| IPAddress.ntoa(i) } + end + # # Splits a network into different subnets # # If the IP Address is a network, it can be divided into @@ -598,9 +699,9 @@ module IPAddress; # # network / 4 # implies map{|i| i.to_string} # #=> ["172.16.10.0/26", - # "172.16.10.64/26", - # "172.16.10.128/26", - # "172.16.10.192/26"] + # #=> "172.16.10.64/26", + # #=> "172.16.10.128/26", + # #=> "172.16.10.192/26"] # # If +num+ is any other number, the supernet will be # divided into some networks with a even number of hosts and @@ -610,8 +711,8 @@ module IPAddress; # # network / 3 # implies map{|i| i.to_string} # #=> ["172.16.10.0/26", - # "172.16.10.64/26", - # "172.16.10.128/25"] + # #=> "172.16.10.64/26", + # #=> "172.16.10.128/25"] # # Returns an array of IPv4 objects # @@ -969,12 +1070,9 @@ module IPAddress; # private + # Tweaked to remove the #upto(32) def newprefix(num) - num.upto(32) do |i| - if (a = Math::log2(i).to_i) == Math::log2(i) - return @prefix + a - end - end + return @prefix + (Math::log2(num).ceil ) end def sum_first_found(arr) diff --git a/lib/ipaddress/ipv6.rb b/lib/ipaddress/ipv6.rb index 33d4d19..3e506ac 100644 --- a/lib/ipaddress/ipv6.rb +++ b/lib/ipaddress/ipv6.rb @@ -87,6 +87,7 @@ module IPAddress; # ip6 = IPAddress "2001:db8::8:800:200c:417a/64" # def initialize(str) + raise ArgumentError, "Nil IP" unless str ip, netmask = str.split("/") if str =~ /:.+\./ @@ -252,6 +253,15 @@ module IPAddress; end alias_method :group, :[] + # + # Updated the octet specified at index + # + def []=(index, value) + @groups[index] = value + initialize("#{IN6FORMAT % @groups}/#{prefix}") + end + alias_method :group=, :[]= + # # Returns a Base16 number representing the IPv6 # address @@ -388,6 +398,13 @@ module IPAddress; @compressed end + # + # Returns true if the address is a link local address + # + def link_local? + @groups[0] == 0xfe80 + end + # # Returns true if the address is an unspecified address # @@ -478,6 +495,7 @@ module IPAddress; # #=> ["2001:db8:1::1/64","2001:db8:1::1/65","2001:db8:2::1/64"] # def <=>(oth) + return nil unless oth.is_a?(self.class) return prefix <=> oth.prefix if to_u128 == oth.to_u128 to_u128 <=> oth.to_u128 end diff --git a/lib/ipaddress/mongoid.rb b/lib/ipaddress/mongoid.rb new file mode 100644 index 0000000..3af880a --- /dev/null +++ b/lib/ipaddress/mongoid.rb @@ -0,0 +1,75 @@ +module IPAddress + + # + # Mongoid field serialization + # + # IPAddress objects are converted to String + # + # IPAddress.mongoize IPAddress.parse("172.16.10.1") + # #=> "172.16.10.1" + # + # Prefix will be removed from host adresses + # + # IPAddress.mongoize "172.16.10.1/32" + # #=> "172.16.10.1" + # + # Prefix will be kept for network addresses + # + # IPAddress.mongoize "172.16.10.1/24" + # #=> "172.16.10.1/24" + # + # IPv6 addresses will be stored uncompressed to ease DB search and sorting + # + # IPAddress.mongoize "2001:db8::8:800:200c:417a" + # #=> "2001:0db8:0000:0000:0008:0800:200c:417a" + # IPAddress.mongoize "2001:db8::8:800:200c:417a/64" + # #=> "2001:0db8:0000:0000:0008:0800:200c:417a/64" + # + # Invalid addresses will be serialized as nil + # + # IPAddress.mongoize "invalid" + # #=> nil + # IPAddress.mongoize "" + # #=> nil + # IPAddress.mongoize 1 + # #=> nil + # IPAddress.mongoize nil + # #=> nil + # + def self.mongoize(ipaddress) + ipaddress = self.parse(ipaddress) unless ipaddress.is_a?(IPAddress) + if ipaddress.bits.length == ipaddress.prefix + ipaddress.address + elsif ipaddress.is_a?(IPAddress::IPv6) + ipaddress.to_string_uncompressed + else + ipaddress.to_string + end + rescue ArgumentError + nil + end + + # + # Mongoid field deserialization + # + def self.demongoize(string) + parse(string) + rescue ArgumentError + nil + end + + # + # Delegates to IPAddress.mongoize + # + def self.evolve(ipaddress) + mongoize(ipaddress) + end + + # + # Sends self object to IPAddress#mongoize + # + def mongoize + IPAddress.mongoize(self) + end + +end
\ No newline at end of file diff --git a/lib/ipaddress/prefix.rb b/lib/ipaddress/prefix.rb index f3d585d..136f2d3 100644 --- a/lib/ipaddress/prefix.rb +++ b/lib/ipaddress/prefix.rb @@ -55,10 +55,10 @@ module IPAddress # # Sums two prefixes or a prefix to a - # number, returns a Fixnum + # number, returns a Integer # def +(oth) - if oth.is_a? Fixnum + if oth.is_a? Integer self.prefix + oth else self.prefix + oth.prefix @@ -68,10 +68,10 @@ module IPAddress # # Returns the difference between two # prefixes, or a prefix and a number, - # as a Fixnum + # as a Integer # def -(oth) - if oth.is_a? Fixnum + if oth.is_a? Integer self.prefix - oth else (self.prefix - oth.prefix).abs @@ -214,8 +214,8 @@ module IPAddress # #=> 64 # def initialize(num=128) - unless (1..128).include? num.to_i - raise ArgumentError, "Prefix must be in range 1..128, got: #{num}" + unless (0..128).include? num.to_i + raise ArgumentError, "Prefix must be in range 0..128, got: #{num}" end super(num.to_i) end diff --git a/lib/ipaddress/version.rb b/lib/ipaddress/version.rb new file mode 100644 index 0000000..f637ef8 --- /dev/null +++ b/lib/ipaddress/version.rb @@ -0,0 +1,3 @@ +module Ipaddress + VERSION = "0.8.3" +end |