netaddr 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of netaddr might be problematic. Click here for more details.

@@ -0,0 +1,334 @@
1
+ module NetAddr
2
+ private
3
+
4
+ # CIDR METHODS
5
+
6
+ #==============================================================================#
7
+ # cidr_build()
8
+ #==============================================================================#
9
+
10
+ # create either a CIDRv4 or CIDRv6 object
11
+ #
12
+ def cidr_build(version, ip, netmask=nil, tag={}, wildcard_mask=nil, wildcard_mask_bit_flipped=false)
13
+ return( NetAddr::CIDRv4.new(ip, netmask, tag, wildcard_mask, wildcard_mask_bit_flipped) ) if (version == 4)
14
+ return( NetAddr::CIDRv6.new(ip, netmask, tag, wildcard_mask, wildcard_mask_bit_flipped) )
15
+ end
16
+ module_function :cidr_build
17
+
18
+ #==============================================================================#
19
+ # cidr_compare()
20
+ #==============================================================================#
21
+
22
+ # compare 2 CIDR objects
23
+ #
24
+ #return:
25
+ #* 1 if the cidr1 contains cidr2
26
+ #* 0 if the cidr1 and cidr2 are equal
27
+ #* -1 if cidr1 is a subnet of cidr2
28
+ #* nil if the two are unrelated
29
+ #
30
+ def cidr_compare(cidr1,cidr2)
31
+ comparasin = nil
32
+ if ( (cidr1.packed_network == cidr2.packed_network))
33
+ # same network, check netmask
34
+ if (cidr1.packed_netmask == cidr2.packed_netmask)
35
+ comparasin = 0
36
+ elsif(cidr1.packed_netmask < cidr2.packed_netmask)
37
+ comparasin = 1
38
+ elsif(cidr1.packed_netmask > cidr2.packed_netmask)
39
+ comparasin = -1
40
+ end
41
+
42
+ elsif( (cidr2.packed_network | cidr1.packed_hostmask) == (cidr1.packed_network | cidr1.packed_hostmask) )
43
+ # cidr1 contains cidr2
44
+ comparasin = 1
45
+
46
+ elsif( (cidr2.packed_network | cidr2.packed_hostmask) == (cidr1.packed_network | cidr2.packed_hostmask) )
47
+ # cidr2 contains cidr1
48
+ comparasin = -1
49
+ end
50
+
51
+ return(comparasin)
52
+ end
53
+ module_function :cidr_compare
54
+
55
+ #==============================================================================#
56
+ # cidr_gt_lt()
57
+ #==============================================================================#
58
+
59
+ # given a pair of CIDRs, determine if first is greater than or less than the second
60
+ #
61
+ # return 1 if cidr1 > cidr2
62
+ # return 0 if cidr1 == cidr2
63
+ # return -1 if cidr1 < cidr2
64
+ #
65
+ def cidr_gt_lt(cidr1,cidr2)
66
+ gt_lt = 1
67
+ if(cidr1.packed_network < cidr2.packed_network)
68
+ gt_lt = -1
69
+ elsif (cidr1.packed_network == cidr2.packed_network)
70
+ if (cidr1.packed_netmask < cidr2.packed_netmask)
71
+ gt_lt = -1
72
+ elsif (cidr1.packed_netmask == cidr2.packed_netmask)
73
+ gt_lt = 0
74
+ end
75
+ end
76
+
77
+ return(gt_lt)
78
+ end
79
+ module_function :cidr_gt_lt
80
+
81
+ #==============================================================================#
82
+ # cidr_fill_in()
83
+ #==============================================================================#
84
+
85
+ #Given a list of subnets of supernet, return a new list with any
86
+ #holes (missing subnets) filled in.
87
+ #
88
+ def cidr_fill_in(supernet,list)
89
+ # sort our cidr's and see what is missing
90
+ complete_list = []
91
+ expected = supernet.packed_network
92
+ all_f = supernet.all_f
93
+ version = supernet.version
94
+
95
+ NetAddr.cidr_sort(list).each do |cidr|
96
+ network = cidr.packed_network
97
+ bitstep = (all_f + 1) - cidr.packed_netmask
98
+
99
+ if (network > expected)
100
+ num_ips_missing = network - expected
101
+ sub_list = cidr_make_subnets_from_base_and_ip_count(supernet,expected,num_ips_missing)
102
+ complete_list.concat(sub_list)
103
+ elsif (network < expected)
104
+ next
105
+ end
106
+
107
+ complete_list.push(NetAddr.cidr_build(version,network,cidr.packed_netmask))
108
+ expected = network + bitstep
109
+ end
110
+
111
+ # if expected is not the next subnet, then we're missing subnets
112
+ # at the end of the cidr
113
+ next_sub = supernet.next_subnet(:Objectify => true).packed_network
114
+ if (expected != next_sub)
115
+ num_ips_missing = next_sub - expected
116
+ sub_list = cidr_make_subnets_from_base_and_ip_count(supernet,expected,num_ips_missing)
117
+ complete_list.concat(sub_list)
118
+ end
119
+
120
+ return(complete_list)
121
+ end
122
+ module_function :cidr_fill_in
123
+
124
+ #==============================================================================#
125
+ # cidr_find_in_list()
126
+ #==============================================================================#
127
+
128
+ # evaluate cidr against list of cidrs.
129
+ #
130
+ # return entry from list if entry is supernet of cidr (first matching entry)
131
+ # return index # of entry if entry is a duplicate of cidr
132
+ # return nil if no match found
133
+ #
134
+ def cidr_find_in_list(cidr,list)
135
+ return(nil) if (list.length == 0)
136
+
137
+ match = nil
138
+ low = 0
139
+ high = list.length - 1
140
+ index = low + ( (high-low)/2 )
141
+ while ( low <= high)
142
+ cmp = cidr_gt_lt(cidr,list[index])
143
+ if ( cmp == -1 )
144
+ high = index - 1
145
+
146
+ elsif ( cmp == 1 )
147
+ if (cidr_compare(cidr,list[index]) == -1)
148
+ match = list[index]
149
+ break
150
+ end
151
+ low = index + 1
152
+
153
+ else
154
+ match = index
155
+ break
156
+ end
157
+ index = low + ( (high-low)/2 )
158
+ end
159
+ return(match)
160
+ end
161
+ module_function :cidr_find_in_list
162
+
163
+ #==============================================================================#
164
+ # cidr_make_subnets_from_base_and_ip_count()
165
+ #==============================================================================#
166
+
167
+ # Make CIDR addresses from a base addr and an number of ip's to encapsulate.
168
+ #
169
+ #===Arguments:
170
+ # * base ip as packed integer
171
+ # * number of ip's required
172
+ #
173
+ #===Returns:
174
+ # * array of NetAddr::CIDR objects
175
+ #
176
+ def cidr_make_subnets_from_base_and_ip_count(cidr,base_addr,ip_count)
177
+ list = []
178
+ until (ip_count == 0)
179
+ mask = cidr.all_f
180
+ multiplier = 0
181
+ bitstep = 0
182
+ last_addr = base_addr
183
+ done = false
184
+ until (done == true)
185
+ if (bitstep < ip_count && (base_addr & mask == last_addr & mask) )
186
+ multiplier += 1
187
+ elsif (bitstep > ip_count || (base_addr & mask != last_addr & mask) )
188
+ multiplier -= 1
189
+ done = true
190
+ else
191
+ done = true
192
+ end
193
+ bitstep = 2**multiplier
194
+ mask = cidr.all_f << multiplier & cidr.all_f
195
+ last_addr = base_addr + bitstep - 1
196
+ end
197
+
198
+ list.push(NetAddr.cidr_build(cidr.version,base_addr,mask))
199
+ ip_count -= bitstep
200
+ base_addr += bitstep
201
+ end
202
+
203
+ return(list)
204
+ end
205
+ module_function :cidr_make_subnets_from_base_and_ip_count
206
+
207
+ #==============================================================================#
208
+ # cidr_sort()
209
+ #==============================================================================#
210
+
211
+ # given a list of NetAddr::CIDRs, return them as a sorted list
212
+ #
213
+ def cidr_sort(list)
214
+ # uses simple quicksort algorithm
215
+ sorted_list = []
216
+ if (list.length < 1)
217
+ sorted_list = list
218
+ else
219
+ less_list = []
220
+ greater_list = []
221
+ equal_list = []
222
+ pivot = list[rand(list.length)]
223
+ list.each do |x|
224
+ gt_lt = cidr_gt_lt(pivot,x)
225
+ if (gt_lt == 1)
226
+ less_list.push(x)
227
+ elsif (gt_lt == -1)
228
+ greater_list.push(x)
229
+ else
230
+ equal_list.push(x)
231
+ end
232
+ end
233
+ sorted_list.concat( cidr_sort(less_list) )
234
+ sorted_list.concat(equal_list)
235
+ sorted_list.concat( cidr_sort(greater_list) )
236
+ end
237
+
238
+ return(sorted_list)
239
+ end
240
+ module_function :cidr_sort
241
+
242
+ #==============================================================================#
243
+ # cidr_summarize()
244
+ #==============================================================================#
245
+
246
+ # given a list of NetAddr::CIDRs (of the same version) summarize them
247
+ #
248
+ # return a hash, with the key = summary address and val = array of original cidrs
249
+ #
250
+ def cidr_summarize(subnet_list)
251
+ all_f = subnet_list[0].all_f
252
+ version = subnet_list[0].version
253
+ subnet_list = cidr_sort(subnet_list)
254
+
255
+ # continue summarization attempts until sorted_list stops getting shorter
256
+ sorted_list = subnet_list.dup
257
+ sorted_list_len = sorted_list.length
258
+ while (1)
259
+ summarized_list = []
260
+ until (sorted_list.length == 0)
261
+ cidr = sorted_list.shift
262
+ network, netmask = cidr.packed_network, cidr.packed_netmask
263
+ supermask = (netmask << 1) & all_f
264
+ supernet = supermask & network
265
+
266
+ if (network == supernet && sorted_list.length > 0)
267
+ # network is lower half of supernet, so see if we have the upper half
268
+ bitstep = (all_f + 1) - netmask
269
+ expected = network + bitstep
270
+ next_cidr = sorted_list.shift
271
+ next_network, next_netmask = next_cidr.packed_network, next_cidr.packed_netmask
272
+
273
+ if ( (next_network == expected) && (next_netmask == netmask) )
274
+ # we do indeed have the upper half. store new supernet.
275
+ summarized_list.push( cidr_build(version,supernet,supermask) )
276
+ else
277
+ # we do not have the upper half. put next_cidr back into sorted_list
278
+ # and store only the original network
279
+ sorted_list.unshift(next_cidr)
280
+ summarized_list.push(cidr)
281
+ end
282
+ else
283
+ # network is upper half of supernet, so save original network only
284
+ summarized_list.push(cidr)
285
+ end
286
+
287
+ end
288
+
289
+ sorted_list = summarized_list.dup
290
+ break if (sorted_list.length == sorted_list_len)
291
+ sorted_list_len = sorted_list.length
292
+ end
293
+
294
+ # clean up summarized_list
295
+ unique_list = {}
296
+ summarized_list.reverse.each do |supernet|
297
+ next if ( unique_list.has_key?(supernet.desc) )
298
+ # remove duplicates
299
+ unique_list[supernet.desc] = supernet
300
+
301
+ # remove any summary blocks that are children of other summary blocks
302
+ index = 0
303
+ until (index >= summarized_list.length)
304
+ subnet = summarized_list[index]
305
+ if (subnet && cidr_compare(supernet,subnet) == 1 )
306
+ subnet_list[index] = nil
307
+ end
308
+ index += 1
309
+ end
310
+ end
311
+ summarized_list = unique_list.values
312
+
313
+ # map original blocks to their summaries
314
+ summarized_list.each do |supernet|
315
+ supernet.tag[:Subnets] = []
316
+ index = 0
317
+ until (index >= subnet_list.length)
318
+ subnet = subnet_list[index]
319
+ if (subnet && cidr_compare(supernet,subnet) == 1 )
320
+ subnet_list[index] = nil
321
+ supernet.tag[:Subnets].push(subnet)
322
+ end
323
+ index += 1
324
+ end
325
+ end
326
+
327
+ return( NetAddr.cidr_sort(summarized_list) )
328
+ end
329
+ module_function :cidr_summarize
330
+
331
+
332
+ end # module NetAddr
333
+
334
+ __END__
data/lib/eui.rb CHANGED
@@ -40,7 +40,7 @@ private_class_method :new
40
40
  # addr = NetAddr::EUI.new('aa-bb-cc-dd-ee-ff-00-01')
