Class: IPAddress

Inherits:
Object
  • Object
show all
Extended by:
Conversions
Includes:
Comparable, Enumerable, Conversions, Nuggets::LazyAttr
Defined in:
lib/ipaddress.rb,
lib/ipaddress/ipv4.rb,
lib/ipaddress/ipv6.rb,
lib/ipaddress/prefix.rb,
lib/ipaddress/conversions.rb

Direct Known Subclasses

IPv4, IPv6

Defined Under Namespace

Modules: Conversions Classes: IPv4, IPv6, Prefix, Prefix128, Prefix32

Constant Summary collapse

VERSION =
'0.8.0.2'
NAME =
'IPAddress'
GEM =
'ipaddress'
AUTHORS =
['Marco Ceresa <[email protected]>']
MAX_PREFIX =
Prefix128::MAX

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Conversions

addr2ary, addr2bits, ary2addr, ary2data, ary2int, bits2addr, data2ary, data2bits, data2int, int2addr, int2ary, int2data

Class Method Details

.parse(str) ⇒ Object

Parse the argument string to create a new IPv4, IPv6 or Mapped IP object

ip  = IPAddress.parse "172.16.10.1/24"
ip6 = IPAddress.parse "2001:db8::8:800:200c:417a/64"
ip_mapped = IPAddress.parse "::ffff:172.16.10.1/128"

All the object created will be instances of the correct class:

ip.class
  #=> IPAddress::IPv4
ip6.class
  #=> IPAddress::IPv6
ip_mapped.class
  #=> IPAddress::IPv6::Mapped


53
54
55
56
57
58
59
60
# File 'lib/ipaddress.rb', line 53

def parse(str)
  case str
    when /:.+\./ then IPv6::Mapped.new(str)
    when /\./    then IPv4.new(str)
    when /:/     then IPv6.new(str)
    else raise ArgumentError, "Unknown IP Address #{str.inspect}"
  end
end

.parse_i(version, i, prefix = nil) ⇒ Object



62
63
64
65
66
67
68
69
70
71
# File 'lib/ipaddress.rb', line 62

def parse_i(version, i, prefix = nil)
  case version
    when 4
      IPv4.parse_i(i, prefix || IPv4::MAX_PREFIX)
    when 6
      IPv6.parse_i(i, prefix || IPv6::MAX_PREFIX).instance_eval { mapped || self }
    else
      raise ArgumentError, "IP protocol version not supported: #{version.inspect}"
  end
end

.subtract(a, *b) ⇒ Object



211
212
213
# File 'lib/ipaddress.rb', line 211

def subtract(a, *b)
  subtract!(a.is_a?(Array) ? a.dup : [a], *b)
end

.subtract!(a, *b) ⇒ Object

Raises:

  • (TypeError)


215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/ipaddress.rb', line 215

def subtract!(a, *b)
  raise TypeError, "Array expected, got #{a.class}" unless a.is_a?(Array)

  a.uniq!; b.flatten!; b.uniq!
  c, d = [], b.map { |i| i.boundaries }

  loop {
    a.delete_if { |i|
      b.any? { |j| j.include?(i) } || if i.overlap_i?(*d)
        (n = i.prefix.next) ? c.concat(i.subnet(n)) : c << i
      end
    }

    c.empty? ? break : a.concat(c); c.clear
  }

  a.replace(summarize(*a)).sort!
end

.summarize(*nets) ⇒ Object

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).map { |i| i.to_string }
  #=> ["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).map { |i| i.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"]


192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/ipaddress.rb', line 192

def summarize(*nets)
  nets.sort!.map! { |i| i.network }
  return nets unless nets.size > 1

  loop {
    i, f = -1, false

    while i < nets.size - 2
      i1, i2 = nets[i += 1, 2]

      if s = i1.proper_supernet(i2)
        nets[i, 2], f = s, true
      end
    end

    return nets unless f
  }
end

