ipadmin 0.1.2 → 0.1.3
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/README +183 -78
- data/lib/ip_admin.rb +1227 -290
- data/tests/cidr_test.rb +4 -0
- data/tests/functions_test.rb +35 -36
- data/tests/tree_test.rb +315 -0
- metadata +3 -4
- data/tests/cidr_table_test.rb +0 -205
- data/tests/dns_test.rb +0 -68
data/README
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
# IPAdmin::IPAddr
|
25
25
|
#============================================================================#
|
26
26
|
puts "IPAdmin::IPAddr"
|
27
|
+
print "\n"
|
27
28
|
|
28
29
|
# new
|
29
30
|
ip4 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.1/24')
|
@@ -33,34 +34,50 @@
|
|
33
34
|
ip6 = IPAdmin::IPAddr.new(:IPAddr => 'fec0::1/64')
|
34
35
|
|
35
36
|
# reader/writer
|
36
|
-
puts
|
37
|
+
puts "TEST 1"
|
38
|
+
puts "ip4 tag '#{ip4.tag['test']}'"
|
37
39
|
ip4.tag['test'] = 'modified ip4 tag'
|
38
|
-
puts ip4.tag['test']
|
40
|
+
puts "updated ip4 tag '#{ip4.tag['test']}'"
|
41
|
+
puts "ip4 version #{ip4.version}"
|
42
|
+
print "\n"
|
39
43
|
|
40
44
|
# base
|
45
|
+
puts "TEST 2"
|
41
46
|
puts "ip4 base addr #{ip4.base()}"
|
42
47
|
puts "ip6 base addr #{ip6.base()}"
|
48
|
+
print "\n"
|
43
49
|
|
44
50
|
# broadcast
|
51
|
+
puts "TEST 3"
|
45
52
|
puts "ip4 bcast addr #{ip4.broadcast()}"
|
53
|
+
print "\n"
|
46
54
|
|
47
55
|
# desc
|
56
|
+
puts "TEST 4"
|
48
57
|
puts "ip4 description #{ip4.desc()}"
|
49
58
|
puts "ip6 description #{ip6.desc()}"
|
59
|
+
print "\n"
|
50
60
|
|
51
61
|
# extended masks
|
62
|
+
puts "TEST 5"
|
52
63
|
puts "ip4 extended hostmask #{ip4.hostmask_ext()}"
|
53
|
-
puts "
|
64
|
+
puts "ip4 extended netmask #{ip4.netmask_ext()}"
|
65
|
+
print "\n"
|
54
66
|
|
55
67
|
# ip
|
68
|
+
puts "TEST 6"
|
56
69
|
puts "ip4 ip addr #{ip4.ip()}"
|
57
70
|
puts "ip6 ip addr #{ip6.ip()}"
|
71
|
+
print "\n"
|
58
72
|
|
59
73
|
# netmask
|
74
|
+
puts "TEST 7"
|
60
75
|
puts "ip4 netmask in CIDR format #{ip4.netmask()}"
|
61
76
|
puts "ip6 netmask in CIDR format #{ip6.netmask()}"
|
77
|
+
print "\n"
|
62
78
|
|
63
79
|
# bits
|
80
|
+
puts "TEST 8"
|
64
81
|
puts "ip4 netmask in bits #{ip4.bits()}"
|
65
82
|
puts "ip6 netmask in bits #{ip6.bits()}"
|
66
83
|
|
@@ -73,6 +90,10 @@
|
|
73
90
|
# IPAdmin::CIDR
|
74
91
|
#============================================================================#
|
75
92
|
puts "IPAdmin::CIDR"
|
93
|
+
print "\n"
|
94
|
+
|
95
|
+
ip4 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.1/24')
|
96
|
+
ip6 = IPAdmin::IPAddr.new(:IPAddr => 'fec0::1/64')
|
76
97
|
|
77
98
|
# new
|
78
99
|
cidr4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
|
@@ -81,44 +102,64 @@
|
|
81
102
|
:Tag => {'test' => 'cidr4 tag'})
|
82
103
|
cidr6 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/64')
|
83
104
|
|
84
|
-
#
|
85
|
-
puts
|
105
|
+
# reader/writer
|
106
|
+
puts "TEST 1"
|
107
|
+
puts "cidr4 tag '#{cidr4.tag['test']}'"
|
86
108
|
cidr4.tag['test'] = 'modified cidr4 tag'
|
87
|
-
puts cidr4.tag['test']
|
109
|
+
puts "updated cidr4 tag '#{cidr4.tag['test']}'"
|
110
|
+
puts "cidr4 version #{cidr4.version}"
|
111
|
+
print "\n"
|
88
112
|
|
89
113
|
# contains
|
114
|
+
puts "TEST 2"
|
90
115
|
puts "#{cidr4.desc} contains #{ip4.desc}" if ( cidr4.contains(ip4) )
|
91
116
|
puts "#{cidr6.desc} contains #{ip6.desc}" if ( cidr6.contains(ip6) )
|
117
|
+
print "\n"
|
92
118
|
|
93
119
|
# desc
|
120
|
+
puts "TEST 3"
|
94
121
|
puts "cidr4 description #{cidr4.desc()}"
|
95
122
|
puts "cidr6 description #{cidr6.desc()}"
|
123
|
+
print "\n"
|
96
124
|
|
97
125
|
# extended masks
|
126
|
+
puts "TEST 4"
|
98
127
|
puts "cidr4 extended hostmask #{cidr4.hostmask_ext()}"
|
99
128
|
puts "cidr4 extended netmask #{cidr4.netmask_ext()}"
|
129
|
+
print "\n"
|
100
130
|
|
101
131
|
# netmask
|
132
|
+
puts "TEST 5"
|
102
133
|
puts "cidr4 netmask in CIDR format #{cidr4.netmask()}"
|
103
134
|
puts "cidr6 netmask in CIDR format #{cidr6.netmask()}"
|
135
|
+
print "\n"
|
104
136
|
|
105
137
|
# bits
|
138
|
+
puts "TEST 6"
|
106
139
|
puts "cidr4 netmask in bits #{cidr4.bits()}"
|
107
140
|
puts "cidr6 netmask in bits #{cidr6.bits()}"
|
141
|
+
print "\n"
|
108
142
|
|
109
143
|
# network
|
144
|
+
puts "TEST 7"
|
110
145
|
puts "cidr4 network address #{cidr4.network()}"
|
111
146
|
puts "cidr6 network address #{cidr6.network()}"
|
147
|
+
print "\n"
|
112
148
|
|
113
149
|
# nth
|
150
|
+
puts "TEST 8"
|
114
151
|
puts "cidr4 1st ip is #{cidr4.nth(:Index => 1)}"
|
115
152
|
puts "cidr6 1st ip is #{(cidr6.nth(:Index => 1, :Objectify => 1)).desc}"
|
153
|
+
print "\n"
|
116
154
|
|
117
155
|
# size
|
156
|
+
puts "TEST 9"
|
118
157
|
puts "cidr4 size is #{cidr4.size()}"
|
119
158
|
puts "cidr6 size is #{cidr6.size()}"
|
159
|
+
print "\n"
|
120
160
|
|
121
161
|
# enumerate
|
162
|
+
puts "TEST 10"
|
122
163
|
puts "first 4 cidr4 addresses (bitstep 32)"
|
123
164
|
list4 = cidr4.enumerate(:Limit => 4, :Bitstep => 32)
|
124
165
|
list4.each do |addr|
|
@@ -130,8 +171,10 @@
|
|
130
171
|
list6.each do |addr|
|
131
172
|
puts " #{addr.desc}"
|
132
173
|
end
|
174
|
+
print "\n"
|
133
175
|
|
134
176
|
# subnet
|
177
|
+
puts "TEST 11"
|
135
178
|
puts "cidr4 subnetted into at least 3 /28 ranges"
|
136
179
|
sn4 = cidr4.subnet(:Subnet => 28, :MinCount => 3)
|
137
180
|
sn4.each do |cidr|
|
@@ -149,76 +192,131 @@
|
|
149
192
|
#
|
150
193
|
#=====================================#
|
151
194
|
|
195
|
+
|
152
196
|
#============================================================================#
|
153
|
-
# IPAdmin::
|
197
|
+
# IPAdmin::Tree
|
154
198
|
#============================================================================#
|
155
|
-
puts "IPAdmin::
|
199
|
+
puts "IPAdmin::Tree"
|
200
|
+
print "\n"
|
156
201
|
|
157
202
|
cidr4_1 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
|
158
|
-
cidr4_2 = IPAdmin::CIDR.new(:CIDR => '
|
159
|
-
cidr4_3 = IPAdmin::CIDR.new(:CIDR => '192.168.1.
|
160
|
-
cidr4_4 =IPAdmin::CIDR.new(:CIDR => '192.168.1.
|
161
|
-
cidr4_5 = IPAdmin::CIDR.new(:CIDR => '192.168.1.
|
162
|
-
cidr4_6 = IPAdmin::CIDR.new(:CIDR => '192.168.1.
|
163
|
-
cidr4_7 = IPAdmin::CIDR.new(:CIDR => '192.168.1.
|
164
|
-
|
165
|
-
cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::/
|
166
|
-
cidr6_2 = IPAdmin::CIDR.new(:CIDR => '
|
167
|
-
cidr6_3 = IPAdmin::CIDR.new(:CIDR => 'fec0
|
168
|
-
cidr6_4 =IPAdmin::CIDR.new(:CIDR => 'fec0
|
203
|
+
cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/26')
|
204
|
+
cidr4_3 = IPAdmin::CIDR.new(:CIDR => '192.168.1.64/26')
|
205
|
+
cidr4_4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.128/26')
|
206
|
+
cidr4_5 = IPAdmin::CIDR.new(:CIDR => '192.168.1.192/26')
|
207
|
+
cidr4_6 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/27')
|
208
|
+
cidr4_7 = IPAdmin::CIDR.new(:CIDR => '192.168.1.32/27')
|
209
|
+
|
210
|
+
cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::/64')
|
211
|
+
cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fec0::/66')
|
212
|
+
cidr6_3 = IPAdmin::CIDR.new(:CIDR => 'fec0::4000:0:0:0/66')
|
213
|
+
cidr6_4 = IPAdmin::CIDR.new(:CIDR => 'fec0::8000:0:0:0/66')
|
214
|
+
cidr6_5 = IPAdmin::CIDR.new(:CIDR => 'fec0::c000:0:0:0/66')
|
215
|
+
cidr6_6 = IPAdmin::CIDR.new(:CIDR => 'fec0::/67')
|
216
|
+
cidr6_7 = IPAdmin::CIDR.new(:CIDR => 'fec0::2000:0:0:0/67')
|
169
217
|
|
170
218
|
# new
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
#
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
puts "
|
194
|
-
|
195
|
-
|
196
|
-
|
219
|
+
tree4 = IPAdmin::Tree.new(:Version => 4)
|
220
|
+
tree6 = IPAdmin::Tree.new(:Version => 6)
|
221
|
+
|
222
|
+
# add
|
223
|
+
tree4.add(cidr4_1)
|
224
|
+
tree4.add(cidr4_2)
|
225
|
+
tree4.add(cidr4_3)
|
226
|
+
tree4.add(cidr4_4)
|
227
|
+
tree4.add(cidr4_5)
|
228
|
+
tree4.add(cidr4_6)
|
229
|
+
tree4.add(cidr4_7)
|
230
|
+
|
231
|
+
tree6.add(cidr6_1)
|
232
|
+
tree6.add(cidr6_2)
|
233
|
+
tree6.add(cidr6_3)
|
234
|
+
tree6.add(cidr6_4)
|
235
|
+
tree6.add(cidr6_5)
|
236
|
+
tree6.add(cidr6_6)
|
237
|
+
tree6.add(cidr6_7)
|
238
|
+
|
239
|
+
# show
|
240
|
+
puts "TEST 1"
|
241
|
+
puts "tree4 is..."
|
242
|
+
puts tree4.show()
|
243
|
+
print "\n"
|
244
|
+
puts "tree6 is..."
|
245
|
+
puts tree6.show()
|
246
|
+
print "\n"
|
247
|
+
|
248
|
+
# collapse
|
249
|
+
puts "TEST 2"
|
250
|
+
puts "collapsed tree4 is..."
|
251
|
+
new_tree4 = tree4.collapse()
|
252
|
+
puts new_tree4.show()
|
253
|
+
print "\n"
|
254
|
+
puts "collapsed tree6 is..."
|
255
|
+
new_tree6 = tree6.collapse()
|
256
|
+
puts new_tree6.show()
|
257
|
+
print "\n"
|
258
|
+
|
259
|
+
# find space
|
260
|
+
puts "TEST 3"
|
261
|
+
puts "available /27 space"
|
262
|
+
space = tree4.find_space(:Size => 27)
|
263
|
+
space.each do |obj|
|
264
|
+
puts " #{obj.desc}"
|
197
265
|
end
|
198
|
-
|
199
|
-
puts "
|
200
|
-
|
201
|
-
|
202
|
-
puts " #{
|
266
|
+
print "\n"
|
267
|
+
puts "available /67 space"
|
268
|
+
space = tree6.find_space(:Size => 67)
|
269
|
+
space.each do |obj|
|
270
|
+
puts " #{obj.desc}"
|
203
271
|
end
|
204
|
-
|
272
|
+
print "\n"
|
273
|
+
|
274
|
+
# remove
|
275
|
+
puts "TEST 4"
|
276
|
+
puts "removing #{cidr4_4.desc}"
|
277
|
+
tree4.remove(cidr4_4)
|
278
|
+
puts tree4.show()
|
279
|
+
print "\n"
|
280
|
+
puts "removing #{cidr6_4.desc}"
|
281
|
+
tree6.remove(cidr6_4)
|
282
|
+
puts tree6.show()
|
283
|
+
print "\n"
|
284
|
+
|
285
|
+
# prune
|
286
|
+
puts "TEST 5"
|
287
|
+
puts "pruning #{cidr4_2.desc}"
|
288
|
+
tree4.prune(cidr4_2)
|
289
|
+
|
290
|
+
puts "pruning #{cidr6_2.desc}"
|
291
|
+
tree6.prune(cidr6_2)
|
292
|
+
print "\n"
|
293
|
+
|
205
294
|
# dump
|
206
|
-
puts
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
295
|
+
puts "TEST 6"
|
296
|
+
puts "dumping & printing tree4"
|
297
|
+
dumped = tree4.dump()
|
298
|
+
dumped.each do |val|
|
299
|
+
obj = val[:Object]
|
300
|
+
depth = val[:Depth]
|
301
|
+
if (depth > 0)
|
302
|
+
indent = " " * (depth*3)
|
303
|
+
puts indent << obj.desc()
|
304
|
+
else
|
305
|
+
puts obj.desc()
|
306
|
+
end
|
215
307
|
end
|
216
|
-
|
217
|
-
puts "
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
308
|
+
print "\n"
|
309
|
+
puts "dumping & printing tree6"
|
310
|
+
dumped = tree6.dump()
|
311
|
+
dumped.each do |val|
|
312
|
+
obj = val[:Object]
|
313
|
+
depth = val[:Depth]
|
314
|
+
if (depth > 0)
|
315
|
+
indent = " " * (depth*3)
|
316
|
+
puts indent << obj.desc()
|
317
|
+
else
|
318
|
+
puts obj.desc()
|
319
|
+
end
|
222
320
|
end
|
223
321
|
|
224
322
|
print "\n\n\n"
|
@@ -232,10 +330,13 @@
|
|
232
330
|
puts "IPAdmin Methods"
|
233
331
|
|
234
332
|
# validate ip
|
333
|
+
puts "TEST 1"
|
235
334
|
puts "192.168.1.0 is valid" if ( IPAdmin.validate_ipv4_addr('192.168.1.0') )
|
236
335
|
puts "192.168.1.0 is valid" if ( IPAdmin.validate_ipv6_addr('fec0::0') )
|
336
|
+
print "\n"
|
237
337
|
|
238
338
|
# validate netmask
|
339
|
+
puts "TEST 2"
|
239
340
|
puts "255.255.255.0 is valid" if (IPAdmin.validate_ipv4_netmask('255.255.255.0') )
|
240
341
|
puts "/24 is valid" if ( IPAdmin.validate_ipv4_netmask(24) )
|
241
342
|
puts "/64 is valid" if ( IPAdmin.validate_ipv6_netmask(64) )
|
@@ -244,10 +345,12 @@
|
|
244
345
|
cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/25')
|
245
346
|
cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/10')
|
246
347
|
cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/64')
|
348
|
+
print "\n"
|
247
349
|
|
248
|
-
#
|
249
|
-
|
250
|
-
|
350
|
+
# compare
|
351
|
+
puts "TEST 3"
|
352
|
+
comp1 = IPAdmin.compare(cidr4_1,cidr4_2)
|
353
|
+
comp2 = IPAdmin.compare(cidr6_1,cidr6_2)
|
251
354
|
puts "#{(comp1[0]).desc} is the supernet of #{(comp1[1]).desc}"
|
252
355
|
puts "#{(comp2[0]).desc} is the supernet of #{(comp2[1]).desc}"
|
253
356
|
|
@@ -256,26 +359,28 @@
|
|
256
359
|
cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/128')
|
257
360
|
cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fec0::1/128')
|
258
361
|
|
259
|
-
# merge_cidr
|
260
|
-
puts "192.168.1.0/24 and 192.168.0.0/24 merge into #{IPAdmin.merge_cidr([cidr4_1,cidr4_2]).desc}"
|
261
|
-
puts "fec0::0/128 and fec0::1/128 merge into #{IPAdmin.merge_cidr([cidr6_1,cidr6_2]).desc}"
|
262
|
-
|
263
362
|
ip1 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.0')
|
264
363
|
ip2 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.50')
|
364
|
+
print "\n"
|
265
365
|
|
266
366
|
# range
|
367
|
+
puts "TEST 4"
|
267
368
|
list = IPAdmin.range(:Boundaries => [ip1,ip2], :Bitstep => 20 )
|
268
369
|
puts "ip's between #{ip1.desc} and #{ip2.desc} (bitstep of 20)"
|
269
370
|
list.each do |x|
|
270
371
|
puts " #{x}"
|
271
372
|
end
|
373
|
+
print "\n"
|
272
374
|
|
273
|
-
#
|
274
|
-
puts "
|
275
|
-
puts "arpa for #{
|
375
|
+
# arpa
|
376
|
+
puts "TEST 5"
|
377
|
+
puts "arpa for #{cidr4_1.desc()} is #{IPAdmin.arpa(cidr4_1)}"
|
378
|
+
puts "arpa for #{cidr6_1.desc()} is #{IPAdmin.arpa(cidr6_1)}"
|
379
|
+
print "\n"
|
276
380
|
|
277
|
-
#
|
278
|
-
puts "
|
381
|
+
# shorten
|
382
|
+
puts "TEST 6"
|
383
|
+
puts "shorthand notation for #{cidr6_1.network()} is #{IPAdmin.shorten(cidr6_1.network)}"
|
279
384
|
|
280
385
|
print "\n\n\n"
|
281
386
|
#=====================================#
|
data/lib/ip_admin.rb
CHANGED
@@ -1,86 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
#============================================================================#
|
6
|
-
# compare_cidr()
|
7
|
-
#============================================================================#
|
8
|
-
|
9
|
-
# Compare cidr addresses of two IPAdmin::CIDR objects.
|
10
|
-
# - Arguments:
|
11
|
-
# * Two IPAdmin::CIDR objects
|
12
|
-
#
|
13
|
-
# - Returns:
|
14
|
-
# * if one object is a subnet of another, then return an array in order of
|
15
|
-
# [supernet,subnet]
|
16
|
-
# * if both are equal, return 1
|
17
|
-
# * if neither is a subnet of the other, return nil
|
18
|
-
#
|
19
|
-
# Example:
|
20
|
-
# supernet,subnet = IPAdmin.compare_cidr(cidr1,cidr2)
|
21
|
-
# puts "#{supernet.desc} is the supernet of #{subnet.desc}"
|
22
|
-
#
|
23
|
-
|
24
|
-
def compare_cidr(cidr1,cidr2)
|
25
|
-
|
26
|
-
# we only accept CIDR objects
|
27
|
-
unless ( (cidr1.kind_of? IPAdmin::CIDR)&&(cidr2.kind_of? IPAdmin::CIDR) )
|
28
|
-
raise ArgumentError, "Arguments shouldbe of type IPAdmin::CIDR."
|
29
|
-
end
|
30
|
-
|
31
|
-
# make sure both are same version
|
32
|
-
unless (cidr1.version == cidr2.version )
|
33
|
-
raise "Provider CIDR objects are incompatible: " +
|
34
|
-
"#{cidr1.desc}/ and #{cidr2.desc}."
|
35
|
-
end
|
36
|
-
|
37
|
-
network1 = cidr1.packed_network
|
38
|
-
network2 = cidr2.packed_network
|
39
|
-
netmask1 = cidr1.packed_netmask
|
40
|
-
netmask2 = cidr2.packed_netmask
|
41
|
-
|
42
|
-
|
43
|
-
# make sure cidr's arent equal. return 1's if they are
|
44
|
-
if ( (network1 == network2) && (netmask1 == netmask2) )
|
45
|
-
return(1)
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
# whichever netmask is smaller will be the supernet
|
50
|
-
# if we '&' both networks by the supernet, and they are
|
51
|
-
# equal, then the supernet is the parent of the other network
|
52
|
-
if (netmask1 > netmask2)
|
53
|
-
if ( (netmask2 & network1) == (netmask2 & network2) )
|
54
|
-
supernet = cidr2
|
55
|
-
subnet = cidr1
|
56
|
-
end
|
57
|
-
|
58
|
-
else
|
59
|
-
if ( (netmask1 & network1) == (netmask1 & network2) )
|
60
|
-
supernet = cidr1
|
61
|
-
subnet = cidr2
|
62
|
-
end
|
1
|
+
#Copyright (c) 2006 Dustin Spinhirne <dspinhir@yahoo.com>
|
2
|
+
#Licensed under the same terms as Ruby, No Warranty is provided.
|
63
3
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
if (supernet)
|
68
|
-
return([supernet,subnet])
|
69
|
-
else
|
70
|
-
return(nil)
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
module_function :compare_cidr
|
75
|
-
|
76
|
-
#=====================================#
|
77
|
-
#
|
78
|
-
#=====================================#
|
4
|
+
module IPAdmin
|
79
5
|
|
80
6
|
|
81
7
|
|
82
8
|
#============================================================================#
|
83
|
-
#
|
9
|
+
# arpa()
|
84
10
|
#============================================================================#
|
85
11
|
|
86
12
|
# Given the address in the provided IPAdmin::IPAddr or IPAdmin::CIDR object,
|
@@ -95,9 +21,9 @@ module_function :compare_cidr
|
|
95
21
|
# * IP/CIDR address in in-addr.arpa or ip6.arpa format
|
96
22
|
#
|
97
23
|
# Example:
|
98
|
-
# arpa = IPAdmin.
|
24
|
+
# arpa = IPAdmin.arpa(cidr)
|
99
25
|
#
|
100
|
-
def
|
26
|
+
def arpa(object)
|
101
27
|
|
102
28
|
if (object.kind_of? IPAdmin::CIDR)
|
103
29
|
base = object.network()
|
@@ -149,6 +75,10 @@ def make_arpa(object)
|
|
149
75
|
return(arpa)
|
150
76
|
|
151
77
|
end
|
78
|
+
module_function :arpa
|
79
|
+
|
80
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
81
|
+
alias make_arpa arpa
|
152
82
|
module_function :make_arpa
|
153
83
|
|
154
84
|
#=====================================#
|
@@ -158,23 +88,183 @@ module_function :make_arpa
|
|
158
88
|
|
159
89
|
|
160
90
|
#============================================================================#
|
161
|
-
#
|
91
|
+
# compare()
|
162
92
|
#============================================================================#
|
163
93
|
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
94
|
+
# Compare IPAdmin::CIDR/IPAdmin::IPAddr objects, and determine if one
|
95
|
+
# is the supernet of the other. IPAdmin::IPAddr objects will use a /32 or /128
|
96
|
+
# netmask for the comparasin.
|
167
97
|
# - Arguments:
|
168
|
-
# *
|
169
|
-
#
|
98
|
+
# * Two IPAdmin::CIDR/IPAdmin::IPAddr objects
|
99
|
+
#
|
170
100
|
# - Returns:
|
171
|
-
# *
|
101
|
+
# * if one object is a subnet of another, then return an array in order of
|
102
|
+
# [supernet,subnet]
|
103
|
+
# * if both are equal, return 1
|
104
|
+
# * if neither is a supernet of the other, return nil
|
172
105
|
#
|
173
106
|
# Example:
|
174
|
-
#
|
107
|
+
# supernet,subnet = IPAdmin.compare_cidr(cidr1,cidr2)
|
108
|
+
# puts "#{supernet.desc} is the supernet of #{subnet.desc}"
|
109
|
+
#
|
110
|
+
|
111
|
+
def compare(obj1,obj2)
|
112
|
+
|
113
|
+
# we only accept CIDR or IPAddr objects
|
114
|
+
unless ( ( (obj1.kind_of?(IPAdmin::CIDR) ) ||
|
115
|
+
(obj1.kind_of?(IPAdmin::IPAddr) ) ) &&
|
116
|
+
( (obj2.kind_of?(IPAdmin::CIDR) ) ||
|
117
|
+
(obj2.kind_of?(IPAdmin::IPAddr) ) ) )
|
118
|
+
raise ArgumentError, "One or more arguments is not of type " +
|
119
|
+
"IPAdmin::CIDR or IPAdmin::IPAddr."
|
120
|
+
end
|
121
|
+
|
122
|
+
# make sure both are same version
|
123
|
+
unless (obj1.version == obj2.version )
|
124
|
+
raise "Provided objects are of different IP versions."
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# get network/netmask of each
|
129
|
+
if ( obj1.kind_of?(IPAdmin::CIDR) )
|
130
|
+
network1 = obj1.packed_network
|
131
|
+
netmask1 = obj1.packed_netmask
|
132
|
+
else
|
133
|
+
network1 = obj1.packed_ip
|
134
|
+
if (obj1.version == 4)
|
135
|
+
netmask1 = (2**32 - 1)
|
136
|
+
else
|
137
|
+
netmask1 = (2**128 - 1)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
if ( obj2.kind_of?(IPAdmin::CIDR) )
|
142
|
+
network2 = obj2.packed_network
|
143
|
+
netmask2 = obj2.packed_netmask
|
144
|
+
else
|
145
|
+
network2 = obj2.packed_ip
|
146
|
+
if (obj2.version == 4)
|
147
|
+
netmask2 = (2**32 - 1)
|
148
|
+
else
|
149
|
+
netmask2 = (2**128 - 1)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# make sure object's arent equal. return 1's if they are
|
155
|
+
if ( (network1 == network2) && (netmask1 == netmask2) )
|
156
|
+
return(1)
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
# whichever netmask is smaller will be the supernet
|
161
|
+
# if we '&' both networks by the supernet, and they are
|
162
|
+
# equal, then the supernet is the parent of the other network
|
163
|
+
if (netmask1 > netmask2)
|
164
|
+
if ( (netmask2 & network1) == (netmask2 & network2) )
|
165
|
+
supernet = obj2
|
166
|
+
subnet = obj1
|
167
|
+
end
|
168
|
+
|
169
|
+
else
|
170
|
+
if ( (netmask1 & network1) == (netmask1 & network2) )
|
171
|
+
supernet = obj1
|
172
|
+
subnet = obj2
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
if (supernet)
|
179
|
+
return([supernet,subnet])
|
180
|
+
else
|
181
|
+
return(nil)
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
module_function :compare
|
186
|
+
|
187
|
+
#=====================================#
|
188
|
+
#
|
189
|
+
#=====================================#
|
190
|
+
|
191
|
+
|
192
|
+
|
193
|
+
#============================================================================#
|
194
|
+
# compare_cidr()
|
195
|
+
#============================================================================#
|
196
|
+
|
197
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
198
|
+
#
|
199
|
+
def compare_cidr(cidr1,cidr2)
|
200
|
+
|
201
|
+
puts "compare_cidr() DEPRICATED, DO NOT USE - this will be removed in future releases."
|
202
|
+
|
203
|
+
# we only accept CIDR objects
|
204
|
+
unless ( (cidr1.kind_of? IPAdmin::CIDR)&&(cidr2.kind_of? IPAdmin::CIDR) )
|
205
|
+
raise ArgumentError, "Arguments shouldbe of type IPAdmin::CIDR."
|
206
|
+
end
|
207
|
+
|
208
|
+
# make sure both are same version
|
209
|
+
unless (cidr1.version == cidr2.version )
|
210
|
+
raise "Provider CIDR objects are incompatible: " +
|
211
|
+
"#{cidr1.desc}/ and #{cidr2.desc}."
|
212
|
+
end
|
213
|
+
|
214
|
+
network1 = cidr1.packed_network
|
215
|
+
network2 = cidr2.packed_network
|
216
|
+
netmask1 = cidr1.packed_netmask
|
217
|
+
netmask2 = cidr2.packed_netmask
|
218
|
+
|
219
|
+
|
220
|
+
# make sure cidr's arent equal. return 1's if they are
|
221
|
+
if ( (network1 == network2) && (netmask1 == netmask2) )
|
222
|
+
return(1)
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
# whichever netmask is smaller will be the supernet
|
227
|
+
# if we '&' both networks by the supernet, and they are
|
228
|
+
# equal, then the supernet is the parent of the other network
|
229
|
+
if (netmask1 > netmask2)
|
230
|
+
if ( (netmask2 & network1) == (netmask2 & network2) )
|
231
|
+
supernet = cidr2
|
232
|
+
subnet = cidr1
|
233
|
+
end
|
234
|
+
|
235
|
+
else
|
236
|
+
if ( (netmask1 & network1) == (netmask1 & network2) )
|
237
|
+
supernet = cidr1
|
238
|
+
subnet = cidr2
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
if (supernet)
|
245
|
+
return([supernet,subnet])
|
246
|
+
else
|
247
|
+
return(nil)
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
module_function :compare_cidr
|
252
|
+
|
253
|
+
#=====================================#
|
254
|
+
#
|
255
|
+
#=====================================#
|
256
|
+
|
257
|
+
|
258
|
+
|
259
|
+
#============================================================================#
|
260
|
+
# merge_cidr()
|
261
|
+
#============================================================================#
|
262
|
+
|
263
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
175
264
|
#
|
176
265
|
def merge_cidr(cidr_list)
|
177
266
|
|
267
|
+
puts "merge_cidr() DEPRICATED, DO NOT USE - this will be removed in future releases."
|
178
268
|
# make sure we have an array with at least 2 objects
|
179
269
|
unless ( (cidr_list.kind_of? Array) && (cidr_list.length > 1) )
|
180
270
|
raise ArgumentError, "Array of at least two IPAdmin::CIDR objects required."
|
@@ -641,52 +731,135 @@ module_function :range
|
|
641
731
|
|
642
732
|
|
643
733
|
#============================================================================#
|
644
|
-
#
|
734
|
+
# shorten()
|
645
735
|
#============================================================================#
|
646
736
|
|
647
|
-
#
|
648
|
-
#
|
737
|
+
# Take a standard IPv6 address, and format it in short-hand notation.
|
738
|
+
# Address should not contain a netmask.
|
649
739
|
# - Arguments:
|
650
|
-
# *
|
740
|
+
# * IPv6 address
|
651
741
|
#
|
652
742
|
# - Returns:
|
653
|
-
# *
|
654
|
-
#
|
743
|
+
# * IPv6 short-hand address.
|
744
|
+
#
|
655
745
|
# Example:
|
656
|
-
#
|
746
|
+
# short = IPAdmin.shorten('fec0:0000:0000:0000:0000:0000:0000:0001')
|
657
747
|
#
|
658
|
-
def
|
748
|
+
def shorten(addr)
|
749
|
+
|
750
|
+
# is this a string?
|
751
|
+
unless (addr.kind_of? String)
|
752
|
+
raise ArgumentError, "Expected String, but #{addr.class} provided."
|
753
|
+
end
|
754
|
+
|
755
|
+
validate_ipv6_addr(addr)
|
659
756
|
|
660
|
-
|
661
|
-
(
|
662
|
-
|
663
|
-
octets[x] = (octets[x]).to_s
|
664
|
-
packed_ip = packed_ip >> 8
|
757
|
+
# make sure this isnt already shorthand
|
758
|
+
if (addr =~ /::/)
|
759
|
+
raise "#{addr} already appears to be in IPv6 shorthand notation."
|
665
760
|
end
|
666
761
|
|
667
|
-
octets.reverse!
|
668
|
-
ip = octets.join('.')
|
669
762
|
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
763
|
+
# look for most 0 fields
|
764
|
+
found_zero = nil
|
765
|
+
pattern = ""
|
766
|
+
zero_fields = []
|
767
|
+
fields = addr.split(":")
|
768
|
+
|
769
|
+
(0..(fields.length-1)).each do |x|
|
770
|
+
fields[x] = fields[x].to_i(16)
|
771
|
+
|
772
|
+
if (fields[x] == 0)
|
773
|
+
if (!found_zero)
|
774
|
+
found_zero = 1
|
775
|
+
end
|
776
|
+
pattern << ":0"
|
777
|
+
else
|
778
|
+
if (found_zero)
|
779
|
+
found_zero = nil
|
780
|
+
pattern << ":"
|
781
|
+
zero_fields.push(pattern)
|
782
|
+
pattern = ""
|
783
|
+
end
|
784
|
+
end
|
785
|
+
|
786
|
+
fields[x] = fields[x].to_s(16)
|
787
|
+
end
|
788
|
+
|
789
|
+
|
790
|
+
# pattern should be the longest set of 0's in a row
|
791
|
+
zero_fields.push(pattern) if (pattern != "")
|
792
|
+
pattern = ""
|
793
|
+
zero_fields.each do |x|
|
794
|
+
pattern = x if (x.length > pattern.length)
|
795
|
+
end
|
796
|
+
|
797
|
+
|
798
|
+
|
799
|
+
short = fields.join(":")
|
800
|
+
short.sub!(pattern,"::")
|
801
|
+
|
802
|
+
return(short)
|
803
|
+
end
|
804
|
+
module_function :shorten
|
805
|
+
|
806
|
+
#DEPRICATED, DO NOT USE - this will be removed in future releases.
|
807
|
+
alias v6_short shorten
|
808
|
+
module_function :v6_short
|
809
|
+
|
810
|
+
#=====================================#
|
811
|
+
#
|
812
|
+
#=====================================#
|
813
|
+
|
814
|
+
|
815
|
+
|
816
|
+
#============================================================================#
|
817
|
+
# unpack_ipv4_addr()
|
818
|
+
#============================================================================#
|
819
|
+
|
820
|
+
# Unack IPv4 address back into a printable string. No attempt at validation
|
821
|
+
# is performed.
|
822
|
+
# - Arguments:
|
823
|
+
# * Byte-packed IPv4 address
|
824
|
+
#
|
825
|
+
# - Returns:
|
826
|
+
# * IPv4 address.
|
827
|
+
#
|
828
|
+
# Example:
|
829
|
+
# unpacked = IPAdmin.unpack_ipv4_addr(packed)
|
830
|
+
#
|
831
|
+
def unpack_ipv4_addr(packed_ip)
|
832
|
+
|
833
|
+
octets = []
|
834
|
+
(0..3).each do |x|
|
835
|
+
octets[x] = packed_ip & 0xFF
|
836
|
+
octets[x] = (octets[x]).to_s
|
837
|
+
packed_ip = packed_ip >> 8
|
838
|
+
end
|
839
|
+
|
840
|
+
octets.reverse!
|
841
|
+
ip = octets.join('.')
|
842
|
+
|
843
|
+
return(ip)
|
844
|
+
end
|
845
|
+
module_function :unpack_ipv4_addr
|
846
|
+
|
847
|
+
#=====================================#
|
848
|
+
#
|
849
|
+
#=====================================#
|
850
|
+
|
851
|
+
|
852
|
+
|
853
|
+
#============================================================================#
|
854
|
+
# unpack_ipv4_netmask()
|
855
|
+
#============================================================================#
|
856
|
+
|
857
|
+
# Unack IPv4 netmask into a integer representing the number of
|
858
|
+
# bits in the CIDR mask. No attempt at validation is performed.
|
859
|
+
# - Arguments:
|
860
|
+
# * Byte-packed IPv4 netmask
|
861
|
+
#
|
862
|
+
# - Returns:
|
690
863
|
# * IPv4 netmask as number of bits (cidr format).
|
691
864
|
#
|
692
865
|
# Example:
|
@@ -790,85 +963,6 @@ module_function :unpack_ipv6_netmask
|
|
790
963
|
|
791
964
|
|
792
965
|
|
793
|
-
#============================================================================#
|
794
|
-
# v6_short()
|
795
|
-
#============================================================================#
|
796
|
-
|
797
|
-
# Take a standard IPv6 address, and format it in short-hand notation.
|
798
|
-
# Address should not contain a netmask.
|
799
|
-
# - Arguments:
|
800
|
-
# * IPv6 address
|
801
|
-
#
|
802
|
-
# - Returns:
|
803
|
-
# * IPv6 short-hand address.
|
804
|
-
#
|
805
|
-
# Example:
|
806
|
-
# short = IPAdmin.v6_short('fec0:0000:0000:0000:0000:0000:0000:0001')
|
807
|
-
#
|
808
|
-
def v6_short(addr)
|
809
|
-
|
810
|
-
# is this a string?
|
811
|
-
unless (addr.kind_of? String)
|
812
|
-
raise ArgumentError, "Expected String, but #{addr.class} provided."
|
813
|
-
end
|
814
|
-
|
815
|
-
validate_ipv6_addr(addr)
|
816
|
-
|
817
|
-
# make sure this isnt already shorthand
|
818
|
-
if (addr =~ /::/)
|
819
|
-
raise "#{addr} already appears to be in IPv6 shorthand notation."
|
820
|
-
end
|
821
|
-
|
822
|
-
|
823
|
-
# look for most 0 fields
|
824
|
-
found_zero = nil
|
825
|
-
pattern = ""
|
826
|
-
zero_fields = []
|
827
|
-
fields = addr.split(":")
|
828
|
-
|
829
|
-
(0..(fields.length-1)).each do |x|
|
830
|
-
fields[x] = fields[x].to_i(16)
|
831
|
-
|
832
|
-
if (fields[x] == 0)
|
833
|
-
if (!found_zero)
|
834
|
-
found_zero = 1
|
835
|
-
end
|
836
|
-
pattern << ":0"
|
837
|
-
else
|
838
|
-
if (found_zero)
|
839
|
-
found_zero = nil
|
840
|
-
pattern << ":"
|
841
|
-
zero_fields.push(pattern)
|
842
|
-
pattern = ""
|
843
|
-
end
|
844
|
-
end
|
845
|
-
|
846
|
-
fields[x] = fields[x].to_s(16)
|
847
|
-
end
|
848
|
-
|
849
|
-
|
850
|
-
# pattern should be the longest set of 0's in a row
|
851
|
-
zero_fields.push(pattern) if (pattern != "")
|
852
|
-
pattern = ""
|
853
|
-
zero_fields.each do |x|
|
854
|
-
pattern = x if (x.length > pattern.length)
|
855
|
-
end
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
short = fields.join(":")
|
860
|
-
short.sub!(pattern,"::")
|
861
|
-
|
862
|
-
return(short)
|
863
|
-
end
|
864
|
-
module_function :v6_short
|
865
|
-
|
866
|
-
#=====================================#
|
867
|
-
#
|
868
|
-
#=====================================#
|
869
|
-
|
870
|
-
|
871
|
-
|
872
966
|
#============================================================================#
|
873
967
|
# validate_ipv4_addr()
|
874
968
|
#============================================================================#
|
@@ -1184,7 +1278,11 @@ class CIDR
|
|
1184
1278
|
# hash of custom tags. should be in the format tag => value
|
1185
1279
|
attr_reader :tag
|
1186
1280
|
|
1187
|
-
#
|
1281
|
+
# Hash of custom tags. should be in the format tag => value
|
1282
|
+
#
|
1283
|
+
# Example:
|
1284
|
+
# cidr4.tag['test'] = 'modified cidr4 tag'
|
1285
|
+
#
|
1188
1286
|
def tag=(new_tag)
|
1189
1287
|
unless (new_tag.kind_of? Hash)
|
1190
1288
|
raise ArgumentError, "Expected Hash, but #{new_tag.class} provided."
|
@@ -1347,8 +1445,8 @@ class CIDR
|
|
1347
1445
|
# contains()
|
1348
1446
|
#============================================================================#
|
1349
1447
|
|
1350
|
-
# Determines if
|
1351
|
-
#
|
1448
|
+
# Determines if IPAdmin::CIDR object contains (is supernet of)
|
1449
|
+
# provided IPAdmin::CIDR or IPAdmin:IPAddr object.
|
1352
1450
|
# - Arguments:
|
1353
1451
|
# * IPAdmin:IPAddr object
|
1354
1452
|
#
|
@@ -1358,32 +1456,46 @@ class CIDR
|
|
1358
1456
|
# Example:
|
1359
1457
|
# contains = cidr.contains(ip)
|
1360
1458
|
#
|
1361
|
-
def contains(
|
1459
|
+
def contains(object)
|
1460
|
+
is_contained = nil
|
1362
1461
|
|
1363
|
-
|
1364
|
-
|
1462
|
+
if (object.kind_of?(IPAdmin::CIDR))
|
1463
|
+
network = object.packed_network
|
1464
|
+
netmask = object.packed_netmask
|
1465
|
+
|
1466
|
+
elsif (object.kind_of?(IPAdmin::IPAddr))
|
1467
|
+
network = object.packed_ip
|
1468
|
+
|
1469
|
+
else
|
1470
|
+
raise ArgumentError, "Expected IPAdmin::CIDR or IPAdmin::IPAddr " +
|
1471
|
+
" object but #{object.class} provided."
|
1365
1472
|
end
|
1366
1473
|
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1474
|
+
|
1475
|
+
unless (object.version == @version)
|
1476
|
+
raise "Attempted to compare a version #{object.version} IP " +
|
1477
|
+
"with a version #{@version} network."
|
1478
|
+
end
|
1479
|
+
|
1480
|
+
|
1481
|
+
# if network == @network, then we have to go by netmask length
|
1482
|
+
# else we can tell by or'ing network and @network by @hostmask
|
1483
|
+
# and comparing the results
|
1484
|
+
if (network == @network)
|
1485
|
+
if (object.kind_of?(IPAdmin::IPAddr) )
|
1486
|
+
is_contained = 1
|
1487
|
+
else
|
1488
|
+
is_contained = 1 if (netmask > @netmask)
|
1372
1489
|
end
|
1373
1490
|
|
1374
|
-
elsif ( (ip_obj.version == 6) && (@version == 6) )
|
1375
|
-
v6_all_f = (2**128)-1
|
1376
|
-
hostmask = @netmask ^ v6_all_f
|
1377
|
-
if ( (ip_obj.packed_ip | hostmask) == (@network | hostmask) )
|
1378
|
-
return(1)
|
1379
|
-
end
|
1380
|
-
|
1381
1491
|
else
|
1382
|
-
|
1383
|
-
|
1492
|
+
if ( (network | @hostmask) == (@network | @hostmask) )
|
1493
|
+
is_contained = 1
|
1494
|
+
end
|
1384
1495
|
end
|
1385
1496
|
|
1386
|
-
|
1497
|
+
|
1498
|
+
return(is_contained)
|
1387
1499
|
end
|
1388
1500
|
|
1389
1501
|
#=====================================#
|
@@ -1990,8 +2102,7 @@ end
|
|
1990
2102
|
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
1991
2103
|
|
1992
2104
|
=begin rdoc
|
1993
|
-
|
1994
|
-
heirarchical tables. Both IPv4 and IPv6 are supported.
|
2105
|
+
DEPRICATED, DO NOT USE - this will be removed in future releases.
|
1995
2106
|
=end
|
1996
2107
|
|
1997
2108
|
class CIDRTable
|
@@ -2002,11 +2113,8 @@ class CIDRTable
|
|
2002
2113
|
# attr_reader / attr_writer
|
2003
2114
|
#============================================================================#
|
2004
2115
|
|
2005
|
-
|
2006
|
-
|
2007
|
-
attr_reader :version
|
2008
|
-
|
2009
|
-
# contains IPAdmin::CIDR entries. hash (IPAdmin::CIDR => IPAdmin::CIDRTable)
|
2116
|
+
# attr_reader/attr_writer
|
2117
|
+
attr_reader :version
|
2010
2118
|
attr_reader :cidr_table
|
2011
2119
|
|
2012
2120
|
#=====================================#
|
@@ -2019,14 +2127,11 @@ class CIDRTable
|
|
2019
2127
|
# initialize()
|
2020
2128
|
#============================================================================#
|
2021
2129
|
|
2022
|
-
# -
|
2023
|
-
# * IP version (4 or 6)
|
2130
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
2024
2131
|
#
|
2025
|
-
# Example:
|
2026
|
-
# table = IPAdmin::CIDRTable.new(4)
|
2027
|
-
#
|
2028
2132
|
def initialize(version)
|
2029
2133
|
|
2134
|
+
puts "DEPRICATED, DO NOT USE - this will be removed in future releases."
|
2030
2135
|
unless ( version.kind_of? Fixnum )
|
2031
2136
|
raise ArgumentError, "Expected Fixnum, but #{version.class} provided."
|
2032
2137
|
end
|
@@ -2049,16 +2154,7 @@ class CIDRTable
|
|
2049
2154
|
# add_cidr()
|
2050
2155
|
#============================================================================#
|
2051
2156
|
|
2052
|
-
#
|
2053
|
-
#
|
2054
|
-
# - Arguments:
|
2055
|
-
# * IPAdmin::CIDR object
|
2056
|
-
#
|
2057
|
-
# - Returns:
|
2058
|
-
# * nothing
|
2059
|
-
#
|
2060
|
-
# Example:
|
2061
|
-
# table.add_cidr(cidr)
|
2157
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
2062
2158
|
#
|
2063
2159
|
def add_cidr(new_cidr)
|
2064
2160
|
|
@@ -2134,16 +2230,7 @@ class CIDRTable
|
|
2134
2230
|
# dump()
|
2135
2231
|
#============================================================================#
|
2136
2232
|
|
2137
|
-
#
|
2138
|
-
#
|
2139
|
-
# - Arguments:
|
2140
|
-
# * none
|
2141
|
-
#
|
2142
|
-
# - Returns:
|
2143
|
-
# * ordered array of IPAdmin::CIDR objects within this table
|
2144
|
-
#
|
2145
|
-
# Example:
|
2146
|
-
# cidr_list = table.dump()
|
2233
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
2147
2234
|
#
|
2148
2235
|
def dump()
|
2149
2236
|
|
@@ -2182,17 +2269,7 @@ class CIDRTable
|
|
2182
2269
|
# find_ip()
|
2183
2270
|
#============================================================================#
|
2184
2271
|
|
2185
|
-
#
|
2186
|
-
# address within the provided IPAdmin::IPAddr object
|
2187
|
-
#
|
2188
|
-
# - Arguments:
|
2189
|
-
# * IPAdmin::IPAddr object
|
2190
|
-
#
|
2191
|
-
# - Returns:
|
2192
|
-
# * IPAdmin::CIDR object, or nil on no match
|
2193
|
-
#
|
2194
|
-
# Example:
|
2195
|
-
# cidr = table.find_ip(ip)
|
2272
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
2196
2273
|
#
|
2197
2274
|
def find_ip(ip_obj)
|
2198
2275
|
|
@@ -2232,19 +2309,7 @@ class CIDRTable
|
|
2232
2309
|
# find_space()
|
2233
2310
|
#============================================================================#
|
2234
2311
|
|
2235
|
-
#
|
2236
|
-
# subnets of each supernet.
|
2237
|
-
#
|
2238
|
-
# - Arguments:
|
2239
|
-
# * Hash with the following fields:
|
2240
|
-
# - :Size -- subnet size (number of bits)
|
2241
|
-
# - :Limit -- max entries to return
|
2242
|
-
#
|
2243
|
-
# - Returns:
|
2244
|
-
# * ordered array of IPAdmin::CIDR objects, or nil on no match
|
2245
|
-
#
|
2246
|
-
# Example:
|
2247
|
-
# cidr_list = table.find_space(:Size => 27)
|
2312
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
2248
2313
|
#
|
2249
2314
|
def find_space(options)
|
2250
2315
|
limit = nil
|
@@ -2338,16 +2403,7 @@ class CIDRTable
|
|
2338
2403
|
# rem_cidr()
|
2339
2404
|
#============================================================================#
|
2340
2405
|
|
2341
|
-
#
|
2342
|
-
#
|
2343
|
-
# - Arguments:
|
2344
|
-
# * IPAdmin::CIDR object
|
2345
|
-
#
|
2346
|
-
# - Returns:
|
2347
|
-
# * nothing
|
2348
|
-
#
|
2349
|
-
# Example:
|
2350
|
-
# table.rem_cidr(cidr)
|
2406
|
+
# DEPRICATED, DO NOT USE - this will be removed in future releases.
|
2351
2407
|
#
|
2352
2408
|
def rem_cidr(cidr)
|
2353
2409
|
|
@@ -2434,7 +2490,11 @@ class IPAddr
|
|
2434
2490
|
# hash of custom tags. should be in the format tag => value
|
2435
2491
|
attr_reader :tag
|
2436
2492
|
|
2437
|
-
#
|
2493
|
+
# Hash of custom tags. should be in the format tag => value
|
2494
|
+
#
|
2495
|
+
# Example:
|
2496
|
+
# ip4.tag['test'] = 'modified ip4 tag'
|
2497
|
+
#
|
2438
2498
|
def tag=(new_tag)
|
2439
2499
|
unless (new_tag.kind_of? Hash)
|
2440
2500
|
raise ArgumentError, "Expected Hash, but #{new_tag.class} provided."
|
@@ -2911,6 +2971,883 @@ end
|
|
2911
2971
|
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
2912
2972
|
|
2913
2973
|
|
2974
|
+
|
2975
|
+
|
2976
|
+
|
2977
|
+
|
2978
|
+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
2979
|
+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
2980
|
+
#
|
2981
|
+
# BEGIN class Tree
|
2982
|
+
#
|
2983
|
+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
2984
|
+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
2985
|
+
|
2986
|
+
=begin rdoc
|
2987
|
+
A class & series of methods for creating and manipulating IP-based
|
2988
|
+
heirarchical trees. Both IPv4 and IPv6 are supported.
|
2989
|
+
=end
|
2990
|
+
|
2991
|
+
class Tree
|
2992
|
+
|
2993
|
+
# define structure for our tree leaves
|
2994
|
+
NetStruct = Struct.new(:network, :netmask, :object, :subnets)
|
2995
|
+
|
2996
|
+
#============================================================================#
|
2997
|
+
# attr_reader / attr_writer
|
2998
|
+
#============================================================================#
|
2999
|
+
|
3000
|
+
|
3001
|
+
# IP version for this tree (4 or 6)
|
3002
|
+
attr_reader :version
|
3003
|
+
|
3004
|
+
#=====================================#
|
3005
|
+
#
|
3006
|
+
#=====================================#
|
3007
|
+
|
3008
|
+
|
3009
|
+
|
3010
|
+
#============================================================================#
|
3011
|
+
# initialize()
|
3012
|
+
#============================================================================#
|
3013
|
+
|
3014
|
+
# - Arguments:
|
3015
|
+
# * Hash with the following fields
|
3016
|
+
# - :Version -- IP version for this tree (4 or 6)
|
3017
|
+
#
|
3018
|
+
# Example:
|
3019
|
+
# table = IPAdmin::CIDRTable.new(:Version => 4)
|
3020
|
+
#
|
3021
|
+
def initialize(options)
|
3022
|
+
unless (options.kind_of? Hash)
|
3023
|
+
raise ArgumentError, "Expected Hash, but #{options.class} provided."
|
3024
|
+
end
|
3025
|
+
|
3026
|
+
if ( options.has_key?(:Version) )
|
3027
|
+
@version = options[:Version]
|
3028
|
+
|
3029
|
+
unless ( @version == 4 || @version == 6 )
|
3030
|
+
raise "IP version should be either 4 or 6."
|
3031
|
+
end
|
3032
|
+
else
|
3033
|
+
raise ArgumentError, "Missing arguments: Version."
|
3034
|
+
end
|
3035
|
+
|
3036
|
+
if (@version == 4)
|
3037
|
+
@all_f = 2**32 - 1
|
3038
|
+
else
|
3039
|
+
@all_f = 2**128 - 1
|
3040
|
+
end
|
3041
|
+
|
3042
|
+
# root of our ordered IP tree
|
3043
|
+
@root = []
|
3044
|
+
|
3045
|
+
end
|
3046
|
+
|
3047
|
+
#=====================================#
|
3048
|
+
#
|
3049
|
+
#=====================================#
|
3050
|
+
|
3051
|
+
|
3052
|
+
|
3053
|
+
#============================================================================#
|
3054
|
+
# add()
|
3055
|
+
#============================================================================#
|
3056
|
+
|
3057
|
+
# Add an IPAdmin::CIDR/IPAdmin::IPAddr object to the tree. IPAdmin::IPAddr
|
3058
|
+
# objects will be treated as either /32 or /128 addresses when added to the
|
3059
|
+
# tree.
|
3060
|
+
#
|
3061
|
+
# - Arguments:
|
3062
|
+
# * IPAdmin::CIDR/IPAdmin::IPAddr object
|
3063
|
+
#
|
3064
|
+
# - Returns:
|
3065
|
+
# * nothing
|
3066
|
+
#
|
3067
|
+
# Example:
|
3068
|
+
# tree.add(cidr)
|
3069
|
+
#
|
3070
|
+
def add(object)
|
3071
|
+
|
3072
|
+
# make sure we have an array with at least 2 objects
|
3073
|
+
unless ( object.kind_of?(IPAdmin::CIDR) ||
|
3074
|
+
object.kind_of?(IPAdmin::IPAddr) )
|
3075
|
+
raise ArgumentError, "IPAdmin::CIDR/IPAdmin::IPAddr object " +
|
3076
|
+
"required but #{object.class} provided."
|
3077
|
+
end
|
3078
|
+
|
3079
|
+
unless (object.version == @version )
|
3080
|
+
raise "IP version #{object.version} is incompatible with " +
|
3081
|
+
"Tree IP version #{@version}."
|
3082
|
+
end
|
3083
|
+
|
3084
|
+
|
3085
|
+
net_struct = create_struct(object)
|
3086
|
+
|
3087
|
+
|
3088
|
+
# search tree for it's home branch
|
3089
|
+
search_results = find_home(net_struct, @root)
|
3090
|
+
home_struct = search_results[0] if (search_results)
|
3091
|
+
home_branch = home_struct.subnets if (search_results)
|
3092
|
+
home_branch = @root if (!home_branch)
|
3093
|
+
|
3094
|
+
# make sure we dont have a duplicate
|
3095
|
+
if (home_struct)
|
3096
|
+
if ( (net_struct.network == home_struct.network) &&
|
3097
|
+
(net_struct.netmask == home_struct.netmask) )
|
3098
|
+
raise "Attempted to add #{object.desc()} multiple times."
|
3099
|
+
end
|
3100
|
+
end
|
3101
|
+
|
3102
|
+
|
3103
|
+
# now that we have our branch location, check that other entries
|
3104
|
+
# of this branch are not subnets of our new object. if they are
|
3105
|
+
# then make them a branch of our new object
|
3106
|
+
home_branch.each do |entry|
|
3107
|
+
is_contained = contains(net_struct, entry)
|
3108
|
+
|
3109
|
+
if (is_contained)
|
3110
|
+
net_struct.subnets.push(entry)
|
3111
|
+
end
|
3112
|
+
end
|
3113
|
+
|
3114
|
+
net_struct.subnets.each do |entry|
|
3115
|
+
home_branch.delete(entry)
|
3116
|
+
end
|
3117
|
+
|
3118
|
+
|
3119
|
+
# add new object as an ordered entry to home_branch
|
3120
|
+
add_to_branch(net_struct,home_branch)
|
3121
|
+
|
3122
|
+
return(nil)
|
3123
|
+
end
|
3124
|
+
|
3125
|
+
#=====================================#
|
3126
|
+
#
|
3127
|
+
#=====================================#
|
3128
|
+
|
3129
|
+
|
3130
|
+
|
3131
|
+
#============================================================================#
|
3132
|
+
# add_to_branch() private
|
3133
|
+
#============================================================================#
|
3134
|
+
|
3135
|
+
# Add Netstruct object to an array of NetStruct's
|
3136
|
+
#
|
3137
|
+
# - Arguments:
|
3138
|
+
# * NetStruct, and array of NetStruct's in which to add it
|
3139
|
+
#
|
3140
|
+
# - Returns:
|
3141
|
+
# * none
|
3142
|
+
#
|
3143
|
+
# Example:
|
3144
|
+
# add_to_branch(net_struct,branch)
|
3145
|
+
#
|
3146
|
+
def add_to_branch(net_struct,branch)
|
3147
|
+
index = 0
|
3148
|
+
branch.each do
|
3149
|
+
if(net_struct.network < (branch[index]).network)
|
3150
|
+
break
|
3151
|
+
end
|
3152
|
+
index += 1
|
3153
|
+
end
|
3154
|
+
|
3155
|
+
branch.insert(index, net_struct)
|
3156
|
+
|
3157
|
+
return()
|
3158
|
+
end
|
3159
|
+
|
3160
|
+
#=====================================#
|
3161
|
+
#
|
3162
|
+
#=====================================#
|
3163
|
+
|
3164
|
+
|
3165
|
+
|
3166
|
+
#============================================================================#
|
3167
|
+
# collapse()
|
3168
|
+
#============================================================================#
|
3169
|
+
|
3170
|
+
# Collapse (supernet) all subnets of the tree,
|
3171
|
+
# and return a new tree. The supernetting of subnets will only occur in
|
3172
|
+
# situations where the newly created supernet will not result in the
|
3173
|
+
# 'creation' of additional space. For example the following blocks
|
3174
|
+
# (192.168.0.0/24, 192.168.1.0/24, and 192.168.2.0/24) would merge into
|
3175
|
+
# 192.168.0.0/23 and 192.168.2.0/24 rather than into 192.168.0.0/22.
|
3176
|
+
#
|
3177
|
+
# - Arguments:
|
3178
|
+
# * none
|
3179
|
+
#
|
3180
|
+
# - Returns:
|
3181
|
+
# * IPAdmin::Tree object
|
3182
|
+
#
|
3183
|
+
# Example:
|
3184
|
+
# new_tree = tree.collapse()
|
3185
|
+
#
|
3186
|
+
def collapse()
|
3187
|
+
tree = IPAdmin::Tree.new(:Version => @version)
|
3188
|
+
branch = collapse_branch(@root)
|
3189
|
+
dumped = dump_branch(branch)
|
3190
|
+
dumped.each do |entry|
|
3191
|
+
net_struct = entry[:NetStruct]
|
3192
|
+
|
3193
|
+
if (@version == 4)
|
3194
|
+
network = IPAdmin.unpack_ipv4_addr(net_struct.network)
|
3195
|
+
netmask = IPAdmin.unpack_ipv4_netmask(net_struct.netmask)
|
3196
|
+
else
|
3197
|
+
network = IPAdmin.unpack_ipv6_addr(net_struct.network)
|
3198
|
+
netmask = IPAdmin.unpack_ipv6_netmask(net_struct.netmask)
|
3199
|
+
end
|
3200
|
+
cidr = IPAdmin::CIDR.new(:CIDR => "#{network}/#{netmask}")
|
3201
|
+
tree.add(cidr)
|
3202
|
+
end
|
3203
|
+
return(tree)
|
3204
|
+
end
|
3205
|
+
|
3206
|
+
#=====================================#
|
3207
|
+
#
|
3208
|
+
#=====================================#
|
3209
|
+
|
3210
|
+
|
3211
|
+
|
3212
|
+
#============================================================================#
|
3213
|
+
# collapse_branch() private
|
3214
|
+
#============================================================================#
|
3215
|
+
|
3216
|
+
# Collapse this branch, and any child branches that it may have.
|
3217
|
+
#
|
3218
|
+
# - Arguments:
|
3219
|
+
# * Array of NetStruct objects
|
3220
|
+
#
|
3221
|
+
# - Returns:
|
3222
|
+
# * Array of NetStruct objects. The 'object' filed will be null.
|
3223
|
+
#
|
3224
|
+
# Example:
|
3225
|
+
# new_branch = collapse_branch(old_branch)
|
3226
|
+
#
|
3227
|
+
def collapse_branch(old_branch)
|
3228
|
+
new_branch = []
|
3229
|
+
|
3230
|
+
# create new_branch from old one
|
3231
|
+
old_branch.each do |entry|
|
3232
|
+
net_struct = NetStruct.new(entry.network,entry.netmask,nil,[])
|
3233
|
+
|
3234
|
+
if (entry.subnets.length > 0)
|
3235
|
+
# get all child subnets of this branch entry
|
3236
|
+
children = collapse_branch(entry.subnets)
|
3237
|
+
grandchildren = nil
|
3238
|
+
|
3239
|
+
# if any child subnets are equal to this branch entry
|
3240
|
+
# then copy the grandchild subnets and delete it
|
3241
|
+
children.each do |child|
|
3242
|
+
if ( (entry.network == child.network) &&
|
3243
|
+
(entry.netmask == child.netmask) )
|
3244
|
+
if (child.subnets.length > 0)
|
3245
|
+
grandchildren = child.subnets
|
3246
|
+
end
|
3247
|
+
children.delete(child)
|
3248
|
+
break
|
3249
|
+
end
|
3250
|
+
end
|
3251
|
+
|
3252
|
+
net_struct.subnets.concat(children)
|
3253
|
+
if (grandchildren)
|
3254
|
+
grandchildren.each do |grandchild|
|
3255
|
+
add_to_branch(grandchild,net_struct.subnets)
|
3256
|
+
end
|
3257
|
+
end
|
3258
|
+
end
|
3259
|
+
|
3260
|
+
new_branch.push(net_struct)
|
3261
|
+
end
|
3262
|
+
|
3263
|
+
# merge subnets of this new branch by removing them from 'new_branch',
|
3264
|
+
# and categorizing them into hash of arrays (key=netmask)
|
3265
|
+
# within each categorization we merge contiguous subnets
|
3266
|
+
# and then remove them from that category & put them back into
|
3267
|
+
# 'new_branch'. we do this until our list stops getting any shorter
|
3268
|
+
categories = {}
|
3269
|
+
branch_length = 0
|
3270
|
+
until (branch_length == new_branch.length)
|
3271
|
+
branch_length = new_branch.length
|
3272
|
+
|
3273
|
+
# bust in to categories
|
3274
|
+
new_branch.each do |entry|
|
3275
|
+
netmask = entry.netmask
|
3276
|
+
if (categories.has_key?(netmask) )
|
3277
|
+
(categories[netmask]).push(entry)
|
3278
|
+
else
|
3279
|
+
categories[netmask] = [entry]
|
3280
|
+
end
|
3281
|
+
end
|
3282
|
+
new_branch.clear
|
3283
|
+
|
3284
|
+
categories.each_key do |netmask|
|
3285
|
+
entries = categories[netmask]
|
3286
|
+
|
3287
|
+
until (entries.length == 0)
|
3288
|
+
supernet = nil
|
3289
|
+
supermask = nil
|
3290
|
+
multiplier = 0
|
3291
|
+
first = entries[0]
|
3292
|
+
to_merge = []
|
3293
|
+
|
3294
|
+
# take first entry and use it to form a base
|
3295
|
+
# supernet address. this supernet should have
|
3296
|
+
# x number of subnets in it, so we look for
|
3297
|
+
# those subnets & if found store them
|
3298
|
+
entries.each do |entry|
|
3299
|
+
num_required = 2**multiplier
|
3300
|
+
supermask = (netmask << multiplier) & @all_f
|
3301
|
+
supernet = supermask & first.network if (!supernet)
|
3302
|
+
|
3303
|
+
if ( (entry.network & supermask) == supernet)
|
3304
|
+
to_merge.push(entry)
|
3305
|
+
if ( (to_merge.length == num_required) &&
|
3306
|
+
(entries.length > (2**multiplier) ) )
|
3307
|
+
multiplier += 1
|
3308
|
+
end
|
3309
|
+
else
|
3310
|
+
multiplier -= 1
|
3311
|
+
supermask = (netmask << multiplier) & @all_f
|
3312
|
+
break
|
3313
|
+
end
|
3314
|
+
end
|
3315
|
+
|
3316
|
+
# now that we have the child members of our new supernet
|
3317
|
+
# take any grandchild subnets that they may have and
|
3318
|
+
# add them to the new supernet. then kill the children
|
3319
|
+
net_struct = NetStruct.new(supernet,supermask,nil,[])
|
3320
|
+
(2**multiplier).times do
|
3321
|
+
to_kill = to_merge.shift
|
3322
|
+
net_struct.subnets.concat(to_kill.subnets)
|
3323
|
+
entries.delete(to_kill)
|
3324
|
+
end
|
3325
|
+
new_branch.push(net_struct)
|
3326
|
+
|
3327
|
+
end
|
3328
|
+
end
|
3329
|
+
categories.clear
|
3330
|
+
end
|
3331
|
+
|
3332
|
+
return(new_branch)
|
3333
|
+
end
|
3334
|
+
|
3335
|
+
#=====================================#
|
3336
|
+
#
|
3337
|
+
#=====================================#
|
3338
|
+
|
3339
|
+
|
3340
|
+
|
3341
|
+
#============================================================================#
|
3342
|
+
# contains() private
|
3343
|
+
#============================================================================#
|
3344
|
+
|
3345
|
+
# Is the first NetStruct object the supernet of the second?
|
3346
|
+
#
|
3347
|
+
# - Arguments:
|
3348
|
+
# * Two NetStruct objects
|
3349
|
+
#
|
3350
|
+
# - Returns:
|
3351
|
+
# * 1 if struct1 contains or is equal to struct2, or nil if not.
|
3352
|
+
#
|
3353
|
+
# Example:
|
3354
|
+
# is_contained = contains(struct1,struct2)
|
3355
|
+
#
|
3356
|
+
def contains(struct1,struct2)
|
3357
|
+
|
3358
|
+
# make sure we have appropriate types
|
3359
|
+
unless (struct1.kind_of?(IPAdmin::Tree::NetStruct) &&
|
3360
|
+
struct2.kind_of?(IPAdmin::Tree::NetStruct) )
|
3361
|
+
raise ArgumentError, "Incorrect argument types " +
|
3362
|
+
"#{struct1.class} and #{struct2.class}."
|
3363
|
+
end
|
3364
|
+
|
3365
|
+
network1 = struct1.network
|
3366
|
+
netmask1 = struct1.netmask
|
3367
|
+
network2 = struct2.network
|
3368
|
+
netmask2 = struct2.netmask
|
3369
|
+
hostmask1 = netmask1 ^ @all_f
|
3370
|
+
|
3371
|
+
|
3372
|
+
# if network1 == network2, then we have to go by netmask length
|
3373
|
+
# else we can tell by or'ing network1 and network2 by hostmask1
|
3374
|
+
# and comparing the results
|
3375
|
+
is_contained = nil
|
3376
|
+
if (network1 == network2)
|
3377
|
+
if (netmask2 >= netmask1)
|
3378
|
+
is_contained = 1
|
3379
|
+
end
|
3380
|
+
else
|
3381
|
+
if ( (network1 | hostmask1) == (network2 | hostmask1) )
|
3382
|
+
is_contained = 1
|
3383
|
+
end
|
3384
|
+
end
|
3385
|
+
|
3386
|
+
return(is_contained)
|
3387
|
+
end
|
3388
|
+
|
3389
|
+
#=====================================#
|
3390
|
+
#
|
3391
|
+
#=====================================#
|
3392
|
+
|
3393
|
+
|
3394
|
+
|
3395
|
+
#============================================================================#
|
3396
|
+
# create_struct() private
|
3397
|
+
#============================================================================#
|
3398
|
+
|
3399
|
+
# Create a NetStruct object from a CIDR or IPAddr object
|
3400
|
+
#
|
3401
|
+
# - Arguments:
|
3402
|
+
# * IPAdmin::CIDR or IPAdmin::IPAddr object
|
3403
|
+
#
|
3404
|
+
# - Returns:
|
3405
|
+
# * IPAdmin::Tree::NetStruct object
|
3406
|
+
#
|
3407
|
+
# Example:
|
3408
|
+
# net_struct = create_struct(object)
|
3409
|
+
#
|
3410
|
+
def create_struct(object)
|
3411
|
+
|
3412
|
+
if ( object.kind_of?(IPAdmin::CIDR) )
|
3413
|
+
network = object.packed_network
|
3414
|
+
netmask = object.packed_netmask
|
3415
|
+
|
3416
|
+
elsif ( object.kind_of?(IPAdmin::IPAddr) )
|
3417
|
+
network = object.packed_ip
|
3418
|
+
netmask = @all_f
|
3419
|
+
end
|
3420
|
+
|
3421
|
+
net_struct = NetStruct.new(network, netmask, object, [])
|
3422
|
+
|
3423
|
+
return(net_struct)
|
3424
|
+
end
|
3425
|
+
|
3426
|
+
#=====================================#
|
3427
|
+
#
|
3428
|
+
#=====================================#
|
3429
|
+
|
3430
|
+
|
3431
|
+
|
3432
|
+
#============================================================================#
|
3433
|
+
# dump
|
3434
|
+
#============================================================================#
|
3435
|
+
|
3436
|
+
# Dump the contents of this tree.
|
3437
|
+
#
|
3438
|
+
# - Arguments:
|
3439
|
+
# * none
|
3440
|
+
#
|
3441
|
+
# - Returns:
|
3442
|
+
# * ordered array of hashes in the form: :Object => CIDR or IPAddr object
|
3443
|
+
# :Depth => (depth level in tree)
|
3444
|
+
# Example:
|
3445
|
+
# dumped = tree.dump()
|
3446
|
+
#
|
3447
|
+
def dump()
|
3448
|
+
list = []
|
3449
|
+
dumped = dump_branch(@root)
|
3450
|
+
|
3451
|
+
dumped.each do |entry|
|
3452
|
+
depth = entry[:Depth]
|
3453
|
+
net_struct = entry[:NetStruct]
|
3454
|
+
object = net_struct.object
|
3455
|
+
list.push({:Depth => depth, :Object => object})
|
3456
|
+
end
|
3457
|
+
|
3458
|
+
return(list)
|
3459
|
+
end
|
3460
|
+
|
3461
|
+
#=====================================#
|
3462
|
+
#
|
3463
|
+
#=====================================#
|
3464
|
+
|
3465
|
+
|
3466
|
+
|
3467
|
+
#============================================================================#
|
3468
|
+
# dump_branch() private
|
3469
|
+
#============================================================================#
|
3470
|
+
|
3471
|
+
# Dump contents of an Array of NetStruct objects
|
3472
|
+
#
|
3473
|
+
# - Arguments:
|
3474
|
+
# * array of NetStruct objects, and an optional depth within the tree
|
3475
|
+
#
|
3476
|
+
# - Returns:
|
3477
|
+
# * array of hashes in form: :NetStruct => IPAdmin::Tree::NetStruct object
|
3478
|
+
# :Depth => (depth level in tree)
|
3479
|
+
# Example:
|
3480
|
+
# dumped = dump_branch(branch)
|
3481
|
+
#
|
3482
|
+
def dump_branch(branch,depth=nil)
|
3483
|
+
list = []
|
3484
|
+
depth = 0 if (!depth)
|
3485
|
+
|
3486
|
+
branch.each do |entry|
|
3487
|
+
subnets = entry.subnets
|
3488
|
+
list.push({:NetStruct => entry, :Depth => depth})
|
3489
|
+
|
3490
|
+
if (subnets.length > 0)
|
3491
|
+
list.concat( dump_branch(subnets, (depth+1) ) )
|
3492
|
+
end
|
3493
|
+
|
3494
|
+
end
|
3495
|
+
|
3496
|
+
return(list)
|
3497
|
+
end
|
3498
|
+
|
3499
|
+
#=====================================#
|
3500
|
+
#
|
3501
|
+
#=====================================#
|
3502
|
+
|
3503
|
+
|
3504
|
+
|
3505
|
+
#============================================================================#
|
3506
|
+
# find()
|
3507
|
+
#============================================================================#
|
3508
|
+
|
3509
|
+
# Find the branch of this tree to which an IPAdmin::CIDR or IPAdmin::IPAddr
|
3510
|
+
# would belong if added. This is useful for finding the longest match for
|
3511
|
+
# an IP address.
|
3512
|
+
#
|
3513
|
+
# - Arguments:
|
3514
|
+
# * IPAdmin::CIDR or IPAdmin::IPAddr object
|
3515
|
+
#
|
3516
|
+
# - Returns:
|
3517
|
+
# * IPAdmin::CIDR object, or nil if not found
|
3518
|
+
#
|
3519
|
+
# Example:
|
3520
|
+
# longest_match = tree.find(ip)
|
3521
|
+
#
|
3522
|
+
def find(object)
|
3523
|
+
unless ( object.kind_of?(IPAdmin::CIDR) ||
|
3524
|
+
object.kind_of?(IPAdmin::IPAddr) )
|
3525
|
+
raise ArgumentError, "IPAdmin::CIDR/IPAdmin::IPAddr object " +
|
3526
|
+
"required but #{object.class} provided."
|
3527
|
+
end
|
3528
|
+
|
3529
|
+
unless (object.version == @version )
|
3530
|
+
raise "IP version #{object.version} is incompatible with " +
|
3531
|
+
"Tree IP version #{@version}."
|
3532
|
+
end
|
3533
|
+
|
3534
|
+
net_struct = create_struct(object)
|
3535
|
+
home_struct,home_branch = find_home(net_struct, @root)
|
3536
|
+
found_obj = home_struct.object if (home_struct)
|
3537
|
+
|
3538
|
+
return(found_obj)
|
3539
|
+
end
|
3540
|
+
|
3541
|
+
#=====================================#
|
3542
|
+
#
|
3543
|
+
#=====================================#
|
3544
|
+
|
3545
|
+
|
3546
|
+
|
3547
|
+
#============================================================================#
|
3548
|
+
# find_home() private
|
3549
|
+
#============================================================================#
|
3550
|
+
|
3551
|
+
# Find the branch to which a NetStruct object belongs.
|
3552
|
+
#
|
3553
|
+
# - Arguments:
|
3554
|
+
# * IPAdmin::Tree::NetStruct to find, and Array of
|
3555
|
+
# IPAdmin::Tree::NetStruct's to search
|
3556
|
+
#
|
3557
|
+
# - Returns:
|
3558
|
+
# * array of: container IPAdmin::Tree::NetStruct object,
|
3559
|
+
# and container branch, or nil
|
3560
|
+
#
|
3561
|
+
# Example:
|
3562
|
+
# branch = find_home(net_struct,branch)
|
3563
|
+
#
|
3564
|
+
def find_home(net_struct,branch)
|
3565
|
+
ret_val = nil
|
3566
|
+
|
3567
|
+
branch.each do |entry|
|
3568
|
+
is_contained = contains(entry,net_struct)
|
3569
|
+
|
3570
|
+
if (is_contained)
|
3571
|
+
home_struct = entry
|
3572
|
+
home_branch = branch
|
3573
|
+
|
3574
|
+
if (home_struct.subnets.length > 0)
|
3575
|
+
search_results = find_home(net_struct,home_struct.subnets)
|
3576
|
+
if (search_results)
|
3577
|
+
home_struct = search_results[0]
|
3578
|
+
home_branch = search_results[1]
|
3579
|
+
end
|
3580
|
+
end
|
3581
|
+
|
3582
|
+
ret_val = [home_struct,home_branch]
|
3583
|
+
break
|
3584
|
+
end
|
3585
|
+
end
|
3586
|
+
|
3587
|
+
return(ret_val)
|
3588
|
+
end
|
3589
|
+
|
3590
|
+
#=====================================#
|
3591
|
+
#
|
3592
|
+
#=====================================#
|
3593
|
+
|
3594
|
+
|
3595
|
+
|
3596
|
+
#============================================================================#
|
3597
|
+
# find_space()
|
3598
|
+
#============================================================================#
|
3599
|
+
|
3600
|
+
# Find Tree entries of at least X size. Returns only the smallest matching
|
3601
|
+
# subnets of each supernet.
|
3602
|
+
#
|
3603
|
+
# - Arguments:
|
3604
|
+
# * Hash with the following fields:
|
3605
|
+
# - :Size -- subnet size (number of bits)
|
3606
|
+
# - :Limit -- max entries to return
|
3607
|
+
#
|
3608
|
+
# - Returns:
|
3609
|
+
# * ordered array of IPAdmin::CIDR/IPAdmin::IPAddr objects
|
3610
|
+
#
|
3611
|
+
# Example:
|
3612
|
+
# list = tree.find_space(:Size => 27)
|
3613
|
+
#
|
3614
|
+
def find_space(options)
|
3615
|
+
limit = nil
|
3616
|
+
list = []
|
3617
|
+
|
3618
|
+
# validate options
|
3619
|
+
unless (options.kind_of? Hash)
|
3620
|
+
raise ArgumentError, "Expected Hash, but #{options.class} provided."
|
3621
|
+
end
|
3622
|
+
|
3623
|
+
unless ( options.has_key?(:Size) )
|
3624
|
+
raise ArgumentError, "Missing argument :Size."
|
3625
|
+
end
|
3626
|
+
subnet_size = options[:Size]
|
3627
|
+
|
3628
|
+
if ( options.has_key?(:Limit) )
|
3629
|
+
limit = options[:Limit]
|
3630
|
+
end
|
3631
|
+
|
3632
|
+
|
3633
|
+
# check that subnet_size is a valid size
|
3634
|
+
if (@version == 4)
|
3635
|
+
unless ( (subnet_size > 0) && (subnet_size < 33) )
|
3636
|
+
raise "#{subnet_size} is out of range for an " +
|
3637
|
+
"IP version #{@version} Tree."
|
3638
|
+
end
|
3639
|
+
|
3640
|
+
else
|
3641
|
+
unless ( (subnet_size > 0) && (subnet_size < 129) )
|
3642
|
+
raise "#{subnet_size} is out of range for an " +
|
3643
|
+
"IP version #{@version} Tree."
|
3644
|
+
end
|
3645
|
+
end
|
3646
|
+
|
3647
|
+
search_list = dump_branch(@root)
|
3648
|
+
|
3649
|
+
search_list.each do |entry|
|
3650
|
+
depth = entry[:Depth]
|
3651
|
+
net_struct = entry[:NetStruct]
|
3652
|
+
|
3653
|
+
# we only want leaf nodes of type IPAdmin::CIDR
|
3654
|
+
if ( (net_struct.subnets.length == 0) &&
|
3655
|
+
(net_struct.object.kind_of?(IPAdmin::CIDR)) )
|
3656
|
+
|
3657
|
+
if (subnet_size >= net_struct.object.bits)
|
3658
|
+
list.push(net_struct.object)
|
3659
|
+
end
|
3660
|
+
end
|
3661
|
+
|
3662
|
+
if (limit && (list.length >= limit) )
|
3663
|
+
break
|
3664
|
+
end
|
3665
|
+
|
3666
|
+
end
|
3667
|
+
|
3668
|
+
return(list)
|
3669
|
+
|
3670
|
+
end
|
3671
|
+
|
3672
|
+
#=====================================#
|
3673
|
+
#
|
3674
|
+
#=====================================#
|
3675
|
+
|
3676
|
+
|
3677
|
+
|
3678
|
+
#============================================================================#
|
3679
|
+
# prune()
|
3680
|
+
#============================================================================#
|
3681
|
+
|
3682
|
+
# Remove an IPAdmin::CIDR/IPAdmin::IPAddr object, and all child
|
3683
|
+
# objects from the tree.
|
3684
|
+
#
|
3685
|
+
# - Arguments:
|
3686
|
+
# * IPAdmin::CIDR or IPAdmin::IPAddr object
|
3687
|
+
#
|
3688
|
+
# - Returns:
|
3689
|
+
# * 1 on success, or nil
|
3690
|
+
#
|
3691
|
+
# Example:
|
3692
|
+
# did_prune = tree.prune(ip)
|
3693
|
+
#
|
3694
|
+
def prune(object)
|
3695
|
+
unless ( object.kind_of?(IPAdmin::CIDR) ||
|
3696
|
+
object.kind_of?(IPAdmin::IPAddr) )
|
3697
|
+
raise ArgumentError, "IPAdmin::CIDR/IPAdmin::IPAddr object " +
|
3698
|
+
"required but #{object.class} provided."
|
3699
|
+
end
|
3700
|
+
|
3701
|
+
unless (object.version == @version )
|
3702
|
+
raise "IP version #{object.version} is incompatible with " +
|
3703
|
+
"Tree IP version #{@version}."
|
3704
|
+
end
|
3705
|
+
|
3706
|
+
net_struct = create_struct(object)
|
3707
|
+
home_struct,home_branch = find_home(net_struct, @root)
|
3708
|
+
|
3709
|
+
# remove if home_struct.object = object
|
3710
|
+
if (home_struct.object = object)
|
3711
|
+
home_branch.delete(home_struct)
|
3712
|
+
pruned = 1
|
3713
|
+
end
|
3714
|
+
|
3715
|
+
return(pruned)
|
3716
|
+
end
|
3717
|
+
|
3718
|
+
#=====================================#
|
3719
|
+
#
|
3720
|
+
#=====================================#
|
3721
|
+
|
3722
|
+
|
3723
|
+
|
3724
|
+
#============================================================================#
|
3725
|
+
# remove()
|
3726
|
+
#============================================================================#
|
3727
|
+
|
3728
|
+
# Remove a single IPAdmin::CIDR/IPAdmin::IPAddr object from the tree.
|
3729
|
+
#
|
3730
|
+
# - Arguments:
|
3731
|
+
# * IPAdmin::CIDR or IPAdmin::IPAddr object
|
3732
|
+
#
|
3733
|
+
# - Returns:
|
3734
|
+
# * 1 on success, or nil
|
3735
|
+
#
|
3736
|
+
# Example:
|
3737
|
+
# did_remove = tree.remove(ip)
|
3738
|
+
#
|
3739
|
+
def remove(object)
|
3740
|
+
unless ( object.kind_of?(IPAdmin::CIDR) ||
|
3741
|
+
object.kind_of?(IPAdmin::IPAddr) )
|
3742
|
+
raise ArgumentError, "IPAdmin::CIDR/IPAdmin::IPAddr object " +
|
3743
|
+
"required but #{object.class} provided."
|
3744
|
+
end
|
3745
|
+
|
3746
|
+
unless (object.version == @version )
|
3747
|
+
raise "IP version #{object.version} is incompatible with " +
|
3748
|
+
"Tree IP version #{@version}."
|
3749
|
+
end
|
3750
|
+
|
3751
|
+
net_struct = create_struct(object)
|
3752
|
+
home_struct,home_branch = find_home(net_struct, @root)
|
3753
|
+
|
3754
|
+
# remove if home_struct.object = object
|
3755
|
+
if (home_struct.object = object)
|
3756
|
+
|
3757
|
+
# if we have children subnets, move them up one level
|
3758
|
+
if (home_struct.subnets.length > 0)
|
3759
|
+
home_struct.subnets.each do |entry|
|
3760
|
+
index = 0
|
3761
|
+
home_branch.each do
|
3762
|
+
if(entry.network < (home_branch[index]).network)
|
3763
|
+
break
|
3764
|
+
end
|
3765
|
+
index += 1
|
3766
|
+
end
|
3767
|
+
home_branch.insert(index, entry)
|
3768
|
+
end
|
3769
|
+
end
|
3770
|
+
|
3771
|
+
home_branch.delete(home_struct)
|
3772
|
+
removed = 1
|
3773
|
+
end
|
3774
|
+
|
3775
|
+
return(removed)
|
3776
|
+
end
|
3777
|
+
|
3778
|
+
#=====================================#
|
3779
|
+
#
|
3780
|
+
#=====================================#
|
3781
|
+
|
3782
|
+
|
3783
|
+
|
3784
|
+
#============================================================================#
|
3785
|
+
# show()
|
3786
|
+
#============================================================================#
|
3787
|
+
|
3788
|
+
# Print the tree in a nicely formatted string.
|
3789
|
+
#
|
3790
|
+
# - Arguments:
|
3791
|
+
# * none
|
3792
|
+
#
|
3793
|
+
# - Returns:
|
3794
|
+
# * string representing the contents of the tree
|
3795
|
+
#
|
3796
|
+
# Example:
|
3797
|
+
# puts tree.show()
|
3798
|
+
#
|
3799
|
+
def show()
|
3800
|
+
printed = ""
|
3801
|
+
list = dump_branch(@root)
|
3802
|
+
|
3803
|
+
list.each do |entry|
|
3804
|
+
net_struct = entry[:NetStruct]
|
3805
|
+
depth = entry[:Depth]
|
3806
|
+
|
3807
|
+
if (@version == 4)
|
3808
|
+
network = IPAdmin.unpack_ipv4_addr(net_struct.network)
|
3809
|
+
netmask = IPAdmin.unpack_ipv4_netmask(net_struct.netmask)
|
3810
|
+
|
3811
|
+
else
|
3812
|
+
network = IPAdmin.unpack_ipv6_addr(net_struct.network)
|
3813
|
+
netmask = IPAdmin.unpack_ipv6_netmask(net_struct.netmask)
|
3814
|
+
network = IPAdmin.shorten(network)
|
3815
|
+
end
|
3816
|
+
|
3817
|
+
if (depth == 0)
|
3818
|
+
indent = ""
|
3819
|
+
else
|
3820
|
+
indent = " " * (depth*3)
|
3821
|
+
end
|
3822
|
+
|
3823
|
+
printed << "#{indent}#{network}/#{netmask}\n"
|
3824
|
+
end
|
3825
|
+
|
3826
|
+
return(printed)
|
3827
|
+
end
|
3828
|
+
|
3829
|
+
#=====================================#
|
3830
|
+
#
|
3831
|
+
#=====================================#
|
3832
|
+
|
3833
|
+
|
3834
|
+
|
3835
|
+
private :add_to_branch, :contains, :collapse_branch, :create_struct,
|
3836
|
+
:dump_branch, :find_home
|
3837
|
+
|
3838
|
+
end
|
3839
|
+
|
3840
|
+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
3841
|
+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
3842
|
+
#
|
3843
|
+
# END class Tree
|
3844
|
+
#
|
3845
|
+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
3846
|
+
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
|
3847
|
+
|
3848
|
+
|
3849
|
+
|
3850
|
+
|
2914
3851
|
end # module IPAdmin
|
2915
3852
|
|
2916
3853
|
|