diff --git a/src/seeder/dns.h b/src/seeder/dns.h --- a/src/seeder/dns.h +++ b/src/seeder/dns.h @@ -34,12 +34,17 @@ uint64_t nRequests; }; -// 0: ok -// -1: premature end of input, forward reference, label > MAX_LABEL_LENGTH, -// invalid character -// -2: insufficient space in output -int parse_name(const uint8_t **inpos, const uint8_t *inend, - const uint8_t *inbuf, char *buf, size_t bufsize); +enum class ParseNameStatus { + OK, + // Premature end of input, forward reference, component > 63 char, invalid + // character + InputError, + // Insufficient space in output + OutputBufferError, +}; + +ParseNameStatus parse_name(const uint8_t **inpos, const uint8_t *inend, + const uint8_t *inbuf, char *buf, size_t bufsize); int dnsserver(dns_opt_t *opt); diff --git a/src/seeder/dns.cpp b/src/seeder/dns.cpp --- a/src/seeder/dns.cpp +++ b/src/seeder/dns.cpp @@ -62,27 +62,27 @@ REFUSED = 5, }; -int parse_name(const uint8_t **inpos, const uint8_t *inend, - const uint8_t *inbuf, char *buf, size_t bufsize) { +ParseNameStatus parse_name(const uint8_t **inpos, const uint8_t *inend, + const uint8_t *inbuf, char *buf, size_t bufsize) { if (bufsize == 0) { - return -2; + return ParseNameStatus::OutputBufferError; } size_t bufused = 0; int init = 1; do { if (*inpos == inend) { - return -1; + return ParseNameStatus::InputError; } // read length of next component int octet = *((*inpos)++); if (octet == 0) { buf[bufused] = 0; - return 0; + return ParseNameStatus::OK; } // add dot in output if (!init) { if (bufused == bufsize - 1) { - return -2; + return ParseNameStatus::OutputBufferError; } buf[bufused++] = '.'; } else { @@ -91,36 +91,36 @@ // handle references if ((octet & 0xC0) == 0xC0) { if (*inpos == inend) { - return -1; + return ParseNameStatus::InputError; } int ref = ((octet - 0xC0) << 8) + *((*inpos)++); if (ref < 0 || ref >= (*inpos) - inbuf - 2) { - return -1; + return ParseNameStatus::InputError; } const uint8_t *newbuf = inbuf + ref; return parse_name(&newbuf, (*inpos) - 2, inbuf, buf + bufused, bufsize - bufused); } if (octet > MAX_LABEL_LENGTH) { - return -1; + return ParseNameStatus::InputError; } // The maximum size of a query name is 255. The buffer must have // room for the null-character at the end of the buffer after writing // the label. if (octet + bufused > MAX_QUERY_NAME_LENGTH) { - return -1; + return ParseNameStatus::InputError; } // copy label while (octet) { if (*inpos == inend) { - return -1; + return ParseNameStatus::InputError; } if (bufused == bufsize - 1) { - return -2; + return ParseNameStatus::OutputBufferError; } int c = *((*inpos)++); if (c == '.') { - return -1; + return ParseNameStatus::InputError; } octet--; buf[bufused++] = c; @@ -424,14 +424,14 @@ const uint8_t *inend = inbuf + insize; char name[MAX_QUERY_NAME_BUFFER_LENGTH]; int offset = inpos - inbuf; - int ret = parse_name(&inpos, inend, inbuf, name, - MAX_QUERY_NAME_BUFFER_LENGTH); - if (ret == -1) { + ParseNameStatus ret = parse_name(&inpos, inend, inbuf, name, + MAX_QUERY_NAME_BUFFER_LENGTH); + if (ret == ParseNameStatus::InputError) { responseCode = DNSResponseCode::FORMAT_ERROR; goto error; } - if (ret == -2) { + if (ret == ParseNameStatus::OutputBufferError) { responseCode = DNSResponseCode::REFUSED; goto error; } diff --git a/src/seeder/test/dns_tests.cpp b/src/seeder/test/dns_tests.cpp --- a/src/seeder/test/dns_tests.cpp +++ b/src/seeder/test/dns_tests.cpp @@ -3,12 +3,19 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include +#include #include #include #include +std::ostream &operator<<(std::ostream &os, const ParseNameStatus &status) { + os << to_integral(status); + return os; +} + BOOST_AUTO_TEST_SUITE(dns_tests) static const uint8_t END_OF_NAME_FIELD = 0; @@ -50,11 +57,11 @@ nameFieldEndIndex++) { std::vector parsedQueryName(MAX_QUERY_NAME_BUFFER_LENGTH, 0); const uint8_t *nameFieldBegin = nameField.data(); - int ret = parse_name( + ParseNameStatus ret = parse_name( &nameFieldBegin, nameFieldBegin + nameFieldEndIndex, nameField.data(), parsedQueryName.data(), parsedQueryName.size()); - BOOST_CHECK(ret != 0); + BOOST_CHECK(ret != ParseNameStatus::OK); } // Test when the buffer size is too small @@ -62,10 +69,10 @@ while (outputBufferSize <= queryName.size()) { std::vector parsedQueryName(outputBufferSize, 0); const uint8_t *nameFieldBegin = nameField.data(); - int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameField.size(), - nameField.data(), parsedQueryName.data(), - parsedQueryName.size()); - BOOST_CHECK(ret != 0); + ParseNameStatus ret = parse_name( + &nameFieldBegin, nameFieldBegin + nameField.size(), + nameField.data(), parsedQueryName.data(), parsedQueryName.size()); + BOOST_CHECK(ret != ParseNameStatus::OK); outputBufferSize++; } @@ -73,25 +80,25 @@ while (outputBufferSize <= MAX_QUERY_NAME_BUFFER_LENGTH) { std::vector parsedQueryName(outputBufferSize, 0); const uint8_t *nameFieldBegin = nameField.data(); - int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameField.size(), - nameField.data(), parsedQueryName.data(), - parsedQueryName.size()); - BOOST_CHECK_EQUAL(ret, 0); + ParseNameStatus ret = parse_name( + &nameFieldBegin, nameFieldBegin + nameField.size(), + nameField.data(), parsedQueryName.data(), parsedQueryName.size()); + BOOST_CHECK_EQUAL(ret, ParseNameStatus::OK); BOOST_CHECK_EQUAL(parsedQueryName.data(), queryName); outputBufferSize++; } } static void CheckParseNameError( - const std::string &queryName, const int expectedError, + const std::string &queryName, const ParseNameStatus expectedError, const size_t &outputBufferSize = MAX_QUERY_NAME_BUFFER_LENGTH) { std::vector nameField = CreateDNSQuestionNameField(queryName); std::vector parsedQueryName(outputBufferSize, 0); const uint8_t *nameFieldBegin = nameField.data(); - int ret = parse_name(&nameFieldBegin, nameFieldBegin + nameField.size(), - nameField.data(), parsedQueryName.data(), - parsedQueryName.size()); + ParseNameStatus ret = parse_name( + &nameFieldBegin, nameFieldBegin + nameField.size(), nameField.data(), + parsedQueryName.data(), parsedQueryName.size()); BOOST_CHECK_EQUAL(ret, expectedError); } @@ -112,7 +119,8 @@ CheckParseName("www." + maxLengthLabel + ".com"); // Check that an oversized label causes an error - CheckParseNameError("www." + maxLengthLabel + "a.com", -1); + CheckParseNameError("www." + maxLengthLabel + "a.com", + ParseNameStatus::InputError); } BOOST_AUTO_TEST_CASE(parse_name_qname_length_tests) { @@ -131,7 +139,8 @@ overSizedQName.insert(overSizedQName.end() - 3, '.'); // Allocates an extra large buffer to guarantee an error is not caused by // the buffer size - CheckParseNameError(overSizedQName, -1, 2 * overSizedQName.size()); + CheckParseNameError(overSizedQName, ParseNameStatus::InputError, + 2 * overSizedQName.size()); } BOOST_AUTO_TEST_SUITE_END()