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|