PageRenderTime 365ms CodeModel.GetById 24ms RepoModel.GetById 2ms app.codeStats 1ms

/lib/ruby/1.8/ipaddr.rb

https://github.com/MagLev/maglev
Ruby | 815 lines | 727 code | 48 blank | 40 comment | 35 complexity | cbd578dad12fd49ef59554143807457c MD5 | raw file
Possible License(s): 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: ipaddr.rb 18049 2008-07-12 15:08:29Z shyouhei $
  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._isString
  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._isString
  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. # maglev patch, don't use IPSocket.getaddress here , it causes spec failures
  414. # begin
  415. # IPSocket.getaddress(prefix) # test if address is vaild
  416. # rescue
  417. # raise ArgumentError, "invalid address"
  418. # end
  419. @addr = @family = nil
  420. if family == Socket::AF_UNSPEC || family == Socket::AF_INET
  421. @addr = in_addr(prefix)
  422. if @addr
  423. @family = Socket::AF_INET
  424. end
  425. end
  426. if !@addr && (family == Socket::AF_UNSPEC || family == Socket::AF_INET6)
  427. @addr = in6_addr(prefix)
  428. @family = Socket::AF_INET6
  429. end
  430. if family != Socket::AF_UNSPEC && @family != family
  431. raise ArgumentError, "address family mismatch"
  432. end
  433. if prefixlen
  434. mask!(prefixlen)
  435. else
  436. @mask_addr = (@family == Socket::AF_INET) ? IN4MASK : IN6MASK
  437. end
  438. end
  439. def coerce_other(other)
  440. case other
  441. when IPAddr
  442. other
  443. when String
  444. self.class.new(other)
  445. else
  446. self.class.new(other, @family)
  447. end
  448. end
  449. def in_addr(addr)
  450. if addr =~ /^\d+\.\d+\.\d+\.\d+$/
  451. return addr.split('.').inject(0) { |i, s|
  452. i << 8 | s.to_i
  453. }
  454. end
  455. return nil
  456. 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. return (l + Array.new(rest, '0') + r).inject(0) { |i, s|
  477. i << 16 | s.hex
  478. }
  479. end
  480. def addr_mask(addr)
  481. case @family
  482. when Socket::AF_INET
  483. return addr & IN4MASK
  484. when Socket::AF_INET6
  485. return addr & IN6MASK
  486. else
  487. raise "unsupported address family"
  488. end
  489. end
  490. def _reverse
  491. case @family
  492. when Socket::AF_INET
  493. return (0..3).map { |i|
  494. (@addr >> (8 * i)) & 0xff
  495. }.join('.')
  496. when Socket::AF_INET6
  497. return ("%.32x" % @addr).reverse!.gsub!(/.(?!$)/, '\&.')
  498. else
  499. raise "unsupported address family"
  500. end
  501. end
  502. def _to_string(addr)
  503. case @family
  504. when Socket::AF_INET
  505. return (0..3).map { |i|
  506. (addr >> (24 - 8 * i)) & 0xff
  507. }.join('.')
  508. when Socket::AF_INET6
  509. return (("%.32x" % addr).gsub!(/.{4}(?!$)/, '\&:'))
  510. else
  511. raise "unsupported address family"
  512. end
  513. end
  514. end
  515. if $0 == __FILE__
  516. eval DATA.read, nil, $0, __LINE__+4
  517. end
  518. __END__
  519. require 'test/unit'
  520. require 'test/unit/ui/console/testrunner'
  521. class TC_IPAddr < Test::Unit::TestCase
  522. def test_s_new
  523. assert_nothing_raised {
  524. IPAddr.new("3FFE:505:ffff::/48")
  525. IPAddr.new("0:0:0:1::")
  526. IPAddr.new("2001:200:300::/48")
  527. }
  528. a = IPAddr.new
  529. assert_equal("::", a.to_s)
  530. assert_equal("0000:0000:0000:0000:0000:0000:0000:0000", a.to_string)
  531. assert_equal(Socket::AF_INET6, a.family)
  532. a = IPAddr.new("0123:4567:89ab:cdef:0ABC:DEF0:1234:5678")
  533. assert_equal("123:4567:89ab:cdef:abc:def0:1234:5678", a.to_s)
  534. assert_equal("0123:4567:89ab:cdef:0abc:def0:1234:5678", a.to_string)
  535. assert_equal(Socket::AF_INET6, a.family)
  536. a = IPAddr.new("3ffe:505:2::/48")
  537. assert_equal("3ffe:505:2::", a.to_s)
  538. assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
  539. assert_equal(Socket::AF_INET6, a.family)
  540. assert_equal(false, a.ipv4?)
  541. assert_equal(true, a.ipv6?)
  542. assert_equal("#<IPAddr: IPv6:3ffe:0505:0002:0000:0000:0000:0000:0000/ffff:ffff:ffff:0000:0000:0000:0000:0000>", a.inspect)
  543. a = IPAddr.new("3ffe:505:2::/ffff:ffff:ffff::")
  544. assert_equal("3ffe:505:2::", a.to_s)
  545. assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0000", a.to_string)
  546. assert_equal(Socket::AF_INET6, a.family)
  547. a = IPAddr.new("0.0.0.0")
  548. assert_equal("0.0.0.0", a.to_s)
  549. assert_equal("0.0.0.0", a.to_string)
  550. assert_equal(Socket::AF_INET, a.family)
  551. a = IPAddr.new("192.168.1.2")
  552. assert_equal("192.168.1.2", a.to_s)
  553. assert_equal("192.168.1.2", a.to_string)
  554. assert_equal(Socket::AF_INET, a.family)
  555. assert_equal(true, a.ipv4?)
  556. assert_equal(false, a.ipv6?)
  557. a = IPAddr.new("192.168.1.2/24")
  558. assert_equal("192.168.1.0", a.to_s)
  559. assert_equal("192.168.1.0", a.to_string)
  560. assert_equal(Socket::AF_INET, a.family)
  561. assert_equal("#<IPAddr: IPv4:192.168.1.0/255.255.255.0>", a.inspect)
  562. a = IPAddr.new("192.168.1.2/255.255.255.0")
  563. assert_equal("192.168.1.0", a.to_s)
  564. assert_equal("192.168.1.0", a.to_string)
  565. assert_equal(Socket::AF_INET, a.family)
  566. assert_equal("0:0:0:1::", IPAddr.new("0:0:0:1::").to_s)
  567. assert_equal("2001:200:300::", IPAddr.new("2001:200:300::/48").to_s)
  568. assert_equal("2001:200:300::", IPAddr.new("[2001:200:300::]/48").to_s)
  569. [
  570. ["fe80::1%fxp0"],
  571. ["::1/255.255.255.0"],
  572. ["::1:192.168.1.2/120"],
  573. [IPAddr.new("::1").to_i],
  574. ["::ffff:192.168.1.2/120", Socket::AF_INET],
  575. ["[192.168.1.2]/120"],
  576. ].each { |args|
  577. assert_raises(ArgumentError) {
  578. IPAddr.new(*args)
  579. }
  580. }
  581. end
  582. def test_s_new_ntoh
  583. addr = ''
  584. IPAddr.new("1234:5678:9abc:def0:1234:5678:9abc:def0").hton.each_byte { |c|
  585. addr += sprintf("%02x", c)
  586. }
  587. assert_equal("123456789abcdef0123456789abcdef0", addr)
  588. addr = ''
  589. IPAddr.new("123.45.67.89").hton.each_byte { |c|
  590. addr += sprintf("%02x", c)
  591. }
  592. assert_equal(sprintf("%02x%02x%02x%02x", 123, 45, 67, 89), addr)
  593. a = IPAddr.new("3ffe:505:2::")
  594. assert_equal("3ffe:505:2::", IPAddr.new_ntoh(a.hton).to_s)
  595. a = IPAddr.new("192.168.2.1")
  596. assert_equal("192.168.2.1", IPAddr.new_ntoh(a.hton).to_s)
  597. end
  598. def test_ipv4_compat
  599. a = IPAddr.new("::192.168.1.2")
  600. assert_equal("::192.168.1.2", a.to_s)
  601. assert_equal("0000:0000:0000:0000:0000:0000:c0a8:0102", a.to_string)
  602. assert_equal(Socket::AF_INET6, a.family)
  603. assert_equal(true, a.ipv4_compat?)
  604. b = a.native
  605. assert_equal("192.168.1.2", b.to_s)
  606. assert_equal(Socket::AF_INET, b.family)
  607. assert_equal(false, b.ipv4_compat?)
  608. a = IPAddr.new("192.168.1.2")
  609. b = a.ipv4_compat
  610. assert_equal("::192.168.1.2", b.to_s)
  611. assert_equal(Socket::AF_INET6, b.family)
  612. end
  613. def test_ipv4_mapped
  614. a = IPAddr.new("::ffff:192.168.1.2")
  615. assert_equal("::ffff:192.168.1.2", a.to_s)
  616. assert_equal("0000:0000:0000:0000:0000:ffff:c0a8:0102", a.to_string)
  617. assert_equal(Socket::AF_INET6, a.family)
  618. assert_equal(true, a.ipv4_mapped?)
  619. b = a.native
  620. assert_equal("192.168.1.2", b.to_s)
  621. assert_equal(Socket::AF_INET, b.family)
  622. assert_equal(false, b.ipv4_mapped?)
  623. a = IPAddr.new("192.168.1.2")
  624. b = a.ipv4_mapped
  625. assert_equal("::ffff:192.168.1.2", b.to_s)
  626. assert_equal(Socket::AF_INET6, b.family)
  627. end
  628. def test_reverse
  629. 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)
  630. assert_equal("1.2.168.192.in-addr.arpa", IPAddr.new("192.168.2.1").reverse)
  631. end
  632. def test_ip6_arpa
  633. 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)
  634. assert_raises(ArgumentError) {
  635. IPAddr.new("192.168.2.1").ip6_arpa
  636. }
  637. end
  638. def test_ip6_int
  639. 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)
  640. assert_raises(ArgumentError) {
  641. IPAddr.new("192.168.2.1").ip6_int
  642. }
  643. end
  644. def test_to_s
  645. assert_equal("3ffe:0505:0002:0000:0000:0000:0000:0001", IPAddr.new("3ffe:505:2::1").to_string)
  646. assert_equal("3ffe:505:2::1", IPAddr.new("3ffe:505:2::1").to_s)
  647. end
  648. end
  649. class TC_Operator < Test::Unit::TestCase
  650. IN6MASK32 = "ffff:ffff::"
  651. IN6MASK128 = "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"
  652. def setup
  653. @in6_addr_any = IPAddr.new()
  654. @a = IPAddr.new("3ffe:505:2::/48")
  655. @b = IPAddr.new("0:0:0:1::")
  656. @c = IPAddr.new(IN6MASK32)
  657. end
  658. alias set_up setup
  659. def test_or
  660. assert_equal("3ffe:505:2:1::", (@a | @b).to_s)
  661. a = @a
  662. a |= @b
  663. assert_equal("3ffe:505:2:1::", a.to_s)
  664. assert_equal("3ffe:505:2::", @a.to_s)
  665. assert_equal("3ffe:505:2:1::",
  666. (@a | 0x00000000000000010000000000000000).to_s)
  667. end
  668. def test_and
  669. assert_equal("3ffe:505::", (@a & @c).to_s)
  670. a = @a
  671. a &= @c
  672. assert_equal("3ffe:505::", a.to_s)
  673. assert_equal("3ffe:505:2::", @a.to_s)
  674. assert_equal("3ffe:505::", (@a & 0xffffffff000000000000000000000000).to_s)
  675. end
  676. def test_shift_right
  677. assert_equal("0:3ffe:505:2::", (@a >> 16).to_s)
  678. a = @a
  679. a >>= 16
  680. assert_equal("0:3ffe:505:2::", a.to_s)
  681. assert_equal("3ffe:505:2::", @a.to_s)
  682. end
  683. def test_shift_left
  684. assert_equal("505:2::", (@a << 16).to_s)
  685. a = @a
  686. a <<= 16
  687. assert_equal("505:2::", a.to_s)
  688. assert_equal("3ffe:505:2::", @a.to_s)
  689. end
  690. def test_carrot
  691. a = ~@in6_addr_any
  692. assert_equal(IN6MASK128, a.to_s)
  693. assert_equal("::", @in6_addr_any.to_s)
  694. end
  695. def test_equal
  696. assert_equal(true, @a == IPAddr.new("3ffe:505:2::"))
  697. assert_equal(false, @a == IPAddr.new("3ffe:505:3::"))
  698. assert_equal(true, @a != IPAddr.new("3ffe:505:3::"))
  699. assert_equal(false, @a != IPAddr.new("3ffe:505:2::"))
  700. end
  701. def test_mask
  702. a = @a.mask(32)
  703. assert_equal("3ffe:505::", a.to_s)
  704. assert_equal("3ffe:505:2::", @a.to_s)
  705. end
  706. def test_include?
  707. assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::")))
  708. assert_equal(true, @a.include?(IPAddr.new("3ffe:505:2::1")))
  709. assert_equal(false, @a.include?(IPAddr.new("3ffe:505:3::")))
  710. net1 = IPAddr.new("192.168.2.0/24")
  711. assert_equal(true, net1.include?(IPAddr.new("192.168.2.0")))
  712. assert_equal(true, net1.include?(IPAddr.new("192.168.2.255")))
  713. assert_equal(false, net1.include?(IPAddr.new("192.168.3.0")))
  714. # test with integer parameter
  715. int = (192 << 24) + (168 << 16) + (2 << 8) + 13
  716. assert_equal(true, net1.include?(int))
  717. assert_equal(false, net1.include?(int+255))
  718. end
  719. end