rubysl-ipaddr 1.0.0 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61a9688ec7dfabdf5ce11445ebc70a24a953a1a2
4
- data.tar.gz: 6b81ae1ea4c64b3ebb45277958b80c21fcf4aa61
3
+ metadata.gz: da2d6bd4f039da4e0148fa2df7c361a7631be02c
4
+ data.tar.gz: 6c6bf37f901a3cd7f06471e5f700bae06a613349
5
5
  SHA512:
6
- metadata.gz: 65e6dcee1a31bf2c6144874bf1c8b597027bdd38a63122f1f4f873fc394dfe4d7ab77afbc39c7d94489cddd0b8a82bdfcd22fc00d8490126218f5c2e05fb412f
7
- data.tar.gz: 3b119ec1727908dc3e5a87d57fd0b5b64c837a2d3fa4f816342f3aa763bb6ddee989dc495c5f3843496a3d2c20f295bfac0d79795952568a1a4651c8c44cf152
6
+ metadata.gz: 771036121c91fa439f3c934740af4719471dce44df2d45ad5b9f0a310b3814427b91e560f7bb40bae2be283aeb6e0893391a630873ce129d67eb844db9dc1ac2
7
+ data.tar.gz: 20608b6099a074ce62809a84e4a01e7ed6d4360730b5b24dd2732a363160ede846d5889305a92a2f0d31d7046e3a351f04f0ff20eb5e09af61e44d798bd28318
@@ -1,8 +1,7 @@
1
1
  language: ruby
2
- before_install:
3
- - gem update --system
4
- - gem --version
5
- - gem install rubysl-bundler
6
- script: bundle exec mspec spec
2
+ env:
3
+ - RUBYLIB=lib
4
+ script: bundle exec mspec
7
5
  rvm:
8
- - rbx-nightly-18mode
6
+ - 1.9.3
7
+ - rbx-nightly-19mode
@@ -2,12 +2,12 @@
2
2
  # ipaddr.rb - A class to manipulate an IP address
3
3
  #
4
4
  # Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>.
5
- # Copyright (c) 2007 Akinori MUSHA <knu@iDaemons.org>.
5
+ # Copyright (c) 2007, 2009, 2012 Akinori MUSHA <knu@iDaemons.org>.
6
6
  # All rights reserved.
7
7
  #
8
8
  # You can redistribute and/or modify it under the same terms as Ruby.
9
9
  #
10
- # $Id: ipaddr.rb 18049 2008-07-12 15:08:29Z shyouhei $
10
+ # $Id$
11
11
  #
12
12
  # Contact:
13
13
  # - Akinori MUSHA <knu@iDaemons.org> (current maintainer)
@@ -17,78 +17,88 @@
17
17
  #
18
18
  require 'socket'
19
19
 
