Class: Rex::Proto::DNS::CachedResolver
- Includes:
- Constants
- Defined in:
- lib/rex/proto/dns/cached_resolver.rb
Overview
Provides Rex::Sockets compatible version of Net::DNS::Resolver Modified to work with Dnsruby::Messages, their resolvers are too heavy
Constant Summary
Constants included from Constants
Rex::Proto::DNS::Constants::MATCH_FQDN, Rex::Proto::DNS::Constants::MATCH_HOSTNAME
Constants inherited from Resolver
Instance Attribute Summary collapse
-
#cache ⇒ Object
Returns the value of attribute cache.
Attributes inherited from Resolver
Instance Method Summary collapse
-
#initialize(config = {}) ⇒ nil
constructor
Initialize resolver with cache.
-
#send(argument, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN) ⇒ Dnsruby::Message?
Attempt to find answers to query in DNS cache; failing that, send remainder of DNS queries over appropriate transport and cache answers before returning to caller.
Methods inherited from Resolver
#proxies, #proxies=, #query, #search, #send_tcp, #send_udp
Constructor Details
#initialize(config = {}) ⇒ nil
Initialize resolver with cache
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/rex/proto/dns/cached_resolver.rb', line 23 def initialize(config = {}) super(config) self.cache = Rex::Proto::DNS::Cache.new # Read hostsfile into cache hf = Rex::Compat.is_windows ? '%WINDIR%/system32/drivers/etc/hosts' : '/etc/hosts' entries = begin File.read(hf).lines.map(&:strip).select do |entry| Rex::Socket.is_ip_addr?(entry.gsub(/\s+/,' ').split(' ').first) and not entry.match(/::.*ip6-/) # Ignore Debian/Ubuntu-specific notation for IPv6 hosts end.map do |entry| entry.gsub(/\s+/,' ').split(' ') end rescue => e @logger.error(e) [] end entries.each do |ent| next if ent.first =~ /^127\./ # Deal with multiple hostnames per address while ent.length > 2 hostname = ent.pop next unless MATCH_HOSTNAME.match hostname begin if Rex::Socket.is_ipv4?(ent.first) self.cache.add_static(hostname, ent.first, Dnsruby::Types::A) elsif Rex::Socket.is_ipv6?(ent.first) self.cache.add_static(hostname, ent.first, Dnsruby::Types::AAAA) else raise "Unknown IP address format #{ent.first} in hosts file!" end rescue => e # Deal with edge-cases in users' hostsfile @logger.error(e) end end hostname = ent.pop begin if MATCH_HOSTNAME.match hostname if Rex::Socket.is_ipv4?(ent.first) self.cache.add_static(hostname, ent.first, Dnsruby::Types::A) elsif Rex::Socket.is_ipv6?(ent.first) self.cache.add_static(hostname, ent.first, Dnsruby::Types::AAAA) else raise "Unknown IP address format #{ent.first} in hosts file!" end end rescue => e # Deal with edge-cases in users' hostsfile @logger.error(e) end end # TODO: inotify or similar on hostsfile for live updates? Easy-button functionality self.cache.start unless config[:dns_cache_no_start] return end |
Instance Attribute Details
#cache ⇒ Object
Returns the value of attribute cache.
15 16 17 |
# File 'lib/rex/proto/dns/cached_resolver.rb', line 15 def cache @cache end |
Instance Method Details
#send(argument, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN) ⇒ Dnsruby::Message?
Attempt to find answers to query in DNS cache; failing that, send remainder of DNS queries over appropriate transport and cache answers before returning to caller.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/rex/proto/dns/cached_resolver.rb', line 89 def send(argument, type = Dnsruby::Types::A, cls = Dnsruby::Classes::IN) case argument when Dnsruby::Message req = argument when Net::DNS::Packet, Resolv::DNS::Message req = Rex::Proto::DNS::Packet.encode_drb(argument) else net_packet = make_query_packet(argument,type,cls) # This returns a Net::DNS::Packet. Convert to Dnsruby::Message for consistency req = Rex::Proto::DNS::Packet.encode_drb(net_packet) end resolve = req.dup # Find cached items, remove request from resolved packet req.question.each do |ques| cached = self.cache.find(ques.qname, ques.qtype.to_s) next if cached.empty? req.instance_variable_set(:@answer, (req.answer + cached).uniq) resolve.question.delete(ques) end # Resolve remaining requests, cache responses if resolve.question.count > 0 resolved = super(resolve, type) req.instance_variable_set(:@answer, (req.answer + resolved.answer).uniq) resolved.answer.each do |ans| self.cache.cache_record(ans) end end # Finalize answers in response # Check for empty response prior to sending req.header.rcode = Dnsruby::RCode::NOERROR if req.answer.size < 1 req.header.qr = true # Set response bit return req end |