class IPAddress::IPv4
Name¶ ↑
IPAddress::IPv4
- IP version 4 address manipulation library
Synopsis¶ ↑
require 'ipaddress'
Description¶ ↑
Class IPAddress::IPv4
is used to handle IPv4
type addresses.
Constants
Public Class Methods
Extract an IPv4
address from a string and returns a new object
Example:
str = "foobar172.16.10.1barbaz" ip = IPAddress::IPv4::extract str ip.to_s #=> "172.16.10.1"
# File lib/ipaddress_2/ipv4.rb, line 1127 def self.extract(str) self.new REGEXP.match(str).to_s end
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
andprefix
. This is the common and
suggested way to create an object .
-
“10.1.1.1/255.255.255.0”: ip
address
andnetmask
. 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 are the same ip = IPAddress::IPv4.new("10.0.0.1/24") ip = IPAddress("10.0.0.1/24") # These two are the same IPAddress::IPv4.new "10.0.0.1/8" IPAddress::IPv4.new "10.0.0.1/255.0.0.0"
# File lib/ipaddress_2/ipv4.rb, line 63 def initialize(str) raise ArgumentError, "Nil IP" unless str ip, netmask = str.split("/") # Check the ip and remove white space if IPAddress.valid_ipv4?(ip) @address = ip.strip else raise ArgumentError, "Invalid IP #{ip.inspect}" end # Check the netmask if netmask # netmask is defined netmask.strip! if netmask =~ /^\d{1,2}$/ # netmask in cidr format @prefix = Prefix32.new(netmask.to_i) elsif IPAddress.valid_ipv4_netmask?(netmask) # netmask in IP format @prefix = Prefix32.parse_netmask(netmask) else # invalid netmask raise ArgumentError, "Invalid netmask #{netmask}" end else # netmask is nil, reverting to defaul classful mask @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]) @allocator = 0 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
Example:
ip = IPAddress::IPv4.parse_classful "10.0.0.1" ip.netmask #=> "255.0.0.0" ip.a? #=> true
Note that classes C, D and E will all have a default prefix of /24 or 255.255.255.0
# File lib/ipaddress_2/ipv4.rb, line 1238 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
Creates a new IPv4
object from binary data, like the one you get from a network stream.
For example, on a network stream the IP 172.16.0.1 is represented with the binary “254020n001”.
ip = IPAddress::IPv4::parse_data "\254\020\n\001" ip.prefix = 24 ip.to_string #=> "172.16.10.1/24"
# File lib/ipaddress_2/ipv4.rb, line 1111 def self.parse_data(str, prefix=32) self.new(str.unpack("C4").join(".")+"/#{prefix}") end
Creates a new IPv4
object from an unsigned 32bits integer.
ip = IPAddress::IPv4::parse_u32(167772160) ip.prefix = 8 ip.to_string #=> "10.0.0.0/8"
The prefix
parameter is optional:
ip = IPAddress::IPv4::parse_u32(167772160, 8) ip.to_string #=> "10.0.0.0/8"
# File lib/ipaddress_2/ipv4.rb, line 1094 def self.parse_u32(u32, prefix=32) self.new([u32].pack("N").unpack("C4").join(".")+"/#{prefix}") 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 is called the summarized (or aggregated) network.
It is very important to understand that summarization can only occur if there are no holes in the aggregated network, or, in other words, if the given networks fill completely the address space of the supernet. So the two rules are:
1) The aggregate network must contain all
the IP addresses of the
original networks;
2) The aggregate network must contain only
the IP addresses of the
original networks;
A few examples will help clarify the above. Let's consider for instance the following two networks:
ip1 = IPAddress("172.16.10.0/24") ip2 = IPAddress("172.16.11.0/24")
These two networks can be expressed using only one IP address network if we change the prefix. Let Ruby do the work:
IPAddress::IPv4::summarize(ip1,ip2).to_s #=> "172.16.10.0/23"
We note how the network “172.16.10.0/23” includes all the addresses specified in the above networks, and (more important) includes ONLY those addresses.
If we summarized ip1
and ip2
with the following network:
"172.16.0.0/16"
we would have satisfied rule #1 above, but not rule #2. So “172.16.0.0/16” is not an aggregate network for ip1
and ip2
.
If it's not possible to compute a single aggregated network for all the original networks, the method returns an array with all the aggregate networks found. For example, the following four networks can be aggregated in a single /22:
ip1 = IPAddress("10.0.0.1/24") ip2 = IPAddress("10.0.1.1/24") ip3 = IPAddress("10.0.2.1/24") ip4 = IPAddress("10.0.3.1/24") IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_string #=> "10.0.0.0/22",
But the following networks can't be summarized in a single network:
ip1 = IPAddress("10.0.1.1/24") ip2 = IPAddress("10.0.2.1/24") ip3 = IPAddress("10.0.3.1/24") ip4 = IPAddress("10.0.4.1/24") IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string} #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
# File lib/ipaddress_2/ipv4.rb, line 1193 def self.summarize(*args) # one network? no need to summarize return [args.first.network] if args.size == 1 i = 0 result = args.dup.sort.map{|ip| ip.network} while i < result.size-1 sum = result[i] + result[i+1] result[i..i+1] = sum.first if sum.size == 1 i += 1 end result.flatten! if result.size == args.size # nothing more to summarize return result else # keep on summarizing return self.summarize(*result) end end
Public Instance Methods
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") p (ip1 + ip2).map {|i| i.to_string} #=> ["172.16.10.0/23"]
If the networks are not contiguous, returns the two network numbers from the objects
ip1 = IPAddress("10.0.0.1/24") ip2 = IPAddress("10.0.2.1/24") p (ip1 + ip2).map {|i| i.to_string} #=> ["10.0.0.0/24","10.0.2.0/24"]
# File lib/ipaddress_2/ipv4.rb, line 919 def +(oth) aggregate(*[self,oth].sort.map{|i| i.network}) end
Returns the difference between two IP addresses in unsigned int 32 bits format
Example:
ip1 = IPAddress("172.16.10.0/24") ip2 = IPAddress("172.16.11.0/24") puts ip1 - ip2 #=> 256
# File lib/ipaddress_2/ipv4.rb, line 893 def -(oth) return (to_u32 - oth.to_u32).abs end
Spaceship operator to compare IPv4
objects
Comparing IPv4
addresses is useful to ordinate them into lists that match our intuitive perception of ordered IP addresses.
The first comparison criteria is the u32 value. For example, 10.100.100.1 will be considered to be less than 172.16.0.1, because, in a ordered list, we expect 10.100.100.1 to come before 172.16.0.1.
The second criteria, in case two IPv4
objects have identical addresses, is the prefix. An higher prefix will be considered greater than a lower prefix. This is because we expect to see 10.100.100.0/24 come before 10.100.100.0/25.
Example:
ip1 = IPAddress "10.100.100.1/8" ip2 = IPAddress "172.16.0.1/16" ip3 = IPAddress "10.100.100.1/16" ip1 < ip2 #=> true ip1 > ip3 #=> false [ip1,ip2,ip3].sort.map{|i| i.to_string} #=> ["10.100.100.1/8","10.100.100.1/16","172.16.0.1/16"]
# File lib/ipaddress_2/ipv4.rb, line 566 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
Returns the octet specified by index
ip = IPAddress("172.16.100.50/24") ip[0] #=> 172 ip[1] #=> 16 ip[2] #=> 100 ip[3] #=> 50
# File lib/ipaddress_2/ipv4.rb, line 299 def [](index) @octets[index] end
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>
# File lib/ipaddress_2/ipv4.rb, line 313 def []=(index, value) @octets[index] = value.to_i initialize("#{@octets.join('.')}/#{prefix}") end
Checks whether the ip address belongs to a RFC 791 CLASS A network, no matter what the subnet mask is.
Example:
ip = IPAddress("10.0.0.1/24") ip.a? #=> true
# File lib/ipaddress_2/ipv4.rb, line 1026 def a? CLASSFUL.key(8) === bits end
Returns a new IPv4
object which is the result of advancing this IP address by a given value. In other words, this arithmetically adds IP addresses.
Will raise an error if the resulting address is in a different subnet, except validating is set to false.
Example:
ip = IPAddress::IPv4.new("172.16.10.1/24") ip.add(5).to_string #=> "172.16.10.6/24"
# File lib/ipaddress_2/ipv4.rb, line 936 def add(oth, validating=true) oth = oth.to_i if oth.kind_of? IPAddress::IPv4 # oth shall be integer new_obj = self.class.parse_u32(self.to_i + oth, prefix) if validating and self.network_u32 != new_obj.network_u32 raise RuntimeError, "Subnet (/#{@prefix}) is not large enough." end new_obj end
Returns the address portion of the IPv4
object as a string.
ip = IPAddress("172.16.100.4/22") ip.address #=> "172.16.100.4"
# File lib/ipaddress_2/ipv4.rb, line 105 def address @address end
Returns the network address of the n-th network succeeding this one.
Example:
ip = IPAddress::IPv4.new("172.16.10.0/24") ip.advance_network(24).to_string #=> "172.16.52.0/24"
# File lib/ipaddress_2/ipv4.rb, line 974 def advance_network(amount) IPAddress::IPv4.parse_u32(self.network.u32 + amount*self.size, @prefix) end
Allocates a new ip from the current subnet. Optional skip parameter can be used to skip addresses.
Will raise StopIteration exception when all addresses have been allocated
Example:
ip = IPAddress("10.0.0.0/24") ip.allocate #=> "10.0.0.1/24" ip.allocate #=> "10.0.0.2/24" ip.allocate(2) #=> "10.0.0.5/24"
Uses an internal @allocator which tracks the state of allocated addresses.
# File lib/ipaddress_2/ipv4.rb, line 1268 def allocate(skip=0) @allocator += 1 + skip next_ip = network_u32+@allocator if next_ip > broadcast_u32+1 raise StopIteration end self.class.parse_u32(network_u32+@allocator, @prefix) end
When serializing to JSON format, just use the string representation
ip = IPAddress("172.16.100.4/22") ip.as_json #=> "172.16.100.4/22"
# File lib/ipaddress_2/ipv4.rb, line 117 def as_json to_string end
Checks whether the ip address belongs to a RFC 791 CLASS B network, no matter what the subnet mask is.
Example:
ip = IPAddress("172.16.10.1/24") ip.b? #=> true
# File lib/ipaddress_2/ipv4.rb, line 1042 def b? CLASSFUL.key(16) === bits end
Returns the address portion of an IP in binary format, as a string containing a sequence of 0 and 1
ip = IPAddress("127.0.0.1") ip.bits #=> "01111111000000000000000000000001"
# File lib/ipaddress_2/ipv4.rb, line 328 def bits data.unpack("B*").first end
Returns the broadcast address for the given IP.
ip = IPAddress("172.16.10.64/24") ip.broadcast.to_s #=> "172.16.10.255"
# File lib/ipaddress_2/ipv4.rb, line 340 def broadcast 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
Returns the broadcast address in Unsigned 32bits format
ip = IPaddress("10.0.0.1/29") ip.broadcast_u32 #=> 167772167
# File lib/ipaddress_2/ipv4.rb, line 636 def broadcast_u32 network_u32 + size - 1 end
Checks whether the ip address belongs to a RFC 791 CLASS C network, no matter what the subnet mask is.
Example:
ip = IPAddress("192.168.1.1/30") ip.c? #=> true
# File lib/ipaddress_2/ipv4.rb, line 1058 def c? CLASSFUL.key(24) === bits end
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.data # Send binary data a.puts binary_data
# File lib/ipaddress_2/ipv4.rb, line 281 def data [@u32].pack("N") end
Iterates over all the IP addresses for the given network (or IP address).
The object yielded is a new IPv4
object created from the iteration.
ip = IPAddress("10.0.0.1/29") ip.each do |i| p i.address end #=> "10.0.0.0" #=> "10.0.0.1" #=> "10.0.0.2" #=> "10.0.0.3" #=> "10.0.0.4" #=> "10.0.0.5" #=> "10.0.0.6" #=> "10.0.0.7"
# File lib/ipaddress_2/ipv4.rb, line 499 def each (network_u32..broadcast_u32).each do |i| yield self.class.parse_u32(i, @prefix) end end
Iterates over all the hosts IP addresses for the given network (or IP address).
ip = IPAddress("10.0.0.1/29") ip.each_host do |i| p i.to_s end #=> "10.0.0.1" #=> "10.0.0.2" #=> "10.0.0.3" #=> "10.0.0.4" #=> "10.0.0.5" #=> "10.0.0.6"
# File lib/ipaddress_2/ipv4.rb, line 472 def each_host (network_u32+1..broadcast_u32-1).each do |i| yield self.class.parse_u32(i, @prefix) end end
Finds the adjacent block to a subnet.
Example:
ip = IPAddress("10.0.0.0/24") ip.find_adjacent_subnet #=> "10.0.1.0/24"
# File lib/ipaddress_2/ipv4.rb, line 1287 def find_adjacent_subnet return false if prefix == 0 current_subnet = to_string self.prefix = @prefix - 1 adjacent_subnet = (split.map{|i| i.to_string} - [current_subnet])[0] self.prefix = @prefix + 1 return adjacent_subnet end
Returns a new IPv4
object with the first host IP address in the range.
Example: given the 192.168.100.0/24 network, the first host IP address is 192.168.100.1.
ip = IPAddress("192.168.100.0/24") ip.first.to_s #=> "192.168.100.1"
The object IP doesn't need to be a network: the method automatically gets the network number from it
ip = IPAddress("192.168.100.50/24") ip.first.to_s #=> "192.168.100.1"
# File lib/ipaddress_2/ipv4.rb, line 413 def first 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
Returns the address portion in hex
ip = IPAddress("10.0.0.0") ip.to_h #=> 0a000000
# File lib/ipaddress_2/ipv4.rb, line 256 def hex(space=true) "%.4x%.4x" % [to_u32].pack("N").unpack("nn") end
Returns a new IPv4
object containing only the host part of this IP.
ip = IPAddress("172.16.10.64/24") ip.hostpart.to_s #=> "0.0.0.64"
# File lib/ipaddress_2/ipv4.rb, line 389 def hostpart self.class.parse_u32(hostpart_u32, 32) end
Returns this address' host part in unsigned 32bits format
ip = IPAddress("10.0.0.42/24") ip.host_u32 #=> 42
# File lib/ipaddress_2/ipv4.rb, line 624 def hostpart_u32 @u32 & ~@prefix.to_u32 end
Returns an array with the IP addresses of all the hosts in the network.
ip = IPAddress("10.0.0.1/29") ip.hosts.map {|i| i.address} #=> ["10.0.0.1", #=> "10.0.0.2", #=> "10.0.0.3", #=> "10.0.0.4", #=> "10.0.0.5", #=> "10.0.0.6"]
# File lib/ipaddress_2/ipv4.rb, line 600 def hosts to_a[1..-2] end
Checks whether a subnet includes the given IP address.
Accepts an IPAddress::IPv4
object or a string.
ip = IPAddress("192.168.10.100/24") addr = IPAddress("192.168.10.102/24") ip.include? addr #=> true ip.include? IPAddress("172.16.0.48/16") #=> false ip.include? "192.168.10.50" #=> true
# File lib/ipaddress_2/ipv4.rb, line 658 def include?(oth) unless oth.is_a? IPAddress::IPv4 oth = IPv4.new(oth) end @prefix <= oth.prefix and network_u32 == (oth.to_u32 & @prefix.to_u32) end
Checks whether a subnet includes all the given IPv4
objects or strings.
ip = IPAddress("192.168.10.100/24") addr1 = IPAddress("192.168.10.102/24") addr2 = IPAddress("192.168.10.103/24") ip.include_all?(addr1,addr2) #=> true ip.include_all?("192.168.10.102/24", "192.168.10.103/24") #=> true
# File lib/ipaddress_2/ipv4.rb, line 680 def include_all?(*others) others.all? {|oth| include?(oth)} end
Like its sibling method IPv4#first
, this method returns a new IPv4
object with the last host IP address in the range.
Example: given the 192.168.100.0/24 network, the last host IP address is 192.168.100.254
ip = IPAddress("192.168.100.0/24") ip.last.to_s #=> "192.168.100.254"
The object IP doesn't need to be a network: the method automatically gets the network number from it
ip = IPAddress("192.168.100.50/24") ip.last.to_s #=> "192.168.100.254"
# File lib/ipaddress_2/ipv4.rb, line 445 def last 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
Checks if an IPv4
address objects belongs to a link-local network RFC3927
Example:
ip = IPAddress "169.254.0.1" ip.link_local? #=> true
# File lib/ipaddress_2/ipv4.rb, line 738 def link_local? [self.class.new("169.254.0.0/16")].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
# File lib/ipaddress_2/ipv4.rb, line 724 def loopback? [self.class.new("127.0.0.0/8")].any? {|i| i.include? self} end
Checks if an IPv4
address objects belongs to a multicast network RFC3171
Example:
ip = IPAddress "224.0.0.0/4" ip.multicast? #=> true
# File lib/ipaddress_2/ipv4.rb, line 710 def multicast? [self.class.new("224.0.0.0/4")].any? {|i| i.include? self} end
Returns the prefix as a string in IP format
ip = IPAddress("172.16.100.4/22") ip.netmask #=> "255.255.252.0"
# File lib/ipaddress_2/ipv4.rb, line 205 def netmask @prefix.to_ip end
Like IPv4#prefix=
, this method allow you to change the prefix / netmask of an IP address object.
ip = IPAddress("172.16.100.4") puts ip #=> 172.16.100.4/16 ip.netmask = "255.255.252.0" puts ip #=> 172.16.100.4/22
# File lib/ipaddress_2/ipv4.rb, line 224 def netmask=(addr) @prefix = Prefix32.parse_netmask(addr) end
Returns a new IPv4
object with the network number for the given IP.
ip = IPAddress("172.16.10.64/24") ip.network.to_s #=> "172.16.10.0"
# File lib/ipaddress_2/ipv4.rb, line 377 def network self.class.parse_u32(network_u32, @prefix) end
Checks if the IP address is actually a network
ip = IPAddress("172.16.10.64/24") ip.network? #=> false ip = IPAddress("172.16.10.64/26") ip.network? #=> true
# File lib/ipaddress_2/ipv4.rb, line 364 def network? (@prefix < 32) && (@u32 | @prefix.to_u32 == @prefix.to_u32) end
Returns the network number in Unsigned 32bits format
ip = IPAddress("10.0.0.1/29") ip.network_u32 #=> 167772160
# File lib/ipaddress_2/ipv4.rb, line 612 def network_u32 @u32 & @prefix.to_u32 end
Returns the network address of the network succeeding this one.
Example:
ip = IPAddress::IPv4.new("172.16.10.0/24") ip.next_network.to_string #=> "172.16.11.0/24"
# File lib/ipaddress_2/ipv4.rb, line 986 def next_network advance_network 1 end
Returns the address as an array of decimal values
ip = IPAddress("172.16.100.4") ip.octets #=> [172, 16, 100, 4]
# File lib/ipaddress_2/ipv4.rb, line 167 def octets @octets end
Returns the predecessor to the IP address
Example:
ip = IPAddress("192.168.45.23/16") ip.pred.to_string => "192.168.45.22/16"
# File lib/ipaddress_2/ipv4.rb, line 530 def pred self.class.new("#{IPAddress.ntoa(to_u32.pred % 0x100000000)}/#{prefix}") end
Returns the prefix portion of the IPv4
object as a IPAddress::Prefix32
object
ip = IPAddress("172.16.100.4/22") ip.prefix #=> 22 ip.prefix.class #=> IPAddress::Prefix32
# File lib/ipaddress_2/ipv4.rb, line 133 def prefix @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 IPv4::parse_u32
or if the object was created using the classful mask.
ip = IPAddress("172.16.100.4") puts ip #=> 172.16.100.4/16 ip.prefix = 22 puts ip #=> 172.16.100.4/22
# File lib/ipaddress_2/ipv4.rb, line 155 def prefix=(num) @prefix = Prefix32.new(num) end
Returns the network address of the network preceeding this one.
Example:
ip = IPAddress::IPv4.new("172.16.10.0/24") ip.previous_network.to_string #=> "172.16.9.0/24"
# File lib/ipaddress_2/ipv4.rb, line 1010 def previous_network regress_network 1 end
Checks if an IPv4
address objects belongs to a private network RFC1918
Example:
ip = IPAddress "10.1.1.1/24" ip.private? #=> true
# File lib/ipaddress_2/ipv4.rb, line 694 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 network address of the n-th network preceeding this one.
Example:
ip = IPAddress::IPv4.new("172.16.10.0/24") ip.regress_network(5).to_string #=> "172.16.5.0/24"
# File lib/ipaddress_2/ipv4.rb, line 998 def regress_network(amount) advance_network(-amount) end
Returns the IP address in in-addr.arpa format for DNS lookups
ip = IPAddress("172.16.100.50/24") ip.reverse #=> "50.100.16.172.in-addr.arpa"
# File lib/ipaddress_2/ipv4.rb, line 751 def reverse @octets.reverse.join(".") + ".in-addr.arpa" end
Returns the number of IP addresses included in the network. It also counts the network address and the broadcast address.
ip = IPAddress("10.0.0.1/29") ip.size #=> 8
# File lib/ipaddress_2/ipv4.rb, line 582 def size 2 ** @prefix.host_prefix end
Splits a network into different subnets
If the IP Address is a network, it can be divided into multiple networks. If self
is not a network, this method will calculate the network from the IP and then subnet it.
If subnets
is an power of two number, the resulting networks will be divided evenly from the supernet.
network = IPAddress("172.16.10.0/24") 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"]
If num
is any other number, the supernet will be divided into some networks with a even number of hosts and other networks with the remaining addresses.
network = IPAddress("172.16.10.0/24") network / 3 # implies map{|i| i.to_string} #=> ["172.16.10.0/26", #=> "172.16.10.64/26", #=> "172.16.10.128/25"]
Returns an array of IPv4
objects
# File lib/ipaddress_2/ipv4.rb, line 808 def split(subnets=2) unless (1..(2**@prefix.host_prefix)).include? subnets raise ArgumentError, "Value #{subnets} out of range" end networks = subnet(newprefix(subnets)) until networks.size == subnets networks = sum_first_found(networks) end return networks end
This method implements the subnetting function similar to the one described in RFC3531.
By specifying a new prefix, the method calculates the network number for the given IPv4
object and calculates the subnets associated to the new prefix.
For example, given the following network:
ip = IPAddress "172.16.10.0/24"
we can calculate the subnets with a /26 prefix
ip.subnet(26).map{&:to_string) #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26", "172.16.10.192/26"]
The resulting number of subnets will of course always be a power of two.
# File lib/ipaddress_2/ipv4.rb, line 872 def subnet(subprefix) unless ((@prefix.to_i)..32).include? subprefix raise ArgumentError, "New prefix must be between #@prefix and 32" end Array.new(2**(subprefix-@prefix.to_i)) do |i| self.class.parse_u32(network_u32+(i*(2**(32-subprefix))), subprefix) end end
Returns a new IPv4
object which is the result of decreasing this IP address by a given value. In other words, this arithmetically subtracts IP addresses.
Will raise an error if the resulting address is in a different subnet, except validating is set to false.
Example:
ip = IPAddress::IPv4.new("172.16.10.10/24") ip.subtract(5).to_string #=> "172.16.10.5/24"
# File lib/ipaddress_2/ipv4.rb, line 961 def subtract(oth, validating=true) oth = oth.to_i if oth.kind_of? IPAddress::IPv4 # oth shall be integer add(-oth, validating) end
Returns the successor to the IP address
Example:
ip = IPAddress("192.168.45.23/16") ip.succ.to_string => "192.168.45.24/16"
# File lib/ipaddress_2/ipv4.rb, line 515 def succ self.class.new("#{IPAddress.ntoa(to_u32.succ % 0x100000000)}/#{prefix}") end
Returns a new IPv4
object from the supernetting of the instance network.
Supernetting is similar to subnetting, except that you getting as a result a network with a smaller prefix (bigger host space). For example, given the network
ip = IPAddress("172.16.10.0/24")
you can supernet it with a new /23 prefix
ip.supernet(23).to_string #=> "172.16.10.0/23"
However if you supernet it with a /22 prefix, the network address will change:
ip.supernet(22).to_string #=> "172.16.8.0/22"
If new_prefix
is less than 1, returns 0.0.0.0/0
# File lib/ipaddress_2/ipv4.rb, line 844 def supernet(new_prefix) raise ArgumentError, "New prefix must be smaller than existing prefix" if new_prefix >= @prefix.to_i return self.class.new("0.0.0.0/0") if new_prefix < 1 return self.class.new(@address+"/#{new_prefix}").network end
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"]
# File lib/ipaddress_2/ipv4.rb, line 769 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
Returns a string with the address portion of the IPv4
object
ip = IPAddress("172.16.100.4/22") ip.to_s #=> "172.16.100.4"
# File lib/ipaddress_2/ipv4.rb, line 180 def to_s @address end
Returns a string with the IP address in canonical form.
ip = IPAddress("172.16.100.4/22") ip.to_string #=> "172.16.100.4/22"
# File lib/ipaddress_2/ipv4.rb, line 193 def to_string "#@address/#@prefix" end
Returns the address portion in unsigned 32 bits integer format.
This method is identical to the C function inet_pton to create a 32 bits address family structure.
ip = IPAddress("10.0.0.0/8") ip.to_i #=> 167772160
# File lib/ipaddress_2/ipv4.rb, line 241 def u32 @u32 end
Private Instance Methods
# File lib/ipaddress_2/ipv4.rb, line 1318 def aggregate(ip1,ip2) return [ip1] if ip1.include? ip2 snet = ip1.supernet(ip1.prefix-1) if snet.include_all?(ip1, ip2) && ((ip1.size + ip2.size) == snet.size) return [snet] else return [ip1, ip2] end end
Tweaked to remove the upto(32)
# File lib/ipaddress_2/ipv4.rb, line 1302 def newprefix(num) return @prefix + (Math::log2(num).ceil ) end
# File lib/ipaddress_2/ipv4.rb, line 1306 def sum_first_found(arr) dup = arr.dup.reverse dup.each_with_index do |obj,i| a = [self.class.summarize(obj,dup[i+1])].flatten if a.size == 1 dup[i..i+1] = a return dup.reverse end end return dup.reverse end