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 <array> | |||||
#include <string> | |||||
#include <vector> | |||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
BOOST_AUTO_TEST_SUITE(seeder_tests) | BOOST_AUTO_TEST_SUITE(seeder_tests) | ||||
BOOST_AUTO_TEST_CASE(test_stub) { | static const int QUERY_NAME_BUFFER_LENGTH = 256; | ||||
BOOST_CHECK_EQUAL(true, true); | static const uint8_t END_OF_NAME_FIELD = 0; | ||||
static const size_t MAX_LABEL_LENGTH = 63; | |||||
// Builds the question section of a DNS query | |||||
static std::vector<uint8_t> | |||||
CreateDNSQuestionNameField(const std::string &queryName) { | |||||
std::vector<uint8_t> nameField; | |||||
size_t i = 0; | |||||
size_t labelIndex = 0; | |||||
while (i < queryName.size()) { | |||||
if (queryName[i] == '.') { | |||||
// Push the length of the label and then the label | |||||
nameField.push_back(i - labelIndex); | |||||
while (labelIndex < i) { | |||||
nameField.push_back(queryName[labelIndex]); | |||||
labelIndex++; | |||||
} | |||||
labelIndex = i + 1; | |||||
} | |||||
i++; | |||||
} | |||||
// Push the length of the label and then the label | |||||
nameField.push_back(i - labelIndex); | |||||
while (labelIndex < i) { | |||||
nameField.push_back(queryName[labelIndex]); | |||||
labelIndex++; | |||||
} | |||||
nameField.push_back(END_OF_NAME_FIELD); | |||||
return nameField; | |||||
} | |||||
BOOST_AUTO_TEST_CASE(parse_name_simple) { | |||||
const std::string queryName = "www.mydomain.com"; | |||||
std::vector<uint8_t> nameField = CreateDNSQuestionNameField(queryName); | |||||
std::array<char, QUERY_NAME_BUFFER_LENGTH> parsedQueryName; | |||||
deadalnix: Is the result always zero terminated? And the zero always fit in the buffer?
There are no… | |||||
nakihitoAuthorUnsubmitted Done Inline ActionsWhen successful (return == 0), the result from parse_name() is a 0-terminated c-string. On failure (return != 0), it is a char array that is not 0-terminated. The 0 must be able to fit in the buffer. This is actually tested line 70-79. I have refined the comment on line 73 to better clarify. nakihito: When successful (return == 0), the result from `parse_name()` is a 0-terminated c-string. On… | |||||
parsedQueryName.fill(0); | |||||
const uint8_t *nameFieldBegin = nameField.data(); | |||||
const size_t nameFieldEndIndex = nameField.size(); | |||||
// nameFieldEndIndex should be equal to the number of alphanumeric | |||||
// characters in the query name, +1 for each label (each label length is 1 | |||||
// octet), +1 for the length of the END_NAME_FIELD octet. | |||||
assert(nameFieldEndIndex == queryName.size() + 2); | |||||
deadalnixUnsubmitted Not Done Inline ActionsBOOST_CHECK or BOOST_REQUIRE deadalnix: BOOST_CHECK or BOOST_REQUIRE | |||||
// Happy path | |||||
int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameFieldEndIndex, | |||||
nameField.data(), parsedQueryName.data(), | |||||
parsedQueryName.size()); | |||||
BOOST_CHECK_EQUAL(ret, 0); | |||||
BOOST_CHECK_EQUAL(parsedQueryName.data(), queryName); | |||||
// Test for insufficient output buffer size | |||||
parsedQueryName.fill(0); | |||||
nameFieldBegin = nameField.data(); | |||||
// The size of the buffer being written to is 1 octect too small | |||||
ret = | |||||
parse_name(&nameFieldBegin, nameFieldBegin + nameFieldEndIndex, | |||||
nameField.data(), parsedQueryName.data(), queryName.size()); | |||||
BOOST_CHECK_EQUAL(ret, -2); | |||||
BOOST_CHECK_EQUAL(parsedQueryName.data(), | |||||
queryName.substr(0, queryName.size() - 1)); | |||||
deadalnixUnsubmitted Not Done Inline ActionsI still have to play where is waldo here. Something in these 10 lines of code differs, I don't now what. deadalnix: I still have to play where is waldo here. Something in these 10 lines of code differs, I don't… | |||||
nakihitoAuthorUnsubmitted Done Inline ActionsThere's a comment on line 73 that specifies what is different. nakihito: There's a comment on line 73 that specifies what is different. | |||||
// Test for premature end of input buffer | |||||
parsedQueryName.fill(0); | |||||
nameFieldBegin = nameField.data(); | |||||
// The end index pointer for the DNS message buffer passed is located two | |||||
// octets away from the beginning | |||||
ret = parse_name(&nameFieldBegin, nameFieldBegin + 2, nameField.data(), | |||||
parsedQueryName.data(), parsedQueryName.size()); | |||||
BOOST_CHECK_EQUAL(ret, -1); | |||||
BOOST_CHECK_EQUAL(parsedQueryName.data(), queryName.substr(0, 1)); | |||||
} | |||||
// Test for when name field is too long | |||||
BOOST_AUTO_TEST_CASE(parse_name_field_name_too_long) { | |||||
deadalnixUnsubmitted Not Done Inline ActionsIf you want to test if the name is too long, then you want to check if shorter name pass, up to the maximum length, and then that the maximum length + 1 and more fails. deadalnix: If you want to test if the name is too long, then you want to check if shorter name pass, up to… | |||||
std::string tooLongQName = "www."; | |||||
for (size_t i = 0; i < MAX_LABEL_LENGTH + 1; i++) { | |||||
tooLongQName += 'a'; | |||||
} | |||||
tooLongQName += ".com"; | |||||
std::vector<uint8_t> nameField = CreateDNSQuestionNameField(tooLongQName); | |||||
std::array<char, QUERY_NAME_BUFFER_LENGTH> parsedQueryName; | |||||
parsedQueryName.fill(0); | |||||
const uint8_t *nameFieldBegin = nameField.data(); | |||||
size_t nameFieldEndIndex = nameField.size(); | |||||
// nameFieldEndIndex should be equal to the number of alphanumeric | |||||
// characters in the query name, +1 for each label (each label length is 1 | |||||
// octet), +1 for the length of the END_NAME_FIELD octet. | |||||
assert(nameFieldEndIndex == tooLongQName.size() + 2); | |||||
deadalnixUnsubmitted Not Done Inline ActionsThat is what BOOST_CHECK is for. deadalnix: That is what BOOST_CHECK is for. | |||||
int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameFieldEndIndex, | |||||
nameField.data(), parsedQueryName.data(), | |||||
QUERY_NAME_BUFFER_LENGTH); | |||||
BOOST_CHECK_EQUAL(ret, -1); | |||||
BOOST_CHECK_EQUAL(parsedQueryName.data(), tooLongQName.substr(0, 4)); | |||||
} | } | ||||
BOOST_AUTO_TEST_SUITE_END() | BOOST_AUTO_TEST_SUITE_END() |
Is the result always zero terminated? And the zero always fit in the buffer?
There are no checks for this, and frankly I do not know.