Object
RFC 1035 Section 4.1, RFC 2136 Section 2, RFC 2845
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| ... }
Dnsruby::Message#encode Dnsruby::Message::decode(data)
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.
If this Message is a response from a server, then answerfrom contains the address of the server
If this Message is a response from a server, then answerfrom contains the IP address of the server
If this Message is a response from a server, then answersize contains the size of the response
If the Message was returned from the cache, the cached flag will be set true. It will be false otherwise.
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 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
If there was a problem verifying this message with DNSSEC, then securiy_error will hold a description of the problem. It defaults to ""
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.
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
Decode the encoded message
# File lib/Dnsruby/message.rb, line 597 def Message.decode(m) o = Message.new() begin MessageDecoder.new(m) {|msg| o.header = Header.new(msg) o.header.qdcount.times { question = msg.get_question o.question << question } o.header.ancount.times { rr = msg.get_rr o.answer << rr } o.header.nscount.times { rr = msg.get_rr o.authority << rr } o.header.arcount.times { |count| start = msg.index rr = msg.get_rr if (rr.type == Types::TSIG) if (count!=o.header.arcount-1) Dnsruby.log.Error("Incoming message has TSIG record before last record") raise DecodeError.new("TSIG record present before last record") end o.tsigstart = start # needed for TSIG verification end o.additional << rr } } rescue DecodeError => e # So we got a decode error # However, we might have been able to fill in many parts of the message # So let's raise the DecodeError, but add the partially completed message e.partial_message = o raise e end return o end
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 def initialize(*args) @header = Header.new() # @question = Section.new(self) @question = [] @answer = Section.new(self) @authority = Section.new(self) @additional = Section.new(self) @tsigstate = :Unsigned @signing = false @tsigkey = nil @answerfrom = nil @answerip = nil @send_raw = false @do_validation = true @do_caching = true @security_level = SecurityLevel.UNCHECKED @security_error = nil @cached = false type = Types::A klass = Classes::IN if (args.length > 0) name = args[0] if (args.length > 1) type = Types.new(args[1]) if (args.length > 2) klass = Classes.new(args[2]) end end add_question(name, type, klass) end end
# File lib/Dnsruby/message.rb, line 305 def ==(other) ret = false if (other.kind_of?Message) ret = @header == other.header && @question[0] == other.question[0] && @answer == other.answer && @authority == other.authority && @additional == other.additional end return ret 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)
# File lib/Dnsruby/message.rb, line 361 def add_question(question, type=Types.A, klass=Classes.IN) if (!question.kind_of?Question) question = Question.new(question, type, klass) end @question << question update_counts end
# File lib/Dnsruby/message.rb, line 416 def each_additional @additional.each {|rec| yield rec } end
# File lib/Dnsruby/message.rb, line 390 def each_answer @answer.each {|rec| yield rec } end
# File lib/Dnsruby/message.rb, line 369 def each_question @question.each {|rec| yield rec } end
Calls each_answer, each_authority, each_additional
# File lib/Dnsruby/message.rb, line 428 def each_resource each_answer {|rec| yield rec} each_authority {|rec| yield rec} each_additional {|rec| yield rec} end
Yields each section (question, answer, authority, additional)
# File lib/Dnsruby/message.rb, line 423 def each_section [@answer, @authority, @additional].each {|section| yield section} end
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 575 def encode if ((@tsigkey) && @tsigstate == :Unsigned && !@signing) @signing = true sign! @signing = false end return MessageEncoder.new {|msg| header = @header header.encode(msg) @question.each {|q| msg.put_name(q.qname) msg.put_pack('nn', q.qtype.code, q.qclass.code) } [@answer, @authority, @additional].each {|rr| rr.each { |r| msg.put_rr(r) } } }.to_s end
# File lib/Dnsruby/message.rb, line 277 def get_exception exception = nil if (rcode==RCode.NXDOMAIN) exception = NXDomain.new elsif (rcode==RCode.SERVFAIL) exception = ServFail.new elsif (rcode==RCode.FORMERR) exception = FormErr.new elsif (rcode==RCode.NOTIMP) exception = NotImp.new elsif (rcode==RCode.REFUSED) exception = Refused.new elsif (rcode==RCode.NOTZONE) exception = NotZone.new elsif (rcode==RCode.NOTAUTH) exception = NotAuth.new elsif (rcode==RCode.NXRRSET) exception = NXRRSet.new elsif (rcode==RCode.YXRRSET) exception = YXRRSet.new elsif (rcode==RCode.YXDOMAIN) exception = YXDomain.new elsif (rcode >= RCode.BADSIG && rcode <= RCode.BADALG) return VerifyError.new # @TODO@ end return exception end
# File lib/Dnsruby/message.rb, line 475 def get_opt each_additional do |r| if (r.type == Types::OPT) return r end end return nil end
# File lib/Dnsruby/message.rb, line 484 def rcode rcode = @header.get_header_rcode opt = get_opt if (opt != nil) rcode = rcode.code + (opt.xrcode.code << 4) rcode = RCode.new(rcode) end return rcode; end
# File lib/Dnsruby/message.rb, line 317 def remove_additional @additional = Section.new(self) @header.arcount = 0 end
Return the first rrset of the specified attributes in the message
# File lib/Dnsruby/message.rb, line 323 def rrset(name, type, klass = Classes::IN) [@answer, @authority, @additional].each do |section| if ((rrset = section.rrset(name, type, klass)).length > 0) return rrset end end return RRSet.new end
Return the rrsets of the specified type in the message
# File lib/Dnsruby/message.rb, line 333 def rrsets(type, klass=Classes::IN) rrsetss = [] [@answer, @authority, @additional].each do |section| if ((rrsets = section.rrsets(type, klass)).length > 0) rrsets.each {|rrset| rrsetss.push(rrset) } end end return rrsetss end
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 347 def section_rrsets(type = nil, include_opt = false) ret = {} ["answer", "authority", "additional"].each do |section| ret[section] = self.send(section).rrsets(type, include_opt) end return ret 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.)
# File lib/Dnsruby/message.rb, line 447 def set_tsig(*args) if (args.length == 1) if (args[0].instance_of?RR::TSIG) @tsigkey = args[0] elsif (args[0].instance_of?Hash) @tsigkey = RR.create({:type=>'TSIG', :klass=>'ANY'}.merge(args[0])) else raise ArgumentError.new("Wrong type of argument to Dnsruby::Message#set_tsig - should be TSIG or Hash") end elsif (args.length == 2) @tsigkey = RR.create({:type=>'TSIG', :klass=>'ANY', :name=>args[0], :key=>args[1]}) else raise ArgumentError.new("Wrong number of arguments to Dnsruby::Message#set_tsig") end end
Was this message signed by a TSIG?
# File lib/Dnsruby/message.rb, line 464 def signed? return (@tsigstate == :Signed || @tsigstate == :Verified || @tsigstate == :Failed) end
# File lib/Dnsruby/message.rb, line 494 def to_s retval = ""; if (@answerfrom != nil && @answerfrom != "") retval = retval + ";; Answer received from #{@answerfrom} (#{@answersize} bytes)\n;;\n"; end retval = retval + ";; Security Level : #{@security_level.string}\n" retval = retval + ";; HEADER SECTION\n" # OPT pseudosection? EDNS flags, udpsize opt = get_opt if (!opt) retval = retval + @header.to_s else retval = retval + @header.to_s_with_rcode(rcode()) end retval = retval + "\n" if (opt) retval = retval + opt.to_s retval = retval + "\n" end section = (@header.opcode == OpCode.UPDATE) ? "ZONE" : "QUESTION"; retval = retval + ";; #{section} SECTION (#{@header.qdcount} record#{@header.qdcount == 1 ? '' : 's'})\n"; each_question { |qr| retval = retval + ";; #{qr.to_s}\n"; } if (@answer.size > 0) retval = retval + "\n"; section = (@header.opcode == OpCode.UPDATE) ? "PREREQUISITE" : "ANSWER"; retval = retval + ";; #{section} SECTION (#{@header.ancount} record#{@header.ancount == 1 ? '' : 's'})\n"; each_answer { |rr| retval = retval + rr.to_s + "\n"; } end if (@authority.size > 0) retval = retval + "\n"; section = (@header.opcode == OpCode.UPDATE) ? "UPDATE" : "AUTHORITY"; retval = retval + ";; #{section} SECTION (#{@header.nscount} record#{@header.nscount == 1 ? '' : 's'})\n"; each_authority { |rr| retval = retval + rr.to_s + "\n"; } end if ((@additional.size > 0 && !opt) || (@additional.size > 1)) retval = retval + "\n"; retval = retval + ";; ADDITIONAL SECTION (#{@header.arcount} record#{@header.arcount == 1 ? '' : 's'})\n"; each_additional { |rr| if (rr.type != Types::OPT) retval = retval + rr.to_s+ "\n" end } end return retval; end
Generated with the Darkfish Rdoc Generator 2.