ipadmin 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +147 -61
- data/lib/cidr.rb +88 -25
- data/lib/eui.rb +381 -0
- data/lib/ip_admin.rb +2 -1
- data/lib/methods.rb +75 -735
- data/tests/cidr_test.rb +26 -0
- data/tests/eui_test.rb +50 -0
- data/tests/methods_test.rb +13 -1
- metadata +24 -18
data/README
CHANGED
@@ -1,15 +1,33 @@
|
|
1
1
|
|
2
|
+
=Introduction
|
3
|
+
|
4
|
+
IPAdmin arose from a work-related project to create a Rails IP
|
5
|
+
Administration package. I needed a back-end module that could easily
|
6
|
+
handle such advanced tasks as automating the subnetting/supernetting
|
7
|
+
of IP space, performing calculations on IP CIDR blocks, and other
|
8
|
+
various tasks. At the current time there were no modules that could
|
9
|
+
do any of the things that I needed, so I set out to create my own.
|
10
|
+
Since it proved to be fairly useful to me, I decided to share the
|
11
|
+
code with the Ruby community.
|
12
|
+
|
13
|
+
I apologize in advance for the short release cycles, but I am making
|
14
|
+
changes on a constant basis since this is a very active project.
|
15
|
+
I tend to post new releases to rubyforge since it is a very easy
|
16
|
+
way for me to distribute my changes to my co-workers.
|
17
|
+
|
18
|
+
I have added things that I find immediately useful for me. I am
|
19
|
+
open to suggestions if there is something that I could add to make
|
20
|
+
your life easier. Comments are also welcome (positive ones in particular).
|
21
|
+
|
22
|
+
Dustin Spinhirne
|
23
|
+
|
24
|
+
|
2
25
|
Copyright (c) 2006 Dustin Spinhirne - http://www.spinhirne.com
|
3
26
|
Licensed under the same terms as Ruby, No Warranty is provided.
|
4
27
|
|
5
|
-
|
6
|
-
Comments are welcome. Please include 'IPAdmin' in the title of
|
7
|
-
any emails.
|
8
|
-
|
9
|
-
Dustin Spinhirne
|
10
28
|
|
11
29
|
|
12
|
-
=CIDR
|
30
|
+
=CIDR:
|
13
31
|
|
14
32
|
A class & series of methods for creating and manipulating CIDR network
|
15
33
|
addresses. Both IPv4 and IPv6 are supported.
|
@@ -38,49 +56,15 @@
|
|
38
56
|
You can see how the CIDR object is based around the entire IP space
|
39
57
|
defined by the provided IP/Netmask pair, and not necessarily the individual
|
40
58
|
IP address itself.
|
41
|
-
|
42
|
-
|
43
|
-
=Tree
|
44
|
-
|
45
|
-
A class & series of methods for creating and manipulating IP-based
|
46
|
-
heirarchical trees. Both IPv4 and IPv6 are supported.
|
47
|
-
|
48
|
-
Tree's are useful for creating mini 'routing tables' of CIDR address space.
|
49
|
-
Using a tree, you can quickly determine the 'route' of another CIDR via
|
50
|
-
the standard longest-match algorithm.
|
51
|
-
|
52
|
-
Tree's are not dynamic, in that if you modify any of the CIDR objects
|
53
|
-
contained within, the Tree will not automatically adjust itself accordingly.
|
54
|
-
For example if you have a tree like the following:
|
55
|
-
|
56
|
-
192.168.0.0/24
|
57
|
-
192.168.0.0/26
|
58
|
-
192.168.1.0/24
|
59
|
-
|
60
|
-
You decide to resize 192.168.0.0/24 to 192.168.0.0/23. The tree will now
|
61
|
-
be incorrect:
|
62
|
-
|
63
|
-
192.168.0.0/23
|
64
|
-
192.168.0.0/26
|
65
|
-
192.168.1.0/24
|
66
|
-
|
67
|
-
You would need to remove and re-add the CIDR 192.168.0.0/23 in order for the
|
68
|
-
tree to rebuild itself properly.
|
69
|
-
|
70
59
|
|
71
60
|
|
72
|
-
|
73
|
-
=Examples:
|
74
|
-
|
61
|
+
====Examples:
|
75
62
|
|
76
63
|
#!/usr/bin/ruby
|
77
64
|
|
78
65
|
require 'rubygems'
|
79
66
|
require_gem 'ipadmin'
|
80
67
|
|
81
|
-
#============================================================================#
|
82
|
-
# IPAdmin::CIDR
|
83
|
-
#============================================================================#
|
84
68
|
puts "IPAdmin::CIDR"
|
85
69
|
print "\n"
|
86
70
|
|
@@ -101,8 +85,7 @@
|
|
101
85
|
puts "updated cidr4 tag '#{cidr4.tag['test']}'"
|
102
86
|
puts "cidr4 version #{cidr4.version}"
|
103
87
|
puts "cidr6 version #{cidr6.version}"
|
104
|
-
print "\n"
|
105
|
-
|
88
|
+
print "\n"
|
106
89
|
|
107
90
|
# arpa
|
108
91
|
puts "arpa"
|
@@ -154,6 +137,14 @@
|
|
154
137
|
puts "cidr4 last ip #{cidr4.last()}"
|
155
138
|
puts "cidr6 last ip #{cidr6.last(:Short => true)}"
|
156
139
|
print "\n"
|
140
|
+
|
141
|
+
# multicast_mac
|
142
|
+
mcast = IPAdmin::CIDR.new(:CIDR => '224.0.0.6')
|
143
|
+
mcast2 = IPAdmin::CIDR.new(:CIDR => 'ff00::abcd')
|
144
|
+
puts "multicast_mac"
|
145
|
+
puts "#{mcast.ip} multicast mac is #{mcast.multicast_mac()}"
|
146
|
+
puts "#{mcast2.ip} multicast mac is #{mcast2.multicast_mac()}"
|
147
|
+
print "\n"
|
157
148
|
|
158
149
|
# netmask
|
159
150
|
puts "netmask"
|
@@ -243,15 +234,107 @@
|
|
243
234
|
puts "#{cidr6.desc(:Short => true)} subnetted into at least 4 /67 ranges"
|
244
235
|
cidr6.subnet(:Subnet => 67, :MinCount => 4, :Short => true).each {|x| puts " #{x}"}
|
245
236
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
237
|
+
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
=EUI:
|
242
|
+
|
243
|
+
A class & series of methods for creating and manipulating Extended Unique Identifier
|
244
|
+
(EUI) addresses. Two types of address formats are supported EUI-48 and EUI-64. The
|
245
|
+
most common use for this class will be to manipulate MAC addresses (which are essentially
|
246
|
+
a type of EUI-48 address).
|
247
|
+
|
248
|
+
EUI addresses are separated into two parts, the
|
249
|
+
Organizationally Unique Identifier (OUI) and the Extended Identifier (EI). The OUI
|
250
|
+
is assigned by the IEEE and is used to identify a particular hardware manufacturer.
|
251
|
+
The EI is assigned by the hardware manufacturer as a per device unique address.
|
252
|
+
|
253
|
+
Probably the most useful feature of this class, and thus the reason it was created,
|
254
|
+
is to help automate certain address assignments within IP. For example, IPv6
|
255
|
+
Link Local addresses use MAC addresses for IP auto-assignment and multicast MAC addresses
|
256
|
+
are determined based on the multicast IP address.
|
257
|
+
|
258
|
+
|
259
|
+
====Examples:
|
260
|
+
|
261
|
+
#!/usr/bin/ruby
|
262
|
+
|
263
|
+
require 'rubygems'
|
264
|
+
require_gem 'ipadmin'
|
265
|
+
|
266
|
+
puts "IPAdmin::EUI"
|
267
|
+
print "\n"
|
268
|
+
|
269
|
+
eui1 = IPAdmin::EUI.new(:EUI => 'aa-bb-cc-dd-ee-ff')
|
270
|
+
eui2 = IPAdmin::EUI.new(:EUI => '12-34-56-78-9a-bc-de-f0')
|
271
|
+
|
272
|
+
# oui
|
273
|
+
puts "oui"
|
274
|
+
puts "OUI 1 is #{eui1.oui}"
|
275
|
+
puts "OUI 2 is #{eui2.oui}"
|
276
|
+
print "\n"
|
277
|
+
|
278
|
+
# ei
|
279
|
+
puts "ei"
|
280
|
+
puts "EI 1 is #{eui1.ei}"
|
281
|
+
puts "EI 2 is #{eui2.ei}"
|
282
|
+
print "\n"
|
283
|
+
|
284
|
+
# address
|
285
|
+
puts "address"
|
286
|
+
puts "address 1 is #{eui1.address(:Delimiter => '.')}"
|
287
|
+
puts "address 2 is #{eui2.address(:Delimiter => '.')}"
|
288
|
+
print "\n"
|
289
|
+
|
290
|
+
# link local
|
291
|
+
puts "link local"
|
292
|
+
puts "IPv6 link local 1 is #{eui1.link_local(:Short => true)}"
|
293
|
+
puts "IPv6 link local 2 is #{eui2.link_local(:Short => true)}"
|
294
|
+
print "\n"
|
295
|
+
|
296
|
+
# type
|
297
|
+
puts "type"
|
298
|
+
puts "eui 1 type is #{eui1.type}"
|
299
|
+
puts "eui 2 type is #{eui2.type}"
|
300
|
+
|
301
|
+
|
302
|
+
|
303
|
+
=Tree:
|
304
|
+
|
305
|
+
A class & series of methods for creating and manipulating IP-based
|
306
|
+
heirarchical trees. Both IPv4 and IPv6 are supported.
|
307
|
+
|
308
|
+
Tree's are useful for creating mini 'routing tables' of CIDR address space.
|
309
|
+
Using a tree, you can quickly determine the 'route' of another CIDR via
|
310
|
+
the standard longest-match algorithm.
|
311
|
+
|
312
|
+
Tree's are not dynamic, in that if you modify any of the CIDR objects
|
313
|
+
contained within, the Tree will not automatically adjust itself accordingly.
|
314
|
+
For example if you have a tree like the following:
|
315
|
+
|
316
|
+
192.168.0.0/24
|
317
|
+
192.168.0.0/26
|
318
|
+
192.168.1.0/24
|
319
|
+
|
320
|
+
You decide to resize 192.168.0.0/24 to 192.168.0.0/23. The tree will now
|
321
|
+
be incorrect:
|
322
|
+
|
323
|
+
192.168.0.0/23
|
324
|
+
192.168.0.0/26
|
325
|
+
192.168.1.0/24
|
326
|
+
|
327
|
+
You would need to remove and re-add the CIDR 192.168.0.0/23 in order for the
|
328
|
+
tree to rebuild itself properly.
|
329
|
+
|
330
|
+
|
331
|
+
====Examples:
|
250
332
|
|
333
|
+
#!/usr/bin/ruby
|
251
334
|
|
252
|
-
|
253
|
-
|
254
|
-
|
335
|
+
require 'rubygems'
|
336
|
+
require_gem 'ipadmin'
|
337
|
+
|
255
338
|
puts "IPAdmin::Tree"
|
256
339
|
print "\n"
|
257
340
|
|
@@ -367,15 +450,21 @@
|
|
367
450
|
new_tree6 = tree6.collapse()
|
368
451
|
puts new_tree6.show()
|
369
452
|
|
370
|
-
print "\n\n\n"
|
371
|
-
#=====================================#
|
372
|
-
#
|
373
|
-
#=====================================#
|
374
|
-
|
375
453
|
|
376
|
-
|
377
|
-
|
378
|
-
|
454
|
+
|
455
|
+
= IPAdmin General Methods
|
456
|
+
|
457
|
+
A collection of general purpose methods that dont really fit within
|
458
|
+
a particular class.
|
459
|
+
|
460
|
+
|
461
|
+
====Examples:
|
462
|
+
|
463
|
+
#!/usr/bin/ruby
|
464
|
+
|
465
|
+
require 'rubygems'
|
466
|
+
require_gem 'ipadmin'
|
467
|
+
|
379
468
|
puts "IPAdmin Methods"
|
380
469
|
print "\n"
|
381
470
|
|
@@ -430,7 +519,4 @@
|
|
430
519
|
puts "unshorten"
|
431
520
|
puts "expanded notation for fec0:: is #{IPAdmin.unshorten('fec0::')}"
|
432
521
|
|
433
|
-
#=====================================#
|
434
|
-
#
|
435
|
-
#=====================================#
|
436
522
|
|
data/lib/cidr.rb
CHANGED
@@ -364,11 +364,11 @@ class CIDR
|
|
364
364
|
raise ArgumentError, "Expected Hash, but #{options.class} provided."
|
365
365
|
end
|
366
366
|
|
367
|
-
if (options.has_key?(:Short))
|
367
|
+
if (options.has_key?(:Short) && options[:Short] == true)
|
368
368
|
short = true
|
369
369
|
end
|
370
370
|
|
371
|
-
if (options.has_key?(:IP))
|
371
|
+
if (options.has_key?(:IP) && options[:IP] == true)
|
372
372
|
orig_ip = true
|
373
373
|
end
|
374
374
|
end
|
@@ -424,7 +424,7 @@ class CIDR
|
|
424
424
|
bitstep = options[:Bitstep]
|
425
425
|
end
|
426
426
|
|
427
|
-
if( options.has_key?(:Objectify) )
|
427
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
428
428
|
objectify = true
|
429
429
|
end
|
430
430
|
|
@@ -432,7 +432,7 @@ class CIDR
|
|
432
432
|
limit = options[:Limit]
|
433
433
|
end
|
434
434
|
|
435
|
-
if( options.has_key?(:Short) )
|
435
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
436
436
|
short = true
|
437
437
|
end
|
438
438
|
end
|
@@ -522,11 +522,11 @@ class CIDR
|
|
522
522
|
"#{options.class} provided."
|
523
523
|
end
|
524
524
|
|
525
|
-
if( options.has_key?(:Short) )
|
525
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
526
526
|
short = true
|
527
527
|
end
|
528
528
|
|
529
|
-
if( options.has_key?(:Objectify) )
|
529
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
530
530
|
objectify = true
|
531
531
|
end
|
532
532
|
end
|
@@ -563,7 +563,7 @@ class CIDR
|
|
563
563
|
# * String or CIDR object.
|
564
564
|
#
|
565
565
|
# - Notes:
|
566
|
-
# * The broadcast() method is
|
566
|
+
# * The broadcast() method is aliased to this method, and thus works for
|
567
567
|
# IPv6 despite the fact that the IPv6 protocol does not support IP
|
568
568
|
# broadcasting.
|
569
569
|
#
|
@@ -580,11 +580,11 @@ class CIDR
|
|
580
580
|
"#{options.class} provided."
|
581
581
|
end
|
582
582
|
|
583
|
-
if( options.has_key?(:Short) )
|
583
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
584
584
|
short = true
|
585
585
|
end
|
586
586
|
|
587
|
-
if( options.has_key?(:Objectify) )
|
587
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
588
588
|
objectify = true
|
589
589
|
end
|
590
590
|
|
@@ -608,6 +608,69 @@ class CIDR
|
|
608
608
|
#======================================#
|
609
609
|
|
610
610
|
|
611
|
+
#==============================================================================#
|
612
|
+
# multicast_mac()
|
613
|
+
#==============================================================================#
|
614
|
+
|
615
|
+
# Assuming this CIDR is a valid multicast address (224.0.0.0/4 for IPv4
|
616
|
+
# and ff00::/8 for IPv6), return its ethernet MAC address (EUI-48) mapping.
|
617
|
+
#
|
618
|
+
# - Arguments:
|
619
|
+
# * Optional hash with the following fields:
|
620
|
+
# - :Objectify -- if true, return EUI objects (optional)
|
621
|
+
#
|
622
|
+
# - Returns:
|
623
|
+
# * EUI object
|
624
|
+
#
|
625
|
+
# - Note:
|
626
|
+
# * MAC address is based on original IP address passed during initialization.
|
627
|
+
#
|
628
|
+
# Example:
|
629
|
+
# mcast = IPAdmin::CIDR.new(:CIDR => '224.0.0.6')
|
630
|
+
# puts mcast.multicast_mac.address --> 01-00-5e-00-00-06
|
631
|
+
#
|
632
|
+
def multicast_mac(options=nil)
|
633
|
+
objectify = false
|
634
|
+
|
635
|
+
if (options)
|
636
|
+
if (!options.kind_of? Hash)
|
637
|
+
raise ArgumentError, "Expected Hash, but #{options.class} provided."
|
638
|
+
end
|
639
|
+
|
640
|
+
if (options.has_key?(:Objectify) && options[:Objectify] == true)
|
641
|
+
objectify = true
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
if (@version == 4)
|
646
|
+
if (@ip & 0xf0000000 == 0xe0000000)
|
647
|
+
# map low order 23-bits of ip to 01:00:5e:00:00:00
|
648
|
+
mac = @ip & 0x007fffff | 0x01005e000000
|
649
|
+
else
|
650
|
+
raise "#{self.ip} is not a valid multicast address. IPv4 multicast " +
|
651
|
+
"addresses should be in the range 224.0.0.0/4."
|
652
|
+
end
|
653
|
+
else
|
654
|
+
if (@ip & (0xff << 120) == 0xff << 120)
|
655
|
+
# map low order 32-bits of ip to 33:33:00:00:00:00
|
656
|
+
mac = @ip & (2**32-1) | 0x333300000000
|
657
|
+
else
|
658
|
+
raise "#{self.ip} is not a valid multicast address. IPv6 multicast " +
|
659
|
+
"addresses should be in the range ff00::/8."
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
eui = IPAdmin::EUI.new(:PackedEUI => mac)
|
664
|
+
eui = eui.address if (!objectify)
|
665
|
+
|
666
|
+
return(eui)
|
667
|
+
end
|
668
|
+
|
669
|
+
#======================================#
|
670
|
+
#
|
671
|
+
#======================================#
|
672
|
+
|
673
|
+
|
611
674
|
#==============================================================================#
|
612
675
|
# netmask()
|
613
676
|
#==============================================================================#
|
@@ -691,11 +754,11 @@ class CIDR
|
|
691
754
|
"#{options.class} provided."
|
692
755
|
end
|
693
756
|
|
694
|
-
if( options.has_key?(:Short) )
|
757
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
695
758
|
short = true
|
696
759
|
end
|
697
760
|
|
698
|
-
if( options.has_key?(:Objectify) )
|
761
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
699
762
|
objectify = true
|
700
763
|
end
|
701
764
|
end
|
@@ -753,11 +816,11 @@ class CIDR
|
|
753
816
|
bitstep = options[:Bitstep]
|
754
817
|
end
|
755
818
|
|
756
|
-
if( options.has_key?(:Short) )
|
819
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
757
820
|
short = true
|
758
821
|
end
|
759
822
|
|
760
|
-
if( options.has_key?(:Objectify) )
|
823
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
761
824
|
objectify = true
|
762
825
|
end
|
763
826
|
end
|
@@ -818,11 +881,11 @@ class CIDR
|
|
818
881
|
bitstep = options[:Bitstep]
|
819
882
|
end
|
820
883
|
|
821
|
-
if( options.has_key?(:Short) )
|
884
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
822
885
|
short = true
|
823
886
|
end
|
824
887
|
|
825
|
-
if( options.has_key?(:Objectify) )
|
888
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
826
889
|
objectify = true
|
827
890
|
end
|
828
891
|
end
|
@@ -883,11 +946,11 @@ class CIDR
|
|
883
946
|
end
|
884
947
|
index = options[:Index]
|
885
948
|
|
886
|
-
if( options.has_key?(:Short) )
|
949
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
887
950
|
short = true
|
888
951
|
end
|
889
952
|
|
890
|
-
if( options.has_key?(:Objectify) )
|
953
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
891
954
|
objectify = true
|
892
955
|
end
|
893
956
|
|
@@ -1057,11 +1120,11 @@ class CIDR
|
|
1057
1120
|
raise ArgumentError, "Index #{indexes[1]} is out of bounds for this CIDR."
|
1058
1121
|
end
|
1059
1122
|
|
1060
|
-
if( options.has_key?(:Short) )
|
1123
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
1061
1124
|
short = true
|
1062
1125
|
end
|
1063
1126
|
|
1064
|
-
if( options.has_key?(:Objectify) )
|
1127
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
1065
1128
|
objectify = true
|
1066
1129
|
end
|
1067
1130
|
|
@@ -1100,7 +1163,7 @@ class CIDR
|
|
1100
1163
|
# Given a portion of the current CIDR, provide the remainder of
|
1101
1164
|
# the CIDR. For example if the original CIDR is 192.168.0.0/24 and you
|
1102
1165
|
# provide 192.168.0.64/26 as the portion to exclude, then 192.168.0.0/26,
|
1103
|
-
#
|
1166
|
+
# and 192.168.0.128/25 will be returned as the remainder.
|
1104
1167
|
#
|
1105
1168
|
# - Arguments:
|
1106
1169
|
# * Optional hash with the following fields:
|
@@ -1134,11 +1197,11 @@ class CIDR
|
|
1134
1197
|
"for option: Exclude."
|
1135
1198
|
end
|
1136
1199
|
|
1137
|
-
if( options.has_key?(:Short) )
|
1200
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
1138
1201
|
short = true
|
1139
1202
|
end
|
1140
1203
|
|
1141
|
-
if( options.has_key?(:Objectify) )
|
1204
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
1142
1205
|
objectify = true
|
1143
1206
|
end
|
1144
1207
|
|
@@ -1321,7 +1384,7 @@ class CIDR
|
|
1321
1384
|
# of specified size. If :MinCount is provided, then method will return at least
|
1322
1385
|
# that number of subnets (of size X) and the remainder of the new subnets
|
1323
1386
|
# will be merged together as tightly as possible. If a size is not provided,
|
1324
|
-
# then the current
|
1387
|
+
# then the current CIDR will be split in half.
|
1325
1388
|
#
|
1326
1389
|
# - Arguments:
|
1327
1390
|
# * Optional hash with the following fields:
|
@@ -1368,11 +1431,11 @@ class CIDR
|
|
1368
1431
|
min_count = options[:MinCount]
|
1369
1432
|
end
|
1370
1433
|
|
1371
|
-
if( options.has_key?(:Short) )
|
1434
|
+
if( options.has_key?(:Short) && options[:Short] == true )
|
1372
1435
|
short = true
|
1373
1436
|
end
|
1374
1437
|
|
1375
|
-
if( options.has_key?(:Objectify) )
|
1438
|
+
if( options.has_key?(:Objectify) && options[:Objectify] == true )
|
1376
1439
|
objectify = true
|
1377
1440
|
end
|
1378
1441
|
|