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 <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 <boost/algorithm/string.hpp> | |||||
deadalnix: Please don't add boost dependencies. | |||||
#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 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; | bool fWipeBan; | ||||
int fWipeBan; | bool fWipeIgnore; | ||||
int 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), fWipeBan(DEFAULT_WIPE_BAN), | ||||
fWipeBan(DEFAULT_WIPE_BAN), fWipeIgnore(DEFAULT_WIPE_IGNORE), | fWipeIgnore(DEFAULT_WIPE_IGNORE), mbox(DEFAULT_EMAIL), | ||||
mbox(DEFAULT_EMAIL), ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), | ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), tor(DEFAULT_TOR_PROXY), | ||||
tor(DEFAULT_TOR_PROXY), ipv4_proxy(DEFAULT_IPV4_PROXY), | ipv4_proxy(DEFAULT_IPV4_PROXY), ipv6_proxy(DEFAULT_IPV6_PROXY) {} | ||||
ipv6_proxy(DEFAULT_IPV6_PROXY) {} | |||||
int ParseCommandLine(int argc, char **argv) { | |||||
void ParseCommandLine(int argc, char **argv) { | SetupSeederArgs(); | ||||
static const char *help = | std::string error; | ||||
"Bitcoin-cash-seeder\n" | if (!gArgs.ParseParameters(argc, argv, error)) { | ||||
"Usage: %s -h <host> -n <ns> [-m <mbox>] [-t <threads>] [-p " | fprintf(stderr, "Error parsing command line arguments: %s\n", | ||||
"<port>]\n" | error.c_str()); | ||||
"\n" | return EXIT_FAILURE; | ||||
"Options:\n" | } | ||||
"-h <host> Hostname of the DNS seed\n" | if (HelpRequested(gArgs)) { | ||||
"-n <ns> Hostname of the nameserver\n" | std::string strUsage = "Bitcoin-cash-seeder\nUsage: bitcoin-seeder " | ||||
"-m <mbox> E-Mail address reported in SOA records\n" | "-host=<host> -ns=<ns> [-mbox=<mbox>] " | ||||
"-t <threads> Number of crawlers to run in parallel (default " | "[-threads=<threads>] [-port=<port>]\n\n" + | ||||
"96)\n" | gArgs.GetHelpMessage(); | ||||
"-d <threads> Number of DNS server threads (default 4)\n" | |||||
"-p <port> UDP port to listen on (default 53)\n" | fprintf(stdout, "%s", strUsage.c_str()); | ||||
"-o <ip:port> Tor proxy IP/Port\n" | return EXIT_SUCCESS; | ||||
"-i <ip:port> IPV4 SOCKS5 proxy IP/Port\n" | } | ||||
"-k <ip:port> IPV6 SOCKS5 proxy IP/Port\n" | |||||
"-w f1,f2,... Allow these flag combinations as filters\n" | nThreads = gArgs.GetArg("-threads", DEFAULT_NUM_THREADS); | ||||
"--testnet Use testnet\n" | nPort = gArgs.GetArg("-port", DEFAULT_PORT); | ||||
"--wipeban Wipe list of banned nodes\n" | nDnsThreads = gArgs.GetArg("-dnsthreads", DEFAULT_NUM_DNS_THREADS); | ||||
"--wipeignore Wipe list of ignored nodes\n" | fWipeBan = gArgs.GetBoolArg("-wipeban", DEFAULT_WIPE_BAN); | ||||
"-?, --help Show this text\n" | fWipeIgnore = gArgs.GetBoolArg("-wipeignore", DEFAULT_WIPE_IGNORE); | ||||
"\n"; | mbox = gArgs.GetArg("-mbox", DEFAULT_EMAIL); | ||||
bool showHelp = false; | ns = gArgs.GetArg("-ns", DEFAULT_NAMESERVER); | ||||
host = gArgs.GetArg("-host", DEFAULT_HOST); | |||||
while (1) { | tor = gArgs.GetArg("-onion", DEFAULT_TOR_PROXY); | ||||
static struct option long_options[] = { | ipv4_proxy = gArgs.GetArg("-proxyipv4", DEFAULT_IPV4_PROXY); | ||||
{"host", required_argument, 0, 'h'}, | ipv6_proxy = gArgs.GetArg("-proxyipv6", DEFAULT_IPV6_PROXY); | ||||
{"ns", required_argument, 0, 'n'}, | SelectParams(gArgs.GetChainName()); | ||||
{"mbox", required_argument, 0, 'm'}, | |||||
{"threads", required_argument, 0, 't'}, | if (gArgs.IsArgSet("-filter")) { | ||||
{"dnsthreads", required_argument, 0, 'd'}, | // Parse whitelist additions | ||||
{"port", required_argument, 0, 'p'}, | std::string flagString = gArgs.GetArg("-filter", ""); | ||||
{"onion", required_argument, 0, 'o'}, | std::vector<std::string> flags; | ||||
{"proxyipv4", required_argument, 0, 'i'}, | boost::algorithm::split(flags, flagString, | ||||
{"proxyipv6", required_argument, 0, 'k'}, | boost::algorithm::is_any_of(",")); | ||||
deadalnixUnsubmitted Not Done Inline ActionsThe problem was that you used string overload rather than char ones. You did two backport that fix these over the whole codebase so you should know. deadalnix: The problem was that you used string overload rather than char ones. You did two backport that… | |||||
{"filter", required_argument, 0, 'w'}, | for (const std::string &flag : flags) { | ||||
{"testnet", no_argument, &fUseTestNet, 1}, | filter_whitelist.insert(atoi64(flag)); | ||||
{"wipeban", no_argument, &fWipeBan, 1}, | |||||
{"wipeignore", no_argument, &fWipeIgnore, 1}, | |||||
{"help", no_argument, 0, 'h'}, | |||||
{0, 0, 0, 0}}; | |||||
int option_index = 0; | |||||
int c = | |||||
getopt_long(argc, argv, "h:n:m:t:p:d:o:i:k:w:", long_options, | |||||
&option_index); | |||||
if (c == -1) break; | |||||
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; | |||||
} | |||||
} | } | ||||
} | } | ||||
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); | |||||
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-debug", | |||||
_("Show all debugging options (usage: --help -help-debug)"), false, | |||||
OptionsCategory::DEBUG_TEST); | |||||
SetupChainParamsBaseOptions(); | |||||
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 266 Lines • ▼ Show 20 Lines | do { | ||||
stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, | stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, | ||||
stats.nBanned, (unsigned long long)requests, | stats.nBanned, (unsigned long long)requests, | ||||
(unsigned long long)queries); | (unsigned long long)queries); | ||||
Sleep(1000); | Sleep(1000); | ||||
} while (1); | } while (1); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
static const std::string mainnet_seeds[] = { | |||||
"seed.bitcoinabc.org", "seed-abc.bitcoinforks.org", | |||||
"seed.bitprim.org", "seed.deadalnix.me", | |||||
"seed.bchd.cash", ""}; | |||||
static const std::string testnet_seeds[] = { | |||||
"testnet-seed.bitcoinabc.org", "testnet-seed-abc.bitcoinforks.org", | |||||
"testnet-seed.bitprim.org", "testnet-seed.deadalnix.me", | |||||
"testnet-seed.bchd.cash", ""}; | |||||
static const std::string *seeds = mainnet_seeds; | |||||
const static unsigned int MAX_HOSTS_PER_SEED = 128; | const static unsigned int MAX_HOSTS_PER_SEED = 128; | ||||
extern "C" void *ThreadSeeder(void *) { | extern "C" void *ThreadSeeder(void *) { | ||||
do { | do { | ||||
for (int i = 0; seeds[i] != ""; i++) { | for (const std::string &seed : Params().DNSSeeds()) { | ||||
std::vector<CNetAddr> ips; | std::vector<CNetAddr> ips; | ||||
LookupHost(seeds[i].c_str(), ips, MAX_HOSTS_PER_SEED, true); | LookupHost(seed.c_str(), ips, MAX_HOSTS_PER_SEED, true); | ||||
for (auto &ip : ips) { | for (auto &ip : ips) { | ||||
db.Add(CAddress(CService(ip, GetDefaultPort()), ServiceFlags()), | db.Add(CAddress(CService(ip, GetDefaultPort()), ServiceFlags()), | ||||
true); | true); | ||||
} | } | ||||
} | } | ||||
Sleep(1800000); | Sleep(1800000); | ||||
} while (1); | } while (1); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
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", gArgs.GetChainName().c_str()); | ||||
fprintf(stdout, "Using testnet.\n"); | netMagic = Params().NetMagic(); | ||||
netMagic[0] = 0xf4; | |||||
netMagic[1] = 0xe5; | |||||
netMagic[2] = 0xf3; | |||||
netMagic[3] = 0xf4; | |||||
seeds = testnet_seeds; | |||||
fTestNet = true; | |||||
} | |||||
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); | return EXIT_FAILURE; | ||||
} | } | ||||
if (fDNS && opts.mbox.empty()) { | if (fDNS && opts.mbox.empty()) { | ||||
fprintf(stderr, "No e-mail address set. Please use -m.\n"); | fprintf(stderr, "No e-mail address set. Please use -m.\n"); | ||||
exit(1); | return EXIT_FAILURE; | ||||
} | } | ||||
FILE *f = fsbridge::fopen("dnsseed.dat", "r"); | FILE *f = fsbridge::fopen("dnsseed.dat", "r"); | ||||
if (f) { | if (f) { | ||||
fprintf(stdout, "Loading dnsseed.dat..."); | fprintf(stdout, "Loading dnsseed.dat..."); | ||||
CAutoFile cf(f, SER_DISK, CLIENT_VERSION); | CAutoFile cf(f, SER_DISK, CLIENT_VERSION); | ||||
cf >> db; | cf >> db; | ||||
if (opts.fWipeBan) { | if (opts.fWipeBan) { | ||||
db.banned.clear(); | db.banned.clear(); | ||||
Show All 31 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; | ||||
} | } |
Please don't add boost dependencies.