.valid?(addr) ⇒ Boolean

Checks if the given string is a valid IP address, either IPv4 or IPv6

Example:

IPAddress::valid? "2002::1"
  #=> true

IPAddress::valid? "10.0.0.256"
  #=> false

Returns:

  • (Boolean)


85
86
87
# File 'lib/ipaddress.rb', line 85

def valid?(addr)
  valid_ipv4?(addr) || valid_ipv6?(addr)
end

.valid_ipv4?(addr) ⇒ Boolean

Checks if the given string is a valid IPv4 address

Example:

IPAddress::valid_ipv4? "2002::1"
  #=> false

IPAddress::valid_ipv4? "172.16.10.1"
  #=> true

Returns:

  • (Boolean)


100
101
102
# File 'lib/ipaddress.rb', line 100

def valid_ipv4?(addr)
  IPv4::RE === addr
end

.valid_ipv4_netmask?(addr) ⇒ Boolean

Checks if the argument is a valid IPv4 netmask expressed in dotted decimal format.

IPAddress.valid_ipv4_netmask? "255.255.0.0"
  #=> true

Returns:

  • (Boolean)


111
112
113
# File 'lib/ipaddress.rb', line 111

def valid_ipv4_netmask?(addr)
  valid_ipv4?(addr) && addr2bits(addr) !~ /01/
end

.valid_ipv6?(addr) ⇒ Boolean

Checks if the given string is a valid IPv6 address

Example:

IPAddress::valid_ipv6? "2002::1"
  #=> true

IPAddress::valid_ipv6? "2002::1::2"
  #=> false

Returns:

  • (Boolean)


126
127
128
# File 'lib/ipaddress.rb', line 126

def valid_ipv6?(addr)
  IPv6::RE === addr
end

Instance Method Details

#<=>(other) ⇒ Object

Spaceship operator to compare IPv4/IPv6 objects

Comparing IPv4/IPv6 addresses is useful to ordinate them into lists that match our intuitive perception of ordered IP addresses.

The first comparison criteria is the u32/u128 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; 2001:db8:1::1 will be considered to be less than 2001:db8:2::1, because, in a ordered list, we expect 2001:db8:1::1 to come before 2001:db8:2::1.

The second criteria, in case two IPv4/IPv6 objects have identical addresses, is the prefix. A 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; 2001:db8:1::1/64 before 2001:db8:1::1/65.

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"]

ip1 = IPAddress("2001:db8:1::1/64")
ip2 = IPAddress("2001:db8:2::1/64")
ip3 = IPAddress("2001:db8:1::1/65")

ip1 < ip2
  #=> true
ip1 < ip3
  #=> false

[ip1,ip2,ip3].sort.map { |i| i.to_string }
  #=> ["2001:db8:1::1/64","2001:db8:1::1/65","2001:db8:2::1/64"]


928
929
930
# File 'lib/ipaddress.rb', line 928

def <=>(other)
  [to_i, prefix] <=> [other.to_i, other.prefix]
end

#at(index) ⇒ Object



796
797
798
799
800
801
802
803
# File 'lib/ipaddress.rb', line 796

def at(index)
  s = span

  index += index < 0 ? s.last + 1 : s.first
  each(index) { |i| return i } if s.include?(index)

  nil
end

#bitsObject

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"

ip6 = IPAddress("2001:db8::8:800:200c:417a")

ip6.bits
  #=> "0010000000000001000011011011100000 [...] "


311
312
313
# File 'lib/ipaddress.rb', line 311

def bits
  lazy_attr(:bits) { data2bits(data) }
end

#boundariesObject



722
723
724
# File 'lib/ipaddress.rb', line 722

def boundaries
  lazy_attr(:boundaries) { [(s = span).first, s.last] }
end

#broadcastObject

Returns the broadcast address for the given IP.

ip = IPAddress("172.16.10.64/24")

ip.broadcast.to_s
  #=> "172.16.10.255"


