PageRenderTime 52ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ruby/1.8/ipaddr.rb

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