Class Net::DNS::Header
In: lib/net/dns/header.rb
Parent: Object

Name

Net::DNS::Header - DNS packet header class

Synopsis

  require 'net/dns/header'

Description

The Net::DNS::Header class represents the header portion of a DNS packet. An Header object is created whenever a new packet is parsed or as user request.

  header = Net::DNS::Header.new
    # ;; id = 18123
    # ;; qr = 0       opCode: 0       aa = 0  tc = 0  rd = 1
    # ;; ra = 0       ad = 0  cd = 0  rcode = 0
    # ;; qdCount = 1  anCount = 0     nsCount = 0     arCount = 0

  header.format
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |             18123             |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |0|   0   |0|0|1|0|0| 0 |   0   |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |               1               |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |               0               |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |               0               |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |               0               |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  # packet is an instance of Net::DNS::Packet
  header = packet.header
  puts "Answer is #{header.auth? ? '' : 'non'} authoritative"

A lot of methods were written to keep a compatibility layer with the Perl version of the library, as long as methods name which are more or less the same.

Error classes

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

ArgumentError:Argument Error for class Net::DNS::Packet
WrongCountError:A wrong count parameter has been passed
WrongRecursiveError:A wrong recursive parameter has been passed
WrongOpcodeError:A not valid opCode has been specified
DuplicateIDError:The requested ID is already in use

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.

Methods

aa=   ad=   anCount=   arCount=   auth?   cd=   checking?   data   error?   format   id=   inspect   new   nsCount=   opCode=   opCode_str   parse   qdCount=   qr=   query?   rCode=   rCode_str   r_available?   ra=   rd=   recursive=   recursive?   response?   tc=   truncated?   verified?  

Classes and Modules

Class Net::DNS::Header::ArgumentError
Class Net::DNS::Header::DuplicateIDError
Class Net::DNS::Header::Error
Class Net::DNS::Header::RCode
Class Net::DNS::Header::WrongCountError
Class Net::DNS::Header::WrongOpcodeError
Class Net::DNS::Header::WrongRecursiveError

Constants

QUERY = 0   Constant for opCode query
IQUERY = 1   Constant for opCode iquery
STATUS = 2   Constant for opCode status
OPARR = %w[QUERY IQUERY STATUS]   Array with given strings

Attributes

anCount  [R]  Reader for answer section entries number
arCount  [R]  Reader for addictional section entries number
id  [R]  Reader for id attribute
nsCount  [R]  Reader for authority section entries number
opCode  [R]  Reader for the operational code
qdCount  [R]  Reader for question section entries number
rCode  [R]  Reader for the rCode instance

Public Class methods

Creates a new Net::DNS::Header object with the desired values, which can be specified as an Hash argument. When called without arguments, defaults are used. If a data string is passed, values are taken from parsing the string.

Examples:

  # Create a new Net::DNS::Header object
  header = Net::DNS::Header.new

  # Create a new Net::DNS::Header object passing values
  header = Net::DNS::Header.new(:opCode => 1, :rd => 0)

  # Create a new Net::DNS::Header object with binary data
  header = Net::DNS::Header.new(data)

Default values are:

  :id => auto generated
  :qr      => 0 # Query response flag
  :aa      => 0 # Authoritative answer flag
  :tc      => 0 # Truncated packet flag
  :ra      => 0 # Recursiond available flag
  :rCode   => 0 # Response code (status of the query)
  :opCode  => 0 # Operational code (purpose of the query)
  :cd      => 0 # Checking disable flag
  :ad      => 0 # Only relevant in DNSSEC context
  :rd      => 1 # Recursion desired flag
  :qdCount => 1 # Number of questions in the dns packet
  :anCount => 0 # Number of answer RRs in the dns packet
  :nsCount => 0 # Number of authoritative RRs in the dns packet
  :arCount => 0 # Number of additional RRs in the dns packet

See also each option for a detailed explanation of usage.

[Source]

# File lib/net/dns/header.rb, line 261
      def initialize(arg = {})
        if arg.kind_of? Hash
          new_from_hash(arg)
        else
          raise ArgumentError, "Wrong argument class `#{arg.class}'"
        end
      end

