Parent

Included Modules

Net::DNS::Packet

Name

Net::DNS::Packet - DNS packet object class

Synopsis

require 'net/dns/packet'

Description

The Net::DNS::Packet class represents an entire DNS packet, divided in his main section:

You can use this class whenever you need to create a DNS packet, whether in an user application, in a resolver instance (have a look, for instance, at the Net::DNS::Resolver#send method) or for a nameserver.

Some example:

# Create a packet
packet = Net::DNS::Packet.new("www.example.com")
mx = Net::DNS::Packet.new("example.com", Net::DNS::MX)

# Getting packet binary data, suitable for network transmission
data = packet.data

A packet object can be created from binary data too, like an answer packet just received from a network stream:

packet = Net::DNS::Packet::parse(data)

Each part of a packet can be gotten by the right accessors:

header = packet.header     # Instance of Net::DNS::Header class
question = packet.question # Instance of Net::DNS::Question class

# Iterate over additional RRs
packet.additional.each do |rr|
  puts "Got an #{rr.type} record"
end

Some iterators have been written to easy the access of those RRs, which are often the most important. So instead of doing:

packet.answer.each do |rr|
  if rr.type == Net::DNS::RR::Types::A
    # do something with +rr.address+
  end
end

we can do:

packet.each_address do |ip|
  # do something with +ip+
end

Be sure you don't miss all the iterators in the class documentation.

Logging facility

As Net::DNS::Resolver class, Net::DNS::Packet class has its own logging facility too. It work in the same way the other one do, so you can maybe want to override it or change the file descriptor.

packet = Net::DNS::Packet.new("www.example.com")
packet.logger = $stderr

# or even
packet.logger = Logger.new("/tmp/packet.log")

If the Net::DNS::Packet class is directly instantiated by the Net::DNS::Resolver class, like the great majority of the time, it will use the same logger facility.

Logger level will be set to Logger::Debug if $DEBUG variable is set.

Error classes

Some error classes has been defined for the Net::DNS::Packet class, which are listed here to keep a light and browsable main documentation. We have:

ArgumentError

Argument Error for class Net::DNS::Packet

PacketError

Generic Packet Error

Copyright

Copyright (c) 2006 Marco Ceresa

All rights reserved. This program is free software; you may redistribute it and/or modify it under the same terms as Ruby itself.

Attributes

additional[R]
answer[R]
answerfrom[R]
answersize[R]
authority[R]
header[R]
question[R]

Public Class Methods

new(name, type = Net::DNS::A, cls = Net::DNS::IN) click to toggle source

Create a new instance of Net::DNS::Packet class. Arguments are the canonical name of the resourse, an optional type field and an optional class field. The record type and class can be omitted; they default to A and IN.

packet = Net::DNS::Packet.new("www.example.com")
packet = Net::DNS::Packet.new("example.com", Net::DNS::MX)
packet = Net::DNS::Packet.new("example.com", Net::DNS::TXT, Net::DNS::CH)

This class no longer instantiate object from binary data coming from network streams. Please use Net::DNS::Packet.new_from_data instead.

# File lib/net/dns/packet.rb, line 138
def initialize(name, type = Net::DNS::A, cls = Net::DNS::IN)
  @header = Net::DNS::Header.new(:qdCount => 1)
  @question = [Net::DNS::Question.new(name, type, cls)]
  @answer = []
  @authority = []
  @additional = []
  @logger = Logger.new $stdout
  @logger.level = $DEBUG ? Logger::DEBUG : Logger::WARN
end
parse(*args) click to toggle source

Create a new instance of Net::DNS::Packet class from binary data, taken out by a network stream. For example:

# udp_socket is an UDPSocket waiting for a response
ans = udp_socket.recvfrom(1500)
packet = Net::DNS::Packet::parse(ans)

An optional from argument can be used to specify the information of the sender. If data is passed as is from a Socket#recvfrom call, the method will accept it.

Be sure that your network data is clean from any UDP/TCP header, expecially when using RAW sockets.

# File lib/net/dns/packet.rb, line 162
def Packet.parse(*args)
  o = allocate
  o.send(:new_from_data, *args)
  o
end

Public Instance Methods

additional=(object) click to toggle source

Assign a Net::DNS::RR object, or an array of RR objects, to a Net::DNS::Packet instance additional section.

# File lib/net/dns/packet.rb, line 365
def additional=(object)
  case object
  when Array
    if object.all? {|x| x.kind_of? Net::DNS::RR}
      @additional = object
    else
      raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
    end
  when Net::DNS::RR
    @additional = [object]
  else
    raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
  end
end
answer=(object) click to toggle source

Assign a Net::DNS::RR object, or an array of RR objects, to a Net::DNS::Packet instance answer section.

# File lib/net/dns/packet.rb, line 346
def answer=(object)
  case object
  when Array
    if object.all? {|x| x.kind_of? Net::DNS::RR}
      @answer = object
    else
      raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
    end
  when Net::DNS::RR
    @answer = [object]
  else
    raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
  end
end
authority=(object) click to toggle source

Assign a Net::DNS::RR object, or an array of RR objects, to a Net::DNS::Packet instance authority section.

# File lib/net/dns/packet.rb, line 384
def authority=(object)
  case object
  when Array
    if object.all? {|x| x.kind_of? Net::DNS::RR}
      @authority = object
    else
      raise ArgumentError, "Some of the elements is not an Net::DNS::RR object"
    end
  when Net::DNS::RR
    @authority = [object]
  else
    raise ArgumentError, "Invalid argument, not a RR object nor an array of objects"
  end
end
data() click to toggle source

Return the packet object in binary data, suitable for sending across a network stream.

packet_data = packet.data
puts "Packet is #{packet_data.size} bytes long"
# File lib/net/dns/packet.rb, line 180
def data
  qdcount=ancount=nscount=arcount=0
  data = @header.data
  headerlength = data.length
  
  @question.each do |question|
    data += question.data
    qdcount += 1
  end
  @answer.each do |rr|
    data += rr.data#(data.length)
    ancount += 1
  end
  @authority.each do |rr|
    data += rr.data#(data.length)
    nscount += 1
  end
  @additional.each do |rr|
    data += rr.data#(data.length)
    arcount += 1
  end
  
  @header.qdCount = qdcount
  @header.anCount = ancount
  @header.nsCount = nscount
  @header.arCount = arcount

  @header.data + data[Net::DNS::HFIXEDSZ..data.size]
end
data_comp() click to toggle source

Same as Net::DNS::Packet#data, but implements name compression (see RFC1025) for a considerable save of bytes.

packet = Net::DNS::Packet.new("www.example.com")
puts "Size normal is #{packet.data.size} bytes"
puts "Size compressed is #{packet.data_comp.size} bytes"
# File lib/net/dns/packet.rb, line 217
def data_comp
  offset = 0
  compnames = {}
  qdcount=ancount=nscount=arcount=0
  data = @header.data
  headerlength = data.length

  @question.each do |question|
    str,offset,names = question.data
    data += str
    compnames.update(names)
    qdcount += 1
  end
  
  @answer.each do |rr|
    str,offset,names = rr.data(offset,compnames)
    data += str
    compnames.update(names)
    ancount += 1
  end
  
  @authority.each do |rr|
    str,offset,names = rr.data(offset,compnames)
    data += str
    compnames.update(names)
    nscount += 1
  end
  
  @additional.each do |rr|
    str,offset,names = rr.data(offset,compnames)
    data += str
    compnames.update(names)
    arcount += 1
  end
  
  @header.qdCount = qdcount
  @header.anCount = ancount
  @header.nsCount = nscount
  @header.arCount = arcount
  
  @header.data + data[Net::DNS::HFIXEDSZ..data.size]
end
each_address() click to toggle source

Iterate for every address in the answer section of a Net::DNS::Packet object.

packet.each_address do |ip|
  ping ip.to_s
end

As you can see in the documentation for Net::DNS::RR::A class, the address returned is an instance of IPAddr class.

# File lib/net/dns/packet.rb, line 409
def each_address
  @answer.each do |elem|
    next unless elem.class == Net::DNS::RR::A
    yield elem.address
  end
end
each_cname() click to toggle source

Iterate for every canonical name in the answer section of a Net::DNS::Packet object.

packet.each_cname do |cname|
  puts "Canonical name: #{cname}"
end
# File lib/net/dns/packet.rb, line 451
def each_cname
  @answer.each do |elem|
    next unless elem.class == Net::DNS::RR::CNAME
    yield elem.cname
  end
end
each_mx() click to toggle source

Iterate for every exchange record in the answer section of a Net::DNS::Packet object.

packet.each_mx do |pref,name|
  puts "Mail exchange #{name} has preference #{pref}"
end
# File lib/net/dns/packet.rb, line 437
def each_mx
  @answer.each do |elem|
    next unless elem.class == Net::DNS::RR::MX
    yield elem.preference,elem.exchange
  end
end
each_nameserver() click to toggle source

Iterate for every nameserver in the answer section of a Net::DNS::Packet object.

packet.each_nameserver do |ns|
  puts "Nameserver found: #{ns}"
end
# File lib/net/dns/packet.rb, line 423
def each_nameserver
  @answer.each do |elem|
    next unless elem.class == Net::DNS::RR::NS
    yield elem.nsdname
  end
end
each_ptr() click to toggle source

Iterate for every pointer in the answer section of a Net::DNS::Packet object.

packet.each_ptr do |ptr|
  puts "Pointer for resource: #{ptr}"
end
# File lib/net/dns/packet.rb, line 465
def each_ptr
  @answer.each do |elem|
    next unless elem.class == Net::DNS::RR::PTR
    yield elem.ptrdname
  end
end
header=(object) click to toggle source

Assing a Net::DNS::Header object to a Net::DNS::Packet instance.

# File lib/net/dns/packet.rb, line 316
def header=(object)
  if object.kind_of? Net::DNS::Header
    @header = object
  else
    raise ArgumentError, "Argument must be a Net::DNS::Header object"
  end
end
inspect() click to toggle source

Inspect method

# File lib/net/dns/packet.rb, line 261
def inspect
  retval = ""
  if @answerfrom != "0.0.0.0:0" and @answerfrom
    retval += ";; Answer received from #@answerfrom (#{@answersize} bytes)\n;;\n"
  end
  
  retval += ";; HEADER SECTION\n"
  retval += @header.inspect
  
  retval += "\n"
  section = (@header.opCode == "UPDATE") ? "ZONE" : "QUESTION"
  retval += ";; #{section} SECTION (#{@header.qdCount} record#{@header.qdCount == 1 ? '' : 's'}):\n"
  @question.each do |qr|
    retval += ";; " + qr.inspect + "\n"
  end

  unless @answer.size == 0
    retval += "\n"
    section = (@header.opCode == "UPDATE") ? "PREREQUISITE" : "ANSWER"
    retval += ";; #{section} SECTION (#{@header.anCount} record#{@header.anCount == 1 ? '' : 's'}):\n"
    @answer.each do |rr|
      retval += rr.inspect + "\n"
    end
  end

  unless @authority.size == 0
    retval += "\n"
    section = (@header.opCode == "UPDATE") ? "UPDATE" : "AUTHORITY"
    retval += ";; #{section} SECTION (#{@header.nsCount} record#{@header.nsCount == 1 ? '' : 's'}):\n"
    @authority.each do |rr|
      retval += rr.inspect + "\n"
    end
  end
  
  unless @additional.size == 0
    retval += "\n"
    retval += ";; ADDITIONAL SECTION (#{@header.arCount} record#{@header.arCount == 1 ? '' : 's'}):\n"
    @additional.each do |rr|
      retval += rr.inspect + "\n"
    end
  end
  
  retval
end
Also aliased as: to_s
nxdomain?() click to toggle source

Checks whether a query has returned a NXDOMAIN error, meaning the domain name queried doesn't exists.

%w[a.com google.com ibm.com d.com].each do |domain|
  response = Net::DNS::Resolver.new.send(domain)
  puts "#{domain} doesn't exist" if response.nxdomain?
end
  #=> a.com doesn't exist
  #=> d.com doesn't exist
# File lib/net/dns/packet.rb, line 493
def nxdomain?
  header.rCode.code == Net::DNS::Header::RCode::NAME
end
query?() click to toggle source

Checks if the packet is a QUERY packet

# File lib/net/dns/packet.rb, line 170
def query?
  @header.opCode == Net::DNS::Header::QUERY
end
question=(object) click to toggle source

Assign a Net::DNS::Question object, or an array of Questions objects, to a Net::DNS::Packet instance.

# File lib/net/dns/packet.rb, line 327
def question=(object)
  case object
  when Array
    if object.all? {|x| x.kind_of? Net::DNS::Question}
      @question = object
    else
      raise ArgumentError, "Some of the elements is not an Net::DNS::Question object"
    end
  when Net::DNS::Question
    @question = [object]
  else
    raise ArgumentError, "Invalid argument, not a Question object nor an array of objects"
  end
end
size() click to toggle source

Returns the packet size in bytes

Resolver("www.google.com") do |packet| 
  puts packet.size + " bytes"}
end
  #=> 484 bytes
# File lib/net/dns/packet.rb, line 479
def size
  data.size
end
to_s() click to toggle source
Alias for: inspect
truncated?() click to toggle source

Wrapper to Header#truncated?

# File lib/net/dns/packet.rb, line 309
def truncated?
  @header.truncated?
end

[Validate]

Generated with the Darkfish Rdoc Generator 2.