~ubuntu-branches/ubuntu/hardy/ruby1.8/hardy-updates

« back to all changes in this revision

Viewing changes to lib/ipaddr.rb

  • Committer: Bazaar Package Importer
  • Author(s): akira yamada
  • Date: 2007-03-13 22:11:58 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070313221158-h3oql37brlaf2go2
Tags: 1.8.6-1
* new upstream version, 1.8.6.
* libruby1.8 conflicts with libopenssl-ruby1.8 (< 1.8.6) (closes: #410018)
* changed packaging style to cdbs from dbs.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# ipaddr.rb - A class to manipulate an IP address
 
3
#
 
4
# Copyright (c) 2002 Hajimu UMEMOTO <ume@mahoroba.org>.
 
5
# All rights reserved.
 
6
#
 
7
# You can redistribute and/or modify it under the same terms as Ruby.
 
8
#
 
9
# $Id: ipaddr.rb 11708 2007-02-12 23:01:19Z shyouhei $
 
10
#
 
11
# TODO:
 
12
#   - scope_id support
 
13
require 'socket'
 
14
 
 
15
unless Socket.const_defined? "AF_INET6"
 
16
  class Socket
 
17
    AF_INET6 = Object.new
 
18
  end
 
19
 
 
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
 
27
 
 
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?($')
 
37
 
 
38
      false
 
39
    end
 
40
 
 
41
    def valid?(addr)
 
42
      valid_v4?(addr) || valid_v6?(addr)
 
43
    end
 
44
 
 
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
 
57
 
 
58
# IPAddr provides a set of methods to manipulate an IP address.  Both IPv4 and
 
59
# IPv6 are supported.
 
60
#
 
61
# == Example
 
62
#
 
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>
 
78
 
 
79
class IPAddr
 
80
 
 
81
  IN4MASK = 0xffffffff
 
82
  IN6MASK = 0xffffffffffffffffffffffffffffffff
 
83
  IN6FORMAT = (["%.4x"] * 8).join(':')
 
84
 
 
85
  # Returns the address family of this IP address.
 
86
  attr :family
 
87
 
 
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
 
93
 
 
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
 
107
 
 
108
  # Returns a new ipaddr built by bitwise AND.
 
109
  def &(other)
 
110
    return self.clone.set(@addr & other.to_i)
 
111
  end
 
112
 
 
113
  # Returns a new ipaddr built by bitwise OR.
 
114
  def |(other)
 
115
    return self.clone.set(@addr | other.to_i)
 
116
  end
 
117
 
 
118
  # Returns a new ipaddr built by bitwise right-shift.
 
119
  def >>(num)
 
120
    return self.clone.set(@addr >> num)
 
121
  end
 
122
 
 
123
  # Returns a new ipaddr built by bitwise left shift.
 
124
  def <<(num)
 
125
    return self.clone.set(addr_mask(@addr << num))
 
126
  end
 
127
 
 
128
  # Returns a new ipaddr built by bitwise negation.
 
129
  def ~
 
130
    return self.clone.set(addr_mask(~@addr))
 
131
  end
 
132
 
 
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
 
140
 
 
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
 
146
 
 
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
 
180
 
 
181
    if family != other_family
 
182
      return false
 
183
    end
 
184
    return ((addr & mask_addr) == (other_addr & mask_addr))
 
185
  end
 
186
  alias === include?
 
187
 
 
188
  # Returns the integer representation of the ipaddr.
 
189
  def to_i
 
190
    return @addr
 
191
  end
 
192
 
 
193
  # Returns a string containing the IP address representation.
 
194
  def to_s
 
195
    str = to_string
 
196
    return str if ipv4?
 
197
 
 
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,}/, '::')
 
210
 
 
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
 
214
 
 
215
    str
 
216
  end
 
217
 
 
218
  # Returns a string containing the IP address representation in
 
219
  # canonical form.
 
220
  def to_string
 
221
    return _to_string(@addr)
 
222
  end
 
223
 
 
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
 
237
 
 
238
  # Returns true if the ipaddr is an IPv4 address.
 
239
  def ipv4?
 
240
    return @family == Socket::AF_INET
 
241
  end
 
242
 
 
243
  # Returns true if the ipaddr is an IPv6 address.
 
244
  def ipv6?
 
245
    return @family == Socket::AF_INET6
 
246
  end
 
247
 
 
248
  # Returns true if the ipaddr is an IPv4-mapped IPv6 address.
 
249
  def ipv4_mapped?
 
250
    return ipv6? && (@addr >> 32) == 0xffff
 
251
  end
 
252
 
 
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
 
261
 
 
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
 
270
 
 
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
 
279
 
 
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
 
289
 
 
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
 
302
 
 
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
 
310
 
 
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
 
318
 
 
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
 
333
 
 
334
  protected
 
335
 
 
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
 
355
 
 
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
 
391
 
 
392
  private
 
393
 
 
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
 
444
 
 
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
 
456
 
 
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
 
484
 
 
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
 
496
 
 
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
 
509
 
 
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
 
522
 
 
523
end
 
524
 
 
525
if $0 == __FILE__
 
526
  eval DATA.read, nil, $0, __LINE__+4
 
527
end
 
528
 
 
529
__END__
 
530
 
 
531
require 'test/unit'
 
532
require 'test/unit/ui/console/testrunner'
 
533
 
 
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
    }
 
541
 
 
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)
 
546
 
 
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)
 
551
 
 
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)
 
559
 
 
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)
 
564
 
 
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)
 
569
 
 
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?)
 
576
 
 
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)
 
582
 
 
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)
 
587
 
 
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)
 
590
 
 
591
    assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s)
 
592
 
 
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
 
606
 
 
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
 
623
 
 
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?)
 
634
 
 
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
 
640
 
 
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?)
 
651
 
 
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
 
657
 
 
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
 
662
 
 
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
 
669
 
 
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
 
676
 
 
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
 
681
end
 
682
 
 
683
class TC_Operator < Test::Unit::TestCase
 
684
 
 
685
  IN6MASK32  = "ffff:ffff::"
 
686
  IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
 
687
 
 
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
 
695
 
 
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
 
705
 
 
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
 
714
 
 
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
 
722
 
 
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
 
730
 
 
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
 
736
 
 
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
 
743
 
 
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
 
749
 
 
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
 
760
 
 
761
    assert_equal(true, net1.include?(int))
 
762
    assert_equal(false, net1.include?(int+255))
 
763
 
 
764
  end
 
765
 
 
766
end