41
41
  #
42
42
  #===Arguments
43
- #* EUI as a String
43
+ #* eui = EUI as a String
44
44
  #
45
45
  #===Returns
46
46
  #* EUI48 or EUI64 object
@@ -62,7 +62,7 @@ private_class_method :new
62
62
  else
63
63
  eui = NetAddr::EUI64.new(eui.to_i(16))
64
64
  end
65
-
65
+
66
66
  return(eui)
67
67
  end
68
68
 
@@ -76,8 +76,8 @@ private_class_method :new
76
76
  # puts addr.address(:Delimiter => '.') --> 'aabb.ccdd.eeff'
77
77
  #
78
78
  #===Arguments:
79
- #* Optional Hash with the following fields:
80
- # :Delimiter -- delimitation character. valid values are (-,:,and .) (optional)
79
+ #* options = Hash with the following fields:
80
+ # :Delimiter -- delimitation character. valid values are (-,:,and .)
81
81
  #
82
82
  #===Returns:
83
83
  #* String
@@ -135,8 +135,8 @@ private_class_method :new
135
135
  # puts addr.ei(:Delimiter => '-')
136
136
  #
137
137
  #===Arguments:
138
- #* Optional Hash with the following fields:
139
- # :Delimiter -- delimitation character. valid values are (-, and :) (optional)
138
+ #* options = Hash with the following fields:
139
+ # :Delimiter -- delimitation character. valid values are (-, and :)
140
140
  #