Creates a new Net::DNS::Header object from binary data, which is passed as a string object as argument. The configurations parameters are taken from parsing the string.

Example:

  # Create a new Net::DNS::Header object with binary data
  header = Net::DNS::Header.new(data)

  header.auth?
    #=> "true" if it comes from authoritative name server

[Source]

# File lib/net/dns/header.rb, line 281
      def self.parse(arg)
        if arg.kind_of? String
          o = allocate
          o.send(:new_from_binary, arg)
          o
        else
          raise ArgumentError, "Wrong argument class `#{arg.class}'"
        end
      end

Public Instance methods

Set the aa flag (authoritative answer) to either true or false. You can also use 0 or 1.

This flag indicates whether a DNS answer packet contains authoritative data, meaning that is was generated by a nameserver authoritative for the domain of the question.

Must only be set to true in DNS answer packets.

[Source]

# File lib/net/dns/header.rb, line 481
      def aa=(val)
        case val
        when true
          @aa = 1
        when false
          @aa = 0
        when 0,1
          @aa = val
        else
          raise ArgumentError, ":aa must be true(or 1) or false(or 0)"
        end
      end

Set the ad flag to either true ot false. You can also use 0 or 1.

The AD bit is only set on answers where signatures have been cryptographically verified or the server is authoritative for the data and is allowed to set the bit by policy.

[Source]

# File lib/net/dns/header.rb, line 636
      def ad=(val)
        case val
        when true
          @ad = 1
        when false
          @ad = 0
        when 0,1
          @ad = val
        else
          raise ArgumentError, ":ad must be true(or 1) or false(or 0)"
        end
      end

Sets the number of RRs in an answer section

[Source]

# File lib/net/dns/header.rb, line 690
      def anCount=(val)
        if (0..65535).include? val
          @anCount = val
        else
          raise WrongCountError, "Wrong number of count (#{val}), must be 0-65535"
        end
      end

Sets the number of RRs in an addictional section

[Source]

# File lib/net/dns/header.rb, line 710
      def arCount=(val)
        if (0..65535).include? val
          @arCount = val
        else
          raise WrongCountError, "Wrong number of count: `#{val}' must be 0-65535"
        end
      end

Checks whether the response is authoritative

  if header.auth?
    puts "Response is authoritative"
  else
    puts "Answer is NOT authoritative"
  end

[Source]

# File lib/net/dns/header.rb, line 468
      def auth?
        @aa == 1
      end

Set the cd flag (checking disabled) to either true ot false. You can also use 0 or 1.

[Source]

# File lib/net/dns/header.rb, line 608
      def cd=(val)
        case val
        when true
          @cd = 1
        when false
          @cd = 0
        when 0,1
          @cd = val
        else
          raise ArgumentError, ":cd must be true(or 1) or false(or 0)"
        end
      end

Checks whether checking is enabled or disabled.

Checking is enabled by default.

[Source]

# File lib/net/dns/header.rb, line 601
      def checking?
        @cd == 0
      end

Returns the header data in binary format, appropriate for use in a DNS query packet.

  hdata = header.data
  puts "Header is #{hdata.size} bytes"

[Source]

# File lib/net/dns/header.rb, line 370
      def data
        arr = []
        arr.push(@id)
        arr.push((@qr<<7)|(@opCode<<3)|(@aa<<2)|(@tc<<1)|@rd)
        arr.push((@ra<<7)|(@ad<<5)|(@cd<<4)|@rCode.code)
        arr.push(@qdCount)
        arr.push(@anCount)
        arr.push(@nsCount)
        arr.push(@arCount)
        arr.pack("n C2 n4")
      end

Checks for errors in the DNS packet

  unless header.error?
    puts "No errors in DNS answer packet"
  end

[Source]

# File lib/net/dns/header.rb, line 667
      def error?
        @rCode.code > 0
      end

