Class: Ronin::DNS::Proxy::Server

Inherits:
Async::DNS::Server
  • Object
show all
Defined in:
lib/ronin/dns/proxy/server.rb

Overview

A rule based DNS proxy server.

Constant Summary collapse

RECORD_TYPES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Mapping of Resolv resource classes to Symbols.

{
  Resolv::DNS::Resource::IN::A     => :A,
  Resolv::DNS::Resource::IN::AAAA  => :AAAA,
  Resolv::DNS::Resource::IN::ANY   => :ANY,
  Resolv::DNS::Resource::IN::CNAME => :CNAME,
  Resolv::DNS::Resource::IN::HINFO => :HINFO,
  Resolv::DNS::Resource::IN::LOC   => :LOC,
  Resolv::DNS::Resource::IN::MINFO => :MINFO,
  Resolv::DNS::Resource::IN::MX    => :MX,
  Resolv::DNS::Resource::IN::NS    => :NS,
  Resolv::DNS::Resource::IN::PTR   => :PTR,
  Resolv::DNS::Resource::IN::SOA   => :SOA,
  Resolv::DNS::Resource::IN::SRV   => :SRV,
  Resolv::DNS::Resource::IN::TXT   => :TXT,
  Resolv::DNS::Resource::IN::WKS   => :WKS
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, port, nameservers: Ronin::Support::Network::DNS.nameservers, rules: nil) {|server| ... } ⇒ Server

Initializes the DNS server.

Examples:

Initializes a new DNS proxy server:

server = Ronin::DNS::Proxy.new('127.0.0.1', 2346)
server.rule :A, 'example.com', '10.0.0.1'
server.rule :AAAA, 'example.com', 'dead:beef::1'

Initializing a new DNS proxy server with a block:

server = Ronin::DNS::Proxy.new('127.0.0.1', 2346) do |server|
  server.rule :A, 'example.com', '10.0.0.1'
  server.rule :AAAA, 'example.com', 'dead:beef::1'
end

Parameters:

  • host (String)

    The interface to listen on.

  • port (Integer)

    The local port to listen on.

  • nameservers (Array<String>) (defaults to: Ronin::Support::Network::DNS.nameservers)

    The upstream DNS server(s) to pass queries to.

  • rules (Array<(Symbol, String, String), (Symbol, Regexp, String), (Symbol, Regexp, Proc)>) (defaults to: nil)

    Optional rules to populate the server with.

Yields:

  • (server)

    If a block is given, it will be passed the newly created server.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/ronin/dns/proxy/server.rb', line 89

def initialize(host,port, nameservers: Ronin::Support::Network::DNS.nameservers,
                          rules: nil)
  @host = host
  @port = port

  super([[:udp, host, port]])

  @resolver = Async::DNS::Resolver.new(
    nameservers.map { |ip| [:udp, ip, 53] }
  )

  @rules = []

  if rules
    rules.each do |(record_type,name,result)|
      rule(record_type,name,result)
    end
  end

  yield self if block_given?
end

Instance Attribute Details

#hostString (readonly)

The host the server will listen on.

Returns:

  • (String)


37
38
39
# File 'lib/ronin/dns/proxy/server.rb', line 37

def host
  @host
end

#portInteger (readonly)

The port the server will listen on.

Returns:

  • (Integer)


42
43
44
# File 'lib/ronin/dns/proxy/server.rb', line 42

def port
  @port
end

#resolverAsync::DNS::Resolver (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The upstream DNS resolver.

Returns:

  • (Async::DNS::Resolver)


49
50
51
# File 'lib/ronin/dns/proxy/server.rb', line 49

def resolver
  @resolver
end

#rulesArray<Rule> (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The defined rules for the proxy server.

Returns:



56
57
58
# File 'lib/ronin/dns/proxy/server.rb', line 56

def rules
  @rules
end

Instance Method Details

#process(name, resource_class, transaction) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Processes a received query.

Parameters:

  • name (String)

    The query value (ex: www.example.com).

  • resource_class (Class<Resolv::DNS::Resource>)

    The resource class (ex: Resolv::DNS::Resource::IN::A).

  • transaction (Async::DNS::Transaction)

    The DNS transaction object.



209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/ronin/dns/proxy/server.rb', line 209

def process(name,resource_class,transaction)
  query_type = RECORD_TYPES.fetch(resource_class)

  matched_rule = @rules.find do |rule|
    rule.matches?(query_type,name)
  end

  if matched_rule
    matched_rule.call(query_type,name,transaction)
  else
    transaction.passthrough!(@resolver)
  end
end

#rule(record_type, name, result = nil) {|type, name, transaction| ... } ⇒ Object

Adds a rule to the server.

Examples:

override the IP address for a domain:

server.rule :A, 'example.com', '10.0.0.42'

return multiple IP addresses:

server.rule :A, 'example.com', ['10.0.0.42', '10.0.0.43']

return an error for the given hostname:

server.rule :A, 'updates.example.com', :ServFail

match a query using a regex:

server.rule :TXT, /^spf\./, "v=spf1 include:10.0.0.1 ~all"

define a dynamic rule:

server.rule(:CNAME, /^www\./) do |type,name,transaction|
  # append '.hax' to the domain name
  names = name.split('.').push('hax')

  transaction.respond!(names)
end

Parameters:

  • record_type (:A, :AAAA, :ANY, :CNAME, :HINFO, :LOC, :MINFO, :MX, :NS, :PTR, :SOA, :SRV, :TXT, :WKS)

    The record type that the rule will match against.

  • name (String, Regexp)

    The record name that the rule will match against.

  • result (String, Array<String>, Symbol, #call) (defaults to: nil)

    The result to respond with. It can be a String, or an Array of Strings, or an error code:

    • :NoError - No error occurred.
    • :FormErr - The incoming data was not formatted correctly.
    • :ServFail - The operation caused a server failure (internal error, etc).
    • :NXDomain - Non-eXistant Domain (domain record does not exist).
    • :NotImp - The operation requested is not implemented.
    • :Refused - The operation was refused by the server.
    • :NotAuth - The server is not authoritive for the zone.

Yields:

  • (type, name, transaction)

    If no result argument is given, the given block will be passed the DNS query's type, name, and transaction object.

Yield Parameters:

  • type (Symbol)

    The query type.

  • name (String)

    The queried host name.

  • transaction (Async::DNS::Transaction)

    The DNS query transaction object.



167
168
169
170
171
172
173
# File 'lib/ronin/dns/proxy/server.rb', line 167

def rule(record_type,name,result=nil,&block)
  unless (result || block)
    raise(ArgumentError,"must specify a result value or a block")
  end

  @rules << Rule.new(record_type,name,result,&block)
end