385
386
387
# File 'lib/ipaddress.rb', line 385

def broadcast
  lazy_attr(:broadcast, false) { at(-1) }
end

#broadcast_iObject

Returns the broadcast address in Unsigned 32bits/128bits format

ip = IPaddress("10.0.0.1/29")

ip.broadcast_u32
  #=> 167772167

ip6 = IPAddress("2001:db8::8:800:200c:417a/64")

ip6.broadcast_u128
  #=> 42540766411282592875350729025363378175

Please note that there is no Broadcast concept in IPv6 addresses as in IPv4 addresses, and this method is just a helper to other functions.



406
407
408
# File 'lib/ipaddress.rb', line 406

def broadcast_i
  lazy_attr(:broadcast_i) { network_i + size - 1 }
end

#distance(other) ⇒ Object

Returns the difference between two IP addresses in unsigned int 32/128 bits format

Example:

ip1 = IPAddress("172.16.10.0/24")
ip2 = IPAddress("172.16.11.0/24")

ip1.distance(ip2)
  #=> 256


651
652
653
# File 'lib/ipaddress.rb', line 651

def distance(other)
  (to_i - other.to_i).abs
end

#each(*args) ⇒ Object

Iterates over all the IP addresses for the given network (or IP address).

The object yielded is a new IPv4/IPv6 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"

ip6 = IPAddress("2001:db8::4/125")

ip6.each do |i|
  p i.compressed
end
  #=> "2001:db8::"
  #=> "2001:db8::1"
  #=> "2001:db8::2"
  #=> "2001:db8::3"
  #=> "2001:db8::4"
  #=> "2001:db8::5"
  #=> "2001:db8::6"
  #=> "2001:db8::7"

WARNING: if the host portion is very large, this method can be very slow and possibly hang your system!



770
771
772
773
# File 'lib/ipaddress.rb', line 770

def each(*args)
  f = prefix
  each_i(*args) { |i| yield self.class.parse_i(i, f) }
end

#each_hostObject

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"


791
792
793
794
# File 'lib/ipaddress.rb', line 791

def each_host
  f, l = boundaries
  each(f + 1, l - 1) { |i| yield i }
end

#each_i(first = nil, last = nil) ⇒ Object



726
727
728
729
730
# File 'lib/ipaddress.rb', line 726

def each_i(first = nil, last = nil)
  f, l = boundaries
  [first || f, f].max.upto([last || l, l].min) { |i| yield i }
  self
end

#exact_supernet(*other) ⇒ Object



603
604
605
606
# File 'lib/ipaddress.rb', line 603

def exact_supernet(*other)
  s = supernet(prefix - 1)
  s if s.include_exactly?(self, *other)
end

#firstObject

Returns a new IPv4/IPv6 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"


825
826
827
# File 'lib/ipaddress.rb', line 825

def first
  lazy_attr(:first, false) { at(1) }
end

#hashObject



932
933
934
# File 'lib/ipaddress.rb', line 932

def hash
  lazy_attr(:hash) { [to_i, prefix.hash].hash }
end

#hostsObject

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"]


872
873
874
# File 'lib/ipaddress.rb', line 872

def hosts
  lazy_attr(:hosts) { hosts = []; each_host { |i| hosts << i }; hosts }
end

#include?(other) ⇒ Boolean

Checks whether a subnet includes the given IP address.

Accepts an IPAddress::IPv4 object.

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

ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
addr = IPAddress("2001:db8::8:800:200c:1/128")

ip6.include?(addr)
  #=> true

ip6.include?(IPAddress("2001:db8:1::8:800:200c:417a/76"))
  #=> false

Returns:

  • (Boolean)


484
485
486
# File 'lib/ipaddress.rb', line 484

def include?(other)
  prefix <= other.prefix && network_i == other.to_i & prefix.to_i
end

#include_all?(*other) ⇒ Boolean

