ip 0.0.3 → 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.
Files changed (3) hide show
  1. data/lib/ip.rb +141 -43
  2. data/test/ip.rb +274 -0
  3. metadata +5 -4
data/lib/ip.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  #
2
2
  # IP - Collection of Tools to work with IP addresses
3
3
  #
4
- # Version:: 0.0.2
4
+ # Version:: 0.1.0
5
5
  # Author:: Erik Hollensbe
6
6
  # License:: BSD
7
7
  # Contact:: erik@hollensbe.org
@@ -95,24 +95,24 @@ class IP
95
95
  raw1, raw2 = [nil, nil]
96
96
 
97
97
  if addr1.kind_of? String
98
- raw1 = IP::Address.pack(IP::Address.new(addr1))
98
+ raw1 = IP::Address::Util.pack(IP::Address.new(addr1))
99
99
  elsif addr1.kind_of? IP::Address
100
- raw1 = IP::Address.pack(addr1)
100
+ raw1 = IP::Address::Util.pack(addr1)
101
101
  else
102
102
  raise IP::AddressException("IP Address is not type String or IP::Address")
103
103
  end
104
104
 
105
105
  if addr2.kind_of? String
106
- raw2 = IP::Address.pack(IP::Address.new(addr2))
106
+ raw2 = IP::Address::Util.pack(IP::Address.new(addr2))
107
107
  elsif addr2.kind_of? IP::Address
108
- raw2 = IP::Address.pack(addr2)
108
+ raw2 = IP::Address::Util.pack(addr2)
109
109
  else
110
110
  raise IP::AddressException("IP Address is not type String or IP::Address")
111
111
  end
112
112
 
113
113
  range = []
114
114
 
115
- (raw1..raw2).each { |x| range.push(IP::Address.unpack(x)) }
115
+ (raw1..raw2).each { |x| range.push(IP::Address::Util.unpack(x)) }
116
116
 
117
117
  return range
118
118
  end
@@ -120,13 +120,9 @@ class IP
120
120
 
121
121
  #
122
122
  # IP::CIDR - Works with Classless Inter-Domain Routing formats, such
123
- # as 10.0.0.1/32.
123
+ # as 10.0.0.1/32 or 10.0.0.1/255.255.255.255
124
124
  #
125
- # Note: this class does not work with expanded RHS
126
- # netmasks, such as 10.0.0.1/255.255.255.255. This is to be
127
- # corrected in a later release.
128
- #
129
-
125
+
130
126
  class CIDR
131
127
  #
132
128
  # Contains the original CIDR you fed it, returned as a string.
@@ -138,7 +134,7 @@ class IP
138
134
  #
139
135
  attr_reader :ip
140
136
  #
141
- # Contains the integer-based netmask (RHS) only. Returned as an
137
+ # Contains the integer-based (short) netmask (RHS) only. Returned as an
142
138
  # integer.
143
139
  #
144
140
  attr_reader :mask
@@ -149,26 +145,49 @@ class IP
149
145
  #
150
146
  def initialize(cidr)
151
147
  if !cidr.kind_of? String
152
- raise IP::AddressException("CIDR value is not of type String")
148
+ raise IP::AddressException.new("CIDR value is not of type String")
153
149
  end
154
150
 
155
151
  @cidr = cidr