The Net::DNS::Header#format method prints out the header in a special ascii representation of data, in a way similar to those often found on RFCs.

  p Net::DNS::Header.new.format
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |             18123             |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |0|   0   |0|0|1|0|0| 0 |   0   |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |               1               |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |               0               |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |               0               |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    #  |               0               |
    #  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

This can be very usefull for didactical purpouses :)

[Source]

# File lib/net/dns/header.rb, line 344
      def format 
        del = ("+-" * 16) + "+\n"
        len = del.length
        str = del + "|" + @id.to_s.center(len-3) + "|\n"
        str += del + "|" + @qr.to_s
        str += "|" + @opCode.to_s.center(7)
        str += "|" + @aa.to_s
        str += "|" + @tc.to_s
        str += "|" + @rd.to_s
        str += "|" + @ra.to_s
        str += "|" + @ad.to_s
        str += "|" + @cd.to_s.center(3)
        str += "|" + @rCode.to_s.center(7) + "|\n"
        str += del + "|" + @qdCount.to_s.center(len-3) + "|\n"
        str += del + "|" + @anCount.to_s.center(len-3) + "|\n"
        str += del + "|" + @nsCount.to_s.center(len-3) + "|\n"
        str += del + "|" + @arCount.to_s.center(len-3) + "|\n" + del
        str
      end

Set the ID for the current header. Useful when performing security tests.

[Source]

# File lib/net/dns/header.rb, line 385
      def id=(val)
        if @@id_arr.include? val
          raise DuplicateIDError, "ID `#{val}' already used"
        end
        if (1..65535).include? val
          @id = val
          @@id_arr.push val
        else
          raise ArgumentError, "ID `#{val}' out of range"
        end
      end

Inspect method, prints out all the options and relative values.

  p Net::DNS::Header.new
    # ;; id = 18123
    # ;; qr = 0       opCode: 0       aa = 0  tc = 0  rd = 1
    # ;; ra = 0       ad = 0  cd = 0  rcode = 0
    # ;; qdCount = 1  anCount = 0     nsCount = 0     arCount = 0

This method will maybe be changed in the future to a more pretty way of display output.

[Source]

# File lib/net/dns/header.rb, line 302
      def inspect 
        ";; id = #@id\n" +
          if false # @opCode == "UPDATE"
            #do stuff
          else
            ";; qr = #@qr\t" +
              "opCode: #{opCode_str}\t" +
              "aa = #@aa\t" +
              "tc = #@tc\t" +
              "rd = #@rd\n" +
              ";; ra = #@ra\t" +
              "ad = #@ad\t" +
              "cd = #@cd\t" +
              "rcode = #{@rCode.type}\n" +
              ";; qdCount = #@qdCount\t"+
              "anCount = #@anCount\t"+
              "nsCount = #@nsCount\t"+
              "arCount = #@arCount\n"
          end
      end

Sets the number of RRs in an authority section

[Source]

# File lib/net/dns/header.rb, line 700
      def nsCount=(val)
        if (0..65535).include? val
          @nsCount = val
        else
          raise WrongCountError, "Wrong number of count (#{val}), must be 0-65535"
        end
      end

Set the opCode variable to a new value. This fields indicates the type of the question present in the DNS packet; val can be one of the values QUERY, IQUERY or STATUS.

  • QUERY is the standard DNS query
  • IQUERY is the inverse query
  • STATUS is used to query the nameserver for its status

Example:

  include Net::DNS
  header = Header.new
  header.opCode = Header::STATUS

[Source]

# File lib/net/dns/header.rb, line 452
      def opCode=(val)
        if (0..2).include? val
          @opCode = val
        else
          raise WrongOpcodeError, "Wrong opCode value (#{val}), must be QUERY, IQUERY or STATUS"
        end
      end

Returns a string representation of the opCode

  puts "Packet is a #{header.opCode_str}"
    #=> Packet is a QUERY

[Source]

# File lib/net/dns/header.rb, line 434
      def opCode_str
        OPARR[@opCode]
      end

Sets the number of entries in a question section

[Source]

# File lib/net/dns/header.rb, line 680
      def qdCount=(val)
        if (0..65535).include? val
          @qdCount = val
        else
          raise WrongCountError, "Wrong number of count (#{val}), must be 0-65535"
        end
      end