141
141
  #===Returns:
142
142
  #* String
@@ -173,9 +173,9 @@ private_class_method :new
173
173
  # puts addr.link_local()
174
174
  #
175
175
  #===Arguments:
176
- #* Optional Hash with the following fields:
177
- # :Short -- if true, return IPv6 addresses in short-hand notation (optional)
178
- # :Objectify -- if true, return CIDR objects (optional)
176
+ #* options = Hash with the following fields:
177
+ # :Short -- if true, return IPv6 addresses in short-hand notation
178
+ # :Objectify -- if true, return CIDR objects
179
179
  #
180
180
  #===Returns:
181
181
  #* CIDR address String or an NetAddr::CIDR object
@@ -228,8 +228,8 @@ private_class_method :new
228
228
  # puts addr.oui(:Delimiter => '-')
229
229
  #
230
230
  #===Arguments:
231
- #* Optional Hash with the following fields:
232
- # :Delimiter -- delimitation character. valid values are (-, and :) (optional)
231
+ #* options = Hash with the following fields:
232
+ # :Delimiter -- delimitation character. valid values are (-, and :)
233
233
  #
234
234
  #===Returns:
235
235
  #* String
@@ -323,12 +323,12 @@ public_class_method :new
323
323
  #* EUI as a String or Integer
