diff --git a/src/seeder/options.cpp b/src/seeder/options.cpp index f8b68133f..7d6e84c60 100644 --- a/src/seeder/options.cpp +++ b/src/seeder/options.cpp @@ -1,136 +1,156 @@ // Copyright (c) 2022 The Bitcoin 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 namespace seeder { int CDnsSeedOpts::ParseCommandLine(int argc, const char **argv) { assert(argsManager); std::string error; if (!argsManager->ParseParameters(argc, argv, error)) { tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error); return EXIT_FAILURE; } if (HelpRequested(*argsManager) || argsManager->IsArgSet("-version")) { std::string strUsage = PACKAGE_NAME " Seeder " + FormatFullVersion() + "\n"; if (HelpRequested(*argsManager)) { strUsage += "\nUsage: bitcoin-seeder -host= -ns= " "[-mbox=] [-threads=] [-port=]\n\n" + argsManager->GetHelpMessage(); } tfm::format(std::cout, "%s", strUsage); return EXIT_SUCCESS; } nThreads = argsManager->GetArg("-threads", DEFAULT_NUM_THREADS); + if (nThreads <= 0) { + tfm::format( + std::cerr, + "Error: -threads argument expects only positive integers\n"); + return EXIT_FAILURE; + } + nPort = argsManager->GetArg("-port", DEFAULT_PORT); + if (nPort < 0 || nPort > 65535) { + tfm::format(std::cerr, "Error: -port argument expects only positive " + "integers in the range 0 - 65535\n"); + return EXIT_FAILURE; + } + nDnsThreads = argsManager->GetArg("-dnsthreads", DEFAULT_NUM_DNS_THREADS); + if (nDnsThreads <= 0) { + tfm::format( + std::cerr, + "Error: -dnsthreads argument expects only positive integers\n"); + return EXIT_FAILURE; + } + fWipeBan = argsManager->GetBoolArg("-wipeban", DEFAULT_WIPE_BAN); fWipeIgnore = argsManager->GetBoolArg("-wipeignore", DEFAULT_WIPE_IGNORE); mbox = argsManager->GetArg("-mbox", DEFAULT_EMAIL); ns = argsManager->GetArg("-ns", DEFAULT_NAMESERVER); host = argsManager->GetArg("-host", DEFAULT_HOST); tor = argsManager->GetArg("-onion", DEFAULT_TOR_PROXY); ip_addr = argsManager->GetArg("-address", DEFAULT_LISTEN_ADDRESS); ipv4_proxy = argsManager->GetArg("-proxyipv4", DEFAULT_IPV4_PROXY); ipv6_proxy = argsManager->GetArg("-proxyipv6", DEFAULT_IPV6_PROXY); SelectParams(argsManager->GetChainName()); // Both IPv4 and IPv6 addresses are valid, but the listening address is // treated as IPv6 internally if (ip_addr.find(':') == std::string::npos) { ip_addr.insert(0, "::FFFF:"); } if (argsManager->IsArgSet("-filter")) { // Parse whitelist additions std::string flagString = argsManager->GetArg("-filter", ""); size_t flagstartpos = 0; while (flagstartpos < flagString.size()) { size_t flagendpos = flagString.find_first_of(',', flagstartpos); uint64_t flag = atoi64( flagString.substr(flagstartpos, (flagendpos - flagstartpos))); filter_whitelist.insert(flag); if (flagendpos == std::string::npos) { break; } flagstartpos = flagendpos + 1; } } if (filter_whitelist.empty()) { filter_whitelist.insert(NODE_NETWORK); filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); filter_whitelist.insert(NODE_NETWORK_LIMITED); filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_BLOOM); } return CONTINUE_EXECUTION; } void CDnsSeedOpts::SetupSeederArgs() { assert(argsManager); SetupHelpOptions(*argsManager); argsManager->AddArg( "-help-debug", "Show all debugging options (usage: --help -help-debug)", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); SetupChainParamsBaseOptions(*argsManager); argsManager->AddArg("-version", "Print version and exit", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsManager->AddArg("-host=", "Hostname of the DNS seed", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsManager->AddArg("-ns=", "Hostname of the nameserver", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsManager->AddArg("-mbox=", "E-Mail address reported in SOA records", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsManager->AddArg( "-threads=", strprintf("Number of crawlers to run in parallel (default: %d)", DEFAULT_NUM_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsManager->AddArg("-dnsthreads=", strprintf("Number of DNS server threads (default: %d)", DEFAULT_NUM_DNS_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsManager->AddArg("-address=
", strprintf("Address to listen on (default: '%s')", DEFAULT_LISTEN_ADDRESS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsManager->AddArg( "-port=", strprintf("UDP port to listen on (default: %d)", DEFAULT_PORT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsManager->AddArg("-onion=", "Tor proxy IP/Port", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsManager->AddArg("-overridednsseed", "If set, only use the specified DNS seed when " "querying for peer addresses via DNS lookup->", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsManager->AddArg("-proxyipv4=", "IPV4 SOCKS5 proxy IP/Port", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsManager->AddArg("-proxyipv6=", "IPV6 SOCKS5 proxy IP/Port", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsManager->AddArg("-filter=", "Allow these flag combinations as filters", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); argsManager->AddArg("-wipeban", "Wipe list of banned nodes", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsManager->AddArg("-wipeignore", "Wipe list of ignored nodes", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); } } // namespace seeder diff --git a/src/seeder/test/options_tests.cpp b/src/seeder/test/options_tests.cpp index 8ed9913b4..102cb9d40 100644 --- a/src/seeder/test/options_tests.cpp +++ b/src/seeder/test/options_tests.cpp @@ -1,41 +1,110 @@ // Copyright (c) 2022 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include +static const char *TEST_HOST = "-host=seeder.bitcoinabc.org"; +static const char *TEST_NAMESERVER = "-ns=localhost"; +static const char *TEST_EMAIL = "-mbox=email@bitcoinabc.org"; + class ArgsTestingSetup { public: ArgsManager argsManager; seeder::CDnsSeedOpts opts = seeder::CDnsSeedOpts(&argsManager); ArgsTestingSetup() { opts.SetupSeederArgs(); } }; BOOST_AUTO_TEST_SUITE(options_tests) BOOST_FIXTURE_TEST_CASE(options_defaults_test, ArgsTestingSetup) { const char *argv[] = {"ignored"}; BOOST_CHECK(opts.ParseCommandLine(1, argv) == seeder::CONTINUE_EXECUTION); BOOST_CHECK(opts.nPort == seeder::DEFAULT_PORT); BOOST_CHECK(opts.nThreads == seeder::DEFAULT_NUM_THREADS); BOOST_CHECK(opts.nDnsThreads == seeder::DEFAULT_NUM_DNS_THREADS); BOOST_CHECK(opts.fWipeBan == seeder::DEFAULT_WIPE_BAN); BOOST_CHECK(opts.fWipeIgnore == seeder::DEFAULT_WIPE_IGNORE); } BOOST_FIXTURE_TEST_CASE(options_basic_test, ArgsTestingSetup) { - const char *argv[] = {"ignored", "-host=seeder.bitcoinabc.org", - "-ns=localhost", "-mbox=email@bitcoinabc.org", + const char *argv[] = {"ignored", TEST_HOST, TEST_NAMESERVER, TEST_EMAIL, "-port=5555"}; BOOST_CHECK(opts.ParseCommandLine(5, argv) == seeder::CONTINUE_EXECUTION); BOOST_CHECK(opts.host == "seeder.bitcoinabc.org"); BOOST_CHECK(opts.ns == "localhost"); BOOST_CHECK(opts.mbox == "email@bitcoinabc.org"); BOOST_CHECK(opts.nPort == 5555); } +BOOST_FIXTURE_TEST_CASE(options_threads_test, ArgsTestingSetup) { + const std::map expectedResults = { + {-9999, EXIT_FAILURE}, + {-1, EXIT_FAILURE}, + {0, EXIT_FAILURE}, + {1, seeder::CONTINUE_EXECUTION}, + {seeder::DEFAULT_NUM_THREADS, seeder::CONTINUE_EXECUTION}, + {9999, seeder::CONTINUE_EXECUTION}}; + + for (const auto entry : expectedResults) { + const std::string testArg = "-threads=" + ToString(entry.first); + const char *argv[] = {"ignored", TEST_HOST, TEST_NAMESERVER, TEST_EMAIL, + testArg.c_str()}; + BOOST_CHECK(opts.ParseCommandLine(5, argv) == entry.second); + if (entry.second == seeder::CONTINUE_EXECUTION) { + BOOST_CHECK(opts.nThreads == entry.first); + } + } +} + +BOOST_FIXTURE_TEST_CASE(options_dns_threads_test, ArgsTestingSetup) { + const std::map expectedResults = { + {-9999, EXIT_FAILURE}, + {-1, EXIT_FAILURE}, + {0, EXIT_FAILURE}, + {1, seeder::CONTINUE_EXECUTION}, + {seeder::DEFAULT_NUM_DNS_THREADS, seeder::CONTINUE_EXECUTION}, + {9999, seeder::CONTINUE_EXECUTION}}; + + for (const auto entry : expectedResults) { + const std::string testArg = "-dnsthreads=" + ToString(entry.first); + const char *argv[] = {"ignored", TEST_HOST, TEST_NAMESERVER, TEST_EMAIL, + testArg.c_str()}; + BOOST_CHECK(opts.ParseCommandLine(5, argv) == entry.second); + if (entry.second == seeder::CONTINUE_EXECUTION) { + BOOST_CHECK(opts.nDnsThreads == entry.first); + } + } +} + +BOOST_FIXTURE_TEST_CASE(options_port_test, ArgsTestingSetup) { + const std::map expectedResults = { + {-9999, EXIT_FAILURE}, + {-1, EXIT_FAILURE}, + // Note: port 0 indicates to the kernel that a random unused port should + // be assigned + {0, seeder::CONTINUE_EXECUTION}, + {1, seeder::CONTINUE_EXECUTION}, + {seeder::DEFAULT_PORT, seeder::CONTINUE_EXECUTION}, + {53, seeder::CONTINUE_EXECUTION}, + {15353, seeder::CONTINUE_EXECUTION}, + {65535, seeder::CONTINUE_EXECUTION}, + {65536, EXIT_FAILURE}, + {999999, EXIT_FAILURE}}; + + for (const auto entry : expectedResults) { + const std::string testArg = "-port=" + ToString(entry.first); + const char *argv[] = {"ignored", TEST_HOST, TEST_NAMESERVER, TEST_EMAIL, + testArg.c_str()}; + BOOST_CHECK(opts.ParseCommandLine(5, argv) == entry.second); + if (entry.second == seeder::CONTINUE_EXECUTION) { + BOOST_CHECK(opts.nPort == entry.first); + } + } +} + BOOST_AUTO_TEST_SUITE_END()