lib/net/dns/resolver.rb in net-dns-0.5.3 vs lib/net/dns/resolver.rb in net-dns-0.6.0

- old
+ new

@@ -1,11 +1,5 @@ -# -# $Id: Resolver.rb,v 1.11 2006/07/30 16:55:35 bluemonk Exp $ -# - - - require 'rbconfig' require 'socket' require 'timeout' require 'ipaddr' require 'logger' @@ -13,22 +7,22 @@ require 'net/dns/resolver/timeouts' alias old_send send # -# Resolver helper method +# = Resolver helper method # -# Calling the resolver directly +# Calling the resolver directly: # # require 'net/dns/resolver' # puts Resolver("www.google.com").answer.size -# #=> 5 +# #=> 5 # -# An optional block can be passed yielding the Net::DNS::Packet object +# An optional block can be passed yielding the Net::DNS::Packet object. # # Resolver("www.google.com") {|packet| puts packet.size + " bytes"} -# #=> 484 bytes +# #=> 484 bytes # def Resolver(name,type=Net::DNS::A,cls=Net::DNS::IN,&blk) obj = Net::DNS::Resolver.start(name,type,cls) if block_given? yield obj @@ -40,20 +34,12 @@ module Net # :nodoc: module DNS include Logger::Severity - # =Name - # - # Net::DNS::Resolver - DNS resolver class + # = Net::DNS::Resolver - DNS resolver class # - # =Synopsis - # - # require 'net/dns/resolver' - # - # =Description - # # The Net::DNS::Resolver class implements a complete DNS resolver written # in pure Ruby, without a single C line of code. It has all of the # tipical properties of an evoluted resolver, and a bit of OO which # comes from having used Ruby. # @@ -61,14 +47,12 @@ # written by Martin Fuhr, but turned out (in the last months) to be # an almost complete rewriting. Well, maybe some of the features of # the Perl version are still missing, but guys, at least this is # readable code! # - # FIXME + # == Environment # - # =Environment - # # The Following Environment variables can also be used to configure # the resolver: # # * +RES_NAMESERVERS+: A space-separated list of nameservers to query. # @@ -107,11 +91,22 @@ # # # C Shell # % setenv RES_OPTIONS "retrans:3 retry:2 debug" # class Resolver - + + # Argument Error for class Net::DNS::Resolver. + class ArgumentError < ArgumentError + end + + class Error < StandardError + end + + class NoResponseError < Error + end + + # An hash with the defaults values of almost all the # configuration parameters of a resolver object. See # the description for each parameter to have an # explanation of its usage. Defaults = { @@ -129,12 +124,13 @@ :defname => true, :dns_search => true, :use_tcp => false, :ignore_truncated => false, :packet_size => 512, - :tcp_timeout => TcpTimeout.new(120), - :udp_timeout => UdpTimeout.new(0)} + :tcp_timeout => TcpTimeout.new(5), + :udp_timeout => UdpTimeout.new(5), + } # Create a new resolver object. # # Argument +config+ can either be empty or be an hash with # some configuration parameters. To know what each parameter @@ -150,11 +146,11 @@ # # Set some option # res = Net::DNS::Resolver.new(:nameservers => "172.16.1.1", # :recursive => false, # :retry => 10) # - # ===Config file + # == Config file # # Net::DNS::Resolver uses a config file to read the usual # values a resolver needs, such as nameserver list and # domain names. On UNIX systems the defaults are read from the # following files, in the order indicated: @@ -189,46 +185,46 @@ # overridden by the other arguments to Resolver::new. # # Explicit arguments to Resolver::new override both the system's defaults # and the values of the custom configuration file, if any. # - # ===Parameters + # == Parameters # # The following arguments to Resolver::new are supported: # - # - nameservers: an array reference of nameservers to query. - # - searchlist: an array reference of domains. - # - recurse - # - debug - # - domain - # - port - # - srcaddr - # - srcport - # - tcp_timeout - # - udp_timeout - # - retrans - # - retry - # - usevc - # - stayopen - # - igntc - # - defnames - # - dnsrch - # - persistent_tcp - # - persistent_udp - # - dnssec + # * nameservers: an array reference of nameservers to query. + # * searchlist: an array reference of domains. + # * recurse + # * debug + # * domain + # * port + # * srcaddr + # * srcport + # * tcp_timeout + # * udp_timeout + # * retrans + # * retry + # * usevc + # * stayopen + # * igntc + # * defnames + # * dnsrch + # * persistent_tcp + # * persistent_udp + # * dnssec # # For more information on any of these options, please consult the # method of the same name. # - # ===Disclaimer + # == Disclaimer # # Part of the above documentation is taken from the one in the # Net::DNS::Resolver Perl module. # def initialize(config = {}) - raise ResolverArgumentError, "Argument has to be Hash" unless config.kind_of? Hash - # config.key_downcase! + raise ArgumentError, "Argument has to be Hash" unless config.kind_of? Hash + # config.downcase_keys! @config = Defaults.merge config @raw = false # New logger facility @logger = Logger.new(@config[:log_file]) @@ -260,52 +256,52 @@ config.each do |key,val| next if key == :log_file or key == :config_file begin eval "self.#{key.to_s} = val" rescue NoMethodError - raise ResolverArgumentError, "Option #{key} not valid" + raise ArgumentError, "Option #{key} not valid" end end end - # Get the resolver searchlist, returned as an array of entries + # Get the resolver search list, returned as an array of entries. # # res.searchlist - # #=> ["example.com","a.example.com","b.example.com"] + # #=> ["example.com","a.example.com","b.example.com"] # def searchlist @config[:searchlist].inspect end # Set the resolver searchlist. - # +arg+ can be a single string or an array of strings + # +arg+ can be a single string or an array of strings. # # res.searchstring = "example.com" # res.searchstring = ["example.com","a.example.com","b.example.com"] # - # Note that you can also append a new name to the searchlist + # Note that you can also append a new name to the searchlist. # # res.searchlist << "c.example.com" # res.searchlist - # #=> ["example.com","a.example.com","b.example.com","c.example.com"] + # #=> ["example.com","a.example.com","b.example.com","c.example.com"] # - # The default is an empty array + # The default is an empty array. # def searchlist=(arg) case arg when String @config[:searchlist] = [arg] if valid? arg @logger.info "Searchlist changed to value #{@config[:searchlist].inspect}" when Array @config[:searchlist] = arg if arg.all? {|x| valid? x} @logger.info "Searchlist changed to value #{@config[:searchlist].inspect}" else - raise ResolverArgumentError, "Wrong argument format, neither String nor Array" + raise ArgumentError, "Wrong argument format, neither String nor Array" end end - # Get the list of resolver nameservers, in a dotted decimal format + # Get the list of resolver nameservers, in a dotted decimal format- # # res.nameservers # #=> ["192.168.0.1","192.168.0.2"] # def nameservers @@ -315,21 +311,21 @@ end arr end alias_method :nameserver, :nameservers - # Set the list of resolver nameservers - # +arg+ can be a single ip address or an array of addresses + # Set the list of resolver nameservers. + # +arg+ can be a single ip address or an array of addresses. # # res.nameservers = "192.168.0.1" # res.nameservers = ["192.168.0.1","192.168.0.2"] # - # If you want you can specify the addresses as IPAddr instances + # If you want you can specify the addresses as IPAddr instances. # # ip = IPAddr.new("192.168.0.3") # res.nameservers << ip - # #=> ["192.168.0.1","192.168.0.2","192.168.0.3"] + # #=> ["192.168.0.1","192.168.0.2","192.168.0.3"] # # The default is 127.0.0.1 (localhost) # def nameservers=(arg) case arg @@ -355,34 +351,31 @@ return end when IPAddr x else - raise ResolverArgumentError, "Wrong argument format" + raise ArgumentError, "Wrong argument format" end end @logger.info "Nameservers list changed to value #{@config[:nameservers].inspect}" else - raise ResolverArgumentError, "Wrong argument format, neither String, Array nor IPAddr" + raise ArgumentError, "Wrong argument format, neither String, Array nor IPAddr" end end alias_method("nameserver=","nameservers=") - # Return a string with the default domain - # + # Return a string with the default domain. def domain @config[:domain].inspect end - # Set the domain for the query - # + # Set the domain for the query. def domain=(name) @config[:domain] = name if valid? name end - # Return the defined size of the packet - # + # Return the defined size of the packet. def packet_size @config[:packet_size] end # Get the port number to which the resolver sends queries. @@ -403,15 +396,15 @@ def port=(num) if (0..65535).include? num @config[:port] = num @logger.info "Port number changed to #{num}" else - raise ResolverArgumentError, "Wrong port number #{num}" + raise ArgumentError, "Wrong port number #{num}" end end - # Get the value of the source port number + # Get the value of the source port number. # # puts "Sending queries using port #{res.source_port}" # def source_port @config[:source_port] @@ -434,11 +427,11 @@ raise ResolverPermissionError, "Are you root?" end if (0..65535).include?(num) @config[:source_port] = num else - raise ResolverArgumentError, "Wrong port number #{num}" + raise ArgumentError, "Wrong port number #{num}" end end alias srcport= source_port= # Get the local address from which the resolver sends queries @@ -448,12 +441,11 @@ def source_address @config[:source_address].to_s end alias srcaddr source_address - # Set the local source address from which the resolver sends its - # queries. + # Set the local source address from which the resolver sends its queries. # # res.source_address = "172.16.100.1" # res.source_address = IPAddr.new("172.16.100.1") # # You can specify +arg+ as either a string containing the ip address @@ -470,16 +462,15 @@ # # Note that if you want to set a non-binded source address you need # root priviledges, as raw sockets will be used to generate packets. # The class will then generate an exception if you're not root. # - # The default is 0.0.0.0, meaning any local address (chosen on routing - # needs). + # The default is 0.0.0.0, meaning any local address (chosen on routing needs). # def source_address=(addr) unless addr.respond_to? :to_s - raise ResolverArgumentError, "Wrong address argument #{addr}" + raise ArgumentError, "Wrong address argument #{addr}" end begin port = rand(64000)+1024 @logger.warn "Try to determine state of source address #{addr} with port #{port}" @@ -511,46 +502,43 @@ end end alias srcaddr= source_address= # Return the retrasmission interval (in seconds) the resolvers has - # been set on - # + # been set on. def retry_interval @config[:retry_interval] end alias retrans retry_interval - # Set the retrasmission interval in seconds. Default 5 seconds - # + # Set the retrasmission interval in seconds. Default 5 seconds. def retry_interval=(num) if num > 0 @config[:retry_interval] = num @logger.info "Retransmission interval changed to #{num} seconds" else - raise ResolverArgumentError, "Interval must be positive" + raise ArgumentError, "Interval must be positive" end end alias retrans= retry_interval= - # The number of times the resolver will try a query + # The number of times the resolver will try a query. # # puts "Will try a max of #{res.retry_number} queries" # def retry_number @config[:retry_number] end # Set the number of times the resolver will try a query. - # Default 4 times - # + # Default 4 times. def retry_number=(num) if num.kind_of? Integer and num > 0 @config[:retry_number] = num @logger.info "Retrasmissions number changed to #{num}" else - raise ResolverArgumentError, "Retry value must be a positive integer" + raise ArgumentError, "Retry value must be a positive integer" end end alias_method('retry=', 'retry_number=') # This method will return true if the resolver is configured to @@ -575,16 +563,16 @@ case bool when TrueClass,FalseClass @config[:recursive] = bool @logger.info("Recursive state changed to #{bool}") else - raise ResolverArgumentError, "Argument must be boolean" + raise ArgumentError, "Argument must be boolean" end end alias_method :recurse=, :recursive= - # Return a string rapresenting the resolver state, suitable + # Return a string representing the resolver state, suitable # for printing on the screen. # # puts "Resolver state:" # puts res.state # @@ -627,31 +615,30 @@ case bool when TrueClass,FalseClass @config[:defname] = bool @logger.info("Defname state changed to #{bool}") else - raise ResolverArgumentError, "Argument must be boolean" + raise ArgumentError, "Argument must be boolean" end end - # Get the state of the dns_search flag + # Get the state of the dns_search flag. def dns_search @config[:dns_search] end alias_method :dnsrch, :dns_search # Set the flag +dns_search+ in a boolean state. If +dns_search+ # is true, when using the Resolver#search method will be applied # the search list. Default is true. - # def dns_search=(bool) case bool when TrueClass,FalseClass @config[:dns_search] = bool @logger.info("DNS search state changed to #{bool}") else - raise ResolverArgumentError, "Argument must be boolean" + raise ArgumentError, "Argument must be boolean" end end alias_method("dnsrch=","dns_search=") # Get the state of the use_tcp flag. @@ -676,11 +663,11 @@ case bool when TrueClass,FalseClass @config[:use_tcp] = bool @logger.info("Use tcp flag changed to #{bool}") else - raise ResolverArgumentError, "Argument must be boolean" + raise ArgumentError, "Argument must be boolean" end end alias usevc= use_tcp= def ignore_truncated? @@ -692,11 +679,11 @@ case bool when TrueClass,FalseClass @config[:ignore_truncated] = bool @logger.info("Ignore truncated flag changed to #{bool}") else - raise ResolverArgumentError, "Argument must be boolean" + raise ArgumentError, "Argument must be boolean" end end # Return an object representing the value of the stored TCP # timeout the resolver will use in is queries. This object @@ -710,12 +697,11 @@ # #=> Timeout of 150 seconds # # puts "You set a timeout of " + res.tcp_timeout.pretty_to_s # #=> You set a timeout of 2 minutes and 30 seconds # - # If the timeout is infinite, a string "infinite" will - # be returned. + # If the timeout is infinite, a string "infinite" will be returned. # def tcp_timeout @config[:tcp_timeout].to_s end @@ -723,20 +709,21 @@ # will be performed using TCP. A value of 0 means that # the timeout will be infinite. # The value is stored internally as a +TcpTimeout+ object, see # the description for Resolver#tcp_timeout # - # Default is 120 seconds + # Default is 5 seconds. + # def tcp_timeout=(secs) @config[:tcp_timeout] = TcpTimeout.new(secs) @logger.info("New TCP timeout value: #{@config[:tcp_timeout]} seconds") end # Return an object representing the value of the stored UDP # timeout the resolver will use in is queries. This object # is an instance of the class +UdpTimeout+, and two methods - # are available for printing informations: UdpTimeout#to_s + # are available for printing information: UdpTimeout#to_s # and UdpTimeout#pretty_to_s. # # Here's some example: # # puts "Timeout of #{res.udp_timeout} seconds" # implicit to_s @@ -754,14 +741,15 @@ # Set the value of UDP timeout for resolver queries that # will be performed using UDP. A value of 0 means that # the timeout will not be used, and the resolver will use # only +retry_number+ and +retry_interval+ parameters. - # That is the default. + # + # Default is 5 seconds. # # The value is stored internally as a +UdpTimeout+ object, see - # the description for Resolver#udp_timeout + # the description for Resolver#udp_timeout. # def udp_timeout=(secs) @config[:udp_timeout] = UdpTimeout.new(secs) @logger.info("New UDP timeout value: #{@config[:udp_timeout]} seconds") end @@ -801,11 +789,11 @@ def logger=(logger) if logger.kind_of? Logger @logger.close @logger = logger else - raise ResolverArgumentError, "Argument must be an instance of Logger class" + raise ArgumentError, "Argument must be an instance of Logger class" end end # Set the log level for the built-in logging facility. # @@ -993,12 +981,13 @@ end ans = self.old_send(method,packet,packet_data) unless ans - @logger.fatal "No response from nameservers list: aborting" - raise NoResponseError + message = "No response from nameservers list" + @logger.fatal(message) + raise NoResponseError, message end @logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}" response = Net::DNS::Packet.parse(ans[0],ans[1]) @@ -1031,12 +1020,10 @@ # # It actually uses the same methods a normal Resolver query would # use, but automatically sort the results based on preferences # and returns an ordered array. # - # Example: - # # res = Net::DNS::Resolver.new # res.mx("google.com") # def mx(name,cls=Net::DNS::IN) arr = [] @@ -1044,26 +1031,22 @@ arr << entry if entry.type == 'MX' end return arr.sort_by {|a| a.preference} end - # # Quick resolver method. Bypass the configuration using # the defaults. # - # Example: + # Net::DNS::Resolver.start "www.google.com" # - # puts Net::DNS::Resolver.start "www.google.com" - # def self.start(*params) self.new.search(*params) end private - # Parse a configuration file specified as the argument. - # + # Parses a configuration file specified as the argument. def parse_config_file if self.class.platform_windows? require 'win32/resolv' arr = Win32::Resolv.get_resolv_info self.domain = arr[0] @@ -1082,11 +1065,11 @@ end end end end - # Parse environment variables + # Parses environment variables. def parse_environment_variables if ENV['RES_NAMESERVERS'] self.nameservers = ENV['RES_NAMESERVERS'].split(" ") end if ENV['RES_SEARCHLIST'] @@ -1099,11 +1082,11 @@ ENV['RES_OPTIONS'].split(" ").each do |opt| name,val = opt.split(":") begin eval("self.#{name} = #{val}") rescue NoMethodError - raise ResolverArgumentError, "Invalid ENV option #{name}" + raise ArgumentError, "Invalid ENV option #{name}" end end end end @@ -1217,11 +1200,11 @@ ans end def valid?(name) if name =~ /[^-\w\.]/ - raise ResolverArgumentError, "Invalid domain name #{name}" + raise ArgumentError, "Invalid domain name #{name}" else true end end @@ -1237,46 +1220,8 @@ !!(Config::CONFIG["host_os"] =~ /msdos|mswin|djgpp|mingw/i) end end - end # class Resolver - end # module DNS -end # module Net - -class ResolverArgumentError < ArgumentError # :nodoc: -end -class NoResponseError < StandardError # :nodoc: -end - -module ExtendHash # :nodoc: - # Returns an hash with all the - # keys turned into downcase - # - # hsh = {"Test" => 1, "FooBar" => 2} - # hsh.key_downcase! - # #=> {"test"=>1,"foobar"=>2} - # - def key_downcase! - hsh = Hash.new - self.each do |key,val| - hsh[key.downcase] = val end - self.replace(hsh) end -end - -class Hash # :nodoc: - include ExtendHash -end - - - - - - - - - - - - +end \ No newline at end of file