Checks whether a subnet includes all the given IP objects.

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

Returns:

  • (Boolean)


500
501
502
# File 'lib/ipaddress.rb', line 500

def include_all?(*other)
  other.all? { |i| include?(i) }
end

#include_exactly?(*other) ⇒ Boolean

Returns:

  • (Boolean)


504
505
506
507
508
# File 'lib/ipaddress.rb', line 504

def include_exactly?(*other)
  s = size
  other.each { |i| s -= i.size }
  s == 0 && include_all?(*other)
end

#inspectObject



293
294
295
# File 'lib/ipaddress.rb', line 293

def inspect
  "#{self.class}@#{to_string}"
end

#ipv4?Boolean

True if the object is an IPv4 address

ip = IPAddress("192.168.10.100/24")

ip.ipv4?
  #-> true

Returns:

  • (Boolean)


259
260
261
# File 'lib/ipaddress.rb', line 259

def ipv4?
  is_a?(IPv4)
end

#ipv6?Boolean

True if the object is an IPv6 address

ip = IPAddress("192.168.10.100/24")

ip.ipv6?
  #-> false

Returns:

  • (Boolean)


271
272
273
# File 'lib/ipaddress.rb', line 271

def ipv6?
  is_a?(IPv6)
end

#lastObject

Like its sibling method IPv4#first/IPv6#first, this method returns a new IPv4/IPv6 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"


850
851
852
# File 'lib/ipaddress.rb', line 850

def last
  lazy_attr(:last, false) { at(-2) }
end

#mappedObject



876
877
878
# File 'lib/ipaddress.rb', line 876

def mapped
  IPv6::Mapped.new(to_string) if ipv4? || mapped?
end

#networkObject

Returns a new IPv4/IPv6 object with the network number for the given IP.

ip = IPAddress("172.16.10.64/24")

ip.network.to_s
  #=> "172.16.10.0"

ip6 = IPAddress("2001:db8:1:1:1:1:1:1/32")

ip6.network.to_string
  #=> "2001:db8::/32"


356
357
358
# File 'lib/ipaddress.rb', line 356

def network
  lazy_attr(:network, false) { network? ? self : at(0) }
end

#network?Boolean

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

ip6 = IPAddress("2001:db8::8:800:200c:417a/64")

ip6.network?
  #=> false

ip6 = IPAddress("2001:db8:8:800::/64")

ip6.network?
  #=> true

Returns:

  • (Boolean)


338
339
340
# File 'lib/ipaddress.rb', line 338

def network?
  lazy_attr(:network_p) { i = prefix.to_i; to_i | i == i }
end

#network_iObject

Returns the network number in Unsigned 32bits/128bits format

ip = IPAddress("10.0.0.1/29")

ip.network_u32
  #=> 167772160

ip6 = IPAddress("2001:db8::8:800:200c:417a/64")

ip6.network_u128
  #=> 42540766411282592856903984951653826560


373
374
375
# File 'lib/ipaddress.rb', line 373

def network_i
  lazy_attr(:network_i) { to_i & prefix.to_i }
end

#new_prefix(prefix) ⇒ Object

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/IPv6.parse_u128 or if the object was created using the classful mask/ the default prefix of 128 bits.

ip = IPAddress("172.16.100.4")

ip.to_string
  #=> 172.16.100.4/16

ip2 = ip.new_prefix(22)

ip2.to_string
  #=> 172.16.100.4/22

ip6 = IPAddress("2001:db8::8:800:200c:417a")

ip6.to_string
  #=> "2001:db8::8:800:200c:417a/128"

ip2 = ip6.new_prefix(64)

ip2.to_string
  #=> "2001:db8::8:800:200c:417a/64"


457
458
459
# File 'lib/ipaddress.rb', line 457

def new_prefix(prefix)
  self.class.parse_i(to_i, prefix)
end

#overlap?(*other) ⇒ Boolean

Returns:

  • (Boolean)