Set the qr query response flag to be either true or false. You can also use the values 0 and 1. This flag indicates if the DNS packet contains a query or an answer, so it should be set to true in DNS answer packets. If qr is true, the packet is a response.

[Source]

# File lib/net/dns/header.rb, line 409
      def qr=(val)
        case val
        when true
          @qr = 1
        when false
          @qr = 0
        when 0,1
          @qr = val
        else
          raise ArgumentError, ":qr must be true(or 1) or false(or 0)"
        end
      end

Checks whether the header is a query (qr bit set to 0)

[Source]

# File lib/net/dns/header.rb, line 399
      def query?
        @qr == 0
      end

Set the rCode value. This should only be done in DNS answer packets.

[Source]

# File lib/net/dns/header.rb, line 674
      def rCode=(val)
        @rCode = RCode.new(val)
      end

Returns an error array for the header response code, or nil if no error is generated.

  error, cause = header.rCode_str
  puts "Error #{error} cause by: #{cause}" if error
    #=> Error ForErr caused by: The name server
    #=> was unable to interpret the query

[Source]

# File lib/net/dns/header.rb, line 657
      def rCode_str
        return rCode.type, rCode.explanation
      end

Checks whether recursion is available. This flag is usually set by nameservers to indicate that they support recursive-type queries.

[Source]

# File lib/net/dns/header.rb, line 575
      def r_available?
        @ra == 1
      end

Set the ra flag (recursion available) to either true or false. You can also use 0 and 1.

This flag must only be set in DNS answer packets.

[Source]

# File lib/net/dns/header.rb, line 584
      def ra=(val)
        case val
        when true
          @ra = 1
        when false
          @ra = 0
        when 0,1
          @ra = val
        else
          raise ArgumentError, ":ra must be true(or 1) or false(or 0)"
        end
      end

Alias for Header#recursive= to keep compatibility with the Perl version.

[Source]

# File lib/net/dns/header.rb, line 567
      def rd=(val)
        self.recursive = val
      end

Sets the recursion desidered bit. Remember that recursion query support is optional.

  header.recursive = true
  hdata = header.data # suitable for sending

Consult RFC1034 and RFC1035 for a detailed explanation of how recursion works.

[Source]

# File lib/net/dns/header.rb, line 549
      def recursive=(val)
        case val
        when true
          @rd = 1
        when false
          @rd = 0
        when 1
          @rd = 1
        when 0
          @rd = 0
        else
          raise WrongRecursiveError, "Wrong value (#{val}), please specify true (1) or false (0)"
        end
      end

Checks whether the packet has a recursion bit set, meaning that recursion is desired

[Source]

# File lib/net/dns/header.rb, line 535
      def recursive?
        @rd == 1
      end

Checks whether the header is a response (qr bit set to 1)

[Source]

# File lib/net/dns/header.rb, line 425
      def response?
        @qr == 1
      end

Set the tc flag (truncated packet) to either true ot false. You can also use 0 or 1.

The truncated flag is used in response packets to indicate that the amount of data to be trasmitted exceedes the maximum allowed by the protocol in use, tipically UDP, and that the data present in the packet has been truncated. A different protocol (such has TCP) need to be used to retrieve full data.

Must only be set in DNS answer packets.

[Source]

# File lib/net/dns/header.rb, line 519
      def tc=(val)
        case val
        when true
          @tc = 1
        when false
          @tc = 0
        when 0,1
          @tc = val
        else
          raise ArgumentError, ":tc must be true(or 1) or false(or 0)"
        end
      end

Checks whether the packet was truncated

  # Sending packet using UDP
  if header.truncated?
    puts "Warning, packet has been truncated!"
    # Sending packet using TCP
  end
  # Do something with the answer

[Source]

# File lib/net/dns/header.rb, line 503
      def truncated?
        @tc == 1
      end

Checks whether ad flag has been set.

This flag is only relevant in DNSSEC context.

[Source]

# File lib/net/dns/header.rb, line 625
      def verified?
        @ad == 1
      end

[Validate]