Browse Source

added comments about EDNS0 version mismatch handling

git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1062 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 15 years ago
parent
commit
ba4051570b
1 changed files with 64 additions and 30 deletions
  1. 64 30
      src/lib/dns/cpp/message.cc

+ 64 - 30
src/lib/dns/cpp/message.cc

@@ -18,11 +18,14 @@
 
 #include <algorithm>
 #include <string>
+#include <sstream>
 #include <vector>
 
 #include <boost/lexical_cast.hpp>
 #include <boost/shared_ptr.hpp>
 
+#include <exceptions/exceptions.h>
+
 #include "buffer.h"
 #include "message.h"
 #include "messagerenderer.h"
@@ -55,7 +58,13 @@ static const flags_t FLAG_RA = 0x0080;
 static const flags_t FLAG_AD = 0x0020;
 static const flags_t FLAG_CD = 0x0010;
 
+//
+// EDNS0 related constants
+//
+static const flags_t EXTFLAG_MASK = 0xffff;
 static const flags_t EXTFLAG_DO = 0x8000;
+static const uint32_t EXTRCODE_MASK = 0xff000000; 
+static const uint32_t EDNSVERSION_MASK = 0x00ff0000;
 
 static const unsigned int OPCODE_MASK = 0x7800;
 static const unsigned int OPCODE_SHIFT = 11;
@@ -64,23 +73,24 @@ static const unsigned int FLAG_MASK = 0x8ff0;
 
 static const unsigned int MESSAGE_REPLYPRESERVE = (FLAG_RD | FLAG_CD);
 