20
- unless Socket.const_defined? "AF_INET6"
21
- class Socket
22
- AF_INET6 = Object.new
23
- end
24
-
25
- class << IPSocket
26
- def valid_v4?(addr)
27
- if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
28
- return $~.captures.all? {|i| i.to_i < 256}
29
- end
30
- return false
31
- end
32
-
33
- def valid_v6?(addr)
34
- # IPv6 (normal)
35
- return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
36
- return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
37
- return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
38
- # IPv6 (IPv4 compat)
39
- return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_v4?($')
40
- return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
41
- return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
42
-
43
- false
44
- end
45
-
46
- def valid?(addr)
47
- valid_v4?(addr) || valid_v6?(addr)
48
- end
49
-
50
- alias getaddress_orig getaddress
51
- def getaddress(s)
52
- if valid?(s)
53
- s
54
- elsif /\A[-A-Za-z\d.]+\Z/ =~ s
55
- getaddress_orig(s)
56
- else
57
- raise ArgumentError, "invalid address"
58
- end
59
- end
60
- end
61
- end
62
-
63
20
  # IPAddr provides a set of methods to manipulate an IP address. Both IPv4 and
64
21
  # IPv6 are supported.
65
22
  #
66
23
  # == Example
67
24
  #
68
25
  # require 'ipaddr'
69
- #
26
+ #
70
27
  # ipaddr1 = IPAddr.new "3ffe:505:2::1"
71
- #
72
- # p ipaddr1 #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
73
- #
74
- # p ipaddr1.to_s #=> "3ffe:505:2::1"
75
- #
76
- # ipaddr2 = ipaddr1.mask(48) #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>
77
- #
78
- # p ipaddr2.to_s #=> "3ffe:505:2::"
79
- #
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
+ #
80
37
  # ipaddr3 = IPAddr.new "192.168.2.0/24"
81
- #
82
- # p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
38
+ #
39
+ # p ipaddr3 #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
83
40
 
84
41
  class IPAddr
85
42
 
43
+ # 32 bit mask for IPv4
86
44
  IN4MASK = 0xffffffff
45
+ # 128 bit mask for IPv4
87
46
  IN6MASK = 0xffffffffffffffffffffffffffffffff
47
+ # Format string for IPv6
88
48
  IN6FORMAT = (["%.4x"] * 8).join(':')
89
49
 
50
+ # Regexp _internally_ used for parsing IPv4 address.
51
+ RE_IPV4ADDRLIKE = %r{
52
+ \A
53
+ (\d+) \. (\d+) \. (\d+) \. (\d+)
54
+ \z
55
+ }x
56
+
57
+ # Regexp _internally_ used for parsing IPv6 address.
58
+ RE_IPV6ADDRLIKE_FULL = %r{
59
+ \A
60
+ (?:
61
+ (?: [\da-f]{1,4} : ){7} [\da-f]{1,4}
62
+ |
63
+ ( (?: [\da-f]{1,4} : ){6} )
64
+ (\d+) \. (\d+) \. (\d+) \. (\d+)
65
+ )
66
+ \z
67
+ }xi
68
+
69
+ # Regexp _internally_ used for parsing IPv6 address.
70
+ RE_IPV6ADDRLIKE_COMPRESSED = %r{
71
+ \A
72
+ ( (?: (?: [\da-f]{1,4} : )* [\da-f]{1,4} )? )
73
+ ::
74
+ ( (?:
75
+ ( (?: [\da-f]{1,4} : )* )
76
+ (?:
77
+ [\da-f]{1,4}
78
+ |
79
+ (\d+) \. (\d+) \. (\d+) \. (\d+)
80
+ )
81
+ )? )
82
+ \z
83
+ }xi
84
+
85
+ # Generic IPAddr related error. Exceptions raised in this class should
86
+ # inherit from Error.
87
+ class Error < ArgumentError; end
88
+
89
+ # Raised when the provided IP address is an invalid address.
90
+ class InvalidAddressError < Error; end
91
+
92
+ # Raised when the address family is invalid such as an address with an
93
+ # unsupported family, an address with an inconsistent family, or an address
94
+ # who's family cannot be determined.
95
+ class AddressFamilyError < Error; end
96
+
97
+ # Raised when the address is an invalid length.
98
+ class InvalidPrefixError < InvalidAddressError; end
99
+
90
100
  # Returns the address family of this IP address.
91
- attr :family
101
+ attr_reader :family
92
102
 
93
103
  # Creates a new ipaddr containing the given network byte ordered
94
104
  # string form of an IP address.
@@ -105,7 +115,7 @@ class IPAddr
105
115
  when 16
106
116
  s = IN6FORMAT % addr.unpack('n8')
107
117
  else
108
- raise ArgumentError, "unsupported address family"
118
+ raise AddressFamilyError, "unsupported address family"
109
119
  end
110
120
  return s
111
121
  end
@@ -154,13 +164,13 @@ class IPAddr
154
164
  # net1 = IPAddr.new("192.168.2.0/24")
155
165
  # net2 = IPAddr.new("192.168.2.100")
156
166
  # net3 = IPAddr.new("192.168.3.0")
157
- # p net1.include?(net2) #=> true
158
- # p net1.include?(net3) #=> false
167
+ # p net1.include?(net2) #=> true
168
+ # p net1.include?(net3) #=> false
159
169
  def include?(other)
160
170
  other = coerce_other(other)
161
171
  if ipv4_mapped?
162
172
  if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
163
- return false
173
+ return false
164
174
  end
165
175
  mask_addr = (@mask_addr & IN4MASK)
166
176
  addr = (@addr & IN4MASK)
@@ -197,7 +207,7 @@ class IPAddr
197
207
 
198
208
  str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
199
209
  loop do
200
- break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
210
+ break if str.sub!(/\A0:0:0:0:0:0:0:0\z/, '::')
201
211
  break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
202
212
  break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
203
213
  break if str.sub!(/\b0:0:0:0:0\b/, ':')
@@ -208,7 +218,7 @@ class IPAddr
208
218
  end
209
219
  str.sub!(/:{3,}/, '::')
210
220
 
211
- if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\Z/i =~ str
221
+ if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\z/i =~ str
212
222
  str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
213
223
  end
214
224
 
@@ -228,10 +238,10 @@ class IPAddr
228
238
  return [@addr].pack('N')
229
239
  when Socket::AF_INET6
230
240
  return (0..7).map { |i|
231
- (@addr >> (112 - 16 * i)) & 0xffff
241
+ (@addr >> (112 - 16 * i)) & 0xffff
232
242
  }.pack('n8')
233
243
  else
234
- raise "unsupported address family"
244
+ raise AddressFamilyError, "unsupported address family"
235
245
  end
236
246
  end
237
247
 
@@ -263,7 +273,7 @@ class IPAddr
263
273
  # into an IPv4-mapped IPv6 address.
264
274
  def ipv4_mapped
265
275
  if !ipv4?
266
- raise ArgumentError, "not an IPv4 address"
276
+ raise InvalidAddressError, "not an IPv4 address"
267
277
  end
268
278
  return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
269
279
  end
@@ -272,7 +282,7 @@ class IPAddr
272
282
  # into an IPv4-compatible IPv6 address.
273
283
  def ipv4_compat
274
284
  if !ipv4?
275
- raise ArgumentError, "not an IPv4 address"
285
+ raise InvalidAddressError, "not an IPv4 address"
276
286
  end
277
287
  return self.clone.set(@addr, Socket::AF_INET6)
278
288
  end
@@ -296,14 +306,14 @@ class IPAddr
296
306
  when Socket::AF_INET6
297
307
  return ip6_arpa
298
308
  else
299
- raise "unsupported address family"
309
+ raise AddressFamilyError, "unsupported address family"
300
310
  end
301
311
  end
302
312
 
303
313
  # Returns a string for DNS reverse lookup compatible with RFC3172.
304
314
  def ip6_arpa
305
315
  if !ipv6?
306
- raise ArgumentError, "not an IPv6 address"
316
+ raise InvalidAddressError, "not an IPv6 address"
307
317
  end
308
318
  return _reverse + ".ip6.arpa"
309
319
  end
@@ -311,7 +321,7 @@ class IPAddr
311
321
  # Returns a string for DNS reverse lookup compatible with RFC1886.
312
322
  def ip6_int
313
323
  if !ipv6?
314
- raise ArgumentError, "not an IPv6 address"
324
+ raise InvalidAddressError, "not an IPv6 address"
315
325
  end
316
326
  return _reverse + ".ip6.int"
317
327
  end
@@ -331,6 +341,16 @@ class IPAddr
331
341
  end
332
342
  include Comparable
333
343
 
344
+ # Checks equality used by Hash.
345
+ def eql?(other)
346
+ return self.class == other.class && self.hash == other.hash && self == other
347
+ end
348
+
349
+ # Returns a hash value used by Hash, Set, and Array classes
350
+ def hash
351
+ return ([@addr, @mask_addr].hash << 1) | (ipv4? ? 0 : 1)
352
+ end
353
+
334
354
  # Creates a Range object for the network address.
335
355
  def to_range
336
356
  begin_addr = (@addr & @mask_addr)
@@ -341,7 +361,7 @@ class IPAddr
341
361
  when Socket::AF_INET6
342
362
  end_addr = (@addr | (IN6MASK ^ @mask_addr))
343
363
  else
344
- raise "unsupported address family"
364
+ raise AddressFamilyError, "unsupported address family"
345
365
  end
346
366
 
347
367
  return clone.set(begin_addr, @family)..clone.set(end_addr, @family)
@@ -356,26 +376,29 @@ class IPAddr
356
376
  when Socket::AF_INET6
357
377
  af = "IPv6"
358
378
  else
359
- raise "unsupported address family"
379
+ raise AddressFamilyError, "unsupported address family"
360
380
  end
361
381
  return sprintf("#<%s: %s:%s/%s>", self.class.name,
362
- af, _to_string(@addr), _to_string(@mask_addr))
382
+ af, _to_string(@addr), _to_string(@mask_addr))
363
383
  end