156
- @ip, @mask = cidr.split(/\//)
152
+ @ip, @mask = cidr.split(/\//, 2)
153
+
154
+ if @ip.nil? or @mask.nil?
155
+ raise IP::AddressException.new("CIDR is not valid - invalid format")
156
+ end
157
157
 
158
- if @mask.length == 0 or @mask.length > 2 or /\D/.match @mask
159
- raise IP::AddressException("CIDR RHS is not valid - #{@mask}")
158
+ if @mask.length == 0 or /[^0-9.]/.match @mask
159
+ raise IP::AddressException.new("CIDR RHS is not valid - #{@mask}")
160
+ end
161
+
162
+ if @mask.length > 2
163
+ # this will throw an exception if the netmask is malformed.
164
+ @mask = IP::Address::Util.short_netmask(IP::Address.new(@mask))
160
165
  end
161
166
 
162
167
  @ip = IP::Address.new(@ip)
163
168
  @mask = @mask.to_i
164
169
  end
165
170
 
171
+ def netmask
172
+ warn "IP::CIDR#netmask is deprecated. Please use IP::CIDR#long_netmask instead."
173
+ return self.long_netmask
174
+ end
175
+
166
176
  #
167
- # This produces the netmask of the CIDR in an IP::Address object.
177
+ # This produces the long netmask (eg. 255.255.255.255) of the CIDR in an
178
+ # IP::Address object.
168
179
  #
169
- def netmask
170
- raw = 0xFFFFFFFF << (32 - @mask)
171
- return IP::Address.unpack(raw)
180
+ def long_netmask
181
+ return IP::Address::Util.long_netmask(@mask)
182
+ end
183
+
184
+ #
185
+ # This produces the short netmask (eg. 32) of the CIDR in an IP::Address
186
+ # object.
187
+ #
188
+
189
+ def short_netmask
190
+ return @mask
172
191
  end
173
192
 
174
193
  #
@@ -176,31 +195,27 @@ class IP
176
195
  # defined by the CIDR object.
177
196
  #
178
197
  def range
179
- rawip = IP::Address.pack(@ip)
180
- rawnm = 0xFFFFFFFF << (32 - @mask)
181
- upper = rawip | ~rawnm
182
- lower = rawip & rawnm
183
- return IP::Range[IP::Address.unpack(lower), IP::Address.unpack(upper)]
198
+ return IP::Range[self.first_ip, self.last_ip]
184
199
  end
185
200
 
186
201
  #
187
202
  # This returns the first ip address of the cidr as an IP::Address object.
188
203
  #
189
204
  def first_ip
190
- rawip = IP::Address.pack(@ip)
205
+ rawip = IP::Address::Util.pack(@ip)
191
206
  rawnm = 0xFFFFFFFF << (32 - @mask)
192
207
  lower = rawip & rawnm
193
- return IP::Address.unpack(lower)
208
+ return IP::Address::Util.unpack(lower)
194
209
  end
195
210
 
196
211
  #
197
212
  # This returns the last ip address of the cidr as an IP::Address object.
198
213
  #
199
214
  def last_ip
200
- rawip = IP::Address.pack(@ip)
215
+ rawip = IP::Address::Util.pack(@ip)
201
216
  rawnm = 0xFFFFFFFF << (32 - @mask)
202
217
  upper = rawip | ~rawnm
203
- return IP::Address.unpack(upper)
218
+ return IP::Address::Util.unpack(upper)
204
219
  end
205
220
 
206
221
  #
@@ -210,13 +225,13 @@ class IP
210
225
  # This also throws a TypeError if passed invalid data.
211
226
  #
212
227
  def overlaps?(other_cidr)
213
- fail TypeError.new("Expected object of type IP::Address") unless(other_cidr.kind_of?(IP::CIDR))
228
+ raise TypeError.new("Expected object of type IP::CIDR") unless(other_cidr.kind_of?(IP::CIDR))
214
229
 
215
- myfirst = IP::Address.pack(self.first_ip)
216
- mylast = IP::Address.pack(self.last_ip)
230
+ myfirst = IP::Address::Util.pack(self.first_ip)
231
+ mylast = IP::Address::Util.pack(self.last_ip)
217
232
 
218
- otherfirst = IP::Address.pack(other_cidr.first_ip)
219
- otherlast = IP::Address.pack(other_cidr.last_ip)
233
+ otherfirst = IP::Address::Util.pack(other_cidr.first_ip)
234
+ otherlast = IP::Address::Util.pack(other_cidr.last_ip)
220
235
 
221
236
  return ((myfirst >= otherfirst && myfirst <= otherlast) ||
222
237
  (mylast <= otherlast && mylast >= otherfirst) ||
@@ -244,7 +259,7 @@ class IP
244
259
  #
245
260
  def initialize(ip_address)
246
261
  if ! ip_address.kind_of? String
247
- raise IP::AddressException("Fed IP address is not String")
262
+ raise IP::AddressException.new("Fed IP address is not String")
248
263
  end
249
264
  @ip_address = ip_address
250
265
  @octets = ip_address.split(/\./).collect { |x| x.to_i }
@@ -275,23 +290,106 @@ class IP
275
290
  # Class method to pack an IP::Address object into a long integer
276
291
  # used for calculation. Returns a 'FixNum' type.
277
292
  #
293
+ # This method is deprecated. Please use IP::Address::Util#pack instead.
294
+ #
278
295
  def Address.pack(ip)
279
- ret = 0
280
- myip = ip.octets.reverse
281
- 4.times { |x| ret = ret | (myip[x] & 0xFF) << 8*x }
282
- return ret
296
+ warn "IP::Address#pack is deprecated. Please use IP::Address::Util#pack instead."
297
+ return IP::Address::Util.pack(ip)
283
298
  end
284
299
 
285
300
  #
286
301
  # Class method to take a 'FixNum' type and return an IP::Address
287
302
  # object.
288
303
  #
304
+ # This method is deprecated. Please use IP::Address::Util#unpack instead.
305
+ #
289
306
  def Address.unpack(ip)
290
- ret = []
291
- 4.times { |x| ret.push((ip >> 8*x) & 0xFF) }
292
- return IP::Address.new(ret.reverse.join("."))
307
+ warn "IP::Address#unpack is deprecated. Please use IP::Address::Util#unpack instead."
308
+ return IP::Address::Util.unpack(ip)
293
309
  end
294
310
 
295
311
  end
296
312
 
297
313
  end
314
+
315
+ module IP::Address::Util
316
+ #
317
+ # Pack an IP::Address object into a long integer
318
+ # used for calculation. Returns a 'FixNum' type.
319
+ #
320
+ def pack(ip)
321
+ ret = 0
322
+ myip = ip.octets.reverse
323
+ 4.times { |x| ret = ret | (myip[x] & 0xFF) << 8*x }
324
+ return ret
325
+ end
326
+
327
+ module_function :pack
328
+
329
+ #
330
+ # Take a 'FixNum' type and return an IP::Address object.
331
+ #
332
+ def unpack(ip)
333
+ ret = []
334
+ 4.times { |x| ret.push((ip >> 8*x) & 0xFF) }
335
+ return IP::Address.new(ret.reverse.join("."))
336
+ end
337
+
338
+ module_function :unpack
339
+
340
+ #
341
+ # Given an IP::Address object suitable for a netmask, returns the CIDR-notation
342
+ # "short" netmask.
343
+ #
344
+ # ex:
345
+ # short_netmask(IP::Address.new("255.255.255.255")) => 32
346
+ # short_netmask(IP::Address.new("255.255.255.240")) => 28
347
+ #
348
+
349
+ def short_netmask(ip)
350
+ a = []
351
+ (0..3).each do |x|
352
+ if x < 3 && ip[x] < 255 && ip[x+1] > 0
353
+ raise IP::BoundaryException.new("Invalid Netmask")
354
+ end
355
+ a += binary_vector(ip[x])
356
+ end
357
+ retval = 0
358
+ a.each { |x| retval += x }
359
+ return retval
360
+ end
361
+
362
+ module_function :short_netmask
363
+
364
+ #
365
+ # Given a CIDR-notation "short" netmask, returns a IP::Address object containing
366
+ # the equivalent "long" netmask.
367
+ #
368
+ # ex:
369
+ # long_netmask(32) => IP::Address object of "255.255.255.255"
370
+ # long_netmask(28) => IP::Address object of "255.255.255.240"
371
+ #
372
+
373
+ def long_netmask(short)
374
+ raw = 0xFFFFFFFF << (32 - short)
375
+ return IP::Address::Util.unpack(raw)
376
+ end
377
+
378
+ module_function :long_netmask
379
+
380
+ #
381
+ # Given a number (presumably an octet), will produce a binary vector indicating the
382
+ # on/off positions as 1 or 0.
383
+ #
384
+ # ex:
385
+ # binary_vector(255) => [1, 1, 1, 1, 1, 1, 1, 1]
386
+ # binary_vector(240) => [1, 1, 1, 1, 0, 0, 0, 0]
387
+ #
388
+
389
+ def binary_vector(octet)
390
+ return octet.to_i.to_s(2).split(//).collect { |x| x.to_i }
391
+ end
392
+
393
+ module_function :binary_vector
394
+
395
+ end
@@ -0,0 +1,274 @@
1
+ require 'test/unit'
2
+ load 'lib/ip.rb'
3
+
4
+ class CIDRTest < Test::Unit::TestCase
5
+
6
+ def name
7
+ return "IP::CIDR tests"
8
+ end
9
+
10
+ def test_init
11
+ a = nil
12
+ begin
13
+ IP::CIDR.new(Hash.new)
14
+ a = false
15
+ rescue IP::AddressException => e
16
+ a = true
17
+ end
18
+
19
+ assert(a, "data types test #1")
20
+
21
+ begin
22
+ IP::CIDR.new("10.0.0.1")
23
+ a = false
24
+ rescue IP::AddressException => e
25
+ a = true
26
+ end
27
+
28
+ assert(a, "data types test #2")
29
+
30
+ begin
31
+ IP::CIDR.new("10.0.0.1/")
32
+ a = false
33
+ rescue IP::AddressException => e
34
+ a = true
35
+ end
36
+
37
+ assert(a, "data types test #3")
38
+
39
+ begin
40
+ IP::CIDR.new("10.0.0.1/asdf/32")
41
+ a = false
42
+ rescue IP::AddressException => e
43
+ a = true
44
+ end
45
+
46
+ assert(a, "data type test #4")
47
+
48
+ begin
49
+ IP::CIDR.new("10.0.0.1/foomatic_wootmaster")
50
+ a = false
51
+ rescue IP::AddressException => e
52
+ a = true
53
+ end
54
+
55
+ assert(a, "data types test #5")
56
+
57
+ begin
58
+ IP::CIDR.new("foomatic_wootmaster/32")
59
+ a = false
60
+ rescue IP::AddressException => e
61
+ a = true
62
+ end
63
+
64
+ assert(a, "data types test #6")
65
+
66
+ begin
67
+ IP::CIDR.new("10.0.0.1/255")
68
+ a = false
69
+ rescue IP::AddressException => e
70
+ a = true
71
+ end
72
+
73
+ assert(a, "data types test #7")
74
+
75
+ cidr = IP::CIDR.new("10.0.0.1/32")
76
+
77
+ assert(cidr.ip.ip_address == "10.0.0.1", "data integrity test #1")
78
+ assert(cidr.mask == 32, "data integrity test #2")
79
+ assert(cidr.cidr == "10.0.0.1/32", "data integrity test #3")
80
+
81
+ cidr = IP::CIDR.new("10.0.0.1/255.255.255.255")
82
+
83
+ assert(cidr.ip.ip_address == "10.0.0.1", "data integrity test #4")
84
+ assert(cidr.mask == 32, "data integrity test #5")
85
+ assert(cidr.cidr == "10.0.0.1/255.255.255.255", "data integrity test #6")
86
+ end
87
+
88
+ def test_netmasks
89
+ cidr = IP::CIDR.new("10.0.0.1/32")
90
+ assert(cidr.short_netmask == 32, "netmask test #1")
91
+ assert(cidr.long_netmask.ip_address == "255.255.255.255", "netmask test #2")
92
+
93
+ cidr = IP::CIDR.new("10.0.0.1/255.255.255.241")
94
+ assert(cidr.short_netmask == 29, "netmask test #3")
95
+ assert(cidr.long_netmask.ip_address == "255.255.255.248", "netmask test #4")
96
+ end
97
+
98
+ def test_first_last
99
+ cidr = IP::CIDR.new("10.0.0.2/24")
100
+ assert(cidr.first_ip.ip_address == "10.0.0.0", "first/last test #1")
101
+ assert(cidr.last_ip.ip_address == "10.0.0.255", "first/last test #2")
102
+ end
103
+
104
+ def test_range
105
+ cidr = IP::CIDR.new("10.0.0.2/24")
106
+ assert(cidr.range.find_all { |x| x.ip_address == "10.0.0.1" }.length == 1, "range test #1")
107
+ assert(cidr.range.find_all { |x| x.ip_address == "10.0.1.0" }.length == 0, "range test #2")
108
+ end
109
+
110
+ def test_overlaps
111
+ cidr = IP::CIDR.new("10.0.0.2/24")
112
+ cidr2 = IP::CIDR.new("10.0.0.1/29")
113
+
114
+ assert(cidr.overlaps?(cidr2), "overlaps test #1")
115
+
116
+ cidr2 = IP::CIDR.new("10.0.0.1/16")
117
+
118
+ assert(cidr2.overlaps?(cidr), "overlaps test #2")
119
+ assert(cidr.overlaps?(cidr2), "overlaps test #3")
120
+ end
121
+ end
122
+
123
+ class RangeTest < Test::Unit::TestCase
124
+ def name
125
+ return "IP::Range tests"
126
+ end
127
+
128
+ def test_range
129
+ a = nil
130
+ begin
131
+ IP::Range["10.0.0.1", "10.0.0.2"]
132
+ a = true
133
+ rescue Exception => e
134
+ a = false
135
+ end
136
+
137
+ assert(a, "data types test #1")
138
+
139
+ begin
140
+ IP::Range[IP::Address.new("10.0.0.1"), IP::Address.new("10.0.0.2")]
141
+ a = true
142
+ rescue Exception => e
143
+ a = false
144
+ end
145
+
146
+ assert(a, "data types test #2")
147
+
148
+ range = IP::Range["10.0.0.1", "10.0.0.10"]
149
+
150
+ assert(range.find_all { |x| x.ip_address == "10.0.0.1" }.length == 1, "range check #1")
151
+ assert(range.find_all { |x| x.ip_address == "10.0.0.10" }.length == 1, "range check #2")
152
+ assert(range.find_all { |x| x.ip_address == "10.0.0.7" }.length == 1, "range check #3")
153
+ assert(range.find_all { |x| x.ip_address == "10.0.0.11" }.length == 0, "range check #4")
154
+
155
+ end
156
+
157
+ end
158
+
159
+ class AddressTest < Test::Unit::TestCase
160
+ def name
161
+ return "IP::Address tests"
162
+ end
163
+
164
+ def test_init
165
+ ip = nil
166
+ begin
167
+ ip = IP::Address.new(Hash.new)
168
+ rescue IP::AddressException => e
169
+ assert(true, "init test #1")
170
+ end
171
+
172
+ assert(false, "init test #2") if ip
173
+
174
+ ip = nil
175
+
176
+ begin
177
+ ip = IP::Address.new("asdf")
178
+ rescue IP::AddressException => e
179
+ assert(true, "init test #2")
180
+ end
181
+
182
+ assert(false, "init test #2") if ip
183
+ ip = nil
184
+
185
+ begin
186
+ ip = IP::Address.new("0.0.0")
187
+ rescue IP::AddressException => e
188
+ assert(true, "init test #3")
189
+ end
190
+
191
+ assert(false, "init test #3") if ip
192
+ ip = nil
193
+
194
+ begin
195
+ ip = IP::Address.new("256.255.255.255")
196
+ rescue IP::AddressException => e
197
+ assert(true, "init test #4")
198
+ end
199
+
200
+ assert(false, "init test #4") if ip
201
+ end
202
+
203
+ def test_accessor
204
+ ip = IP::Address.new("10.1.2.3")
205
+ assert(ip.ip_address == "10.1.2.3", "accessor test #1")
206
+ assert(ip.octets[0] == 10, "accessor test #2")
207
+ assert(ip.octets[3] == 3, "accessor test #3")
208
+ assert(ip.octets[4] == nil, "accessor test #4")
209
+
210
+ assert(ip.octet(1) == ip[1] && ip[1] == 1, "accessor test #5")
211
+
212
+ oct = nil
213
+
214
+ begin
215
+ oct = ip[4]
216
+ rescue IP::BoundaryException => e
217
+ assert(true, "accessor test #6")
218
+ end
219
+
220
+ assert(false, "accessor test #6") if oct
221
+ end
222
+
223
+ end
224
+
225
+ class UtilTest < Test::Unit::TestCase
226
+ def name
227
+ return "IP::Address::Util tests"
228
+ end
229
+
230
+ def test_pack_unpack
231
+ address = "10.0.0.1"
232
+ assert(IP::Address::Util.unpack(IP::Address::Util.pack(IP::Address.new(address))).ip_address == address, "pack/unpack test")
233
+ end
234
+
235
+ def test_short_netmask
236
+ ip = IP::Address.new("255.255.255.255")
237
+ assert(IP::Address::Util.short_netmask(ip) == 32, "Short Netmask Test #1")
238
+ ip = IP::Address.new("255.255.255.241")
239
+ assert(IP::Address::Util.short_netmask(ip) == 29, "Short Netmask Test #2")
240
+
241
+ nm = nil
242
+
243
+ begin
244
+ nm = IP::Address::Util.short_netmask(IP::Address.new("255.255.0.255"))
245
+ rescue IP::BoundaryException => e
246
+ assert(true, "Short Netmask BoundaryException Check #1")
247
+ end
248
+
249
+ assert(false, "Short Netmask BoundaryException Check #1") if nm
250
+
251
+ nm = nil
252
+
253
+ begin
254
+ nm = IP::Address::Util.short_netmask(IP::Address.new("255.255.240.255"))
255
+ rescue IP::BoundaryException => e
256
+ assert(true, "Short Netmask BoundaryException check #2")
257
+ end
258
+
259
+ assert(false, "Short Netmask BoundaryException check #2") if nm
260
+ end
261
+
262
+ def test_long_netmask
263
+ assert(IP::Address::Util.long_netmask(32).ip_address == "255.255.255.255", "Long Netmask Test #1")
264
+ assert(IP::Address::Util.long_netmask(29).ip_address == "255.255.255.248", "Long Netmask Test #2")
265
+ end
266
+
267
+ def test_binary_vector
268
+ assert(IP::Address::Util.binary_vector(255).length == 8, "Binary Vector Test #1")
269
+ assert(IP::Address::Util.binary_vector(240).find_all { |x| x == 1 }.length == 4, "Binary Vector Test #2")
270
+ assert(IP::Address::Util.binary_vector(241).find_all { |x| x == 1 }.length == 5, "Binary Vector Test #3")
271
+ assert(IP::Address::Util.binary_vector(240)[0] == 1, "Binary Vector Test #4")
272
+ end
273
+
274
+ end
metadata CHANGED
@@ -3,14 +3,14 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: ip
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.3
7
- date: 2006-01-03 00:00:00 -08:00
6
+ version: 0.1.0
7
+ date: 2006-01-20 00:00:00 -08:00
8
8
  summary: "Ruby classes to work with IP address, ranges, and netmasks"
9
9
  require_paths:
10
10
  - lib
11
11
  email: erik@hollensbe.org
12
12
  homepage:
13
- rubyforge_project:
13
+ rubyforge_project: ip-address
14
14
  description:
15
15
  autorequire: ip
16
16
  default_executable:
@@ -30,7 +30,8 @@ authors:
30
30
  - Erik Hollensbe
31
31
  files:
32
32
  - lib/ip.rb
33
- test_files: []
33
+ test_files:
34
+ - test/ip.rb
34
35
  rdoc_options: []
35
36
  extra_rdoc_files: []
36
37
  executables: []