Class: Resolv::DNS

Inherits:
Object
  • Object
show all
Defined in:
lib/resolv.rb

Overview

Resolv::DNS is a DNS stub resolver.

Information taken from the following places:

  • STD0013
  • RFC 1035
  • ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
  • etc.

Defined Under Namespace

Modules: Label, OpCode, RCode Classes: Config, DecodeError, EncodeError, Message, Name, Query, Requester, Resource

Constant Summary collapse

Port =

Default DNS Port

53
UDPSize =

Default DNS UDP packet size

512
DNSThreadGroup =

Group of DNS resolver threads

ThreadGroup.new

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_info = nil) ⇒ DNS

Creates a new DNS resolver.

config_info can be:

nil

Uses /etc/resolv.conf.

String

Path to a file using /etc/resolv.conf's format.

Hash

Must contain :nameserver, :search and :ndots keys.

Example:

Resolv::DNS.new(:nameserver => ['210.251.121.21'],
              :search => ['ruby-lang.org'],
              :ndots => 1)


323
324
325
326
327
# File 'lib/resolv.rb', line 323

def initialize(config_info=nil)
  @mutex = Mutex.new
  @config = Config.new(config_info)
  @initialized = nil
end

Class Method Details

.open(*args) ⇒ Object

Creates a new DNS resolver. See Resolv::DNS.new for argument details.

Yields the created DNS resolver to the block, if given, otherwise returns it.



298
299
300
301
302
303
304
305
306
# File 'lib/resolv.rb', line 298

def self.open(*args)
  dns = new(*args)
  return dns unless block_given?
  begin
    yield dns
  ensure
    dns.close
  end
end

Instance Method Details

#closeObject

Closes the DNS resolver.



349
350
351
352
353
354
355
356
357
# File 'lib/resolv.rb', line 349

def close
  @mutex.synchronize {
    if @initialized
      @requester.close if @requester
      @requester = nil
      @initialized = false
    end
  }
end

#each_address(name) ⇒ Object

Iterates over all IP addresses for name retrieved from the DNS resolver.

name can be a Resolv::DNS::Name or a String. Retrieved addresses will be a Resolv::IPv4 or Resolv::IPv6



389
390
391
392
# File 'lib/resolv.rb', line 389

def each_address(name)
  each_resource(name, Resource::IN::A) {|resource| yield resource.address}
  each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
end

#each_name(address) ⇒ Object

Iterates over all hostnames for address retrieved from the DNS resolver.

address must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved names will be Resolv::DNS::Name instances.



424
425
426
427
428
429
430
431
432
433
434
435
436
# File 'lib/resolv.rb', line 424

def each_name(address)
  case address
  when Name
    ptr = address
  when IPv4::Regex
    ptr = IPv4.create(address).to_name
  when IPv6::Regex
    ptr = IPv6.create(address).to_name
  else
    raise ResolvError.new("cannot interpret as address: #{address}")
  end
  each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
end

#each_resource(name, typeclass, &proc) ⇒ Object

Iterates over all typeclass DNS resources for name. See #getresource for argument details.



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
# File 'lib/resolv.rb', line 480

def each_resource(name, typeclass, &proc)
  lazy_initialize
  q = Queue.new
  senders = {}
  begin
    @config.resolv(name) {|candidate, tout, nameserver|
      msg = Message.new
      msg.rd = 1
      msg.add_question(candidate, typeclass)
      unless sender = senders[[candidate, nameserver]]
        sender = senders[[candidate, nameserver]] =
          @requester.sender(msg, candidate, q, nameserver)
      end
      sender.send
      reply = reply_name = nil
      timeout(tout, ResolvTimeout) { reply, reply_name = q.pop }
      case reply.rcode
      when RCode::NoError
        extract_resources(reply, reply_name, typeclass, &proc)
        return
      when RCode::NXDomain
        raise Config::NXDomain.new(reply_name.to_s)
      else
        raise Config::OtherResolvError.new(reply_name.to_s)
      end
    }
  ensure
    @requester.delete(q)
  end
end

#extract_resources(msg, name, typeclass) ⇒ Object

:nodoc:



