Parent

Class Index [+]

Quicksearch

Dnsruby::Message

Defines a DNS packet.

 

RFC 1035 Section 4.1, RFC 2136 Section 2, RFC 2845

Sections

Message objects have five sections:

 
      msg.header=Header.new(...)
      header = msg.header
 
      msg.add_question(Question.new(domain, type, klass))
      msg.each_question do |question|  ....   end
 
      msg.add_additional(rr)
      msg.each_additional {|rr| ... }
 

In addition, each_resource iterates the answer, additional and authority sections :

      msg.each_resource {|rr| ... }

Packet format encoding

      Dnsruby::Message#encode
      Dnsruby::Message::decode(data)

Additional information

security_level records the current DNSSEC status of this Message. answerfrom records the server which this Message was received from. cached records whether this response came from the cache.

Attributes

security_level[RW]

If dnssec is set on, then each message will have the security level set To find the precise error (if any), call Dnsruby::Dnssec::validate(msg) - the resultant exception will define the error.

security_error[RW]

If there was a problem verifying this message with DNSSEC, then securiy_error will hold a description of the problem. It defaults to ““

cached[RW]

If the Message was returned from the cache, the cached flag will be set true. It will be false otherwise.

question[R]

The question section, an array of Dnsruby::Question objects.

answer[R]

The answer section, an array of Dnsruby::RR objects.

authority[R]

The authority section, an array of Dnsruby::RR objects.

additional[R]

The additional section, an array of Dnsruby::RR objects.

header[RW]

The header section, a Dnsruby::Header object.

answerfrom[RW]

If this Message is a response from a server, then answerfrom contains the address of the server

answerip[RW]

If this Message is a response from a server, then answerfrom contains the IP address of the server

answersize[RW]

If this Message is a response from a server, then answersize contains the size of the response

tsigerror[RW]

If this message has been verified using a TSIG RR then tsigerror contains the error code returned by the TSIG verification. The error will be an RCode

tsigstate[RW]

Can be

  • :Unsigned - the default state

  • :Signed - the outgoing message has been signed

  • :Verified - the incoming message has been verified by TSIG

  • :Intermediate - the incoming message is an intermediate envelope in a TCP session

in which only every 100th envelope must be signed

  • :Failed - the incoming response failed verification

tsigstart[RW]
send_raw[RW]

Set send_raw if you wish to send and receive the response to this Message with no additional processing. In other words, if set, then Dnsruby will not touch the Header of the outgoing Message. This option does not affect caching or dnssec validation

This option should not normally be set.

do_validation[RW]

do_validation is set by default. If you do not wish dnsruby to validate this message (on a Resolver with @dnssec==true), then set do_validation to false. This option does not affect caching, or the header options

do_caching[RW]

do_caching is set by default. If you do not wish dnsruby to inspect the cache before sending the query, nor cache the result of the query, then set do_caching to false.

Public Class Methods

decode(m) click to toggle source

Decode the encoded message

     # File lib/Dnsruby/message.rb, line 592
592:     def Message.decode(m)
593:       o = Message.new()
594:       begin
595:         MessageDecoder.new(m) {|msg|
596:           o.header = Header.new(msg)
597:           o.header.qdcount.times {
598:             question = msg.get_question
599:             o.question << question
600:           }
601:           o.header.ancount.times {
602:             rr = msg.get_rr
603:             o.answer << rr
604:           }
605:           o.header.nscount.times {
606:             rr = msg.get_rr
607:             o.authority << rr
608:           }
609:           o.header.arcount.times { |count|
610:             start = msg.index
611:             rr = msg.get_rr
612:             if (rr.type == Types::TSIG)
613:               if (count!=o.header.arcount-1)
614:                 Dnsruby.log.Error("Incoming message has TSIG record before last record")
615:                 raise DecodeError.new("TSIG record present before last record")
616:               end
617:               o.tsigstart = start # needed for TSIG verification
618:             end
619:             o.additional << rr
620:           }
621:         }
622:       rescue DecodeError => e
623:         # So we got a decode error
624:         # However, we might have been able to fill in many parts of the message
625:         # So let's raise the DecodeError, but add the partially completed message
626:         e.partial_message = o
627:         raise e
628:       end
629:       return o
630:     end
new(*args) click to toggle source