364
384
 
365
385
  protected
366
386
 
387
+ # Set +@addr+, the internal stored ip address, to given +addr+. The
388
+ # parameter +addr+ is validated using the first +family+ member,
389
+ # which is +Socket::AF_INET+ or +Socket::AF_INET6+.
367
390
  def set(addr, *family)
368
391
  case family[0] ? family[0] : @family
369
392
  when Socket::AF_INET
370
393
  if addr < 0 || addr > IN4MASK
371
- raise ArgumentError, "invalid address"
394
+ raise InvalidAddressError, "invalid address"
372
395
  end
373
396
  when Socket::AF_INET6
374
397
  if addr < 0 || addr > IN6MASK
375
- raise ArgumentError, "invalid address"
398
+ raise InvalidAddressError, "invalid address"
376
399
  end
377
400
  else
378
- raise ArgumentError, "unsupported address family"
401
+ raise AddressFamilyError, "unsupported address family"
379
402
  end
380
403
  @addr = addr
381
404
  if family[0]
@@ -384,18 +407,19 @@ class IPAddr
384
407
  return self
385
408
  end
386
409
 
410
+ # Set current netmask to given mask.
387
411
  def mask!(mask)
388
412
  if mask.kind_of?(String)
389
413
  if mask =~ /^\d+$/