511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
# File 'lib/resolv.rb', line 511

def extract_resources(msg, name, typeclass) # :nodoc:
  if typeclass < Resource::ANY
    n0 = Name.create(name)
    msg.each_answer {|n, ttl, data|
      yield data if n0 == n
    }
  end
  yielded = false
  n0 = Name.create(name)
  msg.each_answer {|n, ttl, data|
    if n0 == n
      case data
      when typeclass
        yield data
        yielded = true
      when Resource::CNAME
        n0 = data.name
      end
    end
  }
  return if yielded
  msg.each_answer {|n, ttl, data|
    if n0 == n
      case data
      when typeclass
        yield data
      end
    end
  }
end

#getaddress(name) ⇒ Object

Gets the IP address of name from the DNS resolver.

name can be a Resolv::DNS::Name or a String. Retrieved address will be a Resolv::IPv4 or Resolv::IPv6

Raises:



365
366
367
368
# File 'lib/resolv.rb', line 365

def getaddress(name)
  each_address(name) {|address| return address}
  raise ResolvError.new("DNS result has no information for #{name}")
end

#getaddresses(name) ⇒ Object

Gets all IP addresses for name from the DNS resolver.

name can be a Resolv::DNS::Name or a String. Retrieved addresses will be a Resolv::IPv4 or Resolv::IPv6



376
377
378
379
380
# File 'lib/resolv.rb', line 376

def getaddresses(name)
  ret = []
  each_address(name) {|address| ret << address}
  return ret
end

#getname(address) ⇒ Object

Gets the hostname for address from the DNS resolver.

address must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved name will be a Resolv::DNS::Name.

Raises:



400
401
402
403
# File 'lib/resolv.rb', line 400

def getname(address)
  each_name(address) {|name| return name}
  raise ResolvError.new("DNS result has no information for #{address}")
end

#getnames(address) ⇒ Object

Gets all hostnames for address from the DNS resolver.

address must be a Resolv::IPv4, Resolv::IPv6 or a String. Retrieved names will be Resolv::DNS::Name instances.



411
412
413
414
415
# File 'lib/resolv.rb', line 411

def getnames(address)
  ret = []
  each_name(address) {|name| ret << name}
  return ret
end

#getresource(name, typeclass) ⇒ Object

Look up the typeclass DNS resource of name.

name must be a Resolv::DNS::Name or a String.

typeclass should be one of the following:

  • Resolv::DNS::Resource::IN::A
  • Resolv::DNS::Resource::IN::AAAA
  • Resolv::DNS::Resource::IN::ANY
  • Resolv::DNS::Resource::IN::CNAME
  • Resolv::DNS::Resource::IN::HINFO
  • Resolv::DNS::Resource::IN::MINFO
  • Resolv::DNS::Resource::IN::MX
  • Resolv::DNS::Resource::IN::NS
  • Resolv::DNS::Resource::IN::PTR
  • Resolv::DNS::Resource::IN::SOA
  • Resolv::DNS::Resource::IN::TXT
  • Resolv::DNS::Resource::IN::WKS

Returned resource is represented as a Resolv::DNS::Resource instance, i.e. Resolv::DNS::Resource::IN::A.

Raises:



461
462
463
464
# File 'lib/resolv.rb', line 461

def getresource(name, typeclass)
  each_resource(name, typeclass) {|resource| return resource}
  raise ResolvError.new("DNS result has no information for #{name}")
end

#getresources(name, typeclass) ⇒ Object

Looks up all typeclass DNS resources for name. See #getresource for argument details.



470
471
472
473
474
# File 'lib/resolv.rb', line 470

def getresources(name, typeclass)
  ret = []
  each_resource(name, typeclass) {|resource| ret << resource}
  return ret
end

#lazy_initializeObject

:nodoc:



329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/resolv.rb', line 329

def lazy_initialize # :nodoc:
  @mutex.synchronize {
    unless @initialized
      @config.lazy_initialize

      if nameserver = @config.single?
        @requester = Requester::ConnectedUDP.new(nameserver)
      else
        @requester = Requester::UnconnectedUDP.new
      end

      @initialized = true
    end
  }
  self
end