Create a new Message. Takes optional name, type and class

type defaults to A, and klass defaults to IN

  • Dnsruby::Message.new(“example.com“) # defaults to A, IN

  • Dnsruby::Message.new(“example.com“, ‘AAAA’)

  • Dnsruby::Message.new(“example.com“, Dnsruby::Types.PTR, “HS”)

     # File lib/Dnsruby/message.rb, line 189
189:     def initialize(*args)
190:       @header = Header.new()
191:       #      @question = Section.new(self)
192:       @question = []
193:       @answer = Section.new(self)
194:       @authority = Section.new(self)
195:       @additional = Section.new(self)
196:       @tsigstate = :Unsigned
197:       @signing = false
198:       @tsigkey = nil
199:       @answerfrom = nil
200:       @answerip = nil
201:       @send_raw = false
202:       @do_validation = true
203:       @do_caching = true
204:       @security_level = SecurityLevel.UNCHECKED
205:       @security_error = nil
206:       @cached = false
207:       type = Types::A
208:       klass = Classes::IN
209:       if (args.length > 0)
210:         name = args[0]
211:         if (args.length > 1)
212:           type = Types.new(args[1])
213:           if (args.length > 2)
214:             klass = Classes.new(args[2])
215:           end
216:         end
217:         add_question(name, type, klass)
218:       end
219:     end

Public Instance Methods

==(other) click to toggle source
     # File lib/Dnsruby/message.rb, line 305
305:     def ==(other)
306:       ret = false
307:       if (other.kind_of?Message)
308:         ret = @header == other.header &&
309:           @question[0] == other.question[0] &&
310:           @answer == other.answer &&
311:           @authority == other.authority &&
312:           @additional == other.additional
313:       end
314:       return ret
315:     end
add_question(question, type=Types.A, klass=Classes.IN) click to toggle source

Add a new Question to the Message. Takes either a Question, or a name, and an optional type and class.

  • msg.add_question(Question.new(“example.com“, ‘MX’))

  • msg.add_question(“example.com“) # defaults to Types.A, Classes.IN

  • msg.add_question(“example.com“, Types.LOC)

     # File lib/Dnsruby/message.rb, line 356
356:     def add_question(question, type=Types.A, klass=Classes.IN)
357:       if (!question.kind_of?Question)
358:         question = Question.new(question, type, klass)
359:       end
360:       @question << question
361:       update_counts
362:     end
Also aliased as: add_zone
add_zone(question, type=Types.A, klass=Classes.IN) click to toggle source
Alias for: add_question
each_additional() click to toggle source
     # File lib/Dnsruby/message.rb, line 411
411:     def each_additional
412:       @additional.each {|rec|
413:         yield rec
414:       }
415:     end
each_answer() click to toggle source
     # File lib/Dnsruby/message.rb, line 385
385:     def each_answer
386:       @answer.each {|rec|
387:         yield rec
388:       }
389:     end
Also aliased as: each_pre
each_authority() click to toggle source
     # File lib/Dnsruby/message.rb, line 398
398:     def each_authority
399:       @authority.each {|rec|
400:         yield rec
401:       }
402:     end
Also aliased as: each_update
each_pre() click to toggle source
Also aliased as: each_prerequisite
Alias for: each_answer
each_prerequisite() click to toggle source
Alias for: each_pre
each_question() click to toggle source
     # File lib/Dnsruby/message.rb, line 364
364:     def each_question
365:       @question.each {|rec|
366:         yield rec
367:       }
368:     end
Also aliased as: each_zone
each_resource() click to toggle source

Calls each_answer, each_authority, each_additional

     # File lib/Dnsruby/message.rb, line 423
423:     def each_resource
424:       each_answer {|rec| yield rec}
425:       each_authority {|rec| yield rec}
426:       each_additional {|rec| yield rec}
427:     end
each_section() click to toggle source

Yields each section (question, answer, authority, additional)

     # File lib/Dnsruby/message.rb, line 418
418:     def each_section
419:       [@answer, @authority, @additional].each {|section| yield section}
420:     end
each_update() click to toggle source
Alias for: each_authority
each_zone() click to toggle source
Alias for: each_question
encode() click to toggle source

Return the encoded form of the message

 If there is a TSIG record present and the record has not been signed
 then sign it
     # File lib/Dnsruby/message.rb, line 570