390
- prefixlen = mask.to_i
414
+ prefixlen = mask.to_i
391
415
  else
392
- m = IPAddr.new(mask)
393
- if m.family != @family
394
- raise ArgumentError, "address family is not same"
395
- end
396
- @mask_addr = m.to_i
397
- @addr &= @mask_addr
398
- return self
416
+ m = IPAddr.new(mask)
417
+ if m.family != @family
418
+ raise InvalidPrefixError, "address family is not same"
419
+ end
420
+ @mask_addr = m.to_i
421
+ @addr &= @mask_addr
422
+ return self
399
423
  end
400
424
  else
401
425
  prefixlen = mask
@@ -403,18 +427,18 @@ class IPAddr
403
427
  case @family
404
428
  when Socket::AF_INET
405
429
  if prefixlen < 0 || prefixlen > 32
406
- raise ArgumentError, "invalid length"
430
+ raise InvalidPrefixError, "invalid length"
407
431
  end
408
432
  masklen = 32 - prefixlen
409
433
  @mask_addr = ((IN4MASK >> masklen) << masklen)
410
434
  when Socket::AF_INET6
411
435
  if prefixlen < 0 || prefixlen > 128
412
- raise ArgumentError, "invalid length"
436
+ raise InvalidPrefixError, "invalid length"
413
437
  end
414
438
  masklen = 128 - prefixlen
415
439
  @mask_addr = ((IN6MASK >> masklen) << masklen)
416
440
  else
417
- raise "unsupported address family"
441
+ raise AddressFamilyError, "unsupported address family"
418
442
  end
419
443
  @addr = ((@addr >> masklen) << masklen)
420
444
  return self
@@ -425,7 +449,7 @@ class IPAddr
425
449
  # Creates a new ipaddr object either from a human readable IP
426
450
  # address representation in string, or from a packed in_addr value
427
451
  # followed by an address family.
428
- #
452
+ #
429
453
  # In the former case, the following are the valid formats that will
430
454
  # be recognized: "address", "address/prefixlen" and "address/mask",
431
455
  # where IPv6 address may be enclosed in square brackets (`[' and
