ipadmin 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -15,106 +15,140 @@
15
15
  =Examples:
16
16
 
17
17
 
18
+ #!/usr/bin/ruby
19
+
18
20
  require 'rubygems'
19
21
  require_gem 'ipadmin'
20
-
21
-
22
+
22
23
  #============================================================================#
23
24
  # IPAdmin::IPAddr
24
25
  #============================================================================#
25
26
  puts "IPAdmin::IPAddr"
26
-
27
- begin
28
- ip4 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.1/24')
29
- ip4 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.1',
30
- :Netmask => '255.255.255.0',
31
- :Tag => {'test' => 'ip4 tag'})
32
- ip6 = IPAdmin::IPAddr.new(:IPAddr => 'fec0::1/64')
33
- rescue Exception
34
- puts 'oops'
35
- exit
36
- end
37
-
27
+
28
+ # new
29
+ ip4 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.1/24')
30
+ ip4 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.1',
31
+ :Netmask => '255.255.255.0',
32
+ :Tag => {'test' => 'ip4 tag'})
33
+ ip6 = IPAdmin::IPAddr.new(:IPAddr => 'fec0::1/64')
34
+
35
+ # reader/writer
38
36
  puts ip4.tag['test']
39
37
  ip4.tag['test'] = 'modified ip4 tag'
40
38
  puts ip4.tag['test']
41
-
42
- puts "base addr #{ip4.base()}"
43
- puts "base addr #{ip6.base()}"
44
39
 
45
- puts "bcast addr #{ip4.broadcast()}"
40
+ # base
41
+ puts "ip4 base addr #{ip4.base()}"
42
+ puts "ip6 base addr #{ip6.base()}"
46
43
 
47
- puts "description #{ip4.desc()}"
48
- puts "description #{ip6.desc()}"
44
+ # broadcast
45
+ puts "ip4 bcast addr #{ip4.broadcast()}"
49
46
 
50
- puts "extended hostmask #{ip4.hostmask_ext()}"
51
- puts "extended netmask #{ip4.netmask_ext()}"
47
+ # desc
48
+ puts "ip4 description #{ip4.desc()}"
49
+ puts "ip6 description #{ip6.desc()}"
52
50
 
53
- puts "ip addr #{ip4.ip()}"
54
- puts "ip addr #{ip6.ip()}"
51
+ # extended masks
52
+ puts "ip4 extended hostmask #{ip4.hostmask_ext()}"
53
+ puts "ip6 extended netmask #{ip4.netmask_ext()}"
55
54
 
56
- puts "netmask in bits #{ip4.netmask()}"
57
- puts "netmask in bits #{ip6.netmask()}"
55
+ # ip
56
+ puts "ip4 ip addr #{ip4.ip()}"
57
+ puts "ip6 ip addr #{ip6.ip()}"
58
+
59
+ # netmask
60
+ puts "ip4 netmask in CIDR format #{ip4.netmask()}"
61
+ puts "ip6 netmask in CIDR format #{ip6.netmask()}"
62
+
63
+ # bits
64
+ puts "ip4 netmask in bits #{ip4.bits()}"
65
+ puts "ip6 netmask in bits #{ip6.bits()}"
58
66
 
59
67
  print "\n\n\n"
60
68
  #=====================================#
61
- #
69
+ #
62
70
  #=====================================#
63
71
 
64
-
65
72
  #============================================================================#
66
73
  # IPAdmin::CIDR
67
74
  #============================================================================#
68
75
  puts "IPAdmin::CIDR"
69
76
 
70
- begin
71
- cidr4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
72
- cidr4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0',
73
- :Netmask => '255.255.255.0',
74
- :Tag => {'test' => 'cidr4 tag'})
75
- cidr6 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/64')
76
- rescue Exception
77
- puts 'oops'
78
- exit
79
- end
80
-
77
+ # new
78
+ cidr4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
79
+ cidr4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0',
80
+ :Netmask => '255.255.255.0',
81
+ :Tag => {'test' => 'cidr4 tag'})
82
+ cidr6 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/64')
83
+
84
+ # attr reader/writer
81
85
  puts cidr4.tag['test']
82
86
  cidr4.tag['test'] = 'modified cidr4 tag'
83
87
  puts cidr4.tag['test']
84
88
 
85
- puts "cidr4 contains ip4" if ( cidr4.contains(ip4) )
86
- puts "cidr6 contains ip6" if ( cidr6.contains(ip6) )
87
-
88
- puts "description #{cidr4.desc()}"
89
- puts "description #{cidr6.desc()}"
90
-
91
- puts "extended hostmask #{cidr4.hostmask_ext()}"
92
- puts "extended netmask #{cidr4.netmask_ext()}"
93
-
94
- puts "netmask in bits #{cidr4.netmask()}"
95
- puts "netmask in bits #{cidr6.netmask()}"
96
-
97
- puts "network address #{cidr4.network()}"
98
- puts "network address #{cidr6.network()}"
99
-
100
- puts "1st ip is #{cidr4.nth(:Index => 1)}"
101
- puts "1st ip is #{(cidr6.nth(:Index => 1, :Objectify => 1)).desc}"
89
+ # contains
90
+ puts "#{cidr4.desc} contains #{ip4.desc}" if ( cidr4.contains(ip4) )
91
+ puts "#{cidr6.desc} contains #{ip6.desc}" if ( cidr6.contains(ip6) )
92
+
93
+ # desc
94
+ puts "cidr4 description #{cidr4.desc()}"
95
+ puts "cidr6 description #{cidr6.desc()}"
96
+
97
+ # extended masks
98
+ puts "cidr4 extended hostmask #{cidr4.hostmask_ext()}"
99
+ puts "cidr4 extended netmask #{cidr4.netmask_ext()}"
100
+
101
+ # netmask
102
+ puts "cidr4 netmask in CIDR format #{cidr4.netmask()}"
103
+ puts "cidr6 netmask in CIDR format #{cidr6.netmask()}"
102
104
 
105
+ # bits
106
+ puts "cidr4 netmask in bits #{cidr4.bits()}"
107
+ puts "cidr6 netmask in bits #{cidr6.bits()}"
108
+
109
+ # network
110
+ puts "cidr4 network address #{cidr4.network()}"
111
+ puts "cidr6 network address #{cidr6.network()}"
112
+
113
+ # nth
114
+ puts "cidr4 1st ip is #{cidr4.nth(:Index => 1)}"
115
+ puts "cidr6 1st ip is #{(cidr6.nth(:Index => 1, :Objectify => 1)).desc}"
116
+
117
+ # size
103
118
  puts "cidr4 size is #{cidr4.size()}"
104
119
  puts "cidr6 size is #{cidr6.size()}"
120
+
121
+ # enumerate
122
+ puts "first 4 cidr4 addresses (bitstep 32)"
123
+ list4 = cidr4.enumerate(:Limit => 4, :Bitstep => 32)
124
+ list4.each do |addr|
125
+ puts " #{addr}"
126
+ end
105
127
 
106
- cidr4.enumerate(:Limit => 4, :Bitstep => 32) {|addr| puts addr}
107
- cidr6.enumerate(:Limit => 4, :Bitstep => 32, :Objectify => 1) {|addr| puts addr.desc()}
128
+ puts "first 4 cidr6 addresses (bitstep 32)"
129
+ list6 = cidr6.enumerate(:Limit => 4, :Bitstep => 32, :Objectify => 1)
130
+ list6.each do |addr|
131
+ puts " #{addr.desc}"
132
+ end
108
133
 
109
- cidr4.subnet(:Subnet => 28, :MinCount => 3) {|cidr| puts cidr.desc()}
110
- cidr6.subnet(:Subnet => 66, :MinCount => 4) {|cidr| puts cidr.desc()}
134
+ # subnet
135
+ puts "cidr4 subnetted into at least 3 /28 ranges"
136
+ sn4 = cidr4.subnet(:Subnet => 28, :MinCount => 3)
137
+ sn4.each do |cidr|
138
+ puts " #{cidr.desc()}"
139
+ end
111
140
 