570:     def encode
571:       if ((@tsigkey) && @tsigstate == :Unsigned && !@signing)
572:         @signing = true
573:         sign!
574:         @signing = false
575:       end
576:       return MessageEncoder.new {|msg|
577:         header = @header
578:         header.encode(msg)
579:         @question.each {|q|
580:           msg.put_name(q.qname)
581:           msg.put_pack('nn', q.qtype.code, q.qclass.code)
582:         }
583:         [@answer, @authority, @additional].each {|rr|
584:           rr.each { |r|
585:             msg.put_rr(r)
586:           }
587:         }
588:       }.to_s
589:     end
get_exception() click to toggle source
     # File lib/Dnsruby/message.rb, line 277
277:     def get_exception
278:       exception = nil
279:       if (rcode==RCode.NXDOMAIN)
280:         exception = NXDomain.new
281:       elsif (rcode==RCode.SERVFAIL)
282:         exception = ServFail.new
283:       elsif (rcode==RCode.FORMERR)
284:         exception = FormErr.new
285:       elsif (rcode==RCode.NOTIMP)
286:         exception = NotImp.new
287:       elsif (rcode==RCode.REFUSED)
288:         exception = Refused.new
289:       elsif (rcode==RCode.NOTZONE)
290:         exception = NotZone.new
291:       elsif (rcode==RCode.NOTAUTH)
292:         exception = NotAuth.new
293:       elsif (rcode==RCode.NXRRSET)
294:         exception = NXRRSet.new
295:       elsif (rcode==RCode.YXRRSET)
296:         exception = YXRRSet.new
297:       elsif (rcode==RCode.YXDOMAIN)
298:         exception = YXDomain.new
299:       elsif (rcode >= RCode.BADSIG && rcode <= RCode.BADALG)
300:         return VerifyError.new # @TODO@
301:       end
302:       return exception
303:     end
get_opt() click to toggle source
     # File lib/Dnsruby/message.rb, line 470
470:     def get_opt
471:       each_additional do |r|
472:         if (r.type == Types::OPT)
473:           return r
474:         end
475:       end
476:       return nil
477:     end
rcode() click to toggle source
     # File lib/Dnsruby/message.rb, line 479
479:     def rcode
480:       rcode = @header.get_header_rcode
481:       opt = get_opt
482:       if (opt != nil)
483:         rcode = rcode.code + (opt.xrcode.code << 4)
484:         rcode = RCode.new(rcode)
485:       end
486:       return rcode;
487:     end
rrset(name, type, klass = Classes::IN) click to toggle source

Return the first rrset of the specified attributes in the message

     # File lib/Dnsruby/message.rb, line 318
318:     def rrset(name, type, klass = Classes::IN)
319:       [@answer, @authority, @additional].each do |section|
320:         if ((rrset = section.rrset(name, type, klass)).length > 0)
321:           return rrset
322:         end
323:       end
324:       return RRSet.new
325:     end
rrsets(type, klass=Classes::IN) click to toggle source

Return the rrsets of the specified type in the message

     # File lib/Dnsruby/message.rb, line 328
328:     def rrsets(type, klass=Classes::IN)
329:       rrsetss = []
330:       [@answer, @authority, @additional].each do |section|
331:         if ((rrsets = section.rrsets(type, klass)).length > 0)
332:           rrsets.each {|rrset|
333:             rrsetss.push(rrset)
334:           }
335:         end
336:       end
337:       return rrsetss
338:     end
section_rrsets(type = nil, include_opt = false) click to toggle source

Return a hash, with the section as key, and the RRSets in that section as the data : {section => section_rrs}

     # File lib/Dnsruby/message.rb, line 342
342:     def section_rrsets(type = nil, include_opt = false)
343:       ret = {}
344:       ["answer", "authority", "additional"].each do |section|
345:         ret[section] = self.send(section).rrsets(type, include_opt)
346:       end
347:       return ret
348:     end
set_tsig(*args) click to toggle source

Sets the TSIG to sign this message with. Can either be a Dnsruby::RR::TSIG object, or it can be a (name, key) tuple, or it can be a hash which takes Dnsruby::RR::TSIG attributes (e.g. name, key, fudge, etc.)

     # File lib/Dnsruby/message.rb, line 442