@@ -433,8 +457,8 @@ class IPAddr
433
457
  # IP address. Although the address family is determined
434
458
  # automatically from a specified string, you can specify one
435
459
  # explicitly by the optional second argument.
436
- #
437
- # Otherwise an IP addess is generated from a packed in_addr value
460
+ #
461
+ # Otherwise an IP address is generated from a packed in_addr value
438
462
  # and an address family.
439
463
  #
440
464
  # The IPAddr class defines many methods and operators, and some of
@@ -448,9 +472,9 @@ class IPAddr
448
472
  @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
449
473
  return
450
474
  when Socket::AF_UNSPEC
451
- raise ArgumentError, "address family must be specified"
475
+ raise AddressFamilyError, "address family must be specified"
452
476
  else
453
- raise ArgumentError, "unsupported address family: #{family}"
477
+ raise AddressFamilyError, "unsupported address family: #{family}"
454
478
  end
455
479
  end
456
480
  prefix, prefixlen = addr.split('/')
@@ -460,17 +484,12 @@ class IPAddr
460
484
  end
461
485
  # It seems AI_NUMERICHOST doesn't do the job.
462
486
  #Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
463
- # Socket::AI_NUMERICHOST)
464
- begin
465
- IPSocket.getaddress(prefix) # test if address is vaild
466
- rescue
467
- raise ArgumentError, "invalid address"
468
- end
487
+ # Socket::AI_NUMERICHOST)
469
488
  @addr = @family = nil
470
489
  if family == Socket::AF_UNSPEC || family == Socket::AF_INET
471
490
  @addr = in_addr(prefix)
472
491
  if @addr
473
- @family = Socket::AF_INET
492
+ @family = Socket::AF_INET
474
493
  end
475
494
  end
476
495
  if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6)
@@ -478,7 +497,7 @@ class IPAddr
478
497
  @family = Socket::AF_INET6
479
498
  end
480
499
  if family != Socket::AF_UNSPEC && @family != family
481
- raise ArgumentError, "address family mismatch"
500
+ raise AddressFamilyError, "address family mismatch"
482
501
  end
483
502
  if prefixlen
484
503
  mask!(prefixlen)
@@ -499,26 +518,45 @@ class IPAddr
499
518
  end
500
519
 
501
520
  def in_addr(addr)
502
- if addr =~ /^\d+\.\d+\.\d+\.\d+$/
503
- return addr.split('.').inject(0) { |i, s|
504
- i << 8 | s.to_i
505
- }
521
+ case addr
522
+ when Array
523
+ octets = addr
524
+ else
525
+ m = RE_IPV4ADDRLIKE.match(addr) or return nil
526
+ octets = m.captures
506
527
  end
507
- return nil
528
+ octets.inject(0) { |i, s|
529
+ (n = s.to_i) < 256 or raise InvalidAddressError, "invalid address"
530
+ s.match(/\A0./) and raise InvalidAddressError, "zero-filled number in IPv4 address is ambiguous"
531
+ i << 8 | n
532
+ }
508
533
  end
509
534
 
510
535
  def in6_addr(left)
511
536
  case left
512
- when /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i
513
- return in_addr($1) + 0xffff00000000
514
- when /^::(\d+\.\d+\.\d+\.\d+)$/i
515
- return in_addr($1)
516
- when /[^0-9a-f:]/i
517
- raise ArgumentError, "invalid address"
518
- when /^(.*)::(.*)$/
519
- left, right = $1, $2
520
- else
537
+ when RE_IPV6ADDRLIKE_FULL
538
+ if $2
539
+ addr = in_addr($~[2,4])
540
+ left = $1 + ':'
541
+ else
542
+ addr = 0
543
+ end
521
544
  right = ''
545
+ when RE_IPV6ADDRLIKE_COMPRESSED
546
+ if $4
547
+ left.count(':') <= 6 or raise InvalidAddressError, "invalid address"
548
+ addr = in_addr($~[4,4])
549
+ left = $1
550
+ right = $3 + '0:0'
551
+ else
552
+ left.count(':') <= ($1.empty? || $2.empty? ? 8 : 7) or
553
+ raise InvalidAddressError, "invalid address"
554
+ left = $1
555
+ right = $2
556
+ addr = 0
557
+ end
558
+ else
559
+ raise InvalidAddressError, "invalid address"
522
560
  end
