class Async::DNS::Transaction

This class provides all details of a single DNS question and response. This is used by the DSL to provide DNS related functionality.

The main functions to complete the transaction are: {#append!} (evaluate a new query and append the results), {#passthrough!} (pass the query to an upstream server), {#respond!} (compute a specific response) and {#fail!} (fail with an error code).

Constants

DEFAULT_TTL

The default time used for responses (24 hours).

Attributes

options[R]

Any options or configuration associated with the given transaction.

query[R]

The incoming query which is a set of questions.

question[R]

The question that this transaction represents.

resource_class[R]

The resource_class that was requested. This is typically used to generate a response.

response[R]

The current full response to the incoming query.

Public Class Methods

new(server, query, question, resource_class, response, options = {}) click to toggle source
# File lib/async/dns/transaction.rb, line 30
def initialize(server, query, question, resource_class, response, options = {})
        @server = server
        @query = query
        @question = question
        @resource_class = resource_class
        @response = response

        @options = options
end

Public Instance Methods

[](key) click to toggle source
# File lib/async/dns/transaction.rb, line 55
def [] key
        @options[key]
end
add(resources, options = {}) click to toggle source

Append a list of resources.

By default resources are appended to the `answers` section, but this can be changed by setting `options` to either `:authority` or `:additional`.

The time-to-live (TTL) of the resources can be specified using `options` and defaults to `DEFAULT_TTL`.

# File lib/async/dns/transaction.rb, line 139
def add(resources, options = {})
        # Use the default options if provided:
        options = options.merge(@options)
        
        ttl = options[:ttl] || DEFAULT_TTL
        name = options[:name] || @question.to_s + "."
        
        section = (options[:section] || 'answer').to_sym
        method = "add_#{section}".to_sym
        
        resources.each do |resource|
                @server.logger.debug {"#{method}: #{resource.inspect} #{resource.class::TypeValue} #{resource.class::ClassValue}"}
                
                @response.send(method, name, ttl, resource)
        end
end
append!(name, resource_class = nil, options = {}) click to toggle source

Run a new query through the rules with the given name and resource type. The results of this query are appended to the current transaction's `response`.

# File lib/async/dns/transaction.rb, line 70
def append!(name, resource_class = nil, options = {})
        Transaction.new(@server, @query, name, resource_class || @resource_class, @response, options).process
end
append_question!() click to toggle source

A typical response to a DNS request includes both the question and response. This helper appends the question unless it looks like the user is already managing that aspect of the response.

# File lib/async/dns/transaction.rb, line 194
def append_question!
        if @response.question.size == 0
                @response.add_question(@question, @resource_class)
        end
end
fail!(rcode) click to toggle source

This function indicates that there was a failure to resolve the given question. The single argument must be an integer error code, typically given by the constants in {Resolv::DNS::RCode}.

The easiest way to use this function it to simply supply a symbol. Here is a list of the most commonly used ones:

  • `: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.

See [RFC2929](www.rfc-editor.org/rfc/rfc2929.txt) for more information about DNS error codes (specifically, page 3).

**This function will complete deferred transactions.**

# File lib/async/dns/transaction.rb, line 171
def fail!(rcode)
        append_question!
        
        if rcode.kind_of? Symbol
                @response.rcode = Resolv::DNS::RCode.const_get(rcode)
        else
                @response.rcode = rcode.to_i
        end
end
failure!(*args) click to toggle source

@deprecated

# File lib/async/dns/transaction.rb, line 182
def failure!(*args)
        @server.logger.warn "failure! is deprecated, use fail! instead"
        
        fail!(*args)
end
name() click to toggle source

The name of the question, which is typically the requested hostname.

# File lib/async/dns/transaction.rb, line 60
def name
        @question.to_s
end
passthrough(resolver, options = {}) click to toggle source

Use the given resolver to respond to the question.

A block must be supplied, and provided a valid response is received from the upstream server, this function yields with the reply and reply_name.

If `options` is provided, this overrides the default query name sent to the upstream server. The same logic applies to `options`.

# File lib/async/dns/transaction.rb, line 105
def passthrough(resolver, options = {})
        query_name = options[:name] || name
        query_resource_class = options[:resource_class] || resource_class
        
        resolver.query(query_name, query_resource_class)
end
passthrough!(resolver, options = {}) { |response| ... } click to toggle source

Use the given resolver to respond to the question. Uses `passthrough` to do the lookup and merges the result.

If a block is supplied, this function yields with the `response` message if successful. This could be used, for example, to update a cache or modify the reply.

If recursion is not requested, the result is `fail!(:Refused)`. This check is ignored if an explicit `options` or `options` is given.

If the resolver can't reach upstream servers, `fail!(:ServFail)` is invoked.

# File lib/async/dns/transaction.rb, line 81
def passthrough!(resolver, options = {}, &block)
        if @query.rd || options[:force] || options[:name]
                response = passthrough(resolver, options)
                
                if response
                        yield response if block_given?
                        
                        # Recursion is available and is being used:
                        # See issue #26 for more details.
                        @response.ra = 1
                        @response.merge!(response)
                else
                        fail!(:ServFail)
                end
        else
                fail!(:Refused)
        end
end
process() click to toggle source

A helper method to process the transaction on the given server. Unless the transaction is deferred, it will {#succeed} on completion.

# File lib/async/dns/transaction.rb, line 189
def process
        @server.process(name, @resource_class, self)
end
respond!(*args) click to toggle source

The last argument can optionally be a hash of `options`. If `options` is provided, it overrides the default resource class of transaction. Additional `options` are passed to {#append!}.

See `Resolv::DNS::Resource` for more information about the various `resource_classes` available (www.ruby-doc.org/stdlib/libdoc/resolv/rdoc/index.html).

# File lib/async/dns/transaction.rb, line 119
def respond!(*args)
        append_question!
        
        options = args.last.kind_of?(Hash) ? args.pop : {}
        resource_class = options[:resource_class] || @resource_class
        
        if resource_class == nil
                raise ArgumentError.new("Could not instantiate resource #{resource_class}!")
        end
        
        resource = resource_class.new(*args)
        
        add([resource], options)
end
to_s() click to toggle source

Shows the question name and resource class. Suitable for debugging purposes.

# File lib/async/dns/transaction.rb, line 65
def to_s
        "#{name} #{@resource_class.name}"
end