construqt-ipaddress 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile ADDED
@@ -0,0 +1,83 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/clean'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |gem|
8
+ gem.name = "ipaddress"
9
+ gem.summary = %Q{IPv4/IPv6 addresses manipulation library}
10
+ gem.email = "ceresa@gmail.com"
11
+ gem.homepage = "http://github.com/bluemonk/ipaddress"
12
+ gem.authors = ["Marco Ceresa"]
13
+ gem.description = <<-EOD
14
+ IPAddress is a Ruby library designed to make manipulation
15
+ of IPv4 and IPv6 addresses both powerful and simple. It mantains
16
+ a layer of compatibility with Ruby's own IPAddr, while
17
+ addressing many of its issues.
18
+ EOD
19
+ end
20
+ rescue LoadError
21
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
22
+ end
23
+
24
+ require 'rake/testtask'
25
+ Rake::TestTask.new(:test) do |test|
26
+ test.libs << 'lib' << 'test'
27
+ test.pattern = 'test/**/*_test.rb'
28
+ test.verbose = true
29
+ end
30
+
31
+ begin
32
+ require 'rcov/rcovtask'
33
+ Rcov::RcovTask.new do |test|
34
+ test.libs << 'test'
35
+ test.pattern = 'test/**/*_test.rb'
36
+ test.verbose = true
37
+ end
38
+ rescue LoadError
39
+ task :rcov do
40
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
41
+ end
42
+ end
43
+
44
+
45
+ task :default => :test
46
+
47
+ require 'rdoc/task'
48
+ Rake::RDocTask.new do |rdoc|
49
+ if File.exist?('VERSION.yml')
50
+ config = YAML.load(File.read('VERSION.yml'))
51
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
52
+ else
53
+ version = ""
54
+ end
55
+
56
+ rdoc.rdoc_dir = 'rdoc'
57
+ rdoc.title = "ipaddress #{version}"
58
+ rdoc.rdoc_files.include('README*')
59
+ rdoc.rdoc_files.include('lib/**/*.rb')
60
+ end
61
+
62
+ desc "Open an irb session preloaded with this library"
63
+ task :console do
64
+ sh "irb -rubygems -I lib -r ipaddress.rb"
65
+ end
66
+
67
+ desc "Look for TODO and FIXME tags in the code"
68
+ task :todo do
69
+ def egrep(pattern)
70
+ Dir['**/*.rb'].each do |fn|
71
+ count = 0
72
+ open(fn) do |f|
73
+ while line = f.gets
74
+ count += 1
75
+ if line =~ pattern
76
+ puts "#{fn}:#{count}:#{line}"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ egrep /(FIXME|TODO|TBD)/
83
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.8.0
data/ipaddress.gemspec ADDED
@@ -0,0 +1,55 @@
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{construqt-ipaddress}
8
+ s.version = "0.8.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Marco Ceresa", "Meno Abels"]
12
+ s.date = %q{2014-11-29}
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 = %q{meno.abels@construqt.me}
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
+ "test/ipaddress/ipv4_test.rb",
36
+ "test/ipaddress/ipv6_test.rb",
37
+ "test/ipaddress/prefix_test.rb",
38
+ "test/ipaddress_test.rb",
39
+ "test/test_helper.rb"
40
+ ]
41
+ s.homepage = %q{http://github.com/bluemonk/ipaddress}
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.6.2}
44
+ s.summary = %q{IPv4/IPv6 addresses manipulation library}
45
+
46
+ if s.respond_to? :specification_version then
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ else
51
+ end
52
+ else
53
+ end
54
+ end
55
+
data/lib/ipaddress.rb ADDED
@@ -0,0 +1,306 @@
1
+ #
2
+ # = IPAddress
3
+ #
4
+ # A ruby library to manipulate IPv4 and IPv6 addresses
5
+ #
6
+ #
7
+ # Package:: IPAddress
8
+ # Author:: Marco Ceresa <ceresa@ieee.org>
9
+ # License:: Ruby License
10
+ #
11
+ #--
12
+ #
13
+ #++
14
+
15
+ require 'ipaddress/ipv4'
16
+ require 'ipaddress/ipv6'
17
+
18
+ module IPAddress
19
+
20
+ NAME = "IPAddress"
21
+ GEM = "ipaddress"
22
+ AUTHORS = ["Marco Ceresa <ceresa@ieee.org>"]
23
+
24
+ #
25
+ # Parse the argument string to create a new
26
+ # IPv4, IPv6 or Mapped IP object
27
+ #
28
+ # ip = IPAddress.parse "172.16.10.1/24"
29
+ # ip6 = IPAddress.parse "2001:db8::8:800:200c:417a/64"
30
+ # ip_mapped = IPAddress.parse "::ffff:172.16.10.1/128"
31
+ #
32
+ # All the object created will be instances of the
33
+ # correct class:
34
+ #
35
+ # ip.class
36
+ # #=> IPAddress::IPv4
37
+ # ip6.class
38
+ # #=> IPAddress::IPv6
39
+ # ip_mapped.class
40
+ # #=> IPAddress::IPv6::Mapped
41
+ #
42
+ def IPAddress::parse(str)
43
+ case str
44
+ when /:.+\./
45
+ IPAddress::IPv6::Mapped.new(str)
46
+ when /\./
47
+ IPAddress::IPv4.new(str)
48
+ when /:/
49
+ IPAddress::IPv6.new(str)
50
+ else
51
+ raise ArgumentError, "Unknown IP Address #{str}"
52
+ end
53
+ end
54
+
55
+ #
56
+ # True if the object is an IPv4 address
57
+ #
58
+ # ip = IPAddress("192.168.10.100/24")
59
+ #
60
+ # ip.ipv4?
61
+ # #-> true
62
+ #
63
+ def ipv4?
64
+ self.kind_of? IPAddress::IPv4
65
+ end
66
+
67
+ #
68
+ # True if the object is an IPv6 address
69
+ #
70
+ # ip = IPAddress("192.168.10.100/24")
71
+ #
72
+ # ip.ipv6?
73
+ # #-> false
74
+ #
75
+ def ipv6?
76
+ self.kind_of? IPAddress::IPv6
77
+ end
78
+
79
+ #
80
+ # Checks if the given string is a valid IP address,
81
+ # either IPv4 or IPv6
82
+ #
83
+ # Example:
84
+ #
85
+ # IPAddress::valid? "2002::1"
86
+ # #=> true
87
+ #
88
+ # IPAddress::valid? "10.0.0.256"
89
+ # #=> false
90
+ #
91
+ def self.valid?(addr)
92
+ valid_ipv4?(addr) || valid_ipv6?(addr)
93
+ end
94
+
95
+ #
96
+ # Checks if the given string is a valid IPv4 address
97
+ #
98
+ # Example:
99
+ #
100
+ # IPAddress::valid_ipv4? "2002::1"
101
+ # #=> false
102
+ #
103
+ # IPAddress::valid_ipv4? "172.16.10.1"
104
+ # #=> true
105
+ #
106
+ def self.valid_ipv4?(addr)
107
+ if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
108
+ return $~.captures.all? {|i| i.to_i < 256}
109
+ end
110
+ false
111
+ end
112
+
113
+ #
114
+ # Checks if the argument is a valid IPv4 netmask
115
+ # expressed in dotted decimal format.
116
+ #
117
+ # IPAddress.valid_ipv4_netmask? "255.255.0.0"
118
+ # #=> true
119
+ #
120
+ def self.valid_ipv4_netmask?(addr)
121
+ arr = addr.split(".").map{|i| i.to_i}.pack("CCCC").unpack("B*").first.scan(/01/)
122
+ arr.empty? && valid_ipv4?(addr)
123
+ rescue
124
+ return false
125
+ end
126
+
127
+ #
128
+ # Checks if the given string is a valid IPv6 address
129
+ #
130
+ # Example:
131
+ #
132
+ # IPAddress::valid_ipv6? "2002::1"
133
+ # #=> true
134
+ #
135
+ # IPAddress::valid_ipv6? "2002::DEAD::BEEF"
136
+ # #=> false
137
+ #
138
+ def self.valid_ipv6?(addr)
139
+ # https://gist.github.com/cpetschnig/294476
140
+ # http://forums.intermapper.com/viewtopic.php?t=452
141
+ return true if /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/ =~ addr
142
+ false
143
+ end
144
+
145
+ #
146
+ # Deprecate method
147
+ #
148
+ def self.deprecate(message = nil) # :nodoc:
149
+ message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
150
+ warn("DEPRECATION WARNING: #{message}")
151
+ end
152
+
153
+ #
154
+ # private helper for summarize
155
+ # assumes that networks is output from reduce_networks
156
+ # means it should be sorted lowers first and uniq
157
+ #
158
+ def self.aggregate(networks)
159
+ stack = networks.map{|i| i.network }.sort! # make input imutable
160
+ pos = 0
161
+ while true
162
+ pos = pos < 0 ? 0 : pos # start @beginning
163
+ first = stack[pos]
164
+ unless first
165
+ break
166
+ end
167
+ pos += 1
168
+ second = stack[pos]
169
+ unless second
170
+ break
171
+ end
172
+ pos += 1
173
+ if first.include?(second)
174
+ pos -= 2
175
+ stack.delete_at(pos+1)
176
+ else
177
+ first.prefix -= 1
178
+ if first.prefix+1 == second.prefix && first.include?(second)
179
+ pos -= 2
180
+ stack[pos] = first
181
+ stack.delete_at(pos+1)
182
+ pos -= 1 # backtrack
183
+ else
184
+ first.prefix += 1 #reset prefix
185
+ pos -= 1 # do it with second as first
186
+ end
187
+ end
188
+ end
189
+ stack[0..pos-1]
190
+ end
191
+
192
+ #
193
+ # Summarization (or aggregation) is the process when two or more
194
+ # networks are taken together to check if a supernet, including all
195
+ # and only these networks, exists. If it exists then this supernet
196
+ # is called the summarized (or aggregated) network.
197
+ #
198
+ # It is very important to understand that summarization can only
199
+ # occur if there are no holes in the aggregated network, or, in other
200
+ # words, if the given networks fill completely the address space
201
+ # of the supernet. So the two rules are:
202
+ #
203
+ # 1) The aggregate network must contain +all+ the IP addresses of the
204
+ # original networks;
205
+ # 2) The aggregate network must contain +only+ the IP addresses of the
206
+ # original networks;
207
+ #
208
+ # A few examples will help clarify the above. Let's consider for
209
+ # instance the following two networks:
210
+ #
211
+ # ip1 = IPAddress("172.16.10.0/24")
212
+ # ip2 = IPAddress("172.16.11.0/24")
213
+ #
214
+ # These two networks can be expressed using only one IP address
215
+ # network if we change the prefix. Let Ruby do the work:
216
+ #
217
+ # IPAddress::IPv4::summarize(ip1,ip2).to_s
218
+ # #=> "172.16.10.0/23"
219
+ #
220
+ # We note how the network "172.16.10.0/23" includes all the addresses
221
+ # specified in the above networks, and (more important) includes
222
+ # ONLY those addresses.
223
+ #
224
+ # If we summarized +ip1+ and +ip2+ with the following network:
225
+ #
226
+ # "172.16.0.0/16"
227
+ #
228
+ # we would have satisfied rule #1 above, but not rule #2. So "172.16.0.0/16"
229
+ # is not an aggregate network for +ip1+ and +ip2+.
230
+ #
231
+ # If it's not possible to compute a single aggregated network for all the
232
+ # original networks, the method returns an array with all the aggregate
233
+ # networks found. For example, the following four networks can be
234
+ # aggregated in a single /22:
235
+ #
236
+ # ip1 = IPAddress("10.0.0.1/24")
237
+ # ip2 = IPAddress("10.0.1.1/24")
238
+ # ip3 = IPAddress("10.0.2.1/24")
239
+ # ip4 = IPAddress("10.0.3.1/24")
240
+ #
241
+ # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_string
242
+ # #=> "10.0.0.0/22",
243
+ #
244
+ # But the following networks can't be summarized in a single network:
245
+ #
246
+ # ip1 = IPAddress("10.0.1.1/24")
247
+ # ip2 = IPAddress("10.0.2.1/24")
248
+ # ip3 = IPAddress("10.0.3.1/24")
249
+ # ip4 = IPAddress("10.0.4.1/24")
250
+ #
251
+ # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
252
+ # #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
253
+ #
254
+ def self.summarize(networks)
255
+ aggregate(networks.map{|i| ((i.kind_of?(String)&&IPAddress.parse(i))||i) })
256
+ end
257
+
258
+ end # module IPAddress
259
+
260
+ #
261
+ # IPAddress is a wrapper method built around
262
+ # IPAddress's library classes. Its purpouse is to
263
+ # make you indipendent from the type of IP address
264
+ # you're going to use.
265
+ #
266
+ # For example, instead of creating the three types
267
+ # of IP addresses using their own contructors
268
+ #
269
+ # ip = IPAddress::IPv4.new "172.16.10.1/24"
270
+ # ip6 = IPAddress::IPv6.new "2001:db8::8:800:200c:417a/64"
271
+ # ip_mapped = IPAddress::IPv6::Mapped "::ffff:172.16.10.1/128"
272
+ #
273
+ # you can just use the IPAddress wrapper:
274
+ #
275
+ # ip = IPAddress "172.16.10.1/24"
276
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
277
+ # ip_mapped = IPAddress "::ffff:172.16.10.1/128"
278
+ #
279
+ # All the object created will be instances of the
280
+ # correct class:
281
+ #
282
+ # ip.class
283
+ # #=> IPAddress::IPv4
284
+ # ip6.class
285
+ # #=> IPAddress::IPv6
286
+ # ip_mapped.class
287
+ # #=> IPAddress::IPv6::Mapped
288
+ #
289
+ def IPAddress(str)
290
+ IPAddress::parse str
291
+ end
292
+
293
+ #
294
+ # Compatibility with Ruby 1.8
295
+ #
296
+ if RUBY_VERSION =~ /1\.8/
297
+ class Hash # :nodoc:
298
+ alias :key :index
299
+ end
300
+ module Math # :nodoc:
301
+ def Math.log2(n)
302
+ log(n) / log(2)
303
+ end
304
+ end
305
+ end
306
+