Class: Rex::Proto::DNS::Server
- Inherits:
-
Object
- Object
- Rex::Proto::DNS::Server
- Includes:
- IO::GramServer
- Defined in:
- lib/rex/proto/dns/server.rb
Direct Known Subclasses
Defined Under Namespace
Classes: MockDnsClient
Constant Summary collapse
Instance Attribute Summary collapse
-
#cache ⇒ Object
Returns the value of attribute cache.
-
#fwd_res ⇒ Object
Returns the value of attribute fwd_res.
-
#lock ⇒ Object
readonly
Returns the value of attribute lock.
-
#serve_tcp ⇒ Object
Returns the value of attribute serve_tcp.
-
#serve_udp ⇒ Object
Returns the value of attribute serve_udp.
-
#sock_options ⇒ Object
readonly
Returns the value of attribute sock_options.
-
#start_cache ⇒ Object
Returns the value of attribute start_cache.
-
#tcp_sock ⇒ Object
readonly
Returns the value of attribute tcp_sock.
-
#udp_sock ⇒ Object
readonly
Returns the value of attribute udp_sock.
Attributes included from IO::GramServer
#dispatch_request_proc, #listener_thread, #send_response_proc
Class Method Summary collapse
-
.hardcore_alias(*args) ⇒ Object
Returns the hardcore alias for the DNS service.
Instance Method Summary collapse
-
#alias ⇒ Object
DNS server.
-
#default_dispatch_request(cli, data) ⇒ Object
Default DNS request dispatcher, attempts to find response records in cache or forwards request upstream.
-
#dispatch_request(cli, data) ⇒ Object
Process client request, handled with dispatch_request_proc if set.
-
#initialize(lhost = '0.0.0.0', lport = 53, udp = true, tcp = false, start_cache = true, res = nil, comm = nil, ctx = {}, dblock = nil, sblock = nil) ⇒ Rex::Proto::DNS::Server
constructor
Create DNS Server.
-
#monitor_listener ⇒ Object
protected
This method monitors the listener socket for new connections and calls the
on_client_connectcallback routine. -
#on_client_data(cli) ⇒ Object
protected
Processes request coming from client.
-
#running? ⇒ Boolean
Check if server is running.
-
#start ⇒ Object
Start the DNS server and cache.
-
#stop(flush_cache = false) ⇒ Object
Stop the DNS server and cache.
-
#switchns(ns = []) ⇒ Object
Switch DNS forwarders in resolver with thread safety.
Methods included from IO::GramServer
Constructor Details
#initialize(lhost = '0.0.0.0', lport = 53, udp = true, tcp = false, start_cache = true, res = nil, comm = nil, ctx = {}, dblock = nil, sblock = nil) ⇒ Rex::Proto::DNS::Server
Create DNS Server
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/rex/proto/dns/server.rb', line 61 def initialize(lhost = '0.0.0.0', lport = 53, udp = true, tcp = false, start_cache = true, res = nil, comm = nil, ctx = {}, dblock = nil, sblock = nil) @serve_udp = udp @serve_tcp = tcp @sock_options = { 'LocalHost' => lhost, 'LocalPort' => lport, 'Context' => ctx, 'Comm' => comm } self.fwd_res = res.nil? ? Rex::Proto::DNS::Resolver.new(:comm => comm, :context => ctx) : res self.listener_thread = nil self.dispatch_request_proc = dblock self.send_response_proc = sblock self.start_cache = start_cache self.cache = Rex::Proto::DNS::Cache.new @lock = Mutex.new end |
Instance Attribute Details
#cache ⇒ Object
Returns the value of attribute cache.
43 44 45 |
# File 'lib/rex/proto/dns/server.rb', line 43 def cache @cache end |
#fwd_res ⇒ Object
Returns the value of attribute fwd_res.
43 44 45 |
# File 'lib/rex/proto/dns/server.rb', line 43 def fwd_res @fwd_res end |
#lock ⇒ Object (readonly)
Returns the value of attribute lock.
44 45 46 |
# File 'lib/rex/proto/dns/server.rb', line 44 def lock @lock end |
#serve_tcp ⇒ Object
Returns the value of attribute serve_tcp.
43 44 45 |
# File 'lib/rex/proto/dns/server.rb', line 43 def serve_tcp @serve_tcp end |
#serve_udp ⇒ Object
Returns the value of attribute serve_udp.
43 44 45 |
# File 'lib/rex/proto/dns/server.rb', line 43 def serve_udp @serve_udp end |
#sock_options ⇒ Object (readonly)
Returns the value of attribute sock_options.
44 45 46 |
# File 'lib/rex/proto/dns/server.rb', line 44 def @sock_options end |
#start_cache ⇒ Object
Returns the value of attribute start_cache.
43 44 45 |
# File 'lib/rex/proto/dns/server.rb', line 43 def start_cache @start_cache end |
#tcp_sock ⇒ Object (readonly)
Returns the value of attribute tcp_sock.
44 45 46 |
# File 'lib/rex/proto/dns/server.rb', line 44 def tcp_sock @tcp_sock end |
#udp_sock ⇒ Object (readonly)
Returns the value of attribute udp_sock.
44 45 46 |
# File 'lib/rex/proto/dns/server.rb', line 44 def udp_sock @udp_sock end |
Class Method Details
.hardcore_alias(*args) ⇒ Object
Returns the hardcore alias for the DNS service
201 202 203 |
# File 'lib/rex/proto/dns/server.rb', line 201 def self.hardcore_alias(*args) "#{(args[0] || '')}-#{(args[1] || '')}-#{args[5] || ''}" end |
Instance Method Details
#alias ⇒ Object
DNS server.
208 209 210 |
# File 'lib/rex/proto/dns/server.rb', line 208 def alias "DNS Server" end |
#default_dispatch_request(cli, data) ⇒ Object
Default DNS request dispatcher, attempts to find response records in cache or forwards request upstream
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 189 190 191 192 193 194 195 196 |
# File 'lib/rex/proto/dns/server.rb', line 162 def default_dispatch_request(cli,data) return if data.strip.empty? req = Packet.encode_drb(data) forward = req.dup # Dnsruby#dup is shallow - req and forward share the same @question Array. # Give forward its own copy so deleting forwarded questions doesn't also # empty req.question, which we need intact when echoing it in the response. forward.instance_variable_set(:@question, req.question.dup) answers = [] # Find cached items, remove question from forwarded packet req.question.each do |ques| cached = self.cache.find(ques.qname, ques.qtype) unless cached.empty? answers.concat(cached) forward.question.delete(ques) end end # Forward remaining requests, cache responses if forward.question.count > 0 && @fwd_res forwarded = self.fwd_res.send(forward) answers.concat(forwarded.answer) forwarded.answer.each { |ans| self.cache.cache_record(ans) } end # Build a fresh response message to avoid a Dnsruby stale-state encoding bug # where instance_variable_set(:@answer) on a decoded request appends answer # bytes after the packet end rather than inside the answer section. resp = Dnsruby::Message.new resp.header.id = req.header.id resp.header.qr = true resp.header.rd = req.header.rd # echo Recursion Desired back to the client resp.header.ra = !self.fwd_res.nil? # Recursion Available when we can forward upstream req.question.each { |q| resp.add_question(q.qname, q.qtype, q.qclass) } answers.uniq.each { |a| resp.add_answer(a) } send_response(cli, resp.encode) end |
#dispatch_request(cli, data) ⇒ Object
Process client request, handled with dispatch_request_proc if set
148 149 150 151 152 153 154 |
# File 'lib/rex/proto/dns/server.rb', line 148 def dispatch_request(cli, data) if self.dispatch_request_proc self.dispatch_request_proc.call(cli,data) else default_dispatch_request(cli,data) end end |
#monitor_listener ⇒ Object (protected)
This method monitors the listener socket for new connections and calls the on_client_connect callback routine.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/rex/proto/dns/server.rb', line 218 def monitor_listener while true rds = [self.udp_sock] wds = [] eds = [self.udp_sock] r,_,_ = ::IO.select(rds,wds,eds,1) if (r != nil and r[0] == self.udp_sock) buf, addr, source_port = self.udp_sock.recvfrom(65535) if source_port host, port = addr, source_port else host, port = addr[3], addr[1] end # Mock up a client object for sending back data cli = MockDnsClient.new(host, port, r[0]) dispatch_request(cli, buf) end end end |
#on_client_data(cli) ⇒ Object (protected)
Processes request coming from client
244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/rex/proto/dns/server.rb', line 244 def on_client_data(cli) begin data = cli.read(65535) raise ::EOFError if not data raise ::EOFError if data.empty? dispatch_request(cli, data) rescue EOFError => e self.tcp_socket.close_client(cli) if cli raise e end end |
#running? ⇒ Boolean
Check if server is running
96 97 98 |
# File 'lib/rex/proto/dns/server.rb', line 96 def running? self.listener_thread and self.listener_thread.alive? end |
#start ⇒ Object
Start the DNS server and cache
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/rex/proto/dns/server.rb', line 102 def start if self.serve_udp @udp_sock = Rex::Socket::Udp.create(self.) self.listener_thread = Rex::ThreadFactory.spawn("UDPDNSServerListener", false) { monitor_listener } end if self.serve_tcp @tcp_sock = Rex::Socket::TcpServer.create(self.) self.tcp_sock.on_client_data_proc = Proc.new { |cli| on_client_data(cli) } self.tcp_sock.start if !self.serve_udp self.listener_thread = tcp_sock.listener_thread end end self.cache.start if self.start_cache end |
#stop(flush_cache = false) ⇒ Object
Stop the DNS server and cache
129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/rex/proto/dns/server.rb', line 129 def stop(flush_cache = false) ensure_close = [self.udp_sock, self.tcp_sock].compact begin self.listener_thread.kill if self.listener_thread.respond_to?(:kill) self.listener_thread = nil ensure while csock = ensure_close.shift csock.stop if csock.respond_to?(:stop) csock.close unless csock.respond_to?(:close) and csock.closed? end end self.cache.stop(flush_cache) end |
#switchns(ns = []) ⇒ Object
Switch DNS forwarders in resolver with thread safety
84 85 86 87 88 89 90 91 |
# File 'lib/rex/proto/dns/server.rb', line 84 def switchns(ns = []) if ns.respond_to?(:split) ns = [ns] end self.lock.synchronize do self.fwd_res.nameserver = ns end end |