324
324
  #
325
325
  def initialize(eui)
326
-
326
+
327
327
  if (eui.kind_of?(Integer))
328
328
  @oui = eui >> 24
329
329
  @ei = eui & 0xffffff
330
330
 
331
- elsif(eui.kind_of?(String))
331
+ elsif(eui.kind_of?(String))
332
332
  # validate
333
333
  NetAddr.validate_eui(eui)
334
334
 
@@ -361,15 +361,15 @@ public_class_method :new
361
361
  # addr = NetAddr::EUI64.new('aa-bb-cc-dd-ee-ff-00-01')
362
362
  #
363
363
  #===Arguments:
364
- #* EUI as a String or Integer
364
+ #* eui = EUI as a String or Integer
365
365
  #
366
366
  def initialize(eui)
367
-
367
+
368
368
  if (eui.kind_of?(Integer))
369
369
  @oui = eui >> 40
370
370
  @ei = eui & 0xffffffffffd
371
371
 
372
- elsif(eui.kind_of?(String))
372
+ elsif(eui.kind_of?(String))
373
373
  # validate
374
374
  NetAddr.validate_eui(eui)
375
375
 
data/lib/ip_math.rb ADDED
@@ -0,0 +1,241 @@
1
+ module NetAddr
2
+ private
3
+
4
+
5
+ # IP MATH METHODS
6
+
7
+ #==============================================================================#
8
+ # bits_to_mask()
9
+ #==============================================================================#
10
+
11
+ # convert a netmask (in bits) to an integer mask
12
+ #
13
+ def bits_to_mask(netmask,version)
14
+ return(0) if (netmask == 0)
15
+ all_f = 2**32-1
16
+ all_f = 2**128-1 if (version == 6)
17
+ return( all_f ^ (all_f >> netmask) )
18
+ end
19
+ module_function :bits_to_mask
20
+
21
+ #==============================================================================#
22
+ # detect_ip_version()
23
+ #==============================================================================#
24
+
25
+ # determine the ip version from ip address string.
26
+ #
27
+ # return 4, 6, or nil
28
+ #
29
+ def detect_ip_version(ip)
30
+ version = nil
31
+ if ( ip =~ /\./ && ip !~ /:/ )
32
+ version = 4
33
+ elsif (ip =~ /:/)
34
+ version = 6
35
+ else
36
+ raise ValidationError, "Count not auto-detect IP version for '#{ip}'."
37
+ end
38
+ return(version)
39
+ end
40
+ module_function :detect_ip_version
41
+
42
+ #==============================================================================#
43
+ # ip_count_to_size()
44
+ #==============================================================================#
45
+
46
+ # given an ip count, determine the most appropriate mask (in bits)
47
+ #
48
+ def ip_count_to_size(ipcount,version,extended=false)
49
+ address_len = 32
50
+ address_len = 128 if (version == 6 )
51
+
52
+ if (ipcount > 2**address_len)
53
+ raise BoundaryError, "Required IP count exceeds number of IP addresses available " +
54
+ "for IPv#{version}."
55
+ end
56
+
57
+ bits_needed = 0
58
+ until (2**bits_needed >= ipcount)
59
+ bits_needed += 1
60
+ end
61
+ subnet_bits = address_len - bits_needed
62
+
63
+ return( ip_int_to_str(bits_to_mask(subnet_bits, 4), 4) ) if (extended && version == 4)
64
+ return(subnet_bits)
65
+ end
66
+ module_function :ip_count_to_size
67
+
68
+ #==============================================================================#
69
+ # ip_int_to_str()
70
+ #==============================================================================#
71
+
72
+ # unpack an int into an ip address string
73
+ #
74
+ def ip_int_to_str(packed_ip, version, ipv4_mapped=nil)
75
+ ip = nil
76
+ version = 4 if (!version && packed_ip < 2**32)
77
+ if (version == 4)
78
+ octets = []
79
+ 4.times do
80
+ octet = packed_ip & 0xFF
81
+ octets.unshift(octet.to_s)
82
+ packed_ip = packed_ip >> 8
83
+ end
84
+ ip = octets.join('.')
85
+ else
86
+ fields = []
87
+ if (!ipv4_mapped)
88
+ loop_count = 8
89
+ else
90
+ loop_count = 6
91
+ packed_v4 = packed_ip & 0xffffffff
92
+ ipv4_addr = ip_int_to_str(packed_v4, 4)
93
+ fields.unshift(ipv4_addr)
94
+ packed_ip = packed_ip >> 32
95
+ end
96
+
97
+ loop_count.times do
98
+ octet = packed_ip & 0xFFFF
99
+ octet = octet.to_s(16)
100
+ packed_ip = packed_ip >> 16
101
+
102
+ # if octet < 4 characters, then pad with 0's
103
+ (4 - octet.length).times do
104
+ octet = '0' << octet
105
+ end
106
+ fields.unshift(octet)
107
+ end
108
+ ip = fields.join(':')
109
+ end
110
+ return(ip)
111
+ end
112
+ module_function :ip_int_to_str
113
+
114
+ #==============================================================================#
115
+ # ip_str_to_int()
116
+ #==============================================================================#
117
+
118
+ # convert an ip string into an int
119
+ #
120
+ def ip_str_to_int(ip,version)
121
+ packed_ip = 0
122
+ if ( version == 4)
123
+ octets = ip.split('.')
124
+ (0..3).each do |x|
125
+ octet = octets.pop.to_i
126
+ octet = octet << 8*x
127
+ packed_ip = packed_ip | octet
128
+ end
129
+
130
+ else
131
+ # if ipv4-mapped ipv6 addr
132
+ if (ip =~ /\./)
133
+ dotted_dec = true
134
+ end
135
+
136
+ # split up by ':'
137
+ fields = []
138
+ if (ip =~ /::/)
139
+ shrthnd = ip.split( /::/ )
140
+ if (shrthnd.length == 0)
141
+ return(0)
142
+ else
143
+ first_half = shrthnd[0].split( /:/ ) if (shrthnd[0])
144
+ sec_half = shrthnd[1].split( /:/ ) if (shrthnd[1])
145
+ first_half = [] if (!first_half)
146
+ sec_half = [] if (!sec_half)
147
+ end
148
+ missing_fields = 8 - first_half.length - sec_half.length
149
+ missing_fields -= 1 if dotted_dec
150
+ fields = fields.concat(first_half)
151
+ missing_fields.times {fields.push('0')}
152
+ fields = fields.concat(sec_half)
153
+
154
+ else
155
+ fields = ip.split(':')
156
+ end
157
+
158
+ if (dotted_dec)
159
+ ipv4_addr = fields.pop
160
+ packed_v4 = NetAddr.pack_ip_addr(ipv4_addr, :Version => 4)
161
+ octets = []
162
+ 2.times do
163
+ octet = packed_v4 & 0xFFFF
164
+ octets.unshift(octet.to_s(16))
165
+ packed_v4 = packed_v4 >> 16
166
+ end
167
+ fields.concat(octets)
168
+ end
169
+
170
+ # pack
171
+ (0..7).each do |x|
172
+ field = fields.pop.to_i(16)
173
+ field = field << 16*x
174
+ packed_ip = packed_ip | field
175
+ end
176
+
177
+ end
178
+ return(packed_ip)
179
+ end
180
+ module_function :ip_str_to_int
181
+
182
+ #==============================================================================#
183
+ # mask_to_bits()
184
+ #==============================================================================#
185
+
186
+ # convert integer into a cidr formatted netmask (bits)
187
+ #
188
+ def mask_to_bits(packed_netmask)
189
+ return(packed_netmask) if (packed_netmask == 0)
190
+
191
+ mask = nil
192
+ if (packed_netmask < 2**32)
193
+ mask = 32
194
+ validate_netmask_int(packed_netmask, 4, true)
195
+ else
196
+ mask = 128
197
+ validate_netmask_int(packed_netmask, 6, true)
198
+ end
199
+
200
+ mask.times do
201
+ if ( (packed_netmask & 1) == 1)
202
+ break
203
+ end
204
+ packed_netmask = packed_netmask >> 1
205
+ mask = mask - 1
206
+ end
207
+ return(mask)
208
+ end
209
+ module_function :mask_to_bits
210
+
211
+ #==============================================================================#
212
+ # netmask_str_to_int()
213
+ #==============================================================================#
214
+
215
+ # convert string into integer mask
216
+ #
217
+ def netmask_str_to_int(netmask,version)
218
+ packed_netmask = nil
219
+ all_f = 2**32-1
220
+ all_f = 2**128-1 if (version == 6)
221
+ if(netmask =~ /\./)
222
+ packed_netmask = NetAddr.pack_ip_addr(netmask)
223
+ else
224
+ # remove '/' if present
225
+ if (netmask =~ /^\// )
226
+ netmask[0] = " "
227
+ netmask.lstrip!
228
+ end
229
+ netmask = netmask.to_i
230
+ packed_netmask = all_f ^ (all_f >> netmask)
231
+ end
232
+ return(packed_netmask)
233
+ end
234
+ module_function :netmask_str_to_int
235
+
236
+
237
+
238
+ end # module NetAddr
239
+
240
+ __END__
241
+