112
- print "\n\n\n"
141
+ puts "cidr6 subnetted into at least 4 /66 ranges"
142
+ sn6 = cidr6.subnet(:Subnet => 66, :MinCount => 4)
143
+ sn6.each do |cidr|
144
+ puts " #{cidr.desc()}"
145
+ end
146
+
147
+ print "\n\n\n"
113
148
  #=====================================#
114
- #
149
+ #
115
150
  #=====================================#
116
151
 
117
-
118
152
  #============================================================================#
119
153
  # IPAdmin::CIDRTable
120
154
  #============================================================================#
@@ -127,20 +161,17 @@
127
161
  cidr4_5 = IPAdmin::CIDR.new(:CIDR => '192.168.1.64/26')
128
162
  cidr4_6 = IPAdmin::CIDR.new(:CIDR => '192.168.1.128/26')
129
163
  cidr4_7 = IPAdmin::CIDR.new(:CIDR => '192.168.1.192/26')
130
-
164
+
131
165
  cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::/10')
132
166
  cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fe80::/10')
133
167
  cidr6_3 = IPAdmin::CIDR.new(:CIDR => 'fec0::/64')
134
168
  cidr6_4 =IPAdmin::CIDR.new(:CIDR => 'fec0::/126')
135
-
136
- begin
137
- table4 = IPAdmin::CIDRTable.new(4)
138
- table6 = IPAdmin::CIDRTable.new(6)
139
- rescue Exception
140
- puts 'oops'
141
- exit
142
- end
143
-
169
+
170
+ # new
171
+ table4 = IPAdmin::CIDRTable.new(4)
172
+ table6 = IPAdmin::CIDRTable.new(6)
173
+
174
+ # add_cidr
144
175
  table4.add_cidr(cidr4_1)
145
176
  table4.add_cidr(cidr4_2)
146
177
  table4.add_cidr(cidr4_3)
@@ -148,92 +179,105 @@
148
179
  table4.add_cidr(cidr4_5)
149
180
  table4.add_cidr(cidr4_6)
150
181
  table4.add_cidr(cidr4_7)
151
-
182
+
152
183
  table6.add_cidr(cidr6_1)
153
184
  table6.add_cidr(cidr6_2)
154
185
  table6.add_cidr(cidr6_3)
155
186
  table6.add_cidr(cidr6_4)
156
187
 
157
- puts "ip4 belongs in #{table4.find_ip(ip4).desc}"
158
- puts "ip6 belongs in #{table6.find_ip(ip6).desc}"
159
-
188
+ # find_ip
189
+ puts "#{ip4.desc} belongs in #{table4.find_ip(ip4).desc}"
190
+ puts "#{ip6.desc} belongs in #{table6.find_ip(ip6).desc}"
191
+
192
+ # find_space
160
193
  puts "all blocks that can hold a /27"
161
194
  list4 = table4.find_space(:Size => 27)
162
195
  list4.each do |cidr|
163
196
  puts " #{cidr.desc()}"
164
197
  end
165
-
198
+
166
199
  puts "first block that can hold a /64"
167
200
  list6 = table6.find_space(:Size => 64, :Limit => 1)
168
201
  list6.each do |cidr|
169
202
  puts " #{cidr.desc()}"
170
203
  end
171
-
172
-
204
+
205
+ # dump
173
206
  puts 'dump table4...'
174
- dump4 = table4.dump
207
+ dump4 = table4.dump
175
208
  dump4.each do |cidr|
176
209
  puts " #{cidr.desc}"
177
210
  end
178
211
  puts 'dump table6...'
179
- dump6 = table6.dump
212
+ dump6 = table6.dump
180
213
  dump6.each do |cidr|
181
214
  puts " #{cidr.desc}"
182
215
  end
216
+
217
+ puts "remove 192.168.1.0/26 from table4"
218
+ table4.rem_cidr(cidr4_3)
219
+ dump4 = table4.dump
220
+ dump4.each do |cidr|
221
+ puts " #{cidr.desc}"
222
+ end
183
223
 
184
224
  print "\n\n\n"
185
225
  #=====================================#
186
- #
226
+ #
187
227
  #=====================================#
188
228
 
189
-
190
229
  #============================================================================#
191
- # IPAdmin Misc Methods
230
+ # IPAdmin Methods
192
231
  #============================================================================#
193
- puts "Misc Methods"
232
+ puts "IPAdmin Methods"
194
233
 
234
+ # validate ip
195
235
  puts "192.168.1.0 is valid" if ( IPAdmin.validate_ipv4_addr('192.168.1.0') )
196
236
  puts "192.168.1.0 is valid" if ( IPAdmin.validate_ipv6_addr('fec0::0') )
197
-
237
+
238
+ # validate netmask
198
239
  puts "255.255.255.0 is valid" if (IPAdmin.validate_ipv4_netmask('255.255.255.0') )
199
240
  puts "/24 is valid" if ( IPAdmin.validate_ipv4_netmask(24) )
200
241
  puts "/64 is valid" if ( IPAdmin.validate_ipv6_netmask(64) )
201
-
242
+
202
243
  cidr4_1 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
203
244
  cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/25')
204
245
  cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/10')
205
246
  cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/64')
206
-
247
+
248
+ # compare_cidr
207
249
  comp1 = IPAdmin.compare_cidr(cidr4_1,cidr4_2)
208
250
  comp2 = IPAdmin.compare_cidr(cidr6_1,cidr6_2)
209
251
  puts "#{(comp1[0]).desc} is the supernet of #{(comp1[1]).desc}"
210
252
  puts "#{(comp2[0]).desc} is the supernet of #{(comp2[1]).desc}"
211
-
253
+
212
254
  cidr4_1 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
213
255
  cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.0.0/24')
214
256
  cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/128')
215
257
  cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fec0::1/128')
216
-
258
+
259
+ # merge_cidr
217
260
  puts "192.168.1.0/24 and 192.168.0.0/24 merge into #{IPAdmin.merge_cidr([cidr4_1,cidr4_2]).desc}"
218
261
  puts "fec0::0/128 and fec0::1/128 merge into #{IPAdmin.merge_cidr([cidr6_1,cidr6_2]).desc}"
219
262
 
220
263
  ip1 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.0')
221
264
  ip2 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.50')
222
265
 
223
-
266
+ # range
224
267
  list = IPAdmin.range(:Boundaries => [ip1,ip2], :Bitstep => 20 )
225
- puts "ip's between #{ip1.desc} and #{ip2.desc}"
268
+ puts "ip's between #{ip1.desc} and #{ip2.desc} (bitstep of 20)"
226
269
  list.each do |x|
227
270
  puts " #{x}"
228
271
  end
229
272
 
273
+ # make_arpa
274
+ puts "arpa for #{cidr4_1.desc()} is #{IPAdmin.make_arpa(cidr4_1)}"
275
+ puts "arpa for #{cidr6_1.desc()} is #{IPAdmin.make_arpa(cidr6_1)}"
230
276
 
277
+ # v6_short
278
+ puts "shorthand notation for #{cidr6_1.network()} is #{IPAdmin.v6_short(cidr6_1.network)}"
279
+
231
280
  print "\n\n\n"
232
281
  #=====================================#
233
- #
282
+ #
234
283
  #=====================================#
235
-
236
-
237
-
238
-
239
-
@@ -9,18 +9,23 @@ module IPAdmin
9
9
  # Compare cidr addresses of two IPAdmin::CIDR objects.
10
10
  # - Arguments:
11
11
  # * Two IPAdmin::CIDR objects
12
- #
12
+ #
13
13
  # - Returns:
14
14
  # * if one object is a subnet of another, then return an array in order of
15
15
  # [supernet,subnet]
16
16
  # * if both are equal, return 1
17
17
  # * if neither is a subnet of the other, return nil
18
18
  #
19
+ # Example:
20
+ # supernet,subnet = IPAdmin.compare_cidr(cidr1,cidr2)
21
+ # puts "#{supernet.desc} is the supernet of #{subnet.desc}"
22
+ #
23
+
19
24
  def compare_cidr(cidr1,cidr2)
20
25
 
21
26
  # we only accept CIDR objects
22
27
  unless ( (cidr1.kind_of? IPAdmin::CIDR)&&(cidr2.kind_of? IPAdmin::CIDR) )
23
- raise "Expected IPAdmin::CIDR, but #{options.class} provided."
28
+ raise ArgumentError, "Arguments shouldbe of type IPAdmin::CIDR."
24
29
  end
25
30
 
26
31
  # make sure both are same version
@@ -74,6 +79,84 @@ module_function :compare_cidr
74
79
 
75
80
 
76
81
 
82
+ #============================================================================#
83
+ # make_arpa()
84
+ #============================================================================#
85
+
86
+ # Given the address in the provided IPAdmin::IPAddr or IPAdmin::CIDR object,
87
+ # return either an in-addr.arpa. or ip6.arpa string. If an IPAdmin::CIDR
88
+ # object is provided, then its netmask will be used to determine the length
89
+ # of the returned arpa string.
90
+ #
91
+ # - Arguments:
92
+ # * IPAdmin::CIDR or IPAdmin::IPAddr object
93
+ #
94
+ # - Returns:
95
+ # * IP/CIDR address in in-addr.arpa or ip6.arpa format
96
+ #
97
+ # Example:
98
+ # arpa = IPAdmin.make_arpa(cidr)
99
+ #
100
+ def make_arpa(object)
101
+
102
+ if (object.kind_of? IPAdmin::CIDR)
103
+ base = object.network()
104
+ netmask = object.bits()
105
+
106
+ elsif (object.kind_of? IPAdmin::IPAddr)
107
+ base = object.ip()
108
+
109
+ else
110
+ raise ArgumentError, "Expected IPAdmin::CIDR or IPAdmin::IPAddr object, " +
111
+ "but #{object.class} provided."
112
+ end
113
+
114
+
115
+ if (object.version == 4)
116
+ net = base.split('.')
117
+
118
+ if (netmask)
119
+ while (netmask < 32)
120
+ net.pop
121
+ netmask = netmask + 8
122
+ end
123
+ end
124
+
125
+ arpa = net.reverse.join('.')
126
+ arpa << ".in-addr.arpa."
127
+
128
+ else
129
+ fields = base.split(':')
130
+ net = []
131
+ fields.each do |field|
132
+ (field.split("")).each do |x|
133
+ net.push(x)
134
+ end
135
+ end
136
+
137
+ if (netmask)
138
+ while (netmask < 128)
139
+ net.pop
140
+ netmask = netmask + 4
141
+ end
142
+ end
143
+
144
+ arpa = net.reverse.join('.')
145
+ arpa << ".ip6.arpa."
146
+
147
+ end
148
+
149
+ return(arpa)
150
+
151
+ end
152
+ module_function :make_arpa
153
+
154
+ #=====================================#
155
+ #
156
+ #=====================================#
157
+
158
+
159
+
77
160
  #============================================================================#
78
161
  # merge_cidr()
79
162
  #============================================================================#
@@ -87,11 +170,14 @@ module_function :compare_cidr
87
170
  # - Returns:
88
171
  # * IPAdmin::CIDR object
89
172
  #
173
+ # Example:
174
+ # merged = IPAdmin.merge_cidr([cidr1,cidr2])
175
+ #
90
176
  def merge_cidr(cidr_list)
91
177
 
92
178
  # make sure we have an array with at least 2 objects
93
179
  unless ( (cidr_list.kind_of? Array) && (cidr_list.length > 1) )
94
- raise "Array of at least two IPAdmin::CIDR objects required."
180
+ raise ArgumentError, "Array of at least two IPAdmin::CIDR objects required."
95
181
  end
96
182
 
97
183
 
@@ -99,7 +185,7 @@ def merge_cidr(cidr_list)
99
185
  version = {}
100
186
  cidr_list.each do |cidr|
101
187
  unless (cidr.kind_of? IPAdmin::CIDR)
102
- raise "Expected IPAdmin::CIDR, but #{options.class} provided."
188
+ raise ArgumentError, "Expected IPAdmin::CIDR, but #{cidr.class} provided."
103
189
  end
104
190
  version[cidr.version] = 1
105
191
  end
@@ -193,12 +279,15 @@ module_function :merge_cidr
193
279
  #
194
280
  # - Returns:
195
281
  # * packed IPv4 address or exception on error.
282
+ #
283
+ # Example:
284
+ # packed = IPAdmin.pack_ipv4_addr('192.168.1.1')
196
285
  #
197
286
  def pack_ipv4_addr(ip)
198
287
 
199
288
  # is this a string?
200
289
  unless (ip.kind_of? String)
201
- raise "Expected String, but #{ip.class} provided."
290
+ raise ArgumentError, "Expected String, but #{ip.class} provided."
202
291
  end
203
292
 
204
293
  # pack our ip
@@ -227,7 +316,7 @@ module_function :pack_ipv4_addr
227
316
  # pack_ipv4_netmask()
228
317
  #============================================================================#
229
318
 
230
- # Pack IPv4 netmask into a single byte field. No attempt at validation
319
+ # Pack IPv4 netmask into a single byte field. Only very basic validation
231
320
  # is performed.
232
321
  # - Arguments:
233
322
  # * IPv4 netmask in cidr or extended notation
@@ -235,6 +324,10 @@ module_function :pack_ipv4_addr
235
324
  # - Returns:
236
325
  # * packed IPv4 netmask or exception on error.
237
326
  #
327
+ # Example:
328
+ # packed = IPAdmin.pack_ipv4_netmask('255.255.255.0')
329
+ # packed = IPAdmin.pack_ipv4_netmask('24')
330
+ #
238
331
  def pack_ipv4_netmask(netmask)
239
332
 
240
333
  all_f = 2**32-1
@@ -247,10 +340,21 @@ def pack_ipv4_netmask(netmask)
247
340
  packed_netmask = pack_ipv4_addr(netmask)
248
341
  packed_hostmask = packed_netmask ^ all_f
249
342
  rescue Exception
250
- raise "#{netmask} is invalid."
343
+ raise "#{netmask} is not a valid IPv4 netmask."
251
344
  end
252
345
 
