Class: Resolv::DNS

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

Defined Under Namespace

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

Constant Summary collapse

Port =
53
UDPSize =
512
DNSThreadGroup =
ThreadGroup.new
RequestID =
{}
RequestIDMutex =
Mutex.new

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_info = nil) ⇒ DNS

Returns a new instance of DNS.



386
387
388
389
390
# File 'lib/resolv.rb', line 386

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

Class Method Details

.allocate_request_id(host, port) ⇒ Object

:nodoc:



555
556
557
558
559
560
561
562
563
564
565
# File 'lib/resolv.rb', line 555

def self.allocate_request_id(host, port) # :nodoc:
  id = nil
  RequestIDMutex.synchronize {
    h = (RequestID[[host, port]] ||= {})
    begin
      id = rangerand(0x0000..0xffff)
    end while h[id] 
    h[id] = true
  }
  id
end

.bind_random_port(udpsock) ⇒ Object

:nodoc:



579
580
581
582
583
584
585
586
# File 'lib/resolv.rb', line 579

def self.bind_random_port(udpsock) # :nodoc:
  begin
    port = rangerand(1024..65535)
    udpsock.bind("", port)
  rescue Errno::EADDRINUSE
    retry
  end
end

.free_request_id(host, port, id) ⇒ Object

:nodoc:



567
568
569
570
571
572
573
574
575
576
577
# File 'lib/resolv.rb', line 567

def self.free_request_id(host, port, id) # :nodoc:
  RequestIDMutex.synchronize {
    key = [host, port]
    if h = RequestID[key]
      h.delete id
      if h.empty?
        RequestID.delete key
      end
    end
  }
end

.open(*args) ⇒ Object



376
377
378
379
380
381
382
383
384
# File 'lib/resolv.rb', line 376

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

.random(arg) ⇒ Object

:nodoc:



530
531
532
# File 'lib/resolv.rb', line 530

def self.random(arg) # :nodoc:
  rand(arg)
end

.rangerand(range) ⇒ Object

:nodoc:



543
544
545
546
547
548
549
550
# File 'lib/resolv.rb', line 543

def self.rangerand(range) # :nodoc:
  base = range.begin
  len = range.end - range.begin
  if !range.exclude_end?
    len += 1
  end
  base + random(len)
end

Instance Method Details

#closeObject



402
403
404
405
406
407
408
# File 'lib/resolv.rb', line 402

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

#each_address(name) ⇒ Object



421
422
423
# File 'lib/resolv.rb', line 421

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

#each_name(address) ⇒ Object



436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'lib/resolv.rb', line 436

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



461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'lib/resolv.rb', line 461

def each_resource(name, typeclass, &proc)
  lazy_initialize
  requester = make_requester
  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, nameserver)
      end
      reply, reply_name = requester.request(sender, tout)
      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.close
  end
end

#extract_resources(msg, name, typeclass) ⇒ Object



498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
# File 'lib/resolv.rb', line 498

def extract_resources(msg, name, typeclass)
  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

Raises:



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

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

#getaddresses(name) ⇒ Object



415
416
417
418
419
# File 'lib/resolv.rb', line 415

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

#getname(address) ⇒ Object

Raises:



425
426
427
428
# File 'lib/resolv.rb', line 425

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

#getnames(address) ⇒ Object



430
431
432
433
434
# File 'lib/resolv.rb', line 430

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

#getresource(name, typeclass) ⇒ Object

Raises:



450
451
452
453
# File 'lib/resolv.rb', line 450

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



455
456
457
458
459
# File 'lib/resolv.rb', line 455

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

#lazy_initializeObject



392
393
394
395
396
397
398
399
400
# File 'lib/resolv.rb', line 392

def lazy_initialize
  @mutex.synchronize {
    unless @initialized
      @config.lazy_initialize
      @initialized = true
    end
  }
  self
end

#make_requesterObject

:nodoc:



490
491
492
493
494
495
496
# File 'lib/resolv.rb', line 490

def make_requester # :nodoc:
  if nameserver = @config.single?
    Requester::ConnectedUDP.new(nameserver)
  else
    Requester::UnconnectedUDP.new
  end
end