523
561
  l = left.split(':')
524
562
  r = right.split(':')
@@ -526,9 +564,9 @@ class IPAddr
526
564
  if rest < 0
527
565
  return nil
528
566
  end
529
- return (l + Array.new(rest, '0') + r).inject(0) { |i, s|
567
+ (l + Array.new(rest, '0') + r).inject(0) { |i, s|
530
568
  i << 16 | s.hex
531
- }
569
+ } | addr
532
570
  end
533
571
 
534
572
  def addr_mask(addr)
@@ -538,7 +576,7 @@ class IPAddr
538
576
  when Socket::AF_INET6
539
577
  return addr & IN6MASK
540
578
  else
541
- raise "unsupported address family"
579
+ raise AddressFamilyError, "unsupported address family"
542
580
  end
543
581
  end
544
582
 
@@ -546,12 +584,12 @@ class IPAddr
546
584
  case @family
547
585
  when Socket::AF_INET
548
586
  return (0..3).map { |i|
549
- (@addr >> (8 * i)) & 0xff
587
+ (@addr >> (8 * i)) & 0xff
550
588
  }.join('.')
551
589
  when Socket::AF_INET6
552
590
  return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
553
591
  else
554
- raise "unsupported address family"
592
+ raise AddressFamilyError, "unsupported address family"
555
593
  end
556
594
  end
557
595
 
@@ -559,17 +597,66 @@ class IPAddr
559
597
  case @family
560
598
  when Socket::AF_INET
561
599
  return (0..3).map { |i|
562
- (addr >> (24 - 8 * i)) & 0xff
600
+ (addr >> (24 - 8 * i)) & 0xff
563
601
  }.join('.')
564
602
  when Socket::AF_INET6
565
603
  return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:'))
566
604
  else
567
- raise "unsupported address family"
605
+ raise AddressFamilyError, "unsupported address family"
568
606
  end
569
607
  end
570
608
 
571
609
  end
572
610
 
611
+ unless Socket.const_defined? :AF_INET6
612
+ class Socket < BasicSocket
613
+ # IPv6 protocol family
614
+ AF_INET6 = Object.new
615
+ end
616
+
617
+ class << IPSocket
618
+ private
619
+
620
+ def valid_v6?(addr)
621
+ case addr
622
+ when IPAddr::RE_IPV6ADDRLIKE_FULL
623
+ if $2
624
+ $~[2,4].all? {|i| i.to_i < 256 }
625
+ else
626
+ true
627
+ end
628
+ when IPAddr::RE_IPV6ADDRLIKE_COMPRESSED
629
+ if $4
630
+ addr.count(':') <= 6 && $~[4,4].all? {|i| i.to_i < 256}
631
+ else
632
+ addr.count(':') <= 7
633
+ end
634
+ else
635
+ false
636
+ end
637
+ end
638
+
639
+ alias getaddress_orig getaddress
640
+
641
+ public
642
+
643
+ # Returns a +String+ based representation of a valid DNS hostname,
644
+ # IPv4 or IPv6 address.
645
+ #
646
+ # IPSocket.getaddress 'localhost' #=> "::1"
647
+ # IPSocket.getaddress 'broadcasthost' #=> "255.255.255.255"
648
+ # IPSocket.getaddress 'www.ruby-lang.org' #=> "221.186.184.68"
649
+ # IPSocket.getaddress 'www.ccc.de' #=> "2a00:1328:e102:ccc0::122"
650
+ def getaddress(s)
651
+ if valid_v6?(s)
652
+ s
653
+ else
654
+ getaddress_orig(s)
655
+ end
656
+ end
657
+ end
658
+ end
659
+
573
660
  if $0 == __FILE__
574
661
  eval DATA.read, nil, $0, __LINE__+4
575
662
  end
@@ -577,14 +664,20 @@ end
577
664
  __END__
578
665
 
579
666
  require 'test/unit'
