Class: RubyDNS::RuleBasedServer
Overview
Provides the core of the RubyDNS domain-specific language (DSL). It contains a list of rules which are used to match against incoming DNS questions. These rules are used to generate responses which are either DNS resource records or failures.
Defined Under Namespace
Classes: Rule
Constant Summary
Constants inherited from Server
Instance Attribute Summary collapse
-
#logger ⇒ Object
Returns the value of attribute logger.
Instance Method Summary collapse
-
#defer {|fiber| ... } ⇒ Object
Process a block with the current fiber.
-
#fire(event_name) ⇒ Object
Fire the named event, which must have been registered using on.
-
#initialize(&block) ⇒ RuleBasedServer
constructor
Instantiate a server with a block.
-
#match(*pattern, &block) ⇒ Object
This function connects a pattern with a block.
-
#next! ⇒ Object
If you match a rule, but decide within the rule that it isn't the correct one to use, you can call
next!
to evaluate the next rule - in other words, to continue falling down through the list of rules. -
#on(event_name, &block) ⇒ Object
Register a named event which may be invoked later using #fire.
-
#otherwise(&block) ⇒ Object
Specify a default block to execute if all other rules fail to match.
-
#process(name, resource_class, *args) ⇒ Object
Give a name and a record type, try to match a rule and use it for processing the given arguments.
-
#process_query(query, options = {}, &block) ⇒ Object
Process an incoming DNS message.
Methods inherited from Server
Constructor Details
#initialize(&block) ⇒ RuleBasedServer
Instantiate a server with a block
server = Server.new do match(/server.mydomain.com/, IN::A) do |transaction| transaction.respond!("1.2.3.4") end end
211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/rubydns/server.rb', line 211 def initialize(&block) super() @events = {} @rules = [] @otherwise = nil if block_given? instance_eval &block end end |
Instance Attribute Details
#logger ⇒ Object
Returns the value of attribute logger.
223 224 225 |
# File 'lib/rubydns/server.rb', line 223 def logger @logger end |
Instance Method Details
#defer {|fiber| ... } ⇒ Object
Process a block with the current fiber. To resume processing from the block, call fiber.resume
. You shouldn't call fiber.resume
until after the top level block has returned.
289 290 291 292 293 294 295 |
# File 'lib/rubydns/server.rb', line 289 def defer(&block) fiber = Fiber.current yield(fiber) Fiber.yield end |
#fire(event_name) ⇒ Object
Fire the named event, which must have been registered using on.
245 246 247 248 249 250 251 |
# File 'lib/rubydns/server.rb', line 245 def fire(event_name) callback = @events[event_name] if callback callback.call(self) end end |
#match(*pattern, &block) ⇒ Object
This function connects a pattern with a block. A pattern is either a String or a Regex instance. Optionally, a second argument can be provided which is either a String, Symbol or Array of resource record types which the rule matches against.
match("www.google.com") match("gmail.com", IN::MX) match(/g?mail.(com|org|net)/, [IN::MX, IN::A])
231 232 233 |
# File 'lib/rubydns/server.rb', line 231 def match(*pattern, &block) @rules << Rule.new(pattern, block) end |
#next! ⇒ Object
If you match a rule, but decide within the rule that it isn't the correct one to use, you can call next!
to evaluate the next rule - in other words, to continue falling down through the list of rules.
264 265 266 |
# File 'lib/rubydns/server.rb', line 264 def next! throw :next end |
#on(event_name, &block) ⇒ Object
Register a named event which may be invoked later using #fire
on(:start) do |server| RExec.change_user(RUN_AS) end
240 241 242 |
# File 'lib/rubydns/server.rb', line 240 def on(event_name, &block) @events[event_name] = block end |
#otherwise(&block) ⇒ Object
Specify a default block to execute if all other rules fail to match. This block is typially used to pass the request on to another server (i.e. recursive request).
otherwise do |transaction| transaction.passthrough!($R) end
259 260 261 |
# File 'lib/rubydns/server.rb', line 259 def otherwise(&block) @otherwise = block end |
#process(name, resource_class, *args) ⇒ Object
Give a name and a record type, try to match a rule and use it for processing the given arguments.
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'lib/rubydns/server.rb', line 269 def process(name, resource_class, *args) @logger.debug "Searching for #{name} #{resource_class.name}" @rules.each do |rule| @logger.debug "Checking rule #{rule}..." catch (:next) do # If the rule returns true, we assume that it was successful and no further rules need to be evaluated. return if rule.call(self, name, resource_class, *args) end end if @otherwise @otherwise.call(*args) else @logger.warn "Failed to handle #{name} #{resource_class.name}!" end end |
#process_query(query, options = {}, &block) ⇒ Object
Process an incoming DNS message. Returns a serialized message to be sent back to the client.
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/rubydns/server.rb', line 298 def process_query(query, = {}, &block) # Setup answer answer = Resolv::DNS::Message::new(query.id) answer.qr = 1 # 0 = Query, 1 = Response answer.opcode = query.opcode # Type of Query; copy from query answer.aa = 1 # Is this an authoritative response: 0 = No, 1 = Yes answer.rd = query.rd # Is Recursion Desired, copied from query answer.ra = 0 # Does name server support recursion: 0 = No, 1 = Yes answer.rcode = 0 # Response code: 0 = No errors Fiber.new do transaction = nil begin query.question.each do |question, resource_class| @logger.debug "Processing question #{question} #{resource_class}..." transaction = Transaction.new(self, query, question, resource_class, answer, ) transaction.process end rescue @logger.error "Exception thrown while processing #{transaction}!" RubyDNS.log_exception(@logger, $!) answer.rcode = Resolv::DNS::RCode::ServFail end yield answer end.resume end |