Class: Net::DNS::Header

Inherits:
Object
  • Object
show all
Defined in:
lib/net/dns/header.rb

Overview

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:

  • HeaderArgumentError: canonical argument error

  • HeaderWrongCount: a wrong count parameter has been passed

  • HeaderWrongRecursive: a wrong recursive parameter has been passed

  • HeaderWrongOpcode: a not valid opCode has been specified

  • HeaderDuplicateID: the requested ID is already in use

Copyright

Copyright © 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.

Defined Under Namespace

Classes: RCode

Constant Summary collapse

QUERY =

Constant for opCode query

0
IQUERY =

Constant for opCode iquery

1
STATUS =

Constant for opCode status

2
OPARR =

Array with given strings

%w[QUERY IQUERY STATUS]
@@id_arr =
[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(arg = {}) ⇒ Header

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.



239
240
241
242
243
244
245
# File 'lib/net/dns/header.rb', line 239

def initialize(arg = {})
  if arg.kind_of? Hash
    new_from_hash(arg)
  else
    raise HeaderArgumentError, "Wrong argument class: #{arg.class}"
  end
end

Instance Attribute Details

#anCountObject

Reader for answer section entries number



198
199
200
# File 'lib/net/dns/header.rb', line 198

def anCount
  @anCount
end

#arCountObject

Reader for addictional section entries number



202
203
204
# File 'lib/net/dns/header.rb', line 202

def arCount
  @arCount
end

#idObject

Reader for id attribute



190
191
192
# File 'lib/net/dns/header.rb', line 190

def id
  @id
end

#nsCountObject

Reader for authority section entries number



200
201
202
# File 'lib/net/dns/header.rb', line 200

def nsCount
  @nsCount
end

#opCodeObject

Reader for the operational code



192
193
194
# File 'lib/net/dns/header.rb', line 192

def opCode
  @opCode
end

#qdCountObject

Reader for question section entries number



196
197
198
# File 'lib/net/dns/header.rb', line 196

def qdCount
  @qdCount
end

#rCodeObject

Reader for the rCode instance



194
195
196
# File 'lib/net/dns/header.rb', line 194

def rCode
  @rCode
end

Class Method Details

.parse(arg) ⇒ Object

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


259
260
261
262
263
264
265
266
267
# File 'lib/net/dns/header.rb', line 259

def self.parse(arg)
  if arg.kind_of? String
    o = allocate
    o.send(:new_from_binary, arg)
    o
  else
    raise HeaderArgumentError, "Wrong argument class: #{arg.class}"
  end
end

Instance Method Details

#aa=(val) ⇒ Object

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.



459
460
461
462
463
464
465
466
467
468
469
470
# File 'lib/net/dns/header.rb', line 459

def aa=(val)
  case val
  when true
    @aa = 1
  when false
    @aa = 0
  when 0,1
    @aa = val
  else
    raise HeaderArgumentError, ":aa must be true(or 1) or false(or 0)"
  end
end

#ad=(val) ⇒ Object

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.



614
615
616
617
618
619
620
621
622
623
624
625
# File 'lib/net/dns/header.rb', line 614

def ad=(val)
  case val
  when true
    @ad = 1
  when false
    @ad = 0
  when 0,1
    @ad = val
  else
    raise HeaderArgumentError, ":ad must be true(or 1) or false(or 0)"
  end
end

#auth?Boolean

Checks whether the response is authoritative

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

Returns:

  • (Boolean)


446
447
448
# File 'lib/net/dns/header.rb', line 446

def auth?
  @aa == 1
end

#cd=(val) ⇒ Object

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



586
587
588
589
590
591
592
593
594
595
596
597
# File 'lib/net/dns/header.rb', line 586

def cd=(val)
  case val
  when true
    @cd = 1
  when false
    @cd = 0
  when 0,1
    @cd = val
  else
    raise HeaderArgumentError, ":cd must be true(or 1) or false(or 0)"
  end
end

#checking?Boolean

Checks whether checking is enabled or disabled.

Checking is enabled by default.

Returns:

  • (Boolean)


579
580
581
# File 'lib/net/dns/header.rb', line 579

def checking?
  @cd == 0
end

#dataObject

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

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


348
349
350
351
352
353
354
355
356
357
358
# File 'lib/net/dns/header.rb', line 348

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

#error?Boolean

Checks for errors in the DNS packet

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

Returns:

  • (Boolean)


645
646
647
# File 'lib/net/dns/header.rb', line 645

def error?
  @rCode.code > 0
end

#formatObject

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 :)



