Class: Dnsruby::Resolver
- Inherits:
-
Object
- Object
- Dnsruby::Resolver
- Defined in:
- lib/dnsruby/resolver.rb
Overview
Description
Dnsruby::Resolver is a DNS stub resolver.
This class performs queries with retries across multiple nameservers.
The system configured resolvers are used by default.
The retry policy is a combination of the Net::DNS and dnsjava approach, and has the option of :
* A total timeout for the query (defaults to 0, meaning "no total timeout")
* A retransmission system that targets the namervers concurrently once the first query round is
complete, but in which the total time per query round is split between the number of nameservers
targetted for the first round. and total time for query round is doubled for each query round
Note that, if a total timeout is specified, then that will apply regardless of the retry policy
(i.e. it may cut retries short).
Note also that these timeouts are distinct from the SingleResolver's packet_timeout
Timeouts apply to the initial query and response. If DNSSEC validation is to
be performed, then additional queries may be required (these are performed automatically
by Dnsruby). Each additional query will be performed with its own timeouts.
So, even with a query_timeout of 5 seconds, a response which required extensive
validation may take several times that long.
(Future versions of Dnsruby may expose finer-grained events for client tracking of
responses and validation)
== Methods
=== Synchronous
These methods raise an exception or return a response message with rcode==NOERROR
* Dnsruby::Resolver#send_message(msg)
* Dnsruby::Resolver#query(name [, type [, klass]])
There are "!" versions of these two methods that return an array [response, error]
instead of raising an error on failure. They can be called as follows:
response, error = resolver.send_message!(...)
response, error = resolver.query!(...)
If the request succeeds, response will contain the Dnsruby::Message response
and error will be nil.
If the request fails, response will be nil and error will contain the error raised.
=== Asynchronous
These methods use a response queue to return the response and the error
* Dnsruby::Resolver#send_async(msg, response_queue, query_id)
== Event Loop
Dnsruby runs a pure Ruby event loop to handle I/O in a single thread.
Support for EventMachine has been deprecated.
Direct Known Subclasses
Defined Under Namespace
Classes: EventType
Constant Summary collapse
- DefaultQueryTimeout =
0
- DefaultPacketTimeout =
5
- DefaultRetryTimes =
1
- DefaultRetryDelay =
5
- DefaultPort =
53
- DefaultDnssec =
true
- AbsoluteMinDnssecUdpSize =
1220
- MinDnssecUdpSize =
4096
- DefaultUDPSize =
MinDnssecUdpSize
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
The current Config.
-
#dnssec ⇒ Object
Use DNSSEC for this Resolver.
-
#do_caching ⇒ Object
Defines whether we will cache responses, or pass every request to the upstream resolver.
-
#do_validation ⇒ Object
Defines whether validation is performed by default on this Resolver when the query method is called.
-
#ignore_truncation ⇒ Object
Should truncation be ignored? i.e.
-
#no_tcp ⇒ Object
If no_tcp==true, then ONLY UDP will be used as a transport.
-
#packet_timeout ⇒ Object
The timeout for any individual packet.
-
#port ⇒ Object
The port to send queries to on the resolver.
-
#query_timeout ⇒ Object
Note that this timeout represents the total time a query may run for - multiple packets can be sent to multiple nameservers in this time.
-
#recurse ⇒ Object
Should the Recursion Desired bit be set?.
-
#retry_delay ⇒ Object
The query will be tried across nameservers retry_times times, with a delay of retry_delay seconds between each retry.
-
#retry_times ⇒ Object
The query will be tried across nameservers retry_times times, with a delay of retry_delay seconds between each retry.
-
#src_address ⇒ Object
The source address to send queries from for IPv4.
-
#src_address6 ⇒ Object
The source address to send queries from for IPv6.
-
#tsig ⇒ Object
Returns the value of attribute tsig.
-
#udp_size ⇒ Object
The maximum UDP size to be used.
-
#use_tcp ⇒ Object
Should TCP be used as a transport rather than UDP? If use_tcp==true, then ONLY TCP will be used as a transport.
Class Method Summary collapse
- .check_port(p, src_port = []) ⇒ Object
- .get_ports_from(p) ⇒ Object
- .get_tsig(args) ⇒ Object
- .port_in_range(p) ⇒ Object
Instance Method Summary collapse
-
#add_config_nameservers ⇒ Object
:nodoc: all.
-
#add_server(server) ⇒ Object
# Add a new SingleResolver to the list of resolvers this Resolver object will # query.
-
#add_src_port(p) ⇒ Object
Can be a single Fixnum or a Range or an Array If an invalid port is selected (one reserved by IANA), then an ArgumentError will be raised.
-
#close ⇒ Object
Close the Resolver.
-
#generate_timeouts(base = 0) ⇒ Object
:nodoc: all.
-
#initialize(*args) ⇒ Resolver
constructor
Create a new Resolver object.
- #nameserver=(n) ⇒ Object
- #nameservers=(ns) ⇒ Object
- #persistent_tcp=(on) ⇒ Object
- #persistent_udp=(on) ⇒ Object
-
#query(name, type = Types.A, klass = Classes.IN, set_cd = @dnssec) ⇒ Object
Query for a name.
-
#query!(name, type = Types.A, klass = Classes.IN, set_cd = @dnssec) ⇒ Object
Like query, but does not raise an error when an error occurs.
-
#query_no_validation_or_recursion(name, type = Types.A, klass = Classes.IN) ⇒ Object
:nodoc: all.
-
#reset_attributes ⇒ Object
:nodoc: all.
-
#send_async(msg, client_queue, client_query_id = nil) ⇒ Object
Asynchronously send a Message to the server.
-
#send_message(message) ⇒ Object
Send a message, and wait for the response.
-
#send_message!(message) ⇒ Object
Like send_message, but does not raise an error when an error occurs.
-
#send_plain_message(message) ⇒ Object
This method takes a Message (supplied by the client), and sends it to the configured nameservers.
- #set_config_nameserver(n) ⇒ Object
-
#single_res_mutex ⇒ Object
:nodoc: all.
-
#single_resolvers ⇒ Object
}.
-
#single_resolvers=(s) ⇒ Object
The array of SingleResolvers used for sending query messages attr_accessor :single_resolvers # :nodoc:.
-
#src_port ⇒ Object
The source port to send queries from Returns either a single Fixnum or an Array e.g.
-
#src_port=(p) ⇒ Object
Can be a single Fixnum or a Range or an Array If an invalid port is selected (one reserved by IANA), then an ArgumentError will be raised.
-
#update ⇒ Object
:nodoc: all.
- #update_internal_res(res) ⇒ Object
Constructor Details
#initialize(*args) ⇒ Resolver
Create a new Resolver object. If no parameters are passed in, then the default
system configuration will be used. Otherwise, a Hash may be passed in with the
following optional elements :
* :port
* :use_tcp
* :tsig
* :ignore_truncation
* :src_address
* :src_address6
* :src_port
* :recurse
* :udp_size
* :config_info - see Config
* :nameserver - can be either a String or an array of Strings
* :packet_timeout
* :query_timeout
* :retry_times
* :retry_delay
* :do_caching
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/dnsruby/resolver.rb', line 403 def initialize(*args) # @TODO@ Should we allow :namesver to be an RRSet of NS records? Would then need to randomly order them? @resolver_ruby = nil @src_address = nil @src_address6 = nil @single_res_mutex = Mutex.new @configured = false @do_caching = true @config = Config.new() reset_attributes # Process args if args.length == 1 if args[0].class == Hash args[0].keys.each do |key| begin if key == :config_info @config.set_config_info(args[0][:config_info]) elsif key == :nameserver set_config_nameserver(args[0][:nameserver]) elsif key == :nameservers set_config_nameserver(args[0][:nameservers]) else send(key.to_s + '=', args[0][key]) end rescue Exception => e Dnsruby.log.error{"Argument #{key} not valid : #{e}\n"} end end elsif args[0].class == String set_config_nameserver(args[0]) elsif args[0].class == Config # also accepts a Config object from Dnsruby::Resolv @config = args[0] end else # Anything to do? end update end |
Instance Attribute Details
#config ⇒ Object (readonly)
The current Config
121 122 123 |
# File 'lib/dnsruby/resolver.rb', line 121 def config @config end |
#dnssec ⇒ Object
Use DNSSEC for this Resolver
157 158 159 |
# File 'lib/dnsruby/resolver.rb', line 157 def dnssec @dnssec end |
#do_caching ⇒ Object
Defines whether we will cache responses, or pass every request to the
upstream resolver. This is only really useful when querying authoritative
servers (as the upstream recursive resolver is likely to cache)
124 125 126 |
# File 'lib/dnsruby/resolver.rb', line 124 def do_caching @do_caching end |
#do_validation ⇒ Object
Defines whether validation is performed by default on this Resolver when the
query method is called.
Note that send_message and send_async expect a
Message object to be passed in, which is already configured to the callers
requirements.
164 165 166 |
# File 'lib/dnsruby/resolver.rb', line 164 def do_validation @do_validation end |
#ignore_truncation ⇒ Object
Should truncation be ignored?
i.e. the TC bit is ignored and thus the resolver will not requery over TCP if TC is set
106 107 108 |
# File 'lib/dnsruby/resolver.rb', line 106 def ignore_truncation @ignore_truncation end |
#no_tcp ⇒ Object
If no_tcp==true, then ONLY UDP will be used as a transport.
This should not generally be used, but is provided as a debugging aid.
99 100 101 |
# File 'lib/dnsruby/resolver.rb', line 99 def no_tcp @no_tcp end |
#packet_timeout ⇒ Object
The timeout for any individual packet. This is the timeout used by SingleResolver
142 143 144 |
# File 'lib/dnsruby/resolver.rb', line 142 def packet_timeout @packet_timeout end |
#port ⇒ Object
The port to send queries to on the resolver
91 92 93 |
# File 'lib/dnsruby/resolver.rb', line 91 def port @port end |
#query_timeout ⇒ Object
Note that this timeout represents the total time a query may run for - multiple packets
can be sent to multiple nameservers in this time.
This is distinct from the SingleResolver per-packet timeout
The query_timeout is not required - it will default to 0, which means "do not use query_timeout".
If this is the case then the timeout will be dictated by the retry_times and retry_delay attributes
149 150 151 |
# File 'lib/dnsruby/resolver.rb', line 149 def query_timeout @query_timeout end |
#recurse ⇒ Object
Should the Recursion Desired bit be set?
115 116 117 |
# File 'lib/dnsruby/resolver.rb', line 115 def recurse @recurse end |
#retry_delay ⇒ Object
The query will be tried across nameservers retry_times times, with a delay of retry_delay seconds
between each retry. The first time round, retry_delay will be divided by the number of nameservers
being targetted, and a new nameserver will be queried with the resultant delay.
154 155 156 |
# File 'lib/dnsruby/resolver.rb', line 154 def retry_delay @retry_delay end |
#retry_times ⇒ Object
The query will be tried across nameservers retry_times times, with a delay of retry_delay seconds
between each retry. The first time round, retry_delay will be divided by the number of nameservers
being targetted, and a new nameserver will be queried with the resultant delay.
154 155 156 |
# File 'lib/dnsruby/resolver.rb', line 154 def retry_times @retry_times end |
#src_address ⇒ Object
The source address to send queries from for IPv4
109 110 111 |
# File 'lib/dnsruby/resolver.rb', line 109 def src_address @src_address end |
#src_address6 ⇒ Object
The source address to send queries from for IPv6
112 113 114 |
# File 'lib/dnsruby/resolver.rb', line 112 def src_address6 @src_address6 end |
#tsig ⇒ Object
Returns the value of attribute tsig.
102 103 104 |
# File 'lib/dnsruby/resolver.rb', line 102 def tsig @tsig end |
#udp_size ⇒ Object
The maximum UDP size to be used
118 119 120 |
# File 'lib/dnsruby/resolver.rb', line 118 def udp_size @udp_size end |
#use_tcp ⇒ Object
Should TCP be used as a transport rather than UDP?
If use_tcp==true, then ONLY TCP will be used as a transport.
95 96 97 |
# File 'lib/dnsruby/resolver.rb', line 95 def use_tcp @use_tcp end |
Class Method Details
.check_port(p, src_port = []) ⇒ Object
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 |
# File 'lib/dnsruby/resolver.rb', line 615 def Resolver.check_port(p, src_port=[]) if p.class != Fixnum tmp_src_ports = Array.new(src_port) p.each do |x| unless Resolver.check_port(x, tmp_src_ports) return false end tmp_src_ports.push(x) end return true end if Resolver.port_in_range(p) return ! ((p == 0) && (src_port.length > 0)) else Dnsruby.log.error("Illegal port (#{p})") log_and_raise("Illegal port #{p}", ArgumentError) end end |
.get_ports_from(p) ⇒ Object
638 639 640 641 642 643 644 645 646 647 648 |
# File 'lib/dnsruby/resolver.rb', line 638 def Resolver.get_ports_from(p) a = [] if p.class == Fixnum a = [p] else p.each do |x| a.push(x) end end a end |
.get_tsig(args) ⇒ Object
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 |
# File 'lib/dnsruby/resolver.rb', line 689 def Resolver.get_tsig(args) tsig = nil if args.length == 1 if args[0] if args[0].instance_of?(RR::TSIG) tsig = args[0] elsif args[0].instance_of?(Array) tsig = RR.new_from_hash((args)) end else # Dnsruby.log.debug{'TSIG signing switched off'} return nil end else tsig = RR.new_from_hash((args)) end Dnsruby.log.info{"TSIG signing now using #{tsig.name}, key=#{tsig.key}"} tsig end |
.port_in_range(p) ⇒ Object
634 635 636 |
# File 'lib/dnsruby/resolver.rb', line 634 def Resolver.port_in_range(p) (p == 0) || ((p >= 50000) && (p <= 65535)) end |
Instance Method Details
#add_config_nameservers ⇒ Object
:nodoc: all
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 |
# File 'lib/dnsruby/resolver.rb', line 444 def add_config_nameservers # :nodoc: all unless @configured @config.get_ready end @configured = true @single_res_mutex.synchronize { # Add the Config nameservers @config.nameserver.each do |ns| res = PacketSender.new({ server: ns, dnssec: @dnssec, use_tcp: @use_tcp, no_tcp: @no_tcp, packet_timeout: @packet_timeout, tsig: @tsig, ignore_truncation: @ignore_truncation, src_address: @src_address, src_address6: @src_address6, src_port: @src_port, recurse: @recurse, udp_size: @udp_size}) @single_resolvers.push(res) if res end } end |
#add_server(server) ⇒ Object
# Add a new SingleResolver to the list of resolvers this Resolver object will
# query.
def add_resolver(internal) # :nodoc:
# @TODO@ Make a new PacketSender from this SingleResolver!!
@single_resolvers.push(internal)
end
527 528 529 530 531 532 533 |
# File 'lib/dnsruby/resolver.rb', line 527 def add_server(server)# :nodoc: @configured = true res = PacketSender.new(server) log_and_raise("Can't create server #{server}", ArgumentError) unless res update_internal_res(res) @single_res_mutex.synchronize { @single_resolvers.push(res) } end |
#add_src_port(p) ⇒ Object
Can be a single Fixnum or a Range or an Array
If an invalid port is selected (one reserved by
IANA), then an ArgumentError will be raised.
"0" means "any valid port" - this is only a viable
option if it is the only port in the list.
An ArgumentError will be raised if "0" is added to
an existing set of source ports.
res.add_src_port(60000)
res.add_src_port([60001,60005,60010])
res.add_src_port(60015..60115)
601 602 603 604 605 606 607 608 609 610 611 612 613 |
# File 'lib/dnsruby/resolver.rb', line 601 def add_src_port(p) if Resolver.check_port(p, @src_port) a = Resolver.get_ports_from(p) a.each do |x| if (@src_port.length > 0) && (x == 0) log_and_raise("src_port of 0 only allowed as only src_port value (currently #{@src_port.length} values", ArgumentError) end @src_port.push(x) end end update end |
#close ⇒ Object
Close the Resolver. Unfinished queries are terminated with OtherResolvError.
378 379 380 |
# File 'lib/dnsruby/resolver.rb', line 378 def close @resolver_ruby.close if @resolver_ruby end |
#generate_timeouts(base = 0) ⇒ Object
:nodoc: all
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 |
# File 'lib/dnsruby/resolver.rb', line 772 def generate_timeouts(base=0) # :nodoc: all # These should be be pegged to the single_resolver they are targetting : # e.g. timeouts[timeout1]=nameserver timeouts = {} retry_delay = @retry_delay # @single_res_mutex.synchronize { @retry_times.times do |retry_count| if retry_count > 0 retry_delay *= 2 end @single_resolvers.delete(nil) # Just in case... @single_resolvers.each_index do |i| res = @single_resolvers[i] offset = (i * @retry_delay.to_f / @single_resolvers.length) if retry_count == 0 timeouts[base + offset]=[res, retry_count] else if timeouts.has_key?(base + retry_delay + offset) log_and_raise('Duplicate timeout key!') end timeouts[base + retry_delay + offset]=[res, retry_count] end end end # } timeouts end |
#nameserver=(n) ⇒ Object
548 549 550 551 552 553 |
# File 'lib/dnsruby/resolver.rb', line 548 def nameserver=(n) @configured = true @single_res_mutex.synchronize { @single_resolvers=[] } set_config_nameserver(n) add_config_nameservers end |
#nameservers=(ns) ⇒ Object
544 545 546 |
# File 'lib/dnsruby/resolver.rb', line 544 def nameservers=(ns) self.nameserver=(ns) end |
#persistent_tcp=(on) ⇒ Object
732 733 734 735 |
# File 'lib/dnsruby/resolver.rb', line 732 def persistent_tcp=(on) @persistent_tcp = on update end |
#persistent_udp=(on) ⇒ Object
737 738 739 740 |
# File 'lib/dnsruby/resolver.rb', line 737 def persistent_udp=(on) @persistent_udp = on update end |
#query(name, type = Types.A, klass = Classes.IN, set_cd = @dnssec) ⇒ Object
Query for a name. If a valid Message is received, then it is returned
to the caller. Otherwise an exception (a Dnsruby::ResolvError or Dnsruby::ResolvTimeout) is raised.
require 'dnsruby'
res = Dnsruby::Resolver.new
response = res.query('example.com') # defaults to Types.A, Classes.IN
response = res.query('example.com', Types.MX)
response = res.query('208.77.188.166') # IPv4 address so PTR query will be made
response = res.query('208.77.188.166', Types.PTR)
186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/dnsruby/resolver.rb', line 186 def query(name, type=Types.A, klass=Classes.IN, set_cd=@dnssec) msg = Message.new msg.do_caching = @do_caching msg.header.rd = 1 msg.add_question(name, type, klass) msg.do_validation = @do_validation if @dnssec msg.header.cd = set_cd # We do our own validation by default end (msg) end |
#query!(name, type = Types.A, klass = Classes.IN, set_cd = @dnssec) ⇒ Object
Like query, but does not raise an error when an error occurs.
Instead, it returns it.
@return a 2 element array: [response, error]
201 202 203 204 205 206 207 208 209 |
# File 'lib/dnsruby/resolver.rb', line 201 def query!(name, type=Types.A, klass=Classes.IN, set_cd=@dnssec) response = nil; error = nil begin response = query(name, type, klass, set_cd) rescue => e error = e end [response, error] end |
#query_no_validation_or_recursion(name, type = Types.A, klass = Classes.IN) ⇒ Object
:nodoc: all
211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/dnsruby/resolver.rb', line 211 def query_no_validation_or_recursion(name, type=Types.A, klass=Classes.IN) # :nodoc: all msg = Message.new msg.do_caching = @do_caching msg.header.rd = false msg.do_validation = false msg.add_question(name, type, klass) if @dnssec msg.header.cd = true # We do our own validation by default end (msg) end |
#reset_attributes ⇒ Object
:nodoc: all
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
# File 'lib/dnsruby/resolver.rb', line 479 def reset_attributes # :nodoc: all @resolver_ruby.reset_attributes if @resolver_ruby # Attributes # do_validation tells the Resolver whether to try to validate the response # with DNSSEC. This should work for NSEC-signed domains, but NSEC3 # validation is not currently supported. This attribute now defaults to # false. Please let me know if you require NSEC3 validation. @do_validation = false @query_timeout = DefaultQueryTimeout @retry_delay = DefaultRetryDelay @retry_times = DefaultRetryTimes @packet_timeout = DefaultPacketTimeout @port = DefaultPort @udp_size = DefaultUDPSize @dnssec = DefaultDnssec @do_caching= true @use_tcp = false @no_tcp = false @tsig = nil @ignore_truncation = false @config = Config.new() @src_address = nil @src_address6 = nil @src_port = [0] @recurse = true @single_res_mutex.synchronize { @single_resolvers=[] } @configured = false end |
#send_async(msg, client_queue, client_query_id = nil) ⇒ Object
Asynchronously send a Message to the server. The send can be done using just
Dnsruby. Support for EventMachine has been deprecated.
== Dnsruby pure Ruby event loop :
A client_queue is supplied by the client,
along with an optional client_query_id to identify the response. The client_query_id
is generated, if not supplied, and returned to the client.
When the response is known,
a tuple of (query_id, response_message, exception) will be added to the client_queue.
The query is sent synchronously in the caller's thread. The select thread is then used to
listen for and process the response (up to pushing it to the client_queue). The client thread
is then used to retrieve the response and deal with it.
Takes :
* msg - the message to send
* client_queue - a Queue to push the response to, when it arrives
* client_query_id - an optional ID to identify the query to the client
* use_tcp - whether to use only TCP (defaults to SingleResolver.use_tcp)
Returns :
* client_query_id - to identify the query response to the client. This ID is
generated if it is not passed in by the client
=== Example invocations :
id = res.send_async(msg, queue)
NOT SUPPORTED : id = res.send_async(msg, queue, use_tcp)
id = res.send_async(msg, queue, id)
id = res.send_async(msg, queue, id, use_tcp)
=== Example code :
require 'dnsruby'
res = Dnsruby::Resolver.newsend
query_id = 10 # can be any object you like
query_queue = Queue.new
res.send_async(Message.new('example.com', Types.MX), query_queue, query_id)
query_id_2 = res.send_async(Message.new('example.com', Types.A), query_queue)
# ...do a load of other stuff here...
2.times do
response_id, response, exception = query_queue.pop
# You can check the ID to see which query has been answered
if exception == nil
# deal with good response
else
# deal with problem
end
end
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/dnsruby/resolver.rb', line 358 def send_async(msg, client_queue, client_query_id = nil) unless @configured add_config_nameservers end # @single_res_mutex.synchronize { unless @resolver_ruby # @TODO@ Synchronize this? @resolver_ruby = ResolverRuby.new(self) end # } client_query_id = @resolver_ruby.send_async(msg, client_queue, client_query_id) if @single_resolvers.length == 0 Thread.start { sleep(@query_timeout == 0 ? 1 : @query_timeout) client_queue.push([client_query_id, nil, ResolvTimeout.new('Query timed out - no nameservers configured')]) } end client_query_id end |
#send_message(message) ⇒ Object
Send a message, and wait for the response. If a valid Message is received, then it is returned
to the caller. Otherwise an exception (a Dnsruby::ResolvError or Dnsruby::ResolvTimeout) is raised.
send_async is called internally.
example :
require 'dnsruby'
include Dnsruby
res = Dnsruby::Resolver.new
begin
response = res.send_message(Message.new('example.com', Types.MX))
rescue ResolvError
# ...
rescue ResolvTimeout
# ...
end
240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/dnsruby/resolver.rb', line 240 def () Dnsruby.log.debug{'Resolver : sending message'} q = Queue.new send_async(, q) _id, result, error = q.pop if error raise error else result end end |
#send_message!(message) ⇒ Object
Like send_message, but does not raise an error when an error occurs.
Instead, it returns it.
@return a 2 element array: [response, error]
257 258 259 260 261 262 263 264 265 |
# File 'lib/dnsruby/resolver.rb', line 257 def () response = nil; error = nil begin response = () rescue => e error = e end [response, error] end |
#send_plain_message(message) ⇒ Object
This method takes a Message (supplied by the client), and sends it to
the configured nameservers. No changes are made to the Message before it
is sent (TSIG signatures will be applied if configured on the Resolver).
Retries are handled as the Resolver is configured to do.
Incoming responses to the query are not cached or validated (although TCP
fallback will be performed if the TC bit is set and the (Single)Resolver has
ignore_truncation set to false).
Note that the Message is left untouched - this means that no OPT records are
added, even if the UDP transport for the server is specified at more than 512
bytes. If it is desired to use EDNS for this packet, then you should call
the Dnsruby::PacketSender#prepare_for_dnssec(msg), or
Dnsruby::PacketSender#add_opt_rr(msg)
The return value from this method is the [response, error] tuple. Either of
these values may be nil - it is up to the client to check.
example :
require 'dnsruby'
include Dnsruby
res = Dnsruby::Resolver.new
response, error = res.send_plain_message(Message.new('example.com', Types.MX))
if error
print "Error returned : #{error}\n"
else
process_response(response)
end
293 294 295 296 297 298 299 300 301 302 |
# File 'lib/dnsruby/resolver.rb', line 293 def () Dnsruby::TheLog.debug('Resolver : send_plain_message') .do_caching = false .do_validation = false .send_raw = true q = Queue.new send_async(, q) _id, result, error = q.pop [result, error] end |
#set_config_nameserver(n) ⇒ Object
470 471 472 473 474 475 476 477 |
# File 'lib/dnsruby/resolver.rb', line 470 def set_config_nameserver(n) # @TODO@ Should we allow NS RRSet here? If so, then .sort_by {rand} @config.get_ready unless @configured @configured = true @config.nameserver = n.kind_of?(String) ? [n] : n add_config_nameservers end |
#single_res_mutex ⇒ Object
:nodoc: all
768 769 770 |
# File 'lib/dnsruby/resolver.rb', line 768 def single_res_mutex # :nodoc: all @single_res_mutex end |
#single_resolvers ⇒ Object
}
134 135 136 137 138 139 |
# File 'lib/dnsruby/resolver.rb', line 134 def single_resolvers # :nodoc: unless @configured add_config_nameservers end @single_resolvers end |
#single_resolvers=(s) ⇒ Object
The array of SingleResolvers used for sending query messages
attr_accessor :single_resolvers # :nodoc:
128 129 130 131 132 133 |
# File 'lib/dnsruby/resolver.rb', line 128 def single_resolvers=(s) # :nodoc: @configured = true # @single_res_mutex.synchronize { @single_resolvers = s # } end |
#src_port ⇒ Object
The source port to send queries from
Returns either a single Fixnum or an Array
e.g. '0', or '[60001, 60002, 60007]'
Defaults to 0 - random port
570 571 572 |
# File 'lib/dnsruby/resolver.rb', line 570 def src_port @src_port.length == 1 ? @src_port[0] : @src_port end |
#src_port=(p) ⇒ Object
Can be a single Fixnum or a Range or an Array
If an invalid port is selected (one reserved by
IANA), then an ArgumentError will be raised.
res.src_port=0
res.src_port=[60001,60005,60010]
res.src_port=60015..60115
582 583 584 585 586 587 |
# File 'lib/dnsruby/resolver.rb', line 582 def src_port=(p) if Resolver.check_port(p) @src_port = Resolver.get_ports_from(p) update end end |
#update ⇒ Object
:nodoc: all
512 513 514 515 516 517 518 |
# File 'lib/dnsruby/resolver.rb', line 512 def update # :nodoc: all # Update any resolvers we have with the latest config @single_res_mutex.synchronize do @single_resolvers.delete(nil) # Just in case... @single_resolvers.each { |res| update_internal_res(res) } end end |
#update_internal_res(res) ⇒ Object
535 536 537 538 539 540 541 542 |
# File 'lib/dnsruby/resolver.rb', line 535 def update_internal_res(res) [:port, :use_tcp, :no_tcp, :tsig, :ignore_truncation, :packet_timeout, :src_address, :src_address6, :src_port, :recurse, :udp_size, :dnssec].each do |param| res.send(param.to_s + '=', instance_variable_get('@' + param.to_s)) end end |