ipadmin 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+