Class: Rex::Proto::DNS::Cache

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/rex/proto/dns/cache.rb

Constant Summary

Constants included from Constants

Rex::Proto::DNS::Constants::MATCH_FQDN, Rex::Proto::DNS::Constants::MATCH_HOSTNAME

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCache

class DNSRecordError < ::Exception

Create DNS cache



15
16
17
18
# File 'lib/rex/proto/dns/cache.rb', line 15

def initialize
  @records = {}
  @lock = Mutex.new
end

Instance Attribute Details

#lockObject (readonly)

Returns the value of attribute lock.



9
10
11
# File 'lib/rex/proto/dns/cache.rb', line 9

def lock
  @lock
end

#monitor_threadObject (readonly)

Returns the value of attribute monitor_thread.



9
10
11
# File 'lib/rex/proto/dns/cache.rb', line 9

def monitor_thread
  @monitor_thread
end

#recordsObject (readonly)

Returns the value of attribute records.



9
10
11
# File 'lib/rex/proto/dns/cache.rb', line 9

def records
  @records
end

Instance Method Details

#add(record, expire = 0) ⇒ Object (protected)

Add a record to the cache with thread safety

Parameters:

  • record (Dnsruby::RR)

    Record to add

  • expire (Fixnum) (defaults to: 0)

    Time in seconds when record becomes stale



121
122
123
124
125
# File 'lib/rex/proto/dns/cache.rb', line 121

def add(record, expire = 0)
  self.lock.synchronize do
    self.records[record] = expire
  end
end

#add_static(name, address, type = Dnsruby::Types::A, replace = false) ⇒ Object

Add static record to cache

Parameters:

  • name (String)

    Name of record

  • address (String)

    Address of record

  • type (Dnsruby::Types) (defaults to: Dnsruby::Types::A)

    Record type to add

  • replace (TrueClass, FalseClass) (defaults to: false)

    Replace existing records



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/rex/proto/dns/cache.rb', line 66

def add_static(name, address, type = Dnsruby::Types::A, replace = false)
  if Rex::Socket.is_ip_addr?(address.to_s) and
  ( name.to_s.match(MATCH_HOSTNAME) or name == '*')
    find(name, type).each do |found|
      delete(found)
    end if replace
    add(Dnsruby::RR.create(name: name, type: type, address: address),0)
  else
    raise "Invalid parameters for static entry - #{name}, #{address}, #{type}"
  end
end

#cache_record(record) ⇒ Object

Add record to cache, only when “running”

Parameters:

  • record (Dnsruby::RR)

    Record to cache



48
49
50
51
52
53
54
55
56
57
# File 'lib/rex/proto/dns/cache.rb', line 48

def cache_record(record)
  return unless @monitor_thread
  if record.is_a?(Dnsruby::RR) and
  (!record.respond_to?(:address) or Rex::Socket.is_ip_addr?(record.address.to_s)) and
  record.name.to_s.match(MATCH_HOSTNAME)
    add(record, ::Time.now.to_i + record.ttl)
  else
    raise "Invalid record for cache entry - #{record.inspect}"
  end
end

#delete(record) ⇒ Object (protected)

Delete a record from the cache with thread safety

Parameters:

  • record (Dnsruby::RR)

    Record to delete



131
132
133
134
135
# File 'lib/rex/proto/dns/cache.rb', line 131

def delete(record)
  self.lock.synchronize do
    self.records.delete(record)
  end
end

#find(search, type = Dnsruby::Types::A) ⇒ Array

Find entries in cache, substituting names for ‘*’ in return

Parameters:

  • search (String)

    Name or address to search for

  • type (Dnsruby::Types) (defaults to: Dnsruby::Types::A)

    Record type to search for

Returns:

  • (Array)

    Records found



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rex/proto/dns/cache.rb', line 27

def find(search, type = Dnsruby::Types::A)
  self.records.select do |record,expire|
    record.type == type and (expire < 1 or expire > ::Time.now.to_i) and
    (
      record.name == '*' or
      record.name.to_s == search.to_s or record.name.to_s[0..-2] == search.to_s or
      ( record.respond_to?(:address) and record.address.to_s == search.to_s )
    )
  end.keys.map do |record|
    if search.to_s.match(MATCH_HOSTNAME) and record.name == '*'
      record = Dnsruby::RR.create(name: name, type: type, address: address)
    else
      record
    end
  end
end

#prune(before = ::Time.now.to_i) ⇒ Object

Prune cache entries

Parameters:

  • before (Fixnum) (defaults to: ::Time.now.to_i)

    Time in seconds before which records are evicted



82
83
84
85
86
# File 'lib/rex/proto/dns/cache.rb', line 82

def prune(before = ::Time.now.to_i)
  self.records.select do |rec, expire|
    expire > 0 and expire < before
  end.each {|rec, exp| delete(rec)}
end

#startObject

Start the cache monitor



91
92
93
94
95
96
97
98
# File 'lib/rex/proto/dns/cache.rb', line 91

def start
  @monitor_thread = Rex::ThreadFactory.spawn("DNSServerCacheMonitor", false) {
    while true
      prune
      Rex::ThreadSafe.sleep(0.5)
    end
  } unless @monitor_thread
end

#stop(flush = false) ⇒ Object

Stop the cache monitor

Parameters:

  • flush (TrueClass, FalseClass) (defaults to: false)

    Remove non-static entries



104
105
106
107
108
109
110
111
112
# File 'lib/rex/proto/dns/cache.rb', line 104

def stop(flush = false)
  self.monitor_thread.kill unless @monitor_thread.nil?
  @monitor_thread = nil
  if flush
    self.records.select do |rec, expire|
      rec.ttl > 0
    end.each {|rec| delete(rec)}
  end
end