Commit 6caebd56 authored by JINMEI Tatuya's avatar JINMEI Tatuya

checkpoint: supported EDNS0 DO bit, receive side.


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1039 e5f2f494-b856-4b98-b285-d166d9295462
parent 9e7717af
......@@ -55,6 +55,8 @@ static const flags_t FLAG_RA = 0x0080;
static const flags_t FLAG_AD = 0x0020;
static const flags_t FLAG_CD = 0x0010;
static const flags_t EXTFLAG_DO = 0x8000;
static const unsigned int OPCODE_MASK = 0x7800;
static const unsigned int OPCODE_SHIFT = 11;
static const unsigned int RCODE_MASK = 0x000f;
......@@ -151,7 +153,18 @@ Rcode::toText() const
return (rcodetext[code_]);
}
struct MessageImpl {
namespace {
inline unsigned int
sectionCodeToId(const Section& section)
{
unsigned int code = section.getCode();
assert(code > 0);
return (section.getCode() - 1);
}
}
class MessageImpl {
public:
MessageImpl();
// Open issues: should we rather have a header in wire-format
// for efficiency?
......@@ -159,39 +172,51 @@ struct MessageImpl {
const Rcode* rcode_;
const Opcode* opcode_;
flags_t flags_;
bool dnssec_ok_;
static const unsigned int SECTION_MAX = 4; // TODO: revisit this design
int counts_[SECTION_MAX]; // TODO: revisit this definition
vector<QuestionPtr> questions_;
vector<RRsetPtr> rrsets_[SECTION_MAX];
RRsetPtr edns_;
#ifdef notyet
// tsig/sig0: TODO
EDNS* edns_;
RRsetsSorter* sorter_;
#endif
void init();
void parseQuestion(Message& message, InputBuffer& buffer);
void parseSection(Message& messge, const Section& section,
InputBuffer& buffer);
};
MessageImpl::MessageImpl() :
qid_(0), rcode_(NULL), opcode_(NULL), flags_(0)
qid_(0), rcode_(NULL), opcode_(NULL), flags_(0), dnssec_ok_(false)
{
for (int i = 0; i < SECTION_MAX; i++) {
counts_[i] = 0;
}
}
namespace {
inline unsigned int
sectionCodeToId(const Section& section)
void
MessageImpl::init()
{
unsigned int code = section.getCode();
assert(code > 0);
return (section.getCode() - 1);
}
flags_ = 0;
qid_ = 0;
rcode_ = NULL;
opcode_ = NULL;
dnssec_ok_ = false;
edns_ = RRsetPtr();
for (int i = 0; i < SECTION_MAX; i++) {
counts_[i] = 0;
}
questions_.clear();
rrsets_[sectionCodeToId(Section::ANSWER())].clear();
rrsets_[sectionCodeToId(Section::AUTHORITY())].clear();
rrsets_[sectionCodeToId(Section::ADDITIONAL())].clear();
}
Message::Message() :
......@@ -222,6 +247,12 @@ Message::clearHeaderFlag(const MessageFlag& flag)
impl_->flags_ &= ~flag.getBit();
}
bool
Message::isDNSSECSupported() const
{
return (impl_->dnssec_ok_);
}
qid_t
Message::getQid() const
{
......@@ -437,6 +468,30 @@ MessageImpl::parseSection(Message& messge, const Section& section,
size_t rdlen = buffer.readUint16();
RdataPtr rdata = createRdata(rrtype, rrclass, buffer, rdlen);
// XXX: we wanted to avoid hardcoding type-specific logic here,
// but this would be the fastest way for a proof-of-concept
// implementation. We'll revisit this part later.
if (rrtype == RRType::OPT()) {
if (section != Section::ADDITIONAL()) {
dns_throw(DNSMessageFORMERR,
"EDNS OPT RR found in an invalid section");
}
if (edns_ != NULL) {
dns_throw(DNSMessageFORMERR, "multiple EDNS OPT RR found");
}
if (name != Name::ROOT_NAME()) {
dns_throw(DNSMessageFORMERR,
"invalid owner name for EDNS OPT RR");
}
edns_ = RRsetPtr(new RRset(name, rrclass, rrtype, ttl));
edns_->addRdata(rdata);
dnssec_ok_ = (((ttl.getValue() & 0xffff) & EXTFLAG_DO) != 0);
continue;
}
vector<RRsetPtr>::iterator it =
find_if(rrsets_[sectionCodeToId(section)].begin(),
rrsets_[sectionCodeToId(section)].end(),
......@@ -545,6 +600,12 @@ Message::toText() const
return (s);
}
void
Message::clear()
{
impl_->init();
}
void
Message::makeResponse()
{
......@@ -552,8 +613,11 @@ Message::makeResponse()
setHeaderFlag(MessageFlag::QR());
impl_->rrsets_[sectionCodeToId(Section::ANSWER())].clear();
impl_->counts_[Section::ANSWER().getCode()] = 0;
impl_->rrsets_[sectionCodeToId(Section::AUTHORITY())].clear();
impl_->counts_[Section::AUTHORITY().getCode()] = 0;
impl_->rrsets_[sectionCodeToId(Section::ADDITIONAL())].clear();
impl_->counts_[Section::ADDITIONAL().getCode()] = 0;
}
///
......
......@@ -20,8 +20,6 @@
#include <iterator>
#include <string>
#include <boost/shared_ptr.hpp>
#include <exceptions/exceptions.h>
#include "question.h"
#include "rrset.h"
......@@ -29,6 +27,21 @@
namespace isc {
namespace dns {
///
/// \brief A standard DNS module exception ...[TBD]
///
class DNSProtocolError : public Exception {
public:
DNSProtocolError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
class DNSMessageFORMERR : public DNSProtocolError {
public:
DNSMessageFORMERR(const char* file, size_t line, const char* what) :
DNSProtocolError(file, line, what) {}
};
///
/// \brief A standard DNS module exception ...[TBD]
///
......@@ -403,6 +416,8 @@ public:
unsigned int getCode() const { return (code_); }
bool operator==(const Section& other) const
{ return (code_ == other.code_); }
bool operator!=(const Section& other) const
{ return (code_ != other.code_); }
static const Section& QUESTION();
static const Section& ANSWER();
......@@ -474,11 +489,13 @@ public:
~Message();
private:
Message(const Message& source);
void operator=(const Message& source);
Message& operator=(const Message& source);
public:
bool getHeaderFlag(const MessageFlag& flag) const;
void setHeaderFlag(const MessageFlag& flag);
void clearHeaderFlag(const MessageFlag& flag);
bool isDNSSECSupported() const;
void setDNSSECSupported(bool on);
qid_t getQid() const;
void setQid(qid_t qid);
const Rcode& getRcode() const;
......@@ -509,45 +526,26 @@ public:
//void addRR(const Section& section, const RR& rr);
//void removeRR(const Section& section, const RR& rr);
void clear();
// prepare for making a response from a request. This will clear the
// DNS header except those fields that should be kept for the response,
// and clear answer and the following sections.
// see also dns_message_reply() of BIND9.
void makeResponse();
/// Render message
/// \brief Render message.
void toWire(MessageRenderer& renderer);
/// \brief Parse a DNS message.
void fromWire(InputBuffer& buffer);
public:
// public protocol constants
static const rcode_t RCODE_NOERROR = 0;
static const rcode_t RCODE_FORMERR = 1;
static const rcode_t RCODE_SERVFAIL = 2;
static const rcode_t RCODE_NXDOMAIN = 3;
static const rcode_t RCODE_NOTIMP = 4;
static const rcode_t RCODE_REFUSED = 5;
static const rcode_t RCODE_YXDOMAIN = 6;
static const rcode_t RCODE_YXRRSET = 7;
static const rcode_t RCODE_NXRRSET = 8;
static const rcode_t RCODE_NOTAUTH = 9;
static const rcode_t RCODE_NOTZONE = 10;
// ...more to follow
static const opcode_t OPCODE_QUERY = 0;
static const opcode_t OPCODE_IQUERY = 1;
static const opcode_t OPCODE_STATUS = 2;
static const opcode_t OPCODE_NOTIFY = 4;
static const opcode_t OPCODE_UPDATE = 5;
private:
MessageImpl* impl_;
};
std::ostream& operator<<(std::ostream& os, const Opcode& rrset);
std::ostream& operator<<(std::ostream& os, const Rcode& rrset);
std::ostream& operator<<(std::ostream& os, const Opcode& opcode);
std::ostream& operator<<(std::ostream& os, const Rcode& rcode);
std::ostream& operator<<(std::ostream& os, const Message& message);
}
}
......
......@@ -599,6 +599,14 @@ public:
static const uint16_t COMPRESS_POINTER_MARK16 = 0xc000;
//@}
///
/// \name Well-known name constants
///
//@{
/// \brief Root name (i.e. ".").
static const Name& ROOT_NAME();
//@}
private:
std::string ndata_;
std::vector<unsigned char> offsets_;
......@@ -606,6 +614,13 @@ private:
unsigned int labelcount_;
};
inline const Name&
Name::ROOT_NAME()
{
static Name root_name(".");
return (root_name);
}
///
/// \brief Insert the name as a string into stream.
///
......
......@@ -44,6 +44,8 @@ protected:
static void factoryFromFile(Message& message, const char* datafile);
};
const Name test_name("test.example.com");
void
MessageTest::factoryFromFile(Message& message, const char* datafile)
{
......@@ -65,12 +67,16 @@ TEST_F(MessageTest, fromWire)
EXPECT_TRUE(message.getHeaderFlag(MessageFlag::AA()));
QuestionPtr q = *message.beginQuestion();
EXPECT_EQ(Name("test.example.com"), q->getName());
EXPECT_EQ(test_name, q->getName());
EXPECT_EQ(RRType::A(), q->getType());
EXPECT_EQ(RRClass::IN(), q->getClass());
EXPECT_EQ(1, message.getRRCount(Section::QUESTION()));
EXPECT_EQ(2, message.getRRCount(Section::ANSWER()));
EXPECT_EQ(0, message.getRRCount(Section::AUTHORITY()));
EXPECT_EQ(0, message.getRRCount(Section::ADDITIONAL()));
RRsetPtr rrset = *message.beginSection(Section::ANSWER());
EXPECT_EQ(Name("test.example.com"), rrset->getName());
EXPECT_EQ(test_name, rrset->getName());
EXPECT_EQ(RRType::A(), rrset->getType());
EXPECT_EQ(RRClass::IN(), rrset->getClass());
// TTL should be 3600, even though that of the 2nd RR is 7200
......@@ -84,6 +90,40 @@ TEST_F(MessageTest, fromWire)
EXPECT_TRUE(it->isLast());
}
TEST_F(MessageTest, EDNS0DOBit)
{
factoryFromFile(message, "testdata/message_fromWire1");
EXPECT_FALSE(message.isDNSSECSupported());
message.clear();
factoryFromFile(message, "testdata/message_fromWire2");
EXPECT_TRUE(message.isDNSSECSupported());
message.clear();
factoryFromFile(message, "testdata/message_fromWire3");
EXPECT_FALSE(message.isDNSSECSupported());
}
TEST_F(MessageTest, BadEDNS0)
{
// OPT RR in the answer section
EXPECT_THROW(factoryFromFile(message, "testdata/message_fromWire4"),
DNSMessageFORMERR);
// multiple OPT RRs (in the additional section)
message.clear();
EXPECT_THROW(factoryFromFile(message, "testdata/message_fromWire5"),
DNSMessageFORMERR);
// OPT RR of a non root name
message.clear();
EXPECT_THROW(factoryFromFile(message, "testdata/message_fromWire6"),
DNSMessageFORMERR);
// Compressed owner name of OPT RR points to a root name.
// Not necessarily bogus, but very unusual and mostly pathological.
// We accept it, but is it okay?
message.clear();
EXPECT_NO_THROW(factoryFromFile(message, "testdata/message_fromWire7"));
}
TEST_F(MessageTest, toWire)
{
message.setQid(0x1035);
......
......@@ -583,6 +583,11 @@ TEST_F(NameTest, gthan)
EXPECT_FALSE(small_name > large_name);
}
TEST_F(NameTest, constants)
{
EXPECT_EQ(Name("."), Name::ROOT_NAME());
}
// test operator<<. We simply confirm it appends the result of toText().
TEST_F(NameTest, LeftShiftOperator)
{
......
#
# A simple DNS query message with a valid EDNS0 OPT RR
# ID = 0x1035
# QR=0 (query), Opcode=0, RD=1 (other fields are 0)
# QDCOUNT=1, ANCOUNT=0, NSCOUNT=0, ARCOUNT=1
# Question: test.example.com. IN A
1035 0100
0001 0000 0000 0001
#(4) t e s t (7) e x a m p l e (3) c o m .
04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
0001 0001
# EDNS0 OPT RR
# owner name: "."
00
# TYPE: OPT (41 = 0x29)
00 29
# CLASS (= UDP size): 4096
1000
# TTL (extended RCODE and flags): RCODE=0, version=0, flags=DO
0000 8000
# RDLEN = 0
0000
#
# A simple DNS query message with a valid EDNS0 OPT RR, DO bit off
# ID = 0x1035
# QR=0 (query), Opcode=0, RD=1 (other fields are 0)
# QDCOUNT=1, ANCOUNT=0, NSCOUNT=0, ARCOUNT=1
# Question: test.example.com. IN A
1035 0100
0001 0000 0000 0001
#(4) t e s t (7) e x a m p l e (3) c o m .
04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
0001 0001
# EDNS0 OPT RR
# owner name: "."
00
# TYPE: OPT (41 = 0x29)
00 29
# CLASS (= UDP size): 4096
1000
# TTL (extended RCODE and flags): RCODE=0, version=0, flags=0
0000 0000
# RDLEN = 0
0000
#
# A simple DNS query message with a bogus EDNS0 OPT RR (included in the
# answer section)
# ID = 0x1035
# QR=0 (query), Opcode=0, RD=1 (other fields are 0)
# QDCOUNT=1, ANCOUNT=1, NSCOUNT=0, ARCOUNT=0
# Question: test.example.com. IN A
1035 0100
0001 0001 0000 0000
#(4) t e s t (7) e x a m p l e (3) c o m .
04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
0001 0001
# EDNS0 OPT RR
# owner name: "."
00
# TYPE: OPT (41 = 0x29)
00 29
# CLASS (= UDP size): 4096
1000
# TTL (extended RCODE and flags): RCODE=0, version=0, flags=DO
0000 8000
# RDLEN = 0
0000
#
# A simple DNS query message with multiple EDNS0 OPT RRs (bogus)
# ID = 0x1035
# QR=0 (query), Opcode=0, RD=1 (other fields are 0)
# QDCOUNT=1, ANCOUNT=0, NSCOUNT=0, ARCOUNT=2
# Question: test.example.com. IN A
1035 0100
0001 0000 0000 0002
#(4) t e s t (7) e x a m p l e (3) c o m .
04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
0001 0001
# EDNS0 OPT RR (1st)
# owner name: "."
00
# TYPE: OPT (41 = 0x29)
00 29
# CLASS (= UDP size): 4096
1000
# TTL (extended RCODE and flags): RCODE=0, version=0, flags=DO
0000 8000
# RDLEN = 0
0000
# EDNS0 OPT RR (2nd)
# owner name: "."
00
# TYPE: OPT (41 = 0x29)
00 29
# CLASS (= UDP size): 4096
1000
# TTL (extended RCODE and flags): RCODE=0, version=0, flags=DO
0000 8000
# RDLEN = 0
0000
#
# A simple DNS query message with EDNS0 OPT RRs of non root name (bogus)
# ID = 0x1035
# QR=0 (query), Opcode=0, RD=1 (other fields are 0)
# QDCOUNT=1, ANCOUNT=0, NSCOUNT=0, ARCOUNT=1
1035 0100
0001 0000 0000 0001
# Question: test.example.com. IN A
#(4) t e s t (7) e x a m p l e (3) c o m .
04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
0001 0001
# EDNS0 OPT RR
# owner name: "example.com"
#(7) e x a m p l e (3) c o m .
07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
# TYPE: OPT (41 = 0x29)
00 29
# CLASS (= UDP size): 4096
1000
# TTL (extended RCODE and flags): RCODE=0, version=0, flags=DO
0000 8000
# RDLEN = 0
0000
#
# A simple DNS query message with EDNS0 OPT RRs of compressed owner name
# pointing to root (is this bogus?)
# ID = 0x1035
# QR=0 (query), Opcode=0, RD=1 (other fields are 0)
# QDCOUNT=1, ANCOUNT=0, NSCOUNT=0, ARCOUNT=1
#0 1 2 3
1035 0100
#4 5 6 7 8 9 10 1
0001 0000 0000 0001
# Question: test.example.com. IN A
# 2 3 4 5 6 7 8 9 20 1 2 3 4 5 6 7 8 9
#(4) t e s t (7) e x a m p l e (3) c o m .
04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
0001 0001
# EDNS0 OPT RR
# owner name: "example.com"
# pointer = 29 (end of question section)
c0 1d
# TYPE: OPT (41 = 0x29)
00 29
# CLASS (= UDP size): 4096
1000
# TTL (extended RCODE and flags): RCODE=0, version=0, flags=DO
0000 8000
# RDLEN = 0
0000
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment