Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/main.cpp
// Copyright (c) 2017-2019 The Bitcoin developers | // Copyright (c) 2017-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. | ||||
#include <chainparams.h> | |||||
#include <chainparamsbase.h> | |||||
deadalnix: I don't think this is necessary. | |||||
#include <clientversion.h> | #include <clientversion.h> | ||||
#include <fs.h> | #include <fs.h> | ||||
#include <logging.h> | #include <logging.h> | ||||
#include <protocol.h> | #include <protocol.h> | ||||
#include <seeder/bitcoin.h> | #include <seeder/bitcoin.h> | ||||
#include <seeder/db.h> | #include <seeder/db.h> | ||||
#include <seeder/dns.h> | #include <seeder/dns.h> | ||||
#include <streams.h> | #include <streams.h> | ||||
#include <util/strencodings.h> | |||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <algorithm> | #include <algorithm> | ||||
#include <atomic> | #include <atomic> | ||||
#include <cinttypes> | #include <cinttypes> | ||||
#include <csignal> | #include <csignal> | ||||
#include <cstdlib> | #include <cstdlib> | ||||
#include <getopt.h> | |||||
#include <pthread.h> | #include <pthread.h> | ||||
const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr; | const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr; | ||||
static const int CONTINUE_EXECUTION = -1; | |||||
static const int DEFAULT_NUM_THREADS = 96; | static const int DEFAULT_NUM_THREADS = 96; | ||||
static const int DEFAULT_PORT = 53; | static const int DEFAULT_PORT = 53; | ||||
static const int DEFAULT_NUM_DNS_THREADS = 4; | static const int DEFAULT_NUM_DNS_THREADS = 4; | ||||
static const bool DEFAULT_TESTNET = false; | static const std::string DEFAULT_NETWORK = CBaseChainParams::MAIN; | ||||
deadalnixUnsubmitted Not Done Inline ActionsRemove deadalnix: Remove | |||||
static const bool DEFAULT_WIPE_BAN = false; | static const bool DEFAULT_WIPE_BAN = false; | ||||
static const bool DEFAULT_WIPE_IGNORE = false; | static const bool DEFAULT_WIPE_IGNORE = false; | ||||
static const std::string DEFAULT_EMAIL = ""; | static const std::string DEFAULT_EMAIL = ""; | ||||
static const std::string DEFAULT_NAMESERVER = ""; | static const std::string DEFAULT_NAMESERVER = ""; | ||||
static const std::string DEFAULT_HOST = ""; | static const std::string DEFAULT_HOST = ""; | ||||
static const std::string DEFAULT_TOR_PROXY = ""; | static const std::string DEFAULT_TOR_PROXY = ""; | ||||
static const std::string DEFAULT_IPV4_PROXY = ""; | static const std::string DEFAULT_IPV4_PROXY = ""; | ||||
static const std::string DEFAULT_IPV6_PROXY = ""; | static const std::string DEFAULT_IPV6_PROXY = ""; | ||||
class CDnsSeedOpts { | class CDnsSeedOpts { | ||||
public: | public: | ||||
int nThreads; | int nThreads; | ||||
int nPort; | int nPort; | ||||
int nDnsThreads; | int nDnsThreads; | ||||
int fUseTestNet; | std::string fNetwork; | ||||
deadalnixUnsubmitted Not Done Inline ActionsRemove deadalnix: Remove | |||||
int fWipeBan; | bool fWipeBan; | ||||
int fWipeIgnore; | bool fWipeIgnore; | ||||
std::string mbox; | std::string mbox; | ||||
std::string ns; | std::string ns; | ||||
std::string host; | std::string host; | ||||
std::string tor; | std::string tor; | ||||
std::string ipv4_proxy; | std::string ipv4_proxy; | ||||
std::string ipv6_proxy; | std::string ipv6_proxy; | ||||
std::set<uint64_t> filter_whitelist; | std::set<uint64_t> filter_whitelist; | ||||
CDnsSeedOpts() | CDnsSeedOpts() | ||||
: nThreads(DEFAULT_NUM_THREADS), nPort(DEFAULT_PORT), | : nThreads(DEFAULT_NUM_THREADS), nPort(DEFAULT_PORT), | ||||
nDnsThreads(DEFAULT_NUM_DNS_THREADS), fUseTestNet(DEFAULT_TESTNET), | nDnsThreads(DEFAULT_NUM_DNS_THREADS), fNetwork(DEFAULT_NETWORK), | ||||
fWipeBan(DEFAULT_WIPE_BAN), fWipeIgnore(DEFAULT_WIPE_IGNORE), | fWipeBan(DEFAULT_WIPE_BAN), fWipeIgnore(DEFAULT_WIPE_IGNORE), | ||||
mbox(DEFAULT_EMAIL), ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), | mbox(DEFAULT_EMAIL), ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), | ||||
tor(DEFAULT_TOR_PROXY), ipv4_proxy(DEFAULT_IPV4_PROXY), | tor(DEFAULT_TOR_PROXY), ipv4_proxy(DEFAULT_IPV4_PROXY), | ||||
ipv6_proxy(DEFAULT_IPV6_PROXY) {} | ipv6_proxy(DEFAULT_IPV6_PROXY) {} | ||||
void ParseCommandLine(int argc, char **argv) { | int ParseCommandLine(int argc, char **argv) { | ||||
static const char *help = | SetupSeederArgs(); | ||||
"Bitcoin-cash-seeder\n" | std::string error; | ||||
"Usage: %s -h <host> -n <ns> [-m <mbox>] [-t <threads>] [-p " | if (!gArgs.ParseParameters(argc, argv, error)) { | ||||
"<port>]\n" | fprintf(stderr, "Error parsing command line arguments: %s\n", | ||||
"\n" | error.c_str()); | ||||
"Options:\n" | return EXIT_FAILURE; | ||||
"-h <host> Hostname of the DNS seed\n" | } | ||||
"-n <ns> Hostname of the nameserver\n" | if (HelpRequested(gArgs)) { | ||||
"-m <mbox> E-Mail address reported in SOA records\n" | std::string strUsage = "Bitcoin-cash-seeder\nUsage: bitcoin-seeder " | ||||
"-t <threads> Number of crawlers to run in parallel (default " | "-host=<host> -ns=<ns> [-mbox=<mbox>] " | ||||
"96)\n" | "[-threads=<threads>] [-port=<port>]\n\n" + | ||||
"-d <threads> Number of DNS server threads (default 4)\n" | gArgs.GetHelpMessage(); | ||||
"-p <port> UDP port to listen on (default 53)\n" | |||||
"-o <ip:port> Tor proxy IP/Port\n" | fprintf(stdout, "%s", strUsage.c_str()); | ||||
"-i <ip:port> IPV4 SOCKS5 proxy IP/Port\n" | return EXIT_SUCCESS; | ||||
"-k <ip:port> IPV6 SOCKS5 proxy IP/Port\n" | } | ||||
"-w f1,f2,... Allow these flag combinations as filters\n" | |||||
"--testnet Use testnet\n" | nThreads = gArgs.GetArg("-threads", DEFAULT_NUM_THREADS); | ||||
"--wipeban Wipe list of banned nodes\n" | nPort = gArgs.GetArg("-port", DEFAULT_PORT); | ||||
"--wipeignore Wipe list of ignored nodes\n" | nDnsThreads = gArgs.GetArg("-dnsthreads", DEFAULT_NUM_DNS_THREADS); | ||||
"-?, --help Show this text\n" | fNetwork = gArgs.GetChainName(); | ||||
"\n"; | SelectParams(fNetwork); | ||||
bool showHelp = false; | if (fNetwork == CBaseChainParams::REGTEST) { | ||||
fprintf(stdout, "Seeder does not support use of %s.\n", | |||||
while (1) { | CBaseChainParams::REGTEST.c_str()); | ||||
static struct option long_options[] = { | return EXIT_FAILURE; | ||||
{"host", required_argument, 0, 'h'}, | } | ||||
deadalnixUnsubmitted Not Done Inline ActionsThe only reason you need this is because you are not using the chainparams. The solution is simple: use the chainparams. deadalnix: The only reason you need this is because you are not using the chainparams. The solution is… | |||||
{"ns", required_argument, 0, 'n'}, | fWipeBan = gArgs.GetBoolArg("-wipeban", DEFAULT_WIPE_BAN); | ||||
{"mbox", required_argument, 0, 'm'}, | fWipeIgnore = gArgs.GetBoolArg("-wipeignore", DEFAULT_WIPE_IGNORE); | ||||
{"threads", required_argument, 0, 't'}, | mbox = gArgs.GetArg("-mbox", DEFAULT_EMAIL); | ||||
{"dnsthreads", required_argument, 0, 'd'}, | ns = gArgs.GetArg("-ns", DEFAULT_NAMESERVER); | ||||
{"port", required_argument, 0, 'p'}, | host = gArgs.GetArg("-host", DEFAULT_HOST); | ||||
{"onion", required_argument, 0, 'o'}, | tor = gArgs.GetArg("-onion", DEFAULT_TOR_PROXY); | ||||
{"proxyipv4", required_argument, 0, 'i'}, | ipv4_proxy = gArgs.GetArg("-proxyipv4", DEFAULT_IPV4_PROXY); | ||||
{"proxyipv6", required_argument, 0, 'k'}, | ipv6_proxy = gArgs.GetArg("-proxyipv6", DEFAULT_IPV6_PROXY); | ||||
{"filter", required_argument, 0, 'w'}, | |||||
{"testnet", no_argument, &fUseTestNet, 1}, | if (gArgs.IsArgSet("-filter")) { | ||||
{"wipeban", no_argument, &fWipeBan, 1}, | // Parse whitelist additions | ||||
{"wipeignore", no_argument, &fWipeIgnore, 1}, | std::string flags = gArgs.GetArg("-filter", ""); | ||||
{"help", no_argument, 0, 'h'}, | size_t flagstartpos = 0; | ||||
{0, 0, 0, 0}}; | while (flagstartpos < flags.size()) { | ||||
int option_index = 0; | size_t flagendpos = flags.find_first_of(",", flagstartpos); | ||||
deadalnixUnsubmitted Not Done Inline ActionsYou did submit patches in the past about this. deadalnix: You did submit patches in the past about this. | |||||
int c = | uint64_t flag = atoi64( | ||||
getopt_long(argc, argv, "h:n:m:t:p:d:o:i:k:w:", long_options, | flags.substr(flagstartpos, (flagendpos - flagstartpos))); | ||||
&option_index); | filter_whitelist.insert(flag); | ||||
if (c == -1) break; | if (flagendpos == std::string::npos) { | ||||
switch (c) { | |||||
case 'h': { | |||||
host = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'm': { | |||||
mbox = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'n': { | |||||
ns = std::string(optarg); | |||||
break; | |||||
} | |||||
case 't': { | |||||
int n = strtol(optarg, nullptr, 10); | |||||
if (n > 0 && n < 1000) nThreads = n; | |||||
break; | |||||
} | |||||
case 'd': { | |||||
int n = strtol(optarg, nullptr, 10); | |||||
if (n > 0 && n < 1000) nDnsThreads = n; | |||||
break; | |||||
} | |||||
case 'p': { | |||||
int p = strtol(optarg, nullptr, 10); | |||||
if (p > 0 && p < 65536) nPort = p; | |||||
break; | |||||
} | |||||
case 'o': { | |||||
tor = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'i': { | |||||
ipv4_proxy = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'k': { | |||||
ipv6_proxy = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'w': { | |||||
char *ptr = optarg; | |||||
while (*ptr != 0) { | |||||
unsigned long l = strtoul(ptr, &ptr, 0); | |||||
if (*ptr == ',') { | |||||
ptr++; | |||||
} else if (*ptr != 0) { | |||||
break; | |||||
} | |||||
filter_whitelist.insert(l); | |||||
} | |||||
break; | |||||
} | |||||
case '?': { | |||||
showHelp = true; | |||||
break; | break; | ||||
} | } | ||||
flagstartpos = flagendpos + 1; | |||||
} | } | ||||
} | } | ||||
if (filter_whitelist.empty()) { | if (filter_whitelist.empty()) { | ||||
filter_whitelist.insert(NODE_NETWORK); | filter_whitelist.insert(NODE_NETWORK); | ||||
filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); | filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); | ||||
filter_whitelist.insert(NODE_NETWORK | NODE_XTHIN); | filter_whitelist.insert(NODE_NETWORK | NODE_XTHIN); | ||||
filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM | NODE_XTHIN); | filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM | NODE_XTHIN); | ||||
} | } | ||||
if (!host.empty() && ns.empty()) showHelp = true; | return CONTINUE_EXECUTION; | ||||
if (showHelp) fprintf(stderr, help, argv[0]); | } | ||||
private: | |||||
void SetupSeederArgs() { | |||||
gArgs.AddArg("-?", _("Print this help message and exit"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-host=<host>", _("Hostname of the DNS seed"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-ns=<ns>", _("Hostname of the nameserver"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-mbox=<mbox>", | |||||
_("E-Mail address reported in SOA records"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-threads=<threads>", | |||||
_("Number of crawlers to run in parallel (default 96)"), | |||||
false, OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-dnsthreads=<threads>", | |||||
_("Number of DNS server threads (default 4)"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-port=<port>", _("UDP port to listen on (default 53)"), | |||||
false, OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-onion=<ip:port>", _("Tor proxy IP/Port"), false, | |||||
OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-proxyipv4=<ip:port>", _("IPV4 SOCKS5 proxy IP/Port"), | |||||
false, OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-proxyipv6=<ip:port>", _("IPV6 SOCKS5 proxy IP/Port"), | |||||
false, OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-filter=<f1,f2,...>", | |||||
_("Allow these flag combinations as filters"), false, | |||||
OptionsCategory::OPTIONS); | |||||
SetupChainParamsBaseOptions(); | |||||
gArgs.AddArg("-wipeban", _("Wipe list of banned nodes"), false, | |||||
OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-wipeignore", _("Wipe list of ignored nodes"), false, | |||||
OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN); | |||||
gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN); | |||||
} | } | ||||
}; | }; | ||||
extern "C" { | extern "C" { | ||||
#include <seeder/dns.h> | #include <seeder/dns.h> | ||||
} | } | ||||
CAddrDb db; | CAddrDb db; | ||||
▲ Show 20 Lines • Show All 300 Lines • ▼ Show 20 Lines | |||||
int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||
// The logger dump everything on the console by default. | // The logger dump everything on the console by default. | ||||
GetLogger().m_print_to_console = true; | GetLogger().m_print_to_console = true; | ||||
signal(SIGPIPE, SIG_IGN); | signal(SIGPIPE, SIG_IGN); | ||||
setbuf(stdout, nullptr); | setbuf(stdout, nullptr); | ||||
CDnsSeedOpts opts; | CDnsSeedOpts opts; | ||||
opts.ParseCommandLine(argc, argv); | int parseResults = opts.ParseCommandLine(argc, argv); | ||||
if (parseResults != CONTINUE_EXECUTION) { | |||||
return parseResults; | |||||
} | |||||
fprintf(stdout, "Supporting whitelisted filters: "); | fprintf(stdout, "Supporting whitelisted filters: "); | ||||
for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin(); | for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin(); | ||||
it != opts.filter_whitelist.end(); it++) { | it != opts.filter_whitelist.end(); it++) { | ||||
if (it != opts.filter_whitelist.begin()) { | if (it != opts.filter_whitelist.begin()) { | ||||
fprintf(stdout, ","); | fprintf(stdout, ","); | ||||
} | } | ||||
fprintf(stdout, "0x%lx", (unsigned long)*it); | fprintf(stdout, "0x%lx", (unsigned long)*it); | ||||
} | } | ||||
Show All 18 Lines | if (!opts.ipv6_proxy.empty()) { | ||||
CService service(LookupNumeric(opts.ipv6_proxy.c_str(), 9050)); | CService service(LookupNumeric(opts.ipv6_proxy.c_str(), 9050)); | ||||
if (service.IsValid()) { | if (service.IsValid()) { | ||||
fprintf(stdout, "Using IPv6 proxy at %s\n", | fprintf(stdout, "Using IPv6 proxy at %s\n", | ||||
service.ToStringIPPort().c_str()); | service.ToStringIPPort().c_str()); | ||||
SetProxy(NET_IPV6, proxyType(service)); | SetProxy(NET_IPV6, proxyType(service)); | ||||
} | } | ||||
} | } | ||||
bool fDNS = true; | bool fDNS = true; | ||||
if (opts.fUseTestNet) { | fprintf(stdout, "Using %s.\n", opts.fNetwork.c_str()); | ||||
fprintf(stdout, "Using testnet.\n"); | if (opts.fNetwork == CBaseChainParams::TESTNET) { | ||||
netMagic[0] = 0xf4; | netMagic[0] = 0xf4; | ||||
netMagic[1] = 0xe5; | netMagic[1] = 0xe5; | ||||
netMagic[2] = 0xf3; | netMagic[2] = 0xf3; | ||||
netMagic[3] = 0xf4; | netMagic[3] = 0xf4; | ||||
seeds = testnet_seeds; | seeds = testnet_seeds; | ||||
fTestNet = true; | fTestNet = true; | ||||
deadalnixUnsubmitted Not Done Inline ActionsAll these data can be retrieved from the chainparams. Bonus point: you get regtest support for free. You could easily get rid of GetDefaultPort, GetRequireHeight, fTestNet in subsequent patches. You could also delegate the seeds to the generated seeds in the chainparams and so on. deadalnix: All these data can be retrieved from the chainparams. Bonus point: you get regtest support for… | |||||
} | } | ||||
if (opts.ns.empty()) { | if (opts.ns.empty()) { | ||||
fprintf(stdout, "No nameserver set. Not starting DNS server.\n"); | fprintf(stdout, "No nameserver set. Not starting DNS server.\n"); | ||||
fDNS = false; | fDNS = false; | ||||
} | } | ||||
if (fDNS && opts.host.empty()) { | if (fDNS && opts.host.empty()) { | ||||
fprintf(stderr, "No hostname set. Please use -h.\n"); | fprintf(stderr, "No hostname set. Please use -h.\n"); | ||||
exit(1); | exit(1); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | for (int i = 0; i < opts.nThreads; i++) { | ||||
pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); | pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); | ||||
} | } | ||||
pthread_attr_destroy(&attr_crawler); | pthread_attr_destroy(&attr_crawler); | ||||
fprintf(stdout, "done\n"); | fprintf(stdout, "done\n"); | ||||
pthread_create(&threadStats, nullptr, ThreadStats, nullptr); | pthread_create(&threadStats, nullptr, ThreadStats, nullptr); | ||||
pthread_create(&threadDump, nullptr, ThreadDumper, nullptr); | pthread_create(&threadDump, nullptr, ThreadDumper, nullptr); | ||||
void *res; | void *res; | ||||
pthread_join(threadDump, &res); | pthread_join(threadDump, &res); | ||||
return 0; | return EXIT_SUCCESS; | ||||
} | } |
I don't think this is necessary.