lib/net/dns/resolver.rb in net-dns-0.2.5 vs lib/net/dns/resolver.rb in net-dns-0.3

- old
+ new

@@ -13,12 +13,12 @@ module Net # :nodoc: module DNS + include Logger::Severity - # =Name # # Net::DNS::Resolver - DNS resolver class # # =Synopsis @@ -106,11 +106,10 @@ :use_tcp => false, :ignore_trucated => false, :packet_size => 512, :tcp_timeout => TcpTimeout.new(120), :udp_timeout => UdpTimeout.new(0)} - # Create a new resolver object. # # Argument +config+ can either be empty or be an hash with # some configuration parameters. To know what each parameter @@ -206,11 +205,11 @@ @config = Defaults.merge config @raw = false # New logger facility @logger = Logger.new(@config[:log_file]) - @logger.level = Logger::WARN + @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN #------------------------------------------------------------ # Resolver configuration will be set in order from: # 1) initialize arguments # 2) ENV variables @@ -772,23 +771,40 @@ # # res.logger = log # # Note that this will destroy the precedent logger. # - # This is the only mode user will have to control their logger, such - # as setting the level threshold, because no reader is set for this - # instance variable. - # def logger=(logger) if logger.kind_of? Logger @logger.close @logger = logger else raise ResolverArgumentError, "Argument must be an instance of Logger class" end end + # Set the log level for the built-in logging facility. + # + # The log level can be one of the following: + # + # - +Net::DNS::DEBUG+ + # - +Net::DNS::INFO+ + # - +Net::DNS::WARN+ + # - +Net::DNS::ERROR+ + # - +Net::DNS::FATAL+ + # + # Note that if the global variable $DEBUG is set (like when the + # -d switch is used at the command line) the logger level is + # automatically set at DEGUB. + # + # For further informations, see Logger documentation in the + # Ruby standard library. + # + def log_level=(level) + @logger.level = level + end + # Performs a DNS query for the given name, applying the searchlist if # appropriate. The search algorithm is as follows: # # 1. If the name contains at least one dot, try it as is. # 2. If the name doesn't end in a dot then append each item in the search @@ -1038,41 +1054,64 @@ packet end def send_tcp(packet,packet_data) - # Generate new TCP socket or use persistent one - if @config[:persistent_tcp] and @@tcp_socket - socket = @@tcp_socket - @logger.info "Using persistent socket #{socket.inspect}" - else - socket = Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0) - socket.bind(Socket.pack_sockaddr_in(@config[:source_port],@config[:source_address].to_s)) - @@tcp_socket = socket if @config[:persistent_tcp] - end - ans = "" - response = "" + ans = nil length = [packet_data.size].pack("n") @config[:nameservers].each do |ns| - @config[:tcp_timeout].timeout do + begin + + # Generate new TCP socket or use persistent one + if @config[:persistent_tcp] and @@tcp_socket + socket = @@tcp_socket + @logger.info "Using persistent socket #{socket.inspect}" + else + socket = Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0) + socket.bind(Socket.pack_sockaddr_in(@config[:source_port],@config[:source_address].to_s)) + @@tcp_socket = socket if @config[:persistent_tcp] + end + sockaddr = Socket.pack_sockaddr_in(@config[:port],ns.to_s) - socket.connect(sockaddr) - socket.write(length+packet_data) - ans = socket.recv(Net::DNS::INT16SZ) - len = ans.unpack("n")[0] - p len - next if len == 0 - ans = socket.recv(len) - next if ans.size == 0 - p ans.size + + @config[:tcp_timeout].timeout do + socket.connect(sockaddr) + @logger.info "Contacting nameserver #{ns} port #{@config[:port]}" + socket.write(length+packet_data) + ans = socket.recv(Net::DNS::INT16SZ) + len = ans.unpack("n")[0] + + if len == 0 + @logger.warn "Receiving 0 lenght packet from nameserver #{ns}, trying next." + next + end + + ans = socket.recv(len) + unless ans.size == len + @logger.warn "Malformed packet from nameserver #{ns}, trying next." + next + end + end + ans = [ans,["",@config[:port],ns.to_s,ns.to_s]] @logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}" + + rescue TimeoutError + @logger.warn "Nameserver #{ns} not responding within TCP timeout, trying next one" + next + ensure + socket.close unless @config[:persistent_tcp] end - response = Net::DNS::Packet.parse(ans[0],ans[1]) end - return response + + if ans + return Net::DNS::Packet.parse(ans[0],ans[1]) + else + @logger.fatal "No response from nameservers list: aborting" + raise NoResponseError + end end def send_udp(packet,packet_data) # Generate new UDP socket or use persistent one @@ -1088,10 +1127,11 @@ ans = nil response = "" @config[:nameservers].each do |ns| begin @config[:udp_timeout].timeout do + @logger.info "Contacting nameserver #{ns} port #{@config[:port]}" socket.send(packet_data,0,ns.to_s,@config[:port]) ans = socket.recvfrom(@config[:packet_size]) end if ans @logger.info "Received #{ans[0].size} bytes from #{ans[1][2]+":"+ans[1][1].to_s}" @@ -1100,11 +1140,16 @@ rescue TimeoutError @logger.warn "Nameserver #{ns} not responding within UDP timeout, trying next one" next end end - return Net::DNS::Packet.parse(ans[0],ans[1]) + if ans + return Net::DNS::Packet.parse(ans[0],ans[1]) + else + @logger.fatal "No response from nameservers list: aborting" + raise NoResponseError + end end def valid?(name) if name =~ /[^-\w\.]/ raise ResolverArgumentError, "Invalid domain name #{name}" @@ -1117,10 +1162,12 @@ 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}