Class Dnsruby::Message
In: lib/Dnsruby/message.rb
Parent: Object
ResolvError EncodeError OtherResolvError ServFail FormErr DecodeError NXRRSet YXDomain NotImp NXDomain VerifyError NotAuth YXRRSet NotZone Refused TsigError Message Update CodeMapper Types MetaTypes QTypes Nsec3HashAlgorithms Algorithms OpCode Classes ExtendedRCode RCode Modes Comparable Name RRSet Resolver SingleResolver StandardError TimeoutError ResolvTimeout DNS Dnssec Hosts SelectThread\n[lib/Dnsruby/select_thread.rb\nlib/Dnsruby/select_thread.rb.michael.rb] Recursor IPv6 IPv4 ZoneTransfer MessageDecoder MessageEncoder Question Header TheLog RR\n[lib/Dnsruby/resource/A.rb\nlib/Dnsruby/resource/AAAA.rb\nlib/Dnsruby/resource/AFSDB.rb\nlib/Dnsruby/resource/CERT.rb\nlib/Dnsruby/resource/DLV.rb\nlib/Dnsruby/resource/DNSKEY.rb\nlib/Dnsruby/resource/DS.rb\nlib/Dnsruby/resource/HINFO.rb\nlib/Dnsruby/resource/IN.rb\nlib/Dnsruby/resource/ISDN.rb\nlib/Dnsruby/resource/LOC.rb\nlib/Dnsruby/resource/MINFO.rb\nlib/Dnsruby/resource/MX.rb\nlib/Dnsruby/resource/NAPTR.rb\nlib/Dnsruby/resource/NSAP.rb\nlib/Dnsruby/resource/NSEC.rb\nlib/Dnsruby/resource/NSEC3.rb\nlib/Dnsruby/resource/NSEC3PARAM.rb\nlib/Dnsruby/resource/OPT.rb\nlib/Dnsruby/resource/PX.rb\nlib/Dnsruby/resource/RP.rb\nlib/Dnsruby/resource/RRSIG.rb\nlib/Dnsruby/resource/RT.rb\nlib/Dnsruby/resource/SOA.rb\nlib/Dnsruby/resource/SPF.rb\nlib/Dnsruby/resource/SRV.rb\nlib/Dnsruby/resource/TKEY.rb\nlib/Dnsruby/resource/TSIG.rb\nlib/Dnsruby/resource/TXT.rb\nlib/Dnsruby/resource/X25.rb\nlib/Dnsruby/resource/domain_name.rb\nlib/Dnsruby/resource/generic.rb\nlib/Dnsruby/resource/resource.rb] ValidatorThread PacketSender ResolverRuby Config KeyCache Cache SingleVerifier Resolv Iana lib/Dnsruby/DNS.rb lib/Dnsruby/dnssec.rb lib/Dnsruby/Hosts.rb lib/Dnsruby/select_thread.rb.michael.rb lib/Dnsruby/Recursor.rb lib/Dnsruby/update.rb lib/Dnsruby/ipv6.rb lib/Dnsruby/ipv4.rb lib/Dnsruby/code_mapper.rb lib/Dnsruby/zone_transfer.rb lib/Dnsruby/message.rb lib/Dnsruby/TheLog.rb lib/Dnsruby/resource/resource.rb lib/Dnsruby/validator_thread.rb lib/Dnsruby/PacketSender.rb lib/Dnsruby/Resolver.rb lib/Dnsruby/Config.rb lib/Dnsruby/key_cache.rb lib/Dnsruby/Cache.rb lib/Dnsruby/single_verifier.rb lib/Dnsruby/SingleResolver.rb lib/Dnsruby/name.rb lib/dnsruby.rb lib/Dnsruby/resource/TKEY.rb lib/Dnsruby/iana_ports.rb Dnsruby dot/m_56_0.png

Defines a DNS packet.

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

Sections

Message objects have five sections:

  • The header section, a Dnsruby::Header object.
        msg.header=Header.new(...)
        header = msg.header
    
  • The question section, an array of Dnsruby::Question objects.
        msg.add_question(Question.new(domain, type, klass))
        msg.each_question do |question|  ....   end
    
  • The answer section, an array of Dnsruby::RR objects.
        msg.add_answer(RR.create({:name    => "a2.example.com",
                     :type    => "A", :address => "10.0.0.2"}))
        msg.each_answer {|answer| ... }
    
  • The authority section, an array of Dnsruby::RR objects.
        msg.add_authority(rr)
        msg.each_authority {|rr| ... }
    
  • The additional section, an array of Dnsruby::RR objects.
        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.

