ipaddress 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +73 -0
- data/README.rdoc +120 -86
- data/Rakefile +7 -15
- data/VERSION +1 -1
- data/lib/ipaddress.rb +131 -15
- data/lib/ipaddress/extensions/extensions.rb +8 -2
- data/lib/ipaddress/ipv4.rb +132 -49
- data/lib/ipaddress/ipv6.rb +64 -18
- data/lib/ipaddress/prefix.rb +38 -1
- data/test/ipaddress/ipv4_test.rb +92 -38
- data/test/ipaddress/ipv6_test.rb +34 -10
- data/test/ipaddress/prefix_test.rb +15 -0
- data/test/ipaddress_test.rb +17 -0
- data/test/test_helper.rb +0 -5
- metadata +11 -25
- data/lib/ipaddress/ipbase.rb +0 -83
- data/test/ipaddress/ipbase_test.rb +0 -28
data/Rakefile
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
3
|
require 'rake/clean'
|
4
|
-
require 'rcov/rcovtask'
|
5
|
-
|
6
4
|
|
7
5
|
begin
|
8
6
|
require 'jeweler'
|
@@ -12,9 +10,13 @@ begin
|
|
12
10
|
gem.email = "ceresa@gmail.com"
|
13
11
|
gem.homepage = "http://github.com/bluemonk/ipaddress"
|
14
12
|
gem.authors = ["Marco Ceresa"]
|
15
|
-
|
13
|
+
gem.description = <<-EOD
|
14
|
+
IPAddress is a Ruby library designed to make manipulation
|
15
|
+
of IPv4 and IPv6 addresses both powerful and simple. It mantains
|
16
|
+
a layer of compatibility with Ruby's own IPAddr, while
|
17
|
+
addressing many of its issues.
|
18
|
+
EOD
|
16
19
|
end
|
17
|
-
|
18
20
|
rescue LoadError
|
19
21
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
22
|
end
|
@@ -59,7 +61,7 @@ end
|
|
59
61
|
|
60
62
|
desc "Open an irb session preloaded with this library"
|
61
63
|
task :console do
|
62
|
-
sh "
|
64
|
+
sh "irb1.9 -rubygems -I lib -r ipaddress.rb"
|
63
65
|
end
|
64
66
|
|
65
67
|
desc "Look for TODO and FIXME tags in the code"
|
@@ -79,13 +81,3 @@ task :todo do
|
|
79
81
|
end
|
80
82
|
egrep /(FIXME|TODO|TBD)/
|
81
83
|
end
|
82
|
-
|
83
|
-
begin
|
84
|
-
require 'jeweler'
|
85
|
-
Jeweler::Tasks.new do |gemspec|
|
86
|
-
# omitted for brevity
|
87
|
-
end
|
88
|
-
Jeweler::GemcutterTasks.new
|
89
|
-
rescue LoadError
|
90
|
-
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
91
|
-
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.6.0
|
data/lib/ipaddress.rb
CHANGED
@@ -1,9 +1,136 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
#
|
2
|
+
# = IPAddress
|
3
|
+
#
|
4
|
+
# A ruby library to manipulate IPv4 and IPv6 addresses
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Package:: IPAddress
|
8
|
+
# Author:: Marco Ceresa <ceresa@ieee.org>
|
9
|
+
# License:: Ruby License
|
10
|
+
#
|
11
|
+
#--
|
12
|
+
#
|
13
|
+
#++
|
3
14
|
|
4
|
-
require 'ipaddress/ipbase'
|
5
15
|
require 'ipaddress/ipv4'
|
6
16
|
require 'ipaddress/ipv6'
|
17
|
+
require 'ipaddress/extensions/extensions'
|
18
|
+
|
19
|
+
|
20
|
+
module IPAddress
|
21
|
+
|
22
|
+
NAME = "IPAddress"
|
23
|
+
GEM = "ipaddress"
|
24
|
+
AUTHORS = ["Marco Ceresa <ceresa@ieee.org>"]
|
25
|
+
|
26
|
+
#
|
27
|
+
# Parse the argument string to create a new
|
28
|
+
# IPv4, IPv6 or Mapped IP object
|
29
|
+
#
|
30
|
+
# ip = IPAddress.parse "172.16.10.1/24"
|
31
|
+
# ip6 = IPAddress.parse "2001:db8::8:800:200c:417a/64"
|
32
|
+
# ip_mapped = IPAddress.parse "::ffff:172.16.10.1/128"
|
33
|
+
#
|
34
|
+
# All the object created will be instances of the
|
35
|
+
# correct class:
|
36
|
+
#
|
37
|
+
# ip.class
|
38
|
+
# #=> IPAddress::IPv4
|
39
|
+
# ip6.class
|
40
|
+
# #=> IPAddress::IPv6
|
41
|
+
# ip_mapped.class
|
42
|
+
# #=> IPAddress::IPv6::Mapped
|
43
|
+
#
|
44
|
+
def IPAddress::parse(str)
|
45
|
+
case str
|
46
|
+
when /:.+\./
|
47
|
+
IPAddress::IPv6::Mapped.new(str)
|
48
|
+
else
|
49
|
+
begin
|
50
|
+
IPAddress::IPv4.new(str)
|
51
|
+
rescue ArgumentError
|
52
|
+
IPAddress::IPv6.new(str)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Checks if the given string is a valid IP address,
|
59
|
+
# either IPv4 or IPv6
|
60
|
+
#
|
61
|
+
# Example:
|
62
|
+
#
|
63
|
+
# IPAddress::valid? "2002::1"
|
64
|
+
# #=> true
|
65
|
+
#
|
66
|
+
# IPAddress::valid? "10.0.0.256"
|
67
|
+
# #=> false
|
68
|
+
#
|
69
|
+
def self.valid?(addr)
|
70
|
+
valid_ipv4?(addr) || valid_ipv6?(addr)
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Checks if the given string is a valid IPv4 address
|
75
|
+
#
|
76
|
+
# Example:
|
77
|
+
#
|
78
|
+
# IPAddress::valid_ipv4? "2002::1"
|
79
|
+
# #=> false
|
80
|
+
#
|
81
|
+
# IPAddress::valid_ipv4? "172.16.10.1"
|
82
|
+
# #=> true
|
83
|
+
#
|
84
|
+
def self.valid_ipv4?(addr)
|
85
|
+
if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
|
86
|
+
return $~.captures.all? {|i| i.to_i < 256}
|
87
|
+
end
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Checks if the argument is a valid IPv4 netmask
|
93
|
+
# expressed in dotted decimal format.
|
94
|
+
#
|
95
|
+
# IPAddress.valid_ipv4_netmask? "255.255.0.0"
|
96
|
+
# #=> true
|
97
|
+
#
|
98
|
+
def self.valid_ipv4_netmask?(addr)
|
99
|
+
arr = addr.split(".").map{|i| i.to_i}.pack("CCCC").unpack("B*").first.scan(/01/)
|
100
|
+
arr.empty? && valid_ipv4?(addr)
|
101
|
+
rescue
|
102
|
+
return false
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Checks if the given string is a valid IPv6 address
|
107
|
+
#
|
108
|
+
# Example:
|
109
|
+
#
|
110
|
+
# IPAddress::valid_ipv6? "2002::1"
|
111
|
+
# #=> true
|
112
|
+
#
|
113
|
+
# IPAddress::valid_ipv6? "2002::DEAD::BEEF"
|
114
|
+
# #=> false
|
115
|
+
#
|
116
|
+
def self.valid_ipv6?(addr)
|
117
|
+
# IPv6 (normal)
|
118
|
+
return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
|
119
|
+
return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
|
120
|
+
return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
|
121
|
+
# IPv6 (IPv4 compat)
|
122
|
+
return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_ipv4?($')
|
123
|
+
return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
|
124
|
+
return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_ipv4?($')
|
125
|
+
false
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.deprecate(message = nil) # :nodoc:
|
129
|
+
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
|
130
|
+
warn("DEPRECATION WARNING: #{message}")
|
131
|
+
end
|
132
|
+
|
133
|
+
end # module IPAddress
|
7
134
|
|
8
135
|
#
|
9
136
|
# IPAddress is a wrapper method built around
|
@@ -35,18 +162,7 @@ require 'ipaddress/ipv6'
|
|
35
162
|
# #=> IPAddress::IPv6::Mapped
|
36
163
|
#
|
37
164
|
def IPAddress(str)
|
38
|
-
|
39
|
-
when /:.+\./
|
40
|
-
IPAddress::IPv6::Mapped.new(str)
|
41
|
-
else
|
42
|
-
begin
|
43
|
-
IPAddress::IPv4.new(str)
|
44
|
-
rescue ArgumentError
|
45
|
-
IPAddress::IPv6.new(str)
|
46
|
-
end
|
47
|
-
end
|
165
|
+
IPAddress::parse str
|
48
166
|
end
|
49
167
|
|
50
168
|
|
51
|
-
|
52
|
-
|
@@ -2,13 +2,19 @@ class << Math
|
|
2
2
|
def log2(n); log(n) / log(2); end
|
3
3
|
end
|
4
4
|
|
5
|
+
if RUBY_VERSION =~ /1\.8/
|
6
|
+
class Hash
|
7
|
+
alias :key :index
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
5
11
|
class Integer
|
6
12
|
def power_of_2?
|
7
13
|
Math::log2(self).to_i == Math::log2(self)
|
8
14
|
end
|
9
15
|
|
10
|
-
def closest_power_of_2
|
11
|
-
self.upto(
|
16
|
+
def closest_power_of_2(limit=32)
|
17
|
+
self.upto(limit) do |i|
|
12
18
|
return i if i.power_of_2?
|
13
19
|
end
|
14
20
|
end
|
data/lib/ipaddress/ipv4.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'ipaddress/ipbase'
|
2
1
|
require 'ipaddress/prefix'
|
3
2
|
|
4
3
|
module IPAddress;
|
@@ -15,7 +14,7 @@ module IPAddress;
|
|
15
14
|
#
|
16
15
|
# Class IPAddress::IPv4 is used to handle IPv4 type addresses.
|
17
16
|
#
|
18
|
-
class IPv4
|
17
|
+
class IPv4
|
19
18
|
|
20
19
|
include IPAddress
|
21
20
|
include Enumerable
|
@@ -102,6 +101,7 @@ module IPAddress;
|
|
102
101
|
# as a string.
|
103
102
|
#
|
104
103
|
# ip = IPAddress("172.16.100.4/22")
|
104
|
+
#
|
105
105
|
# ip.address
|
106
106
|
# #=> "172.16.100.4"
|
107
107
|
#
|
@@ -114,8 +114,10 @@ module IPAddress;
|
|
114
114
|
# as a IPAddress::Prefix32 object
|
115
115
|
#
|
116
116
|
# ip = IPAddress("172.16.100.4/22")
|
117
|
+
#
|
117
118
|
# ip.prefix
|
118
119
|
# #=> 22
|
120
|
+
#
|
119
121
|
# ip.prefix.class
|
120
122
|
# #=> IPAddress::Prefix32
|
121
123
|
#
|
@@ -132,10 +134,12 @@ module IPAddress;
|
|
132
134
|
# mask.
|
133
135
|
#
|
134
136
|
# ip = IPAddress("172.16.100.4")
|
137
|
+
#
|
135
138
|
# puts ip
|
136
139
|
# #=> 172.16.100.4/16
|
137
140
|
#
|
138
141
|
# ip.prefix = 22
|
142
|
+
#
|
139
143
|
# puts ip
|
140
144
|
# #=> 172.16.100.4/22
|
141
145
|
#
|
@@ -147,6 +151,7 @@ module IPAddress;
|
|
147
151
|
# Returns the address as an array of decimal values
|
148
152
|
#
|
149
153
|
# ip = IPAddress("172.16.100.4")
|
154
|
+
#
|
150
155
|
# ip.octets
|
151
156
|
# #=> [172, 16, 100, 4]
|
152
157
|
#
|
@@ -154,22 +159,38 @@ module IPAddress;
|
|
154
159
|
@octets
|
155
160
|
end
|
156
161
|
|
162
|
+
#
|
163
|
+
# Returns a string with the address portion of
|
164
|
+
# the IPv4 object
|
165
|
+
#
|
166
|
+
# ip = IPAddress("172.16.100.4/22")
|
167
|
+
#
|
168
|
+
# ip.to_s
|
169
|
+
# #=> "172.16.100.4"
|
170
|
+
#
|
171
|
+
def to_s
|
172
|
+
@address
|
173
|
+
end
|
174
|
+
|
157
175
|
#
|
158
176
|
# Returns a string with the IP address in canonical
|
159
177
|
# form.
|
160
178
|
#
|
161
179
|
# ip = IPAddress("172.16.100.4/22")
|
162
|
-
#
|
180
|
+
#
|
181
|
+
# ip.to_string
|
163
182
|
# #=> "172.16.100.4/22"
|
164
183
|
#
|
165
|
-
def
|
184
|
+
def to_string
|
166
185
|
"#@address/#@prefix"
|
167
186
|
end
|
168
187
|
|
188
|
+
|
169
189
|
#
|
170
190
|
# Returns the prefix as a string in IP format
|
171
191
|
#
|
172
192
|
# ip = IPAddress("172.16.100.4/22")
|
193
|
+
#
|
173
194
|
# ip.netmask
|
174
195
|
# #=> "255.255.252.0"
|
175
196
|
#
|
@@ -183,10 +204,12 @@ module IPAddress;
|
|
183
204
|
# object.
|
184
205
|
#
|
185
206
|
# ip = IPAddress("172.16.100.4")
|
207
|
+
#
|
186
208
|
# puts ip
|
187
209
|
# #=> 172.16.100.4/16
|
188
210
|
#
|
189
211
|
# ip.netmask = "255.255.252.0"
|
212
|
+
#
|
190
213
|
# puts ip
|
191
214
|
# #=> 172.16.100.4/22
|
192
215
|
#
|
@@ -203,6 +226,7 @@ module IPAddress;
|
|
203
226
|
# structure.
|
204
227
|
#
|
205
228
|
# ip = IPAddress("10.0.0.0/8")
|
229
|
+
#
|
206
230
|
# ip.to_u32
|
207
231
|
# #=> 167772160
|
208
232
|
#
|
@@ -216,6 +240,7 @@ module IPAddress;
|
|
216
240
|
# in a network byte order format.
|
217
241
|
#
|
218
242
|
# ip = IPAddress("172.16.10.1/24")
|
243
|
+
#
|
219
244
|
# ip.data
|
220
245
|
# #=> "\254\020\n\001"
|
221
246
|
#
|
@@ -237,6 +262,7 @@ module IPAddress;
|
|
237
262
|
# Returns the octet specified by index
|
238
263
|
#
|
239
264
|
# ip = IPAddress("172.16.100.50/24")
|
265
|
+
#
|
240
266
|
# ip[0]
|
241
267
|
# #=> 172
|
242
268
|
# ip[1]
|
@@ -256,6 +282,7 @@ module IPAddress;
|
|
256
282
|
# as a string containing a sequence of 0 and 1
|
257
283
|
#
|
258
284
|
# ip = IPAddress("127.0.0.1")
|
285
|
+
#
|
259
286
|
# ip.bits
|
260
287
|
# #=> "01111111000000000000000000000001"
|
261
288
|
#
|
@@ -267,8 +294,9 @@ module IPAddress;
|
|
267
294
|
# Returns the broadcast address for the given IP.
|
268
295
|
#
|
269
296
|
# ip = IPAddress("172.16.10.64/24")
|
297
|
+
#
|
270
298
|
# ip.broadcast.to_s
|
271
|
-
# #=> "172.16.10.255
|
299
|
+
# #=> "172.16.10.255"
|
272
300
|
#
|
273
301
|
def broadcast
|
274
302
|
self.class.parse_u32(broadcast_u32, @prefix)
|
@@ -278,10 +306,12 @@ module IPAddress;
|
|
278
306
|
# Checks if the IP address is actually a network
|
279
307
|
#
|
280
308
|
# ip = IPAddress("172.16.10.64/24")
|
309
|
+
#
|
281
310
|
# ip.network?
|
282
311
|
# #=> false
|
283
312
|
#
|
284
313
|
# ip = IPAddress("172.16.10.64/26")
|
314
|
+
#
|
285
315
|
# ip.network?
|
286
316
|
# #=> true
|
287
317
|
#
|
@@ -294,8 +324,9 @@ module IPAddress;
|
|
294
324
|
# for the given IP.
|
295
325
|
#
|
296
326
|
# ip = IPAddress("172.16.10.64/24")
|
327
|
+
#
|
297
328
|
# ip.network.to_s
|
298
|
-
# #=> "172.16.10.0
|
329
|
+
# #=> "172.16.10.0"
|
299
330
|
#
|
300
331
|
def network
|
301
332
|
self.class.parse_u32(network_u32, @prefix)
|
@@ -309,15 +340,17 @@ module IPAddress;
|
|
309
340
|
# host IP address is 192.168.100.1.
|
310
341
|
#
|
311
342
|
# ip = IPAddress("192.168.100.0/24")
|
343
|
+
#
|
312
344
|
# ip.first.to_s
|
313
|
-
# #=> "192.168.100.1
|
345
|
+
# #=> "192.168.100.1"
|
314
346
|
#
|
315
347
|
# The object IP doesn't need to be a network: the method
|
316
348
|
# automatically gets the network number from it
|
317
349
|
#
|
318
350
|
# ip = IPAddress("192.168.100.50/24")
|
351
|
+
#
|
319
352
|
# ip.first.to_s
|
320
|
-
# #=> "192.168.100.1
|
353
|
+
# #=> "192.168.100.1"
|
321
354
|
#
|
322
355
|
def first
|
323
356
|
self.class.parse_u32(network_u32+1, @prefix)
|
@@ -329,18 +362,20 @@ module IPAddress;
|
|
329
362
|
# last host IP address in the range.
|
330
363
|
#
|
331
364
|
# Example: given the 192.168.100.0/24 network, the last
|
332
|
-
# host IP address is 192.168.100.
|
365
|
+
# host IP address is 192.168.100.254
|
333
366
|
#
|
334
367
|
# ip = IPAddress("192.168.100.0/24")
|
368
|
+
#
|
335
369
|
# ip.last.to_s
|
336
|
-
# #=> "192.168.100.254
|
370
|
+
# #=> "192.168.100.254"
|
337
371
|
#
|
338
372
|
# The object IP doesn't need to be a network: the method
|
339
373
|
# automatically gets the network number from it
|
340
374
|
#
|
341
375
|
# ip = IPAddress("192.168.100.50/24")
|
376
|
+
#
|
342
377
|
# ip.last.to_s
|
343
|
-
# #=> "192.168.100.254
|
378
|
+
# #=> "192.168.100.254"
|
344
379
|
#
|
345
380
|
def last
|
346
381
|
self.class.parse_u32(broadcast_u32-1, @prefix)
|
@@ -350,9 +385,10 @@ module IPAddress;
|
|
350
385
|
# Iterates over all the hosts IP addresses for the given
|
351
386
|
# network (or IP address).
|
352
387
|
#
|
353
|
-
# ip =
|
388
|
+
# ip = IPAddress("10.0.0.1/29")
|
389
|
+
#
|
354
390
|
# ip.each do |i|
|
355
|
-
# p i
|
391
|
+
# p i.to_s
|
356
392
|
# end
|
357
393
|
# #=> "10.0.0.1"
|
358
394
|
# #=> "10.0.0.2"
|
@@ -374,7 +410,8 @@ module IPAddress;
|
|
374
410
|
# The object yielded is a new IPv4 object created
|
375
411
|
# from the iteration.
|
376
412
|
#
|
377
|
-
# ip =
|
413
|
+
# ip = IPAddress("10.0.0.1/29")
|
414
|
+
#
|
378
415
|
# ip.each do |i|
|
379
416
|
# p i.address
|
380
417
|
# end
|
@@ -406,8 +443,8 @@ module IPAddress;
|
|
406
443
|
# Example:
|
407
444
|
#
|
408
445
|
# ip1 = IPAddress "10.100.100.1/8"
|
409
|
-
# ip2 = IPAddress "
|
410
|
-
# ip3 = IPAddress "
|
446
|
+
# ip2 = IPAddress "172.16.0.1/16"
|
447
|
+
# ip3 = IPAddress "10.100.100.1/16"
|
411
448
|
#
|
412
449
|
# ip1 < ip2
|
413
450
|
# #=> true
|
@@ -434,7 +471,8 @@ module IPAddress;
|
|
434
471
|
# in the network. It also counts the network
|
435
472
|
# address and the broadcast address.
|
436
473
|
#
|
437
|
-
# ip =
|
474
|
+
# ip = IPAddress("10.0.0.1/29")
|
475
|
+
#
|
438
476
|
# ip.size
|
439
477
|
# #=> 8
|
440
478
|
#
|
@@ -446,7 +484,8 @@ module IPAddress;
|
|
446
484
|
# Returns an array with the IP addresses of
|
447
485
|
# all the hosts in the network.
|
448
486
|
#
|
449
|
-
# ip =
|
487
|
+
# ip = IPAddress("10.0.0.1/29")
|
488
|
+
#
|
450
489
|
# ip.hosts.map {|i| i.address}
|
451
490
|
# #=> ["10.0.0.1",
|
452
491
|
# #=> "10.0.0.2",
|
@@ -462,7 +501,8 @@ module IPAddress;
|
|
462
501
|
#
|
463
502
|
# Returns the network number in Unsigned 32bits format
|
464
503
|
#
|
465
|
-
# ip =
|
504
|
+
# ip = IPAddress("10.0.0.1/29")
|
505
|
+
#
|
466
506
|
# ip.network_u32
|
467
507
|
# #=> 167772160
|
468
508
|
#
|
@@ -474,6 +514,7 @@ module IPAddress;
|
|
474
514
|
# Returns the broadcast address in Unsigned 32bits format
|
475
515
|
#
|
476
516
|
# ip = IPaddress("10.0.0.1/29")
|
517
|
+
#
|
477
518
|
# ip.broadcast_u32
|
478
519
|
# #=> 167772167
|
479
520
|
#
|
@@ -490,6 +531,7 @@ module IPAddress;
|
|
490
531
|
# ip = IPAddress("192.168.10.100/24")
|
491
532
|
#
|
492
533
|
# addr = IPAddress("192.168.10.102/24")
|
534
|
+
#
|
493
535
|
# ip.include? addr
|
494
536
|
# #=> true
|
495
537
|
#
|
@@ -505,12 +547,14 @@ module IPAddress;
|
|
505
547
|
# for DNS lookups
|
506
548
|
#
|
507
549
|
# ip = IPAddress("172.16.100.50/24")
|
550
|
+
#
|
508
551
|
# ip.reverse
|
509
552
|
# #=> "50.100.16.172.in-addr.arpa"
|
510
553
|
#
|
511
554
|
def reverse
|
512
555
|
@octets.reverse.join(".") + ".in-addr.arpa"
|
513
556
|
end
|
557
|
+
alias_method :arpa, :reverse
|
514
558
|
|
515
559
|
#
|
516
560
|
# Subnetting a network
|
@@ -524,7 +568,8 @@ module IPAddress;
|
|
524
568
|
# networks will be divided evenly from the supernet.
|
525
569
|
#
|
526
570
|
# network = IPAddress("172.16.10.0/24")
|
527
|
-
#
|
571
|
+
#
|
572
|
+
# network / 4 # implies map{|i| i.to_string}
|
528
573
|
# #=> ["172.16.10.0/26",
|
529
574
|
# "172.16.10.64/26",
|
530
575
|
# "172.16.10.128/26",
|
@@ -535,7 +580,8 @@ module IPAddress;
|
|
535
580
|
# other networks with the remaining addresses.
|
536
581
|
#
|
537
582
|
# network = IPAddress("172.16.10.0/24")
|
538
|
-
#
|
583
|
+
#
|
584
|
+
# network / 3 # implies map{|i| i.to_string}
|
539
585
|
# #=> ["172.16.10.0/26",
|
540
586
|
# "172.16.10.64/26",
|
541
587
|
# "172.16.10.128/25"]
|
@@ -546,7 +592,6 @@ module IPAddress;
|
|
546
592
|
unless (1..(2**(32-prefix.to_i))).include? subnets
|
547
593
|
raise ArgumentError, "Value #{subnets} out of range"
|
548
594
|
end
|
549
|
-
|
550
595
|
calculate_subnets(subnets)
|
551
596
|
end
|
552
597
|
alias_method :/, :subnet
|
@@ -564,13 +609,13 @@ module IPAddress;
|
|
564
609
|
#
|
565
610
|
# you can supernet it with a new /23 prefix
|
566
611
|
#
|
567
|
-
# ip.supernet(23).
|
612
|
+
# ip.supernet(23).to_string
|
568
613
|
# #=> "172.16.10.0/23"
|
569
614
|
#
|
570
615
|
# However if you supernet it with a /22 prefix, the
|
571
616
|
# network address will change:
|
572
617
|
#
|
573
|
-
# ip.supernet(22).
|
618
|
+
# ip.supernet(22).to_string
|
574
619
|
# #=> "172.16.8.0/22"
|
575
620
|
#
|
576
621
|
def supernet(new_prefix)
|
@@ -583,6 +628,14 @@ module IPAddress;
|
|
583
628
|
# Returns the difference between two IP addresses
|
584
629
|
# in unsigned int 32 bits format
|
585
630
|
#
|
631
|
+
# Example:
|
632
|
+
#
|
633
|
+
# ip1 = IPAddress("172.16.10.0/24")
|
634
|
+
# ip2 = IPAddress("172.16.11.0/24")
|
635
|
+
#
|
636
|
+
# puts ip1 - ip2
|
637
|
+
# #=> 256
|
638
|
+
#
|
586
639
|
def -(oth)
|
587
640
|
return (to_u32 - oth.to_u32).abs
|
588
641
|
end
|
@@ -596,14 +649,21 @@ module IPAddress;
|
|
596
649
|
#
|
597
650
|
# ip1 = IPAddress("172.16.10.1/24")
|
598
651
|
# ip2 = IPAddress("172.16.11.2/24")
|
599
|
-
#
|
600
|
-
#
|
652
|
+
#
|
653
|
+
# p (ip1 + ip2).map {|i| i.to_string}
|
654
|
+
# #=> ["172.16.10.0/23"]
|
601
655
|
#
|
602
656
|
# If the networks are not contiguous, returns
|
603
657
|
# the two network numbers from the objects
|
604
658
|
#
|
659
|
+
# ip1 = IPAddress("10.0.0.1/24")
|
660
|
+
# ip2 = IPAddress("10.0.2.1/24")
|
661
|
+
#
|
662
|
+
# p (ip1 + ip2).map {|i| i.to_string}
|
663
|
+
# #=> ["10.0.0.0/24","10.0.2.0/24"]
|
664
|
+
#
|
605
665
|
def +(oth)
|
606
|
-
|
666
|
+
aggregate(*[self,oth].sort.map{|i| i.network})
|
607
667
|
end
|
608
668
|
|
609
669
|
#
|
@@ -614,11 +674,12 @@ module IPAddress;
|
|
614
674
|
# Example:
|
615
675
|
#
|
616
676
|
# ip = IPAddress("10.0.0.1/24")
|
677
|
+
#
|
617
678
|
# ip.a?
|
618
679
|
# #=> true
|
619
680
|
#
|
620
681
|
def a?
|
621
|
-
CLASSFUL.
|
682
|
+
CLASSFUL.key(8) === bits
|
622
683
|
end
|
623
684
|
|
624
685
|
#
|
@@ -629,11 +690,12 @@ module IPAddress;
|
|
629
690
|
# Example:
|
630
691
|
#
|
631
692
|
# ip = IPAddress("172.16.10.1/24")
|
693
|
+
#
|
632
694
|
# ip.b?
|
633
695
|
# #=> true
|
634
696
|
#
|
635
697
|
def b?
|
636
|
-
CLASSFUL.
|
698
|
+
CLASSFUL.key(16) === bits
|
637
699
|
end
|
638
700
|
|
639
701
|
#
|
@@ -644,11 +706,12 @@ module IPAddress;
|
|
644
706
|
# Example:
|
645
707
|
#
|
646
708
|
# ip = IPAddress("192.168.1.1/30")
|
709
|
+
#
|
647
710
|
# ip.c?
|
648
711
|
# #=> true
|
649
712
|
#
|
650
713
|
def c?
|
651
|
-
CLASSFUL.
|
714
|
+
CLASSFUL.key(24) === bits
|
652
715
|
end
|
653
716
|
|
654
717
|
#
|
@@ -658,6 +721,7 @@ module IPAddress;
|
|
658
721
|
# Example:
|
659
722
|
#
|
660
723
|
# ip = IPAddress("172.16.10.1/24")
|
724
|
+
#
|
661
725
|
# ip.to_ipv6
|
662
726
|
# #=> "ac10:0a01"
|
663
727
|
#
|
@@ -670,14 +734,16 @@ module IPAddress;
|
|
670
734
|
# unsigned 32bits integer.
|
671
735
|
#
|
672
736
|
# ip = IPAddress::IPv4::parse_u32(167772160)
|
737
|
+
#
|
673
738
|
# ip.prefix = 8
|
674
|
-
# ip.
|
739
|
+
# ip.to_string
|
675
740
|
# #=> "10.0.0.0/8"
|
676
741
|
#
|
677
742
|
# The +prefix+ parameter is optional:
|
678
743
|
#
|
679
744
|
# ip = IPAddress::IPv4::parse_u32(167772160, 8)
|
680
|
-
#
|
745
|
+
#
|
746
|
+
# ip.to_string
|
681
747
|
# #=> "10.0.0.0/8"
|
682
748
|
#
|
683
749
|
def self.parse_u32(u32, prefix=nil)
|
@@ -699,7 +765,7 @@ module IPAddress;
|
|
699
765
|
# ip = IPAddress::IPv4::parse_data "\254\020\n\001"
|
700
766
|
# ip.prefix = 24
|
701
767
|
#
|
702
|
-
# ip.
|
768
|
+
# ip.to_string
|
703
769
|
# #=> "172.16.10.1/24"
|
704
770
|
#
|
705
771
|
def self.parse_data(str)
|
@@ -713,10 +779,10 @@ module IPAddress;
|
|
713
779
|
# Example:
|
714
780
|
#
|
715
781
|
# str = "foobar172.16.10.1barbaz"
|
716
|
-
# ip =
|
782
|
+
# ip = IPAddress::IPv4::extract str
|
717
783
|
#
|
718
784
|
# ip.to_s
|
719
|
-
# #=> "172.16.10.1
|
785
|
+
# #=> "172.16.10.1"
|
720
786
|
#
|
721
787
|
def self.extract(str)
|
722
788
|
self.new REGEXP.match(str).to_s
|
@@ -770,7 +836,8 @@ module IPAddress;
|
|
770
836
|
# ip2 = IPAddress("10.0.1.1/24")
|
771
837
|
# ip3 = IPAddress("10.0.2.1/24")
|
772
838
|
# ip4 = IPAddress("10.0.3.1/24")
|
773
|
-
#
|
839
|
+
#
|
840
|
+
# IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_string
|
774
841
|
# #=> "10.0.0.0/22",
|
775
842
|
#
|
776
843
|
# But the following networks can't be summarized in a single network:
|
@@ -779,27 +846,28 @@ module IPAddress;
|
|
779
846
|
# ip2 = IPAddress("10.0.2.1/24")
|
780
847
|
# ip3 = IPAddress("10.0.3.1/24")
|
781
848
|
# ip4 = IPAddress("10.0.4.1/24")
|
782
|
-
#
|
849
|
+
#
|
850
|
+
# IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
|
783
851
|
# #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
|
784
852
|
#
|
785
853
|
def self.summarize(*args)
|
786
854
|
# one network? no need to summarize
|
787
|
-
return args.
|
855
|
+
return [args.first.network] if args.size == 1
|
788
856
|
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
result << x.network unless result.any?{|i| i.include? x}
|
796
|
-
end
|
857
|
+
i = 0
|
858
|
+
result = args.dup.sort.map{|ip| ip.network}
|
859
|
+
while i < result.size-1
|
860
|
+
sum = result[i] + result[i+1]
|
861
|
+
result[i..i+1] = sum.first if sum.size == 1
|
862
|
+
i += 1
|
797
863
|
end
|
798
|
-
result << last unless result.any?{|i| i.include? last}
|
799
864
|
|
865
|
+
result.flatten!
|
800
866
|
if result.size == args.size
|
867
|
+
# nothing more to summarize
|
801
868
|
return result
|
802
869
|
else
|
870
|
+
# keep on summarizing
|
803
871
|
return self.summarize(*result)
|
804
872
|
end
|
805
873
|
end
|
@@ -815,12 +883,12 @@ module IPAddress;
|
|
815
883
|
|
816
884
|
def prefix_from_ip(ip)
|
817
885
|
bits = bits_from_address(ip)
|
818
|
-
CLASSFUL.each {|reg,prefix| return prefix if bits =~ reg}
|
886
|
+
CLASSFUL.each {|reg,prefix| return Prefix32.new(prefix) if bits =~ reg}
|
819
887
|
end
|
820
888
|
|
821
889
|
def calculate_subnets(subnets)
|
822
890
|
po2 = subnets.closest_power_of_2
|
823
|
-
new_prefix = @prefix
|
891
|
+
new_prefix = @prefix + Math::log2(po2).to_i
|
824
892
|
networks = Array.new
|
825
893
|
(0..po2-1).each do |i|
|
826
894
|
mul = i * (2**(32-new_prefix))
|
@@ -843,6 +911,21 @@ module IPAddress;
|
|
843
911
|
end
|
844
912
|
return dup.reverse
|
845
913
|
end
|
914
|
+
|
915
|
+
def aggregate(ip1,ip2)
|
916
|
+
if ip1.include? ip2
|
917
|
+
return [ip1]
|
918
|
+
else
|
919
|
+
snet = ip1.supernet(ip1.prefix-1)
|
920
|
+
arr1 = ip1.subnet(2**(ip2.prefix-ip1.prefix)).map{|i| i.to_string}
|
921
|
+
arr2 = snet.subnet(2**(ip2.prefix-snet.prefix)).map{|i| i.to_string}
|
922
|
+
if (arr2 - [ip2.to_string] - arr1).empty?
|
923
|
+
return [snet]
|
924
|
+
else
|
925
|
+
return [ip1, ip2]
|
926
|
+
end
|
927
|
+
end
|
928
|
+
end
|
846
929
|
|
847
930
|
end # class IPv4
|
848
931
|
end # module IPAddress
|