lib/ipaddress/ipv4.rb in ipaddress-0.6.0 vs lib/ipaddress/ipv4.rb in ipaddress-0.7.0

- old
+ new

@@ -40,34 +40,27 @@ # # Creates a new IPv4 address object. # # An IPv4 address can be expressed in any of the following forms: # - # * "10.1.1.1/24": ip address and prefix. This is the common and - # suggested way to create an object . - # * "10.1.1.1/255.255.255.0": ip address and netmask. Although - # convenient sometimes, this format is less clear than the previous - # one. - # * "10.1.1.1": if the address alone is specified, the prefix will be - # assigned using the classful boundaries. In this case, the - # prefix would be /8, a 255.0.0.0 netmask. - # - # It is advisable to use the syntactic shortcut provided with the - # IPAddress() method, as in all the examples below. - # + # * "10.1.1.1/24": ip +address+ and +prefix+. This is the common and + # suggested way to create an object . + # * "10.1.1.1/255.255.255.0": ip +address+ and +netmask+. Although + # convenient sometimes, this format is less clear than the previous + # one. + # * "10.1.1.1": if the address alone is specified, the prefix will be + # set as default 32, also known as the host prefix + # # Examples: # - # # These two methods return the same object + # # These two are the same # ip = IPAddress::IPv4.new("10.0.0.1/24") # ip = IPAddress("10.0.0.1/24") # - # # These three are the same - # IPAddress("10.0.0.1/8") - # IPAddress("10.0.0.1/255.0.0.0") - # IPAddress("10.0.0.1") - # #=> #<IPAddress::IPv4:0xb7b1a438 - # @octets=[10, 0, 0, 1], @address="10.0.0.1", @prefix=8> + # # These two are the same + # IPAddress::IPv4.new "10.0.0.1/8" + # IPAddress::IPv4.new "10.0.0.1/255.0.0.0" # def initialize(str) ip, netmask = str.split("/") # Check the ip and remove white space @@ -86,16 +79,18 @@ @prefix = Prefix32.parse_netmask(netmask) else # invalid netmask raise ArgumentError, "Invalid netmask #{netmask}" end else # netmask is nil, reverting to defaul classful mask - @prefix = prefix_from_ip(@address) + @prefix = Prefix32.new(32) end # Array formed with the IP octets @octets = @address.split(".").map{|i| i.to_i} - + # 32 bits interger containing the address + @u32 = (@octets[0]<< 24) + (@octets[1]<< 16) + (@octets[2]<< 8) + (@octets[3]) + end # def initialize # # Returns the address portion of the IPv4 object # as a string. @@ -183,11 +178,10 @@ # def to_string "#@address/#@prefix" end - # # Returns the prefix as a string in IP format # # ip = IPAddress("172.16.100.4/22") # @@ -225,18 +219,19 @@ # inet_pton to create a 32 bits address family # structure. # # ip = IPAddress("10.0.0.0/8") # - # ip.to_u32 + # ip.to_i # #=> 167772160 # - def to_u32 - data.unpack("N").first + def u32 + @u32 end - alias_method :to_i, :to_u32 - + alias_method :to_i, :u32 + alias_method :to_u32, :u32 + # # Returns the address portion of an IPv4 object # in a network byte order format. # # ip = IPAddress("172.16.10.1/24") @@ -253,11 +248,11 @@ # # # Send binary data # a.puts binary_data # def data - @octets.pack("C4") + [@u32].pack("N") end # # Returns the octet specified by index # @@ -314,11 +309,11 @@ # # ip.network? # #=> true # def network? - to_u32 | @prefix.to_u32 == @prefix.to_u32 + @u32 | @prefix.to_u32 == @prefix.to_u32 end # # Returns a new IPv4 object with the network number # for the given IP. @@ -475,11 +470,11 @@ # # ip.size # #=> 8 # def size - broadcast_u32 - network_u32 + 1 + 2 ** @prefix.host_prefix end # # Returns an array with the IP addresses of # all the hosts in the network. @@ -505,11 +500,11 @@ # # ip.network_u32 # #=> 167772160 # def network_u32 - to_u32 & @prefix.to_u32 + @u32 & @prefix.to_u32 end # # Returns the broadcast address in Unsigned 32bits format # @@ -517,11 +512,11 @@ # # ip.broadcast_u32 # #=> 167772167 # def broadcast_u32 - [to_u32 | ~@prefix.to_u32].pack("N").unpack("N").first + network_u32 + size - 1 end # # Checks whether a subnet includes the given IP address. # @@ -537,14 +532,30 @@ # # ip.include? IPAddress("172.16.0.48/16") # #=> false # def include?(oth) - @prefix <= oth.prefix and network_u32 == self.class.new(oth.address+"/#@prefix").network_u32 + @prefix <= oth.prefix and network_u32 == (oth.to_u32 & @prefix.to_u32) end # + # Checks if an IPv4 address objects belongs + # to a private network RFC1918 + # + # Example: + # + # ip = IPAddress "10.1.1.1/24" + # ip.private? + # #=> true + # + def private? + [self.class.new("10.0.0.0/8"), + self.class.new("172.16.0.0/12"), + self.class.new("192.168.0.0/16")].any? {|i| i.include? self} + end + + # # Returns the IP address in in-addr.arpa format # for DNS lookups # # ip = IPAddress("172.16.100.50/24") # @@ -587,11 +598,11 @@ # "172.16.10.128/25"] # # Returns an array of IPAddress objects # def subnet(subnets=2) - unless (1..(2**(32-prefix.to_i))).include? subnets + unless (1..(2**@prefix.host_prefix)).include? subnets raise ArgumentError, "Value #{subnets} out of range" end calculate_subnets(subnets) end alias_method :/, :subnet @@ -744,17 +755,12 @@ # ip = IPAddress::IPv4::parse_u32(167772160, 8) # # ip.to_string # #=> "10.0.0.0/8" # - def self.parse_u32(u32, prefix=nil) - ip = [u32].pack("N").unpack("C4").join(".") - if prefix - self.new(ip+"/#{prefix}") - else - self.new(ip) - end + def self.parse_u32(u32, prefix=32) + self.new([u32].pack("N").unpack("C4").join(".")+"/#{prefix}") end # # Creates a new IPv4 object from binary data, # like the one you get from a network stream. @@ -766,16 +772,16 @@ # ip.prefix = 24 # # ip.to_string # #=> "172.16.10.1/24" # - def self.parse_data(str) - self.new str.unpack("C4").join(".") + def self.parse_data(str, prefix=32) + self.new(str.unpack("C4").join(".")+"/#{prefix}") end # - # Exctract an IPv4 address from a string and + # Extract an IPv4 address from a string and # returns a new object # # Example: # # str = "foobar172.16.10.1barbaz" @@ -871,22 +877,46 @@ return self.summarize(*result) end end # + # Creates a new IPv4 address object by parsing the + # address in a classful way. + # + # Classful addresses have a fixed netmask based on the + # class they belong to: + # + # * Class A, from 0.0.0.0 to 127.255.255.255 + # * Class B, from 128.0.0.0 to 191.255.255.255 + # * Class C, D and E, from 192.0.0.0 to 255.255.255.254 + # + # Note that classes C, D and E will all have a default + # prefix of /24 or 255.255.255.0 + # + # Example: + # + # ip = IPAddress::IPv4.parse_classful "10.0.0.1" + # + # ip.netmask + # #=> "255.0.0.0" + # ip.a? + # #=> true + # + def self.parse_classful(ip) + if IPAddress.valid_ipv4?(ip) + address = ip.strip + else + raise ArgumentError, "Invalid IP #{ip.inspect}" + end + prefix = CLASSFUL.find{|h,k| h === ("%.8b" % address.to_i)}.last + self.new "#{address}/#{prefix}" + end + + # # private methods # private - def bits_from_address(ip) - ip.split(".").map{|i| i.to_i}.pack("C4").unpack("B*").first - end - - def prefix_from_ip(ip) - bits = bits_from_address(ip) - CLASSFUL.each {|reg,prefix| return Prefix32.new(prefix) if bits =~ reg} - end - def calculate_subnets(subnets) po2 = subnets.closest_power_of_2 new_prefix = @prefix + Math::log2(po2).to_i networks = Array.new (0..po2-1).each do |i|