Methods

Classes and Modules

Class Dnsruby::Message::Section
Class Dnsruby::Message::SecurityLevel

External Aliases

question -> zone
  In dynamic update packets, the question section is known as zone and specifies the zone to be updated.
answer -> pre
  In dynamic update packets, the answer section is known as pre or prerequisite and specifies the RRs or RRsets which must or must not preexist.
add_answer -> add_pre
pre -> prerequisite
  In dynamic update packets, the answer section is known as pre or prerequisite and specifies the RRs or RRsets which must or must not preexist.
add_pre -> add_prerequisite
authority -> update
  In dynamic update packets, the authority section is known as update and specifies the RRs or RRsets to be added or delted.
add_authority -> add_update

Attributes

additional  [R]  The additional section, an array of Dnsruby::RR objects.
answer  [R]  The answer section, an array of Dnsruby::RR objects.
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
authority  [R]  The authority section, an array of Dnsruby::RR objects.
cached  [RW]  If the Message was returned from the cache, the cached flag will be set true. It will be false otherwise.
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.
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
header  [RW]  The header section, a Dnsruby::Header object.
question  [R]  The question section, an array of Dnsruby::Question objects.
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 ""
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.
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.

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
tsigstart  [RW] 
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

Public Class methods

Decode the encoded message

[Source]

     # File lib/Dnsruby/message.rb, line 587
587:     def Message.decode(m)
588:       o = Message.new()
589:       MessageDecoder.new(m) {|msg|
590:         o.header = Header.new(msg)
591:         o.header.qdcount.times {
592:           question = msg.get_question
593:           o.question << question
594:         }
595:         o.header.ancount.times {
596:           rr = msg.get_rr
597:           o.answer << rr
598:         }
599:         o.header.nscount.times {
600:           rr = msg.get_rr
601:           o.authority << rr
602:         }
603:         o.header.arcount.times { |count|
604:           start = msg.index
605:           rr = msg.get_rr
606:           if (rr.type == Types::TSIG)
607:             if (count!=o.header.arcount-1)
608:               Dnsruby.log.Error("Incoming message has TSIG record before last record")
609:               raise DecodeError.new("TSIG record present before last record")
610:             end
611:             o.tsigstart = start # needed for TSIG verification
612:           end
613:           o.additional << rr
614:         }
615:       }
616:       return o
617:     end

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

type defaults to A, and klass defaults to IN

[Source]

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

Public Instance methods

[Source]

     # File lib/Dnsruby/message.rb, line 302
302:     def ==(other)
303:       ret = false
304:       if (other.kind_of?Message)
305:         ret = @header == other.header &&
306:           @question[0] == other.question[0] &&
307:           @answer == other.answer &&
308:           @authority == other.authority &&
309:           @additional == other.additional
310:       end
311:       return ret
312:     end

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)

[Source]

     # File lib/Dnsruby/message.rb, line 351
351:     def add_question(question, type=Types.A, klass=Classes.IN)
352:       if (!question.kind_of?Question)
353:         question = Question.new(question, type, klass)
354:       end
355:       @question << question
356:       update_counts
357:     end
add_zone(question, type=Types.A, klass=Classes.IN)

Alias for add_question

[Source]

     # File lib/Dnsruby/message.rb, line 406
406:     def each_additional
407:       @additional.each {|rec|
408:         yield rec
409:       }
410:     end

[Source]

     # File lib/Dnsruby/message.rb, line 380
380:     def each_answer
381:       @answer.each {|rec|
382:         yield rec
383:       }
384:     end

[Source]

     # File lib/Dnsruby/message.rb, line 393
393:     def each_authority
394:       @authority.each {|rec|
395:         yield rec
396:       }
397:     end
each_pre()

Alias for each_answer

each_prerequisite()

Alias for each_pre

[Source]

     # File lib/Dnsruby/message.rb, line 359
359:     def each_question
360:       @question.each {|rec|
361:         yield rec
362:       }
363:     end

Calls each_answer, each_authority, each_additional

[Source]

     # File lib/Dnsruby/message.rb, line 418
418:     def each_resource
419:       each_answer {|rec| yield rec}
420:       each_authority {|rec| yield rec}
421:       each_additional {|rec| yield rec}
422:     end

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