580
- require 'test/unit/ui/console/testrunner'
581
667
 
582
668
  class TC_IPAddr < Test::Unit::TestCase
583
669
  def test_s_new
584
- assert_nothing_raised {
585
- IPAddr.new("3FFE:505:ffff::/48")
586
- IPAddr.new("0:0:0:1::")
587
- IPAddr.new("2001:200:300::/48")
670
+ [
671
+ ["3FFE:505:ffff::/48"],
672
+ ["0:0:0:1::"],
673
+ ["2001:200:300::/48"],
674
+ ["2001:200:300::192.168.1.2/48"],
675
+ ["1:2:3:4:5:6:7::"],
676
+ ["::2:3:4:5:6:7:8"],
677
+ ].each { |args|
678
+ assert_nothing_raised {
679
+ IPAddr.new(*args)
680
+ }
588
681
  }
589
682
 
590
683
  a = IPAddr.new
@@ -637,19 +730,18 @@ class TC_IPAddr < Test::Unit::TestCase
637
730
  assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s)
638
731
 
639
732
  assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s)
733
+ assert_equal("1:2:3:4:5:6:7:0", IPAddr.new("1:2:3:4:5:6:7::").to_s)
734
+ assert_equal("0:2:3:4:5:6:7:8", IPAddr.new("::2:3:4:5:6:7:8").to_s)
640
735
 
