blackwinter-ipaddress 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,72 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+
6
+ $:.unshift(File.expand_path('../lib', __FILE__))
7
+ require 'ipaddress'
8
+
9
+ begin
10
+ require 'rubygems'
11
+ require 'jeweler'
12
+
13
+ Jeweler::Tasks.new do |gem|
14
+ gem.name = IPAddress::GEM
15
+ gem.summary = "IPv4/IPv6 addresses manipulation library"
16
+ gem.email = "ceresa@gmail.com"
17
+ gem.homepage = "http://github.com/bluemonk/ipaddress"
18
+ gem.authors = ["Marco Ceresa"]
19
+ gem.description = <<-EOD
20
+ IPAddress is a Ruby library designed to make manipulation
21
+ of IPv4 and IPv6 addresses both powerful and simple. It mantains
22
+ a layer of compatibility with Ruby's own IPAddr, while
23
+ addressing many of its issues.
24
+ EOD
25
+ end
26
+ rescue LoadError
27
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
28
+ end
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib' << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = true
34
+ end
35
+
36
+ begin
37
+ require 'rcov/rcovtask'
38
+
39
+ Rcov::RcovTask.new do |t|
40
+ t.libs << 'lib' << 'test'
41
+ t.pattern = 'test/**/*_test.rb'
42
+ t.verbose = true
43
+ end
44
+ rescue LoadError
45
+ task :rcov do
46
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
47
+ end
48
+ end
49
+
50
+
51
+ task :default => :test
52
+
53
+ Rake::RDocTask.new do |rdoc|
54
+ rdoc.rdoc_dir = 'rdoc'
55
+ rdoc.title = "ipaddress #{IPAddress::VERSION}"
56
+ rdoc.rdoc_files.include('README*')
57
+ rdoc.rdoc_files.include('lib/**/*.rb')
58
+ end
59
+
60
+ desc "Open an irb session preloaded with this library"
61
+ task :console do
62
+ sh "irb -rubygems -Ilib -ripaddress"
63
+ end
64
+
65
+ desc "Look for TODO and FIXME tags in the code"
66
+ task :todo do
67
+ r = /FIXME|TODO|TBD/
68
+
69
+ Dir['**/*.rb'].each { |f|
70
+ File.foreach(f) { |l| puts "#{f}:#{$.}:#{l}" if l =~ r }
71
+ }
72
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.8.0
data/ipaddress.gemspec ADDED
@@ -0,0 +1,57 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{blackwinter-ipaddress}
8
+ s.version = "0.8.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ['Marco Ceresa', 'Jens Wille']
12
+ s.date = %q{2012-07-20}
13
+ s.description = %q{ IPAddress is a Ruby library designed to make manipulation
14
+ of IPv4 and IPv6 addresses both powerful and simple. It mantains
15
+ a layer of compatibility with Ruby's own IPAddr, while
16
+ addressing many of its issues.
17
+ }
18
+ s.email = %w[ceresa@gmail.com jens.wille@uni-koeln.de]
19
+ s.extra_rdoc_files = [
20
+ "LICENSE",
21
+ "README.rdoc"
22
+ ]
23
+ s.files = [
24
+ ".document",
25
+ "CHANGELOG.rdoc",
26
+ "LICENSE",
27
+ "README.rdoc",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "ipaddress.gemspec",
31
+ "lib/ipaddress.rb",
32
+ "lib/ipaddress/ipv4.rb",
33
+ "lib/ipaddress/ipv6.rb",
34
+ "lib/ipaddress/prefix.rb",
35
+ "lib/ipaddress/conversions.rb",
36
+ "lib/ipaddress/lazy.rb",
37
+ "test/ipaddress/ipv4_test.rb",
38
+ "test/ipaddress/ipv6_test.rb",
39
+ "test/ipaddress/prefix_test.rb",
40
+ "test/ipaddress_test.rb",
41
+ "test/test_helper.rb"
42
+ ]
43
+ s.homepage = %q{https://github.com/blackwinter/ipaddress}
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.6.2}
46
+ s.summary = %q{IPv4/IPv6 addresses manipulation library [Incompatible fork]}
47
+
48
+ if s.respond_to? :specification_version then
49
+ s.specification_version = 3
50
+
51
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
52
+ else
53
+ end
54
+ else
55
+ end
56
+ end
57
+
@@ -0,0 +1,59 @@
1
+ class IPAddress
2
+
3
+ module Conversions
4
+
5
+ extend self
6
+
7
+ def addr2ary(addr)
8
+ addr.split('.').map! { |i| i.to_i }
9
+ end
10
+
11
+ def ary2addr(ary)
12
+ ary.join('.')
13
+ end
14
+
15
+ def addr2bits(addr)
16
+ data2bits(ary2data(addr2ary(addr)))
17
+ end
18
+
19
+ def bits2addr(bits)
20
+ ary2addr([bits].pack('B*').unpack('C4'))
21
+ end
22
+
23
+ def data2bits(data)
24
+ data.unpack('B*').first
25
+ end
26
+
27
+ def int2addr(int)
28
+ ary2addr(int2ary(int))
29
+ end
30
+
31
+ def int2ary(int)
32
+ data2ary(int2data(int))
33
+ end
34
+
35
+ def ary2int(ary)
36
+ int = 0
37
+ ary.each_with_index { |i, j| int += i << (3 - j) * 8 }
38
+ int
39
+ end
40
+
41
+ def data2ary(data)
42
+ data.unpack('C4').map! { |i| i.to_i }
43
+ end
44
+
45
+ def ary2data(ary)
46
+ ary.pack('C4')
47
+ end
48
+
49
+ def data2int(data)
50
+ ary2int(data2ary(data))
51
+ end
52
+
53
+ def int2data(int)
54
+ [int].pack('N')
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,433 @@
1
+ class IPAddress
2
+
3
+ #
4
+ # =Name
5
+ #
6
+ # IPAddress::IPv4 - IP version 4 address manipulation library
7
+ #
8
+ # =Synopsis
9
+ #
10
+ # require 'ipaddress'
11
+ #
12
+ # =Description
13
+ #
14
+ # Class IPAddress::IPv4 is used to handle IPv4 type addresses.
15
+ #
16
+ class IPv4 < self
17
+
18
+ #
19
+ # This Hash contains the prefix values for Classful networks
20
+ #
21
+ # Note that classes C, D and E will all have a default
22
+ # prefix of /24 or 255.255.255.0
23
+ #
24
+ CLASSFUL = {
25
+ 8 => /\A0../, # Class A, from 0.0.0.0 to 127.255.255.255
26
+ 16 => /\A10./, # Class B, from 128.0.0.0 to 191.255.255.255
27
+ 24 => /\A110/ # Class C, D and E, from 192.0.0.0 to 255.255.255.254
28
+ }
29
+
30
+ part = %r{(?: 25[0-5] | 2[0-4]\d | 1\d\d | [1-9]\d | \d )}x
31
+
32
+ INTERNAL_RE = %r{ (?: #{part} \. ){3} #{part} }xo
33
+
34
+ #
35
+ # Regular expression to match an IPv4 address
36
+ #
37
+ RE = %r{ \A #{INTERNAL_RE} \z }xo
38
+
39
+ Prefix = Prefix32
40
+
41
+ MAX_PREFIX = Prefix::MAX
42
+
43
+ PREFIX_RE = %r{\A(?:[12]?\d|3[0-2])\z}
44
+
45
+ class << self
46
+
47
+ alias_method :valid_ip?, :valid_ipv4?
48
+
49
+ #
50
+ # Creates a new IPv4 object from an
51
+ # unsigned 32bits integer.
52
+ #
53
+ # ip = IPAddress::IPv4.parse_u32(167772160)
54
+ #
55
+ # ip.to_string
56
+ # #=> "10.0.0.0/32"
57
+ #
58
+ # The +prefix+ parameter is optional:
59
+ #
60
+ # ip = IPAddress::IPv4.parse_u32(167772160, 8)
61
+ #
62
+ # ip.to_string
63
+ # #=> "10.0.0.0/8"
64
+ #
65
+ def parse_i(i, prefix = MAX_PREFIX)
66
+ instantiate { @int, @_prefix = i, prefix }
67
+ end
68
+
69
+ alias_method :parse_u32, :parse_i
70
+
71
+ #
72
+ # Creates a new IPv4 object from binary data,
73
+ # like the one you get from a network stream.
74
+ #
75
+ # For example, on a network stream the IP 172.16.0.1
76
+ # is represented with the binary "\254\020\n\001".
77
+ #
78
+ # ip = IPAddress::IPv4.parse_data("\254\020\n\001", 24)
79
+ #
80
+ # ip.to_string
81
+ # #=> "172.16.10.1/24"
82
+ #
83
+ def parse_data(data, prefix = MAX_PREFIX)
84
+ parse_i(data2int(data), prefix)
85
+ end
86
+
87
+ #
88
+ # Creates a new IPv4 address object by parsing the
89
+ # address in a classful way.
90
+ #
91
+ # Classful addresses have a fixed netmask based on the
92
+ # class they belong to:
93
+ #
94
+ # * Class A, from 0.0.0.0 to 127.255.255.255
95
+ # * Class B, from 128.0.0.0 to 191.255.255.255
96
+ # * Class C, D and E, from 192.0.0.0 to 255.255.255.254
97
+ #
98
+ # Example:
99
+ #
100
+ # ip = IPAddress::IPv4.parse_classful("10.0.0.1")
101
+ #
102
+ # ip.netmask
103
+ # #=> "255.0.0.0"
104
+ # ip.a?
105
+ # #=> true
106
+ #
107
+ # Note that classes C, D and E will all have a default
108
+ # prefix of /24 or 255.255.255.0
109
+ #
110
+ def parse_classful(ip)
111
+ raise ArgumentError, "Invalid IP #{ip.inspect}" unless valid_ipv4?(ip)
112
+
113
+ bits = '%.8b' % ip.to_i
114
+ new("#{ip.strip}/#{CLASSFUL.find { |_, re| re === bits }.first}")
115
+ end
116
+
117
+ #
118
+ # Extract an IPv4 address from a string and
119
+ # returns a new object
120
+ #
121
+ # Example:
122
+ #
123
+ # str = "foobar172.16.10.1barbaz"
124
+ # ip = IPAddress::IPv4.extract(str)
125
+ #
126
+ # ip.to_s
127
+ # #=> "172.16.10.1"
128
+ #
129
+ def extract(str, prefix = MAX_PREFIX)
130
+ new("#{INTERNAL_RE.match(str)}/#{prefix}")
131
+ end
132
+
133
+ def extract_all(str, prefix = MAX_PREFIX)
134
+ str.scan(INTERNAL_RE).map! { |m| new("#{m}/#{prefix}") }
135
+ end
136
+
137
+ def private_nets
138
+ @private_nets ||= %w[
139
+ 10.0.0.0/8
140
+ 172.16.0.0/12
141
+ 192.168.0.0/16
142
+ ].map! { |i| new(i) }
143
+ end
144
+
145
+ end
146
+
147
+ #
148
+ # Creates a new IPv4 address object.
149
+ #
150
+ # An IPv4 address can be expressed in any of the following forms:
151
+ #
152
+ # * "10.1.1.1/24": ip +address+ and +prefix+. This is the common and
153
+ # suggested way to create an object.
154
+ # * "10.1.1.1/255.255.255.0": ip +address+ and +netmask+. Although
155
+ # convenient sometimes, this format is less clear than the previous
156
+ # one.
157
+ # * "10.1.1.1": if the address alone is specified, the prefix will be
158
+ # set as default 32, also known as the host prefix
159
+ #
160
+ # Examples:
161
+ #
162
+ # # These two are the same
163
+ # ip = IPAddress::IPv4.new("10.0.0.1/24")
164
+ # ip = IPAddress("10.0.0.1/24")
165
+ #
166
+ # # These two are the same
167
+ # IPAddress::IPv4.new("10.0.0.1/8")
168
+ # IPAddress::IPv4.new("10.0.0.1/255.0.0.0")
169
+ #
170
+ def initialize(str)
171
+ ip, netmask = split_ip_and_netmask(str)
172
+
173
+ if netmask.nil? || netmask =~ PREFIX_RE
174
+ @_prefix = netmask || 32
175
+ elsif self.class.valid_ipv4_netmask?(netmask)
176
+ @prefix = Prefix.parse_netmask(netmask)
177
+ else
178
+ raise ArgumentError, "Invalid netmask #{netmask.inspect}"
179
+ end
180
+
181
+ @address, @octets = ip, addr2ary(ip)
182
+ end
183
+
184
+ #
185
+ # Returns the address portion of the IPv4 object
186
+ # as a string.
187
+ #
188
+ # ip = IPAddress("172.16.100.4/22")
189
+ #
190
+ # ip.address
191
+ # #=> "172.16.100.4"
192
+ #
193
+ def address
194
+ lazy(:address) { ary2addr(octets) }
195
+ end
196
+
197
+ #
198
+ # Returns the prefix portion of the IPv4 object
199
+ # as a IPAddress::Prefix32 object
200
+ #
201
+ # ip = IPAddress("172.16.100.4/22")
202
+ #
203
+ # ip.prefix
204
+ # #=> 22
205
+ #
206
+ # ip.prefix.class
207
+ # #=> IPAddress::Prefix32
208
+ #
209
+ def prefix
210
+ lazy(:prefix, false) { Prefix.new(@_prefix) }
211
+ end
212
+
213
+ #
214
+ # Returns the prefix as a string in IP format
215
+ #
216
+ # ip = IPAddress("172.16.100.4/22")
217
+ #
218
+ # ip.netmask
219
+ # #=> "255.255.252.0"
220
+ #
221
+ def netmask
222
+ lazy(:netmask) { prefix.to_ip }
223
+ end
224
+
225
+ #
226
+ # Like IPv4#prefix=, this method allow you to
227
+ # change the prefix / netmask of an IP address
228
+ # object.
229
+ #
230
+ # ip = IPAddress("172.16.100.4")
231
+ #
232
+ # ip.to_string
233
+ # #=> 172.16.100.4/16
234
+ #
235
+ # ip2 = ip.new_netmask("255.255.252.0")
236
+ #
237
+ # ip2.to_string
238
+ # #=> 172.16.100.4/22
239
+ #
240
+ def new_netmask(addr)
241
+ new_prefix(Prefix.parse_netmask(addr))
242
+ end
243
+
244
+ #
245
+ # Returns the address as an array of decimal values
246
+ #
247
+ # ip = IPAddress("172.16.100.4")
248
+ #
249
+ # ip.octets
250
+ # #=> [172, 16, 100, 4]
251
+ #
252
+ def octets
253
+ lazy(:octets) { int2ary(to_i) }
254
+ end
255
+
256
+ alias_method :groups, :octets
257
+
258
+ #
259
+ # Returns a string with the address portion of
260
+ # the IPv4 object
261
+ #
262
+ # ip = IPAddress("172.16.100.4/22")
263
+ #
264
+ # ip.to_s
265
+ # #=> "172.16.100.4"
266
+ #
267
+ def to_s
268
+ address
269
+ end
270
+
271
+ #
272
+ # Returns the address portion in unsigned
273
+ # 32 bits integer format.
274
+ #
275
+ # This method is identical to the C function
276
+ # inet_pton to create a 32 bits address family
277
+ # structure.
278
+ #
279
+ # ip = IPAddress("10.0.0.0/8")
280
+ #
281
+ # ip.to_i
282
+ # #=> 167772160
283
+ #
284
+ def to_i
285
+ lazy(:int) { ary2int(octets) }
286
+ end
287
+
288
+ alias_method :u32, :to_i
289
+ alias_method :to_u32, :to_i
290
+
291
+ #
292
+ # Returns the address portion of an IPv4 object
293
+ # in a network byte order format.
294
+ #
295
+ # ip = IPAddress("172.16.10.1/24")
296
+ #
297
+ # ip.data
298
+ # #=> "\254\020\n\001"
299
+ #
300
+ # It is usually used to include an IP address
301
+ # in a data packet to be sent over a socket
302
+ #
303
+ # a = Socket.open(params) # socket details here
304
+ # ip = IPAddress("10.1.1.0/24")
305
+ # binary_data = ["Address: "].pack("a*") + ip.data
306
+ #
307
+ # # Send binary data
308
+ # a.puts binary_data
309
+ #
310
+ def data
311
+ lazy(:data) { int2data(to_i) }
312
+ end
313
+
314
+ #
315
+ # Returns the octet specified by index
316
+ #
317
+ # ip = IPAddress("172.16.100.50/24")
318
+ #
319
+ # ip[0]
320
+ # #=> 172
321
+ # ip[1]
322
+ # #=> 16
323
+ # ip[2]
324
+ # #=> 100
325
+ # ip[3]
326
+ # #=> 50
327
+ #
328
+ def [](index)
329
+ octets[index]
330
+ end
331
+
332
+ alias_method :octet, :[]
333
+ alias_method :group, :[]
334
+
335
+ alias_method :network_u32, :network_i
336
+
337
+ alias_method :broadcast_u32, :broadcast_i
338
+
339
+ #
340
+ # Returns the IP address in in-addr.arpa format
341
+ # for DNS lookups
342
+ #
343
+ # ip = IPAddress("172.16.100.50/24")
344
+ #
345
+ # ip.reverse
346
+ # #=> "50.100.16.172.in-addr.arpa"
347
+ #
348
+ def reverse
349
+ lazy(:reverse) { "#{ary2addr(octets.reverse)}.in-addr.arpa" }
350
+ end
351
+
352
+ alias_method :arpa, :reverse
353
+
354
+ #
355
+ # Checks if an IPv4 address objects belongs
356
+ # to a private network RFC1918
357
+ #
358
+ # Example:
359
+ #
360
+ # ip = IPAddress "10.1.1.1/24"
361
+ # ip.private?
362
+ # #=> true
363
+ #
364
+ def private?
365
+ lazy(:private_p) { self.class.private_nets.any? { |i| i.include?(self) } }
366
+ end
367
+
368
+ #
369
+ # Checks whether the ip address belongs to a
370
+ # RFC 791 CLASS A network, no matter
371
+ # what the subnet mask is.
372
+ #
373
+ # Example:
374
+ #
375
+ # ip = IPAddress("10.0.0.1/24")
376
+ #
377
+ # ip.a?
378
+ # #=> true
379
+ #
380
+ def a?
381
+ lazy(:a_p) { CLASSFUL[8] === bits }
382
+ end
383
+
384
+ #
385
+ # Checks whether the ip address belongs to a
386
+ # RFC 791 CLASS B network, no matter
387
+ # what the subnet mask is.
388
+ #
389
+ # Example:
390
+ #
391
+ # ip = IPAddress("172.16.10.1/24")
392
+ #
393
+ # ip.b?
394
+ # #=> true
395
+ #
396
+ def b?
397
+ lazy(:b_p) { CLASSFUL[16] === bits }
398
+ end
399
+
400
+ #
401
+ # Checks whether the ip address belongs to a
402
+ # RFC 791 CLASS C network, no matter
403
+ # what the subnet mask is.
404
+ #
405
+ # Example:
406
+ #
407
+ # ip = IPAddress("192.168.1.1/30")
408
+ #
409
+ # ip.c?
410
+ # #=> true
411
+ #
412
+ def c?
413
+ lazy(:c_p) { CLASSFUL[24] === bits }
414
+ end
415
+
416
+ #
417
+ # Return the ip address in a format compatible
418
+ # with the IPv6 Mapped IPv4 addresses
419
+ #
420
+ # Example:
421
+ #
422
+ # ip = IPAddress("172.16.10.1/24")
423
+ #
424
+ # ip.to_ipv6
425
+ # #=> "ac10:0a01"
426
+ #
427
+ def to_ipv6
428
+ lazy(:to_ipv6) { '%.4x:%.4x' % int2data(to_i).unpack('n2') }
429
+ end
430
+
431
+ end
432
+
433
+ end