[Source]

     # File lib/Dnsruby/message.rb, line 413
413:     def each_section
414:       [@answer, @authority, @additional].each {|section| yield section}
415:     end
each_update()

Alias for each_authority

each_zone()

Alias for each_question

Return the encoded form of the message

 If there is a TSIG record present and the record has not been signed
 then sign it

[Source]

     # File lib/Dnsruby/message.rb, line 565
565:     def encode
566:       if ((@tsigkey) && @tsigstate == :Unsigned && !@signing)
567:         @signing = true
568:         sign!
569:         @signing = false
570:       end
571:       return MessageEncoder.new {|msg|
572:         header = @header
573:         header.encode(msg)
574:         @question.each {|q|
575:           msg.put_name(q.qname)
576:           msg.put_pack('nn', q.qtype.code, q.qclass.code)
577:         }
578:         [@answer, @authority, @additional].each {|rr|
579:           rr.each { |r|
580:             msg.put_rr(r)
581:           }
582:         }
583:       }.to_s
584:     end

[Source]

     # File lib/Dnsruby/message.rb, line 274
274:     def get_exception
275:       exception = nil
276:       if (rcode==RCode.NXDOMAIN)
277:         exception = NXDomain.new
278:       elsif (rcode==RCode.SERVFAIL)
279:         exception = ServFail.new
280:       elsif (rcode==RCode.FORMERR)
281:         exception = FormErr.new
282:       elsif (rcode==RCode.NOTIMP)
283:         exception = NotImp.new
284:       elsif (rcode==RCode.REFUSED)
285:         exception = Refused.new
286:       elsif (rcode==RCode.NOTZONE)
287:         exception = NotZone.new
288:       elsif (rcode==RCode.NOTAUTH)
289:         exception = NotAuth.new
290:       elsif (rcode==RCode.NXRRSET)
291:         exception = NXRRSet.new
292:       elsif (rcode==RCode.YXRRSET)
293:         exception = YXRRSet.new
294:       elsif (rcode==RCode.YXDOMAIN)
295:         exception = YXDomain.new
296:       elsif (rcode >= RCode.BADSIG && rcode <= RCode.BADALG)
297:         return VerifyError.new # @TODO@
298:       end
299:       return exception
300:     end

[Source]

     # File lib/Dnsruby/message.rb, line 465
465:     def get_opt
466:       each_additional do |r|
467:         if (r.type == Types::OPT)
468:           return r
469:         end
470:       end
471:       return nil
472:     end

[Source]

     # File lib/Dnsruby/message.rb, line 474
474:     def rcode
475:       rcode = @header.get_header_rcode
476:       opt = get_opt
477:       if (opt != nil)
478:         rcode = rcode.code + (opt.xrcode.code << 4)
479:         rcode = RCode.new(rcode)
480:       end
481:       return rcode;
482:     end

Return the first rrset of the specified attributes in the message

[Source]

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

Return the rrsets of the specified type in the message

[Source]

     # File lib/Dnsruby/message.rb, line 325
325:     def rrsets(type, klass=Classes::IN)
326:       rrsets = []
327:       [@answer, @authority, @additional].each do |section|
328:         if ((rrset = section.rrsets(type, klass)).length > 0)
329:           rrsets.push(rrset)
330:         end
331:       end
332:       return rrsets
333:     end

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

[Source]

     # File lib/Dnsruby/message.rb, line 337
337:     def section_rrsets(type = nil, include_opt = false)
338:       ret = {}
339:       ["answer", "authority", "additional"].each do |section|
340:         ret[section] = self.send(section).rrsets(type, include_opt)
341:       end
342:       return ret
343:     end

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

[Source]

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

Was this message signed by a TSIG?

[Source]

     # File lib/Dnsruby/message.rb, line 454
454:     def signed?
455:       return (@tsigstate == :Signed ||
456:           @tsigstate == :Verified ||
457:           @tsigstate == :Failed)
458:     end

[Source]

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

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

[Source]

     # File lib/Dnsruby/message.rb, line 425
425:     def tsig
426:       if (@additional.last)
427:         if (@additional.last.rr_type == Types.TSIG)
428:           return @additional.last
429:         end
430:       end
431:       return nil
432:     end

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

[Source]

     # File lib/Dnsruby/message.rb, line 461
461:     def verified?
462:       return (@tsigstate == :Verified)
463:     end

[Validate]