322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/net/dns/header.rb', line 322

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

#inspectObject

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.



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/net/dns/header.rb', line 280

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

#opCode_strObject

Returns a string representation of the opCode

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


412
413
414
# File 'lib/net/dns/header.rb', line 412

def opCode_str
  OPARR[@opCode]
end

#qr=(val) ⇒ Object

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.



387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/net/dns/header.rb', line 387

def qr=(val)
  case val
  when true
    @qr = 1
  when false
    @qr = 0
  when 0,1
    @qr = val
  else
    raise HeaderArgumentError, ":qr must be true(or 1) or false(or 0)"
  end
end

#query?Boolean

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

Returns:

  • (Boolean)


377
378
379
# File 'lib/net/dns/header.rb', line 377

def query?
  @qr == 0
end

#r_available?Boolean

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

Returns:

  • (Boolean)


553
554
555
# File 'lib/net/dns/header.rb', line 553

def r_available?
  @ra == 1
end

#ra=(val) ⇒ Object

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.



562
563
564
565
566
567
568
569
570
571
572
573
# File 'lib/net/dns/header.rb', line 562

def ra=(val)
  case val
  when true
    @ra = 1
  when false
    @ra = 0
  when 0,1
    @ra = val
  else
    raise HeaderArgumentError, ":ra must be true(or 1) or false(or 0)"
  end
end

#rCode_strObject

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


635
636
637
# File 'lib/net/dns/header.rb', line 635

def rCode_str
  return rCode.type, rCode.explanation
end

#rd=(val) ⇒ Object

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



545
546
547
# File 'lib/net/dns/header.rb', line 545

def rd=(val)
  self.recursive = val
end

#recursive=(val) ⇒ Object

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.



527
528
529
530
531
532
533
534
535
536
537
538
539
540
# File 'lib/net/dns/header.rb', line 527

def recursive=(val)
  case val
  when true
    @rd = 1
  when false
    @rd = 0
  when 1
    @rd = 1
  when 0
    @rd = 0
  else
    raise HeaderWrongRecursive, "Wrong value (#{val}), please specify true (1) or false (0)"
  end
end

#recursive?Boolean

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

Returns:

  • (Boolean)


513
514
515
# File 'lib/net/dns/header.rb', line 513

def recursive?
  @rd == 1
end

#response?Boolean

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

Returns:

  • (Boolean)


403
404
405
# File 'lib/net/dns/header.rb', line 403

def response?
  @qr == 1
end

#tc=(val) ⇒ Object

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.



497
498
499
500
501
502
503
504
505
506
507
508
# File 'lib/net/dns/header.rb', line 497

def tc=(val)
  case val
  when true
    @tc = 1
  when false
    @tc = 0
  when 0,1
    @tc = val
  else
    raise HeaderArgumentError, ":tc must be true(or 1) or false(or 0)"
  end
end

#truncated?Boolean

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

Returns:

  • (Boolean)


481
482
483
# File 'lib/net/dns/header.rb', line 481

def truncated?
  @tc == 1
end

#verified?Boolean

Checks whether ad flag has been set.

This flag is only relevant in DNSSEC context.

Returns:

  • (Boolean)


603
604
605
# File 'lib/net/dns/header.rb', line 603

def verified?
  @ad == 1
end