Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/test/seeder_tests.cpp
// Copyright (c) 2019 The Bitcoin developers | // Copyright (c) 2019 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#define BOOST_TEST_MODULE Bitcoin Seeder Test Suite | #define BOOST_TEST_MODULE Bitcoin Seeder Test Suite | ||||
#include <seeder/dns.h> | |||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
#include <array> | |||||
#include <iomanip> | |||||
#include <iostream> | |||||
#include <sstream> | |||||
#include <string> | |||||
BOOST_AUTO_TEST_SUITE(seeder) | BOOST_AUTO_TEST_SUITE(seeder) | ||||
BOOST_AUTO_TEST_CASE(parse_name_simple) { | static const int BUFFER_LENGTH = 512; | ||||
BOOST_CHECK_EQUAL(true, true); | static const int QUALIFIER_NAME_BUFFER_LENGTH = 256; | ||||
static const int SIZE_OF_QUESTION_TYPE = 2; | |||||
static const int SIZE_OF_QUESTION_CLASS = 2; | |||||
static const uint16_t QUESTION_CLASS = 1; | |||||
static const uint16_t QUESTION_TYPE = 1; | |||||
jasonbcox: Although these are part of a question, the actual name of these fields is Query Class, Query… | |||||
static const uint8_t END_OF_NAME_FIELD = 0; | |||||
static const size_t MAX_LABEL_LENGTH = 63; | |||||
// Builds dummy DNS query message | |||||
std::array<uint8_t, BUFFER_LENGTH> | |||||
CreateDNSQuestion(const std::string &qualifierName) { | |||||
std::stringstream querryhex; | |||||
querryhex.clear(); | |||||
querryhex << std::hex << std::setfill('0'); | |||||
// Build the DNS message question section | |||||
uint8_t i = 0; | |||||
uint8_t lastPeriod = 0; | |||||
while (i < qualifierName.size()) { | |||||
if (qualifierName[i] == '.') { | |||||
uint8_t labelLength = i - lastPeriod; | |||||
querryhex << labelLength; | |||||
while (lastPeriod < i) { | |||||
querryhex << qualifierName[lastPeriod]; | |||||
lastPeriod++; | |||||
} | |||||
lastPeriod = i + 1; | |||||
} | |||||
i++; | |||||
} | |||||
uint8_t labelLength = i - lastPeriod; | |||||
querryhex << labelLength; | |||||
while (lastPeriod < i) { | |||||
querryhex << qualifierName[lastPeriod]; | |||||
lastPeriod++; | |||||
} | |||||
// End of name field | |||||
querryhex << END_OF_NAME_FIELD; | |||||
// QTYPE = A query | |||||
querryhex << QUESTION_TYPE; | |||||
// QCLASS = IN | |||||
jasonbcoxUnsubmitted Not Done Inline ActionsThese types of comments are more appropriate with the declaration of the query type, etc. jasonbcox: These types of comments are more appropriate with the declaration of the query type, etc. | |||||
querryhex << QUESTION_CLASS; | |||||
std::array<uint8_t, BUFFER_LENGTH> messageBuffer; | |||||
messageBuffer.fill(0); | |||||
querryhex >> std::hex >> messageBuffer.data(); | |||||
return messageBuffer; | |||||
} | |||||
BOOST_AUTO_TEST_CASE(parse_name_happy_path) { | |||||
const std::string messageQualifierName = "www.mydomain.com"; | |||||
std::array<uint8_t, BUFFER_LENGTH> dnsMessage = | |||||
CreateDNSQuestion(messageQualifierName); | |||||
std::array<char, QUALIFIER_NAME_BUFFER_LENGTH> qualifierName; | |||||
qualifierName.fill(0); | |||||
size_t writeBufferSize = QUALIFIER_NAME_BUFFER_LENGTH; | |||||
const uint8_t *messageBegin = dnsMessage.data(); | |||||
// +1 for the last octet ending the field name | |||||
const uint8_t *messageEnd = dnsMessage.data() + | |||||
messageQualifierName.size() + 1 + | |||||
SIZE_OF_QUESTION_TYPE + SIZE_OF_QUESTION_CLASS; | |||||
int ret = parse_name(&messageBegin, messageEnd, dnsMessage.data(), | |||||
qualifierName.data(), writeBufferSize); | |||||
BOOST_CHECK_EQUAL(ret, 0); | |||||
BOOST_CHECK_EQUAL(qualifierName.data(), messageQualifierName); | |||||
} | |||||
// Test for insufficient output buffer size | |||||
BOOST_AUTO_TEST_CASE(parse_name_insufficient_output_buffer_size) { | |||||
const std::string messageQualifierName = "www.mydomain.com"; | |||||
std::array<uint8_t, BUFFER_LENGTH> dnsMessage = | |||||
CreateDNSQuestion(messageQualifierName); | |||||
std::array<char, QUALIFIER_NAME_BUFFER_LENGTH> qualifierName; | |||||
qualifierName.fill(0); | |||||
const uint8_t *messageBegin = dnsMessage.data(); | |||||
// +1 for the last octet ending the field name | |||||
const uint8_t *messageEnd = dnsMessage.data() + | |||||
messageQualifierName.size() + 1 + | |||||
SIZE_OF_QUESTION_TYPE + SIZE_OF_QUESTION_CLASS; | |||||
// The size of the buffer being written to is 1 octect too small | |||||
int ret = parse_name(&messageBegin, messageEnd, dnsMessage.data(), | |||||
qualifierName.data(), messageQualifierName.size()); | |||||
BOOST_CHECK_EQUAL(ret, -2); | |||||
BOOST_CHECK_EQUAL( | |||||
qualifierName.data(), | |||||
messageQualifierName.substr(0, messageQualifierName.size() - 1)); | |||||
} | |||||
// Test for premature end of input buffer | |||||
BOOST_AUTO_TEST_CASE(parse_name_premature_end_of_input_buffer) { | |||||
const std::string messageQualifierName = "www.mydomain.com"; | |||||
std::array<uint8_t, BUFFER_LENGTH> dnsMessage = | |||||
CreateDNSQuestion(messageQualifierName); | |||||
std::array<char, QUALIFIER_NAME_BUFFER_LENGTH> qualifierName; | |||||
qualifierName.fill(0); | |||||
size_t writeBufferSize = QUALIFIER_NAME_BUFFER_LENGTH; | |||||
const uint8_t *messageBegin = dnsMessage.data(); | |||||
// The end index pointer for the DNS message buffer passed is located two | |||||
// octets away from the beginning | |||||
int ret = parse_name(&messageBegin, messageBegin + 2, dnsMessage.data(), | |||||
qualifierName.data(), writeBufferSize); | |||||
BOOST_CHECK_EQUAL(ret, -1); | |||||
BOOST_CHECK_EQUAL(qualifierName.data(), messageQualifierName.substr(0, 1)); | |||||
} | |||||
// Test for when name field is too long | |||||
BOOST_AUTO_TEST_CASE(parse_name_field_name_too_long) { | |||||
std::string tooLongQName = "www."; | |||||
for (size_t i = 0; i < MAX_LABEL_LENGTH + 1; i++) { | |||||
tooLongQName += 'a'; | |||||
} | |||||
tooLongQName += ".com"; | |||||
std::array<uint8_t, BUFFER_LENGTH> dnsMessage = | |||||
CreateDNSQuestion(tooLongQName); | |||||
std::array<char, QUALIFIER_NAME_BUFFER_LENGTH> qualifierName; | |||||
qualifierName.fill(0); | |||||
size_t writeBufferSize = QUALIFIER_NAME_BUFFER_LENGTH; | |||||
const uint8_t *messageBegin = dnsMessage.data(); | |||||
const uint8_t *messageEnd = dnsMessage.data() + tooLongQName.size() + 1 + | |||||
SIZE_OF_QUESTION_TYPE + SIZE_OF_QUESTION_CLASS; | |||||
int ret = parse_name(&messageBegin, messageEnd, dnsMessage.data(), | |||||
qualifierName.data(), writeBufferSize); | |||||
BOOST_CHECK_EQUAL(ret, -1); | |||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |
Although these are part of a question, the actual name of these fields is Query Class, Query Type and Query Name. See the RFC: https://tools.ietf.org/html/rfc883