ipadmin 0.2.2 → 0.3.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/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
|
|