diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -145,12 +145,20 @@ wallet/test/wallet_test_fixture.h endif +if BUILD_BITCOIN_SEEDER +BITCOIN_TESTS += \ + seeder/test/seeder_tests.cpp +endif + test_test_bitcoin_SOURCES = $(BITCOIN_TEST_SUITE) $(BITCOIN_TESTS) $(JSON_TEST_FILES) $(RAW_TEST_FILES) test_test_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(TESTDEFS) $(EVENT_CFLAGS) test_test_bitcoin_LDADD = if ENABLE_WALLET test_test_bitcoin_LDADD += $(LIBBITCOIN_WALLET) endif +if BUILD_BITCOIN_SEEDER +test_test_bitcoin_LDADD += $(LIBBITCOIN_SEEDER) +endif test_test_bitcoin_LDADD += $(LIBBITCOIN_SERVER) $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CONSENSUS) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) \ $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) $(BOOST_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIB) $(LIBSECP256K1) $(EVENT_LIBS) $(EVENT_PTHREADS_LIBS) diff --git a/src/seeder/test/seeder_tests.cpp b/src/seeder/test/seeder_tests.cpp new file mode 100644 --- /dev/null +++ b/src/seeder/test/seeder_tests.cpp @@ -0,0 +1,134 @@ +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include + +#include + +#include +#include +#include +#include + +BOOST_FIXTURE_TEST_SUITE(seeder_tests, BasicTestingSetup) + +const int BUFFER_LENGTH = 512; + +const int QNAME_BUFFER_LENGTH = 256; + +const int SIZE_OF_DNS_MESSAGE_HEADER = 12; + +const int SIZE_OF_QTYPE = 2; + +const int SIZE_OF_QCLASS = 2; + +// Builds dummy DNS query message +std::array CreateDNSMessage(const std::string &qname) { + std::stringstream querryhex; + querryhex.clear(); + querryhex << std::hex << std::setfill('0'); + // ID + querryhex << std::setw(2) << static_cast(0); + // QR to RD + querryhex << std::setw(1) << static_cast(128); + // RA to RCODE + querryhex << std::setw(1) << static_cast(0); + // QDCOUNT + querryhex << std::setw(2) << static_cast(1); + // ANCOUNT + querryhex << std::setw(2) << static_cast(0); + // NSCOUNT + querryhex << std::setw(2) << static_cast(0); + // ARCOUNT + querryhex << std::setw(2) << static_cast(0); + size_t i = 0; + size_t lastperiod = 0; + while (i < qname.size()) { + if (qname[i] == '.') { + querryhex << std::setw(1) << static_cast(i - lastperiod); + while (lastperiod < i) { + querryhex << std::setw(1) + << static_cast(qname[lastperiod]); + lastperiod++; + } + lastperiod = i + 1; + } + i++; + } + querryhex << std::setw(1) << static_cast(i - lastperiod); + while (lastperiod < i) { + querryhex << std::setw(1) << static_cast(qname[lastperiod]); + lastperiod++; + } + // End of name field + querryhex << std::setw(1) << static_cast(0); + + // QTYPE = A query + querryhex << std::setw(2) << static_cast(1); + // QCLASS = IN + querryhex << std::setw(2) << static_cast(1); + + std::array messageBuffer; + messageBuffer.fill(0); + querryhex >> std::hex >> messageBuffer.data(); + return messageBuffer; +} + +BOOST_AUTO_TEST_CASE(parse_name_simple) { + const std::string messageQName = "www.mydomain.com"; + std::array inbuf; + inbuf.fill(0); + inbuf = CreateDNSMessage(messageQName); + std::array qname; + qname.fill(0); + size_t insize = QNAME_BUFFER_LENGTH; + const uint8_t *inpos = inbuf.data() + SIZE_OF_DNS_MESSAGE_HEADER; + // +1 for the last octet ending the field name + const uint8_t *inend = inbuf.data() + SIZE_OF_DNS_MESSAGE_HEADER + + messageQName.size() + 1 + SIZE_OF_QTYPE + + SIZE_OF_QCLASS; + + int ret = parse_name(&inpos, inend, inbuf.data(), qname.data(), insize); + + BOOST_CHECK_EQUAL(ret, 0); + BOOST_CHECK_EQUAL(qname.data(), messageQName); + + // Test for insufficient output buffer size + qname.fill(0); + inpos = inbuf.data() + SIZE_OF_DNS_MESSAGE_HEADER; + ret = parse_name(&inpos, inend, inbuf.data(), qname.data(), + messageQName.size()); + BOOST_CHECK_EQUAL(ret, -2); + BOOST_CHECK_EQUAL(qname.data(), + messageQName.substr(0, messageQName.size() - 1)); + + // Test for premature end of input buffer + qname.fill(0); + inpos = inbuf.data() + SIZE_OF_DNS_MESSAGE_HEADER; + ret = parse_name(&inpos, inpos + 2, inbuf.data(), qname.data(), insize); + BOOST_CHECK_EQUAL(ret, -1); + BOOST_CHECK_EQUAL(qname.data(), messageQName.substr(0, 1)); + + // Test for when name field is too long + std::string longMessageQName = "www."; + for (size_t i = 0; i < 65; i++) { + longMessageQName += 'a'; + } + longMessageQName += ".com"; + qname.fill(0); + std::array longInbuf; + longInbuf.fill(0); + longInbuf = CreateDNSMessage(longMessageQName); + const uint8_t *longInpos = longInbuf.data() + SIZE_OF_DNS_MESSAGE_HEADER; + const uint8_t *longInend = longInbuf.data() + SIZE_OF_DNS_MESSAGE_HEADER + + longMessageQName.size() + 1 + SIZE_OF_QTYPE + + SIZE_OF_QCLASS; + ret = parse_name(&longInpos, longInend, longInbuf.data(), qname.data(), + insize); + BOOST_CHECK_EQUAL(ret, -1); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -178,3 +178,10 @@ ../wallet/test/coinselector_tests.cpp ) endif() + +if(BUILD_BITCOIN_SEEDER) + target_sources(test_bitcoin + PRIVATE + ../seeder/test/seeder_tests.cpp + ) +endif()