Class: Async::DNS::Transaction

Inherits:
Object
  • Object
show all
Defined in:
lib/async/dns/transaction.rb

Overview

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).

Constant Summary collapse

DEFAULT_TTL =

The default time used for responses (24 hours).

86400

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server, query, question, resource_class, response, options = {}) ⇒ Transaction

Returns a new instance of Transaction.



30
31
32
33
34
35
36
37
38
# 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

Instance Attribute Details

#optionsObject (readonly)

Any options or configuration associated with the given transaction.



53
54
55
# File 'lib/async/dns/transaction.rb', line 53

def options
  @options
end

#queryObject (readonly)

The incoming query which is a set of questions.



44
45
46
# File 'lib/async/dns/transaction.rb', line 44

def query
  @query
end

#questionObject (readonly)

The question that this transaction represents.



47
48
49
# File 'lib/async/dns/transaction.rb', line 47

def question
  @question
end

#resource_classObject (readonly)

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



41
42
43
# File 'lib/async/dns/transaction.rb', line 41

def resource_class
  @resource_class
end

#responseObject (readonly)

The current full response to the incoming query.



50
51
52
# File 'lib/async/dns/transaction.rb', line 50

def response
  @response
end

Instance Method Details

#[](key) ⇒ Object



55
56
57
# File 'lib/async/dns/transaction.rb', line 55

def [] key
	@options[key]
end

#add(resources, options = {}) ⇒ Object

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



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# 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 = {}) ⇒ Object

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



70
71
72
# 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

#fail!(rcode) ⇒ Object

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.**



171
172
173
174
175
176
177
178
179
# 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) ⇒ Object

Deprecated.


182
183
184
185
186
# File 'lib/async/dns/transaction.rb', line 182

def failure!(*args)
	@server.logger.warn "failure! is deprecated, use fail! instead"
	
	fail!(*args)
end

#nameObject

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



60
61
62
# File 'lib/async/dns/transaction.rb', line 60

def name
	@question.to_s
end

#passthrough(resolver, options = {}) ⇒ Object

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



105
106
107
108
109
110
# 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 = {}, &block) ⇒ Object

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.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# 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

#processObject

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



189
190
191
# File 'lib/async/dns/transaction.rb', line 189

def process
	@server.process(name, @resource_class, self)
end

#respond!(*args) ⇒ Object

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).



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# 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_sObject

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



65
66
67
# File 'lib/async/dns/transaction.rb', line 65

def to_s
	"#{name} #{@resource_class.name}"
end