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

/lib/ruby/1.8/resolv.rb

http://github.com/jruby/jruby
Ruby | 2295 lines | 1599 code | 346 blank | 350 comment | 98 complexity | 281e87abf63b556c3140815ac480dcca MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause, GPL-2.0, JSON, LGPL-2.1
  1. require 'socket'
  2. require 'fcntl'
  3. require 'timeout'
  4. require 'thread'
  5. begin
  6. require 'securerandom'
  7. rescue LoadError
  8. end
  9. # Resolv is a thread-aware DNS resolver library written in Ruby. Resolv can
  10. # handle multiple DNS requests concurrently without blocking. The ruby
  11. # interpreter.
  12. #
  13. # See also resolv-replace.rb to replace the libc resolver with # Resolv.
  14. #
  15. # Resolv can look up various DNS resources using the DNS module directly.
  16. #
  17. # Examples:
  18. #
  19. # p Resolv.getaddress "www.ruby-lang.org"
  20. # p Resolv.getname "210.251.121.214"
  21. #
  22. # Resolv::DNS.open do |dns|
  23. # ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A
  24. # p ress.map { |r| r.address }
  25. # ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX
  26. # p ress.map { |r| [r.exchange.to_s, r.preference] }
  27. # end
  28. #
  29. #
  30. # == Bugs
  31. #
  32. # * NIS is not supported.
  33. # * /etc/nsswitch.conf is not supported.
  34. class Resolv
  35. ##
  36. # Looks up the first IP address for +name+.
  37. def self.getaddress(name)
  38. DefaultResolver.getaddress(name)
  39. end
  40. ##
  41. # Looks up all IP address for +name+.
  42. def self.getaddresses(name)
  43. DefaultResolver.getaddresses(name)
  44. end
  45. ##
  46. # Iterates over all IP addresses for +name+.
  47. def self.each_address(name, &block)
  48. DefaultResolver.each_address(name, &block)
  49. end
  50. ##
  51. # Looks up the hostname of +address+.
  52. def self.getname(address)
  53. DefaultResolver.getname(address)
  54. end
  55. ##
  56. # Looks up all hostnames for +address+.
  57. def self.getnames(address)
  58. DefaultResolver.getnames(address)
  59. end
  60. ##
  61. # Iterates over all hostnames for +address+.
  62. def self.each_name(address, &proc)
  63. DefaultResolver.each_name(address, &proc)
  64. end
  65. ##
  66. # Creates a new Resolv using +resolvers+.
  67. def initialize(resolvers=[Hosts.new, DNS.new])
  68. @resolvers = resolvers
  69. end
  70. ##
  71. # Looks up the first IP address for +name+.
  72. def getaddress(name)
  73. each_address(name) {|address| return address}
  74. raise ResolvError.new("no address for #{name}")
  75. end
  76. ##
  77. # Looks up all IP address for +name+.
  78. def getaddresses(name)
  79. ret = []
  80. each_address(name) {|address| ret << address}
  81. return ret
  82. end
  83. ##
  84. # Iterates over all IP addresses for +name+.
  85. def each_address(name)
  86. if AddressRegex =~ name
  87. yield name
  88. return
  89. end
  90. yielded = false
  91. @resolvers.each {|r|
  92. r.each_address(name) {|address|
  93. yield address.to_s
  94. yielded = true
  95. }
  96. return if yielded
  97. }
  98. end
  99. ##
  100. # Looks up the hostname of +address+.
  101. def getname(address)
  102. each_name(address) {|name| return name}
  103. raise ResolvError.new("no name for #{address}")
  104. end
  105. ##
  106. # Looks up all hostnames for +address+.
  107. def getnames(address)
  108. ret = []
  109. each_name(address) {|name| ret << name}
  110. return ret
  111. end
  112. ##
  113. # Iterates over all hostnames for +address+.
  114. def each_name(address)
  115. yielded = false
  116. @resolvers.each {|r|
  117. r.each_name(address) {|name|
  118. yield name.to_s
  119. yielded = true
  120. }
  121. return if yielded
  122. }
  123. end
  124. ##
  125. # Indicates a failure to resolve a name or address.
  126. class ResolvError < StandardError; end
  127. ##
  128. # Indicates a timeout resolving a name or address.
  129. class ResolvTimeout < TimeoutError; end
  130. ##
  131. # DNS::Hosts is a hostname resolver that uses the system hosts file.
  132. class Hosts
  133. require 'rbconfig'
  134. if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::Config::CONFIG['host_os'] =~ /mswin/
  135. require 'win32/resolv'
  136. DefaultFileName = Win32::Resolv.get_hosts_path
  137. else
  138. DefaultFileName = '/etc/hosts'
  139. end
  140. ##
  141. # Creates a new DNS::Hosts, using +filename+ for its data source.
  142. def initialize(filename = DefaultFileName)
  143. @filename = filename
  144. @mutex = Mutex.new
  145. @initialized = nil
  146. end
  147. def lazy_initialize # :nodoc:
  148. @mutex.synchronize {
  149. unless @initialized
  150. @name2addr = {}
  151. @addr2name = {}
  152. open(@filename) {|f|
  153. f.each {|line|
  154. line.sub!(/#.*/, '')
  155. addr, hostname, *aliases = line.split(/\s+/)
  156. next unless addr
  157. addr.untaint
  158. hostname.untaint
  159. @addr2name[addr] = [] unless @addr2name.include? addr
  160. @addr2name[addr] << hostname
  161. @addr2name[addr] += aliases
  162. @name2addr[hostname] = [] unless @name2addr.include? hostname
  163. @name2addr[hostname] << addr
  164. aliases.each {|n|
  165. n.untaint
  166. @name2addr[n] = [] unless @name2addr.include? n
  167. @name2addr[n] << addr
  168. }
  169. }
  170. }
  171. @name2addr.each {|name, arr| arr.reverse!}
  172. @initialized = true
  173. end
  174. }
  175. self
  176. end
  177. ##
  178. # Gets the IP address of +name+ from the hosts file.
  179. def getaddress(name)
  180. each_address(name) {|address| return address}
  181. raise ResolvError.new("#{@filename} has no name: #{name}")
  182. end
  183. ##
  184. # Gets all IP addresses for +name+ from the hosts file.
  185. def getaddresses(name)
  186. ret = []
  187. each_address(name) {|address| ret << address}
  188. return ret
  189. end
  190. ##
  191. # Iterates over all IP addresses for +name+ retrieved from the hosts file.
  192. def each_address(name, &proc)
  193. lazy_initialize
  194. if @name2addr.include?(name)
  195. @name2addr[name].each(&proc)
  196. end
  197. end
  198. ##
  199. # Gets the hostname of +address+ from the hosts file.
  200. def getname(address)
  201. each_name(address) {|name| return name}
  202. raise ResolvError.new("#{@filename} has no address: #{address}")
  203. end
  204. ##
  205. # Gets all hostnames for +address+ from the hosts file.
  206. def getnames(address)
  207. ret = []
  208. each_name(address) {|name| ret << name}
  209. return ret
  210. end
  211. ##
  212. # Iterates over all hostnames for +address+ retrieved from the hosts file.
  213. def each_name(address, &proc)
  214. lazy_initialize
  215. if @addr2name.include?(address)
  216. @addr2name[address].each(&proc)
  217. end
  218. end
  219. end
  220. ##
  221. # Resolv::DNS is a DNS stub resolver.
  222. #
  223. # Information taken from the following places:
  224. #
  225. # * STD0013
  226. # * RFC 1035
  227. # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
  228. # * etc.
  229. class DNS
  230. ##
  231. # Default DNS Port
  232. Port = 53
  233. ##
  234. # Default DNS UDP packet size
  235. UDPSize = 512
  236. ##
  237. # Group of DNS resolver threads (obsolete)
  238. DNSThreadGroup = ThreadGroup.new
  239. ##
  240. # Creates a new DNS resolver. See Resolv::DNS.new for argument details.
  241. #
  242. # Yields the created DNS resolver to the block, if given, otherwise
  243. # returns it.
  244. def self.open(*args)
  245. dns = new(*args)
  246. return dns unless block_given?
  247. begin
  248. yield dns
  249. ensure
  250. dns.close
  251. end
  252. end
  253. ##
  254. # Creates a new DNS resolver.
  255. #
  256. # +config_info+ can be:
  257. #
  258. # nil:: Uses /etc/resolv.conf.
  259. # String:: Path to a file using /etc/resolv.conf's format.
  260. # Hash:: Must contain :nameserver, :search and :ndots keys.
  261. #
  262. # Example:
  263. #
  264. # Resolv::DNS.new(:nameserver => ['210.251.121.21'],
  265. # :search => ['ruby-lang.org'],
  266. # :ndots => 1)
  267. def initialize(config_info=nil)
  268. @mutex = Mutex.new
  269. @config = Config.new(config_info)
  270. @initialized = nil
  271. end
  272. def lazy_initialize # :nodoc:
  273. @mutex.synchronize {
  274. unless @initialized
  275. @config.lazy_initialize
  276. @initialized = true
  277. end
  278. }
  279. self
  280. end
  281. ##
  282. # Closes the DNS resolver.
  283. def close
  284. @mutex.synchronize {
  285. if @initialized
  286. @initialized = false
  287. end
  288. }
  289. end
  290. ##
  291. # Gets the IP address of +name+ from the DNS resolver.
  292. #
  293. # +name+ can be a Resolv::DNS::Name or a String. Retrieved address will
  294. # be a Resolv::IPv4 or Resolv::IPv6
  295. def getaddress(name)
  296. each_address(name) {|address| return address}
  297. raise ResolvError.new("DNS result has no information for #{name}")
  298. end
  299. ##
  300. # Gets all IP addresses for +name+ from the DNS resolver.
  301. #
  302. # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will
  303. # be a Resolv::IPv4 or Resolv::IPv6
  304. def getaddresses(name)
  305. ret = []
  306. each_address(name) {|address| ret << address}
  307. return ret
  308. end
  309. ##
  310. # Iterates over all IP addresses for +name+ retrieved from the DNS
  311. # resolver.
  312. #
  313. # +name+ can be a Resolv::DNS::Name or a String. Retrieved addresses will
  314. # be a Resolv::IPv4 or Resolv::IPv6
  315. def each_address(name)
  316. each_resource(name, Resource::IN::A) {|resource| yield resource.address}
  317. each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
  318. end
  319. ##
  320. # Gets the hostname for +address+ from the DNS resolver.
  321. #
  322. # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved
  323. # name will be a Resolv::DNS::Name.
  324. def getname(address)
  325. each_name(address) {|name| return name}
  326. raise ResolvError.new("DNS result has no information for #{address}")
  327. end
  328. ##
  329. # Gets all hostnames for +address+ from the DNS resolver.
  330. #
  331. # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved
  332. # names will be Resolv::DNS::Name instances.
  333. def getnames(address)
  334. ret = []
  335. each_name(address) {|name| ret << name}
  336. return ret
  337. end
  338. ##
  339. # Iterates over all hostnames for +address+ retrieved from the DNS
  340. # resolver.
  341. #
  342. # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved
  343. # names will be Resolv::DNS::Name instances.
  344. def each_name(address)
  345. case address
  346. when Name
  347. ptr = address
  348. when IPv4::Regex
  349. ptr = IPv4.create(address).to_name
  350. when IPv6::Regex
  351. ptr = IPv6.create(address).to_name
  352. else
  353. raise ResolvError.new("cannot interpret as address: #{address}")
  354. end
  355. each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
  356. end
  357. ##
  358. # Look up the +typeclass+ DNS resource of +name+.
  359. #
  360. # +name+ must be a Resolv::DNS::Name or a String.
  361. #
  362. # +typeclass+ should be one of the following:
  363. #
  364. # * Resolv::DNS::Resource::IN::A
  365. # * Resolv::DNS::Resource::IN::AAAA
  366. # * Resolv::DNS::Resource::IN::ANY
  367. # * Resolv::DNS::Resource::IN::CNAME
  368. # * Resolv::DNS::Resource::IN::HINFO
  369. # * Resolv::DNS::Resource::IN::MINFO
  370. # * Resolv::DNS::Resource::IN::MX
  371. # * Resolv::DNS::Resource::IN::NS
  372. # * Resolv::DNS::Resource::IN::PTR
  373. # * Resolv::DNS::Resource::IN::SOA
  374. # * Resolv::DNS::Resource::IN::TXT
  375. # * Resolv::DNS::Resource::IN::WKS
  376. #
  377. # Returned resource is represented as a Resolv::DNS::Resource instance,
  378. # i.e. Resolv::DNS::Resource::IN::A.
  379. def getresource(name, typeclass)
  380. each_resource(name, typeclass) {|resource| return resource}
  381. raise ResolvError.new("DNS result has no information for #{name}")
  382. end
  383. ##
  384. # Looks up all +typeclass+ DNS resources for +name+. See #getresource for
  385. # argument details.
  386. def getresources(name, typeclass)
  387. ret = []
  388. each_resource(name, typeclass) {|resource| ret << resource}
  389. return ret
  390. end
  391. ##
  392. # Iterates over all +typeclass+ DNS resources for +name+. See
  393. # #getresource for argument details.
  394. def each_resource(name, typeclass, &proc)
  395. lazy_initialize
  396. requester = make_requester
  397. senders = {}
  398. begin
  399. @config.resolv(name) {|candidate, tout, nameserver|
  400. msg = Message.new
  401. msg.rd = 1
  402. msg.add_question(candidate, typeclass)
  403. unless sender = senders[[candidate, nameserver]]
  404. sender = senders[[candidate, nameserver]] =
  405. requester.sender(msg, candidate, nameserver)
  406. end
  407. reply, reply_name = requester.request(sender, tout)
  408. case reply.rcode
  409. when RCode::NoError
  410. extract_resources(reply, reply_name, typeclass, &proc)
  411. return
  412. when RCode::NXDomain
  413. raise Config::NXDomain.new(reply_name.to_s)
  414. else
  415. raise Config::OtherResolvError.new(reply_name.to_s)
  416. end
  417. }
  418. ensure
  419. requester.close
  420. end
  421. end
  422. def make_requester # :nodoc:
  423. nameserver_port = @config.nameserver_port
  424. if nameserver_port.length == 1
  425. Requester::ConnectedUDP.new(*nameserver_port[0])
  426. else
  427. Requester::UnconnectedUDP.new(*nameserver_port)
  428. end
  429. end
  430. def extract_resources(msg, name, typeclass) # :nodoc:
  431. if typeclass < Resource::ANY
  432. n0 = Name.create(name)
  433. msg.each_answer {|n, ttl, data|
  434. yield data if n0 == n
  435. }
  436. end
  437. yielded = false
  438. n0 = Name.create(name)
  439. msg.each_answer {|n, ttl, data|
  440. if n0 == n
  441. case data
  442. when typeclass
  443. yield data
  444. yielded = true
  445. when Resource::CNAME
  446. n0 = data.name
  447. end
  448. end
  449. }
  450. return if yielded
  451. msg.each_answer {|n, ttl, data|
  452. if n0 == n
  453. case data
  454. when typeclass
  455. yield data
  456. end
  457. end
  458. }
  459. end
  460. if defined? SecureRandom
  461. def self.random(arg) # :nodoc:
  462. begin
  463. SecureRandom.random_number(arg)
  464. rescue NotImplementedError
  465. rand(arg)
  466. end
  467. end
  468. else
  469. def self.random(arg) # :nodoc:
  470. rand(arg)
  471. end
  472. end
  473. def self.rangerand(range) # :nodoc:
  474. base = range.begin
  475. len = range.end - range.begin
  476. if !range.exclude_end?
  477. len += 1
  478. end
  479. base + random(len)
  480. end
  481. RequestID = {}
  482. RequestIDMutex = Mutex.new
  483. def self.allocate_request_id(host, port) # :nodoc:
  484. id = nil
  485. RequestIDMutex.synchronize {
  486. h = (RequestID[[host, port]] ||= {})
  487. begin
  488. id = rangerand(0x0000..0xffff)
  489. end while h[id]
  490. h[id] = true
  491. }
  492. id
  493. end
  494. def self.free_request_id(host, port, id) # :nodoc:
  495. RequestIDMutex.synchronize {
  496. key = [host, port]
  497. if h = RequestID[key]
  498. h.delete id
  499. if h.empty?
  500. RequestID.delete key
  501. end
  502. end
  503. }
  504. end
  505. def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
  506. begin
  507. port = rangerand(1024..65535)
  508. udpsock.bind(bind_host, port)
  509. rescue Errno::EADDRINUSE
  510. retry
  511. end
  512. end
  513. class Requester # :nodoc:
  514. def initialize
  515. @senders = {}
  516. @socks = nil
  517. end
  518. def request(sender, tout)
  519. timelimit = Time.now + tout
  520. sender.send
  521. while true
  522. now = Time.now
  523. timeout = timelimit - now
  524. if timeout <= 0
  525. raise ResolvTimeout
  526. end
  527. select_result = IO.select(@socks, nil, nil, timeout)
  528. if !select_result
  529. raise ResolvTimeout
  530. end
  531. reply, from = recv_reply(select_result[0])
  532. begin
  533. msg = Message.decode(reply)
  534. rescue DecodeError
  535. next # broken DNS message ignored
  536. end
  537. if s = @senders[[from,msg.id]]
  538. break
  539. else
  540. # unexpected DNS message ignored
  541. end
  542. end
  543. return msg, s.data
  544. end
  545. def close
  546. socks = @socks
  547. @socks = nil
  548. if socks
  549. socks.each {|sock| sock.close }
  550. end
  551. end
  552. class Sender # :nodoc:
  553. def initialize(msg, data, sock)
  554. @msg = msg
  555. @data = data
  556. @sock = sock
  557. end
  558. end
  559. class UnconnectedUDP < Requester # :nodoc:
  560. def initialize(*nameserver_port)
  561. super()
  562. @nameserver_port = nameserver_port
  563. @socks_hash = {}
  564. @socks = []
  565. nameserver_port.each {|host, port|
  566. if host.index(':')
  567. bind_host = "::"
  568. af = Socket::AF_INET6
  569. else
  570. bind_host = "0.0.0.0"
  571. af = Socket::AF_INET
  572. end
  573. next if @socks_hash[bind_host]
  574. sock = UDPSocket.new(af)
  575. sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  576. DNS.bind_random_port(sock, bind_host)
  577. @socks << sock
  578. @socks_hash[bind_host] = sock
  579. }
  580. end
  581. def recv_reply(readable_socks)
  582. reply, from = readable_socks[0].recvfrom(UDPSize)
  583. return reply, [from[3],from[1]]
  584. end
  585. def sender(msg, data, host, port=Port)
  586. service = [host, port]
  587. id = DNS.allocate_request_id(host, port)
  588. request = msg.encode
  589. request[0,2] = [id].pack('n')
  590. sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
  591. return @senders[[service, id]] =
  592. Sender.new(request, data, sock, host, port)
  593. end
  594. def close
  595. super
  596. @senders.each_key {|service, id|
  597. DNS.free_request_id(service[0], service[1], id)
  598. }
  599. end
  600. class Sender < Requester::Sender # :nodoc:
  601. def initialize(msg, data, sock, host, port)
  602. super(msg, data, sock)
  603. @host = host
  604. @port = port
  605. end
  606. attr_reader :data
  607. def send
  608. @sock.send(@msg, 0, @host, @port)
  609. end
  610. end
  611. end
  612. class ConnectedUDP < Requester # :nodoc:
  613. def initialize(host, port=Port)
  614. super()
  615. @host = host
  616. @port = port
  617. is_ipv6 = host.index(':')
  618. sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
  619. @socks = [sock]
  620. sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  621. DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
  622. sock.connect(host, port)
  623. end
  624. def recv_reply(readable_socks)
  625. reply = readable_socks[0].recv(UDPSize)
  626. return reply, nil
  627. end
  628. def sender(msg, data, host=@host, port=@port)
  629. unless host == @host && port == @port
  630. raise RequestError.new("host/port don't match: #{host}:#{port}")
  631. end
  632. id = DNS.allocate_request_id(@host, @port)
  633. request = msg.encode
  634. request[0,2] = [id].pack('n')
  635. return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
  636. end
  637. def close
  638. super
  639. @senders.each_key {|from, id|
  640. DNS.free_request_id(@host, @port, id)
  641. }
  642. end
  643. class Sender < Requester::Sender # :nodoc:
  644. def send
  645. @sock.send(@msg, 0)
  646. end
  647. attr_reader :data
  648. end
  649. end
  650. class TCP < Requester # :nodoc:
  651. def initialize(host, port=Port)
  652. super()
  653. @host = host
  654. @port = port
  655. sock = TCPSocket.new(@host, @port)
  656. @socks = [sock]
  657. sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  658. @senders = {}
  659. end
  660. def recv_reply(readable_socks)
  661. len = readable_socks[0].read(2).unpack('n')[0]
  662. reply = @socks[0].read(len)
  663. return reply, nil
  664. end
  665. def sender(msg, data, host=@host, port=@port)
  666. unless host == @host && port == @port
  667. raise RequestError.new("host/port don't match: #{host}:#{port}")
  668. end
  669. id = DNS.allocate_request_id(@host, @port)
  670. request = msg.encode
  671. request[0,2] = [request.length, id].pack('nn')
  672. return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
  673. end
  674. class Sender < Requester::Sender # :nodoc:
  675. def send
  676. @sock.print(@msg)
  677. @sock.flush
  678. end
  679. attr_reader :data
  680. end
  681. def close
  682. super
  683. @senders.each_key {|from,id|
  684. DNS.free_request_id(@host, @port, id)
  685. }
  686. end
  687. end
  688. ##
  689. # Indicates a problem with the DNS request.
  690. class RequestError < StandardError
  691. end
  692. end
  693. class Config # :nodoc:
  694. def initialize(config_info=nil)
  695. @mutex = Mutex.new
  696. @config_info = config_info
  697. @initialized = nil
  698. end
  699. def Config.parse_resolv_conf(filename)
  700. nameserver = []
  701. search = nil
  702. ndots = 1
  703. open(filename) {|f|
  704. f.each {|line|
  705. line.sub!(/[#;].*/, '')
  706. keyword, *args = line.split(/\s+/)
  707. args.each { |arg|
  708. arg.untaint
  709. }
  710. next unless keyword
  711. case keyword
  712. when 'nameserver'
  713. nameserver += args
  714. when 'domain'
  715. next if args.empty?
  716. search = [args[0]]
  717. when 'search'
  718. next if args.empty?
  719. search = args
  720. when 'options'
  721. args.each {|arg|
  722. case arg
  723. when /\Andots:(\d+)\z/
  724. ndots = $1.to_i
  725. end
  726. }
  727. end
  728. }
  729. }
  730. return { :nameserver => nameserver, :search => search, :ndots => ndots }
  731. end
  732. def Config.default_config_hash(filename="/etc/resolv.conf")
  733. if File.exist? filename
  734. config_hash = Config.parse_resolv_conf(filename)
  735. else
  736. require 'rbconfig'
  737. if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM || ::Config::CONFIG['host_os'] =~ /mswin/
  738. require 'win32/resolv'
  739. search, nameserver = Win32::Resolv.get_resolv_info
  740. config_hash = {}
  741. config_hash[:nameserver] = nameserver if nameserver
  742. config_hash[:search] = [search].flatten if search
  743. end
  744. end
  745. config_hash
  746. end
  747. def lazy_initialize
  748. @mutex.synchronize {
  749. unless @initialized
  750. @nameserver = []
  751. @search = nil
  752. @ndots = 1
  753. case @config_info
  754. when nil
  755. config_hash = Config.default_config_hash
  756. when String
  757. config_hash = Config.parse_resolv_conf(@config_info)
  758. when Hash
  759. config_hash = @config_info.dup
  760. if String === config_hash[:nameserver]
  761. config_hash[:nameserver] = [config_hash[:nameserver]]
  762. end
  763. if String === config_hash[:search]
  764. config_hash[:search] = [config_hash[:search]]
  765. end
  766. else
  767. raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
  768. end
  769. @nameserver = config_hash[:nameserver] if config_hash.include? :nameserver
  770. @search = config_hash[:search] if config_hash.include? :search
  771. @ndots = config_hash[:ndots] if config_hash.include? :ndots
  772. @nameserver = ['0.0.0.0'] if @nameserver.empty?
  773. if @search
  774. @search = @search.map {|arg| Label.split(arg) }
  775. else
  776. hostname = Socket.gethostname
  777. if /\./ =~ hostname
  778. @search = [Label.split($')]
  779. else
  780. @search = [[]]
  781. end
  782. end
  783. if !@nameserver.kind_of?(Array) ||
  784. !@nameserver.all? {|ns| String === ns }
  785. raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}")
  786. end
  787. if !@search.kind_of?(Array) ||
  788. !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
  789. raise ArgumentError.new("invalid search config: #{@search.inspect}")
  790. end
  791. if !@ndots.kind_of?(Integer)
  792. raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
  793. end
  794. @initialized = true
  795. end
  796. }
  797. self
  798. end
  799. def single?
  800. lazy_initialize
  801. if @nameserver.length == 1
  802. return @nameserver[0]
  803. else
  804. return nil
  805. end
  806. end
  807. def nameserver_port
  808. lazy_initialize
  809. @nameserver_port ||= @nameserver.map {|i| [i, Port] }
  810. @nameserver_port
  811. end
  812. def generate_candidates(name)
  813. candidates = nil
  814. name = Name.create(name)
  815. if name.absolute?
  816. candidates = [name]
  817. else
  818. if @ndots <= name.length - 1
  819. candidates = [Name.new(name.to_a)]
  820. else
  821. candidates = []
  822. end
  823. candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
  824. end
  825. return candidates
  826. end
  827. InitialTimeout = 5
  828. def generate_timeouts
  829. ts = [InitialTimeout]
  830. ts << ts[-1] * 2 / @nameserver.length
  831. ts << ts[-1] * 2
  832. ts << ts[-1] * 2
  833. return ts
  834. end
  835. def resolv(name)
  836. candidates = generate_candidates(name)
  837. timeouts = generate_timeouts
  838. begin
  839. candidates.each {|candidate|
  840. begin
  841. timeouts.each {|tout|
  842. @nameserver.each {|nameserver|
  843. begin
  844. yield candidate, tout, nameserver
  845. rescue ResolvTimeout
  846. end
  847. }
  848. }
  849. raise ResolvError.new("DNS resolv timeout: #{name}")
  850. rescue NXDomain
  851. end
  852. }
  853. rescue ResolvError
  854. end
  855. end
  856. ##
  857. # Indicates no such domain was found.
  858. class NXDomain < ResolvError
  859. end
  860. ##
  861. # Indicates some other unhandled resolver error was encountered.
  862. class OtherResolvError < ResolvError
  863. end
  864. end
  865. module OpCode # :nodoc:
  866. Query = 0
  867. IQuery = 1
  868. Status = 2
  869. Notify = 4
  870. Update = 5
  871. end
  872. module RCode # :nodoc:
  873. NoError = 0
  874. FormErr = 1
  875. ServFail = 2
  876. NXDomain = 3
  877. NotImp = 4
  878. Refused = 5
  879. YXDomain = 6
  880. YXRRSet = 7
  881. NXRRSet = 8
  882. NotAuth = 9
  883. NotZone = 10
  884. BADVERS = 16
  885. BADSIG = 16
  886. BADKEY = 17
  887. BADTIME = 18
  888. BADMODE = 19
  889. BADNAME = 20
  890. BADALG = 21
  891. end
  892. ##
  893. # Indicates that the DNS response was unable to be decoded.
  894. class DecodeError < StandardError
  895. end
  896. ##
  897. # Indicates that the DNS request was unable to be encoded.
  898. class EncodeError < StandardError
  899. end
  900. module Label # :nodoc:
  901. def self.split(arg)
  902. labels = []
  903. arg.scan(/[^\.]+/) {labels << Str.new($&)}
  904. return labels
  905. end
  906. class Str # :nodoc:
  907. def initialize(string)
  908. @string = string
  909. @downcase = string.downcase
  910. end
  911. attr_reader :string, :downcase
  912. def to_s
  913. return @string
  914. end
  915. def inspect
  916. return "#<#{self.class} #{self.to_s}>"
  917. end
  918. def ==(other)
  919. return @downcase == other.downcase
  920. end
  921. def eql?(other)
  922. return self == other
  923. end
  924. def hash
  925. return @downcase.hash
  926. end
  927. end
  928. end
  929. ##
  930. # A representation of a DNS name.
  931. class Name
  932. ##
  933. # Creates a new DNS name from +arg+. +arg+ can be:
  934. #
  935. # Name:: returns +arg+.
  936. # String:: Creates a new Name.
  937. def self.create(arg)
  938. case arg
  939. when Name
  940. return arg
  941. when String
  942. return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
  943. else
  944. raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
  945. end
  946. end
  947. def initialize(labels, absolute=true) # :nodoc:
  948. @labels = labels
  949. @absolute = absolute
  950. end
  951. def inspect # :nodoc:
  952. "#<#{self.class}: #{self.to_s}#{@absolute ? '.' : ''}>"
  953. end
  954. ##
  955. # True if this name is absolute.
  956. def absolute?
  957. return @absolute
  958. end
  959. def ==(other) # :nodoc:
  960. return false unless Name === other
  961. return @labels.join == other.to_a.join && @absolute == other.absolute?
  962. end
  963. alias eql? == # :nodoc:
  964. ##
  965. # Returns true if +other+ is a subdomain.
  966. #
  967. # Example:
  968. #
  969. # domain = Resolv::DNS::Name.create("y.z")
  970. # p Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true
  971. # p Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true
  972. # p Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false
  973. # p Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false
  974. # p Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false
  975. # p Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false
  976. #
  977. def subdomain_of?(other)
  978. raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other
  979. return false if @absolute != other.absolute?
  980. other_len = other.length
  981. return false if @labels.length <= other_len
  982. return @labels[-other_len, other_len] == other.to_a
  983. end
  984. def hash # :nodoc:
  985. return @labels.hash ^ @absolute.hash
  986. end
  987. def to_a # :nodoc:
  988. return @labels
  989. end
  990. def length # :nodoc:
  991. return @labels.length
  992. end
  993. def [](i) # :nodoc:
  994. return @labels[i]
  995. end
  996. ##
  997. # returns the domain name as a string.
  998. #
  999. # The domain name doesn't have a trailing dot even if the name object is
  1000. # absolute.
  1001. #
  1002. # Example:
  1003. #
  1004. # p Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z"
  1005. # p Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z"
  1006. def to_s
  1007. return @labels.join('.')
  1008. end
  1009. end
  1010. class Message # :nodoc:
  1011. @@identifier = -1
  1012. def initialize(id = (@@identifier += 1) & 0xffff)
  1013. @id = id
  1014. @qr = 0
  1015. @opcode = 0
  1016. @aa = 0
  1017. @tc = 0
  1018. @rd = 0 # recursion desired
  1019. @ra = 0 # recursion available
  1020. @rcode = 0
  1021. @question = []
  1022. @answer = []
  1023. @authority = []
  1024. @additional = []
  1025. end
  1026. attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode
  1027. attr_reader :question, :answer, :authority, :additional
  1028. def ==(other)
  1029. return @id == other.id &&
  1030. @qr == other.qr &&
  1031. @opcode == other.opcode &&
  1032. @aa == other.aa &&
  1033. @tc == other.tc &&
  1034. @rd == other.rd &&
  1035. @ra == other.ra &&
  1036. @rcode == other.rcode &&
  1037. @question == other.question &&
  1038. @answer == other.answer &&
  1039. @authority == other.authority &&
  1040. @additional == other.additional
  1041. end
  1042. def add_question(name, typeclass)
  1043. @question << [Name.create(name), typeclass]
  1044. end
  1045. def each_question
  1046. @question.each {|name, typeclass|
  1047. yield name, typeclass
  1048. }
  1049. end
  1050. def add_answer(name, ttl, data)
  1051. @answer << [Name.create(name), ttl, data]
  1052. end
  1053. def each_answer
  1054. @answer.each {|name, ttl, data|
  1055. yield name, ttl, data
  1056. }
  1057. end
  1058. def add_authority(name, ttl, data)
  1059. @authority << [Name.create(name), ttl, data]
  1060. end
  1061. def each_authority
  1062. @authority.each {|name, ttl, data|
  1063. yield name, ttl, data
  1064. }
  1065. end
  1066. def add_additional(name, ttl, data)
  1067. @additional << [Name.create(name), ttl, data]
  1068. end
  1069. def each_additional
  1070. @additional.each {|name, ttl, data|
  1071. yield name, ttl, data
  1072. }
  1073. end
  1074. def each_resource
  1075. each_answer {|name, ttl, data| yield name, ttl, data}
  1076. each_authority {|name, ttl, data| yield name, ttl, data}
  1077. each_additional {|name, ttl, data| yield name, ttl, data}
  1078. end
  1079. def encode
  1080. return MessageEncoder.new {|msg|
  1081. msg.put_pack('nnnnnn',
  1082. @id,
  1083. (@qr & 1) << 15 |
  1084. (@opcode & 15) << 11 |
  1085. (@aa & 1) << 10 |
  1086. (@tc & 1) << 9 |
  1087. (@rd & 1) << 8 |
  1088. (@ra & 1) << 7 |
  1089. (@rcode & 15),
  1090. @question.length,
  1091. @answer.length,
  1092. @authority.length,
  1093. @additional.length)
  1094. @question.each {|q|
  1095. name, typeclass = q
  1096. msg.put_name(name)
  1097. msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue)
  1098. }
  1099. [@answer, @authority, @additional].each {|rr|
  1100. rr.each {|r|
  1101. name, ttl, data = r
  1102. msg.put_name(name)
  1103. msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl)
  1104. msg.put_length16 {data.encode_rdata(msg)}
  1105. }
  1106. }
  1107. }.to_s
  1108. end
  1109. class MessageEncoder # :nodoc:
  1110. def initialize
  1111. @data = ''
  1112. @names = {}
  1113. yield self
  1114. end
  1115. def to_s
  1116. return @data
  1117. end
  1118. def put_bytes(d)
  1119. @data << d
  1120. end
  1121. def put_pack(template, *d)
  1122. @data << d.pack(template)
  1123. end
  1124. def put_length16
  1125. length_index = @data.length
  1126. @data << "\0\0"
  1127. data_start = @data.length
  1128. yield
  1129. data_end = @data.length
  1130. @data[length_index, 2] = [data_end - data_start].pack("n")
  1131. end
  1132. def put_string(d)
  1133. self.put_pack("C", d.length)
  1134. @data << d
  1135. end
  1136. def put_string_list(ds)
  1137. ds.each {|d|
  1138. self.put_string(d)
  1139. }
  1140. end
  1141. def put_name(d)
  1142. put_labels(d.to_a)
  1143. end
  1144. def put_labels(d)
  1145. d.each_index {|i|
  1146. domain = d[i..-1]
  1147. if idx = @names[domain]
  1148. self.put_pack("n", 0xc000 | idx)
  1149. return
  1150. else
  1151. @names[domain] = @data.length
  1152. self.put_label(d[i])
  1153. end
  1154. }
  1155. @data << "\0"
  1156. end
  1157. def put_label(d)
  1158. self.put_string(d.to_s)
  1159. end
  1160. end
  1161. def Message.decode(m)
  1162. o = Message.new(0)
  1163. MessageDecoder.new(m) {|msg|
  1164. id, flag, qdcount, ancount, nscount, arcount =
  1165. msg.get_unpack('nnnnnn')
  1166. o.id = id
  1167. o.qr = (flag >> 15) & 1
  1168. o.opcode = (flag >> 11) & 15
  1169. o.aa = (flag >> 10) & 1
  1170. o.tc = (flag >> 9) & 1
  1171. o.rd = (flag >> 8) & 1
  1172. o.ra = (flag >> 7) & 1
  1173. o.rcode = flag & 15
  1174. (1..qdcount).each {
  1175. name, typeclass = msg.get_question
  1176. o.add_question(name, typeclass)
  1177. }
  1178. (1..ancount).each {
  1179. name, ttl, data = msg.get_rr
  1180. o.add_answer(name, ttl, data)
  1181. }
  1182. (1..nscount).each {
  1183. name, ttl, data = msg.get_rr
  1184. o.add_authority(name, ttl, data)
  1185. }
  1186. (1..arcount).each {
  1187. name, ttl, data = msg.get_rr
  1188. o.add_additional(name, ttl, data)
  1189. }
  1190. }
  1191. return o
  1192. end
  1193. class MessageDecoder # :nodoc:
  1194. def initialize(data)
  1195. @data = data
  1196. @index = 0
  1197. @limit = data.length
  1198. yield self
  1199. end
  1200. def get_length16
  1201. len, = self.get_unpack('n')
  1202. save_limit = @limit
  1203. @limit = @index + len
  1204. d = yield(len)
  1205. if @index < @limit
  1206. raise DecodeError.new("junk exists")
  1207. elsif @limit < @index
  1208. raise DecodeError.new("limit exceeded")
  1209. end
  1210. @limit = save_limit
  1211. return d
  1212. end
  1213. def get_bytes(len = @limit - @index)
  1214. d = @data[@index, len]
  1215. @index += len
  1216. return d
  1217. end
  1218. def get_unpack(template)
  1219. len = 0
  1220. template.each_byte {|byte|
  1221. case byte
  1222. when ?c, ?C
  1223. len += 1
  1224. when ?n
  1225. len += 2
  1226. when ?N
  1227. len += 4
  1228. else
  1229. raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
  1230. end
  1231. }
  1232. raise DecodeError.new("limit exceeded") if @limit < @index + len
  1233. arr = @data.unpack("@#{@index}#{template}")
  1234. @index += len
  1235. return arr
  1236. end
  1237. def get_string
  1238. len = @data[@index]
  1239. raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len
  1240. d = @data[@index + 1, len]
  1241. @index += 1 + len
  1242. return d
  1243. end
  1244. def get_string_list
  1245. strings = []
  1246. while @index < @limit
  1247. strings << self.get_string
  1248. end
  1249. strings
  1250. end
  1251. def get_name
  1252. return Name.new(self.get_labels)
  1253. end
  1254. def get_labels(limit=nil)
  1255. limit = @index if !limit || @index < limit
  1256. d = []
  1257. while true
  1258. case @data[@index]
  1259. when 0
  1260. @index += 1
  1261. return d
  1262. when 192..255
  1263. idx = self.get_unpack('n')[0] & 0x3fff
  1264. if limit <= idx
  1265. raise DecodeError.new("non-backward name pointer")
  1266. end
  1267. save_index = @index
  1268. @index = idx
  1269. d += self.get_labels(limit)
  1270. @index = save_index
  1271. return d
  1272. else
  1273. d << self.get_label
  1274. end
  1275. end
  1276. return d
  1277. end
  1278. def get_label
  1279. return Label::Str.new(self.get_string)
  1280. end
  1281. def get_question
  1282. name = self.get_name
  1283. type, klass = self.get_unpack("nn")
  1284. return name, Resource.get_class(type, klass)
  1285. end
  1286. def get_rr
  1287. name = self.get_name
  1288. type, klass, ttl = self.get_unpack('nnN')
  1289. typeclass = Resource.get_class(type, klass)
  1290. return name, ttl, self.get_length16 {typeclass.decode_rdata(self)}
  1291. end
  1292. end
  1293. end
  1294. ##
  1295. # A DNS query abstract class.
  1296. class Query
  1297. def encode_rdata(msg) # :nodoc:
  1298. raise EncodeError.new("#{self.class} is query.")
  1299. end
  1300. def self.decode_rdata(msg) # :nodoc:
  1301. raise DecodeError.new("#{self.class} is query.")
  1302. end
  1303. end
  1304. ##
  1305. # A DNS resource abstract class.
  1306. class Resource < Query
  1307. ##
  1308. # Remaining Time To Live for this Resource.
  1309. attr_reader :ttl
  1310. ClassHash = {} # :nodoc:
  1311. def encode_rdata(msg) # :nodoc:
  1312. raise NotImplementedError.new
  1313. end
  1314. def self.decode_rdata(msg) # :nodoc:
  1315. raise NotImplementedError.new
  1316. end
  1317. def ==(other) # :nodoc:
  1318. return self.class == other.class &&
  1319. self.instance_variables == other.instance_variables &&
  1320. self.instance_variables.collect {|name| self.instance_eval name} ==
  1321. other.instance_variables.collect {|name| other.instance_eval name}
  1322. end
  1323. def eql?(other) # :nodoc:
  1324. return self == other
  1325. end
  1326. def hash # :nodoc:
  1327. h = 0
  1328. self.instance_variables.each {|name|
  1329. h ^= self.instance_eval("#{name}.hash")
  1330. }
  1331. return h
  1332. end
  1333. def self.get_class(type_value, class_value) # :nodoc:
  1334. return ClassHash[[type_value, class_value]] ||
  1335. Generic.create(type_value, class_value)
  1336. end
  1337. ##
  1338. # A generic resource abstract class.
  1339. class Generic < Resource
  1340. ##
  1341. # Creates a new generic resource.
  1342. def initialize(data)
  1343. @data = data
  1344. end
  1345. ##
  1346. # Data for this generic resource.
  1347. attr_reader :data
  1348. def encode_rdata(msg) # :nodoc:
  1349. msg.put_bytes(data)
  1350. end
  1351. def self.decode_rdata(msg) # :nodoc:
  1352. return self.new(msg.get_bytes)
  1353. end
  1354. def self.create(type_value, class_value) # :nodoc:
  1355. c = Class.new(Generic)
  1356. c.const_set(:TypeValue, type_value)
  1357. c.const_set(:ClassValue, class_value)
  1358. Generic.const_set("Type#{type_value}_Class#{class_value}", c)
  1359. ClassHash[[type_value, class_value]] = c
  1360. return c
  1361. end
  1362. end
  1363. ##
  1364. # Domain Name resource abstract class.
  1365. class DomainName < Resource
  1366. ##
  1367. # Creates a new DomainName from +name+.
  1368. def initialize(name)
  1369. @name = name
  1370. end
  1371. ##
  1372. # The name of this DomainName.
  1373. attr_reader :name
  1374. def encode_rdata(msg) # :nodoc:
  1375. msg.put_name(@name)
  1376. end
  1377. def self.decode_rdata(msg) # :nodoc:
  1378. return self.new(msg.get_name)
  1379. end
  1380. end
  1381. # Standard (class generic) RRs
  1382. ClassValue = nil # :nodoc:
  1383. ##
  1384. # An authoritative name server.
  1385. class NS < DomainName
  1386. TypeValue = 2 # :nodoc:
  1387. end
  1388. ##
  1389. # The canonical name for an alias.
  1390. class CNAME < DomainName
  1391. TypeValue = 5 # :nodoc:
  1392. end
  1393. ##
  1394. # Start Of Authority resource.
  1395. class SOA < Resource
  1396. TypeValue = 6 # :nodoc:
  1397. ##
  1398. # Creates a new SOA record. See the attr documentation for the
  1399. # details of each argument.
  1400. def initialize(mname, rname, serial, refresh, retry_, expire, minimum)
  1401. @mname = mname
  1402. @rname = rname
  1403. @serial = serial
  1404. @refresh = refresh
  1405. @retry = retry_
  1406. @expire = expire
  1407. @minimum = minimum
  1408. end
  1409. ##
  1410. # Name of the host where the master zone file for this zone resides.
  1411. attr_reader :mname
  1412. ##
  1413. # The person responsible for this domain name.
  1414. attr_reader :rname
  1415. ##
  1416. # The version number of the zone file.
  1417. attr_reader :serial
  1418. ##
  1419. # How often, in seconds, a secondary name server is to check for
  1420. # updates from the primary name server.
  1421. attr_reader :refresh
  1422. ##
  1423. # How often, in seconds, a secondary name server is to retry after a
  1424. # failure to check for a refresh.
  1425. attr_reader :retry
  1426. ##
  1427. # Time in seconds that a secondary name server is to use the data
  1428. # before refreshing from the primary name server.
  1429. attr_reader :expire
  1430. ##
  1431. # The minimum number of seconds to be used for TTL values in RRs.
  1432. attr_reader :minimum
  1433. def encode_rdata(msg) # :nodoc:
  1434. msg.put_name(@mname)
  1435. msg.put_name(@rname)
  1436. msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum)
  1437. end
  1438. def self.decode_rdata(msg) # :nodoc:
  1439. mname = msg.get_name
  1440. rname = msg.get_name
  1441. serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN')
  1442. return self.new(
  1443. mname, rname, serial, refresh, retry_, expire, minimum)
  1444. end
  1445. end
  1446. ##
  1447. # A Pointer to another DNS name.
  1448. class PTR < DomainName
  1449. TypeValue = 12 # :nodoc:
  1450. end
  1451. ##
  1452. # Host Information resource.
  1453. class HINFO < Resource
  1454. TypeValue = 13 # :nodoc:
  1455. ##
  1456. # Creates a new HINFO running +os+ on +cpu+.
  1457. def initialize(cpu, os)
  1458. @cpu = cpu
  1459. @os = os
  1460. end
  1461. ##
  1462. # CPU architecture for this resource.
  1463. attr_reader :cpu
  1464. ##
  1465. # Operating system for this resource.
  1466. attr_reader :os
  1467. def encode_rdata(msg) # :nodoc:
  1468. msg.put_string(@cpu)
  1469. msg.put_string(@os)
  1470. end
  1471. def self.decode_rdata(msg) # :nodoc:
  1472. cpu = msg.get_string
  1473. os = msg.get_string
  1474. return self.new(cpu, os)
  1475. end
  1476. end
  1477. ##
  1478. # Mailing list or mailbox information.
  1479. class MINFO < Resource
  1480. TypeValue = 14 # :nodoc:
  1481. def initialize(rmailbx, emailbx)
  1482. @rmailbx = rmailbx
  1483. @emailbx = emailbx
  1484. end
  1485. ##
  1486. # Domain name responsible for this mail list or mailbox.
  1487. attr_reader :rmailbx
  1488. ##
  1489. # Mailbox to use for error messages related to the mail list or mailbox.
  1490. attr_reader :emailbx
  1491. def encode_rdata(msg) # :nodoc:
  1492. msg.put_name(@rmailbx)
  1493. msg.put_name(@emailbx)
  1494. end
  1495. def self.decode_rdata(msg) # :nodoc:
  1496. rmailbx = msg.get_string
  1497. emailbx = msg.get_string
  1498. return self.new(rmailbx, emailbx)
  1499. end
  1500. end
  1501. ##
  1502. # Mail Exchanger resource.
  1503. class MX < Resource
  1504. TypeValue= 15 # :nodoc:
  1505. ##
  1506. # Creates a new MX record with +preference+, accepting mail at
  1507. # +exchange+.
  1508. def initialize(preference, exchange)
  1509. @preference = preference
  1510. @exchange = exchange
  1511. end
  1512. ##
  1513. # The preference for this MX.
  1514. attr_reader :preference
  1515. ##
  1516. # The host of this MX.
  1517. attr_reader :exchange
  1518. def encode_rdata(msg) # :nodoc:
  1519. msg.put_pack('n', @preference)
  1520. msg.put_name(@exchange)
  1521. end
  1522. def self.decode_rdata(msg) # :nodoc:
  1523. preference, = msg.get_unpack('n')
  1524. exchange = msg.get_name
  1525. return self.new(preference, exchange)
  1526. end
  1527. end
  1528. ##
  1529. # Unstructured text resource.
  1530. class TXT < Resource
  1531. TypeValue = 16 # :nodoc:
  1532. def initialize(first_string, *rest_strings)
  1533. @strings = [first_string, *rest_strings]
  1534. end
  1535. ##
  1536. # Returns an Array of Strings for this TXT record.
  1537. attr_reader :strings
  1538. ##
  1539. # Returns the first string from +strings+.
  1540. def data
  1541. @strings[0]
  1542. end
  1543. def encode_rdata(msg) # :nodoc:
  1544. msg.put_string_list(@strings)
  1545. end
  1546. def self.decode_rdata(msg) # :nodoc:
  1547. strings = msg.get_string_list
  1548. return self.new(*strings)
  1549. end
  1550. end
  1551. ##
  1552. # A Query type requesting any RR.
  1553. class ANY < Query
  1554. TypeValue = 255 # :nodoc:
  1555. end
  1556. ClassInsensitiveTypes = [ # :nodoc:
  1557. NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, ANY
  1558. ]
  1559. ##
  1560. # module IN contains ARPA Internet specific RRs.
  1561. module IN
  1562. ClassValue = 1 # :nodoc:
  1563. ClassInsensitiveTypes.each {|s|
  1564. c = Class.new(s)
  1565. c.const_set(:TypeValue, s::TypeValue)
  1566. c.const_set(:ClassValue, ClassValue)
  1567. ClassHash[[s::TypeValue, ClassValue]] = c
  1568. self.const_set(s.name.sub(/.*::/, ''), c)
  1569. }
  1570. ##
  1571. # IPv4 Address resource
  1572. class A < Resource
  1573. TypeValue = 1
  1574. ClassValue = IN::ClassValue
  1575. ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1576. ##
  1577. # Creates a new A for +address+.
  1578. def initialize(address)
  1579. @address = IPv4.create(address)
  1580. end
  1581. ##
  1582. # The Resolv::IPv4 address for this A.
  1583. attr_reader :address
  1584. def encode_rdata(msg) # :nodoc:
  1585. msg.put_bytes(@address.address)
  1586. end
  1587. def self.decode_rdata(msg) # :nodoc:
  1588. return self.new(IPv4.new(msg.get_bytes(4)))
  1589. end
  1590. end
  1591. ##
  1592. # Well Known Service resource.
  1593. class WKS < Resource
  1594. TypeValue = 11
  1595. ClassValue = IN::ClassValue
  1596. ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1597. def initialize(address, protocol, bitmap)
  1598. @address = IPv4.create(address)
  1599. @protocol = protocol
  1600. @bitmap = bitmap
  1601. end
  1602. ##
  1603. # The host these services run on.
  1604. attr_reader :address
  1605. ##
  1606. # IP protocol number for these services.
  1607. attr_reader :protocol
  1608. ##
  1609. # A bit map of enabled services on this host.
  1610. #
  1611. # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP
  1612. # service (port 25). If this bit is set, then an SMTP server should
  1613. # be listening on TCP port 25; if zero, SMTP service is not
  1614. # supported.
  1615. attr_reader :bitmap
  1616. def encode_rdata(msg) # :nodoc:
  1617. msg.put_bytes(@address.address)
  1618. msg.put_pack("n", @protocol)
  1619. msg.put_bytes(@bitmap)
  1620. end
  1621. def self.decode_rdata(msg) # :nodoc:
  1622. address = IPv4.new(msg.get_bytes(4))
  1623. protocol, = msg.get_unpack("n")
  1624. bitmap = msg.get_bytes
  1625. return self.new(address, protocol, bitmap)
  1626. end
  1627. end
  1628. ##
  1629. # An IPv6 address record.
  1630. class AAAA < Resource
  1631. TypeValue = 28
  1632. ClassValue = IN::ClassValue
  1633. ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1634. ##
  1635. # Creates a new AAAA for +address+.
  1636. def initialize(address)
  1637. @address = IPv6.create(address)
  1638. end
  1639. ##
  1640. # The Resolv::IPv6 address for this AAAA.
  1641. attr_reader :address
  1642. def encode_rdata(msg) # :nodoc:
  1643. msg.put_bytes(@address.address)
  1644. end
  1645. def self.decode_rdata(msg) # :nodoc:
  1646. return self.new(IPv6.new(msg.get_bytes(16)))
  1647. end
  1648. end
  1649. ##
  1650. # SRV resource record defined in RFC 2782
  1651. #
  1652. # These records identify the hostname and port that a service is
  1653. # available at.
  1654. class SRV < Resource
  1655. TypeValue = 33
  1656. ClassValue = IN::ClassValue
  1657. ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1658. # Create a SRV resource record.
  1659. #
  1660. # See the documentation for #priority, #weight, #port and #target
  1661. # for +priority+, +weight+, +port and +target+ respectively.
  1662. def initialize(priority, weight, port, target)
  1663. @priority = priority.to_int
  1664. @weight = weight.to_int
  1665. @port = port.to_int
  1666. @target = Name.create(target)
  1667. end
  1668. # The priority of this target host.
  1669. #
  1670. # A client MUST attempt to contact the target host with the
  1671. # lowest-numbered priority it can reach; target hosts with the same
  1672. # priority SHOULD be tried in an order defined by the weight field.
  1673. # The range is 0-65535. Note that it is not widely implemented and
  1674. # should be set to zero.
  1675. attr_reader :priority
  1676. # A server selection mechanism.
  1677. #
  1678. # The weight field specifies a relative weight for entries with the
  1679. # same priority. Larger weights SHOULD be given a proportionately
  1680. # higher probability of being selected. The range of this number is
  1681. # 0-65535. Domain administrators SHOULD use Weight 0 when there
  1682. # isn't any server selection to do, to make the RR easier to read
  1683. # for humans (less noisy). Note that it is not widely implemented
  1684. # and should be set to zero.
  1685. attr_reader :weight
  1686. # The port on this target host of this service.
  1687. #
  1688. # The range is 0-65535.
  1689. attr_reader :port
  1690. # The domain name of the target host.
  1691. #
  1692. # A target of "." means that the service is decidedly not available
  1693. # at this domain.
  1694. attr_reader :target
  1695. def encode_rdata(msg) # :nodoc:
  1696. msg.put_pack("n", @priority)
  1697. msg.put_pack("n", @weight)
  1698. msg.put_pack("n", @port)
  1699. msg.put_name(@target)
  1700. end
  1701. def self.decode_rdata(msg) # :nodoc:
  1702. priority, = msg.get_unpack("n")
  1703. weight, = msg.get_unpack("n")
  1704. port, = msg.get_unpack("n")
  1705. target = msg.get_name
  1706. return self.new(priority, weight, port, target)
  1707. end
  1708. end
  1709. end
  1710. end
  1711. end
  1712. ##
  1713. # A Resolv::DNS IPv4 address.
  1714. class IPv4
  1715. ##
  1716. # Regular expression IPv4 addresses must match.
  1717. Regex256 = /0
  1718. |1(?:[0-9][0-9]?)?
  1719. |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
  1720. |[3-9][0-9]?/x
  1721. Regex = /\A(#{Regex256})\.(#{Regex256})\.(#{Regex256})\.(#{Regex256})\z/
  1722. def self.create(arg)
  1723. case arg
  1724. when IPv4
  1725. return arg
  1726. when Regex
  1727. if (0..255) === (a = $1.to_i) &&
  1728. (0..255) === (b = $2.to_i) &&
  1729. (0..255) === (c = $3.to_i) &&
  1730. (0..255) === (d = $4.to_i)
  1731. return self.new([a, b, c, d].pack("CCCC"))
  1732. else
  1733. raise ArgumentError.new("IPv4 address with invalid value: " + arg)
  1734. end
  1735. else
  1736. raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}")
  1737. end
  1738. end
  1739. def initialize(address) # :nodoc:
  1740. unless address.kind_of?(String) && address.length == 4
  1741. raise ArgumentError.new('IPv4 address must be 4 bytes')
  1742. end
  1743. @address = address
  1744. end
  1745. ##
  1746. # A String representation of this IPv4 address.
  1747. ##
  1748. # The raw IPv4 address as a String.
  1749. attr_reader :address
  1750. def to_s # :nodoc:
  1751. return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC"))
  1752. end
  1753. def inspect # :nodoc:
  1754. return "#<#{self.class} #{self.to_s}>"
  1755. end
  1756. ##
  1757. # Turns this IPv4 address into a Resolv::DNS::Name.
  1758. def to_name
  1759. return DNS::Name.create(
  1760. '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse)
  1761. end
  1762. def ==(other) # :nodoc:
  1763. return @address == other.address
  1764. end
  1765. def eql?(other) # :nodoc:
  1766. return self == other
  1767. end
  1768. def hash # :nodoc:
  1769. return @address.hash
  1770. end
  1771. end
  1772. ##
  1773. # A Resolv::DNS IPv6 address.
  1774. class IPv6
  1775. ##
  1776. # IPv6 address format a:b:c:d:e:f:g:h
  1777. Regex_8Hex = /\A
  1778. (?:[0-9A-Fa-f]{1,4}:){7}
  1779. [0-9A-Fa-f]{1,4}
  1780. \z/x
  1781. ##
  1782. # Compressed IPv6 address format a::b
  1783. Regex_CompressedHex = /\A
  1784. ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
  1785. ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
  1786. \z/x
  1787. ##
  1788. # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z
  1789. Regex_6Hex4Dec = /\A
  1790. ((?:[0-9A-Fa-f]{1,4}:){6,6})
  1791. (\d+)\.(\d+)\.(\d+)\.(\d+)
  1792. \z/x
  1793. ##
  1794. # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z
  1795. Regex_CompressedHex4Dec = /\A
  1796. ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
  1797. ((?:[0-9A-Fa-f]{1,4}:)*)
  1798. (\d+)\.(\d+)\.(\d+)\.(\d+)
  1799. \z/x
  1800. ##
  1801. # A composite IPv6 address Regexp.
  1802. Regex = /
  1803. (?:#{Regex_8Hex}) |
  1804. (?:#{Regex_CompressedHex}) |
  1805. (?:#{Regex_6Hex4Dec}) |
  1806. (?:#{Regex_CompressedHex4Dec})/x
  1807. ##
  1808. # Creates a new IPv6 address from +arg+ which may be:
  1809. #
  1810. # IPv6:: returns +arg+.
  1811. # String:: +arg+ must match one of the IPv6::Regex* constants
  1812. def self.create(arg)
  1813. case arg
  1814. when IPv6
  1815. return arg
  1816. when String
  1817. address = ''
  1818. if Regex_8Hex =~ arg
  1819. arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
  1820. elsif Regex_CompressedHex =~ arg
  1821. prefix = $1
  1822. suffix = $2
  1823. a1 = ''
  1824. a2 = ''
  1825. prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
  1826. suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
  1827. omitlen = 16 - a1.length - a2.length
  1828. address << a1 << "\0" * omitlen << a2
  1829. elsif Regex_6Hex4Dec =~ arg
  1830. prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
  1831. if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
  1832. prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
  1833. address << [a, b, c, d].pack('CCCC')
  1834. else
  1835. raise ArgumentError.new("not numeric IPv6 address: " + arg)
  1836. end
  1837. elsif Regex_CompressedHex4Dec =~ arg
  1838. prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
  1839. if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
  1840. a1 = ''
  1841. a2 = ''
  1842. prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
  1843. suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
  1844. omitlen = 12 - a1.length - a2.length
  1845. address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
  1846. else
  1847. raise ArgumentError.new("not numeric IPv6 address: " + arg)
  1848. end
  1849. else
  1850. raise ArgumentError.new("not numeric IPv6 address: " + arg)
  1851. end
  1852. return IPv6.new(address)
  1853. else
  1854. raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}")
  1855. end
  1856. end
  1857. def initialize(address) # :nodoc:
  1858. unless address.kind_of?(String) && address.length == 16
  1859. raise ArgumentError.new('IPv6 address must be 16 bytes')
  1860. end
  1861. @address = address
  1862. end
  1863. ##
  1864. # The raw IPv6 address as a String.
  1865. attr_reader :address
  1866. def to_s # :nodoc:
  1867. address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn"))
  1868. unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
  1869. address.sub!(/(^|:)0(:|$)/, '::')
  1870. end
  1871. return address
  1872. end
  1873. def inspect # :nodoc:
  1874. return "#<#{self.class} #{self.to_s}>"
  1875. end
  1876. ##
  1877. # Turns this IPv6 address into a Resolv::DNS::Name.
  1878. #--
  1879. # ip6.arpa should be searched too. [RFC3152]
  1880. def to_name
  1881. return DNS::Name.new(
  1882. @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa'])
  1883. end
  1884. def ==(other) # :nodoc:
  1885. return @address == other.address
  1886. end
  1887. def eql?(other) # :nodoc:
  1888. return self == other
  1889. end
  1890. def hash # :nodoc:
  1891. return @address.hash
  1892. end
  1893. end
  1894. ##
  1895. # Default resolver to use for Resolv class methods.
  1896. DefaultResolver = self.new
  1897. ##
  1898. # Address Regexp to use for matching IP addresses.
  1899. AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
  1900. end