Imported File#ftype spec from rubyspecs.
[rbx.git] / lib / ipaddr.rb
blobcef8733b04e5c49a8fbcf0b4604a0e756247dfaa
2 # ipaddr.rb - A class to manipulate an IP address
4 # Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>.
5 # All rights reserved.
7 # You can redistribute and/or modify it under the same terms as Ruby.
9 # $Id: ipaddr.rb 11708 2007-02-12 23:01:19Z shyouhei $
11 # TODO:
12 #   - scope_id support
13 require 'socket'
15 unless Socket.const_defined? "AF_INET6"
16   class Socket
17     AF_INET6 = Object.new
18   end
20   class << IPSocket
21     def valid_v4?(addr)
22       if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
23         return $~.captures.all? {|i| i.to_i < 256}
24       end
25       return false
26     end
28     def valid_v6?(addr)
29       # IPv6 (normal)
30       return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ addr
31       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
32       return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ addr
33       # IPv6 (IPv4 compat)
34       return true if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ addr && valid_v4?($')
35       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?($')
36       return true if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ addr && valid_v4?($')
38       false
39     end
41     def valid?(addr)
42       valid_v4?(addr) || valid_v6?(addr)
43     end
45     alias getaddress_orig getaddress
46     def getaddress(s)
47       if valid?(s)
48         s
49       elsif /\A[-A-Za-z\d.]+\Z/ =~ s
50         getaddress_orig(s)
51       else
52         raise ArgumentError, "invalid address"
53       end
54     end
55   end
56 end
58 # IPAddr provides a set of methods to manipulate an IP address.  Both IPv4 and
59 # IPv6 are supported.
61 # == Example
63 #   require 'ipaddr'
64 #   
65 #   ipaddr1 = IPAddr.new "3ffe:505:2::1"
66 #   
67 #   p ipaddr1                   #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
68 #   
69 #   p ipaddr1.to_s              #=> "3ffe:505:2::1"
70 #   
71 #   ipaddr2 = ipaddr1.mask(48)  #=> #<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>
72 #   
73 #   p ipaddr2.to_s              #=> "3ffe:505:2::"
74 #   
75 #   ipaddr3 = IPAddr.new "192.168.2.0/24"
76 #   
77 #   p ipaddr3                   #=> #<IPAddr: IPv4:192.168.2.0/255.255.255.0>
79 class IPAddr
81   IN4MASK = 0xffffffff
82   IN6MASK = 0xffffffffffffffffffffffffffffffff
83   IN6FORMAT = (["%.4x"] * 8).join(':')
85   # Returns the address family of this IP address.
86   attr :family
88   # Creates a new ipaddr containing the given network byte ordered
89   # string form of an IP address.
90   def IPAddr::new_ntoh(addr)
91     return IPAddr.new(IPAddr::ntop(addr))
92   end
94   # Convert a network byte ordered string form of an IP address into
95   # human readable form.
96   def IPAddr::ntop(addr)
97     case addr.size
98     when 4
99       s = addr.unpack('C4').join('.')
100     when 16
101       s = IN6FORMAT % addr.unpack('n8')
102     else
103       raise ArgumentError, "unsupported address family"
104     end
105     return s
106   end
108   # Returns a new ipaddr built by bitwise AND.
109   def &(other)
110     return self.clone.set(@addr & other.to_i)
111   end
113   # Returns a new ipaddr built by bitwise OR.
114   def |(other)
115     return self.clone.set(@addr | other.to_i)
116   end
118   # Returns a new ipaddr built by bitwise right-shift.
119   def >>(num)
120     return self.clone.set(@addr >> num)
121   end
123   # Returns a new ipaddr built by bitwise left shift.
124   def <<(num)
125     return self.clone.set(addr_mask(@addr << num))
126   end
128   # Returns a new ipaddr built by bitwise negation.
129   def ~
130     return self.clone.set(addr_mask(~@addr))
131   end
133   # Returns true if two ipaddr are equal.
134   def ==(other)
135     if other.kind_of?(IPAddr) && @family != other.family
136       return false
137     end
138     return (@addr == other.to_i)
139   end
141   # Returns a new ipaddr built by masking IP address with the given
142   # prefixlen/netmask. (e.g. 8, 64, "255.255.255.0", etc.)
143   def mask(prefixlen)
144     return self.clone.mask!(prefixlen)
145   end
147   # Returns true if the given ipaddr is in the range.
148   #
149   # e.g.:
150   #   require 'ipaddr'
151   #   net1 = IPAddr.new("192.168.2.0/24")
152   #   p net1.include?(IPAddr.new("192.168.2.0"))        #=> true
153   #   p net1.include?(IPAddr.new("192.168.2.255"))      #=> true
154   #   p net1.include?(IPAddr.new("192.168.3.0"))        #=> false
155   def include?(other)
156     if ipv4_mapped?
157       if (@mask_addr >> 32) != 0xffffffffffffffffffffffff
158         return false
159       end
160       mask_addr = (@mask_addr & IN4MASK)
161       addr = (@addr & IN4MASK)
162       family = Socket::AF_INET
163     else
164       mask_addr = @mask_addr
165       addr = @addr
166       family = @family
167     end
168     if other.kind_of?(IPAddr)
169       if other.ipv4_mapped?
170         other_addr = (other.to_i & IN4MASK)
171         other_family = Socket::AF_INET
172       else
173         other_addr = other.to_i
174         other_family = other.family
175       end
176     else # Not IPAddr - assume integer in same family as us
177       other_addr   = other.to_i
178       other_family = family
179     end
181     if family != other_family
182       return false
183     end
184     return ((addr & mask_addr) == (other_addr & mask_addr))
185   end
186   alias === include?
188   # Returns the integer representation of the ipaddr.
189   def to_i
190     return @addr
191   end
193   # Returns a string containing the IP address representation.
194   def to_s
195     str = to_string
196     return str if ipv4?
198     str.gsub!(/\b0{1,3}([\da-f]+)\b/i, '\1')
199     loop do
200       break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
201       break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
202       break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
203       break if str.sub!(/\b0:0:0:0:0\b/, ':')
204       break if str.sub!(/\b0:0:0:0\b/, ':')
205       break if str.sub!(/\b0:0:0\b/, ':')
206       break if str.sub!(/\b0:0\b/, ':')
207       break
208     end
209     str.sub!(/:{3,}/, '::')
211     if /\A::(ffff:)?([\da-f]{1,4}):([\da-f]{1,4})\Z/i =~ str
212       str = sprintf('::%s%d.%d.%d.%d', $1, $2.hex / 256, $2.hex % 256, $3.hex / 256, $3.hex % 256)
213     end
215     str
216   end
218   # Returns a string containing the IP address representation in
219   # canonical form.
220   def to_string
221     return _to_string(@addr)
222   end
224   # Returns a network byte ordered string form of the IP address.
225   def hton
226     case @family
227     when Socket::AF_INET
228       return [@addr].pack('N')
229     when Socket::AF_INET6
230       return (0..7).map { |i|
231         (@addr >> (112 - 16 * i)) & 0xffff
232       }.pack('n8')
233     else
234       raise "unsupported address family"
235     end
236   end
238   # Returns true if the ipaddr is an IPv4 address.
239   def ipv4?
240     return @family == Socket::AF_INET
241   end
243   # Returns true if the ipaddr is an IPv6 address.
244   def ipv6?
245     return @family == Socket::AF_INET6
246   end
248   # Returns true if the ipaddr is an IPv4-mapped IPv6 address.
249   def ipv4_mapped?
250     return ipv6? && (@addr >> 32) == 0xffff
251   end
253   # Returns true if the ipaddr is an IPv4-compatible IPv6 address.
254   def ipv4_compat?
255     if !ipv6? || (@addr >> 32) != 0
256       return false
257     end
258     a = (@addr & IN4MASK)
259     return a != 0 && a != 1
260   end
262   # Returns a new ipaddr built by converting the native IPv4 address
263   # into an IPv4-mapped IPv6 address.
264   def ipv4_mapped
265     if !ipv4?
266       raise ArgumentError, "not an IPv4 address"
267     end
268     return self.clone.set(@addr | 0xffff00000000, Socket::AF_INET6)
269   end
271   # Returns a new ipaddr built by converting the native IPv4 address
272   # into an IPv4-compatible IPv6 address.
273   def ipv4_compat
274     if !ipv4?
275       raise ArgumentError, "not an IPv4 address"
276     end
277     return self.clone.set(@addr, Socket::AF_INET6)
278   end
280   # Returns a new ipaddr built by converting the IPv6 address into a
281   # native IPv4 address.  If the IP address is not an IPv4-mapped or
282   # IPv4-compatible IPv6 address, returns self.
283   def native
284     if !ipv4_mapped? && !ipv4_compat?
285       return self
286     end
287     return self.clone.set(@addr & IN4MASK, Socket::AF_INET)
288   end
290   # Returns a string for DNS reverse lookup.  It returns a string in
291   # RFC3172 form for an IPv6 address.
292   def reverse
293     case @family
294     when Socket::AF_INET
295       return _reverse + ".in-addr.arpa"
296     when Socket::AF_INET6
297       return ip6_arpa
298     else
299       raise "unsupported address family"
300     end
301   end
303   # Returns a string for DNS reverse lookup compatible with RFC3172.
304   def ip6_arpa
305     if !ipv6?
306       raise ArgumentError, "not an IPv6 address"
307     end
308     return _reverse + ".ip6.arpa"
309   end
311   # Returns a string for DNS reverse lookup compatible with RFC1886.
312   def ip6_int
313     if !ipv6?
314       raise ArgumentError, "not an IPv6 address"
315     end
316     return _reverse + ".ip6.int"
317   end
319   # Returns a string containing a human-readable representation of the
320   # ipaddr. ("#<IPAddr: family:address/mask>")
321   def inspect
322     case @family
323     when Socket::AF_INET
324       af = "IPv4"
325     when Socket::AF_INET6
326       af = "IPv6"
327     else
328       raise "unsupported address family"
329     end
330     return sprintf("#<%s: %s:%s/%s>", self.class.name,
331                    af, _to_string(@addr), _to_string(@mask_addr))
332   end
334   protected
336   def set(addr, *family)
337     case family[0] ? family[0] : @family
338     when Socket::AF_INET
339       if addr < 0 || addr > IN4MASK
340         raise ArgumentError, "invalid address"
341       end
342     when Socket::AF_INET6
343       if addr < 0 || addr > IN6MASK
344         raise ArgumentError, "invalid address"
345       end
346     else
347       raise ArgumentError, "unsupported address family"
348     end
349     @addr = addr
350     if family[0]
351       @family = family[0]
352     end
353     return self
354   end
356   def mask!(mask)
357     if mask.kind_of?(String)
358       if mask =~ /^\d+$/
359         prefixlen = mask.to_i
360       else
361         m = IPAddr.new(mask)
362         if m.family != @family
363           raise ArgumentError, "address family is not same"
364         end
365         @mask_addr = m.to_i
366         @addr &= @mask_addr
367         return self
368       end
369     else
370       prefixlen = mask
371     end
372     case @family
373     when Socket::AF_INET
374       if prefixlen < 0 || prefixlen > 32
375         raise ArgumentError, "invalid length"
376       end
377       masklen = 32 - prefixlen
378       @mask_addr = ((IN4MASK >> masklen) << masklen)
379     when Socket::AF_INET6
380       if prefixlen < 0 || prefixlen > 128
381         raise ArgumentError, "invalid length"
382       end
383       masklen = 128 - prefixlen
384       @mask_addr = ((IN6MASK >> masklen) << masklen)
385     else
386       raise "unsupported address family"
387     end
388     @addr = ((@addr >> masklen) << masklen)
389     return self
390   end
392   private
394   # Creates a new ipaddr containing the given human readable form of
395   # an IP address.  It also accepts `address/prefixlen' and
396   # `address/mask'.  When prefixlen or mask is specified, it returns a
397   # masked ipaddr.  IPv6 address may beenclosed with `[' and `]'.
398   #
399   # Although an address family is determined automatically from a
400   # specified address, you can specify an address family explicitly by
401   # the optional second argument.
402   def initialize(addr = '::', family = Socket::AF_UNSPEC)
403     if !addr.kind_of?(String)
404       if family != Socket::AF_INET6 && family != Socket::AF_INET
405         raise ArgumentError, "unsupported address family"
406       end
407       set(addr, family)
408       @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
409       return
410     end
411     prefix, prefixlen = addr.split('/')
412     if prefix =~ /^\[(.*)\]$/i
413       prefix = $1
414       family = Socket::AF_INET6
415     end
416     # It seems AI_NUMERICHOST doesn't do the job.
417     #Socket.getaddrinfo(left, nil, Socket::AF_INET6, Socket::SOCK_STREAM, nil,
418     #                  Socket::AI_NUMERICHOST)
419     begin
420       IPSocket.getaddress(prefix)               # test if address is vaild
421     rescue
422       raise ArgumentError, "invalid address"
423     end
424     @addr = @family = nil
425     if family == Socket::AF_UNSPEC || family == Socket::AF_INET
426       @addr = in_addr(prefix)
427       if @addr
428         @family = Socket::AF_INET
429       end
430     end
431     if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6)
432       @addr = in6_addr(prefix)
433       @family = Socket::AF_INET6
434     end
435     if family != Socket::AF_UNSPEC && @family != family
436       raise ArgumentError, "address family unmatch"
437     end
438     if prefixlen
439       mask!(prefixlen)
440     else
441       @mask_addr = (family == Socket::AF_INET) ? IN4MASK : IN6MASK
442     end
443   end
445   def in_addr(addr)
446     if addr =~ /^\d+\.\d+\.\d+\.\d+$/
447       n = 0
448       addr.split('.').each { |i|
449         n <<= 8
450         n += i.to_i
451       }
452       return n
453     end
454     return nil
455   end
457   def in6_addr(left)
458     case left
459     when /^::ffff:(\d+\.\d+\.\d+\.\d+)$/i
460       return in_addr($1) + 0xffff00000000
461     when /^::(\d+\.\d+\.\d+\.\d+)$/i
462       return in_addr($1)
463     when /[^0-9a-f:]/i
464       raise ArgumentError, "invalid address"
465     when /^(.*)::(.*)$/
466       left, right = $1, $2
467     else
468       right = ''
469     end
470     l = left.split(':')
471     r = right.split(':')
472     rest = 8 - l.size - r.size
473     if rest < 0
474       return nil
475     end
476     a = [l, Array.new(rest, '0'), r].flatten!
477     n = 0
478     a.each { |i|
479       n <<= 16
480       n += i.hex
481     }
482     return n
483   end
485   def addr_mask(addr)
486     case @family
487     when Socket::AF_INET
488       addr &= IN4MASK
489     when Socket::AF_INET6
490       addr &= IN6MASK
491     else
492       raise "unsupported address family"
493     end
494     return addr
495   end
497   def _reverse
498     case @family
499     when Socket::AF_INET
500       return (0..3).map { |i|
501         (@addr >> (8 * i)) & 0xff
502       }.join('.')
503     when Socket::AF_INET6
504       return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
505     else
506       raise "unsupported address family"
507     end
508   end
510   def _to_string(addr)
511     case @family
512     when Socket::AF_INET
513       return (0..3).map { |i|
514         (addr >> (24 - 8 * i)) & 0xff
515       }.join('.')
516     when Socket::AF_INET6
517       return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:'))
518     else
519       raise "unsupported address family"
520     end
521   end
525 if $0 == __FILE__
526   eval DATA.read, nil, $0, __LINE__+4
529 __END__
531 require 'test/unit'
532 require 'test/unit/ui/console/testrunner'
534 class TC_IPAddr < Test::Unit::TestCase
535   def test_s_new
536     assert_nothing_raised {
537       IPAddr.new("3FFE:505:ffff::/48")
538       IPAddr.new("0:0:0:1::")
539       IPAddr.new("2001:200:300::/48")
540     }
542     a = IPAddr.new
543     assert_equal("::", a.to_s)
544     assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string)
545     assert_equal(Socket::AF_INET6, a.family)
547     a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678")
548     assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s)
549     assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string)
550     assert_equal(Socket::AF_INET6, a.family)
552     a = IPAddr.new("3ffe:505:2::/48")
553     assert_equal("3ffe:505:2::", a.to_s)
554     assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
555     assert_equal(Socket::AF_INET6, a.family)
556     assert_equal(false, a.ipv4?)
557     assert_equal(true, a.ipv6?)
558     assert_equal("#<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>", a.inspect)
560     a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::")
561     assert_equal("3ffe:505:2::", a.to_s)
562     assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
563     assert_equal(Socket::AF_INET6, a.family)
565     a = IPAddr.new("0.0.0.0")
566     assert_equal("0.0.0.0", a.to_s)
567     assert_equal("0.0.0.0", a.to_string)
568     assert_equal(Socket::AF_INET, a.family)
570     a = IPAddr.new("192.168.1.2")
571     assert_equal("192.168.1.2", a.to_s)
572     assert_equal("192.168.1.2", a.to_string)
573     assert_equal(Socket::AF_INET, a.family)
574     assert_equal(true, a.ipv4?)
575     assert_equal(false, a.ipv6?)
577     a = IPAddr.new("192.168.1.2/24")
578     assert_equal("192.168.1.0", a.to_s)
579     assert_equal("192.168.1.0", a.to_string)
580     assert_equal(Socket::AF_INET, a.family)
581     assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.0>", a.inspect)
583     a = IPAddr.new("192.168.1.2/255.255.255.0")
584     assert_equal("192.168.1.0", a.to_s)
585     assert_equal("192.168.1.0", a.to_string)
586     assert_equal(Socket::AF_INET, a.family)
588     assert_equal("0:0:0:1::", IPAddr.new("0:0:0:1::").to_s)
589     assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s)
591     assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s)
593     [
594       ["fe80::1%fxp0"],
595       ["::1/255.255.255.0"],
596       ["::1:192.168.1.2/120"],
597       [IPAddr.new("::1").to_i],
598       ["::ffff:192.168.1.2/120", Socket::AF_INET],
599       ["[192.168.1.2]/120"],
600     ].each { |args|
601       assert_raises(ArgumentError) {
602         IPAddr.new(*args)
603       }
604     }
605   end
607   def test_s_new_ntoh
608     addr = ''
609     IPAddr.new("1234:5678:9abc:def0:1234:5678:9abc:def0").hton.each_byte { |c|
610       addr += sprintf("%02x", c)
611     }
612     assert_equal("123456789abcdef0123456789abcdef0", addr)
613     addr = ''
614     IPAddr.new("123.45.67.89").hton.each_byte { |c|
615       addr += sprintf("%02x", c)
616     }
617     assert_equal(sprintf("%02x%02x%02x%02x", 123, 45, 67, 89), addr)
618     a = IPAddr.new("3ffe:505:2::")
619     assert_equal("3ffe:505:2::", IPAddr.new_ntoh(a.hton).to_s)
620     a = IPAddr.new("192.168.2.1")
621     assert_equal("192.168.2.1", IPAddr.new_ntoh(a.hton).to_s)
622   end
624   def test_ipv4_compat
625     a = IPAddr.new("::192.168.1.2")
626     assert_equal("::192.168.1.2", a.to_s)
627     assert_equal("0000:0000:0000:0000:0000:0000:c0a8:0102", a.to_string)
628     assert_equal(Socket::AF_INET6, a.family)
629     assert_equal(true, a.ipv4_compat?)
630     b = a.native
631     assert_equal("192.168.1.2", b.to_s)
632     assert_equal(Socket::AF_INET, b.family)
633     assert_equal(false, b.ipv4_compat?)
635     a = IPAddr.new("192.168.1.2")
636     b = a.ipv4_compat
637     assert_equal("::192.168.1.2", b.to_s)
638     assert_equal(Socket::AF_INET6, b.family)
639   end
641   def test_ipv4_mapped
642     a = IPAddr.new("::ffff:192.168.1.2")
643     assert_equal("::ffff:192.168.1.2", a.to_s)
644     assert_equal("0000:0000:0000:0000:0000:ffff:c0a8:0102", a.to_string)
645     assert_equal(Socket::AF_INET6, a.family)
646     assert_equal(true, a.ipv4_mapped?)
647     b = a.native
648     assert_equal("192.168.1.2", b.to_s)
649     assert_equal(Socket::AF_INET, b.family)
650     assert_equal(false, b.ipv4_mapped?)
652     a = IPAddr.new("192.168.1.2")
653     b = a.ipv4_mapped
654     assert_equal("::ffff:192.168.1.2", b.to_s)
655     assert_equal(Socket::AF_INET6, b.family)
656   end
658   def test_reverse
659     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").reverse)
660     assert_equal("1.2.168.192.in-addr.arpa", IPAddr.new("192.168.2.1").reverse)
661   end
663   def test_ip6_arpa
664     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)
665     assert_raises(ArgumentError) {
666       IPAddr.new("192.168.2.1").ip6_arpa
667     }
668   end
670   def test_ip6_int
671     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)
672     assert_raises(ArgumentError) {
673       IPAddr.new("192.168.2.1").ip6_int
674     }
675   end
677   def test_to_s
678     assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0001", IPAddr.new("3ffe:505:2::1").to_string)
679     assert_equal("3ffe:505:2::1", IPAddr.new("3ffe:505:2::1").to_s)
680   end
683 class TC_Operator < Test::Unit::TestCase
685   IN6MASK32  = "ffff:ffff::"
686   IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
688   def setup
689     @in6_addr_any = IPAddr.new()
690     @a = IPAddr.new("3ffe:505:2::/48")
691     @b = IPAddr.new("0:0:0:1::")
692     @c = IPAddr.new(IN6MASK32)
693   end
694   alias set_up setup
696   def test_or
697     assert_equal("3ffe:505:2:1::", (@a | @b).to_s)
698     a = @a
699     a |= @b
700     assert_equal("3ffe:505:2:1::", a.to_s)
701     assert_equal("3ffe:505:2::", @a.to_s)
702     assert_equal("3ffe:505:2:1::",
703                  (@a | 0x00000000000000010000000000000000).to_s)
704   end
706   def test_and
707     assert_equal("3ffe:505::", (@a & @c).to_s)
708     a = @a
709     a &= @c
710     assert_equal("3ffe:505::", a.to_s)
711     assert_equal("3ffe:505:2::", @a.to_s)
712     assert_equal("3ffe:505::", (@a & 0xffffffff000000000000000000000000).to_s)
713   end
715   def test_shift_right
716     assert_equal("0:3ffe:505:2::", (@a >> 16).to_s)
717     a = @a
718     a >>= 16
719     assert_equal("0:3ffe:505:2::", a.to_s)
720     assert_equal("3ffe:505:2::", @a.to_s)
721   end
723   def test_shift_left
724     assert_equal("505:2::", (@a << 16).to_s)
725     a = @a
726     a <<= 16
727     assert_equal("505:2::", a.to_s)
728     assert_equal("3ffe:505:2::", @a.to_s)
729   end
731   def test_carrot
732     a = ~@in6_addr_any
733     assert_equal(IN6MASK128, a.to_s)
734     assert_equal("::", @in6_addr_any.to_s)
735   end
737   def test_equal
738     assert_equal(true, @a == IPAddr.new("3ffe:505:2::"))
739     assert_equal(false, @a == IPAddr.new("3ffe:505:3::"))
740     assert_equal(true, @a != IPAddr.new("3ffe:505:3::"))
741     assert_equal(false, @a != IPAddr.new("3ffe:505:2::"))
742   end
744   def test_mask
745     a = @a.mask(32)
746     assert_equal("3ffe:505::", a.to_s)
747     assert_equal("3ffe:505:2::", @a.to_s)
748   end
750   def test_include?
751     assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::")))
752     assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::1")))
753     assert_equal(false, @a.include?(IPAddr.new("3ffe:505:3::")))
754     net1 = IPAddr.new("192.168.2.0/24")
755     assert_equal(true, net1.include?(IPAddr.new("192.168.2.0")))
756     assert_equal(true, net1.include?(IPAddr.new("192.168.2.255")))
757     assert_equal(false, net1.include?(IPAddr.new("192.168.3.0")))
758     # test with integer parameter
759     int = (192 << 24) + (168 << 16) + (2 << 8) + 13
761     assert_equal(true, net1.include?(int))
762     assert_equal(false, net1.include?(int+255))
764   end