-static const Rcode* rcodes[] = {
-    &Rcode::NOERROR(),
-    &Rcode::FORMERR(),
-    &Rcode::SERVFAIL(),
-    &Rcode::NXDOMAIN(),
-    &Rcode::NOTIMP(),
-    &Rcode::REFUSED(),
-    &Rcode::YXDOMAIN(),
-    &Rcode::YXRRSET(),
-    &Rcode::NXRRSET(),
-    &Rcode::NOTAUTH(),
-    &Rcode::NOTZONE(),
-    &Rcode::RESERVED11(),
-    &Rcode::RESERVED12(),
-    &Rcode::RESERVED13(),
-    &Rcode::RESERVED14(),
-    &Rcode::RESERVED15()
+static const Rcode rcodes[] = {
+    Rcode::NOERROR(),
+    Rcode::FORMERR(),
+    Rcode::SERVFAIL(),
+    Rcode::NXDOMAIN(),
+    Rcode::NOTIMP(),
+    Rcode::REFUSED(),
+    Rcode::YXDOMAIN(),
+    Rcode::YXRRSET(),
+    Rcode::NXRRSET(),
+    Rcode::NOTAUTH(),
+    Rcode::NOTZONE(),
+    Rcode::RESERVED11(),
+    Rcode::RESERVED12(),
+    Rcode::RESERVED13(),
+    Rcode::RESERVED14(),
+    Rcode::RESERVED15(),
+    Rcode::BADVERS()
 };
 
 static const char *rcodetext[] = {
@@ -99,7 +109,8 @@ static const char *rcodetext[] = {
     "RESERVED12",
     "RESERVED13",
     "RESERVED14",
-    "RESERVED15"
+    "RESERVED15",
+    "BADVERS"
 };
 
 static const Opcode* opcodes[] = {
@@ -147,10 +158,23 @@ Opcode::toText() const
     return (opcodetext[code_]);
 }
 
+Rcode::Rcode(uint16_t code) : code_(code)
+{
+    if (code_ > MAX_RCODE) {
+        dns_throw(OutOfRange, "Rcode is too large to construct");
+    }
+}
+
 string
 Rcode::toText() const
 {
-    return (rcodetext[code_]);
+    if (code_ < sizeof(rcodetext) / sizeof (const char *)) {
+        return (rcodetext[code_]);
+    }
+
+    ostringstream oss;
+    oss << code_;
+    return (oss.str());
 }
 
 namespace {
@@ -169,7 +193,7 @@ public:
     // Open issues: should we rather have a header in wire-format
     // for efficiency?
     qid_t qid_;
-    const Rcode* rcode_;
+    Rcode rcode_;
     const Opcode* opcode_;
     flags_t flags_;
     bool dnssec_ok_;
@@ -192,7 +216,8 @@ public:
                       InputBuffer& buffer);
 };
 
-MessageImpl::MessageImpl()
+MessageImpl::MessageImpl() :
+    rcode_(Rcode::NOERROR())
 {
     init();
 }
@@ -202,7 +227,7 @@ MessageImpl::init()
 {
     flags_ = 0;
     qid_ = 0;
-    rcode_ = NULL;
+    rcode_ = Rcode::NOERROR();  // XXX
     opcode_ = NULL;
     dnssec_ok_ = false;
     edns_ = RRsetPtr();
@@ -273,13 +298,13 @@ Message::setQid(qid_t qid)
 const Rcode&
 Message::getRcode() const
 {
-    return (*impl_->rcode_);
+    return (impl_->rcode_);
 }
 
 void
 Message::setRcode(const Rcode& rcode)
 {
-    impl_->rcode_ = &rcode;
+    impl_->rcode_ = rcode;
 }
 
 const Opcode&
@@ -378,7 +403,7 @@ Message::toWire(MessageRenderer& renderer)
     renderer.writeUint16At(impl_->qid_, header_pos);
     header_pos += sizeof(uint16_t);
     codes_and_flags = (impl_->opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
-    codes_and_flags |= (impl_->rcode_->getCode() & RCODE_MASK);
+    codes_and_flags |= (impl_->rcode_.getCode() & RCODE_MASK);
     codes_and_flags |= (impl_->flags_ & FLAG_MASK);
     renderer.writeUint16At(codes_and_flags, header_pos);
     header_pos += sizeof(uint16_t);
@@ -456,14 +481,15 @@ struct MatchRR : public unary_function<RRsetPtr, bool> {
 }
 
 void
-MessageImpl::parseSection(Message& messge, const Section& section,
+MessageImpl::parseSection(Message& message, const Section& section,
                           InputBuffer& buffer)
 {
     for (unsigned int count = 0; count < counts_[section.getCode()]; count++) {
         Name name(buffer);
 
+        // buffer must store at least RR TYPE, RR CLASS, TTL, and RDLEN.
         if ((buffer.getLength() - buffer.getPosition()) <
-            2 * sizeof(uint16_t) + sizeof(uint32_t)) {
+            3 * sizeof(uint16_t) + sizeof(uint32_t)) {
             dns_throw(MessageTooShort, "");
         }
 
@@ -484,7 +510,13 @@ MessageImpl::parseSection(Message& messge, const Section& section,
             if (edns_ != NULL) {
                 dns_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
             }
-            if (((ttl.getValue() & 0x00ff0000) >> 16) >
+            if (((ttl.getValue() & EDNSVERSION_MASK) >> 16) >
+                // XXX: we should probably not reject the message yet, because
+                // it's better to let the requestor know the responder-side
+                // highest version as indicated in Section 4.6 of RFC2671.
+                // This is probably because why BIND 9 does the version check
+                // in the client code.
+                // This is a TODO item.  Right now we simply reject it.
                 Message::EDNS0_SUPPORTED_VERSION) {
                 dns_throw(DNSMessageBADVERS, "unsupported EDNS version");
             }
@@ -496,10 +528,12 @@ MessageImpl::parseSection(Message& messge, const Section& section,
             edns_ = RRsetPtr(new RRset(name, rrclass, rrtype, ttl));
             edns_->addRdata(rdata);
 
-            dnssec_ok_ = (((ttl.getValue() & 0xffff) & EXTFLAG_DO) != 0);
+            dnssec_ok_ = (((ttl.getValue() & EXTFLAG_MASK) & EXTFLAG_DO) != 0);
             if (rrclass.getCode() > Message::DEFAULT_MAX_UDPSIZE) {
                 udpsize_ = rrclass.getCode();
             }
+            rcode_ = Rcode(((ttl.getValue() & EXTRCODE_MASK) >> 20) |
+                           rcode_.getCode());
             continue;
         }
 
@@ -550,7 +584,7 @@ Message::toText() const
 
     s += ";; ->>HEADER<<- opcode: " + impl_->opcode_->toText();
     // for simplicity we don't consider extended rcode (unlike BIND9)
-    s += ", status: " + impl_->rcode_->toText();
+    s += ", status: " + impl_->rcode_.toText();
     s += ", id: " + boost::lexical_cast<string>(impl_->qid_);
     s += "\n;; flags: ";
     if (getHeaderFlag(MessageFlag::QR()))