ipaddr 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e0852ad74f0bf3001f4c3bc91c8f4709066469b3
4
+ data.tar.gz: e7207467627207e243b6764fd80cb9d27c4690e9
5
+ SHA512:
6
+ metadata.gz: 6819559510a3f7e073dc08ecba98679efd9bed002cb780b4efdb925477af41d1c36bfeb8c2057826bab94b3196ea4769886299cecd5a661273651c88d54a1c0f
7
+ data.tar.gz: 8fa05f41fe8712d9641dd03515341611dd46ee2fdd9a0deb886942a8e17fed97c6e01f9d0d007d40cc554dea7bf0870e9896ad8cd0ffc857c1cc802807187377
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,6 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.1
5
+ - ruby-head
6
+ before_install: gem install bundler
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in ipaddr.gemspec
4
+ gemspec
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>
2
+ Copyright (c) 2007-2017 Akinori MUSHA <knu@iDaemons.org>
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+ 1. Redistributions of source code must retain the above copyright
8
+ notice, this list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright
10
+ notice, this list of conditions and the following disclaimer in the
11
+ documentation and/or other materials provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
+ SUCH DAMAGE.
@@ -0,0 +1,54 @@
1
+ # IPAddr
2
+
3
+ IPAddr provides a set of methods to manipulate an IP address. Both
4
+ IPv4 and IPv6 are supported.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'ipaddr'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install ipaddr
21
+
22
+ ## Usage
23
+
24
+ ```ruby
25
+ require 'ipaddr'
26
+
27
+ ipaddr1 = IPAddr.new "3ffe:505:2::1"
28
+
29
+ p ipaddr1 #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
30
+
31
+ p ipaddr1.to_s #=> "3ffe:505:2::1"
32
+
33
+ ipaddr2 = ipaddr1.mask(48) #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>
34
+
35
+ p ipaddr2.to_s #=> "3ffe:505:2::"
36
+
37
+ ipaddr3 = IPAddr.new "192.168.2.0/24"
38
+
39
+ p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
40
+ ```
41
+
42
+ ## Development
43
+
44
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
45
+
46
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
47
+
48
+ ## Contributing
49
+
50
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/ipaddr.
51
+
52
+ ## License
53
+
54
+ The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ipaddr"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "ipaddr"
7
+ spec.version = "1.0.0"
8
+ spec.authors = ["Akinori MUSHA", "Hajimu UMEMOTO"]
9
+ spec.email = ["knu@idaemons.org", "ume@mahoroba.org"]
10
+
11
+ spec.summary = %q{A class to manipulate an IP address in ruby}
12
+ spec.description = <<-'DESCRIPTION'
13
+ IPAddr provides a set of methods to manipulate an IP address.
14
+ Both IPv4 and IPv6 are supported.
15
+ DESCRIPTION
16
+ spec.homepage = "https://github.com/ruby/ipaddr"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
+ f.match(%r{^(test|spec|features)/})
20
+ end
21
+ spec.bindir = "exe"
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.15"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "test-unit"
28
+ end
@@ -0,0 +1,662 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # ipaddr.rb - A class to manipulate an IP address
4
+ #
5
+ # Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>.
6
+ # Copyright (c) 2007, 2009, 2012 Akinori MUSHA <knu@iDaemons.org>.
7
+ # All rights reserved.
8
+ #
9
+ # You can redistribute and/or modify it under the same terms as Ruby.
10
+ #
11
+ # $Id$
12
+ #
13
+ # Contact:
14
+ # - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
15
+ #
16
+ # TODO:
17
+ # - scope_id support
18
+ #
19
+ require 'socket'
20
+
21
+ # IPAddr provides a set of methods to manipulate an IP address. Both IPv4 and
22
+ # IPv6 are supported.
23
+ #
24
+ # == Example
25
+ #
26
+ # require 'ipaddr'
27
+ #
28
+ # ipaddr1 = IPAddr.new "3ffe:505:2::1"
29
+ #
30
+ # p ipaddr1 #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
31
+ #
32
+ # p ipaddr1.to_s #=> "3ffe:505:2::1"
33
+ #
34
+ # ipaddr2 = ipaddr1.mask(48) #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>
35
+ #
36
+ # p ipaddr2.to_s #=> "3ffe:505:2::"
37
+ #
38
+ # ipaddr3 = IPAddr.new "192.168.2.0/24"
39
+ #
40
+ # p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
41
+
42
+ class IPAddr
43
+
44
+ # 32 bit mask for IPv4
45
+ IN4MASK = 0xffffffff
46
+ # 128 bit mask for IPv6
47
+ IN6MASK = 0xffffffffffffffffffffffffffffffff
48
+ # Format string for IPv6
49
+ IN6FORMAT = (["%.4x"] * 8).join(':')
50
+
51
+ # Regexp _internally_ used for parsing IPv4 address.
52
+ RE_IPV4ADDRLIKE = %r{
53
+ \A
54
+ (\d+) \. (\d+) \. (\d+) \. (\d+)
55
+ \z
56
+ }x
57
+
58
+ # Regexp _internally_ used for parsing IPv6 address.
59
+ RE_IPV6ADDRLIKE_FULL = %r{
60
+ \A
61
+ (?:
62
+ (?: [\da-f]{1,4} : ){7} [\da-f]{1,4}
63
+ |
64
+ ( (?: [\da-f]{1,4} : ){6} )
65
+ (\d+) \. (\d+) \. (\d+) \. (\d+)
66
+ )
67
+ \z
68
+ }xi
69
+
70
+ # Regexp _internally_ used for parsing IPv6 address.
71
+ RE_IPV6ADDRLIKE_COMPRESSED = %r{
72
+ \A
73
+ ( (?: (?: [\da-f]{1,4} : )* [\da-f]{1,4} )? )
74
+ ::
75
+ ( (?:
76
+ ( (?: [\da-f]{1,4} : )* )
77
+ (?:
78
+ [\da-f]{1,4}
79
+ |
80
+ (\d+) \. (\d+) \. (\d+) \. (\d+)
81
+ )
82
+ )? )
83
+ \z
84
+ }xi
85
+
86
+ # Generic IPAddr related error. Exceptions raised in this class should
87
+ # inherit from Error.
88
+ class Error < ArgumentError; end
89
+
90
+ # Raised when the provided IP address is an invalid address.
91
+ class InvalidAddressError < Error; end
92
+
93
+ # Raised when the address family is invalid such as an address with an
94
+ # unsupported family, an address with an inconsistent family, or an address
95
+ # who's family cannot be determined.
96
+ class AddressFamilyError < Error; end
97
+
98
+ # Raised when the address is an invalid length.
99
+ class InvalidPrefixError < InvalidAddressError; end
100
+
101
+ # Returns the address family of this IP address.
102
+ attr_reader :family
103
+
104
+ # Creates a new ipaddr containing the given network byte ordered
105
+ # string form of an IP address.
106
+ def IPAddr::new_ntoh(addr)
107
+ return IPAddr.new(IPAddr::ntop(addr))
108
+ end
109
+
110
+ # Convert a network byte ordered string form of an IP address into
111
+ # human readable form.
112
+ def IPAddr::ntop(addr)
113
+ case addr.size
114
+ when 4
115
+ s = addr.unpack('C4').join('.')
116
+ when 16
117
+ s = IN6FORMAT % addr.unpack('n8')
118
+ else
119
+ raise AddressFamilyError, "unsupported address family"
120
+ end
121
+ return s
122
+ end
123
+
124
+ # Returns a new ipaddr built by bitwise AND.
125
+ def &(other)
126
+ return self.clone.set(@addr & coerce_other(other).to_i)
127
+ end
128
+
129
+ # Returns a new ipaddr built by bitwise OR.
130
+ def |(other)
131
+ return self.clone.set(@addr | coerce_other(other).to_i)
132
+ end
133
+
134
+ # Returns a new ipaddr built by bitwise right-shift.
135
+ def >>(num)
136
+ return self.clone.set(@addr >> num)
137
+ end
138
+
139
+ # Returns a new ipaddr built by bitwise left shift.
140
+ def <<(num)
141
+ return self.clone.set(addr_mask(@addr << num))
142
+ end
143
+
144
+ # Returns a new ipaddr built by bitwise negation.
145
+ def ~
146
+ return self.clone.set(addr_mask(~@addr))
147
+ end
148
+
149
+ # Returns true if two ipaddrs are equal.
150
+ def ==(other)
151
+ other = coerce_other(other)
152
+ rescue
153
+ false
154
+ else
155
+ @family == other.family && @addr == other.to_i
156
+ end
157
+
158
+ # Returns a new ipaddr built by masking IP address with the given
159
+ # prefixlen/netmask. (e.g. 8, 64, "255.255.255.0", etc.)
160
+ def mask(prefixlen)
161
+ return self.clone.mask!(prefixlen)
162
+ end
163
+
164
+ # Returns true if the given ipaddr is in the range.
165
+ #
166
+ # e.g.:
167
+ # require 'ipaddr'
168
+ # net1 = IPAddr.new("192.168.2.0/24")
169
+ # net2 = IPAddr.new("192.168.2.100")
170
+ # net3 = IPAddr.new("192.168.3.0")
171
+ # p net1.include?(net2) #=> true
172
+ # p net1.include?(net3) #=> false
173
+ def include?(other)
174
+ other = coerce_other(other)
175
+ if ipv4_mapped?
176
+ if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
177
+ return false
178
+ end
179
+ mask_addr = (@mask_addr & IN4MASK)
180
+ addr = (@addr & IN4MASK)
181
+ family = Socket::AF_INET
182
+ else
183
+ mask_addr = @mask_addr
184
+ addr = @addr
185
+ family = @family
186
+ end
187
+ if other.ipv4_mapped?
188
+ other_addr = (other.to_i & IN4MASK)
189
+ other_family = Socket::AF_INET
190
+ else
191
+ other_addr = other.to_i
192
+ other_family = other.family
193
+ end
194
+
195
+ if family != other_family
196
+ return false
197
+ end
198
+ return ((addr & mask_addr) == (other_addr & mask_addr))
199
+ end
200
+ alias === include?
201
+
202
+ # Returns the integer representation of the ipaddr.
203
+ def to_i
204
+ return @addr
205
+ end
206
+
207
+ # Returns a string containing the IP address representation.
208
+ def to_s
209
+ str = to_string
210
+ return str if ipv4?
211
+
212
+ str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
213
+ loop do
214
+ break if str.sub!(/\A0:0:0:0:0:0:0:0\z/, '::')
215
+ break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
216
+ break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
217
+ break if str.sub!(/\b0:0:0:0:0\b/, ':')
218
+ break if str.sub!(/\b0:0:0:0\b/, ':')
219
+ break if str.sub!(/\b0:0:0\b/, ':')
220
+ break if str.sub!(/\b0:0\b/, ':')
221
+ break
222
+ end
223
+ str.sub!(/:{3,}/, '::')
224
+
225
+ if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\z/i =~ str
226
+ str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
227
+ end
228
+
229
+ str
230
+ end
231
+
232
+ # Returns a string containing the IP address representation in
233
+ # canonical form.
234
+ def to_string
235
+ return _to_string(@addr)
236
+ end
237
+
238
+ # Returns a network byte ordered string form of the IP address.
239
+ def hton
240
+ case @family
241
+ when Socket::AF_INET
242
+ return [@addr].pack('N')
243
+ when Socket::AF_INET6
244
+ return (0..7).map { |i|
245
+ (@addr >> (112 - 16 * i)) & 0xffff
246
+ }.pack('n8')
247
+ else
248
+ raise AddressFamilyError, "unsupported address family"
249
+ end
250
+ end
251
+
252
+ # Returns true if the ipaddr is an IPv4 address.
253
+ def ipv4?
254
+ return @family == Socket::AF_INET
255
+ end
256
+
257
+ # Returns true if the ipaddr is an IPv6 address.
258
+ def ipv6?
259
+ return @family == Socket::AF_INET6
260
+ end
261
+
262
+ # Returns true if the ipaddr is an IPv4-mapped IPv6 address.
263
+ def ipv4_mapped?
264
+ return ipv6? && (@addr >> 32) == 0xffff
265
+ end
266
+
267
+ # Returns true if the ipaddr is an IPv4-compatible IPv6 address.
268
+ def ipv4_compat?
269
+ if !ipv6? || (@addr >> 32) != 0
270
+ return false
271
+ end
272
+ a = (@addr & IN4MASK)
273
+ return a != 0 && a != 1
274
+ end
275
+
276
+ # Returns a new ipaddr built by converting the native IPv4 address
277
+ # into an IPv4-mapped IPv6 address.
278
+ def ipv4_mapped
279
+ if !ipv4?
280
+ raise InvalidAddressError, "not an IPv4 address"
281
+ end
282
+ return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
283
+ end
284
+
285
+ # Returns a new ipaddr built by converting the native IPv4 address
286
+ # into an IPv4-compatible IPv6 address.
287
+ def ipv4_compat
288
+ if !ipv4?
289
+ raise InvalidAddressError, "not an IPv4 address"
290
+ end
291
+ return self.clone.set(@addr, Socket::AF_INET6)
292
+ end
293
+
294
+ # Returns a new ipaddr built by converting the IPv6 address into a
295
+ # native IPv4 address. If the IP address is not an IPv4-mapped or
296
+ # IPv4-compatible IPv6 address, returns self.
297
+ def native
298
+ if !ipv4_mapped? && !ipv4_compat?
299
+ return self
300
+ end
301
+ return self.clone.set(@addr & IN4MASK, Socket::AF_INET)
302
+ end
303
+
304
+ # Returns a string for DNS reverse lookup. It returns a string in
305
+ # RFC3172 form for an IPv6 address.
306
+ def reverse
307
+ case @family
308
+ when Socket::AF_INET
309
+ return _reverse + ".in-addr.arpa"
310
+ when Socket::AF_INET6
311
+ return ip6_arpa
312
+ else
313
+ raise AddressFamilyError, "unsupported address family"
314
+ end
315
+ end
316
+
317
+ # Returns a string for DNS reverse lookup compatible with RFC3172.
318
+ def ip6_arpa
319
+ if !ipv6?
320
+ raise InvalidAddressError, "not an IPv6 address"
321
+ end
322
+ return _reverse + ".ip6.arpa"
323
+ end
324
+
325
+ # Returns a string for DNS reverse lookup compatible with RFC1886.
326
+ def ip6_int
327
+ if !ipv6?
328
+ raise InvalidAddressError, "not an IPv6 address"
329
+ end
330
+ return _reverse + ".ip6.int"
331
+ end
332
+
333
+ # Returns the successor to the ipaddr.
334
+ def succ
335
+ return self.clone.set(@addr + 1, @family)
336
+ end
337
+
338
+ # Compares the ipaddr with another.
339
+ def <=>(other)
340
+ other = coerce_other(other)
341
+ rescue
342
+ nil
343
+ else
344
+ @addr <=> other.to_i if other.family == @family
345
+ end
346
+ include Comparable
347
+
348
+ # Checks equality used by Hash.
349
+ def eql?(other)
350
+ return self.class == other.class && self.hash == other.hash && self == other
351
+ end
352
+
353
+ # Returns a hash value used by Hash, Set, and Array classes
354
+ def hash
355
+ return ([@addr, @mask_addr].hash << 1) | (ipv4? ? 0 : 1)
356
+ end
357
+
358
+ # Creates a Range object for the network address.
359
+ def to_range
360
+ begin_addr = (@addr & @mask_addr)
361
+
362
+ case @family
363
+ when Socket::AF_INET
364
+ end_addr = (@addr | (IN4MASK ^ @mask_addr))
365
+ when Socket::AF_INET6
366
+ end_addr = (@addr | (IN6MASK ^ @mask_addr))
367
+ else
368
+ raise AddressFamilyError, "unsupported address family"
369
+ end
370
+
371
+ return clone.set(begin_addr, @family)..clone.set(end_addr, @family)
372
+ end
373
+
374
+ # Returns a string containing a human-readable representation of the
375
+ # ipaddr. ("#<IPAddr: family:address/mask>")
376
+ def inspect
377
+ case @family
378
+ when Socket::AF_INET
379
+ af = "IPv4"
380
+ when Socket::AF_INET6
381
+ af = "IPv6"
382
+ else
383
+ raise AddressFamilyError, "unsupported address family"
384
+ end
385
+ return sprintf("#<%s: %s:%s/%s>", self.class.name,
386
+ af, _to_string(@addr), _to_string(@mask_addr))
387
+ end
388
+
389
+ protected
390
+
391
+ # Set +@addr+, the internal stored ip address, to given +addr+. The
392
+ # parameter +addr+ is validated using the first +family+ member,
393
+ # which is +Socket::AF_INET+ or +Socket::AF_INET6+.
394
+ def set(addr, *family)
395
+ case family[0] ? family[0] : @family
396
+ when Socket::AF_INET
397
+ if addr < 0 || addr > IN4MASK
398
+ raise InvalidAddressError, "invalid address"
399
+ end
400
+ when Socket::AF_INET6
401
+ if addr < 0 || addr > IN6MASK
402
+ raise InvalidAddressError, "invalid address"
403
+ end
404
+ else
405
+ raise AddressFamilyError, "unsupported address family"
406
+ end
407
+ @addr = addr
408
+ if family[0]
409
+ @family = family[0]
410
+ end
411
+ return self
412
+ end
413
+
414
+ # Set current netmask to given mask.
415
+ def mask!(mask)
416
+ if mask.kind_of?(String)
417
+ if mask =~ /\A\d+\z/
418
+ prefixlen = mask.to_i
419
+ else
420
+ m = IPAddr.new(mask)
421
+ if m.family != @family
422
+ raise InvalidPrefixError, "address family is not same"
423
+ end
424
+ @mask_addr = m.to_i
425
+ @addr &= @mask_addr
426
+ return self
427
+ end
428
+ else
429
+ prefixlen = mask
430
+ end
431
+ case @family
432
+ when Socket::AF_INET
433
+ if prefixlen < 0 || prefixlen > 32
434
+ raise InvalidPrefixError, "invalid length"
435
+ end
436
+ masklen = 32 - prefixlen
437
+ @mask_addr = ((IN4MASK >> masklen) << masklen)
438
+ when Socket::AF_INET6
439
+ if prefixlen < 0 || prefixlen > 128
440
+ raise InvalidPrefixError, "invalid length"
441
+ end
442
+ masklen = 128 - prefixlen
443
+ @mask_addr = ((IN6MASK >> masklen) << masklen)
444
+ else
445
+ raise AddressFamilyError, "unsupported address family"
446
+ end
447
+ @addr = ((@addr >> masklen) << masklen)
448
+ return self
449
+ end
450
+
451
+ private
452
+
453
+ # Creates a new ipaddr object either from a human readable IP
454
+ # address representation in string, or from a packed in_addr value
455
+ # followed by an address family.
456
+ #
457
+ # In the former case, the following are the valid formats that will
458
+ # be recognized: "address", "address/prefixlen" and "address/mask",
459
+ # where IPv6 address may be enclosed in square brackets (`[' and
460
+ # `]'). If a prefixlen or a mask is specified, it returns a masked
461
+ # IP address. Although the address family is determined
462
+ # automatically from a specified string, you can specify one
463
+ # explicitly by the optional second argument.
464
+ #
465
+ # Otherwise an IP address is generated from a packed in_addr value
466
+ # and an address family.
467
+ #
468
+ # The IPAddr class defines many methods and operators, and some of
469
+ # those, such as &, |, include? and ==, accept a string, or a packed
470
+ # in_addr value instead of an IPAddr object.
471
+ def initialize(addr = '::', family = Socket::AF_UNSPEC)
472
+ if !addr.kind_of?(String)
473
+ case family
474
+ when Socket::AF_INET, Socket::AF_INET6
475
+ set(addr.to_i, family)
476
+ @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
477
+ return
478
+ when Socket::AF_UNSPEC
479
+ raise AddressFamilyError, "address family must be specified"
480
+ else
481
+ raise AddressFamilyError, "unsupported address family: #{family}"
482
+ end
483
+ end
484
+ prefix, prefixlen = addr.split('/')
485
+ if prefix =~ /\A\[(.*)\]\z/i
486
+ prefix = $1
487
+ family = Socket::AF_INET6
488
+ end
489
+ # It seems AI_NUMERICHOST doesn't do the job.
490
+ #Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
491
+ # Socket::AI_NUMERICHOST)
492
+ @addr = @family = nil
493
+ if family == Socket::AF_UNSPEC || family == Socket::AF_INET
494
+ @addr = in_addr(prefix)
495
+ if @addr
496
+ @family = Socket::AF_INET
497
+ end
498
+ end
499
+ if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6)
500
+ @addr = in6_addr(prefix)
501
+ @family = Socket::AF_INET6
502
+ end
503
+ if family != Socket::AF_UNSPEC && @family != family
504
+ raise AddressFamilyError, "address family mismatch"
505
+ end
506
+ if prefixlen
507
+ mask!(prefixlen)
508
+ else
509
+ @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK
510
+ end
511
+ end
512
+
513
+ def coerce_other(other)
514
+ case other
515
+ when IPAddr
516
+ other
517
+ when String
518
+ self.class.new(other)
519
+ else
520
+ self.class.new(other, @family)
521
+ end
522
+ end
523
+
524
+ def in_addr(addr)
525
+ case addr
526
+ when Array
527
+ octets = addr
528
+ else
529
+ m = RE_IPV4ADDRLIKE.match(addr) or return nil
530
+ octets = m.captures
531
+ end
532
+ octets.inject(0) { |i, s|
533
+ (n = s.to_i) < 256 or raise InvalidAddressError, "invalid address"
534
+ s.match(/\A0./) and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous"
535
+ i << 8 | n
536
+ }
537
+ end
538
+
539
+ def in6_addr(left)
540
+ case left
541
+ when RE_IPV6ADDRLIKE_FULL
542
+ if $2
543
+ addr = in_addr($~[2,4])
544
+ left = $1 + ':'
545
+ else
546
+ addr = 0
547
+ end
548
+ right = ''
549
+ when RE_IPV6ADDRLIKE_COMPRESSED
550
+ if $4
551
+ left.count(':') <= 6 or raise InvalidAddressError, "invalid address"
552
+ addr = in_addr($~[4,4])
553
+ left = $1
554
+ right = $3 + '0:0'
555
+ else
556
+ left.count(':') <= ($1.empty? || $2.empty? ? 8 : 7) or
557
+ raise InvalidAddressError, "invalid address"
558
+ left = $1
559
+ right = $2
560
+ addr = 0
561
+ end
562
+ else
563
+ raise InvalidAddressError, "invalid address"
564
+ end
565
+ l = left.split(':')
566
+ r = right.split(':')
567
+ rest = 8 - l.size - r.size
568
+ if rest < 0
569
+ return nil
570
+ end
571
+ (l + Array.new(rest, '0') + r).inject(0) { |i, s|
572
+ i << 16 | s.hex
573
+ } | addr
574
+ end
575
+
576
+ def addr_mask(addr)
577
+ case @family
578
+ when Socket::AF_INET
579
+ return addr & IN4MASK
580
+ when Socket::AF_INET6
581
+ return addr & IN6MASK
582
+ else
583
+ raise AddressFamilyError, "unsupported address family"
584
+ end
585
+ end
586
+
587
+ def _reverse
588
+ case @family
589
+ when Socket::AF_INET
590
+ return (0..3).map { |i|
591
+ (@addr >> (8 * i)) & 0xff
592
+ }.join('.')
593
+ when Socket::AF_INET6
594
+ return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
595
+ else
596
+ raise AddressFamilyError, "unsupported address family"
597
+ end
598
+ end
599
+
600
+ def _to_string(addr)
601
+ case @family
602
+ when Socket::AF_INET
603
+ return (0..3).map { |i|
604
+ (addr >> (24 - 8 * i)) & 0xff
605
+ }.join('.')
606
+ when Socket::AF_INET6
607
+ return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:'))
608
+ else
609
+ raise AddressFamilyError, "unsupported address family"
610
+ end
611
+ end
612
+
613
+ end
614
+
615
+ unless Socket.const_defined? :AF_INET6
616
+ class Socket < BasicSocket
617
+ # IPv6 protocol family
618
+ AF_INET6 = Object.new
619
+ end
620
+
621
+ class << IPSocket
622
+ private
623
+
624
+ def valid_v6?(addr)
625
+ case addr
626
+ when IPAddr::RE_IPV6ADDRLIKE_FULL
627
+ if $2
628
+ $~[2,4].all? {|i| i.to_i < 256 }
629
+ else
630
+ true
631
+ end
632
+ when IPAddr::RE_IPV6ADDRLIKE_COMPRESSED
633
+ if $4
634
+ addr.count(':') <= 6 && $~[4,4].all? {|i| i.to_i < 256}
635
+ else
636
+ addr.count(':') <= 7
637
+ end
638
+ else
639
+ false
640
+ end
641
+ end
642
+
643
+ alias getaddress_orig getaddress
644
+
645
+ public
646
+
647
+ # Returns a +String+ based representation of a valid DNS hostname,
648
+ # IPv4 or IPv6 address.
649
+ #
650
+ # IPSocket.getaddress 'localhost' #=> "::1"
651
+ # IPSocket.getaddress 'broadcasthost' #=> "255.255.255.255"
652
+ # IPSocket.getaddress 'www.ruby-lang.org' #=> "221.186.184.68"
653
+ # IPSocket.getaddress 'www.ccc.de' #=> "2a00:1328:e102:ccc0::122"
654
+ def getaddress(s)
655
+ if valid_v6?(s)
656
+ s
657
+ else
658
+ getaddress_orig(s)
659
+ end
660
+ end
661
+ end
662
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ipaddr
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Akinori MUSHA
8
+ - Hajimu UMEMOTO
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2017-08-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.15'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.15'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '10.0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: test-unit
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: |
57
+ IPAddr provides a set of methods to manipulate an IP address.
58
+ Both IPv4 and IPv6 are supported.
59
+ email:
60
+ - knu@idaemons.org
61
+ - ume@mahoroba.org
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files: []
65
+ files:
66
+ - ".gitignore"
67
+ - ".travis.yml"
68
+ - Gemfile
69
+ - LICENSE.txt
70
+ - README.md
71
+ - Rakefile
72
+ - bin/console
73
+ - bin/setup
74
+ - ipaddr.gemspec
75
+ - lib/ipaddr.rb
76
+ homepage: https://github.com/ruby/ipaddr
77
+ licenses: []
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.6.11
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: A class to manipulate an IP address in ruby
99
+ test_files: []