442:     def set_tsig(*args)
443:       if (args.length == 1)
444:         if (args[0].instance_of?RR::TSIG)
445:           @tsigkey = args[0]
446:         elsif (args[0].instance_of?Hash)
447:           @tsigkey = RR.create({:type=>'TSIG', :klass=>'ANY'}.merge(args[0]))
448:         else
449:           raise ArgumentError.new("Wrong type of argument to Dnsruby::Message#set_tsig - should be TSIG or Hash")
450:         end
451:       elsif (args.length == 2)
452:         @tsigkey = RR.create({:type=>'TSIG', :klass=>'ANY', :name=>args[0], :key=>args[1]})
453:       else
454:         raise ArgumentError.new("Wrong number of arguments to Dnsruby::Message#set_tsig")
455:       end
456:     end
signed?() click to toggle source

Was this message signed by a TSIG?

     # File lib/Dnsruby/message.rb, line 459
459:     def signed?
460:       return (@tsigstate == :Signed ||
461:           @tsigstate == :Verified ||
462:           @tsigstate == :Failed)
463:     end
to_s() click to toggle source
     # File lib/Dnsruby/message.rb, line 489
489:     def to_s
490:       retval = "";
491:       
492:       if (@answerfrom != nil && @answerfrom != "")
493:         retval = retval + ";; Answer received from #{@answerfrom} (#{@answersize} bytes)\n;;\n";
494:       end
495:       retval = retval + ";; Security Level : #{@security_level.string}\n"
496:       
497:       retval = retval + ";; HEADER SECTION\n"
498:       # OPT pseudosection? EDNS flags, udpsize
499:       opt = get_opt
500:       if (!opt)
501:         retval = retval + @header.to_s
502:       else
503:         retval = retval + @header.to_s_with_rcode(rcode())
504:       end
505:       retval = retval + "\n"
506:       
507:       if (opt)
508:         retval = retval + opt.to_s
509:         retval = retval + "\n"
510:       end
511:             
512:       section = (@header.opcode == OpCode.UPDATE) ? "ZONE" : "QUESTION";
513:       retval = retval +  ";; #{section} SECTION (#{@header.qdcount}  record#{@header.qdcount == 1 ? '' : 's'})\n";
514:       each_question { |qr|
515:         retval = retval + ";; #{qr.to_s}\n";
516:       }
517:       
518:       if (@answer.size > 0)
519:         retval = retval + "\n";
520:         section = (@header.opcode == OpCode.UPDATE) ? "PREREQUISITE" : "ANSWER";
521:         retval = retval + ";; #{section} SECTION (#{@header.ancount}  record#{@header.ancount == 1 ? '' : 's'})\n";
522:         each_answer { |rr|
523:           retval = retval + rr.to_s + "\n";
524:         }
525:       end
526:       
527:       if (@authority.size > 0)
528:         retval = retval + "\n";
529:         section = (@header.opcode == OpCode.UPDATE) ? "UPDATE" : "AUTHORITY";
530:         retval = retval + ";; #{section} SECTION (#{@header.nscount}  record#{@header.nscount == 1 ? '' : 's'})\n";
531:         each_authority { |rr|
532:           retval = retval + rr.to_s + "\n";
533:         }
534:       end
535:       
536:       if ((@additional.size > 0 && !opt) || (@additional.size > 1))
537:         retval = retval + "\n";
538:         retval = retval + ";; ADDITIONAL SECTION (#{@header.arcount}  record#{@header.arcount == 1 ? '' : 's'})\n";
539:         each_additional { |rr|
540:           if (rr.type != Types::OPT)
541:             retval = retval + rr.to_s+ "\n"
542:           end
543:         }
544:       end
545:       
546:       return retval;
547:     end
tsig() click to toggle source

Returns the TSIG record from the ADDITIONAL section, if one is present.

     # File lib/Dnsruby/message.rb, line 430
430:     def tsig
431:       if (@additional.last)
432:         if (@additional.last.rr_type == Types.TSIG)
433:           return @additional.last
434:         end
435:       end
436:       return nil
437:     end
verified?() click to toggle source

If this message was signed by a TSIG, was the TSIG verified?

     # File lib/Dnsruby/message.rb, line 466
466:     def verified?
467:       return (@tsigstate == :Verified)
468:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.