diff --git a/src/seeder/test/seeder_tests.cpp b/src/seeder/test/seeder_tests.cpp --- a/src/seeder/test/seeder_tests.cpp +++ b/src/seeder/test/seeder_tests.cpp @@ -4,12 +4,112 @@ #define BOOST_TEST_MODULE Bitcoin Seeder Test Suite +#include + +#include +#include +#include + #include BOOST_AUTO_TEST_SUITE(seeder_tests) -BOOST_AUTO_TEST_CASE(test_stub) { - BOOST_CHECK_EQUAL(true, true); +static const int QUERY_NAME_BUFFER_LENGTH = 256; +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 +CreateDNSQuestionNameField(const std::string &queryName) { + std::vector 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 nameField = CreateDNSQuestionNameField(queryName); + std::array parsedQueryName; + 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); + + // 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)); + + // 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) { + std::string tooLongQName = "www."; + for (size_t i = 0; i < MAX_LABEL_LENGTH + 1; i++) { + tooLongQName += 'a'; + } + tooLongQName += ".com"; + std::vector nameField = CreateDNSQuestionNameField(tooLongQName); + std::array 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); + 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()