510
511
512
# File 'lib/ipaddress.rb', line 510

def overlap?(*other)
  overlap_i?(*other.map! { |i| i.boundaries })
end

#overlap_i?(*other) ⇒ Boolean

Returns:

  • (Boolean)


514
515
516
517
# File 'lib/ipaddress.rb', line 514

def overlap_i?(*other)
  f, l = boundaries
  !other.all? { |i, j| l < i || f > j }
end

#proper_supernet(*other) ⇒ Object



608
609
610
# File 'lib/ipaddress.rb', line 608

def proper_supernet(*other)
  include_all?(*other) ? self : exact_supernet(*other)
end

#range(other) ⇒ Object

Raises:

  • (TypeError)


689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
# File 'lib/ipaddress.rb', line 689

def range(other)
  raise TypeError, 'must be same version' if other.version != version

  return [self] unless other > self

  nets, n, l, m = [], to_i, other.to_i, self.class::MAX_PREFIX

  until n > l
    i = self.class.parse_i(n, m)
    f = i.bits.rindex('1') || -1

    while s = i.supernet(f += 1, true)
      unless s.broadcast_i > l
        i = s
        break
      end
    end

    nets << i
    n = i.broadcast_i + 1
  end

  nets
end

#sizeObject

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

ip6 = IPAddress("2001:db8::8:800:200c:417a/64")

ip6.size
  #=> 18446744073709551616


425
426
427
# File 'lib/ipaddress.rb', line 425

def size
  lazy_attr(:size) { 2 ** prefix.host_prefix }
end

#spanObject



714
715
716
# File 'lib/ipaddress.rb', line 714

def span
  lazy_attr(:span) { network_i..broadcast_i }
end

#span_iObject



718
719
720
# File 'lib/ipaddress.rb', line 718

def span_i
  lazy_attr(:span_i) { span.to_a }
end

#split(subnets = 2) ⇒ Object Also known as: /

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).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).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



551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
# File 'lib/ipaddress.rb', line 551

def split(subnets = 2)
  unless (1..size).include?(subnets)
    raise ArgumentError, "Value #{subnets} out of range"
  end

  networks = subnet(prefix + Math.log2(subnets).ceil)

  until networks.size == subnets
    networks.reverse!.each_with_index { |n, i|
      if s = n.proper_supernet(networks[i + 1])
        networks[i, 2] = s
        break
      end
    }

    networks.reverse!
  end

  networks
end

#subnet(num) ⇒ Object

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 { |i| i.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.



634
635
636
637
# File 'lib/ipaddress.rb', line 634

def subnet(num)
  n, m, s = network_i, *prefix.subprefix(num)
  Array.new(s) { |i| self.class.parse_i(n + (i * m), num) }
end

#subtract(*other) ⇒ Object Also known as: -



655
656
657
# File 'lib/ipaddress.rb', line 655

def subtract(*other)
  self.class.subtract(self, *other)
end

#succObject



854
855
856
# File 'lib/ipaddress.rb', line 854

def succ
  lazy_attr(:succ, false) { self.class.parse_i(to_i + 1, prefix) }
end

#summarize(other) ⇒ Object Also known as: +

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"]


683
684
685
# File 'lib/ipaddress.rb', line 683

def summarize(other)
  self.class.summarize(self, other)
end

#supernet(num, relax = false) ⇒ Object

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



598
599
600
601
# File 'lib/ipaddress.rb', line 598

def supernet(num, relax = false)
  superprefix = prefix.superprefix(num, relax)
  new_prefix(superprefix).network if superprefix
end

#to_stringObject

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"

ip6 = IPAddress("2001:0db8:0000:0000:0008:0800:200c:417a/64")

ip6.to_string
  #=> "2001:db8::8:800:200c:417a/64"


289
290
291
# File 'lib/ipaddress.rb', line 289

def to_string
  "#{to_s}/#{prefix}"
end