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

/multisketchup/ruby-1.8.0-win32-lib/lib/ruby/1.8/resolv.rb

http://multisketchup.googlecode.com/
Ruby | 1710 lines | 1376 code | 145 blank | 189 comment | 65 complexity | 6c928dcb0ae656c8310892ee5781ca15 MD5 | raw file
  1. =begin
  2. = resolv library
  3. resolv.rb is a resolver library written in Ruby.
  4. Since it is written in Ruby, it is thread-aware.
  5. I.e. it can resolv many hostnames concurrently.
  6. It is possible to lookup various resources of DNS using DNS module directly.
  7. == example
  8. Resolv.getaddress("www.ruby-lang.org")
  9. Resolv.getname("210.251.121.214")
  10. dns = Resolv::DNS.new
  11. dns.getresources("www.ruby-lang.org", Resolv::DNS::Resource::IN::A).collect {|r| r.address}
  12. dns.getresources("ruby-lang.org", Resolv::DNS::Resource::IN::MX).collect {|r| [r.exchange.to_s, r.preference]}
  13. == Resolv class
  14. === class methods
  15. --- Resolv.getaddress(name)
  16. --- Resolv.getaddresses(name)
  17. --- Resolv.each_address(name) {|address| ...}
  18. They lookups IP addresses of ((|name|)) which represents a hostname
  19. as a string by default resolver.
  20. getaddress returns first entry of lookupped addresses.
  21. getaddresses returns lookupped addresses as an array.
  22. each_address iterates over lookupped addresses.
  23. --- Resolv.getname(address)
  24. --- Resolv.getnames(address)
  25. --- Resolv.each_name(address) {|name| ...}
  26. lookups hostnames of ((|address|)) which represents IP address as a string.
  27. getname returns first entry of lookupped names.
  28. getnames returns lookupped names as an array.
  29. each_names iterates over lookupped names.
  30. == Resolv::Hosts class
  31. hostname resolver using /etc/hosts format.
  32. === class methods
  33. --- Resolv::Hosts.new(hosts='/etc/hosts')
  34. === methods
  35. --- Resolv::Hosts#getaddress(name)
  36. --- Resolv::Hosts#getaddresses(name)
  37. --- Resolv::Hosts#each_address(name) {|address| ...}
  38. address lookup methods.
  39. --- Resolv::Hosts#getname(address)
  40. --- Resolv::Hosts#getnames(address)
  41. --- Resolv::Hosts#each_name(address) {|name| ...}
  42. hostnames lookup methods.
  43. == Resolv::DNS class
  44. DNS stub resolver.
  45. === class methods
  46. --- Resolv::DNS.new(resolv_conf='/etc/resolv.conf')
  47. --- Resolv::DNS.open(resolv_conf='/etc/resolv.conf')
  48. --- Resolv::DNS.open(resolv_conf='/etc/resolv.conf') {|dns| ...}
  49. === methods
  50. --- Resolv::DNS#close
  51. --- Resolv::DNS#getaddress(name)
  52. --- Resolv::DNS#getaddresses(name)
  53. --- Resolv::DNS#each_address(name) {|address| ...}
  54. address lookup methods.
  55. ((|name|)) must be a instance of Resolv::DNS::Name or String. Lookupped
  56. address is represented as an instance of Resolv::IPv4 or Resolv::IPv6.
  57. --- Resolv::DNS#getname(address)
  58. --- Resolv::DNS#getnames(address)
  59. --- Resolv::DNS#each_name(address) {|name| ...}
  60. hostnames lookup methods.
  61. ((|address|)) must be a instance of Resolv::IPv4, Resolv::IPv6 or String.
  62. Lookupped name is represented as an instance of Resolv::DNS::Name.
  63. --- Resolv::DNS#getresource(name, typeclass)
  64. --- Resolv::DNS#getresources(name, typeclass)
  65. --- Resolv::DNS#each_resource(name, typeclass) {|resource| ...}
  66. They lookup DNS resources of ((|name|)).
  67. ((|name|)) must be a instance of Resolv::Name or String.
  68. ((|typeclass|)) should be one of follows:
  69. * Resolv::DNS::Resource::IN::ANY
  70. * Resolv::DNS::Resource::IN::NS
  71. * Resolv::DNS::Resource::IN::CNAME
  72. * Resolv::DNS::Resource::IN::SOA
  73. * Resolv::DNS::Resource::IN::HINFO
  74. * Resolv::DNS::Resource::IN::MINFO
  75. * Resolv::DNS::Resource::IN::MX
  76. * Resolv::DNS::Resource::IN::TXT
  77. * Resolv::DNS::Resource::IN::ANY
  78. * Resolv::DNS::Resource::IN::A
  79. * Resolv::DNS::Resource::IN::WKS
  80. * Resolv::DNS::Resource::IN::PTR
  81. * Resolv::DNS::Resource::IN::AAAA
  82. Lookupped resource is represented as an instance of (a subclass of)
  83. Resolv::DNS::Resource.
  84. (Resolv::DNS::Resource::IN::A, etc.)
  85. == Resolv::DNS::Resource::IN::NS class
  86. --- name
  87. == Resolv::DNS::Resource::IN::CNAME class
  88. --- name
  89. == Resolv::DNS::Resource::IN::SOA class
  90. --- mname
  91. --- rname
  92. --- serial
  93. --- refresh
  94. --- retry
  95. --- expire
  96. --- minimum
  97. == Resolv::DNS::Resource::IN::HINFO class
  98. --- cpu
  99. --- os
  100. == Resolv::DNS::Resource::IN::MINFO class
  101. --- rmailbx
  102. --- emailbx
  103. == Resolv::DNS::Resource::IN::MX class
  104. --- preference
  105. --- exchange
  106. == Resolv::DNS::Resource::IN::TXT class
  107. --- data
  108. == Resolv::DNS::Resource::IN::A class
  109. --- address
  110. == Resolv::DNS::Resource::IN::WKS class
  111. --- address
  112. --- protocol
  113. --- bitmap
  114. == Resolv::DNS::Resource::IN::PTR class
  115. --- name
  116. == Resolv::DNS::Resource::IN::AAAA class
  117. --- address
  118. == Resolv::DNS::Name class
  119. === class methods
  120. --- Resolv::DNS::Name.create(name)
  121. === methods
  122. --- Resolv::DNS::Name#to_s
  123. == Resolv::DNS::Resource class
  124. == Resolv::IPv4 class
  125. === class methods
  126. --- Resolv::IPv4.create(address)
  127. === methods
  128. --- Resolv::IPv4#to_s
  129. --- Resolv::IPv4#to_name
  130. === constants
  131. --- Resolv::IPv4::Regex
  132. regular expression for IPv4 address.
  133. == Resolv::IPv6 class
  134. === class methods
  135. --- Resolv::IPv6.create(address)
  136. === methods
  137. --- Resolv::IPv6#to_s
  138. --- Resolv::IPv6#to_name
  139. === constants
  140. --- Resolv::IPv6::Regex
  141. regular expression for IPv6 address.
  142. == Bugs
  143. * NIS is not supported.
  144. * /etc/nsswitch.conf is not supported.
  145. * IPv6 is not supported.
  146. =end
  147. require 'socket'
  148. require 'fcntl'
  149. require 'timeout'
  150. require 'thread'
  151. class Resolv
  152. def self.getaddress(name)
  153. DefaultResolver.getaddress(name)
  154. end
  155. def self.getaddresses(name)
  156. DefaultResolver.getaddresses(name)
  157. end
  158. def self.each_address(name, &block)
  159. DefaultResolver.each_address(name, &block)
  160. end
  161. def self.getname(address)
  162. DefaultResolver.getname(address)
  163. end
  164. def self.getnames(address)
  165. DefaultResolver.getnames(address)
  166. end
  167. def self.each_name(address, &proc)
  168. DefaultResolver.each_name(address, &proc)
  169. end
  170. def initialize(resolvers=[Hosts.new, DNS.new])
  171. @resolvers = resolvers
  172. end
  173. def getaddress(name)
  174. each_address(name) {|address| return address}
  175. raise ResolvError.new("no address for #{name}")
  176. end
  177. def getaddresses(name)
  178. ret = []
  179. each_address(name) {|address| ret << address}
  180. return ret
  181. end
  182. def each_address(name)
  183. if AddressRegex =~ name
  184. yield name
  185. return
  186. end
  187. yielded = false
  188. @resolvers.each {|r|
  189. r.each_address(name) {|address|
  190. yield address.to_s
  191. yielded = true
  192. }
  193. return if yielded
  194. }
  195. end
  196. def getname(address)
  197. each_name(address) {|name| return name}
  198. raise ResolvError.new("no name for #{address}")
  199. end
  200. def getnames(address)
  201. ret = []
  202. each_name(address) {|name| ret << name}
  203. return ret
  204. end
  205. def each_name(address)
  206. yielded = false
  207. @resolvers.each {|r|
  208. r.each_name(address) {|name|
  209. yield name.to_s
  210. yielded = true
  211. }
  212. return if yielded
  213. }
  214. end
  215. class ResolvError < StandardError
  216. end
  217. class ResolvTimeout < TimeoutError
  218. end
  219. class Hosts
  220. if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
  221. require 'win32/resolv'
  222. DefaultFileName = Win32::Resolv.get_hosts_path
  223. else
  224. DefaultFileName = '/etc/hosts'
  225. end
  226. def initialize(filename = DefaultFileName)
  227. @filename = filename
  228. @mutex = Mutex.new
  229. @initialized = nil
  230. end
  231. def lazy_initialize
  232. @mutex.synchronize {
  233. unless @initialized
  234. @name2addr = {}
  235. @addr2name = {}
  236. open(@filename) {|f|
  237. f.each {|line|
  238. line.sub!(/#.*/, '')
  239. addr, hostname, *aliases = line.split(/\s+/)
  240. next unless addr
  241. addr.untaint
  242. hostname.untaint
  243. @addr2name[addr] = [] unless @addr2name.include? addr
  244. @addr2name[addr] << hostname
  245. @addr2name[addr] += aliases
  246. @name2addr[hostname] = [] unless @name2addr.include? hostname
  247. @name2addr[hostname] << addr
  248. aliases.each {|n|
  249. n.untaint
  250. @name2addr[n] = [] unless @name2addr.include? n
  251. @name2addr[n] << addr
  252. }
  253. }
  254. }
  255. @name2addr.each {|name, arr| arr.reverse!}
  256. @initialized = true
  257. end
  258. }
  259. end
  260. def getaddress(name)
  261. each_address(name) {|address| return address}
  262. raise ResolvError.new("#{@filename} has no name: #{name}")
  263. end
  264. def getaddresses(name)
  265. ret = []
  266. each_address(name) {|address| ret << address}
  267. return ret
  268. end
  269. def each_address(name, &proc)
  270. lazy_initialize
  271. if @name2addr.include?(name)
  272. @name2addr[name].each(&proc)
  273. end
  274. end
  275. def getname(address)
  276. each_name(address) {|name| return name}
  277. raise ResolvError.new("#{@filename} has no address: #{address}")
  278. end
  279. def getnames(address)
  280. ret = []
  281. each_name(address) {|name| ret << name}
  282. return ret
  283. end
  284. def each_name(address, &proc)
  285. lazy_initialize
  286. if @addr2name.include?(address)
  287. @addr2name[address].each(&proc)
  288. end
  289. end
  290. end
  291. class DNS
  292. # STD0013 (RFC 1035, etc.)
  293. # ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
  294. Port = 53
  295. UDPSize = 512
  296. DNSThreadGroup = ThreadGroup.new
  297. def self.open(*args)
  298. dns = new(*args)
  299. return dns unless block_given?
  300. begin
  301. yield dns
  302. ensure
  303. dns.close
  304. end
  305. end
  306. def initialize(config="/etc/resolv.conf")
  307. @mutex = Mutex.new
  308. @config = Config.new(config)
  309. @initialized = nil
  310. end
  311. def lazy_initialize
  312. @mutex.synchronize {
  313. unless @initialized
  314. @config.lazy_initialize
  315. if nameserver = @config.single?
  316. @requester = Requester::ConnectedUDP.new(nameserver)
  317. else
  318. @requester = Requester::UnconnectedUDP.new
  319. end
  320. @initialized = true
  321. end
  322. }
  323. end
  324. def close
  325. @mutex.synchronize {
  326. if @initialized
  327. @requester.close if @requester
  328. @requester = nil
  329. @initialized = false
  330. end
  331. }
  332. end
  333. def getaddress(name)
  334. each_address(name) {|address| return address}
  335. raise ResolvError.new("DNS result has no information for #{name}")
  336. end
  337. def getaddresses(name)
  338. ret = []
  339. each_address(name) {|address| ret << address}
  340. return ret
  341. end
  342. def each_address(name)
  343. each_resource(name, Resource::IN::A) {|resource| yield resource.address}
  344. end
  345. def getname(address)
  346. each_name(address) {|name| return name}
  347. raise ResolvError.new("DNS result has no information for #{address}")
  348. end
  349. def getnames(address)
  350. ret = []
  351. each_name(address) {|name| ret << name}
  352. return ret
  353. end
  354. def each_name(address)
  355. case address
  356. when Name
  357. ptr = address
  358. when IPv4::Regex
  359. ptr = IPv4.create(address).to_name
  360. when IPv6::Regex
  361. ptr = IPv6.create(address).to_name
  362. else
  363. raise ResolvError.new("cannot interpret as address: #{address}")
  364. end
  365. each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
  366. end
  367. def getresource(name, typeclass)
  368. each_resource(name, typeclass) {|resource| return resource}
  369. raise ResolvError.new("DNS result has no information for #{name}")
  370. end
  371. def getresources(name, typeclass)
  372. ret = []
  373. each_resource(name, typeclass) {|resource| ret << resource}
  374. return ret
  375. end
  376. def each_resource(name, typeclass, &proc)
  377. lazy_initialize
  378. q = Queue.new
  379. senders = {}
  380. begin
  381. @config.resolv(name) {|candidate, tout, nameserver|
  382. msg = Message.new
  383. msg.rd = 1
  384. msg.add_question(candidate, typeclass)
  385. unless sender = senders[[candidate, nameserver]]
  386. sender = senders[[candidate, nameserver]] =
  387. @requester.sender(msg, candidate, q, nameserver)
  388. end
  389. sender.send
  390. reply = reply_name = nil
  391. timeout(tout, ResolvTimeout) { reply, reply_name = q.pop }
  392. case reply.rcode
  393. when RCode::NoError
  394. extract_resources(reply, reply_name, typeclass, &proc)
  395. return
  396. when RCode::NXDomain
  397. raise Config::NXDomain.new(reply_name.to_s)
  398. else
  399. raise Config::OtherResolvError.new(reply_name.to_s)
  400. end
  401. }
  402. ensure
  403. @requester.delete(q)
  404. end
  405. end
  406. def extract_resources(msg, name, typeclass)
  407. if typeclass < Resource::ANY
  408. n0 = Name.create(name)
  409. msg.each_answer {|n, ttl, data|
  410. yield data if n0 == n
  411. }
  412. end
  413. yielded = false
  414. n0 = Name.create(name)
  415. msg.each_answer {|n, ttl, data|
  416. if n0 == n
  417. case data
  418. when typeclass
  419. yield data
  420. yielded = true
  421. when Resource::CNAME
  422. n0 = data.name
  423. end
  424. end
  425. }
  426. return if yielded
  427. msg.each_answer {|n, ttl, data|
  428. if n0 == n
  429. case data
  430. when typeclass
  431. yield data
  432. end
  433. end
  434. }
  435. end
  436. class Requester
  437. def initialize
  438. @senders = {}
  439. end
  440. def close
  441. thread, sock, @thread, @sock = @thread, @sock
  442. begin
  443. if thread
  444. thread.kill
  445. thread.join
  446. end
  447. ensure
  448. sock.close if sock
  449. end
  450. end
  451. def delete(arg)
  452. case arg
  453. when Sender
  454. @senders.delete_if {|k, s| s == arg }
  455. when Queue
  456. @senders.delete_if {|k, s| s.queue == arg }
  457. else
  458. raise ArgumentError.new("neither Sender or Queue: #{arg}")
  459. end
  460. end
  461. class Sender
  462. def initialize(msg, data, sock, queue)
  463. @msg = msg
  464. @data = data
  465. @sock = sock
  466. @queue = queue
  467. end
  468. attr_reader :queue
  469. def recv(msg)
  470. @queue.push([msg, @data])
  471. end
  472. end
  473. class UnconnectedUDP < Requester
  474. def initialize
  475. super()
  476. @sock = UDPSocket.new
  477. @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
  478. @id = {}
  479. @id.default = -1
  480. @thread = Thread.new {
  481. DNSThreadGroup.add Thread.current
  482. loop {
  483. reply, from = @sock.recvfrom(UDPSize)
  484. msg = begin
  485. Message.decode(reply)
  486. rescue DecodeError
  487. STDERR.print("DNS message decoding error: #{reply.inspect}\n")
  488. next
  489. end
  490. if s = @senders[[[from[3],from[1]],msg.id]]
  491. s.recv msg
  492. else
  493. #STDERR.print("non-handled DNS message: #{msg.inspect} from #{from.inspect}\n")
  494. end
  495. }
  496. }
  497. end
  498. def sender(msg, data, queue, host, port=Port)
  499. service = [host, port]
  500. id = Thread.exclusive {
  501. @id[service] = (@id[service] + 1) & 0xffff
  502. }
  503. request = msg.encode
  504. request[0,2] = [id].pack('n')
  505. return @senders[[service, id]] =
  506. Sender.new(request, data, @sock, host, port, queue)
  507. end
  508. class Sender < Requester::Sender
  509. def initialize(msg, data, sock, host, port, queue)
  510. super(msg, data, sock, queue)
  511. @host = host
  512. @port = port
  513. end
  514. def send
  515. @sock.send(@msg, 0, @host, @port)
  516. end
  517. end
  518. end
  519. class ConnectedUDP < Requester
  520. def initialize(host, port=Port)
  521. super()
  522. @host = host
  523. @port = port
  524. @sock = UDPSocket.new
  525. @sock.connect(host, port)
  526. @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
  527. @id = -1
  528. @thread = Thread.new {
  529. DNSThreadGroup.add Thread.current
  530. loop {
  531. reply = @sock.recv(UDPSize)
  532. msg = begin
  533. Message.decode(reply)
  534. rescue DecodeError
  535. STDERR.print("DNS message decoding error: #{reply.inspect}")
  536. next
  537. end
  538. if s = @senders[msg.id]
  539. s.recv msg
  540. else
  541. #STDERR.print("non-handled DNS message: #{msg.inspect}")
  542. end
  543. }
  544. }
  545. end
  546. def sender(msg, data, queue, host=@host, port=@port)
  547. unless host == @host && port == @port
  548. raise RequestError.new("host/port don't match: #{host}:#{port}")
  549. end
  550. id = Thread.exclusive { @id = (@id + 1) & 0xffff }
  551. request = msg.encode
  552. request[0,2] = [id].pack('n')
  553. return @senders[id] = Sender.new(request, data, @sock, queue)
  554. end
  555. class Sender < Requester::Sender
  556. def send
  557. @sock.send(@msg, 0)
  558. end
  559. end
  560. end
  561. class TCP < Requester
  562. def initialize(host, port=Port)
  563. super()
  564. @host = host
  565. @port = port
  566. @sock = TCPSocket.new
  567. @sock.connect(host, port)
  568. @sock.fcntl(Fcntl::F_SETFD, 1) if defined? Fcntl::F_SETFD
  569. @id = -1
  570. @senders = {}
  571. @thread = Thread.new {
  572. DNSThreadGroup.add Thread.current
  573. loop {
  574. len = @sock.read(2).unpack('n')
  575. reply = @sock.read(len)
  576. msg = begin
  577. Message.decode(reply)
  578. rescue DecodeError
  579. STDERR.print("DNS message decoding error: #{reply.inspect}")
  580. next
  581. end
  582. if s = @senders[msg.id]
  583. s.push msg
  584. else
  585. #STDERR.print("non-handled DNS message: #{msg.inspect}")
  586. end
  587. }
  588. }
  589. end
  590. def sender(msg, data, queue, host=@host, port=@port)
  591. unless host == @host && port == @port
  592. raise RequestError.new("host/port don't match: #{host}:#{port}")
  593. end
  594. id = Thread.exclusive { @id = (@id + 1) & 0xffff }
  595. request = msg.encode
  596. request[0,2] = [request.length, id].pack('nn')
  597. return @senders[id] = Sender.new(request, data, @sock, queue)
  598. end
  599. class Sender < Requester::Sender
  600. def send
  601. @sock.print(@msg)
  602. @sock.flush
  603. end
  604. end
  605. end
  606. class RequestError < StandardError
  607. end
  608. end
  609. class Config
  610. def initialize(filename="/etc/resolv.conf")
  611. @mutex = Mutex.new
  612. @filename = filename
  613. @initialized = nil
  614. end
  615. def lazy_initialize
  616. @mutex.synchronize {
  617. unless @initialized
  618. @nameserver = []
  619. @search = nil
  620. @ndots = 1
  621. begin
  622. open(@filename) {|f|
  623. f.each {|line|
  624. line.sub!(/[#;].*/, '')
  625. keyword, *args = line.split(/\s+/)
  626. args.each { |arg|
  627. arg.untaint
  628. }
  629. next unless keyword
  630. case keyword
  631. when 'nameserver'
  632. @nameserver += args
  633. when 'domain'
  634. @search = [Label.split(args[0])]
  635. when 'search'
  636. @search = args.map {|arg| Label.split(arg)}
  637. end
  638. }
  639. }
  640. rescue Errno::ENOENT
  641. if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
  642. search, nameserver = Win32::Resolv.get_resolv_info
  643. @search = [search] if search
  644. @nameserver = nameserver if nameserver
  645. end
  646. end
  647. @nameserver = ['0.0.0.0'] if @nameserver.empty?
  648. unless @search
  649. hostname = Socket.gethostname
  650. if /\./ =~ hostname
  651. @search = [Label.split($')]
  652. else
  653. @search = [[]]
  654. end
  655. end
  656. @initialized = true
  657. end
  658. }
  659. end
  660. def single?
  661. lazy_initialize
  662. if @nameserver.length == 1
  663. return @nameserver[0]
  664. else
  665. return nil
  666. end
  667. end
  668. def generate_candidates(name)
  669. candidates = nil
  670. name = Name.create(name)
  671. if name.absolute?
  672. candidates = [name]
  673. else
  674. if @ndots <= name.length - 1
  675. candidates = [Name.new(name.to_a)]
  676. else
  677. candidates = []
  678. end
  679. candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
  680. end
  681. return candidates
  682. end
  683. InitialTimeout = 5
  684. def generate_timeouts
  685. ts = [InitialTimeout]
  686. ts << ts[-1] * 2 / @nameserver.length
  687. ts << ts[-1] * 2
  688. ts << ts[-1] * 2
  689. return ts
  690. end
  691. def resolv(name)
  692. candidates = generate_candidates(name)
  693. timeouts = generate_timeouts
  694. begin
  695. candidates.each {|candidate|
  696. begin
  697. timeouts.each {|tout|
  698. @nameserver.each {|nameserver|
  699. begin
  700. yield candidate, tout, nameserver
  701. rescue ResolvTimeout
  702. end
  703. }
  704. }
  705. raise ResolvError.new("DNS resolv timeout: #{name}")
  706. rescue NXDomain
  707. end
  708. }
  709. rescue OtherResolvError
  710. raise ResolvError.new("DNS error: #{$!.message}")
  711. end
  712. raise ResolvError.new("DNS resolv error: #{name}")
  713. end
  714. class NXDomain < ResolvError
  715. end
  716. class OtherResolvError < ResolvError
  717. end
  718. end
  719. module OpCode
  720. Query = 0
  721. IQuery = 1
  722. Status = 2
  723. Notify = 4
  724. Update = 5
  725. end
  726. module RCode
  727. NoError = 0
  728. FormErr = 1
  729. ServFail = 2
  730. NXDomain = 3
  731. NotImp = 4
  732. Refused = 5
  733. YXDomain = 6
  734. YXRRSet = 7
  735. NXRRSet = 8
  736. NotAuth = 9
  737. NotZone = 10
  738. BADVERS = 16
  739. BADSIG = 16
  740. BADKEY = 17
  741. BADTIME = 18
  742. BADMODE = 19
  743. BADNAME = 20
  744. BADALG = 21
  745. end
  746. class DecodeError < StandardError
  747. end
  748. class EncodeError < StandardError
  749. end
  750. module Label
  751. def self.split(arg)
  752. labels = []
  753. arg.scan(/[^\.]+/) {labels << Str.new($&)}
  754. return labels
  755. end
  756. class Str
  757. def initialize(string)
  758. @string = string
  759. @downcase = string.downcase
  760. end
  761. attr_reader :string, :downcase
  762. def to_s
  763. return @string
  764. end
  765. def inspect
  766. return "#<#{self.class} #{self.to_s}>"
  767. end
  768. def ==(other)
  769. return @downcase == other.downcase
  770. end
  771. def eql?(other)
  772. return self == other
  773. end
  774. def hash
  775. return @downcase.hash
  776. end
  777. end
  778. end
  779. class Name
  780. def self.create(arg)
  781. case arg
  782. when Name
  783. return arg
  784. when String
  785. return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
  786. else
  787. raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
  788. end
  789. end
  790. def initialize(labels, absolute=true)
  791. @labels = labels
  792. @absolute = absolute
  793. end
  794. def absolute?
  795. return @absolute
  796. end
  797. def ==(other)
  798. return @labels == other.to_a && @absolute == other.absolute?
  799. end
  800. alias eql? ==
  801. def hash
  802. return @labels.hash ^ @absolute.hash
  803. end
  804. def to_a
  805. return @labels
  806. end
  807. def length
  808. return @labels.length
  809. end
  810. def [](i)
  811. return @labels[i]
  812. end
  813. def to_s
  814. return @labels.join('.')
  815. end
  816. end
  817. class Message
  818. @@identifier = -1
  819. def initialize(id = (@@identifier += 1) & 0xffff)
  820. @id = id
  821. @qr = 0
  822. @opcode = 0
  823. @aa = 0
  824. @tc = 0
  825. @rd = 0 # recursion desired
  826. @ra = 0 # recursion available
  827. @rcode = 0
  828. @question = []
  829. @answer = []
  830. @authority = []
  831. @additional = []
  832. end
  833. attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode
  834. attr_reader :question, :answer, :authority, :additional
  835. def ==(other)
  836. return @id == other.id &&
  837. @qr == other.qr &&
  838. @opcode == other.opcode &&
  839. @aa == other.aa &&
  840. @tc == other.tc &&
  841. @rd == other.rd &&
  842. @ra == other.ra &&
  843. @rcode == other.rcode &&
  844. @question == other.question &&
  845. @answer == other.answer &&
  846. @authority == other.authority &&
  847. @additional == other.additional
  848. end
  849. def add_question(name, typeclass)
  850. @question << [Name.create(name), typeclass]
  851. end
  852. def each_question
  853. @question.each {|name, typeclass|
  854. yield name, typeclass
  855. }
  856. end
  857. def add_answer(name, ttl, data)
  858. @answer << [Name.create(name), ttl, data]
  859. end
  860. def each_answer
  861. @answer.each {|name, ttl, data|
  862. yield name, ttl, data
  863. }
  864. end
  865. def add_authority(name, ttl, data)
  866. @authority << [Name.create(name), ttl, data]
  867. end
  868. def each_authority
  869. @authority.each {|name, ttl, data|
  870. yield name, ttl, data
  871. }
  872. end
  873. def add_additional(name, ttl, data)
  874. @additional << [Name.create(name), ttl, data]
  875. end
  876. def each_additional
  877. @additional.each {|name, ttl, data|
  878. yield name, ttl, data
  879. }
  880. end
  881. def each_resource
  882. each_answer {|name, ttl, data| yield name, ttl, data}
  883. each_authority {|name, ttl, data| yield name, ttl, data}
  884. each_additional {|name, ttl, data| yield name, ttl, data}
  885. end
  886. def encode
  887. return MessageEncoder.new {|msg|
  888. msg.put_pack('nnnnnn',
  889. @id,
  890. (@qr & 1) << 15 |
  891. (@opcode & 15) << 11 |
  892. (@aa & 1) << 10 |
  893. (@tc & 1) << 9 |
  894. (@rd & 1) << 8 |
  895. (@ra & 1) << 7 |
  896. (@rcode & 15),
  897. @question.length,
  898. @answer.length,
  899. @authority.length,
  900. @additional.length)
  901. @question.each {|q|
  902. name, typeclass = q
  903. msg.put_name(name)
  904. msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue)
  905. }
  906. [@answer, @authority, @additional].each {|rr|
  907. rr.each {|r|
  908. name, ttl, data = r
  909. msg.put_name(name)
  910. msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl)
  911. msg.put_length16 {data.encode_rdata(msg)}
  912. }
  913. }
  914. }.to_s
  915. end
  916. class MessageEncoder
  917. def initialize
  918. @data = ''
  919. @names = {}
  920. yield self
  921. end
  922. def to_s
  923. return @data
  924. end
  925. def put_bytes(d)
  926. @data << d
  927. end
  928. def put_pack(template, *d)
  929. @data << d.pack(template)
  930. end
  931. def put_length16
  932. length_index = @data.length
  933. @data << "\0\0"
  934. data_start = @data.length
  935. yield
  936. data_end = @data.length
  937. @data[length_index, 2] = [data_end - data_start].pack("n")
  938. end
  939. def put_string(d)
  940. self.put_pack("C", d.length)
  941. @data << d
  942. end
  943. def put_name(d)
  944. put_labels(d.to_a)
  945. end
  946. def put_labels(d)
  947. d.each_index {|i|
  948. domain = d[i..-1]
  949. if idx = @names[domain]
  950. self.put_pack("n", 0xc000 | idx)
  951. return
  952. else
  953. @names[domain] = @data.length
  954. self.put_label(d[i])
  955. end
  956. }
  957. @data << "\0"
  958. end
  959. def put_label(d)
  960. self.put_string(d.string)
  961. end
  962. end
  963. def Message.decode(m)
  964. o = Message.new(0)
  965. MessageDecoder.new(m) {|msg|
  966. id, flag, qdcount, ancount, nscount, arcount =
  967. msg.get_unpack('nnnnnn')
  968. o.id = id
  969. o.qr = (flag >> 15) & 1
  970. o.opcode = (flag >> 11) & 15
  971. o.aa = (flag >> 10) & 1
  972. o.tc = (flag >> 9) & 1
  973. o.rd = (flag >> 8) & 1
  974. o.ra = (flag >> 7) & 1
  975. o.rcode = flag & 15
  976. (1..qdcount).each {
  977. name, typeclass = msg.get_question
  978. o.add_question(name, typeclass)
  979. }
  980. (1..ancount).each {
  981. name, ttl, data = msg.get_rr
  982. o.add_answer(name, ttl, data)
  983. }
  984. (1..nscount).each {
  985. name, ttl, data = msg.get_rr
  986. o.add_authority(name, ttl, data)
  987. }
  988. (1..arcount).each {
  989. name, ttl, data = msg.get_rr
  990. o.add_additional(name, ttl, data)
  991. }
  992. }
  993. return o
  994. end
  995. class MessageDecoder
  996. def initialize(data)
  997. @data = data
  998. @index = 0
  999. @limit = data.length
  1000. yield self
  1001. end
  1002. def get_length16
  1003. len, = self.get_unpack('n')
  1004. save_limit = @limit
  1005. @limit = @index + len
  1006. d = yield len
  1007. if @index < @limit
  1008. raise DecodeError.new("junk exist")
  1009. elsif @limit < @index
  1010. raise DecodeError.new("limit exceed")
  1011. end
  1012. @limit = save_limit
  1013. return d
  1014. end
  1015. def get_bytes(len = @limit - @index)
  1016. d = @data[@index, len]
  1017. @index += len
  1018. return d
  1019. end
  1020. def get_unpack(template)
  1021. len = 0
  1022. template.each_byte {|byte|
  1023. case byte
  1024. when ?c, ?C
  1025. len += 1
  1026. when ?n
  1027. len += 2
  1028. when ?N
  1029. len += 4
  1030. else
  1031. raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
  1032. end
  1033. }
  1034. raise DecodeError.new("limit exceed") if @limit < @index + len
  1035. arr = @data.unpack("@#{@index}#{template}")
  1036. @index += len
  1037. return arr
  1038. end
  1039. def get_string
  1040. len = @data[@index]
  1041. raise DecodeError.new("limit exceed") if @limit < @index + 1 + len
  1042. d = @data[@index + 1, len]
  1043. @index += 1 + len
  1044. return d
  1045. end
  1046. def get_name
  1047. return Name.new(self.get_labels)
  1048. end
  1049. def get_labels(limit=nil)
  1050. limit = @index if !limit || @index < limit
  1051. d = []
  1052. while true
  1053. case @data[@index]
  1054. when 0
  1055. @index += 1
  1056. return d
  1057. when 192..255
  1058. idx = self.get_unpack('n')[0] & 0x3fff
  1059. if limit <= idx
  1060. raise DecodeError.new("non-backward name pointer")
  1061. end
  1062. save_index = @index
  1063. @index = idx
  1064. d += self.get_labels(limit)
  1065. @index = save_index
  1066. return d
  1067. else
  1068. d << self.get_label
  1069. end
  1070. end
  1071. return d
  1072. end
  1073. def get_label
  1074. return Label::Str.new(self.get_string)
  1075. end
  1076. def get_question
  1077. name = self.get_name
  1078. type, klass = self.get_unpack("nn")
  1079. return name, Resource.get_class(type, klass)
  1080. end
  1081. def get_rr
  1082. name = self.get_name
  1083. type, klass, ttl = self.get_unpack('nnN')
  1084. typeclass = Resource.get_class(type, klass)
  1085. return name, ttl, self.get_length16 {typeclass.decode_rdata(self)}
  1086. end
  1087. end
  1088. end
  1089. class Query
  1090. def encode_rdata(msg)
  1091. raise EncodeError.new("#{self.class} is query.")
  1092. end
  1093. def self.decode_rdata(msg)
  1094. raise DecodeError.new("#{self.class} is query.")
  1095. end
  1096. end
  1097. class Resource < Query
  1098. ClassHash = {}
  1099. def encode_rdata(msg)
  1100. raise NotImplementedError.new
  1101. end
  1102. def self.decode_rdata(msg)
  1103. raise NotImplementedError.new
  1104. end
  1105. def ==(other)
  1106. return self.class == other.class &&
  1107. self.instance_variables == other.instance_variables &&
  1108. self.instance_variables.collect {|name| self.instance_eval name} ==
  1109. other.instance_variables.collect {|name| other.instance_eval name}
  1110. end
  1111. def eql?(other)
  1112. return self == other
  1113. end
  1114. def hash
  1115. h = 0
  1116. self.instance_variables.each {|name|
  1117. h ^= self.instance_eval("#{name}.hash")
  1118. }
  1119. return h
  1120. end
  1121. def self.get_class(type_value, class_value)
  1122. return ClassHash[[type_value, class_value]] ||
  1123. Generic.create(type_value, class_value)
  1124. end
  1125. class Generic < Resource
  1126. def initialize(data)
  1127. @data = data
  1128. end
  1129. attr_reader :data
  1130. def encode_rdata(msg)
  1131. msg.put_bytes(data)
  1132. end
  1133. def self.decode_rdata(msg)
  1134. return self.new(msg.get_bytes)
  1135. end
  1136. def self.create(type_value, class_value)
  1137. c = Class.new(Generic)
  1138. c.const_set(:TypeValue, type_value)
  1139. c.const_set(:ClassValue, class_value)
  1140. Generic.const_set("Type#{type_value}_Class#{class_value}", c)
  1141. ClassHash[[type_value, class_value]] = c
  1142. return c
  1143. end
  1144. end
  1145. class DomainName < Resource
  1146. def initialize(name)
  1147. @name = name
  1148. end
  1149. attr_reader :name
  1150. def encode_rdata(msg)
  1151. msg.put_name(@name)
  1152. end
  1153. def self.decode_rdata(msg)
  1154. return self.new(msg.get_name)
  1155. end
  1156. end
  1157. # Standard (class generic) RRs
  1158. ClassValue = nil
  1159. class NS < DomainName
  1160. TypeValue = 2
  1161. end
  1162. class CNAME < DomainName
  1163. TypeValue = 5
  1164. end
  1165. class SOA < Resource
  1166. TypeValue = 6
  1167. def initialize(mname, rname, serial, refresh, retry_, expire, minimum)
  1168. @mname = mname
  1169. @rname = rname
  1170. @serial = serial
  1171. @refresh = refresh
  1172. @retry = retry_
  1173. @expire = expire
  1174. @minimum = minimum
  1175. end
  1176. attr_reader :mname, :rname, :serial, :refresh, :retry, :expire, :minimum
  1177. def encode_rdata(msg)
  1178. msg.put_name(@mname)
  1179. msg.put_name(@rname)
  1180. msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum)
  1181. end
  1182. def self.decode_rdata(msg)
  1183. mname = msg.get_name
  1184. rname = msg.get_name
  1185. serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN')
  1186. return self.new(
  1187. mname, rname, serial, refresh, retry_, expire, minimum)
  1188. end
  1189. end
  1190. class PTR < DomainName
  1191. TypeValue = 12
  1192. end
  1193. class HINFO < Resource
  1194. TypeValue = 13
  1195. def initialize(cpu, os)
  1196. @cpu = cpu
  1197. @os = os
  1198. end
  1199. attr_reader :cpu, :os
  1200. def encode_rdata(msg)
  1201. msg.put_string(@cpu)
  1202. msg.put_string(@os)
  1203. end
  1204. def self.decode_rdata(msg)
  1205. cpu = msg.get_string
  1206. os = msg.get_string
  1207. return self.new(cpu, os)
  1208. end
  1209. end
  1210. class MINFO < Resource
  1211. TypeValue = 14
  1212. def initialize(rmailbx, emailbx)
  1213. @rmailbx = rmailbx
  1214. @emailbx = emailbx
  1215. end
  1216. attr_reader :rmailbx, :emailbx
  1217. def encode_rdata(msg)
  1218. msg.put_name(@rmailbx)
  1219. msg.put_name(@emailbx)
  1220. end
  1221. def self.decode_rdata(msg)
  1222. rmailbx = msg.get_string
  1223. emailbx = msg.get_string
  1224. return self.new(rmailbx, emailbx)
  1225. end
  1226. end
  1227. class MX < Resource
  1228. TypeValue= 15
  1229. def initialize(preference, exchange)
  1230. @preference = preference
  1231. @exchange = exchange
  1232. end
  1233. attr_reader :preference, :exchange
  1234. def encode_rdata(msg)
  1235. msg.put_pack('n', @preference)
  1236. msg.put_name(@exchange)
  1237. end
  1238. def self.decode_rdata(msg)
  1239. preference, = msg.get_unpack('n')
  1240. exchange = msg.get_name
  1241. return self.new(preference, exchange)
  1242. end
  1243. end
  1244. class TXT < Resource
  1245. TypeValue = 16
  1246. def initialize(data)
  1247. @data = data
  1248. end
  1249. attr_reader :data
  1250. def encode_rdata(msg)
  1251. msg.put_string(@data)
  1252. end
  1253. def self.decode_rdata(msg)
  1254. data = msg.get_string
  1255. return self.new(data)
  1256. end
  1257. end
  1258. class ANY < Query
  1259. TypeValue = 255
  1260. end
  1261. ClassInsensitiveTypes = [
  1262. NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, ANY
  1263. ]
  1264. # ARPA Internet specific RRs
  1265. module IN
  1266. ClassValue = 1
  1267. ClassInsensitiveTypes.each {|s|
  1268. c = Class.new(s)
  1269. c.const_set(:TypeValue, s::TypeValue)
  1270. c.const_set(:ClassValue, ClassValue)
  1271. ClassHash[[s::TypeValue, ClassValue]] = c
  1272. self.const_set(s.name.sub(/.*::/, ''), c)
  1273. }
  1274. class A < Resource
  1275. ClassHash[[TypeValue = 1, ClassValue = ClassValue]] = self
  1276. def initialize(address)
  1277. @address = IPv4.create(address)
  1278. end
  1279. attr_reader :address
  1280. def encode_rdata(msg)
  1281. msg.put_bytes(@address.address)
  1282. end
  1283. def self.decode_rdata(msg)
  1284. return self.new(IPv4.new(msg.get_bytes(4)))
  1285. end
  1286. end
  1287. class WKS < Resource
  1288. ClassHash[[TypeValue = 11, ClassValue = ClassValue]] = self
  1289. def initialize(address, protocol, bitmap)
  1290. @address = IPv4.create(address)
  1291. @protocol = protocol
  1292. @bitmap = bitmap
  1293. end
  1294. attr_reader :address, :protocol, :bitmap
  1295. def encode_rdata(msg)
  1296. msg.put_bytes(@address.address)
  1297. msg.put_pack("n", @protocol)
  1298. msg.put_bytes(@bitmap)
  1299. end
  1300. def self.decode_rdata(msg)
  1301. address = IPv4.new(msg.get_bytes(4))
  1302. protocol, = msg.get_unpack("n")
  1303. bitmap = msg.get_bytes
  1304. return self.new(address, protocol, bitmap)
  1305. end
  1306. end
  1307. class AAAA < Resource
  1308. ClassHash[[TypeValue = 28, ClassValue = ClassValue]] = self
  1309. def initialize(address)
  1310. @address = IPv6.create(address)
  1311. end
  1312. attr_reader :address
  1313. def encode_rdata(msg)
  1314. msg.put_bytes(@address.address)
  1315. end
  1316. def self.decode_rdata(msg)
  1317. return self.new(IPv6.new(msg.get_bytes(16)))
  1318. end
  1319. end
  1320. end
  1321. end
  1322. end
  1323. class IPv4
  1324. Regex = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)\z/
  1325. def self.create(arg)
  1326. case arg
  1327. when IPv4
  1328. return arg
  1329. when Regex
  1330. if (0..255) === (a = $1.to_i) &&
  1331. (0..255) === (b = $2.to_i) &&
  1332. (0..255) === (c = $3.to_i) &&
  1333. (0..255) === (d = $4.to_i)
  1334. return self.new([a, b, c, d].pack("CCCC"))
  1335. else
  1336. raise ArgumentError.new("IPv4 address with invalid value: " + arg)
  1337. end
  1338. else
  1339. raise ArgumentError.new("cannot interprete as IPv4 address: #{arg.inspect}")
  1340. end
  1341. end
  1342. def initialize(address)
  1343. unless address.kind_of?(String) && address.length == 4
  1344. raise ArgumentError.new('IPv4 address must be 4 bytes')
  1345. end
  1346. @address = address
  1347. end
  1348. attr_reader :address
  1349. def to_s
  1350. return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC"))
  1351. end
  1352. def inspect
  1353. return "#<#{self.class} #{self.to_s}>"
  1354. end
  1355. def to_name
  1356. return DNS::Name.create(
  1357. '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse)
  1358. end
  1359. def ==(other)
  1360. return @address == other.address
  1361. end
  1362. def eql?(other)
  1363. return self == other
  1364. end
  1365. def hash
  1366. return @address.hash
  1367. end
  1368. end
  1369. class IPv6
  1370. Regex_8Hex = /\A
  1371. (?:[0-9A-Fa-f]{1,4}:){7}
  1372. [0-9A-Fa-f]{1,4}
  1373. \z/x
  1374. Regex_CompressedHex = /\A
  1375. ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
  1376. ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
  1377. \z/x
  1378. Regex_6Hex4Dec = /\A
  1379. ((?:[0-9A-Fa-f]{1,4}:){6,6})
  1380. (\d+)\.(\d+)\.(\d+)\.(\d+)
  1381. \z/x
  1382. Regex_CompressedHex4Dec = /\A
  1383. ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
  1384. ((?:[0-9A-Fa-f]{1,4}:)*)
  1385. (\d+)\.(\d+)\.(\d+)\.(\d+)
  1386. \z/x
  1387. Regex = /
  1388. (?:#{Regex_8Hex.source}) |
  1389. (?:#{Regex_CompressedHex.source}) |
  1390. (?:#{Regex_6Hex4Dec.source}) |
  1391. (?:#{Regex_CompressedHex4Dec.source})/x
  1392. def self.create(arg)
  1393. case arg
  1394. when IPv6
  1395. return arg
  1396. when String
  1397. address = ''
  1398. if Regex_8Hex =~ arg
  1399. arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
  1400. elsif Regex_CompressedHex =~ arg
  1401. prefix = $1
  1402. suffix = $2
  1403. a1 = ''
  1404. a2 = ''
  1405. prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
  1406. suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
  1407. omitlen = 16 - a1.length - a2.length
  1408. address << a1 << "\0" * omitlen << a2
  1409. elsif Regex_6Hex4Dec =~ arg
  1410. prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
  1411. if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
  1412. prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
  1413. address << [a, b, c, d].pack('CCCC')
  1414. else
  1415. raise ArgumentError.new("not numeric IPv6 address: " + arg)
  1416. end
  1417. elsif Regex_CompressedHex4Dec =~ arg
  1418. prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
  1419. if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
  1420. a1 = ''
  1421. a2 = ''
  1422. prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
  1423. suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
  1424. omitlen = 12 - a1.length - a2.length
  1425. address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
  1426. else
  1427. raise ArgumentError.new("not numeric IPv6 address: " + arg)
  1428. end
  1429. else
  1430. raise ArgumentError.new("not numeric IPv6 address: " + arg)
  1431. end
  1432. return IPv6.new(address)
  1433. else
  1434. raise ArgumentError.new("cannot interprete as IPv6 address: #{arg.inspect}")
  1435. end
  1436. end
  1437. def initialize(address)
  1438. unless address.kind_of?(String) && address.length == 16
  1439. raise ArgumentError.new('IPv6 address must be 16 bytes')
  1440. end
  1441. @address = address
  1442. end
  1443. attr_reader :address
  1444. def to_s
  1445. address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn"))
  1446. unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
  1447. address.sub!(/(^|:)0(:|$)/, '::')
  1448. end
  1449. return address
  1450. end
  1451. def inspect
  1452. return "#<#{self.class} #{self.to_s}>"
  1453. end
  1454. def to_name
  1455. # ip6.arpa should be searched too. [RFC3152]
  1456. return DNS::Name.new(
  1457. @address.unpack("H32")[0].split(//).reverse + ['ip6', 'int'])
  1458. end
  1459. def ==(other)
  1460. return @address == other.address
  1461. end
  1462. def eql?(other)
  1463. return self == other
  1464. end
  1465. def hash
  1466. return @address.hash
  1467. end
  1468. end
  1469. DefaultResolver = self.new
  1470. AddressRegex = /(?:#{IPv4::Regex.source})|(?:#{IPv6::Regex.source})/
  1471. end