message_unittest.cc 10.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

// $Id$

17 18
#include <exceptions/exceptions.h>

19
#include <dns/buffer.h>
20
#include <dns/exceptions.h>
21 22 23 24 25 26 27
#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/question.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
#include <dns/rrttl.h>
#include <dns/rrtype.h>
28 29 30

#include <gtest/gtest.h>

31
#include <dns/tests/unittest_util.h>
32 33 34 35 36 37

using isc::UnitTestUtil;
using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;

JINMEI Tatuya's avatar
JINMEI Tatuya committed
38 39 40 41 42 43 44 45 46 47 48 49
//
// Note: we need more tests, including:
// parsing malformed headers
// more complete tests about parsing/rendering header flags, opcode, rcode, etc.
// tests for adding RRsets
// tests for RRset/Question iterators
// But, we'll ship with the current set of tests for now, partly because many
// of the above are covered as part of other tests, and partly due to time
// limitation.  We also expect to revisit the fundamental design of the Message
// class, at which point we'll also revise the tests including more cases.
//

50 51
const uint16_t Message::DEFAULT_MAX_UDPSIZE;

52 53 54
namespace {
class MessageTest : public ::testing::Test {
protected:
55 56 57 58 59
    MessageTest() : obuffer(0), renderer(obuffer),
                    message_parse(Message::PARSE),
                    message_render(Message::RENDER)
    {}
    
60 61 62
    static Question factoryFromFile(const char* datafile);
    OutputBuffer obuffer;
    MessageRenderer renderer;
63 64
    Message message_parse;
    Message message_render;
65 66 67
    static void factoryFromFile(Message& message, const char* datafile);
};

68 69
const Name test_name("test.example.com");

70
void
JINMEI Tatuya's avatar
JINMEI Tatuya committed
71
MessageTest::factoryFromFile(Message& message, const char* datafile) {
72 73 74 75 76 77 78
    std::vector<unsigned char> data;
    UnitTestUtil::readWireData(datafile, data);

    InputBuffer buffer(&data[0], data.size());
    message.fromWire(buffer);
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
79
TEST_F(MessageTest, RcodeConstruct) {
80 81 82 83 84 85 86 87 88
    // normal cases
    EXPECT_EQ(0, Rcode(0).getCode());
    EXPECT_EQ(0xfff, Rcode(0xfff).getCode()); // possible max code

    // should fail on attempt of construction with an out of range code
    EXPECT_THROW(Rcode(0x1000), isc::OutOfRange);
    EXPECT_THROW(Rcode(0xffff), isc::OutOfRange);
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
89
TEST_F(MessageTest, RcodeToText) {
90 91 92 93 94 95
    EXPECT_EQ("NOERROR", Rcode::NOERROR().toText());
    EXPECT_EQ("BADVERS", Rcode::BADVERS().toText());
    EXPECT_EQ("17", Rcode(Rcode::BADVERS().getCode() + 1).toText());
    EXPECT_EQ("4095", Rcode(Rcode(0xfff)).toText());
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
96 97

TEST_F(MessageTest, fromWire) {
98
    factoryFromFile(message_parse, "message_fromWire1");
99 100 101 102 103 104 105 106
    EXPECT_EQ(0x1035, message_parse.getQid());
    EXPECT_EQ(Opcode::QUERY(), message_parse.getOpcode());
    EXPECT_EQ(Rcode::NOERROR(), message_parse.getRcode());
    EXPECT_TRUE(message_parse.getHeaderFlag(MessageFlag::QR()));
    EXPECT_TRUE(message_parse.getHeaderFlag(MessageFlag::RD()));
    EXPECT_TRUE(message_parse.getHeaderFlag(MessageFlag::AA()));

    QuestionPtr q = *message_parse.beginQuestion();
107
    EXPECT_EQ(test_name, q->getName());
108 109
    EXPECT_EQ(RRType::A(), q->getType());
    EXPECT_EQ(RRClass::IN(), q->getClass());
110 111 112 113
    EXPECT_EQ(1, message_parse.getRRCount(Section::QUESTION()));
    EXPECT_EQ(2, message_parse.getRRCount(Section::ANSWER()));
    EXPECT_EQ(0, message_parse.getRRCount(Section::AUTHORITY()));
    EXPECT_EQ(0, message_parse.getRRCount(Section::ADDITIONAL()));
114

115
    RRsetPtr rrset = *message_parse.beginSection(Section::ANSWER());
116
    EXPECT_EQ(test_name, rrset->getName());
117 118 119 120 121 122 123 124 125 126 127 128 129
    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
    EXPECT_EQ(RRTTL(3600), rrset->getTTL());
    RdataIteratorPtr it = rrset->getRdataIterator();
    it->first();
    EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
    it->next();
    EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
    it->next();
    EXPECT_TRUE(it->isLast());
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
130
TEST_F(MessageTest, GetEDNS0DOBit) {
131
    // Without EDNS0, DNSSEC is considered to be unsupported.
132
    factoryFromFile(message_parse, "message_fromWire1");
133
    EXPECT_FALSE(message_parse.isDNSSECSupported());
134

135
    // If DO bit is on, DNSSEC is considered to be supported.
136
    message_parse.clear(Message::PARSE);
137
    factoryFromFile(message_parse, "message_fromWire2");
138
    EXPECT_TRUE(message_parse.isDNSSECSupported());
139

140
    // If DO bit is off, DNSSEC is considered to be unsupported.
141
    message_parse.clear(Message::PARSE);
142
    factoryFromFile(message_parse, "message_fromWire3");
143 144 145
    EXPECT_FALSE(message_parse.isDNSSECSupported());
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
146
TEST_F(MessageTest, SetEDNS0DOBit) {
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
    // By default, it's false, and we can enable/disable it.
    EXPECT_FALSE(message_render.isDNSSECSupported());
    message_render.setDNSSECSupported(true);
    EXPECT_TRUE(message_render.isDNSSECSupported());
    message_render.setDNSSECSupported(false);
    EXPECT_FALSE(message_render.isDNSSECSupported());

    // A message in the parse mode doesn't allow this flag to be set.
    EXPECT_THROW(message_parse.setDNSSECSupported(true),
                 InvalidMessageOperation);
    // Once converted to the render mode, it works as above
    message_parse.makeResponse();
    EXPECT_FALSE(message_parse.isDNSSECSupported());
    message_parse.setDNSSECSupported(true);
    EXPECT_TRUE(message_parse.isDNSSECSupported());
    message_parse.setDNSSECSupported(false);
    EXPECT_FALSE(message_parse.isDNSSECSupported());
164 165
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
166
TEST_F(MessageTest, GetEDNS0UDPSize) {
167
    // Without EDNS0, the default max UDP size is used.
168
    factoryFromFile(message_parse, "message_fromWire1");
169
    EXPECT_EQ(Message::DEFAULT_MAX_UDPSIZE, message_parse.getUDPSize());
170 171

    // If the size specified in EDNS0 > default max, use it.
172
    message_parse.clear(Message::PARSE);
173
    factoryFromFile(message_parse, "message_fromWire2");
174
    EXPECT_EQ(4096, message_parse.getUDPSize());
175 176

    // If the size specified in EDNS0 < default max, keep using the default.
177
    message_parse.clear(Message::PARSE);
178
    factoryFromFile(message_parse, "message_fromWire8");
179 180 181
    EXPECT_EQ(Message::DEFAULT_MAX_UDPSIZE, message_parse.getUDPSize());
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
182
TEST_F(MessageTest, SetEDNS0UDPSize) {
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    // The default size if unspecified
    EXPECT_EQ(Message::DEFAULT_MAX_UDPSIZE, message_render.getUDPSize());
    // A common buffer size with EDNS, should succeed
    message_render.setUDPSize(4096);
    EXPECT_EQ(4096, message_render.getUDPSize());
    // Unusual large value, but accepted
    message_render.setUDPSize(0xffff);
    EXPECT_EQ(0xffff, message_render.getUDPSize());
    // Too small is value is rejected
    EXPECT_THROW(message_render.setUDPSize(511), InvalidMessageUDPSize);

    // A message in the parse mode doesn't allow the set operation.
    EXPECT_THROW(message_parse.setUDPSize(4096), InvalidMessageOperation);
    // Once converted to the render mode, it works as above.
    message_parse.makeResponse();
    message_parse.setUDPSize(4096);
    EXPECT_EQ(4096, message_parse.getUDPSize());
    message_parse.setUDPSize(0xffff);
    EXPECT_EQ(0xffff, message_parse.getUDPSize());
    EXPECT_THROW(message_parse.setUDPSize(511), InvalidMessageUDPSize);
203 204
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
205
TEST_F(MessageTest, EDNS0ExtCode) {
206
    // Extended Rcode = BADVERS
207
    factoryFromFile(message_parse, "message_fromWire10");
208
    EXPECT_EQ(Rcode::BADVERS(), message_parse.getRcode());
209 210

    // Maximum extended Rcode
211
    message_parse.clear(Message::PARSE);
212
    factoryFromFile(message_parse, "message_fromWire11");
213
    EXPECT_EQ(0xfff, message_parse.getRcode().getCode());
214 215
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
216
TEST_F(MessageTest, BadEDNS0) {
217
    // OPT RR in the answer section
218
    EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire4"),
219 220
                 DNSMessageFORMERR);
    // multiple OPT RRs (in the additional section)
221
    message_parse.clear(Message::PARSE);
222
    EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire5"),
223 224
                 DNSMessageFORMERR);
    // OPT RR of a non root name
225
    message_parse.clear(Message::PARSE);
226
    EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire6"),
227 228 229 230
                 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?
231
    message_parse.clear(Message::PARSE);
232
    EXPECT_NO_THROW(factoryFromFile(message_parse, "message_fromWire7"));
233
    // Unsupported Version
234
    message_parse.clear(Message::PARSE);
235
    EXPECT_THROW(factoryFromFile(message_parse, "message_fromWire9"),
236
                 DNSMessageBADVERS);
237 238
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
239
TEST_F(MessageTest, toWire) {
240 241 242 243 244 245 246 247
    message_render.setQid(0x1035);
    message_render.setOpcode(Opcode::QUERY());
    message_render.setRcode(Rcode::NOERROR());
    message_render.setHeaderFlag(MessageFlag::QR());
    message_render.setHeaderFlag(MessageFlag::RD());
    message_render.setHeaderFlag(MessageFlag::AA());
    message_render.addQuestion(Question(Name("test.example.com"), RRClass::IN(),
                                        RRType::A()));
248 249 250 251
    RRsetPtr rrset = RRsetPtr(new RRset(Name("test.example.com"), RRClass::IN(),
                                        RRType::A(), RRTTL(3600)));
    rrset->addRdata(in::A("192.0.2.1"));
    rrset->addRdata(in::A("192.0.2.2"));
252
    message_render.addRRset(Section::ANSWER(), rrset);
253

254 255 256 257
    EXPECT_EQ(1, message_render.getRRCount(Section::QUESTION()));
    EXPECT_EQ(2, message_render.getRRCount(Section::ANSWER()));
    EXPECT_EQ(0, message_render.getRRCount(Section::AUTHORITY()));
    EXPECT_EQ(0, message_render.getRRCount(Section::ADDITIONAL()));
258

259
    message_render.toWire(renderer);
260
    vector<unsigned char> data;
261
    UnitTestUtil::readWireData("message_toWire1", data);
262 263 264 265
    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, obuffer.getData(),
                        obuffer.getLength(), &data[0], data.size());
}
}