253
- elsif (netmask !~ /\D/)
346
+ else
347
+ # remove '/' if present
348
+ if (netmask =~ /^\// )
349
+ netmask[0] = " "
350
+ netmask.lstrip!
351
+ end
352
+
353
+ # check if we have any non numeric characters
354
+ if (netmask =~ /\D/)
355
+ raise "#{netmask} is not a valid IPv4 netmask."
356
+ end
357
+
254
358
  if (netmask.kind_of? String)
255
359
  netmask = netmask.to_i
256
360
  end
@@ -258,9 +362,6 @@ def pack_ipv4_netmask(netmask)
258
362
  packed_hostmask = all_f >> netmask
259
363
  packed_netmask = all_f ^ packed_hostmask
260
364
 
261
- else
262
- raise "#{netmask} is unrecognized."
263
-
264
365
  end
265
366
 
266
367
  ret_vals = [packed_netmask,packed_hostmask]
@@ -287,11 +388,14 @@ module_function :pack_ipv4_netmask
287
388
  # - Returns:
288
389
  # * packed IPv6 address or exception on error.
289
390
  #
391
+ # Example:
392
+ # packed = IPAdmin.pack_ipv4_netmask('fec0::0001')
393
+ #
290
394
  def pack_ipv6_addr(ip)
291
395
 
292
396
  # is this a string?
293
397
  unless (ip.kind_of? String)
294
- raise "Expected String, but #{ip.class} provided."
398
+ raise ArgumentError, "Expected String, but #{ip.class} provided."
295
399
  end
296
400
 
297
401
 
@@ -351,7 +455,7 @@ module_function :pack_ipv6_addr
351
455
  # pack_ipv6_netmask()
352
456
  #============================================================================#
353
457
 
354
- # Pack IPv6 netmask into a single byte field. No attempt at validation
458
+ # Pack IPv6 netmask into a single byte field. Only very basic validation
355
459
  # is performed.
356
460
  # - Arguments:
357
461
  # * IPv6 netmask in cidr notation
@@ -359,10 +463,18 @@ module_function :pack_ipv6_addr
359
463
  # - Returns:
360
464
  # * packed IPv6 netmask or exception on error.
361
465
  #
466
+ # Example:
467
+ # packed = IPAdmin.pack_ipv4_netmask('64')
468
+ #
362
469
  def pack_ipv6_netmask(netmask)
363
470
 
364
471
  all_f = 2**128-1
365
472
 
473
+ # remove '/' if present
474
+ if (netmask =~ /^\// )
475
+ netmask[0] = " "
476
+ netmask.lstrip!
477
+ end
366
478
 
367
479
  if (netmask !~ /\D/)
368
480
  # pack
@@ -374,7 +486,7 @@ def pack_ipv6_netmask(netmask)
374
486
  packed_netmask = all_f ^ packed_hostmask
375
487
 
376
488
  else
377
- raise "#{netmask} is unrecognized."
489
+ raise "#{netmask} is not a valid IPv6 netmask."
378
490
 
379
491
  end
380
492
 
@@ -401,14 +513,17 @@ module_function :pack_ipv6_netmask
401
513
  #
402
514
  # - Arguments:
403
515
  # * Hash with the following fields
404
- # - :Bitstep -- enumerate in X sized steps
405
- # - :Boundaries -- array of (2) IPAdmin::IPAddr objects
406
- # - :Limit -- limit returned list to X number of items
407
- # - :Objectify -- return IPAdmin::IPAddr objects
516
+ # - :Bitstep -- enumerate in X sized steps
517
+ # - :Boundaries -- array of (2) IPAdmin::IPAddr objects
518
+ # - :Limit -- limit returned list to X number of items
519
+ # - :Objectify -- return IPAdmin::IPAddr objects
408
520
  #
409
521
  # - Returns:
410
522
  # * array of IP addresses or IPAdmin::IPAddr objects
411
523
  #
524
+ # Example:
525
+ # list = IPAdmin.range(:Boundaries => [ip1,ip2])
526
+ #
412
527
  def range(options)
413
528
  list = []
414
529
  bitstep = 1
@@ -537,6 +652,9 @@ module_function :range
537
652
  # - Returns:
538
653
  # * IPv4 address.
539
654
  #
655
+ # Example:
656
+ # unpacked = IPAdmin.unpack_ipv4_addr(packed)
657
+ #
540
658
  def unpack_ipv4_addr(packed_ip)
541
659
 
542
660
  octets = []
@@ -571,6 +689,9 @@ module_function :unpack_ipv4_addr
571
689
  # - Returns:
572
690
  # * IPv4 netmask as number of bits (cidr format).
573
691
  #
692
+ # Example:
693
+ # unpacked = IPAdmin.unpack_ipv4_netmask(packed)
694
+ #
574
695
  def unpack_ipv4_netmask(packed_mask)
575
696
 
576
697
  mask = 32
@@ -604,6 +725,9 @@ module_function :unpack_ipv4_netmask
604
725
  # - Returns:
605
726
  # * IPv6 address.
606
727
  #
728
+ # Example:
729
+ # unpacked = IPAdmin.unpack_ipv6_addr(packed)
730
+ #
607
731
  def unpack_ipv6_addr(packed_ip)
608
732
  hex_fields = []
609
733
  (0..7).each do |x|
@@ -642,6 +766,9 @@ module_function :unpack_ipv6_addr
642
766
  # - Returns:
643
767
  # * IPv6 netmask as number of bits (cidr format).
644
768
  #
769
+ # Example:
770
+ # unpacked = IPAdmin.unpack_ipv6_netmask(packed)
771
+ #
645
772
  def unpack_ipv6_netmask(packed_mask)
646
773
 
647
774
  mask = 128
@@ -663,22 +790,104 @@ module_function :unpack_ipv6_netmask
663
790
 
664
791
 
665
792
 
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
+
666
872
  #============================================================================#
667
873
  # validate_ipv4_addr()
668
874
  #============================================================================#
669
875
 
670
- # Validate IPv4 addresses.
876
+ # Validate IPv4 addresses. Address should not contain a netmask.
671
877
  # - Arguments:
672
878
  # * IPv4 address
673
879
  #
674
880
  # - Returns:
675
881
  # * 1 on valid IP or exception on error.
676
882
  #
883
+ # Example:
884
+ # IPAdmin.validate_ipv4_addr('192.168.1.1')
885
+ #
677
886
  def validate_ipv4_addr(ip)
678
887
 
679
888
  # is this a string?
680
889
  unless (ip.kind_of? String)
681
- raise "Expected String, but #{ip.class} provided."
890
+ raise ArgumentError, "Expected String, but #{ip.class} provided."
682
891
  end
683
892
  octets = ip.split( /\./ )
684
893
 
@@ -686,14 +895,14 @@ def validate_ipv4_addr(ip)
686
895
 
687
896
  # check validity of characters in the addr
688
897
  if ( (ip =~ /\.{2,}?/ ) || (ip =~ /[^0-9\.]/) )
689
- raise "#{ip} is invalid."
898
+ raise "#{ip} is not a valid IPv4 address."
690
899
  end
691
900
 
692
901
 
693
902
 
694
903
  # do we have 4 octets?
695
904
  if (octets.length != 4)
696
- raise "#{ip} is invalid."
905
+ raise "#{ip} is not a valid IPv4 address."
697
906
  end
698
907
 
699
908
 
@@ -702,14 +911,14 @@ def validate_ipv4_addr(ip)
702
911
  (0..3).each do |x|
703
912
  octets[x] = octets[x].to_i
704
913
  unless ( (octets[x] >= 0) && (octets[x] < 256 ) )
705
- raise "#{ip} is invalid."
914
+ raise "#{ip} is not a valid IPv4 address."
706
915
  end
707
916
  end
708
917
 
709
918
 
710
919
  # dont allow first octet to be 0
711
920
  if (octets[0] == 0)
712
- raise "#{ip} is invalid."
921
+ raise "#{ip} is not a valid IPv4 address."
713
922
  end
714
923
 
715
924
  return(1)
@@ -734,6 +943,12 @@ module_function :validate_ipv4_addr
734
943
  # - Returns:
735
944
  # * 1 on valid IP or exception on error.
736
945
  #
946
+ # Example:
947
+ # IPAdmin.validate_ipv4_netmask('255.255.255.0')
948
+ # IPAdmin.validate_ipv4_netmask('24')
949
+ # IPAdmin.validate_ipv4_netmask('/24')
950
+ # IPAdmin.validate_ipv4_netmask(24)
951
+ #
737
952
  def validate_ipv4_netmask(netmask)
738
953
 
739
954
  all_f = (2**32)-1
@@ -747,7 +962,7 @@ def validate_ipv4_netmask(netmask)
747
962
  packed_mask = pack_ipv4_addr(netmask)
748
963
 
749
964
  rescue Exception
750
- raise "#{netmask} is invalid."
965
+ raise "#{netmask} is not a valid IPv4 netmask."
751
966
  end
752
967
 
753
968
  # cycle through the bits of hostmask and compare
@@ -762,7 +977,7 @@ def validate_ipv4_netmask(netmask)
762
977
  if ( check != 0)
763
978
  hostmask = hostmask >> 1
764
979
  unless ( (packed_mask ^ hostmask) == all_f)
765
- raise "#{netmask} is invalid."
980
+ raise "#{netmask} is not a valid IPv4 netmask."
766
981
  end
767
982
  break
768
983
  else
@@ -773,9 +988,15 @@ def validate_ipv4_netmask(netmask)
773
988
 
774
989
  else
775
990
 
991
+ # remove '/' if present
992
+ if (netmask =~ /^\// )
993
+ netmask[0] = " "
994
+ netmask.lstrip!
995
+ end
996
+
776
997
  # check if we have any non numeric characters
777
998
  if (netmask =~ /\D/)
778
- raise "#{netmask} is invalid."
999
+ raise "#{netmask} is not a valid IPv4 netmask."
779
1000
  end
780
1001
 
781
1002
 
@@ -785,7 +1006,7 @@ def validate_ipv4_netmask(netmask)
785
1006
  end
786
1007
 
787
1008
  if ( (netmask > 32) || (netmask == 0) )
788
- raise "#{netmask} is invalid."
1009
+ raise "#{netmask} is not a valid IPv4 netmask."
789
1010
  end
790
1011
 
791
1012
  end
@@ -805,24 +1026,27 @@ module_function :validate_ipv4_netmask
805
1026
  # validate_ipv6_addr()
806
1027
  #============================================================================#
807
1028
 
808
- # Validate IPv6 addresses.
1029
+ # Validate IPv6 addresses. Address should not contain a netmask.
809
1030
  # - Arguments:
810
1031
  # * IPv6 address
811
1032
  #
812
1033
  # - Returns:
813
1034
  # * 1 on valid IP or exception on error.
814
1035
  #
1036
+ # Example:
1037
+ # IPAdmin.validate_ipv6_addr('fec0::')
1038
+ #
815
1039
  def validate_ipv6_addr(ip)
816
1040
  # is this a string?
817
1041
  unless (ip.kind_of? String)
818
- raise "Expected String, but #{ip.class} provided."
1042
+ raise ArgumentError, "Expected String, but #{ip.class} provided."
819
1043
  end
820
1044
 
821
1045
 
822
1046
 
823
1047
  # check validity of characters in the addr
824
1048
  if ( (ip =~ /:{3,}?/ ) || (ip =~ /[^0-9a-fA-F:]/) )
825
- raise "#{ip} is invalid."
1049
+ raise "#{ip} is not a valid IPv6 address."
826
1050
  end
827
1051
 
828
1052
 
@@ -833,7 +1057,7 @@ def validate_ipv6_addr(ip)
833
1057
  if (ip =~ /::/)
834
1058
  shrthnd = ip.split( /::/ )
835
1059
  unless ( (shrthnd.length > 0) && (shrthnd.length < 3) )
836
- raise "#{ip} is invalid."
1060
+ raise "#{ip} is not a valid IPv6 address."
837
1061
  end
838
1062
  end
839
1063
 
@@ -848,7 +1072,7 @@ def validate_ipv6_addr(ip)
848
1072
  elements.each {|x| hex_fields.push(x)}
849
1073
  end
850
1074
  if ( (hex_fields.length < 1) || (hex_fields.length > 7) )
851
- raise "#{ip} is invalid."
1075
+ raise "#{ip} is not a valid IPv6 address."
852
1076
  end
853
1077
 
854
1078
  else
@@ -856,7 +1080,7 @@ def validate_ipv6_addr(ip)
856
1080
  # have exactly 8 hex fields
857
1081
  hex_fields = ip.split( /:/ )
858
1082
  if (hex_fields.length != 8)
859
- raise "#{ip} is invalid."
1083
+ raise "#{ip} is not a valid IPv6 address."
860
1084
  end
861
1085
 
862
1086
  end
@@ -867,7 +1091,7 @@ def validate_ipv6_addr(ip)
867
1091
  # hex field
868
1092
  hex_fields.each do |x|
869
1093
  if (x.length > 4)
870
- raise "#{ip} is invalid."
1094
+ raise "#{ip} is not a valid IPv6 address."
871
1095
  end
872
1096
  end
873
1097
 
@@ -893,11 +1117,22 @@ module_function :validate_ipv6_addr
893
1117
  #
894
1118
  # - Returns:
895
1119
  # * 1 on valid IP or exception on error.
1120
+ #
1121
+ # Example:
1122
+ # IPAdmin.validate_ipv6_netmask('64')
1123
+ # IPAdmin.validate_ipv6_netmask('/64')
1124
+ # IPAdmin.validate_ipv6_netmask(64)
896
1125
  #
897
1126
  def validate_ipv6_netmask(netmask)
898
1127
 
1128
+ # remove '/' if present
1129
+ if (netmask =~ /^\// )
1130
+ netmask[0] = " "
1131
+ netmask.lstrip!
1132
+ end
1133
+
899
1134
  if (netmask =~ /\D/)
900
- raise "#{netmask} is invalid."
1135
+ raise "#{netmask} is not a valid IPv6 netmask."
901
1136
 
902
1137
  else
903
1138
  # are we between 1 and 128 inclusive
@@ -906,7 +1141,7 @@ def validate_ipv6_netmask(netmask)
906
1141
  end
907
1142
 
908
1143
  if ( (netmask > 128) || (netmask == 0) )
909
- raise "#{netmask} is invalid."
1144
+ raise "#{netmask} is not a valid IPv6 netmask."
910
1145
  end
911
1146
 
912
1147
  end
@@ -942,17 +1177,20 @@ class CIDR
942
1177
  #============================================================================#
943
1178
  # attr_reader/attr_writer
944
1179
  #============================================================================#
945
-
946
- # @network - packed cidr network
947
- # @netmask - packet cidr netmask
948
- # @hostmask - inverse packed netmask
949
1180
 
950
1181
  # ip version 4 or 6
951
1182
  attr_reader :version
952
1183
 
953
1184
  # hash of custom tags. should be in the format tag => value
954
1185
  attr_reader :tag
955
- attr_writer :tag
1186
+
1187
+ # attr_writer - hash of custom tags. should be in the format tag => value
1188
+ def tag=(new_tag)
1189
+ unless (new_tag.kind_of? Hash)
1190
+ raise ArgumentError, "Expected Hash, but #{new_tag.class} provided."
1191
+ end
1192
+ @tag = new_tag
1193
+ end
956
1194
 
957
1195
  #=====================================#
958
1196
  #
@@ -966,14 +1204,21 @@ class CIDR
966
1204
 
967
1205
  # - Arguments:
968
1206
  # * Hash with the following fields:
969
- # :CIDR -- IPv4 or IPv6 cidr block
970
- # :Netmask -- IPv4 netmask in extended format (if not provided in :CIDR)
971
- # :Tag -- Custom descriptor tag for object. Should be Hash (tag => value)
1207
+ # - :CIDR -- IPv4 or IPv6 cidr block
1208
+ # - :Netmask -- IPv4 netmask in extended format (if not provided in :CIDR)
1209
+ # - :Tag -- Custom descriptor tag for object. Should be Hash (tag => value)
1210
+ #
1211
+ # Example:
1212
+ # cidr4 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0',
1213
+ # :Netmask => '255.255.255.0')
1214
+ # cidr6 = IPAdmin::CIDR.new(:CIDR => 'fec0::/64',
1215
+ # :Tag => {'interface' => 'g0/1'})
1216
+ #
972
1217
  #
973
1218
  def initialize(options)
974
1219
 
975
1220
  unless (options.kind_of? Hash)
976
- raise "Expected Hash, but #{options.class} provided."
1221
+ raise ArgumentError, "Expected Hash, but #{options.class} provided."
977
1222
  end
978
1223
 
979
1224
 
@@ -1051,8 +1296,11 @@ class CIDR
1051
1296
 
1052
1297
 
1053
1298
  # set tag if present
1054
- if ( options.has_key?(:Tag) )
1299
+ if ( options.has_key?(:Tag) )
1055
1300
  @tag = options[:Tag]
1301
+ unless (@tag.kind_of? Hash)
1302
+ raise "Expected Hash, but #{@tag.class} provided for option :Tag."
1303
+ end
1056
1304
  end
1057
1305
 
1058
1306
 
@@ -1064,6 +1312,37 @@ class CIDR
1064
1312
 
1065
1313
 
1066
1314
 
1315
+ #============================================================================#
1316
+ # bits()
1317
+ #============================================================================#
1318
+
1319
+ # Provide number of bits of Netmask.
1320
+ #
1321
+ # - Arguments:
1322
+ # * none
1323
+ #
1324
+ # - Returns:
1325
+ # * Number of bits of Netmask.
1326
+ #
1327
+ # Example:
1328
+ # bits = cidr.bits()
1329
+ #
1330
+ def bits()
1331
+ if (@version == 4)
1332
+ bits = IPAdmin.unpack_ipv4_netmask(@netmask)
1333
+ else
1334
+ bits = IPAdmin.unpack_ipv6_netmask(@netmask)
1335
+ end
1336
+
1337
+ return(bits)
1338
+ end
1339
+
1340
+ #=====================================#
1341
+ #
1342
+ #=====================================#
1343
+
1344
+
1345
+
1067
1346
  #============================================================================#
1068
1347
  # contains()
1069
1348
  #============================================================================#
@@ -1075,9 +1354,16 @@ class CIDR
1075
1354
  #
1076
1355
  # - Returns:
1077
1356
  # * 1 on true, nil on false
1357
+ #
1358
+ # Example:
1359
+ # contains = cidr.contains(ip)
1078
1360
  #
1079
1361
  def contains(ip_obj)
1080
1362
 
1363
+ unless (ip_obj.kind_of? IPAdmin::IPAddr)
1364
+ raise ArgumentError, "Expected IPAdmin::IPAddr object, but #{ip_obj.class} provided."
1365
+ end
1366
+
1081
1367
  if ( (ip_obj.version == 4) && (@version == 4) )
1082
1368
  v4_all_f = (2**32)-1
1083
1369
  hostmask = @netmask ^ v4_all_f
@@ -1117,6 +1403,9 @@ class CIDR
1117
1403
  #
1118
1404
  # - Returns:
1119
1405
  # * Description in network/netmask format
1406
+ #
1407
+ # Example:
1408
+ # desc = cidr.desc()
1120
1409
  #
1121
1410
  def desc()
1122
1411
 
@@ -1147,12 +1436,15 @@ class CIDR
1147
1436
  #
1148
1437
  # - Arguments:
1149
1438
  # * Hash with the following fields
1150
- # - :Bitstep -- enumerate in X sized steps
1151
- # - :Objectify -- return IPAdmin::IPAddr objects
1152
- # - :Limit -- limit returned list to X number of items
1439
+ # - :Bitstep -- enumerate in X sized steps
1440
+ # - :Objectify -- return IPAdmin::IPAddr objects
1441
+ # - :Limit -- limit returned list to X number of items
1153
1442
  #
1154
1443
  # - Returns:
1155
1444
  # * array of IP addresses or IPAdmin::IPAddr objects
1445
+ #
1446
+ # Example:
1447
+ # ip_list = cidr.enumerate(:Bitstep => 2)
1156
1448
  #
1157
1449
  def enumerate(options=nil)
1158
1450
  bitstep = 1
@@ -1265,6 +1557,9 @@ class CIDR
1265
1557
  #
1266
1558
  # - Returns:
1267
1559
  # * Hostmask in extended (y.y.y.y) format.
1560
+ #
1561
+ # Example:
1562
+ # hostmask = cidr.hostmask_ext()
1268
1563
  #
1269
1564
  def hostmask_ext()
1270
1565
  if (@version == 4)
@@ -1292,7 +1587,10 @@ class CIDR
1292
1587
  # * none
1293
1588
  #
1294
1589
  # - Returns:
1295
- # * Number of bits in the netmask.
1590
+ # * Netmask in CIDR format.
1591
+ #
1592
+ # Example:
1593
+ # netmask = cidr.netmask()
1296
1594
  #
1297
1595
  def netmask()
1298
1596
  if (@version == 4)
@@ -1301,7 +1599,7 @@ class CIDR
1301
1599
  bits = IPAdmin.unpack_ipv6_netmask(@netmask)
1302
1600
  end
1303
1601
 
1304
- return(bits)
1602
+ return("/#{bits}")
1305
1603
  end
1306
1604
 
1307
1605
  #=====================================#
@@ -1321,13 +1619,16 @@ class CIDR
1321
1619
  #
1322
1620
  # - Returns:
1323
1621
  # * Netmask in extended (y.y.y.y) format.
1622
+ #
1623
+ # Example:
1624
+ # netmask = cidr.netmask_ext()
1324
1625
  #
1325
1626
  def netmask_ext()
1326
1627
  if (@version == 4)
1327
1628
  netmask = IPAdmin.unpack_ipv4_addr(@netmask)
1328
1629
  else
1329
1630
  raise "IPv6 does not support extended netmask notation. " +
1330
- "Use bits() method instead."
1631
+ "Use netmask() method instead."
1331
1632
  end
1332
1633
 
1333
1634
  return(netmask)
@@ -1350,6 +1651,9 @@ class CIDR
1350
1651
  #
1351
1652
  # - Returns:
1352
1653
  # * Base network address.
1654
+ #
1655
+ # Example:
1656
+ # network = cidr.network()
1353
1657
  #
1354
1658
  def network()
1355
1659
  if (@version == 4)
@@ -1375,11 +1679,14 @@ class CIDR
1375
1679
  #
1376
1680
  # - Arguments:
1377
1681
  # * Hash with the following fields
1378
- # - :Index -- index of the address to return
1379
- # - :Objectify -- return IPAdmin::IPAddr objects
1682
+ # - :Index -- index number of the IP address to return
1683
+ # - :Objectify -- return IPAdmin::IPAddr objects
1380
1684
  #
1381
1685
  # - Returns:
1382
1686
  # * IP address or IPAdmin::IPAddr object.
1687
+ #
1688
+ # Example:
1689
+ # first_ip = cidr.nth(:Index => 1)
1383
1690
  #
1384
1691
  def nth(options)
1385
1692
  objectify = nil
@@ -1458,6 +1765,9 @@ class CIDR
1458
1765
  #
1459
1766
  # - Returns:
1460
1767
  # * Byte-packed Hostmask.
1768
+ #
1769
+ # Example:
1770
+ # packed = cidr.packed_hostmask()
1461
1771
  #
1462
1772
  def packed_hostmask()
1463
1773
  return(@hostmask)
@@ -1480,6 +1790,9 @@ class CIDR
1480
1790
  #
1481
1791
  # - Returns:
1482
1792
  # * Byte-packed Netmask.
1793
+ #
1794
+ # Example:
1795
+ # packed = cidr.packed_netmask()
1483
1796
  #
1484
1797
  def packed_netmask()
1485
1798
  return(@netmask)
@@ -1502,6 +1815,9 @@ class CIDR
1502
1815
  #
1503
1816
  # - Returns:
1504
1817
  # * Byte-packed Network Address.
1818
+ #
1819
+ # Example:
1820
+ # packed = cidr.packed_network()
1505
1821
  #
1506
1822
  def packed_network()
1507
1823
  return(@network)
@@ -1524,6 +1840,9 @@ class CIDR
1524
1840
  #
1525
1841
  # - Returns:
1526
1842
  # * Number of IP addresses in this CIDR block.
1843
+ #
1844
+ # Example:
1845
+ # num_ip = cidr.size()
1527
1846
  #
1528
1847
  def size()
1529
1848
  return(@hostmask + 1)
@@ -1544,16 +1863,19 @@ class CIDR
1544
1863
  #
1545
1864
  # - Arguments:
1546
1865
  # * Hash with the following fields:
1547
- # :Subnet -- number of bits of new subnet to create (24,26, etc...)
1548
- # :MinCount -- minimum number of subnets of size :Subnet to return
1866
+ # - :Subnet -- number of bits of new subnet to create (24,26, etc...)
1867
+ # - :MinCount -- minimum number of subnets of size :Subnet to return
1549
1868
  #
1550
1869
  # - Returns:
1551
1870
  # * array of IPAdmin::CIDR objects
1871
+ #
1872
+ # Example:
1873
+ # cidr_list = cidr4.subnet(:Subnet => 28, :MinCount => 3)
1552
1874
  #
1553
1875
  def subnet(options)
1554
1876
  subnet = options[:Subnet]
1555
1877
  min_count = options[:MinCount]
1556
- mymask = self.netmask
1878
+ mymask = self.bits
1557
1879
  num_avail = 2**(subnet - mymask)
1558
1880
  new_subnets = []
1559
1881
 
@@ -1698,12 +2020,15 @@ class CIDRTable
1698
2020
  #============================================================================#
1699
2021
 
1700
2022
  # - Arguments:
1701
- # * Table version (4 or 6)
2023
+ # * IP version (4 or 6)
2024
+ #
2025
+ # Example:
2026
+ # table = IPAdmin::CIDRTable.new(4)
1702
2027
  #
1703
2028
  def initialize(version)
1704
2029
 
1705
2030
  unless ( version.kind_of? Fixnum )
1706
- raise "Expected Fixnum, but #{version.class} provided."
2031
+ raise ArgumentError, "Expected Fixnum, but #{version.class} provided."
1707
2032
  end
1708
2033
 
1709
2034
  unless ( version == 4 || version == 6 )
@@ -1730,10 +2055,17 @@ class CIDRTable
1730
2055
  # * IPAdmin::CIDR object
1731
2056
  #
1732
2057
  # - Returns:
1733
- # * nil
2058
+ # * nothing
2059
+ #
2060
+ # Example:
2061
+ # table.add_cidr(cidr)
1734
2062
  #
1735
2063
  def add_cidr(new_cidr)
1736
2064
 
2065
+ unless (new_cidr.kind_of? IPAdmin::CIDR)
2066
+ raise ArgumentError, "Expected IPAdmin::CIDR, but #{new_cidr.class} provided."
2067
+ end
2068
+
1737
2069
  unless (new_cidr.version == @version )
1738
2070
  raise "CIDR version #{new_cidr.version} is incompatible with " +
1739
2071
  "CIDRTable version #{@version}."
@@ -1805,10 +2137,13 @@ class CIDRTable
1805
2137
  # Dump contents of this table
1806
2138
  #
1807
2139
  # - Arguments:
1808
- # * nil
2140
+ # * none
1809
2141
  #
1810
2142
  # - Returns:
1811
2143
  # * ordered array of IPAdmin::CIDR objects within this table
2144
+ #
2145
+ # Example:
2146
+ # cidr_list = table.dump()
1812
2147
  #
1813
2148
  def dump()
1814
2149
 
@@ -1855,15 +2190,18 @@ class CIDRTable
1855
2190
  #
1856
2191
  # - Returns:
1857
2192
  # * IPAdmin::CIDR object, or nil on no match
2193
+ #
2194
+ # Example:
2195
+ # cidr = table.find_ip(ip)
1858
2196
  #
1859
2197
  def find_ip(ip_obj)
1860
2198
 
1861
2199
  unless (ip_obj.kind_of? IPAdmin::IPAddr)
1862
- raise "Expected IPAdmin::IPAddr, but #{options.class} provided."
2200
+ raise ArgumentError, "Expected IPAdmin::IPAddr, but #{ip_obj.class} provided."
1863
2201
  end
1864
2202
 
1865
2203
  unless (ip_obj.version == @version )
1866
- raise "IPAddr version #{ip_addr.version} is incompatible with " +
2204
+ raise "IPAddr version #{ip_obj.version} is incompatible with " +
1867
2205
  "CIDRTable version #{@version}."
1868
2206
  end
1869
2207
 
@@ -1899,11 +2237,14 @@ class CIDRTable
1899
2237
  #
1900
2238
  # - Arguments:
1901
2239
  # * Hash with the following fields:
1902
- # :Size -- subnet size (number of bits)
1903
- # :Limit -- max entries to return
2240
+ # - :Size -- subnet size (number of bits)
2241
+ # - :Limit -- max entries to return
1904
2242
  #
1905
2243
  # - Returns:
1906
2244
  # * ordered array of IPAdmin::CIDR objects, or nil on no match
2245
+ #
2246
+ # Example:
2247
+ # cidr_list = table.find_space(:Size => 27)
1907
2248
  #
1908
2249
  def find_space(options)
1909
2250
  limit = nil
@@ -1915,11 +2256,11 @@ class CIDRTable
1915
2256
 
1916
2257
  # validate options
1917
2258
  unless (options.kind_of? Hash)
1918
- raise "Expected Hash, but #{options.class} provided."
2259
+ raise ArgumentError, "Expected Hash, but #{options.class} provided."
1919
2260
  end
1920
2261
 
1921
2262
  unless ( options.has_key?(:Size) )
1922
- raise "Missing argument :Size."
2263
+ raise ArgumentError, "Missing argument :Size."
1923
2264
  end
1924
2265
  subnet_size = options[:Size]
1925
2266
 
@@ -1953,7 +2294,7 @@ class CIDRTable
1953
2294
  # find space
1954
2295
  sorted_parents.each do |key|
1955
2296
  parent = parent_hash[key]
1956
- if ( parent.netmask() < subnet_size )
2297
+ if ( parent.bits() < subnet_size )
1957
2298
  if (@cidr_table[parent] != 0)
1958
2299
  child_list = []
1959
2300
  child_list = (@cidr_table[parent]).find_space(:Size => subnet_size)
@@ -1970,7 +2311,7 @@ class CIDRTable
1970
2311
 
1971
2312
  end
1972
2313
 
1973
- elsif ( (parent_hash[key].netmask() == subnet_size) &&
2314
+ elsif ( (parent_hash[key].bits() == subnet_size) &&
1974
2315
  (@cidr_table[parent] == 0) )
1975
2316
  list.push(parent)
1976
2317
 
@@ -1993,6 +2334,62 @@ class CIDRTable
1993
2334
 
1994
2335
 
1995
2336
 
2337
+ #============================================================================#
2338
+ # rem_cidr()
2339
+ #============================================================================#
2340
+
2341
+ # Remove an IPAdmin::CIDR object from this table
2342
+ #
2343
+ # - Arguments:
2344
+ # * IPAdmin::CIDR object
2345
+ #
2346
+ # - Returns:
2347
+ # * nothing
2348
+ #
2349
+ # Example:
2350
+ # table.rem_cidr(cidr)
2351
+ #
2352
+ def rem_cidr(cidr)
2353
+
2354
+ unless (cidr.kind_of? IPAdmin::CIDR)
2355
+ raise ArgumentError, "Expected IPAdmin::CIDR, but #{cidr.class} provided."
2356
+ end
2357
+
2358
+ unless (cidr.version == @version )
2359
+ raise "CIDR version #{cidr.version} is incompatible with " +
2360
+ "CIDRTable version #{@version}."
2361
+ end
2362
+
2363
+ # if cidr is part of this table
2364
+ if (@cidr_table.has_key?(cidr) )
2365
+
2366
+ if (@cidr_table[cidr] != 0)
2367
+ child_table = @cidr_table[cidr]
2368
+ child_table.cidr_table.each_key do |child|
2369
+ child_table.rem_cidr(child)
2370
+ end
2371
+ end
2372
+ @cidr_table.delete(cidr)
2373
+
2374
+ # else search @cidr_table to see if cidr is a child block
2375
+ else
2376
+ @cidr_table.each_key do |entry|
2377
+ parent,child = IPAdmin.compare_cidr(cidr,entry)
2378
+
2379
+ if (parent == entry)
2380
+ (@cidr_table[entry]).rem_cidr(cidr)
2381
+ end
2382
+ end
2383
+ end
2384
+
2385
+ end
2386
+
2387
+ #=====================================#
2388
+ #
2389
+ #=====================================#
2390
+
2391
+
2392
+
1996
2393
 
1997
2394
  end
1998
2395
 
@@ -2031,17 +2428,19 @@ class IPAddr
2031
2428
  # attr_reader/attr_writer
2032
2429
  #============================================================================#
2033
2430
 
2034
- # @ip - packed ip address
2035
- # @netmask - packed netmask
2036
- # @hostmask - inverse packed netmask
2037
-
2038
2431
  # ip version 4 or 6
2039
2432
  attr_reader :version
2040
2433
 
2041
2434
  # hash of custom tags. should be in the format tag => value
2042
2435
  attr_reader :tag
2043
- attr_writer :tag
2044
-
2436
+
2437
+ # attr_writer - hash of custom tags. should be in the format tag => value
2438
+ def tag=(new_tag)
2439
+ unless (new_tag.kind_of? Hash)
2440
+ raise ArgumentError, "Expected Hash, but #{new_tag.class} provided."
2441
+ end
2442
+ @tag = new_tag
2443
+ end
2045
2444
 
2046
2445
  #=====================================#
2047
2446
  #
@@ -2055,14 +2454,21 @@ class IPAddr
2055
2454
 
2056
2455
  # - Arguments:
2057
2456
  # * Hash with the following fields
2058
- # :IPAddr -- IPv4 or IPv6 address (assume host address by default)
2059
- # :Netmask -- IPv4 netmask in extended format ( if not part of IPAddr)
2060
- # :Tag -- Custom descriptor tag for object. Should be Hash (tag => value)
2457
+ # - :IPAddr -- IPv4 or IPv6 address (assume host address by default)
2458
+ # - :Netmask -- IPv4 netmask in extended format ( if not part of IPAddr)
2459
+ # - :Tag -- Custom descriptor tag for object. Should be Hash (tag => value)
2460
+ #
2461
+ # Example:
2462
+ # ip4 = IPAdmin::IPAddr.new(:IPAddr => '192.168.1.1',
2463
+ # :Netmask => '255.255.255.0',
2464
+ # :Tag => {'desc' => 'FastEthernet0/1'})
2465
+ #
2466
+ # ip6 = IPAdmin::IPAddr.new(:IPAddr => 'fec0::/64')
2061
2467
  #
2062
2468
  def initialize(options)
2063
2469
 
2064
2470
  unless (options.kind_of? Hash)
2065
- raise "Expected Hash, but #{options.class} provided."
2471
+ raise ArgumentError, "Expected Hash, but #{options.class} provided."
2066
2472
  end
2067
2473
 
2068
2474
  if ( options.has_key?(:IPAddr) )
@@ -2144,10 +2550,12 @@ class IPAddr
2144
2550
 
2145
2551
 
2146
2552
  # set tag if present
2147
- if ( options.has_key?(:Tag) )
2553
+ if ( options.has_key?(:Tag) )
2148
2554
  @tag = options[:Tag]
2555
+ unless (@tag.kind_of? Hash)
2556
+ raise "Expected Hash, but #{@tag.class} provided for option :Tag."
2557
+ end
2149
2558
  end
2150
-
2151
2559
 
2152
2560
  end
2153
2561
 
@@ -2170,6 +2578,9 @@ class IPAddr
2170
2578
  #
2171
2579
  # - Returns:
2172
2580
  # * base network address.
2581
+ #
2582
+ # Example:
2583
+ # base = ip.base()
2173
2584
  #
2174
2585
  def base()
2175
2586
  if (@version == 4)
@@ -2189,6 +2600,37 @@ class IPAddr
2189
2600
 
2190
2601
 
2191
2602
 
2603
+ #============================================================================#
2604
+ # bits()
2605
+ #============================================================================#
2606
+
2607
+ # Provide number of bits of Netmask.
2608
+ #
2609
+ # - Arguments:
2610
+ # * none
2611
+ #
2612
+ # - Returns:
2613
+ # * Number of bits of Netmask.
2614
+ #
2615
+ # Example:
2616
+ # bits = ip.bits()
2617
+ #
2618
+ def bits()
2619
+ if (@version == 4)
2620
+ bits = IPAdmin.unpack_ipv4_netmask(@netmask)
2621
+ else
2622
+ bits = IPAdmin.unpack_ipv6_netmask(@netmask)
2623
+ end
2624
+
2625
+ return(bits)
2626
+ end
2627
+
2628
+ #=====================================#
2629
+ #
2630
+ #=====================================#
2631
+
2632
+
2633
+
2192
2634
  #============================================================================#
2193
2635
  # broadcast()
2194
2636
  #============================================================================#
@@ -2200,6 +2642,9 @@ class IPAddr
2200
2642
  #
2201
2643
  # - Returns:
2202
2644
  # * broadcast address.
2645
+ #
2646
+ # Example:
2647
+ # bcast = ip.broadcast()
2203
2648
  #
2204
2649
  def broadcast()
2205
2650
  if (@version == 4)
@@ -2230,6 +2675,9 @@ class IPAddr
2230
2675
  #
2231
2676
  # - Returns:
2232
2677
  # * ip/netmask.
2678
+ #
2679
+ # Example:
2680
+ # desc = ip.desc()
2233
2681
  #
2234
2682
  def desc()
2235
2683
  if (@version == 4)
@@ -2262,6 +2710,9 @@ class IPAddr
2262
2710
  #
2263
2711
  # - Returns:
2264
2712
  # * IPv4 Hostmask in extended (y.y.y.y) format.
2713
+ #
2714
+ # Example:
2715
+ # hostmask = ip.hostmask_ext()
2265
2716
  #
2266
2717
  def hostmask_ext()
2267
2718
  if (@version == 4)
@@ -2290,6 +2741,9 @@ class IPAddr
2290
2741
  #
2291
2742
  # - Returns:
2292
2743
  # * IP address.
2744
+ #
2745
+ # Example:
2746
+ # addr = ip.ip()
2293
2747
  #
2294
2748
  def ip()
2295
2749
  if (@version == 4)
@@ -2311,13 +2765,16 @@ class IPAddr
2311
2765
  # netmask()
2312
2766
  #============================================================================#
2313
2767
 
2314
- # Provide Netmask for address within IPAdmin::IPAddr object.
2768
+ # Provide Netmask in cidr format.
2315
2769
  #
2316
2770
  # - Arguments:
2317
2771
  # * none
2318
2772
  #
2319
2773
  # - Returns:
2320
- # * Number of bits in the netmask.
2774
+ # * Netmask in CIDR format.
2775
+ #
2776
+ # Example:
2777
+ # netmask = ip.netmask()
2321
2778
  #
2322
2779
  def netmask()
2323
2780
  if (@version == 4)
@@ -2326,7 +2783,7 @@ class IPAddr
2326
2783
  bits = IPAdmin.unpack_ipv6_netmask(@netmask)
2327
2784
  end
2328
2785
 
2329
- return(bits)
2786
+ return("/#{bits}")
2330
2787
  end
2331
2788
 
2332
2789
  #=====================================#
@@ -2346,13 +2803,16 @@ class IPAddr
2346
2803
  #
2347
2804
  # - Returns:
2348
2805
  # * IPv4 Netmask in extended (y.y.y.y) format.
2806
+ #
2807
+ # Example:
2808
+ # netmask = ip.netmask_ext()
2349
2809
  #
2350
2810
  def netmask_ext()
2351
2811
  if (@version == 4)
2352
2812
  netmask = IPAdmin.unpack_ipv4_addr(@netmask)
2353
2813
  else
2354
2814
  raise "IPv6 does not support extended netmask notation. " +
2355
- "Use bits() method instead."
2815
+ "Use netmask() method instead."
2356
2816
  end
2357
2817
 
2358
2818
  return(netmask)
@@ -2375,6 +2835,9 @@ class IPAddr
2375
2835
  #
2376
2836
  # - Returns:
2377
2837
  # * byte-packed Hostmask.
2838
+ #
2839
+ # Example:
2840
+ # packed = ip.packed_hostmask()
2378
2841
  #
2379
2842
  def packed_hostmask()
2380
2843
  return(@hostmask)
@@ -2397,6 +2860,9 @@ class IPAddr
2397
2860
  #
2398
2861
  # - Returns:
2399
2862
  # * byte-packed IP address.
2863
+ #
2864
+ # Example:
2865
+ # packed = ip.packed_ip()
2400
2866
  #
2401
2867
  def packed_ip()
2402
2868
  return(@ip)
@@ -2419,6 +2885,9 @@ class IPAddr
2419
2885
  #
2420
2886
  # - Returns:
2421
2887
  # * byte-packed Netask.
2888
+ #
2889
+ # Example:
2890
+ # packed = ip.packed_netmask()
2422
2891
  #
2423
2892
  def packed_netmask()
2424
2893
  return(@netmask)