Multiple DNS threads
This commit is contained in:
parent
ca1ca62a8a
commit
54fb24d7c3
4 changed files with 114 additions and 64 deletions
8
Makefile
8
Makefile
|
@ -1,14 +1,10 @@
|
||||||
dnsseed: dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
dnsseed: dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
||||||
g++ -pthread -lcrypto -o dnsseed dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
g++ -pthread -lcrypto -o dnsseed dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
||||||
strip -s dnsseed
|
|
||||||
|
|
||||||
dnsseed.dbg: dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
|
||||||
g++ -pthread -lcrypto -o dnsseed.dbg dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
|
||||||
|
|
||||||
%.o: %.cpp bitcoin.h netbase.h protocol.h db.h serialize.h uint256.h util.h
|
%.o: %.cpp bitcoin.h netbase.h protocol.h db.h serialize.h uint256.h util.h
|
||||||
g++ -pthread -O3 -ggdb3 -march=nocona -Wno-invalid-offsetof -c -o $@ $<
|
g++ -pthread -O2 -ggdb3 -march=nocona -Wno-invalid-offsetof -c -o $@ $<
|
||||||
|
|
||||||
dns.o: dns.c
|
dns.o: dns.c
|
||||||
gcc -pthread -std=c99 -O3 -g0 -march=nocona dns.c -c -o dns.o
|
gcc -pthread -std=c99 -O2 -ggdb3 -march=nocona dns.c -c -o dns.o
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
|
|
38
dns.c
38
dns.c
|
@ -296,7 +296,7 @@ ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insi
|
||||||
// A records
|
// A records
|
||||||
if ((typ == TYPE_A || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
if ((typ == TYPE_A || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
||||||
struct in_addr addr[32];
|
struct in_addr addr[32];
|
||||||
int naddr = opt->cb(addr, 32, 1);
|
int naddr = opt->cb((void*)opt, addr, 32, 1);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (n < naddr) {
|
while (n < naddr) {
|
||||||
int ret = write_record_a(&outpos, outend - auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]);
|
int ret = write_record_a(&outpos, outend - auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]);
|
||||||
|
@ -333,27 +333,39 @@ error:
|
||||||
return 12;
|
return 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int listenSocket = -1;
|
||||||
|
|
||||||
int dnsserver(dns_opt_t *opt) {
|
int dnsserver(dns_opt_t *opt) {
|
||||||
struct sockaddr_in si_me, si_other;
|
struct sockaddr_in si_other;
|
||||||
socklen_t s, slen=sizeof(si_other);
|
int senderSocket = -1;
|
||||||
|
senderSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
if (senderSocket == -1)
|
||||||
|
return -3;
|
||||||
|
|
||||||
|
if (listenSocket == -1) {
|
||||||
|
struct sockaddr_in si_me;
|
||||||
|
if ((listenSocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
|
||||||
|
listenSocket = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset((char *) &si_me, 0, sizeof(si_me));
|
||||||
|
si_me.sin_family = AF_INET;
|
||||||
|
si_me.sin_port = htons(opt->port);
|
||||||
|
si_me.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
if (bind(listenSocket, (struct sockaddr*)&si_me, sizeof(si_me))==-1)
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
unsigned char inbuf[BUFLEN], outbuf[BUFLEN];
|
unsigned char inbuf[BUFLEN], outbuf[BUFLEN];
|
||||||
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
|
|
||||||
return -1;
|
|
||||||
memset((char *) &si_me, 0, sizeof(si_me));
|
|
||||||
si_me.sin_family = AF_INET;
|
|
||||||
si_me.sin_port = htons(opt->port);
|
|
||||||
si_me.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
if (bind(s, (struct sockaddr*)&si_me, sizeof(si_me))==-1)
|
|
||||||
return -2;
|
|
||||||
do {
|
do {
|
||||||
ssize_t insize = recvfrom(s, inbuf, BUFLEN, 0, (struct sockaddr*)&si_other, &slen);
|
socklen_t si_other_len = sizeof(si_other);
|
||||||
|
ssize_t insize = recvfrom(listenSocket, inbuf, BUFLEN, 0, (struct sockaddr*)&si_other, &si_other_len);
|
||||||
unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr;
|
unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr;
|
||||||
// printf("DNS: Request %llu from %i.%i.%i.%i:%i of %i bytes\n", (unsigned long long)(opt->nRequests), addr[0], addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
|
// printf("DNS: Request %llu from %i.%i.%i.%i:%i of %i bytes\n", (unsigned long long)(opt->nRequests), addr[0], addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
|
||||||
opt->nRequests++;
|
opt->nRequests++;
|
||||||
if (insize > 0) {
|
if (insize > 0) {
|
||||||
ssize_t ret = dnshandle(opt, inbuf, insize, outbuf);
|
ssize_t ret = dnshandle(opt, inbuf, insize, outbuf);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
sendto(s, outbuf, ret, 0, (struct sockaddr*)&si_other, slen);
|
sendto(listenSocket, outbuf, ret, 0, (struct sockaddr*)&si_other, sizeof(si_other));
|
||||||
}
|
}
|
||||||
} while(1);
|
} while(1);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
2
dns.h
2
dns.h
|
@ -10,7 +10,7 @@ typedef struct {
|
||||||
const char *host;
|
const char *host;
|
||||||
const char *ns;
|
const char *ns;
|
||||||
const char *mbox;
|
const char *mbox;
|
||||||
int (*cb)(struct in_addr *addr, int max, int ipv4only);
|
int (*cb)(void *opt, struct in_addr *addr, int max, int ipv4only);
|
||||||
// stats
|
// stats
|
||||||
uint64_t nRequests;
|
uint64_t nRequests;
|
||||||
} dns_opt_t;
|
} dns_opt_t;
|
||||||
|
|
130
main.cpp
130
main.cpp
|
@ -16,11 +16,12 @@ class CDnsSeedOpts {
|
||||||
public:
|
public:
|
||||||
int nThreads;
|
int nThreads;
|
||||||
int nPort;
|
int nPort;
|
||||||
|
int nDnsThreads;
|
||||||
const char *mbox;
|
const char *mbox;
|
||||||
const char *ns;
|
const char *ns;
|
||||||
const char *host;
|
const char *host;
|
||||||
|
|
||||||
CDnsSeedOpts() : nThreads(24), nPort(53), mbox(NULL), ns(NULL), host(NULL) {}
|
CDnsSeedOpts() : nThreads(24), nDnsThreads(24), nPort(53), mbox(NULL), ns(NULL), host(NULL) {}
|
||||||
|
|
||||||
void ParseCommandLine(int argc, char **argv) {
|
void ParseCommandLine(int argc, char **argv) {
|
||||||
static const char *help = "Bitcoin-seeder\n"
|
static const char *help = "Bitcoin-seeder\n"
|
||||||
|
@ -31,6 +32,7 @@ public:
|
||||||
"-n <ns> Hostname of the nameserver\n"
|
"-n <ns> Hostname of the nameserver\n"
|
||||||
"-m <mbox> E-Mail address reported in SOA records\n"
|
"-m <mbox> E-Mail address reported in SOA records\n"
|
||||||
"-t <threads> Number of crawlers to run in parallel (default 24)\n"
|
"-t <threads> Number of crawlers to run in parallel (default 24)\n"
|
||||||
|
"-d <threads> Number of DNS server threads (default 24)\n"
|
||||||
"-p <port> UDP port to listen on (default 53)\n"
|
"-p <port> UDP port to listen on (default 53)\n"
|
||||||
"-?, --help Show this text\n"
|
"-?, --help Show this text\n"
|
||||||
"\n";
|
"\n";
|
||||||
|
@ -42,12 +44,13 @@ public:
|
||||||
{"ns", required_argument, 0, 'n'},
|
{"ns", required_argument, 0, 'n'},
|
||||||
{"mbox", required_argument, 0, 'm'},
|
{"mbox", required_argument, 0, 'm'},
|
||||||
{"threads", required_argument, 0, 't'},
|
{"threads", required_argument, 0, 't'},
|
||||||
|
{"dnsthreads", required_argument, 0, 'd'},
|
||||||
{"port", required_argument, 0, 'p'},
|
{"port", required_argument, 0, 'p'},
|
||||||
{"help", no_argument, 0, 'h'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
int option_index = 0;
|
int option_index = 0;
|
||||||
int c = getopt_long(argc, argv, "h:n:m:t:p:", long_options, &option_index);
|
int c = getopt_long(argc, argv, "h:n:m:t:p:d:", long_options, &option_index);
|
||||||
if (c == -1) break;
|
if (c == -1) break;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h': {
|
case 'h': {
|
||||||
|
@ -71,6 +74,12 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'd': {
|
||||||
|
int n = strtol(optarg, NULL, 10);
|
||||||
|
if (n > 0 && n < 1000) nDnsThreads = n;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'p': {
|
case 'p': {
|
||||||
int p = strtol(optarg, NULL, 10);
|
int p = strtol(optarg, NULL, 10);
|
||||||
if (p > 0 && p < 65536) nPort = p;
|
if (p > 0 && p < 65536) nPort = p;
|
||||||
|
@ -118,57 +127,78 @@ extern "C" void* ThreadCrawler(void* data) {
|
||||||
} while(1);
|
} while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static vector<struct in_addr> cache;
|
extern "C" int GetIPList(void *thread, struct in_addr *addr, int max, int ipv4only);
|
||||||
static time_t cacheTime;
|
|
||||||
static unsigned int cacheHits = 1000000000;
|
|
||||||
static uint64_t dbQueries = 0;
|
|
||||||
|
|
||||||
void static cacheRefresh(int ipv4only) {
|
class CDnsThread {
|
||||||
time_t now = time(NULL);
|
public:
|
||||||
cacheHits++;
|
dns_opt_t dns_opt;
|
||||||
if (cacheHits > (cache.size()*cache.size()/400) || (cacheHits*cacheHits > cache.size() / 20 && (now - cacheTime > 5))) {
|
vector<struct in_addr> cache;
|
||||||
set<CIP> ips;
|
time_t cacheTime;
|
||||||
db.GetIPs(ips, 1000, ipv4only);
|
unsigned int cacheHits;
|
||||||
dbQueries++;
|
uint64_t dbQueries;
|
||||||
cache.clear();
|
|
||||||
cache.reserve(ips.size());
|
void cacheHit(int ipv4only, bool force = false) {
|
||||||
for (set<CIP>::iterator it = ips.begin(); it != ips.end(); it++) {
|
time_t now = time(NULL);
|
||||||
struct in_addr addr;
|
cacheHits++;
|
||||||
if ((*it).GetInAddr(&addr)) {
|
if (force || cacheHits > (cache.size()*cache.size()/400) || (cacheHits*cacheHits > cache.size() / 20 && (now - cacheTime > 5))) {
|
||||||
cache.push_back(addr);
|
set<CIP> ips;
|
||||||
|
db.GetIPs(ips, 1000, ipv4only);
|
||||||
|
dbQueries++;
|
||||||
|
cache.clear();
|
||||||
|
cache.reserve(ips.size());
|
||||||
|
for (set<CIP>::iterator it = ips.begin(); it != ips.end(); it++) {
|
||||||
|
struct in_addr addr;
|
||||||
|
if ((*it).GetInAddr(&addr)) {
|
||||||
|
cache.push_back(addr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
cacheHits = 0;
|
||||||
|
cacheTime = now;
|
||||||
}
|
}
|
||||||
cacheHits = 0;
|
|
||||||
cacheTime = now;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" int GetIPList(struct in_addr *addr, int max, int ipv4only) {
|
CDnsThread(CDnsSeedOpts* opts) {
|
||||||
cacheRefresh(ipv4only);
|
dns_opt.host = opts->host;
|
||||||
if (max > cache.size())
|
dns_opt.ns = opts->ns;
|
||||||
max = cache.size();
|
dns_opt.mbox = opts->mbox;
|
||||||
|
dns_opt.datattl = 60;
|
||||||
|
dns_opt.nsttl = 40000;
|
||||||
|
dns_opt.cb = GetIPList;
|
||||||
|
dns_opt.port = opts->nPort;
|
||||||
|
dns_opt.nRequests = 0;
|
||||||
|
cache.clear();
|
||||||
|
cache.reserve(1000);
|
||||||
|
cacheTime = 0;
|
||||||
|
cacheHits = 0;
|
||||||
|
dbQueries = 0;
|
||||||
|
cacheHit(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() {
|
||||||
|
dnsserver(&dns_opt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" int GetIPList(void *data, struct in_addr *addr, int max, int ipv4only) {
|
||||||
|
CDnsThread *thread = (CDnsThread*)data;
|
||||||
|
thread->cacheHit(ipv4only);
|
||||||
|
unsigned int size = thread->cache.size();
|
||||||
|
if (max > size)
|
||||||
|
max = size;
|
||||||
for (int i=0; i<max; i++) {
|
for (int i=0; i<max; i++) {
|
||||||
int j = i + (rand() % (cache.size() - i));
|
int j = i + (rand() % (size - i));
|
||||||
addr[i] = cache[j];
|
addr[i] = thread->cache[j];
|
||||||
cache[j] = cache[i];
|
thread->cache[j] = thread->cache[i];
|
||||||
cache[i] = addr[i];
|
thread->cache[i] = addr[i];
|
||||||
}
|
}
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
static dns_opt_t dns_opt;
|
vector<CDnsThread*> dnsThread;
|
||||||
|
|
||||||
extern "C" void* ThreadDNS(void* arg) {
|
extern "C" void* ThreadDNS(void* arg) {
|
||||||
CDnsSeedOpts *opts = (CDnsSeedOpts*)arg;
|
CDnsThread *thread = (CDnsThread*)arg;
|
||||||
dns_opt.host = opts->host;
|
thread->run();
|
||||||
dns_opt.ns = opts->ns;
|
|
||||||
dns_opt.mbox = opts->mbox;
|
|
||||||
dns_opt.datattl = 60;
|
|
||||||
dns_opt.nsttl = 40000;
|
|
||||||
dns_opt.cb = GetIPList;
|
|
||||||
dns_opt.port = opts->nPort;
|
|
||||||
dns_opt.nRequests = 0;
|
|
||||||
dnsserver(&dns_opt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int StatCompare(const CAddrReport& a, const CAddrReport& b) {
|
int StatCompare(const CAddrReport& a, const CAddrReport& b) {
|
||||||
|
@ -223,7 +253,13 @@ extern "C" void* ThreadStats(void*) {
|
||||||
CAddrDbStats stats;
|
CAddrDbStats stats;
|
||||||
db.GetStats(stats);
|
db.GetStats(stats);
|
||||||
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
|
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
|
||||||
printf("%s %i/%i available (%i tried in %is, %i new, %i active), %i banned; %llu DNS requests, %llu db reads", c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)dns_opt.nRequests, (unsigned long long)dbQueries);
|
uint64_t requests = 0;
|
||||||
|
uint64_t queries = 0;
|
||||||
|
for (unsigned int i=0; i<dnsThread.size(); i++) {
|
||||||
|
requests += dnsThread[i]->dns_opt.nRequests;
|
||||||
|
queries += dnsThread[i]->dbQueries;
|
||||||
|
}
|
||||||
|
printf("%s %i/%i available (%i tried in %is, %i new, %i active), %i banned; %llu DNS requests, %llu db queries", c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)requests, (unsigned long long)queries);
|
||||||
Sleep(1000);
|
Sleep(1000);
|
||||||
} while(1);
|
} while(1);
|
||||||
}
|
}
|
||||||
|
@ -276,8 +312,14 @@ int main(int argc, char **argv) {
|
||||||
printf("done\n");
|
printf("done\n");
|
||||||
pthread_create(&threadDump, NULL, ThreadDumper, NULL);
|
pthread_create(&threadDump, NULL, ThreadDumper, NULL);
|
||||||
if (fDNS) {
|
if (fDNS) {
|
||||||
printf("Starting DNS server for %s on %s (port %i)...", opts.host, opts.ns, opts.nPort);
|
printf("Starting %i DNS threads for %s on %s (port %i)...", opts.nDnsThreads, opts.host, opts.ns, opts.nPort);
|
||||||
pthread_create(&threadDns, NULL, ThreadDNS, &opts);
|
dnsThread.clear();
|
||||||
|
for (int i=0; i<opts.nDnsThreads; i++) {
|
||||||
|
dnsThread.push_back(new CDnsThread(&opts));
|
||||||
|
pthread_create(&threadDns, NULL, ThreadDNS, dnsThread[i]);
|
||||||
|
printf(".");
|
||||||
|
Sleep(20);
|
||||||
|
}
|
||||||
printf("done\n");
|
printf("done\n");
|
||||||
}
|
}
|
||||||
pthread_create(&threadStats, NULL, ThreadStats, NULL);
|
pthread_create(&threadStats, NULL, ThreadStats, NULL);
|
||||||
|
|
Loading…
Reference in a new issue