rubysl-ipaddr 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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