641
- [
642
- ["fe80::1%fxp0"],
643
- ["::1/255.255.255.0"],
644
- ["::1:192.168.1.2/120"],
645
- [IPAddr.new("::1").to_i],
646
- ["::ffff:192.168.1.2/120", Socket::AF_INET],
647
- ["[192.168.1.2]/120"],
648
- ].each { |args|
649
- assert_raises(ArgumentError) {
650
- IPAddr.new(*args)
651
- }
652
- }
736
+ assert_raises(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.256") }
737
+ assert_raises(IPAddr::InvalidAddressError) { IPAddr.new("192.168.0.011") }
738
+ assert_raises(IPAddr::InvalidAddressError) { IPAddr.new("fe80::1%fxp0") }
739
+ assert_raises(IPAddr::InvalidAddressError) { IPAddr.new("[192.168.1.2]/120") }
740
+ assert_raises(IPAddr::InvalidPrefixError) { IPAddr.new("::1/255.255.255.0") }
741
+ assert_raises(IPAddr::InvalidPrefixError) { IPAddr.new("::1/129") }
742
+ assert_raises(IPAddr::InvalidPrefixError) { IPAddr.new("192.168.0.1/33") }
743
+ assert_raises(IPAddr::AddressFamilyError) { IPAddr.new(1) }
744
+ assert_raises(IPAddr::AddressFamilyError) { IPAddr.new("::ffff:192.168.1.2/120", Socket::AF_INET) }
653
745
  end
654
746
 
655
747
  def test_s_new_ntoh
@@ -710,14 +802,14 @@ class TC_IPAddr < Test::Unit::TestCase
710
802
 
711
803
  def test_ip6_arpa
712
804
  assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa", IPAddr.new("3ffe:505:2::f").ip6_arpa)
713
- assert_raises(ArgumentError) {
805
+ assert_raises(IPAddr::InvalidAddressError) {
714
806
  IPAddr.new("192.168.2.1").ip6_arpa
715
807
  }
716
808
  end
717
809
 
718
810
  def test_ip6_int
719
811
  assert_equal("f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.int", IPAddr.new("3ffe:505:2::f").ip6_int)
720
- assert_raises(ArgumentError) {
812
+ assert_raises(IPAddr::InvalidAddressError) {
721
813
  IPAddr.new("192.168.2.1").ip6_int
722
814
  }
723
815
  end
@@ -748,7 +840,7 @@ class TC_Operator < Test::Unit::TestCase
748
840
  assert_equal("3ffe:505:2:1::", a.to_s)
749
841
  assert_equal("3ffe:505:2::", @a.to_s)
750
842
  assert_equal("3ffe:505:2:1::",
751
- (@a | 0x00000000000000010000000000000000).to_s)
843
+ (@a | 0x00000000000000010000000000000000).to_s)
752
844
  end
753
845
 
754
846
  def test_and
@@ -783,7 +875,9 @@ class TC_Operator < Test::Unit::TestCase
783
875
  end
784
876
 
785
877
  def test_equal
786
- assert_equal(true, @a == IPAddr.new("3ffe:505:2::"))
878
+ assert_equal(true, @a == IPAddr.new("3FFE:505:2::"))
879
+ assert_equal(true, @a == IPAddr.new("3ffe:0505:0002::"))
880
+ assert_equal(true, @a == IPAddr.new("3ffe:0505:0002:0:0:0:0:0"))
787
881
  assert_equal(false, @a == IPAddr.new("3ffe:505:3::"))
788
882
  assert_equal(true, @a != IPAddr.new("3ffe:505:3::"))
789
883
  assert_equal(false, @a != IPAddr.new("3ffe:505:2::"))
@@ -811,4 +905,31 @@ class TC_Operator < Test::Unit::TestCase
811
905
 
812
906
  end
813
907
 
908
+ def test_hash
909
+ a1 = IPAddr.new('192.168.2.0')
910
+ a2 = IPAddr.new('192.168.2.0')
911
+ a3 = IPAddr.new('3ffe:505:2::1')
912
+ a4 = IPAddr.new('3ffe:505:2::1')
913
+ a5 = IPAddr.new('127.0.0.1')
914
+ a6 = IPAddr.new('::1')
915
+ a7 = IPAddr.new('192.168.2.0/25')
916
+ a8 = IPAddr.new('192.168.2.0/25')
917
+
918
+ h = { a1 => 'ipv4', a2 => 'ipv4', a3 => 'ipv6', a4 => 'ipv6', a5 => 'ipv4', a6 => 'ipv6', a7 => 'ipv4', a8 => 'ipv4'}
919
+ assert_equal(5, h.size)
920
+ assert_equal('ipv4', h[a1])
921
+ assert_equal('ipv4', h[a2])
922
+ assert_equal('ipv6', h[a3])
923
+ assert_equal('ipv6', h[a4])
924
+
925
+ require 'set'
926
+ s = Set[a1, a2, a3, a4, a5, a6, a7, a8]
927
+ assert_equal(5, s.size)
928
+ assert_equal(true, s.include?(a1))
929
+ assert_equal(true, s.include?(a2))
930
+ assert_equal(true, s.include?(a3))
931
+ assert_equal(true, s.include?(a4))
932
+ assert_equal(true, s.include?(a5))
933
+ assert_equal(true, s.include?(a6))
934
+ end
814
935
  end
@@ -1,5 +1,5 @@
1
1
  module RubySL
2
- module IPAddr
3
- VERSION = "1.0.0"
2
+ module Ipaddr
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -3,7 +3,7 @@ require './lib/rubysl/ipaddr/version'
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = "rubysl-ipaddr"
6
- spec.version = RubySL::IPAddr::VERSION
6
+ spec.version = RubySL::Ipaddr::VERSION
7
7
  spec.authors = ["Brian Shirai"]
8
8
  spec.email = ["brixen@gmail.com"]
9
9
  spec.description = %q{Ruby standard library ipaddr.}
@@ -19,5 +19,4 @@ Gem::Specification.new do |spec|
19
19
  spec.add_development_dependency "bundler", "~> 1.3"
20
20
  spec.add_development_dependency "rake", "~> 10.0"
21
21
  spec.add_development_dependency "mspec", "~> 1.5"
22
- spec.add_development_dependency "rubysl-prettyprint", "~> 1.0"
23
- end
22
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubysl-ipaddr
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Shirai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-27 00:00:00.000000000 Z
11
+ date: 2013-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.5'
55
- - !ruby/object:Gem::Dependency
56
- name: rubysl-prettyprint
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ~>
60
- - !ruby/object:Gem::Version
61
- version: '1.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ~>
67
- - !ruby/object:Gem::Version
68
- version: '1.0'
69
55
  description: Ruby standard library ipaddr.
70
56
  email:
71
57
  - brixen@gmail.com