PageRenderTime 52ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ipaddr.rb

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