Module: Rex::Proto::DNS::CustomNameserverProvider
- Defined in:
- lib/rex/proto/dns/custom_nameserver_provider.rb
Overview
Provides a DNS resolver the ability to use different nameservers for different requests, based on the domain being queried.
Defined Under Namespace
Classes: CommSink
Constant Summary collapse
Class Method Summary collapse
Instance Method Summary collapse
-
#add_upstream_rule(resolvers, comm: nil, wildcard: '*', index: -1)) ⇒ Object
Add a custom nameserver entry to the custom provider.
- #flush ⇒ Object
-
#has_config? ⇒ Boolean
Check whether or not there is configuration data in Metasploit’s configuration file which is persisted on disk.
- #init ⇒ Object
-
#load_config ⇒ Object
Load the custom settings from the MSF config file.
-
#reinit ⇒ Object
Reinitialize the configuration to its original state.
-
#remove_ids(ids) ⇒ Array<UpstreamRule>
Remove upstream rules with the given indices Ignore entries that are not found.
-
#reorder_ids(ids, new_id) ⇒ Array<UpstreamRule>
Move upstream rules with the given indices into the location provided.
-
#save_config ⇒ Object
Save the custom settings to the MSF config file.
- #set_framework(framework) ⇒ Object
-
#upstream_resolvers_for_packet(packet) ⇒ Array<Array>
The nameservers that match the given packet.
- #upstream_rules ⇒ Object
Class Method Details
.extended(mod) ⇒ Object
228 229 230 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 228 def self.extended(mod) mod.init end |
Instance Method Details
#add_upstream_rule(resolvers, comm: nil, wildcard: '*', index: -1)) ⇒ Object
Add a custom nameserver entry to the custom provider.
124 125 126 127 128 129 130 131 132 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 124 def add_upstream_rule(resolvers, comm: nil, wildcard: '*', index: -1) resolvers = [resolvers] if resolvers.is_a?(String) # coerce into an array of strings @upstream_rules.insert(index, UpstreamRule.new( wildcard: wildcard, resolvers: resolvers, comm: comm )) end |
#flush ⇒ Object
190 191 192 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 190 def flush @upstream_rules.clear end |
#has_config? ⇒ Boolean
Check whether or not there is configuration data in Metasploit’s configuration file which is persisted on disk.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 70 def has_config? config = Msf::Config.load version = config.fetch(CONFIG_KEY_BASE, {}).fetch('configuration_version', nil) if version.nil? @logger.info 'DNS configuration can not be loaded because the version is missing' return false end their_version = Rex::Version.new(version) if their_version > CONFIG_VERSION # if the config is newer, it's incompatible (we only guarantee backwards compat) @logger.info "DNS configuration version #{their_version} can not be loaded because it is too new" return false end my_minimum_version = Rex::Version.new(CONFIG_VERSION.canonical_segments.first.to_s) if their_version < my_minimum_version # can not be older than our major version @logger.info "DNS configuration version #{their_version} can not be loaded because it is too old" return false end true end |
#init ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 36 def init @upstream_rules = [] resolvers = [UpstreamResolver.create_static] if @config[:nameservers].empty? # if no nameservers are specified, fallback to the system resolvers << UpstreamResolver.create_system else # migrate the originally configured name servers resolvers += @config[:nameservers].map(&:to_s) @config[:nameservers].clear end add_upstream_rule(resolvers) nil end |
#load_config ⇒ Object
Load the custom settings from the MSF config file
109 110 111 112 113 114 115 116 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 109 def load_config unless has_config? raise ResolverError.new('There is no compatible configuration data to load') end load_config_entries load_config_static_hostnames end |
#reinit ⇒ Object
Reinitialize the configuration to its original state.
55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 55 def reinit parse_config_file parse_environment_variables self.static_hostnames.flush self.static_hostnames.parse_hosts_file init cache.flush if respond_to?(:cache) nil end |
#remove_ids(ids) ⇒ Array<UpstreamRule>
Remove upstream rules with the given indices Ignore entries that are not found
139 140 141 142 143 144 145 146 147 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 139 def remove_ids(ids) removed = [] ids.sort.reverse.each do |id| upstream_rule = @upstream_rules.delete_at(id) removed << upstream_rule if upstream_rule end removed.reverse end |
#reorder_ids(ids, new_id) ⇒ Array<UpstreamRule>
Move upstream rules with the given indices into the location provided. If multiple IDs are provided, they will all be inserted into the provided location, in the order provided. Ignore entries that are not found
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 157 def reorder_ids(ids, new_id) if new_id == -1 new_id = @upstream_rules.length end if new_id > @upstream_rules.length raise ::ArgumentError.new("Insertion ID is past the end of the ruleset") end to_move = [] to_subtract = 0 # Get the entries before we delete (gets too complicated with indices changing otherwise) ids.each do |id| upstream_rule = @upstream_rules[id] unless upstream_rule.nil? to_move << upstream_rule if new_id > id to_subtract += 1 # Adjust for the fact that are about to delete one, so the indices would be off-by-one after that index is deleted end end end new_id -= to_subtract ids.sort.reverse.each do |id| @upstream_rules.delete_at(id) end to_move.reverse.each do |rule| @upstream_rules.insert(new_id, rule) end to_move end |
#save_config ⇒ Object
Save the custom settings to the MSF config file
96 97 98 99 100 101 102 103 104 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 96 def save_config new_config = { 'configuration_version' => CONFIG_VERSION.to_s } Msf::Config.save(CONFIG_KEY_BASE => new_config) save_config_upstream_rules save_config_static_hostnames end |
#set_framework(framework) ⇒ Object
232 233 234 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 232 def set_framework(framework) self.feature_set = framework.features end |
#upstream_resolvers_for_packet(packet) ⇒ Array<Array>
The nameservers that match the given packet
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 199 def upstream_resolvers_for_packet(packet) unless feature_set.enabled?(Msf::FeatureManager::DNS) return super end # Leaky abstraction: a packet could have multiple question entries, # and each of these could have different nameservers, or travel via # different comm channels. We can't allow DNS leaks, so for now, we # will throw an error here. results_from_all_questions = [] packet.question.each do |question| name = question.qname.to_s upstream_rule = self.upstream_rules.find { |ur| ur.matches_name?(name) } if upstream_rule upstream_resolvers = upstream_rule.resolvers else # Fall back to default nameservers upstream_resolvers = super end results_from_all_questions << upstream_resolvers.uniq end results_from_all_questions.uniq! if results_from_all_questions.size != 1 raise ResolverError.new('Inconsistent nameserver entries attempted to be sent in the one packet') end results_from_all_questions[0] end |
#upstream_rules ⇒ Object
236 237 238 |
# File 'lib/rex/proto/dns/custom_nameserver_provider.rb', line 236 def upstream_rules @upstream_rules.dup end |