ipadmin 0.1.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 ADDED
@@ -0,0 +1,228 @@
1
+
2
+ Copyright (c) 2006 Dustin Spinhirne <dspinhir@yahoo.com>
3
+ Licensed under the same terms as Ruby, No Warranty is provided.
4
+
5
+
6
+ Comments are welcome. Please include 'Ruby - IPAdmin' in the title of
7
+ any emails.
8
+
9
+ Dustin Spinhirne
10
+
11
+
12
+
13
+
14
+
15
+ =Examples:
16
+
17
+
18
+ require 'rubygems'
19
+ require_gem 'ipadmin'
20
+
21
+
22
+ #============================================================================#
23
+ # IPAdmin::IPAddr
24
+ #============================================================================#
25
+ 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
+
38
+ puts ip4.tag['test']
39
+ ip4.tag['test'] = 'modified ip4 tag'
40
+ puts ip4.tag['test']
41
+
42
+ puts "base addr #{ip4.base()}"
43
+ puts "base addr #{ip6.base()}"
44
+
45
+ puts "bcast addr #{ip4.broadcast()}"
46
+
47
+ puts "description #{ip4.desc()}"
48
+ puts "description #{ip6.desc()}"
49
+
50
+ puts "extended hostmask #{ip4.hostmask_ext()}"
51
+ puts "extended netmask #{ip4.netmask_ext()}"
52
+
53
+ puts "ip addr #{ip4.ip()}"
54
+ puts "ip addr #{ip6.ip()}"
55
+
56
+ puts "netmask in bits #{ip4.netmask()}"
57
+ puts "netmask in bits #{ip6.netmask()}"
58
+
59
+ print "\n\n\n"
60
+ #=====================================#
61
+ #
62
+ #=====================================#
63
+
64
+
65
+ #============================================================================#
66
+ # IPAdmin::CIDR
67
+ #============================================================================#
68
+ puts "IPAdmin::CIDR"
69
+
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
+
81
+ puts cidr4.tag['test']
82
+ cidr4.tag['test'] = 'modified cidr4 tag'
83
+ puts cidr4.tag['test']
84
+
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}"
102
+
103
+ puts "cidr4 size is #{cidr4.size()}"
104
+ puts "cidr6 size is #{cidr6.size()}"
105
+
106
+ cidr4.enumerate(:Limit => 4, :BitStep => 32) {|addr| puts addr}
107
+ cidr6.enumerate(:Limit => 4, :BitStep => 32, :Objectify => 1) {|addr| puts addr.desc()}
108
+
109
+ cidr4.subnet(:Subnet => 28, :MinCount => 3) {|cidr| puts cidr.desc()}
110
+ cidr6.subnet(:Subnet => 66, :MinCount => 4) {|cidr| puts cidr.desc()}
111
+
112
+ print "\n\n\n"
113
+ #=====================================#
114
+ #
115
+ #=====================================#
116
+
117
+
118
+ #============================================================================#
119
+ # IPAdmin::CIDRTable
120
+ #============================================================================#
121
+ puts "IPAdmin::CIDRTable"
122
+
123
+ cidr4_1 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
124
+ cidr4_2 = IPAdmin::CIDR.new(:CIDR => '10.1.0.0/24')
125
+ cidr4_3 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/26')
126
+ cidr4_4 =IPAdmin::CIDR.new(:CIDR => '192.168.1.0/30')
127
+ cidr4_5 = IPAdmin::CIDR.new(:CIDR => '192.168.1.64/26')
128
+ cidr4_6 = IPAdmin::CIDR.new(:CIDR => '192.168.1.128/26')
129
+ cidr4_7 = IPAdmin::CIDR.new(:CIDR => '192.168.1.192/26')
130
+
131
+ cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::/10')
132
+ cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fe80::/10')
133
+ cidr6_3 = IPAdmin::CIDR.new(:CIDR => 'fec0::/64')
134
+ 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
+
144
+ table4.add_cidr(cidr4_1)
145
+ table4.add_cidr(cidr4_2)
146
+ table4.add_cidr(cidr4_3)
147
+ table4.add_cidr(cidr4_4)
148
+ table4.add_cidr(cidr4_5)
149
+ table4.add_cidr(cidr4_6)
150
+ table4.add_cidr(cidr4_7)
151
+
152
+ table6.add_cidr(cidr6_1)
153
+ table6.add_cidr(cidr6_2)
154
+ table6.add_cidr(cidr6_3)
155
+ table6.add_cidr(cidr6_4)
156
+
157
+ puts "ip4 belongs in #{table4.find_ip(ip4).desc}"
158
+ puts "ip6 belongs in #{table6.find_ip(ip6).desc}"
159
+
160
+ puts "all blocks that can hold a /27"
161
+ list4 = table4.find_space(:Size => 27)
162
+ list4.each do |cidr|
163
+ puts " #{cidr.desc()}"
164
+ end
165
+
166
+ puts "first block that can hold a /64"
167
+ list6 = table6.find_space(:Size => 64, :Limit => 1)
168
+ list6.each do |cidr|
169
+ puts " #{cidr.desc()}"
170
+ end
171
+
172
+
173
+ puts 'dump table4...'
174
+ dump4 = table4.dump
175
+ dump4.each do |cidr|
176
+ puts " #{cidr.desc}"
177
+ end
178
+ puts 'dump table6...'
179
+ dump6 = table6.dump
180
+ dump6.each do |cidr|
181
+ puts " #{cidr.desc}"
182
+ end
183
+
184
+ print "\n\n\n"
185
+ #=====================================#
186
+ #
187
+ #=====================================#
188
+
189
+
190
+ #============================================================================#
191
+ # IPAdmin Misc Methods
192
+ #============================================================================#
193
+ puts "Misc Methods"
194
+
195
+ puts "192.168.1.0 is valid" if ( IPAdmin.validate_ipv4_addr('192.168.1.0') )
196
+ puts "192.168.1.0 is valid" if ( IPAdmin.validate_ipv6_addr('fec0::0') )
197
+
198
+ puts "255.255.255.0 is valid" if (IPAdmin.validate_ipv4_netmask('255.255.255.0') )
199
+ puts "/24 is valid" if ( IPAdmin.validate_ipv4_netmask(24) )
200
+ puts "/64 is valid" if ( IPAdmin.validate_ipv6_netmask(64) )
201
+
202
+ cidr4_1 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
203
+ cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/25')
204
+ cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/10')
205
+ cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/64')
206
+
207
+ comp1 = IPAdmin.compare_cidr(cidr4_1,cidr4_2)
208
+ comp2 = IPAdmin.compare_cidr(cidr6_1,cidr6_2)
209
+ puts "#{(comp1[0]).desc} is the supernet of #{(comp1[1]).desc}"
210
+ puts "#{(comp2[0]).desc} is the supernet of #{(comp2[1]).desc}"
211
+
212
+ cidr4_1 = IPAdmin::CIDR.new(:CIDR => '192.168.1.0/24')
213
+ cidr4_2 = IPAdmin::CIDR.new(:CIDR => '192.168.0.0/24')
214
+ cidr6_1 = IPAdmin::CIDR.new(:CIDR => 'fec0::0/128')
215
+ cidr6_2 = IPAdmin::CIDR.new(:CIDR => 'fec0::1/128')
216
+
217
+ puts "192.168.1.0/24 and 192.168.0.0/24 merge into #{IPAdmin.merge_cidr([cidr4_1,cidr4_2]).desc}"
218
+ puts "fec0::0/128 and fec0::1/128 merge into #{IPAdmin.merge_cidr([cidr6_1,cidr6_2]).desc}"
219
+
220
+ print "\n\n\n"
221
+ #=====================================#
222
+ #
223
+ #=====================================#
224
+
225
+
226
+
227
+
228
+
@@ -0,0 +1,2317 @@
1
+ module IPAdmin
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
+ def compare_cidr(cidr1,cidr2)
20
+
21
+ # we only accept CIDR objects
22
+ unless ( (cidr1.kind_of? IPAdmin::CIDR)&&(cidr2.kind_of? IPAdmin::CIDR) )
23
+ raise "Expected IPAdmin::CIDR, but #{options.class} provided."
24
+ end
25
+
26
+ # make sure both are same version
27
+ unless (cidr1.version == cidr2.version )
28
+ raise "Provider CIDR objects are incompatible: " +
29
+ "#{cidr1.desc}/ and #{cidr2.desc}."
30
+ end
31
+
32
+ network1 = cidr1.packed_network
33
+ network2 = cidr2.packed_network
34
+ netmask1 = cidr1.packed_netmask
35
+ netmask2 = cidr2.packed_netmask
36
+
37
+
38
+ # make sure cidr's arent equal. return 1's if they are
39
+ if ( (network1 == network2) && (netmask1 == netmask2) )
40
+ return(1)
41
+ end
42
+
43
+
44
+ # whichever netmask is smaller will be the supernet
45
+ # if we '&' both networks by the supernet, and they are
46
+ # equal, then the supernet is the parent of the other network
47
+ if (netmask1 > netmask2)
48
+ if ( (netmask2 & network1) == (netmask2 & network2) )
49
+ supernet = cidr2
50
+ subnet = cidr1
51
+ end
52
+
53
+ else
54
+ if ( (netmask1 & network1) == (netmask1 & network2) )
55
+ supernet = cidr1
56
+ subnet = cidr2
57
+ end
58
+
59
+ end
60
+
61
+
62
+ if (supernet)
63
+ return([supernet,subnet])
64
+ else
65
+ return(nil)
66
+ end
67
+
68
+ end
69
+ module_function :compare_cidr
70
+
71
+ #=====================================#
72
+ #
73
+ #=====================================#
74
+
75
+
76
+
77
+ #============================================================================#
78
+ # merge_cidr()
79
+ #============================================================================#
80
+
81
+ # Merge (supernet) contiguous IPAdmin::CIDR blocks into a single block.
82
+ # Blocks must be contiguous, and must be able to form a single supernet.
83
+ #
84
+ # - Arguments:
85
+ # * array of IPAdmin::CIDR objects to merge
86
+ #
87
+ # - Returns:
88
+ # * IPAdmin::CIDR object
89
+ #
90
+ def merge_cidr(cidr_list)
91
+
92
+ # make sure we have an array with at least 2 objects
93
+ unless ( (cidr_list.kind_of? Array) && (cidr_list.length > 1) )
94
+ raise "Array of at least two IPAdmin::CIDR objects required."
95
+ end
96
+
97
+
98
+ # make sure all are CIDR objects of the same version
99
+ version = {}
100
+ cidr_list.each do |cidr|
101
+ unless (cidr.kind_of? IPAdmin::CIDR)
102
+ raise "Expected IPAdmin::CIDR, but #{options.class} provided."
103
+ end
104
+ version[cidr.version] = 1
105
+ end
106
+ if (version.length > 1)
107
+ raise "Provided CIDR objects must all be of the same version."
108
+ end
109
+
110
+
111
+ # cidr_list.length should be a power of 2
112
+ multiplier = 1
113
+ while (1)
114
+ if ( (2**multiplier) < cidr_list.length)
115
+ multiplier = multiplier + 1
116
+ elsif ( (2**multiplier) == cidr_list.length)
117
+ break
118
+ elsif ( (2**multiplier) > cidr_list.length)
119
+ raise "Provided CIDR objects will not merge into " +
120
+ "a single supernet"
121
+ end
122
+ end
123
+
124
+
125
+ # take each netmask of the cidr_list items, supernet them by
126
+ # 'multiplier' bits, and store them.
127
+ netmasks = {}
128
+ cidr_list.each do |cidr|
129
+ netmask = cidr.packed_netmask
130
+ netmask = netmask << multiplier
131
+ netmasks[netmask] = 1
132
+ end
133
+
134
+
135
+ # if we have multiple, different netmasks then the provided
136
+ # cidr objects are not part of the same supernet
137
+ if (netmasks.length > 1)
138
+ raise "Provided CIDR objects will not merge into " +
139
+ "a single supernet"
140
+ end
141
+ new_netmask = (netmasks.keys)[0]
142
+
143
+
144
+ # make new supernet by combining network with new netmask
145
+ # if we have multiple, different supernets, then the provided
146
+ # cidr objects are not part of the same supernet
147
+ supernets = {}
148
+ cidr_list.each do |cidr|
149
+ network = cidr.packed_network
150
+ supernets[network & new_netmask] = 1
151
+ end
152
+
153
+ if (supernets.length > 1)
154
+ raise "Provided CIDR objects will not merge into " +
155
+ "a single supernet"
156
+
157
+ else
158
+ supernet = (supernets.keys)[0]
159
+ end
160
+
161
+
162
+ # unpack our supernet addr
163
+ if (version.has_key?(4) )
164
+ supernet = unpack_ipv4_addr(supernet)
165
+ new_netmask = unpack_ipv4_netmask(new_netmask)
166
+ else
167
+ supernet = unpack_ipv6_addr(supernet)
168
+ new_netmask = unpack_ipv6_netmask(new_netmask)
169
+ end
170
+
171
+
172
+ new_cidr = IPAdmin::CIDR.new(:CIDR => "#{supernet}/#{new_netmask}")
173
+
174
+ return(new_cidr)
175
+
176
+ end
177
+ module_function :merge_cidr
178
+
179
+ #=====================================#
180
+ #
181
+ #=====================================#
182
+
183
+
184
+
185
+ #============================================================================#
186
+ # pack_ipv4_addr()
187
+ #============================================================================#
188
+
189
+ # Pack IPv4 addresses into a single byte field. No attempt at validation
190
+ # is performed.
191
+ # - Arguments:
192
+ # * IPv4 address
193
+ #
194
+ # - Returns:
195
+ # * packed IPv4 address or exception on error.
196
+ #
197
+ def pack_ipv4_addr(ip)
198
+
199
+ # is this a string?
200
+ unless (ip.kind_of? String)
201
+ raise "Expected String, but #{ip.class} provided."
202
+ end
203
+
204
+ # pack our ip
205
+ octets = ip.split( /\./ ).reverse
206
+ packed_ip = 0
207
+
208
+ (0..3).each do |x|
209
+ octets[x] = (octets[x]).to_i
210
+ octets[x] = octets[x] << 8*x
211
+ packed_ip = packed_ip | octets[x]
212
+ end
213
+
214
+
215
+ return(packed_ip)
216
+ end
217
+ module_function :pack_ipv4_addr
218
+
219
+ #=====================================#
220
+ #
221
+ #=====================================#
222
+
223
+
224
+
225
+
226
+ #============================================================================#
227
+ # pack_ipv4_netmask()
228
+ #============================================================================#
229
+
230
+ # Pack IPv4 netmask into a single byte field. No attempt at validation
231
+ # is performed.
232
+ # - Arguments:
233
+ # * IPv4 netmask in cidr or extended notation
234
+ #
235
+ # - Returns:
236
+ # * packed IPv4 netmask or exception on error.
237
+ #
238
+ def pack_ipv4_netmask(netmask)
239
+
240
+ all_f = 2**32-1
241
+
242
+
243
+ # is this a CIDR or Extended mask?
244
+ if(netmask =~ /\./)
245
+ # pack extended mask
246
+ begin
247
+ packed_netmask = pack_ipv4_addr(netmask)
248
+ packed_hostmask = packed_netmask ^ all_f
249
+ rescue Exception
250
+ raise "#{netmask} is invalid."
251
+ end
252
+
253
+ elsif (netmask !~ /\D/)
254
+ if (netmask.kind_of? String)
255
+ netmask = netmask.to_i
256
+ end
257
+
258
+ packed_hostmask = all_f >> netmask
259
+ packed_netmask = all_f ^ packed_hostmask
260
+
261
+ else
262
+ raise "#{netmask} is unrecognized."
263
+
264
+ end
265
+
266
+ ret_vals = [packed_netmask,packed_hostmask]
267
+
268
+ return(ret_vals)
269
+ end
270
+ module_function :pack_ipv4_netmask
271
+
272
+ #=====================================#
273
+ #
274
+ #=====================================#
275
+
276
+
277
+
278
+ #============================================================================#
279
+ # pack_ipv6_addr()
280
+ #============================================================================#
281
+
282
+ # Pack IPv6 addresses into a single byte field. No attempt at validation
283
+ # is performed.
284
+ # - Arguments:
285
+ # * IPv6 address
286
+ #
287
+ # - Returns:
288
+ # * packed IPv6 address or exception on error.
289
+ #
290
+ def pack_ipv6_addr(ip)
291
+
292
+ # is this a string?
293
+ unless (ip.kind_of? String)
294
+ raise "Expected String, but #{ip.class} provided."
295
+ end
296
+
297
+
298
+
299
+ # look for a '::' to see if this address is in shorthand
300
+ # if found, split on it
301
+ hex_fields = []
302
+ if (ip =~ /::/)
303
+ shrthnd = ip.split( /::/ )
304
+ if (ip =~ /^::/)
305
+ sec_half = shrthnd[1].split( /:/ )
306
+ zero_pads = 8 - sec_half.length
307
+ (1..zero_pads).each {hex_fields.push('0')}
308
+ sec_half.each {|field| hex_fields.push(field)}
309
+ elsif (ip =~ /::$/)
310
+ hex_fields = shrthnd[0].split( /:/ )
311
+ zero_pads = 8 - hex_fields.length
312
+ (1..zero_pads).each {hex_fields.push('0')}
313
+ else
314
+ first_half = shrthnd[0].split( /:/ )
315
+ sec_half = shrthnd[1].split( /:/ )
316
+ zero_pads = 8 - (first_half.length + sec_half.length)
317
+ first_half.each {|field| hex_fields.push(field)}
318
+ (1..zero_pads).each {hex_fields.push('0')}
319
+ sec_half.each {|field| hex_fields.push(field)}
320
+ end
321
+
322
+ else
323
+ hex_fields = ip.split( /:/ )
324
+ end
325
+
326
+
327
+
328
+ # pack
329
+ hex_fields.reverse!
330
+ packed_ip = 0
331
+ (0..7).each do |x|
332
+ hex = hex_fields[x]
333
+ base16 = hex.to_i(16)
334
+
335
+ base16 = base16 << 16*x
336
+ packed_ip = packed_ip | base16
337
+ end
338
+
339
+
340
+ return(packed_ip)
341
+ end
342
+ module_function :pack_ipv6_addr
343
+
344
+ #=====================================#
345
+ #
346
+ #=====================================#
347
+
348
+
349
+
350
+ #============================================================================#
351
+ # pack_ipv6_netmask()
352
+ #============================================================================#
353
+
354
+ # Pack IPv6 netmask into a single byte field. No attempt at validation
355
+ # is performed.
356
+ # - Arguments:
357
+ # * IPv6 netmask in cidr notation
358
+ #
359
+ # - Returns:
360
+ # * packed IPv6 netmask or exception on error.
361
+ #
362
+ def pack_ipv6_netmask(netmask)
363
+
364
+ all_f = 2**128-1
365
+
366
+
367
+ if (netmask !~ /\D/)
368
+ # pack
369
+ if (netmask.kind_of? String)
370
+ netmask = netmask.to_i
371
+ end
372
+
373
+ packed_hostmask = all_f >> netmask
374
+ packed_netmask = all_f ^ packed_hostmask
375
+
376
+ else
377
+ raise "#{netmask} is unrecognized."
378
+
379
+ end
380
+
381
+
382
+ ret_vals = [packed_netmask,packed_hostmask]
383
+
384
+ return(ret_vals)
385
+
386
+ end
387
+ module_function :pack_ipv6_netmask
388
+
389
+ #=====================================#
390
+ #
391
+ #=====================================#
392
+
393
+
394
+
395
+ #============================================================================#
396
+ # unpack_ipv4_addr()
397
+ #============================================================================#
398
+
399
+ # Unack IPv4 address back into a printable string. No attempt at validation
400
+ # is performed.
401
+ # - Arguments:
402
+ # * Byte-packed IPv4 address
403
+ #
404
+ # - Returns:
405
+ # * IPv4 address.
406
+ #
407
+ def unpack_ipv4_addr(packed_ip)
408
+
409
+ octets = []
410
+ (0..3).each do |x|
411
+ octets[x] = packed_ip & 0xFF
412
+ octets[x] = (octets[x]).to_s
413
+ packed_ip = packed_ip >> 8
414
+ end
415
+
416
+ octets.reverse!
417
+ ip = octets.join('.')
418
+
419
+ return(ip)
420
+ end
421
+ module_function :unpack_ipv4_addr
422
+
423
+ #=====================================#
424
+ #
425
+ #=====================================#
426
+
427
+
428
+
429
+ #============================================================================#
430
+ # unpack_ipv4_netmask()
431
+ #============================================================================#
432
+
433
+ # Unack IPv4 netmask into a integer representing the number of
434
+ # bits in the CIDR mask. No attempt at validation is performed.
435
+ # - Arguments:
436
+ # * Byte-packed IPv4 netmask
437
+ #
438
+ # - Returns:
439
+ # * IPv4 netmask as number of bits (cidr format).
440
+ #
441
+ def unpack_ipv4_netmask(packed_mask)
442
+
443
+ mask = 32
444
+ 32.times do
445
+ if ( (packed_mask & 1) != 0)
446
+ break
447
+ end
448
+ packed_mask = packed_mask >> 1
449
+ mask = mask - 1
450
+ end
451
+
452
+ return(mask)
453
+ end
454
+ module_function :unpack_ipv4_netmask
455
+
456
+ #=====================================#
457
+ #
458
+ #=====================================#
459
+
460
+
461
+
462
+ #============================================================================#
463
+ # unpack_ipv6_addr()
464
+ #============================================================================#
465
+
466
+ # Unack IPv6 address back into a printable string. No attempt at validation
467
+ # is performed.
468
+ # - Arguments:
469
+ # * Byte-packed IPv6 address
470
+ #
471
+ # - Returns:
472
+ # * IPv6 address.
473
+ #
474
+ def unpack_ipv6_addr(packed_ip)
475
+ hex_fields = []
476
+ (0..7).each do |x|
477
+ hex_fields[x] = packed_ip & 0xFFFF
478
+ hex_fields[x] = (hex_fields[x]).to_s(16)
479
+ packed_ip = packed_ip >> 16
480
+
481
+ # if hex_fields[x] < 4 characters, then pad with 0's
482
+ (4 - hex_fields[x].length).times do
483
+ hex_fields[x] = '0' << hex_fields[x]
484
+ end
485
+ end
486
+
487
+ hex_fields.reverse!
488
+ ip = hex_fields.join(':')
489
+
490
+ return(ip)
491
+ end
492
+ module_function :unpack_ipv6_addr
493
+
494
+ #=====================================#
495
+ #
496
+ #=====================================#
497
+
498
+
499
+
500
+ #============================================================================#
501
+ # unpack_ipv6_netmask()
502
+ #============================================================================#
503
+
504
+ # Unack IPv6 netmask into a integer representing the number of
505
+ # bits in the CIDR mask. No attempt at validation is performed.
506
+ # - Arguments:
507
+ # * Byte-packed IPv6 netmask
508
+ #
509
+ # - Returns:
510
+ # * IPv6 netmask as number of bits (cidr format).
511
+ #
512
+ def unpack_ipv6_netmask(packed_mask)
513
+
514
+ mask = 128
515
+ 128.times do
516
+ if ( (packed_mask & 1) == 1)
517
+ break
518
+ end
519
+ mask = mask - 1
520
+ packed_mask = packed_mask >> 1
521
+ end
522
+
523
+ return(mask)
524
+ end
525
+ module_function :unpack_ipv6_netmask
526
+
527
+ #=====================================#
528
+ #
529
+ #=====================================#
530
+
531
+
532
+
533
+ #============================================================================#
534
+ # validate_ipv4_addr()
535
+ #============================================================================#
536
+
537
+ # Validate IPv4 addresses.
538
+ # - Arguments:
539
+ # * IPv4 address
540
+ #
541
+ # - Returns:
542
+ # * 1 on valid IP or exception on error.
543
+ #
544
+ def validate_ipv4_addr(ip)
545
+
546
+ # is this a string?
547
+ unless (ip.kind_of? String)
548
+ raise "Expected String, but #{ip.class} provided."
549
+ end
550
+ octets = ip.split( /\./ )
551
+
552
+
553
+
554
+ # check validity of characters in the addr
555
+ if ( (ip =~ /\.{2,}?/ ) || (ip =~ /[^0-9\.]/) )
556
+ raise "#{ip} is invalid."
557
+ end
558
+
559
+
560
+
561
+ # do we have 4 octets?
562
+ if (octets.length != 4)
563
+ raise "#{ip} is invalid."
564
+ end
565
+
566
+
567
+
568
+ # are octets in range 0..255?
569
+ (0..3).each do |x|
570
+ octets[x] = octets[x].to_i
571
+ unless ( (octets[x] >= 0) && (octets[x] < 256 ) )
572
+ raise "#{ip} is invalid."
573
+ end
574
+ end
575
+
576
+
577
+ # dont allow first octet to be 0
578
+ if (octets[0] == 0)
579
+ raise "#{ip} is invalid."
580
+ end
581
+
582
+ return(1)
583
+
584
+ end
585
+ module_function :validate_ipv4_addr
586
+
587
+ #=====================================#
588
+ #
589
+ #=====================================#
590
+
591
+
592
+
593
+ #============================================================================#
594
+ # validate_ipv4_netmask()
595
+ #============================================================================#
596
+
597
+ # Validate IPv4 Netmask.
598
+ # - Arguments:
599
+ # * IPv4 netmask in cidr or extended notation
600
+ #
601
+ # - Returns:
602
+ # * 1 on valid IP or exception on error.
603
+ #
604
+ def validate_ipv4_netmask(netmask)
605
+
606
+ all_f = (2**32)-1
607
+
608
+
609
+ # is this a CIDR or Extended mask?
610
+ if(netmask =~ /\./)
611
+ # validate & pack extended mask
612
+ begin
613
+ validate_ipv4_addr(netmask)
614
+ packed_mask = pack_ipv4_addr(netmask)
615
+
616
+ rescue Exception
617
+ raise "#{netmask} is invalid."
618
+ end
619
+
620
+ # cycle through the bits of hostmask and compare
621
+ # with packed_mask. when we hit the firt '1' within
622
+ # packed_mask (our netmask boundary), xor hostmask and
623
+ # packed_mask. the result should be all 1's. this whole
624
+ # process is in place to make sure that we dont have
625
+ # and crazy masks such as 255.254.255.0
626
+ hostmask = 1
627
+ 32.times do
628
+ check = packed_mask & hostmask
629
+ if ( check != 0)
630
+ hostmask = hostmask >> 1
631
+ unless ( (packed_mask ^ hostmask) == all_f)
632
+ raise "#{netmask} is invalid."
633
+ end
634
+ break
635
+ else
636
+ hostmask = hostmask << 1
637
+ hostmask = hostmask | 1
638
+ end
639
+ end
640
+
641
+ else
642
+
643
+ # check if we have any non numeric characters
644
+ if (netmask =~ /\D/)
645
+ raise "#{netmask} is invalid."
646
+ end
647
+
648
+
649
+ # are we between 1 and 32 inclusive
650
+ if (netmask.kind_of? String)
651
+ netmask = netmask.to_i
652
+ end
653
+
654
+ if ( (netmask > 32) || (netmask == 0) )
655
+ raise "#{netmask} is invalid."
656
+ end
657
+
658
+ end
659
+
660
+ return(1)
661
+
662
+ end
663
+ module_function :validate_ipv4_netmask
664
+
665
+ #=====================================#
666
+ #
667
+ #=====================================#
668
+
669
+
670
+
671
+ #============================================================================#
672
+ # validate_ipv6_addr()
673
+ #============================================================================#
674
+
675
+ # Validate IPv6 addresses.
676
+ # - Arguments:
677
+ # * IPv6 address
678
+ #
679
+ # - Returns:
680
+ # * 1 on valid IP or exception on error.
681
+ #
682
+ def validate_ipv6_addr(ip)
683
+ # is this a string?
684
+ unless (ip.kind_of? String)
685
+ raise "Expected String, but #{ip.class} provided."
686
+ end
687
+
688
+
689
+
690
+ # check validity of characters in the addr
691
+ if ( (ip =~ /:{3,}?/ ) || (ip =~ /[^0-9a-fA-F:]/) )
692
+ raise "#{ip} is invalid."
693
+ end
694
+
695
+
696
+
697
+ # look for a '::' to see if this address is in shorthand
698
+ # if found, split on it & make sure that we have at most
699
+ # two elements
700
+ if (ip =~ /::/)
701
+ shrthnd = ip.split( /::/ )
702
+ unless ( (shrthnd.length > 0) && (shrthnd.length < 3) )
703
+ raise "#{ip} is invalid."
704
+ end
705
+ end
706
+
707
+
708
+
709
+ if (shrthnd)
710
+ # if shorthand, we should have between 1 and 7
711
+ # hex fields
712
+ hex_fields = []
713
+ shrthnd.each do |x|
714
+ elements = x.split( /:/ )
715
+ elements.each {|x| hex_fields.push(x)}
716
+ end
717
+ if ( (hex_fields.length < 1) || (hex_fields.length > 7) )
718
+ raise "#{ip} is invalid."
719
+ end
720
+
721
+ else
722
+ # since no shorthand notation was detected we should
723
+ # have exactly 8 hex fields
724
+ hex_fields = ip.split( /:/ )
725
+ if (hex_fields.length != 8)
726
+ raise "#{ip} is invalid."
727
+ end
728
+
729
+ end
730
+
731
+
732
+
733
+ # check that we have no more than 4 characters in each
734
+ # hex field
735
+ hex_fields.each do |x|
736
+ if (x.length > 4)
737
+ raise "#{ip} is invalid."
738
+ end
739
+ end
740
+
741
+
742
+ return(1)
743
+
744
+ end
745
+ module_function :validate_ipv6_addr
746
+
747
+ #=====================================#
748
+ #
749
+ #=====================================#
750
+
751
+
752
+
753
+ #============================================================================#
754
+ # validate_ipv6_netmask()
755
+ #============================================================================#
756
+
757
+ # Validate IPv6 netmask.
758
+ # - Arguments:
759
+ # * IPv6 netmask in cidr notation
760
+ #
761
+ # - Returns:
762
+ # * 1 on valid IP or exception on error.
763
+ #
764
+ def validate_ipv6_netmask(netmask)
765
+
766
+ if (netmask =~ /\D/)
767
+ raise "#{netmask} is invalid."
768
+
769
+ else
770
+ # are we between 1 and 128 inclusive
771
+ if (netmask.kind_of? String)
772
+ netmask = netmask.to_i
773
+ end
774
+
775
+ if ( (netmask > 128) || (netmask == 0) )
776
+ raise "#{netmask} is invalid."
777
+ end
778
+
779
+ end
780
+
781
+ return(1)
782
+
783
+ end
784
+ module_function :validate_ipv6_netmask
785
+
786
+ #=====================================#
787
+ #
788
+ #=====================================#
789
+
790
+
791
+
792
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
793
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
794
+ #
795
+ # BEGIN class CIDR
796
+ #
797
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
798
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
799
+
800
+ =begin rdoc
801
+ A class & series of methods for creating and manipulating CIDR network
802
+ addresses. Both IPv4 and IPv6 are supported.
803
+ =end
804
+
805
+ class CIDR
806
+
807
+
808
+
809
+ #============================================================================#
810
+ # attr_reader/attr_writer
811
+ #============================================================================#
812
+
813
+ # @network - packed cidr network
814
+ # @netmask - packet cidr netmask
815
+ # @hostmask - inverse packed netmask
816
+
817
+ # ip version 4 or 6
818
+ attr_reader :version
819
+
820
+ # hash of custom tags. should be in the format tag => value
821
+ attr_reader :tag
822
+ attr_writer :tag
823
+
824
+ #=====================================#
825
+ #
826
+ #=====================================#
827
+
828
+
829
+
830
+ #============================================================================#
831
+ # initialize()
832
+ #============================================================================#
833
+
834
+ # - Arguments:
835
+ # * Hash with the following fields:
836
+ # :CIDR -- IPv4 or IPv6 cidr block
837
+ # :Netmask -- IPv4 netmask in extended format (if not provided in :CIDR)
838
+ # :Tag -- Custom descriptor tag for object. Should be Hash (tag => value)
839
+ #
840
+ def initialize(options)
841
+
842
+ unless (options.kind_of? Hash)
843
+ raise "Expected Hash, but #{options.class} provided."
844
+ end
845
+
846
+
847
+ if ( options.has_key?(:CIDR) )
848
+ network = options[:CIDR]
849
+
850
+
851
+ if (network =~/\./) # assume IPv4
852
+ @version = 4
853
+
854
+ if (network =~ /\//)
855
+ ip,netmask = network.split(/\//)
856
+
857
+ # validate
858
+ IPAdmin.validate_ipv4_addr(ip)
859
+ IPAdmin.validate_ipv4_netmask(netmask)
860
+
861
+ # pack
862
+ @network = IPAdmin.pack_ipv4_addr(ip)
863
+ @netmask,@hostmask = IPAdmin.pack_ipv4_netmask(netmask)
864
+
865
+ elsif ( options.has_key?(:Netmask) )
866
+ ip = network
867
+ netmask = options[:Netmask]
868
+
869
+ # validate
870
+ IPAdmin.validate_ipv4_addr(ip)
871
+ IPAdmin.validate_ipv4_netmask(netmask)
872
+
873
+ # pack
874
+ @network = IPAdmin.pack_ipv4_addr(ip)
875
+ @netmask,@hostmask = IPAdmin.pack_ipv4_netmask(netmask)
876
+
877
+ else
878
+ raise "Missing Netmask or invalid CIDR format."
879
+
880
+ end
881
+
882
+
883
+ elsif (network =~/:/) # assume IPv6
884
+ @version = 6
885
+
886
+ if (network =~ /\//)
887
+ ip,netmask = network.split(/\//)
888
+
889
+ # validate
890
+ IPAdmin.validate_ipv6_addr(ip)
891
+ IPAdmin.validate_ipv6_netmask(netmask)
892
+
893
+ # pack
894
+ @network = IPAdmin.pack_ipv6_addr(ip)
895
+ @netmask,@hostmask = IPAdmin.pack_ipv6_netmask(netmask)
896
+
897
+ else
898
+ raise "Missing Netmask or invalid CIDR format."
899
+
900
+ end
901
+
902
+ else
903
+ raise "Invalid CIDR address format: #{network}."
904
+ end
905
+
906
+ else
907
+ raise ArgumentError, "Missing arguments: CIDR."
908
+
909
+ end
910
+
911
+
912
+ # make sure that this is a valid address/mask pair
913
+ masked_val = (@network & @netmask)
914
+ if (masked_val != @network )
915
+ raise "Invalid address/netmask pair. Did you provide "+
916
+ "an IP address instead of a CIDR block?"
917
+ end
918
+
919
+
920
+ # set tag if present
921
+ if ( options.has_key?(:Tag) )
922
+ @tag = options[:Tag]
923
+ end
924
+
925
+
926
+ end
927
+
928
+ #=====================================#
929
+ #
930
+ #=====================================#
931
+
932
+
933
+
934
+ #============================================================================#
935
+ # contains()
936
+ #============================================================================#
937
+
938
+ # Determines if cidr block of IPAdmin::CIDR contains IP address
939
+ # of provided IPAdmin:IPAddr object.
940
+ # - Arguments:
941
+ # * IPAdmin:IPAddr object
942
+ #
943
+ # - Returns:
944
+ # * 1 on true, nil on false
945
+ #
946
+ def contains(ip_obj)
947
+
948
+ if ( (ip_obj.version == 4) && (@version == 4) )
949
+ v4_all_f = (2**32)-1
950
+ hostmask = @netmask ^ v4_all_f
951
+ if ( (ip_obj.packed_ip | hostmask) == (@network | hostmask) )
952
+ return(1)
953
+ end
954
+
955
+ elsif ( (ip_obj.version == 6) && (@version == 6) )
956
+ v6_all_f = (2**128)-1
957
+ hostmask = @netmask ^ v6_all_f
958
+ if ( (ip_obj.packed_ip | hostmask) == (@network | hostmask) )
959
+ return(1)
960
+ end
961
+
962
+ else
963
+ raise "Attempted to compare a version #{ip_obj.version} IP " +
964
+ "with a version #{@version} network."
965
+ end
966
+
967
+ return(nil)
968
+ end
969
+
970
+ #=====================================#
971
+ #
972
+ #=====================================#
973
+
974
+
975
+
976
+ #============================================================================#
977
+ # desc()
978
+ #============================================================================#
979
+
980
+ # Displays network/netmask of an IPAdmin::CIDR object
981
+ # of provided IPAdmin:IPAddr object.
982
+ # - Arguments:
983
+ # * none
984
+ #
985
+ # - Returns:
986
+ # * Description in network/netmask format
987
+ #
988
+ def desc()
989
+
990
+ if (@version == 4)
991
+ ip = IPAdmin.unpack_ipv4_addr(@network)
992
+ mask = IPAdmin.unpack_ipv4_netmask(@netmask)
993
+ else
994
+ ip = IPAdmin.unpack_ipv6_addr(@network)
995
+ mask = IPAdmin.unpack_ipv6_netmask(@netmask)
996
+ end
997
+
998
+ return("#{ip}/#{mask}")
999
+
1000
+ end
1001
+
1002
+ #=====================================#
1003
+ #
1004
+ #=====================================#
1005
+
1006
+
1007
+
1008
+ #============================================================================#
1009
+ # enumerate()
1010
+ #============================================================================#
1011
+
1012
+ # Provide all IP addresses within a CIDR block
1013
+ # (warning: this can be quite large for big blocks)
1014
+ #
1015
+ # - Arguments:
1016
+ # * Hash with the following fields
1017
+ # - :BitStep -- enumerate in X sized steps
1018
+ # - :Objectify -- return IPAdmin::IPAddr objects
1019
+ # - :Limit -- limit returned list to X number of items
1020
+ #
1021
+ # - Returns:
1022
+ # * array of IP addresses or IPAdmin::IPAddr objects
1023
+ #
1024
+ def enumerate(options=nil)
1025
+ bitstep = 1
1026
+ objectify = nil
1027
+ limit = nil
1028
+ v4_all_f = (2**32)-1
1029
+ v6_all_f = (2**128)-1
1030
+
1031
+ if (options)
1032
+ if( options.has_key?(:BitStep) )
1033
+ bitstep = options[:BitStep]
1034
+ end
1035
+
1036
+ if( options.has_key?(:Objectify) )
1037
+ objectify = 1
1038
+ end
1039
+
1040
+ if( options.has_key?(:Limit) )
1041
+ limit = options[:Limit]
1042
+ end
1043
+ end
1044
+
1045
+
1046
+ list = []
1047
+ if ( (@version == 4) && !objectify)
1048
+ my_ip = @network
1049
+ hostmask = @netmask ^ v4_all_f
1050
+ change_mask = hostmask | my_ip
1051
+
1052
+ until ( change_mask != (hostmask | @network) )
1053
+ list.push( IPAdmin.unpack_ipv4_addr(my_ip) )
1054
+ my_ip = my_ip + bitstep
1055
+ change_mask = hostmask | my_ip
1056
+ if (limit)
1057
+ limit = limit -1
1058
+ break if (limit == 0)
1059
+ end
1060
+ end
1061
+
1062
+ elsif ( (@version == 4) && objectify)
1063
+ my_ip = @network
1064
+ hostmask = @netmask ^ v4_all_f
1065
+ change_mask = hostmask | my_ip
1066
+
1067
+ until ( change_mask != (hostmask | @network) )
1068
+ my_ip_s = IPAdmin.unpack_ipv4_addr(my_ip)
1069
+ list.push( IPAdmin::IPAddr.new(:IPAddr => my_ip_s) )
1070
+ my_ip = my_ip + bitstep
1071
+ change_mask = hostmask | my_ip
1072
+ if (limit)
1073
+ limit = limit -1
1074
+ break if (limit == 0)
1075
+ end
1076
+ end
1077
+
1078
+ elsif ( (@version == 6) && !objectify)
1079
+ my_ip = @network
1080
+ hostmask = @netmask ^ v6_all_f
1081
+ change_mask = hostmask | my_ip
1082
+
1083
+ until ( change_mask != (hostmask | @network) )
1084
+ list.push( IPAdmin.unpack_ipv6_addr(my_ip) )
1085
+ my_ip = my_ip + bitstep
1086
+ change_mask = hostmask | my_ip
1087
+ if (limit)
1088
+ limit = limit -1
1089
+ break if (limit == 0)
1090
+ end
1091
+ end
1092
+
1093
+ elsif ( (@version == 6) && objectify)
1094
+ my_ip = @network
1095
+ hostmask = @netmask ^ v6_all_f
1096
+ change_mask = hostmask | my_ip
1097
+
1098
+ until ( change_mask != (hostmask | @network) )
1099
+ my_ip_s = IPAdmin.unpack_ipv6_addr(my_ip)
1100
+ list.push( IPAdmin::IPAddr.new(:IPAddr => my_ip_s) )
1101
+ my_ip = my_ip + bitstep
1102
+ change_mask = hostmask | my_ip
1103
+ if (limit)
1104
+ limit = limit -1
1105
+ break if (limit == 0)
1106
+ end
1107
+ end
1108
+
1109
+ else
1110
+ list = nil
1111
+
1112
+ end
1113
+
1114
+
1115
+ return(list)
1116
+ end
1117
+
1118
+ #=====================================#
1119
+ #
1120
+ #=====================================#
1121
+
1122
+
1123
+
1124
+ #============================================================================#
1125
+ # hostmask_ext()
1126
+ #============================================================================#
1127
+
1128
+ # Provide IPv4 Hostmask in extended format.
1129
+ #
1130
+ # - Arguments:
1131
+ # * none
1132
+ #
1133
+ # - Returns:
1134
+ # * Hostmask in extended (y.y.y.y) format.
1135
+ #
1136
+ def hostmask_ext()
1137
+ if (@version == 4)
1138
+ hostmask = IPAdmin.unpack_ipv4_addr(@hostmask)
1139
+ else
1140
+ raise "IPv6 does not support extended hostmask notation."
1141
+ end
1142
+
1143
+ return(hostmask)
1144
+ end
1145
+
1146
+ #=====================================#
1147
+ #
1148
+ #=====================================#
1149
+
1150
+
1151
+
1152
+ #============================================================================#
1153
+ # netmask()
1154
+ #============================================================================#
1155
+
1156
+ # Provide Netmask in cidr format.
1157
+ #
1158
+ # - Arguments:
1159
+ # * none
1160
+ #
1161
+ # - Returns:
1162
+ # * Number of bits in the netmask.
1163
+ #
1164
+ def netmask()
1165
+ if (@version == 4)
1166
+ bits = IPAdmin.unpack_ipv4_netmask(@netmask)
1167
+ else
1168
+ bits = IPAdmin.unpack_ipv6_netmask(@netmask)
1169
+ end
1170
+
1171
+ return(bits)
1172
+ end
1173
+
1174
+ #=====================================#
1175
+ #
1176
+ #=====================================#
1177
+
1178
+
1179
+
1180
+ #============================================================================#
1181
+ # netmask_ext()
1182
+ #============================================================================#
1183
+
1184
+ # Provide IPv4 Netmask in extended format.
1185
+ #
1186
+ # - Arguments:
1187
+ # * none
1188
+ #
1189
+ # - Returns:
1190
+ # * Netmask in extended (y.y.y.y) format.
1191
+ #
1192
+ def netmask_ext()
1193
+ if (@version == 4)
1194
+ netmask = IPAdmin.unpack_ipv4_addr(@netmask)
1195
+ else
1196
+ raise "IPv6 does not support extended netmask notation. " +
1197
+ "Use bits() method instead."
1198
+ end
1199
+
1200
+ return(netmask)
1201
+ end
1202
+
1203
+ #=====================================#
1204
+ #
1205
+ #=====================================#
1206
+
1207
+
1208
+
1209
+ #============================================================================#
1210
+ # network()
1211
+ #============================================================================#
1212
+
1213
+ # Provide base Network address.
1214
+ #
1215
+ # - Arguments:
1216
+ # * none
1217
+ #
1218
+ # - Returns:
1219
+ # * Base network address.
1220
+ #
1221
+ def network()
1222
+ if (@version == 4)
1223
+ formatted = IPAdmin.unpack_ipv4_addr(@network)
1224
+ else
1225
+ formatted = IPAdmin.unpack_ipv6_addr(@network)
1226
+ end
1227
+
1228
+ return(formatted)
1229
+ end
1230
+
1231
+ #=====================================#
1232
+ #
1233
+ #=====================================#
1234
+
1235
+
1236
+
1237
+ #============================================================================#
1238
+ # nth()
1239
+ #============================================================================#
1240
+
1241
+ # Provide the nth IP within the cidr block of an IPAdmin::CIDR object.
1242
+ #
1243
+ # - Arguments:
1244
+ # * Hash with the following fields
1245
+ # - :Index -- index of the address to return
1246
+ # - :Objectify -- return IPAdmin::IPAddr objects
1247
+ #
1248
+ # - Returns:
1249
+ # * IP address or IPAdmin::IPAddr object.
1250
+ #
1251
+ def nth(options)
1252
+ objectify = nil
1253
+ v4_all_f = (2**32)-1
1254
+ v6_all_f = (2**128)-1
1255
+
1256
+ unless( options.has_key?(:Index) )
1257
+ raise ArgumentError, "Missing arguments: Index."
1258
+ end
1259
+ index = options[:Index]
1260
+
1261
+
1262
+ if( options.has_key?(:Objectify) )
1263
+ objectify = 1
1264
+ end
1265
+
1266
+
1267
+
1268
+ if ( (@version == 4) && !objectify)
1269
+ my_ip = @network + index
1270
+ hostmask = @netmask ^ v4_all_f
1271
+
1272
+ if ( (hostmask | my_ip) == (hostmask | @network) )
1273
+ my_ip = IPAdmin.unpack_ipv4_addr(my_ip)
1274
+ return(my_ip)
1275
+ end
1276
+
1277
+ elsif ( (@version == 4) && objectify)
1278
+ my_ip = @network + index
1279
+ hostmask = @netmask ^ v4_all_f
1280
+
1281
+ if ( (hostmask | my_ip) == (hostmask | @network) )
1282
+ my_ip_s = IPAdmin.unpack_ipv4_addr(my_ip)
1283
+ return( IPAdmin::IPAddr.new(:IPAddr => my_ip_s) )
1284
+ end
1285
+
1286
+ elsif ( (@version == 6) && !objectify)
1287
+ my_ip = @network + index
1288
+ hostmask = @netmask ^ v6_all_f
1289
+
1290
+ if ( (hostmask | my_ip) == (hostmask | @network) )
1291
+ my_ip = IPAdmin.unpack_ipv6_addr(my_ip)
1292
+ return(my_ip)
1293
+ end
1294
+
1295
+ elsif ( (@version == 6) && objectify)
1296
+ my_ip = @network + index
1297
+ hostmask = @netmask ^ v6_all_f
1298
+
1299
+ if ( (hostmask | my_ip) == (hostmask | @network) )
1300
+ my_ip_s = IPAdmin.unpack_ipv6_addr(my_ip)
1301
+ return( IPAdmin::IPAddr.new(:IPAddr => my_ip_s) )
1302
+ end
1303
+
1304
+ end
1305
+
1306
+ raise "Index of #{index} returns IP that is out of " +
1307
+ "bounds of CIDR network."
1308
+
1309
+ end
1310
+
1311
+ #=====================================#
1312
+ #
1313
+ #=====================================#
1314
+
1315
+
1316
+
1317
+ #============================================================================#
1318
+ # packed_hostmask()
1319
+ #============================================================================#
1320
+
1321
+ # Provide byte-packed Hostmask of cidr block of an IPAdmin::CIDR object.
1322
+ #
1323
+ # - Arguments:
1324
+ # * none
1325
+ #
1326
+ # - Returns:
1327
+ # * Byte-packed Hostmask.
1328
+ #
1329
+ def packed_hostmask()
1330
+ return(@hostmask)
1331
+ end
1332
+
1333
+ #=====================================#
1334
+ #
1335
+ #=====================================#
1336
+
1337
+
1338
+
1339
+ #============================================================================#
1340
+ # packed_netmask()
1341
+ #============================================================================#
1342
+
1343
+ # Provide byte-packed Netmask of cidr block of an IPAdmin::CIDR object.
1344
+ #
1345
+ # - Arguments:
1346
+ # * none
1347
+ #
1348
+ # - Returns:
1349
+ # * Byte-packed Netmask.
1350
+ #
1351
+ def packed_netmask()
1352
+ return(@netmask)
1353
+ end
1354
+
1355
+ #=====================================#
1356
+ #
1357
+ #=====================================#
1358
+
1359
+
1360
+
1361
+ #============================================================================#
1362
+ # packed_network()
1363
+ #============================================================================#
1364
+
1365
+ # Provide byte-packed Network address of cidr block of an IPAdmin::CIDR object.
1366
+ #
1367
+ # - Arguments:
1368
+ # * none
1369
+ #
1370
+ # - Returns:
1371
+ # * Byte-packed Network Address.
1372
+ #
1373
+ def packed_network()
1374
+ return(@network)
1375
+ end
1376
+
1377
+ #=====================================#
1378
+ #
1379
+ #=====================================#
1380
+
1381
+
1382
+
1383
+ #============================================================================#
1384
+ # size()
1385
+ #============================================================================#
1386
+
1387
+ # Provide number of addresses within cidr block of an IPAdmin::CIDR object.
1388
+ #
1389
+ # - Arguments:
1390
+ # * none
1391
+ #
1392
+ # - Returns:
1393
+ # * Number of IP addresses in this CIDR block.
1394
+ #
1395
+ def size()
1396
+ return(@hostmask + 1)
1397
+ end
1398
+
1399
+ #=====================================#
1400
+ #
1401
+ #=====================================#
1402
+
1403
+
1404
+
1405
+ #============================================================================#
1406
+ # subnet()
1407
+ #============================================================================#
1408
+
1409
+ # Subnet cidr block within an IPAdmin::CIDR object according to user
1410
+ # specifications.
1411
+ #
1412
+ # - Arguments:
1413
+ # * Hash with the following fields:
1414
+ # :Subnet -- number of bits of new subnet to create (24,26, etc...)
1415
+ # :MinCount -- minimum number of subnets of size :Subnet to return
1416
+ #
1417
+ # - Returns:
1418
+ # * array of IPAdmin::CIDR objects
1419
+ #
1420
+ def subnet(options)
1421
+ subnet = options[:Subnet]
1422
+ min_count = options[:MinCount]
1423
+ mymask = self.netmask
1424
+ num_avail = 2**(subnet - mymask)
1425
+ new_subnets = []
1426
+
1427
+
1428
+
1429
+ # make sure subnet isnt bigger than available bits
1430
+ if (@version == 4)
1431
+ max_bits = 32
1432
+ else
1433
+ max_bits = 128
1434
+ end
1435
+
1436
+ if (subnet > max_bits)
1437
+ raise "Requested subnet #{subnet} does not fit " +
1438
+ "within available CIDR space."
1439
+ end
1440
+
1441
+
1442
+ # make sure subnet is larger than mymask
1443
+ if (subnet < mymask)
1444
+ raise "Requested subnet #{subnet} does not fit " +
1445
+ "within available CIDR space."
1446
+ end
1447
+
1448
+
1449
+ # make sure MinCount is smaller than available subnets
1450
+ if (min_count > num_avail)
1451
+ raise "Requested subnet count exceeds subnets available for " +
1452
+ "allocation."
1453
+ end
1454
+
1455
+
1456
+ # list all 'subnet' sized subnets of this cidr block
1457
+ bitstep = 2**(max_bits - subnet)
1458
+ subs = self.enumerate(:BitStep => bitstep)
1459
+ subs.each do |sub|
1460
+ cidr = "#{sub}/#{subnet}"
1461
+ new_subnets.push(IPAdmin::CIDR.new(:CIDR => cidr))
1462
+ end
1463
+
1464
+
1465
+ # combine any unneeded subnets into as few
1466
+ # supernets as possible
1467
+ supernets = []
1468
+ supernet_groups = []
1469
+ if (min_count < num_avail )
1470
+ cidr_list = []
1471
+ num_left = num_avail - min_count
1472
+ multiplier = 1
1473
+ until (num_left < 2)
1474
+ if ( (2**multiplier) < num_left)
1475
+ multiplier = multiplier + 1
1476
+ elsif ( (2**multiplier) == num_left)
1477
+ supernet_groups.push( (2**multiplier) )
1478
+ num_left = num_left - (2**multiplier)
1479
+ break
1480
+ elsif ( (2**multiplier) > num_left)
1481
+ multiplier = multiplier -1
1482
+ supernet_groups.push( (2**multiplier) )
1483
+ num_left = num_left - (2**multiplier)
1484
+ multiplier = 1
1485
+ end
1486
+ end
1487
+ end
1488
+
1489
+
1490
+ supernet_groups.each do |group|
1491
+ cidr_list = []
1492
+ (1..group).each do
1493
+ cidr_list.push(new_subnets.pop)
1494
+ end
1495
+ supernets.push( IPAdmin.merge_cidr(cidr_list) )
1496
+ end
1497
+
1498
+
1499
+ # add supernets to new_subnets
1500
+ (1..supernets.length).each do
1501
+ new_subnets.push(supernets.pop)
1502
+ end
1503
+
1504
+ return(new_subnets)
1505
+ end
1506
+
1507
+ #=====================================#
1508
+ #
1509
+ #=====================================#
1510
+
1511
+
1512
+
1513
+ end
1514
+
1515
+
1516
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1517
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1518
+ #
1519
+ # END class CIDR
1520
+ #
1521
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1522
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1523
+
1524
+
1525
+
1526
+
1527
+
1528
+
1529
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1530
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1531
+ #
1532
+ # BEGIN class CIDRTable
1533
+ #
1534
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1535
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1536
+
1537
+ =begin rdoc
1538
+ A class & series of methods for creating and manipulating CIDR-based
1539
+ heirarchical tables. Both IPv4 and IPv6 are supported.
1540
+ =end
1541
+
1542
+ class CIDRTable
1543
+
1544
+
1545
+
1546
+ #============================================================================#
1547
+ # attr_reader / attr_writer
1548
+ #============================================================================#
1549
+
1550
+
1551
+ # ip table version (4 or 6)
1552
+ attr_reader :version
1553
+
1554
+ # contains IPAdmin::CIDR entries. hash (IPAdmin::CIDR => IPAdmin::CIDRTable)
1555
+ attr_reader :cidr_table
1556
+
1557
+ #=====================================#
1558
+ #
1559
+ #=====================================#
1560
+
1561
+
1562
+
1563
+ #============================================================================#
1564
+ # initialize()
1565
+ #============================================================================#
1566
+
1567
+ # - Arguments:
1568
+ # * Table version (4 or 6)
1569
+ #
1570
+ def initialize(version)
1571
+
1572
+ unless ( version.kind_of? Fixnum )
1573
+ raise "Expected Fixnum, but #{version.class} provided."
1574
+ end
1575
+
1576
+ unless ( version == 4 || version == 6 )
1577
+ raise "Version should be either 4 or 6."
1578
+ end
1579
+
1580
+ @version = version
1581
+ @cidr_table = {}
1582
+ end
1583
+
1584
+ #=====================================#
1585
+ #
1586
+ #=====================================#
1587
+
1588
+
1589
+
1590
+ #============================================================================#
1591
+ # add_cidr()
1592
+ #============================================================================#
1593
+
1594
+ # Add an IPAdmin::CIDR object to this table
1595
+ #
1596
+ # - Arguments:
1597
+ # * IPAdmin::CIDR object
1598
+ #
1599
+ # - Returns:
1600
+ # * nil
1601
+ #
1602
+ def add_cidr(new_cidr)
1603
+
1604
+ unless (new_cidr.version == @version )
1605
+ raise "CIDR version #{new_cidr.version} is incompatible with " +
1606
+ "CIDRTable version #{@version}."
1607
+ end
1608
+
1609
+
1610
+
1611
+ # compare new cidr with existing cidr's
1612
+ # determine if this is a parent or child of an existing cidr.
1613
+ # if neither, add @networks. if child of existing, add to that
1614
+ # child's @networks. if parent of existing, make existing child
1615
+ # of new cidr
1616
+ duplicate = nil
1617
+ parent_of = []
1618
+ child_of = nil
1619
+ @cidr_table.each_key do |old_cidr|
1620
+ parent,child = IPAdmin.compare_cidr(new_cidr,old_cidr)
1621
+
1622
+ if (parent)
1623
+ if (new_cidr == parent)
1624
+ parent_of.push(child)
1625
+ @cidr_table.delete(child)
1626
+
1627
+ elsif (new_cidr == child)
1628
+ child_of = parent
1629
+ break
1630
+
1631
+ elsif (parent == 1)
1632
+ duplicate = 1
1633
+ break
1634
+ end
1635
+ end
1636
+ end
1637
+
1638
+
1639
+
1640
+ if (parent_of.length != 0)
1641
+ new_entry = IPAdmin::CIDRTable.new(@version)
1642
+ parent_of.each do |old_cidr|
1643
+ new_entry.add_cidr(old_cidr)
1644
+ @cidr_table.delete(old_cidr)
1645
+ end
1646
+ @cidr_table[new_cidr] = new_entry
1647
+
1648
+ elsif (child_of)
1649
+ if (@cidr_table[child_of] == 0)
1650
+ new_entry = IPAdmin::CIDRTable.new(@version)
1651
+ @cidr_table[child_of] = new_entry
1652
+ (@cidr_table[child_of]).add_cidr(new_cidr)
1653
+ else
1654
+ (@cidr_table[child_of]).add_cidr(new_cidr)
1655
+ end
1656
+
1657
+ elsif (!duplicate)
1658
+ @cidr_table[new_cidr] = 0
1659
+ end
1660
+ end
1661
+
1662
+ #=====================================#
1663
+ #
1664
+ #=====================================#
1665
+
1666
+
1667
+
1668
+ #============================================================================#
1669
+ # dump()
1670
+ #============================================================================#
1671
+
1672
+ # Dump contents of this table
1673
+ #
1674
+ # - Arguments:
1675
+ # * nil
1676
+ #
1677
+ # - Returns:
1678
+ # * ordered array of IPAdmin::CIDR objects within this table
1679
+ #
1680
+ def dump()
1681
+
1682
+ list = []
1683
+ sorted_parents = []
1684
+ parent_hash = {}
1685
+ @cidr_table.each_key do |parent|
1686
+ parent_hash[parent.packed_network] = parent
1687
+ end
1688
+ sorted_parents = (parent_hash.keys).sort
1689
+
1690
+
1691
+ sorted_parents.each do |parent|
1692
+ parent_obj = parent_hash[parent]
1693
+ list.push(parent_obj)
1694
+ if (@cidr_table[parent_obj] != 0)
1695
+ children = (@cidr_table[parent_obj]).dump
1696
+ children.each do |child|
1697
+ list.push(child)
1698
+ end
1699
+ end
1700
+
1701
+ end
1702
+
1703
+ return(list)
1704
+
1705
+ end
1706
+
1707
+ #=====================================#
1708
+ #
1709
+ #=====================================#
1710
+
1711
+
1712
+
1713
+ #============================================================================#
1714
+ # find_ip()
1715
+ #============================================================================#
1716
+
1717
+ # Find longest matching IPAdmin::CIDR object whose cidr block contains the IP
1718
+ # address within the provided IPAdmin::IPAddr object
1719
+ #
1720
+ # - Arguments:
1721
+ # * IPAdmin::IPAddr object
1722
+ #
1723
+ # - Returns:
1724
+ # * IPAdmin::CIDR object, or nil on no match
1725
+ #
1726
+ def find_ip(ip_obj)
1727
+
1728
+ unless (ip_obj.kind_of? IPAdmin::IPAddr)
1729
+ raise "Expected IPAdmin::IPAddr, but #{options.class} provided."
1730
+ end
1731
+
1732
+ unless (ip_obj.version == @version )
1733
+ raise "IPAddr version #{ip_addr.version} is incompatible with " +
1734
+ "CIDRTable version #{@version}."
1735
+ end
1736
+
1737
+ belongs_to = nil
1738
+ @cidr_table.each_key do |parent|
1739
+ if ( parent.contains(ip_obj) )
1740
+ if (@cidr_table[parent] != 0)
1741
+ belongs_to = (@cidr_table[parent]).find_ip(ip_obj)
1742
+ end
1743
+
1744
+ if (!belongs_to)
1745
+ belongs_to = parent
1746
+ end
1747
+ end
1748
+ end
1749
+
1750
+ return(belongs_to)
1751
+
1752
+ end
1753
+
1754
+ #=====================================#
1755
+ #
1756
+ #=====================================#
1757
+
1758
+
1759
+
1760
+ #============================================================================#
1761
+ # find_space()
1762
+ #============================================================================#
1763
+
1764
+ # Find CIDR blocks of at least X size. Returns only the smallest matching
1765
+ # subnets of each supernet.
1766
+ #
1767
+ # - Arguments:
1768
+ # * Hash with the following fields:
1769
+ # :Size -- subnet size (number of bits)
1770
+ # :Limit -- max entries to return
1771
+ #
1772
+ # - Returns:
1773
+ # * ordered array of IPAdmin::CIDR objects, or nil on no match
1774
+ #
1775
+ def find_space(options)
1776
+ limit = nil
1777
+ list = []
1778
+ sorted_parents = []
1779
+ parent_hash = {}
1780
+
1781
+
1782
+
1783
+ # validate options
1784
+ unless (options.kind_of? Hash)
1785
+ raise "Expected Hash, but #{options.class} provided."
1786
+ end
1787
+
1788
+ unless ( options.has_key?(:Size) )
1789
+ raise "Missing argument :Size."
1790
+ end
1791
+ subnet_size = options[:Size]
1792
+
1793
+ if ( options.has_key?(:Limit) )
1794
+ limit = options[:Limit]
1795
+ end
1796
+
1797
+
1798
+
1799
+ # check that subnet_size is a valid size
1800
+ if (@version == 4)
1801
+ unless ( (subnet_size > 0) && (subnet_size < 33) )
1802
+ raise "#{subnet_size} is out of range for this CIDRTable."
1803
+ end
1804
+
1805
+ else
1806
+ unless ( (subnet_size > 0) && (subnet_size < 129) )
1807
+ raise "#{subnet_size} is out of range for this CIDRTable."
1808
+ end
1809
+ end
1810
+
1811
+
1812
+ # order cidr objects
1813
+ @cidr_table.each_key do |parent|
1814
+ parent_hash[parent.packed_network] = parent
1815
+ end
1816
+ sorted_parents = (parent_hash.keys).sort
1817
+
1818
+
1819
+
1820
+ # find space
1821
+ sorted_parents.each do |key|
1822
+ parent = parent_hash[key]
1823
+ if ( parent.netmask() < subnet_size )
1824
+ if (@cidr_table[parent] != 0)
1825
+ child_list = []
1826
+ child_list = (@cidr_table[parent]).find_space(:Size => subnet_size)
1827
+ child_list.each do |child|
1828
+ list.push(child)
1829
+ if ( (limit) && (list.length == limit) )
1830
+ break
1831
+ end
1832
+
1833
+ end
1834
+
1835
+ else
1836
+ list.push(parent)
1837
+
1838
+ end
1839
+
1840
+ elsif ( (parent_hash[key].netmask() == subnet_size) &&
1841
+ (@cidr_table[parent] == 0) )
1842
+ list.push(parent)
1843
+
1844
+ end
1845
+
1846
+
1847
+ if ( (limit) && (list.length == limit) )
1848
+ break
1849
+ end
1850
+
1851
+ end
1852
+
1853
+ return(list)
1854
+
1855
+ end
1856
+
1857
+ #=====================================#
1858
+ #
1859
+ #=====================================#
1860
+
1861
+
1862
+
1863
+
1864
+ end
1865
+
1866
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1867
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1868
+ #
1869
+ # END class CIDRTable
1870
+ #
1871
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1872
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1873
+
1874
+
1875
+
1876
+
1877
+
1878
+
1879
+
1880
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1881
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1882
+ #
1883
+ # BEGIN class IPAddr
1884
+ #
1885
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1886
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
1887
+
1888
+ =begin rdoc
1889
+ A class & series of methods for creating and manipulating IP
1890
+ addresses. Both IPv4 and IPv6 are supported.
1891
+ =end
1892
+
1893
+ class IPAddr
1894
+
1895
+
1896
+
1897
+ #============================================================================#
1898
+ # attr_reader/attr_writer
1899
+ #============================================================================#
1900
+
1901
+ # @ip - packed ip address
1902
+ # @netmask - packed netmask
1903
+ # @hostmask - inverse packed netmask
1904
+
1905
+ # ip version 4 or 6
1906
+ attr_reader :version
1907
+
1908
+ # hash of custom tags. should be in the format tag => value
1909
+ attr_reader :tag
1910
+ attr_writer :tag
1911
+
1912
+
1913
+ #=====================================#
1914
+ #
1915
+ #=====================================#
1916
+
1917
+
1918
+
1919
+ #============================================================================#
1920
+ # initialize()
1921
+ #============================================================================#
1922
+
1923
+ # - Arguments:
1924
+ # * Hash with the following fields
1925
+ # :IPAddr -- IPv4 or IPv6 address (assume host address by default)
1926
+ # :Netmask -- IPv4 netmask in extended format ( if not part of IPAddr)
1927
+ # :Tag -- Custom descriptor tag for object. Should be Hash (tag => value)
1928
+ #
1929
+ def initialize(options)
1930
+
1931
+ unless (options.kind_of? Hash)
1932
+ raise "Expected Hash, but #{options.class} provided."
1933
+ end
1934
+
1935
+ if ( options.has_key?(:IPAddr) )
1936
+ ip_addr = options[:IPAddr]
1937
+
1938
+
1939
+ if (ip_addr =~/\./) # assume IPv4
1940
+ @version = 4
1941
+
1942
+ if (ip_addr =~ /\//)
1943
+ ip,netmask = ip_addr.split(/\//)
1944
+
1945
+ # validate
1946
+ IPAdmin.validate_ipv4_addr(ip)
1947
+ IPAdmin.validate_ipv4_netmask(netmask)
1948
+
1949
+ # pack
1950
+ @ip = IPAdmin.pack_ipv4_addr(ip)
1951
+ @netmask,@hostmask = IPAdmin.pack_ipv4_netmask(netmask)
1952
+
1953
+ else
1954
+ # validate
1955
+ IPAdmin.validate_ipv4_addr(ip_addr)
1956
+
1957
+ # pack
1958
+ @ip = IPAdmin.pack_ipv4_addr(ip_addr)
1959
+
1960
+ # check if netmask provided separately
1961
+ if ( options.has_key?(:Netmask) )
1962
+ netmask = options[:Netmask]
1963
+
1964
+ # validate
1965
+ IPAdmin.validate_ipv4_netmask(netmask)
1966
+
1967
+ # pack
1968
+ @netmask,@hostmask =
1969
+ IPAdmin.pack_ipv4_netmask(netmask)
1970
+
1971
+ else
1972
+ @netmask,@hostmask = IPAdmin.pack_ipv4_netmask('32')
1973
+
1974
+ end
1975
+
1976
+ end
1977
+
1978
+
1979
+ elsif (ip_addr =~/:/) # assume IPv6
1980
+ @version = 6
1981
+
1982
+ if (ip_addr =~ /\//)
1983
+ ip,netmask = ip_addr.split(/\//)
1984
+
1985
+ # validate
1986
+ IPAdmin.validate_ipv6_addr(ip)
1987
+ IPAdmin.validate_ipv6_netmask(netmask)
1988
+
1989
+ # pack
1990
+ @ip = IPAdmin.pack_ipv6_addr(ip)
1991
+ @netmask,@hostmask = IPAdmin.pack_ipv6_netmask(netmask)
1992
+
1993
+ else
1994
+ # validate
1995
+ IPAdmin.validate_ipv6_addr(ip_addr)
1996
+
1997
+ # pack
1998
+ @ip = IPAdmin.pack_ipv6_addr(ip_addr)
1999
+ @netmask,@hostmask = IPAdmin.pack_ipv6_netmask('128')
2000
+
2001
+ end
2002
+
2003
+ else
2004
+ raise "Invalid IPAddr address format: #{ip_addr}."
2005
+ end
2006
+
2007
+ else
2008
+ raise ArgumentError, "Missing arguments: IPAddr."
2009
+
2010
+ end
2011
+
2012
+
2013
+ # set tag if present
2014
+ if ( options.has_key?(:Tag) )
2015
+ @tag = options[:Tag]
2016
+ end
2017
+
2018
+
2019
+ end
2020
+
2021
+
2022
+
2023
+ #=====================================#
2024
+ #
2025
+ #=====================================#
2026
+
2027
+
2028
+
2029
+ #============================================================================#
2030
+ # base()
2031
+ #============================================================================#
2032
+
2033
+ # Provide base network address for address within IPAdmin::IPAddr object.
2034
+ #
2035
+ # - Arguments:
2036
+ # * none
2037
+ #
2038
+ # - Returns:
2039
+ # * base network address.
2040
+ #
2041
+ def base()
2042
+ if (@version == 4)
2043
+ packed_base = @ip & @netmask
2044
+ base = IPAdmin.unpack_ipv4_addr(packed_base)
2045
+ else
2046
+ packed_base = @ip & @netmask
2047
+ base = IPAdmin.unpack_ipv6_addr(packed_base)
2048
+ end
2049
+
2050
+ return(base)
2051
+ end
2052
+
2053
+ #=====================================#
2054
+ #
2055
+ #=====================================#
2056
+
2057
+
2058
+
2059
+ #============================================================================#
2060
+ # broadcast()
2061
+ #============================================================================#
2062
+
2063
+ # Provide IPv4 broadcast address for address within IPAdmin::IPAddr object.
2064
+ #
2065
+ # - Arguments:
2066
+ # * none
2067
+ #
2068
+ # - Returns:
2069
+ # * broadcast address.
2070
+ #
2071
+ def broadcast()
2072
+ if (@version == 4)
2073
+ inverse_mask = ~ @netmask
2074
+ packed_bcast = @ip | inverse_mask
2075
+ bcast = IPAdmin.unpack_ipv4_addr(packed_bcast)
2076
+ else
2077
+ raise "IPv6 does not support IP broadcast addresses."
2078
+ end
2079
+
2080
+ return(bcast)
2081
+ end
2082
+
2083
+ #=====================================#
2084
+ #
2085
+ #=====================================#
2086
+
2087
+
2088
+
2089
+ #============================================================================#
2090
+ # desc()
2091
+ #============================================================================#
2092
+
2093
+ # Provide description for IP address within IPAdmin::IPAddr object.
2094
+ #
2095
+ # - Arguments:
2096
+ # * none
2097
+ #
2098
+ # - Returns:
2099
+ # * ip/netmask.
2100
+ #
2101
+ def desc()
2102
+ if (@version == 4)
2103
+ ip = IPAdmin.unpack_ipv4_addr(@ip)
2104
+ netmask = IPAdmin.unpack_ipv4_netmask(@netmask)
2105
+ formatted = "#{ip}/#{netmask}"
2106
+ else
2107
+ ip = IPAdmin.unpack_ipv6_addr(@ip)
2108
+ netmask = IPAdmin.unpack_ipv6_netmask(@netmask)
2109
+ formatted = "#{ip}/#{netmask}"
2110
+ end
2111
+
2112
+ return(formatted)
2113
+ end
2114
+
2115
+ #=====================================#
2116
+ #
2117
+ #=====================================#
2118
+
2119
+
2120
+
2121
+ #============================================================================#
2122
+ # hostmask_ext()
2123
+ #============================================================================#
2124
+
2125
+ # Provide IPv4 Hostmask for address within IPAdmin::IPAddr object.
2126
+ #
2127
+ # - Arguments:
2128
+ # * none
2129
+ #
2130
+ # - Returns:
2131
+ # * IPv4 Hostmask in extended (y.y.y.y) format.
2132
+ #
2133
+ def hostmask_ext()
2134
+ if (@version == 4)
2135
+ hostmask = IPAdmin.unpack_ipv4_addr(@hostmask)
2136
+ else
2137
+ raise "IPv6 does not support extended hostmask notation."
2138
+ end
2139
+
2140
+ return(hostmask)
2141
+ end
2142
+
2143
+ #=====================================#
2144
+ #
2145
+ #=====================================#
2146
+
2147
+
2148
+
2149
+ #============================================================================#
2150
+ # ip()
2151
+ #============================================================================#
2152
+
2153
+ # Provide IP address of IPAdmin::IPAddr object.
2154
+ #
2155
+ # - Arguments:
2156
+ # * none
2157
+ #
2158
+ # - Returns:
2159
+ # * IP address.
2160
+ #
2161
+ def ip()
2162
+ if (@version == 4)
2163
+ formatted = IPAdmin.unpack_ipv4_addr(@ip)
2164
+ else
2165
+ formatted = IPAdmin.unpack_ipv6_addr(@ip)
2166
+ end
2167
+
2168
+ return(formatted)
2169
+ end
2170
+
2171
+ #=====================================#
2172
+ #
2173
+ #=====================================#
2174
+
2175
+
2176
+
2177
+ #============================================================================#
2178
+ # netmask()
2179
+ #============================================================================#
2180
+
2181
+ # Provide Netmask for address within IPAdmin::IPAddr object.
2182
+ #
2183
+ # - Arguments:
2184
+ # * none
2185
+ #
2186
+ # - Returns:
2187
+ # * Number of bits in the netmask.
2188
+ #
2189
+ def netmask()
2190
+ if (@version == 4)
2191
+ bits = IPAdmin.unpack_ipv4_netmask(@netmask)
2192
+ else
2193
+ bits = IPAdmin.unpack_ipv6_netmask(@netmask)
2194
+ end
2195
+
2196
+ return(bits)
2197
+ end
2198
+
2199
+ #=====================================#
2200
+ #
2201
+ #=====================================#
2202
+
2203
+
2204
+
2205
+ #============================================================================#
2206
+ # netmask_ext()
2207
+ #============================================================================#
2208
+
2209
+ # Provide IPv4 Netmask for address within IPAdmin::IPAddr object.
2210
+ #
2211
+ # - Arguments:
2212
+ # * none
2213
+ #
2214
+ # - Returns:
2215
+ # * IPv4 Netmask in extended (y.y.y.y) format.
2216
+ #
2217
+ def netmask_ext()
2218
+ if (@version == 4)
2219
+ netmask = IPAdmin.unpack_ipv4_addr(@netmask)
2220
+ else
2221
+ raise "IPv6 does not support extended netmask notation. " +
2222
+ "Use bits() method instead."
2223
+ end
2224
+
2225
+ return(netmask)
2226
+ end
2227
+
2228
+ #=====================================#
2229
+ #
2230
+ #=====================================#
2231
+
2232
+
2233
+
2234
+ #============================================================================#
2235
+ # packed_hostmask()
2236
+ #============================================================================#
2237
+
2238
+ # Provide byte-packed Hostmask within IPAdmin::IPAddr object.
2239
+ #
2240
+ # - Arguments:
2241
+ # * none
2242
+ #
2243
+ # - Returns:
2244
+ # * byte-packed Hostmask.
2245
+ #
2246
+ def packed_hostmask()
2247
+ return(@hostmask)
2248
+ end
2249
+
2250
+ #=====================================#
2251
+ #
2252
+ #=====================================#
2253
+
2254
+
2255
+
2256
+ #============================================================================#
2257
+ # packed_ip()
2258
+ #============================================================================#
2259
+
2260
+ # Provide byte-packed IP address of IPAdmin::IPAddr object.
2261
+ #
2262
+ # - Arguments:
2263
+ # * none
2264
+ #
2265
+ # - Returns:
2266
+ # * byte-packed IP address.
2267
+ #
2268
+ def packed_ip()
2269
+ return(@ip)
2270
+ end
2271
+
2272
+ #=====================================#
2273
+ #
2274
+ #=====================================#
2275
+
2276
+
2277
+
2278
+ #============================================================================#
2279
+ # packed_netmask()
2280
+ #============================================================================#
2281
+
2282
+ # Provide byte-packed Netmask for IP address of IPAdmin::IPAddr object.
2283
+ #
2284
+ # - Arguments:
2285
+ # * none
2286
+ #
2287
+ # - Returns:
2288
+ # * byte-packed Netask.
2289
+ #
2290
+ def packed_netmask()
2291
+ return(@netmask)
2292
+ end
2293
+
2294
+ #=====================================#
2295
+ #
2296
+ #=====================================#
2297
+
2298
+
2299
+
2300
+ end
2301
+
2302
+
2303
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
2304
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
2305
+ #
2306
+ # END class IPAddr
2307
+ #
2308
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
2309
+ #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#
2310
+
2311
+
2312
+ end # module IPAdmin
2313
+
2314
+
2315
+
2316
+ __END__
2317
+