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

Create a new transaction with the given server, query, question, resource class, response, and options.



23
24
25
26
27
28
29
30
31
# File 'lib/async/dns/transaction.rb', line 23

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)

Returns the value of attribute options.



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

def options
  @options
end

#queryObject (readonly)

Returns the value of attribute query.



37
38
39
# File 'lib/async/dns/transaction.rb', line 37

def query
  @query
end

#questionObject (readonly)

Returns the value of attribute question.



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

def question
  @question
end

#resource_classObject (readonly)

Returns the value of attribute resource_class.



34
35
36
# File 'lib/async/dns/transaction.rb', line 34

def resource_class
  @resource_class
end

#responseObject (readonly)

Returns the value of attribute response.



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

def response
  @response
end

#The resource class to use for responses. This is typically used to generate a response.(resource) ⇒ Object (readonly)



34
# File 'lib/async/dns/transaction.rb', line 34

attr :resource_class

Instance Method Details

#[](key) ⇒ Object

Access the options hash.



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

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[:section] to either :authority or :additional.

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



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/async/dns/transaction.rb', line 132

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

#Additional options associated with the transaction.=(optionsassociatedwiththetransaction. = (value)) ⇒ Object



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

attr :options

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



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

def append!(name, resource_class = nil, options = {})
	Transaction.new(@server, @query, name, resource_class || @resource_class, @response, **options).process
end

#append_question!Object

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.



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

def append_question!
	if @response.question.size == 0
		@response.add_question(@question, @resource_class)
	end
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.**



164
165
166
167
168
169
170
171
172
# File 'lib/async/dns/transaction.rb', line 164

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.


175
176
177
178
179
# File 'lib/async/dns/transaction.rb', line 175

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.



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

def name
	@question.to_s
end

#passthrough(resolver, name: self.name, resource_class: self.resource_class) ⇒ 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[:name] is provided, this overrides the default query name sent to the upstream server. The same logic applies to options[:resource_class].



101
102
103
# File 'lib/async/dns/transaction.rb', line 101

def passthrough(resolver, name: self.name, resource_class: self.resource_class)
	resolver.query(name, resource_class)
end

#passthrough!(resolver, force: false, **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[:name] or options[:force] is given.

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



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/async/dns/transaction.rb', line 77

def passthrough!(resolver, force: false, **options, &block)
	if @query.rd || 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.



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

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

#respond!(*args) ⇒ Object

The last argument can optionally be a hash of options. If options[:resource_class] 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).



112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/async/dns/transaction.rb', line 112

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

#The incoming query.=(incomingquery. = (value)) ⇒ Object



37
# File 'lib/async/dns/transaction.rb', line 37

attr :query

#The question to answer.=(questiontoanswer. = (value)) ⇒ Object



40
# File 'lib/async/dns/transaction.rb', line 40

attr :question

#The response to the query.=(responsetothequery. = (value)) ⇒ Object



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

attr :response

#to_sObject

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



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

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