better_ipaddr 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.travis.yml +12 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +675 -0
- data/README.md +118 -0
- data/Rakefile +10 -0
- data/better_ipaddr.gemspec +25 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/better_ipaddr.rb +2 -0
- data/lib/better_ipaddr/classes.rb +72 -0
- data/lib/better_ipaddr/core_extension.rb +11 -0
- data/lib/better_ipaddr/methods.rb +332 -0
- data/lib/better_ipaddr/space.rb +142 -0
- data/lib/better_ipaddr/version.rb +3 -0
- metadata +103 -0
data/README.md
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# BetterIpaddr
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/better_ipaddr.svg)](https://rubygems.org/gems/better_ipaddr)
|
4
|
+
[![Build Status](https://travis-ci.org/bjmllr/better_ipaddr.svg)](https://travis-ci.org/bjmllr/better_ipaddr)
|
5
|
+
|
6
|
+
The `IPAddr` class that network engineers always wanted.
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
require "better_ipaddr"
|
10
|
+
addr = IPAddr::V4[some_source] # shortcut for .new, because your test suite
|
11
|
+
# contains a zillion IP addresses and you're
|
12
|
+
# tired of typing Socket::AF_INET
|
13
|
+
addr.host? # is it a host address?
|
14
|
+
addr.network? # or a network address?
|
15
|
+
addr.cidr # what is the CIDR representation?
|
16
|
+
addr.grow(1) # what is the next larger enclosing network?
|
17
|
+
addr + 1 # what address comes after this one?
|
18
|
+
addr.size # how many host addresses fit in this network?
|
19
|
+
addr.mask_addr # what's the netmask (as an integer)?
|
20
|
+
addr.prefix_length # what's the prefix length (as an integer)?
|
21
|
+
addr == other_addr # are these the same network?
|
22
|
+
addr.cover?(other_addr) # does this network contain that one?
|
23
|
+
addr.overlap?(other_addr) # do these networks share any hosts?
|
24
|
+
addr.each { ... } # do something with each host in this network
|
25
|
+
addr.first # what's the network address?
|
26
|
+
addr.last # what's the broadcast address?
|
27
|
+
addr.wildcard # what's the wildcard mask for this network?
|
28
|
+
addr.summarize_with(other) # can these networks be summarized?
|
29
|
+
```
|
30
|
+
|
31
|
+
Bonus: comes with an IP space finder.
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
require "better_ipaddr/space"
|
35
|
+
space = BetterIpaddr::Space.new(some_array_of_ipaddrs,
|
36
|
+
space: IPAddr::V4["10.0.0.0/8"])
|
37
|
+
|
38
|
+
space.find_by_minimum_prefix_length(26) # => a subnet with at least 64 addresses
|
39
|
+
space.find_by_minimum_size(256) # => a /24 or larger
|
40
|
+
space.gaps # => all your free subnets
|
41
|
+
```
|
42
|
+
|
43
|
+
Coming soon: MAC addresses and their various notations.
|
44
|
+
|
45
|
+
## Installation
|
46
|
+
|
47
|
+
Ruby 2.0 or later is required. There are no other dependencies.
|
48
|
+
|
49
|
+
Add this line to your application's Gemfile:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
gem 'better_ipaddr'
|
53
|
+
```
|
54
|
+
|
55
|
+
And then execute:
|
56
|
+
|
57
|
+
$ bundle
|
58
|
+
|
59
|
+
Or install it yourself as:
|
60
|
+
|
61
|
+
$ gem install better_ipaddr
|
62
|
+
|
63
|
+
## Usage
|
64
|
+
|
65
|
+
There are multiple ways to load this gem.
|
66
|
+
|
67
|
+
The quick and dirty way is to `require
|
68
|
+
"better_ipaddr/core_extension"`, which adds all the additional methods
|
69
|
+
directly to `IPAddr`. This is "monkey patching", so there may be
|
70
|
+
unintended consequences. If you use this approach in another library
|
71
|
+
or framework, be very clear about it with your users.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
require "better_ipaddr/core_extension"
|
75
|
+
addr = IPAddr["1.0.0.1"]
|
76
|
+
class_c = addr << 8 # => IPAddr::V4["1.0.0.0/24"]
|
77
|
+
IPAddr.new("1.0.0.0/24").summarize_with(IPAddr["1.0.1.0/24"]) # => IPAddr::V4["1.0.0.0/23"]
|
78
|
+
```
|
79
|
+
|
80
|
+
The recommended way is to `require "better_ipaddr"` and use
|
81
|
+
the `IPAddr` subclasses explicitly.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
require "better_ipaddr"
|
85
|
+
addr = IPAddr::V4["1.0.0.1"]
|
86
|
+
class_c = addr << 8 # => IPAddr::V4["1.0.0.0/24"]
|
87
|
+
```
|
88
|
+
|
89
|
+
Another way is to `require "better_ipaddr/methods"` and mix
|
90
|
+
`BetterIpaddr::InstanceMethods` into your own class which implements
|
91
|
+
the rest of the `IPAddr` API, or into individual `IPAddr` objects.
|
92
|
+
|
93
|
+
`BetterIpaddr::Space`, a collection class for dealing with sets of network addresses, is also available but not loaded by default.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
require "better_ipaddr/space"
|
97
|
+
space = BetterIpaddr::Space.new([IPAddr::V4["10.0.0.0/24"],
|
98
|
+
IPAddr::V4["10.0.2.0/24"]])
|
99
|
+
space.gaps # => BetterIpaddr::Space.new([IPAddr::V4["10.0.1.0/24"]])
|
100
|
+
```
|
101
|
+
|
102
|
+
The available methods are described in the [API docs](http://www.rubydoc.info/gems/better_ipaddr).
|
103
|
+
|
104
|
+
## Development
|
105
|
+
|
106
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
107
|
+
|
108
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
109
|
+
|
110
|
+
## Contributing
|
111
|
+
|
112
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/bjmllr/better_ipaddr. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
113
|
+
|
114
|
+
## Copyright and License
|
115
|
+
|
116
|
+
Copyright (C) 2016 Ben Miller
|
117
|
+
|
118
|
+
The gem is available as free software under the terms of the [GNU General Public License, Version 3](http://www.gnu.org/licenses/gpl-3.0.html).
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'better_ipaddr/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "better_ipaddr"
|
8
|
+
spec.version = BetterIpaddr::VERSION
|
9
|
+
spec.authors = ["Ben Miller"]
|
10
|
+
spec.email = ["bmiller@rackspace.com"]
|
11
|
+
|
12
|
+
spec.summary = "IPAddr enhancements for network management."
|
13
|
+
spec.homepage = "https://github.com/bjmllr/better_ipaddr"
|
14
|
+
spec.license = "GPL-3.0"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
.reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r(^exe/)) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.0"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
25
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "better_ipaddr"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require "better_ipaddr/methods"
|
2
|
+
|
3
|
+
class IPAddr
|
4
|
+
class Base < IPAddr
|
5
|
+
include BetterIpaddr::Constants
|
6
|
+
include BetterIpaddr::InstanceMethods
|
7
|
+
include Comparable
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
def inherited(cls)
|
11
|
+
cls.extend BetterIpaddr::ClassMethods
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.[](address, mask = nil, family: self::FAMILY)
|
15
|
+
if mask
|
16
|
+
new(address, family).mask(new(mask, family).to_s)
|
17
|
+
else
|
18
|
+
new(address, family)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return the given address as an instance of a class specific to
|
23
|
+
# its address family.
|
24
|
+
#
|
25
|
+
# @param address [IPAddr] the address to convert
|
26
|
+
# @return [IPAddr::V4, IPAddr::V6, IPAddr::EUI48]
|
27
|
+
def self.specialize(address)
|
28
|
+
return address unless address.class == IPAddr
|
29
|
+
case address.family
|
30
|
+
when Family::IPV4
|
31
|
+
IPAddr::V4[address.to_i, address.instance_variable_get(:@mask_addr)]
|
32
|
+
when Family::IPV6
|
33
|
+
IPAddr::V6[address.to_i, address.instance_variable_get(:@mask_addr)]
|
34
|
+
when Family::EUI48
|
35
|
+
IPAddr::MAC[address.to_i, address.instance_variable_get(:@mask_addr)]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.specialize_constants(family)
|
40
|
+
const_set(:FAMILY, family)
|
41
|
+
const_set(:BIT_LENGTH, FAMILY_TO_BIT_LENGTH.fetch(self::FAMILY))
|
42
|
+
const_set(:NETMASK_TO_PREFIX_LENGTH,
|
43
|
+
NETMASK_TO_PREFIX_LENGTH.fetch(self::FAMILY))
|
44
|
+
const_set(:PREFIX_LENGTH_TO_NETMASK,
|
45
|
+
PREFIX_LENGTH_TO_NETMASK.fetch(self::FAMILY))
|
46
|
+
end
|
47
|
+
|
48
|
+
def address_family_bit_length
|
49
|
+
self.class::BIT_LENGTH
|
50
|
+
end
|
51
|
+
|
52
|
+
def network?
|
53
|
+
prefix_length < self.class::BIT_LENGTH
|
54
|
+
end
|
55
|
+
|
56
|
+
def prefix_length
|
57
|
+
self.class::NETMASK_TO_PREFIX_LENGTH[mask_addr]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class V4 < Base
|
62
|
+
specialize_constants Family::IPV4
|
63
|
+
end
|
64
|
+
|
65
|
+
class V6 < Base
|
66
|
+
specialize_constants Family::IPV6
|
67
|
+
end
|
68
|
+
|
69
|
+
class MAC < Base
|
70
|
+
specialize_constants Family::EUI48
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "ipaddr"
|
2
|
+
require "better_ipaddr/methods"
|
3
|
+
require "better_ipaddr/classes"
|
4
|
+
|
5
|
+
class IPAddr
|
6
|
+
include BetterIpaddr::Constants
|
7
|
+
extend BetterIpaddr::ClassMethods
|
8
|
+
prepend BetterIpaddr::InstanceMethods
|
9
|
+
include Comparable
|
10
|
+
include Enumerable
|
11
|
+
end
|
@@ -0,0 +1,332 @@
|
|
1
|
+
require "ipaddr"
|
2
|
+
require "socket"
|
3
|
+
|
4
|
+
module BetterIpaddr
|
5
|
+
module Constants
|
6
|
+
# Integer codes representing supported address clases.
|
7
|
+
# Reuse values from Socket namespace where possible.
|
8
|
+
module Family
|
9
|
+
IPV4 = Socket::AF_INET
|
10
|
+
IPV6 = Socket::AF_INET6
|
11
|
+
EUI48 = 48
|
12
|
+
EUI64 = 64
|
13
|
+
end
|
14
|
+
|
15
|
+
# Map well known address family names to constants.
|
16
|
+
SYMBOL_TO_FAMILY = {
|
17
|
+
ipv4: Family::IPV4,
|
18
|
+
ipv6: Family::IPV6,
|
19
|
+
eui48: Family::EUI48,
|
20
|
+
eui64: Family::EUI64,
|
21
|
+
mac: Family::EUI48
|
22
|
+
}
|
23
|
+
|
24
|
+
# Map each address family to the size of its address space, in bits.
|
25
|
+
FAMILY_TO_BIT_LENGTH = {
|
26
|
+
Family::IPV4 => 32,
|
27
|
+
Family::IPV6 => 128,
|
28
|
+
Family::EUI48 => 48,
|
29
|
+
Family::EUI64 => 64
|
30
|
+
}
|
31
|
+
|
32
|
+
# Map all possible prefix lengths to the corresponding netmasks.
|
33
|
+
PREFIX_LENGTH_TO_NETMASK = {}
|
34
|
+
FAMILY_TO_BIT_LENGTH.each_pair do |family, size|
|
35
|
+
netmasks = []
|
36
|
+
(0..size).each do |prefix_length|
|
37
|
+
netmasks[prefix_length] = 2**size - 2**(size - prefix_length)
|
38
|
+
end
|
39
|
+
PREFIX_LENGTH_TO_NETMASK[family] = netmasks
|
40
|
+
end
|
41
|
+
|
42
|
+
# Map all possible netmasks to the corresponding prefix lengths.
|
43
|
+
NETMASK_TO_PREFIX_LENGTH = {}
|
44
|
+
PREFIX_LENGTH_TO_NETMASK.each_pair do |family, hash|
|
45
|
+
NETMASK_TO_PREFIX_LENGTH[family] =
|
46
|
+
Hash[hash.map.with_index { |e, i| [e, i] }]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
include Constants
|
52
|
+
|
53
|
+
# @overload [](address, family)
|
54
|
+
# @param address [Integer] the integer representation of the address
|
55
|
+
# @param family [Symbol] a symbol named for the address's
|
56
|
+
# address family, one of +:ipv4+, +:ipv6+, or +:mac+.
|
57
|
+
# @return [IPAddr]
|
58
|
+
# Wrapper for IPAddr.new that accepts a symbolic family name and
|
59
|
+
# returns a specialized IPAddr subclass.
|
60
|
+
#
|
61
|
+
# @overload [](address, family)
|
62
|
+
# @param address [Integer] the integer representation of the address
|
63
|
+
# @param family [Integer] the magic number representing the address's
|
64
|
+
# address family.
|
65
|
+
# @return [IPAddr]
|
66
|
+
# Wrapper for IPAddr.new that accepts a symbolic family name and
|
67
|
+
# returns a specialized IPAddr subclass.
|
68
|
+
#
|
69
|
+
# @overload [](address)
|
70
|
+
# @param address [String] the string representation of the address
|
71
|
+
# @return [IPAddr]
|
72
|
+
# Wrapper for IPAddr.new that accepts the string representation
|
73
|
+
# of an address returns a specialized IPAddr subclass.
|
74
|
+
|
75
|
+
def [](address, family = nil)
|
76
|
+
instance = case family
|
77
|
+
when Symbol
|
78
|
+
self[address, SYMBOL_TO_FAMILY.fetch(family)]
|
79
|
+
when IPAddr
|
80
|
+
address
|
81
|
+
when nil
|
82
|
+
new(address)
|
83
|
+
else
|
84
|
+
new(address, family)
|
85
|
+
end
|
86
|
+
IPAddr::Base.specialize(instance)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
module InstanceMethods
|
91
|
+
include Constants
|
92
|
+
|
93
|
+
# Return the magic number representing the address family.
|
94
|
+
# @return [Integer]
|
95
|
+
attr_reader :family
|
96
|
+
|
97
|
+
# Return the integer representation of the netmask.
|
98
|
+
# @return [Integer]
|
99
|
+
attr_reader :mask_addr
|
100
|
+
alias_method :netmask, :mask_addr
|
101
|
+
|
102
|
+
# Return the address greater than the original address by the
|
103
|
+
# given offset.
|
104
|
+
# @param offset [Integer] the difference between the original
|
105
|
+
# address and the returned address
|
106
|
+
# @return [IPAddr]
|
107
|
+
|
108
|
+
def +(offset)
|
109
|
+
self.class.new(@addr + offset, family)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Return the address less than the original address by the given
|
113
|
+
# offset.
|
114
|
+
# @param offset [Integer] the difference between the original
|
115
|
+
# address and the returned address
|
116
|
+
# @return [IPAddr]
|
117
|
+
|
118
|
+
def -(offset)
|
119
|
+
self + (-offset)
|
120
|
+
end
|
121
|
+
|
122
|
+
# @overload <=>(other)
|
123
|
+
# Compare this address with another address of the same address
|
124
|
+
# family.
|
125
|
+
# @param [IPAddr] other
|
126
|
+
# @return [Integer]
|
127
|
+
|
128
|
+
# @overload <=>(other)
|
129
|
+
# Compare this address with the integer representation of another
|
130
|
+
# address of the same address family.
|
131
|
+
# @param [Integer] other
|
132
|
+
# @return [Integer]
|
133
|
+
|
134
|
+
def <=>(other)
|
135
|
+
if other.is_a?(IPAddr)
|
136
|
+
family_difference = family <=> other.family
|
137
|
+
return family_difference unless family_difference == 0
|
138
|
+
elsif !other.is_a?(Integer)
|
139
|
+
fail ArgumentError, "Can't compare #{self.class} with #{other.class}"
|
140
|
+
end
|
141
|
+
|
142
|
+
address_difference = to_i <=> other.to_i
|
143
|
+
|
144
|
+
if address_difference != 0 || !other.is_a?(IPAddr)
|
145
|
+
return address_difference
|
146
|
+
end
|
147
|
+
|
148
|
+
other.instance_variable_get(:@mask_addr) <=> @mask_addr
|
149
|
+
end
|
150
|
+
|
151
|
+
# Test the equality of two IP addresses, or an IP address an
|
152
|
+
# integer representing an address in the same address family.
|
153
|
+
# @param other [IPAddr, Integer] the address to compare with
|
154
|
+
# @return [Boolean]
|
155
|
+
|
156
|
+
def ==(other)
|
157
|
+
return false if other.nil?
|
158
|
+
(self <=> other) == 0
|
159
|
+
end
|
160
|
+
|
161
|
+
# The address at the given offset relative to the network address
|
162
|
+
# of the network. A negative offset will be used to count
|
163
|
+
# backwards from the highest addresses within the network.
|
164
|
+
# @param offset [Integer] the index within the network of the
|
165
|
+
# desired address
|
166
|
+
# @return [IPAddr] the address at the given index
|
167
|
+
|
168
|
+
def [](offset)
|
169
|
+
offset2 = offset >= 0 ? offset : size + offset
|
170
|
+
self.class[to_i + offset2, family: family]
|
171
|
+
end
|
172
|
+
|
173
|
+
# Returns the number of bits allowed by the address family.
|
174
|
+
# A more efficient form of this method is available to the
|
175
|
+
# specialized IPAddr child classes.
|
176
|
+
#
|
177
|
+
# @return [Integer]
|
178
|
+
|
179
|
+
def address_family_bit_length
|
180
|
+
FAMILY_TO_BIT_LENGTH.fetch(family)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Returns a string representation of the address without a prefix length.
|
184
|
+
#
|
185
|
+
# @return [String]
|
186
|
+
|
187
|
+
def base
|
188
|
+
_to_string(@addr)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Return a string containing the CIDR representation of the address.
|
192
|
+
#
|
193
|
+
# @return [String]
|
194
|
+
|
195
|
+
def cidr
|
196
|
+
return _to_string(@addr) unless ipv4? || ipv6?
|
197
|
+
"#{_to_string(@addr)}/#{prefixlen}"
|
198
|
+
end
|
199
|
+
|
200
|
+
# Test whether or not this address completely encloses the other address.
|
201
|
+
|
202
|
+
def cover?(other)
|
203
|
+
first <= other.first && other.last <= last
|
204
|
+
end
|
205
|
+
|
206
|
+
# @overload each
|
207
|
+
# Yield each host address contained within the network. A host
|
208
|
+
# address, such as +1.1.1.1/32+, will yield only itself. Returns
|
209
|
+
# the original object.
|
210
|
+
# @yield [IPAddr]
|
211
|
+
# @return [IPAddr]
|
212
|
+
|
213
|
+
# @overload each
|
214
|
+
# Return an enumerator with the behavior described above.
|
215
|
+
# @return [Enumerator]
|
216
|
+
|
217
|
+
def each
|
218
|
+
if block_given?
|
219
|
+
(0...size).each do |offset|
|
220
|
+
yield self[offset]
|
221
|
+
end
|
222
|
+
self
|
223
|
+
else
|
224
|
+
enum_for(:each)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# The first host address in the network.
|
229
|
+
# @return [IPAddr]
|
230
|
+
|
231
|
+
def first
|
232
|
+
self[0]
|
233
|
+
end
|
234
|
+
|
235
|
+
# Return a new address with the prefix length reduced by the given
|
236
|
+
# amount. The new address will cover the original address.
|
237
|
+
# @param shift [Integer] the decrease in the prefix length
|
238
|
+
# @return [IPAddr]
|
239
|
+
|
240
|
+
def grow(shift)
|
241
|
+
mask(prefix_length - shift)
|
242
|
+
end
|
243
|
+
|
244
|
+
# Return true if the address represents a host (i.e., only one address).
|
245
|
+
|
246
|
+
def host?
|
247
|
+
prefix_length >= address_family_bit_length
|
248
|
+
end
|
249
|
+
|
250
|
+
# Return the last address in the network, which by convention is
|
251
|
+
# the broadcast address in IP networks.
|
252
|
+
# @return [IPAddr]
|
253
|
+
|
254
|
+
def last
|
255
|
+
self[-1]
|
256
|
+
end
|
257
|
+
|
258
|
+
alias_method :broadcast, :last
|
259
|
+
|
260
|
+
# Test whether or not two networks have any addresses in common
|
261
|
+
# (i.e., if either entirely encloses the other).
|
262
|
+
|
263
|
+
def overlap?(other)
|
264
|
+
cover?(other) || other.cover?(self)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Return the prefix length.
|
268
|
+
# A more efficient form of this method is available to the
|
269
|
+
# specialized +IPAddr+ child classes.
|
270
|
+
# @return [Integer]
|
271
|
+
|
272
|
+
def prefix_length
|
273
|
+
NETMASK_TO_PREFIX_LENGTH[family][mask_addr]
|
274
|
+
end
|
275
|
+
|
276
|
+
alias_method :prefixlen, :prefix_length
|
277
|
+
|
278
|
+
# Return a new address with the prefix length increased by the
|
279
|
+
# given amount. The old address will cover the new address.
|
280
|
+
# @param shift [Integer] the increase in the prefix length
|
281
|
+
# @return [Boolean]
|
282
|
+
|
283
|
+
def shrink(shift)
|
284
|
+
mask(prefix_length + shift)
|
285
|
+
end
|
286
|
+
|
287
|
+
# Return the number of host addresses representable by the network
|
288
|
+
# given its size.
|
289
|
+
# @return [Integer]
|
290
|
+
|
291
|
+
def size
|
292
|
+
2**(address_family_bit_length - prefix_length)
|
293
|
+
end
|
294
|
+
|
295
|
+
# Returns a summary address if the two networks can be combined
|
296
|
+
# into a single network without covering any other networks.
|
297
|
+
# Returns +nil+ if the two networks can't be combined this way.
|
298
|
+
# @return [IPAddr?]
|
299
|
+
|
300
|
+
def summarize_with(other)
|
301
|
+
if other.nil?
|
302
|
+
nil
|
303
|
+
elsif cover?(other)
|
304
|
+
self
|
305
|
+
elsif other.cover?(self)
|
306
|
+
other
|
307
|
+
elsif other.grow(1) == grow(1)
|
308
|
+
grow(1)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
# Return a range representing the network. A block can be given to
|
313
|
+
# specify a conversion procedure, for example to convert the first
|
314
|
+
# and last addresses to integers before building the range.
|
315
|
+
# @return [Range(IPAddr)]
|
316
|
+
|
317
|
+
def to_range
|
318
|
+
if block_given?
|
319
|
+
(yield first)..(yield last)
|
320
|
+
else
|
321
|
+
first..last
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# Return a wildcard mask representing the network.
|
326
|
+
# @return [IPAddr]
|
327
|
+
|
328
|
+
def wildcard
|
329
|
+
_to_string(@mask_addr.to_i ^ (2**address_family_bit_length - 1))
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|