Compare commits

...
Sign in to create a new pull request.

48 commits

Author SHA1 Message Date
Alex Grintsvayg
b0062c2d74
readme update 2021-04-12 15:55:47 -04:00
Alex Grintsvayg
154c58da7a
change it for lbry 2021-04-12 09:37:23 -04:00
Pieter Wuille
a09d2870d1
Merge #89: Avoid strlen; use strnlen
a39d7916d0 Avoid strlen; use strnlen (Pieter Wuille)

Pull request description:

Top commit has no ACKs.

Tree-SHA512: 4e60f2aece7e83635ea0db6adf623472649a05d4b69f3700cae4fb94e2e937503774a332d7bae794f59261d5fd62e3679db9cdd704c31e5350ffb5b9f1b6c51f
2021-01-15 13:33:11 -08:00
Pieter Wuille
a39d7916d0 Avoid strlen; use strnlen 2021-01-14 19:07:52 -08:00
Pieter Wuille
0df0e521f1
Merge #55: Fix Warnings
2cfc903cb9 Fix -Wvarargs warnings (Lucas Betschart)
ff5564e4ce Fix -Wreturn-type warnings (Lucas Betschart)
1065303ecb Fix -Wuninitialized warnings (Lucas Betschart)

Pull request description:

  Fixes what my clang said he doesn't like.

ACKs for top commit:
  Sjors:
    Pure zen, thanks! ACK 2cfc903 (still works when rebased on master)
  sipa:
    utACK 2cfc903cb9

Tree-SHA512: 600fe532cb58c95968afabec38745c2a7c4a60603685c154538eae253ebfd492bce4110a99bcd37ec198150d85e2a1d41f1a491b2cf1d832a84363e913d7c550
2020-12-17 12:36:29 -08:00
Pieter Wuille
00542a6800
Merge #77: [doc] add hex equivalent for flags
f81b533bb5 [doc] add hex equivalent for flags (Sjors Provoost)

Pull request description:

  Handy for those who do not natively think in binary and hex.

ACKs for top commit:
  sipa:
    ACK f81b533bb5

Tree-SHA512: 92ec7604d5a302fabfa68e72c250ea6f69e8715d50b9724cf9af6eb88beff7837d898b60ff1d5b663f473f5e3d6fed41067fb803ec2dffe31c63171d8afa1357
2020-12-17 11:04:31 -08:00
Pieter Wuille
c52f3dbcc8
Merge #84: Add --address, bind to specific address
bf40486011 Add --address, bind to specific address (uhliksk)

Pull request description:

  - Fix #83 (will reply from same address as provided)
  - Fix #59 (will work if you bind to specific IPv4 address)
  - Fix #51 (will work with systemd-resolved service if you bind to specific address)

ACKs for top commit:
  sipa:
    ACK bf40486011

Tree-SHA512: 1924533a31f4e1b1149e1863454c28b5860eea6bd90e4d54fea761b608ad47ad8e15e6e2a745c91717658466cdd6c2cdc221f2587968f94c798d09774e4ddca0
2020-12-17 10:58:03 -08:00
Pieter Wuille
c80dfca92d
Merge #88: Add setcap hint to readme
5586af8ff2 Add setcap hint to readme (Jonas Schnelli)

Pull request description:

ACKs for top commit:
  sipa:
    ACK 5586af8ff2

Tree-SHA512: 1449ba2419bfb4a14b6dfff1683e13b0a6f469d69c8ebf9026ae9b51bba684538e3e89ed714163b83becdf13572174826579dcec2ac2abfc84ce94693935461f
2020-12-17 10:52:02 -08:00
Jonas Schnelli
5586af8ff2 Add setcap hint to readme 2020-12-16 20:25:09 +01:00
Pieter Wuille
b1cf356ff2 Fix stack overflow in write_record_aaaa 2020-10-19 16:32:08 -07:00
Pieter Wuille
63ff7e40c9 Don't merge in re-rumours' nServices 2020-10-10 10:20:26 -07:00
Pieter Wuille
24e1cac582 Avoid strncpy for commands 2020-10-09 19:51:19 -07:00
Pieter Wuille
89929dab5c Use distinct read and except sets in select() 2020-10-09 19:44:29 -07:00
Pieter Wuille
a1e9394284 Overwrite db services with version message results 2020-10-09 19:37:28 -07:00
uhliksk
bf40486011
Add --address, bind to specific address 2020-08-06 03:29:56 +02:00
Pieter Wuille
529a667f30 Convert dns.c to C++ 2019-12-02 15:16:26 -08:00
Sjors Provoost
f81b533bb5
[doc] add hex equivalent for flags 2019-08-22 17:35:13 +02:00
Pieter Wuille
d098ad9a1f Add support for NODE_COMPACT_FILTERS by default 2019-08-09 17:04:12 -07:00
Pieter Wuille
36bd7f9a0f Send BIP37 fRelay as false 2019-08-09 16:56:23 -07:00
Pieter Wuille
180eb62bd2 Delete unused TestUint256AdHoc 2019-08-09 16:53:30 -07:00
Pieter Wuille
002bc0bbd5 Support NODE_NETWORK_LIMITED by default 2019-08-09 16:52:18 -07:00
Lucas Betschart
2cfc903cb9 Fix -Wvarargs warnings 2017-12-29 00:04:40 +01:00
Lucas Betschart
ff5564e4ce Fix -Wreturn-type warnings 2017-12-28 23:58:10 +01:00
Lucas Betschart
1065303ecb Fix -Wuninitialized warnings 2017-12-28 23:45:38 +01:00
Pieter Wuille
d54f39a1ee
Merge #42: thisflag should be declared as FlagSpecificData reference
9e4e634 thisflag should be declared as FlagSpecificData reference (Andrea Suisani)
2017-01-12 21:06:13 -08:00
Andrea Suisani
9e4e6342b7
thisflag should be declared as FlagSpecificData reference
With the current code there's now way that the seeder
returns peers addresses upon dns requests.

Thanks to @gandrewstone for good catch.
2017-01-13 00:04:09 +01:00
Pieter Wuille
d5764c9149 Fix per-flag-cache size tracking 2016-10-29 12:15:18 -07:00
Pieter Wuille
0ec6e14c17
Merge #41: Fix -w option
0984cac Fix -w option (Peter Todd)
2016-06-23 21:51:38 +02:00
Peter Todd
0984caca2a
Fix -w option 2016-06-14 23:53:20 -04:00
Pieter Wuille
43388c3c3e
Merge #40: Improve filter whitelist
fa2aa34 Improve filter whitelist (Pieter Wuille)
2016-06-07 18:58:45 +02:00
Pieter Wuille
fa2aa348c8 Improve filter whitelist 2016-06-07 18:55:16 +02:00
Pieter Wuille
ab0ac73e5f
Merge #36: Add support to filter nodes by node flags
c9679dc Add whitelist for service filter, use a map for cacheTime (Jonas Schnelli)
5c8b9e3 IP-Query: Use a vector instead a set and random pick an IP (Jonas Schnelli)
839db15 Add support to filter nodes by node flags (Jonas Schnelli)
2016-06-07 17:57:12 +02:00
Jonas Schnelli
c9679dc98e
Add whitelist for service filter, use a map for cacheTime 2016-06-03 17:53:03 +02:00
Pieter Wuille
9c32351efd
Merge #38: Wait for more than a single addr to come back
e27d6c5 Adjust protocol timeouts (Pieter Wuille)
a9e960a Wait until we have more than a single addr response (Pieter Wuille)
2016-06-01 12:43:54 +02:00
Pieter Wuille
e27d6c5b3d Adjust protocol timeouts 2016-05-31 22:07:07 +02:00
Pieter Wuille
a9e960a4dd Wait until we have more than a single addr response 2016-05-31 22:06:58 +02:00
Jonas Schnelli
5c8b9e392b
IP-Query: Use a vector instead a set and random pick an IP 2016-05-31 10:40:44 +02:00
Jonas Schnelli
839db157f9
Add support to filter nodes by node flags 2016-05-27 16:22:42 +02:00
Pieter Wuille
c36ed80739
Merge #35: fix typos
3efbe20 fix typos (Carsten Otto)
2016-05-26 15:52:30 +02:00
Pieter Wuille
e7ab039041
Merge #31: Longer TTL
1763253 Longer TTL (Pieter Wuille)
2016-05-26 15:51:27 +02:00
Carsten Otto
3efbe20217 fix typos 2016-02-06 22:32:40 +01:00
Pieter Wuille
1a33b78801
Merge pull request #33
f0c8b87 require e-mail address if dns is enabled (Pavel Vasin)
2015-08-04 18:57:05 +02:00
Pavel Vasin
f0c8b87a07 require e-mail address if dns is enabled
Writing SOA record will cause nullptr dereference if it's not specified.
2015-08-03 22:04:20 +03:00
Pieter Wuille
a59329d936
Merge pull request #19
bb53306 dns: listen on ipv6 (Pavel Vasin)
34fd288 remove option to build without ipv6 support (Pavel Vasin)
2015-07-29 15:55:49 +02:00
Pieter Wuille
69436e5f4b
Merge pull request #32
5be5b37 Fixup (Pieter Wuille)
2015-07-29 15:35:35 +02:00
Pieter Wuille
5be5b37a83 Fixup 2015-07-29 15:34:23 +02:00
Pavel Vasin
bb53306a2e dns: listen on ipv6 2014-07-21 15:59:25 +04:00
Pavel Vasin
34fd2888bb remove option to build without ipv6 support 2014-07-21 15:59:25 +04:00
18 changed files with 471 additions and 475 deletions

View file

@ -4,10 +4,5 @@ LDFLAGS = $(CXXFLAGS)
dnsseed: dns.o bitcoin.o netbase.o protocol.o db.o main.o util.o
g++ -pthread $(LDFLAGS) -o dnsseed dns.o bitcoin.o netbase.o protocol.o db.o main.o util.o -lcrypto
%.o: %.cpp bitcoin.h netbase.h protocol.h db.h serialize.h uint256.h util.h
g++ -DUSE_IPV6 -pthread $(CXXFLAGS) -Wno-invalid-offsetof -c -o $@ $<
dns.o: dns.c
gcc -pthread -std=c99 $(CXXFLAGS) dns.c -c -o dns.o
%.o: %.cpp
%.o: %.cpp *.h
g++ -std=c++11 -pthread $(CXXFLAGS) -Wall -Wno-unused -Wno-sign-compare -Wno-reorder -Wno-comment -c -o $@ $<

62
README
View file

@ -1,62 +0,0 @@
bitcoin-seeder
==============
Bitcoin-seeder is a crawler for the Bitcoin network, which exposes a list
of reliable nodes via a built-in DNS server.
Features:
* regularly revisits known nodes to check their availability
* bans nodes after enough failures, or bad behaviour
* accepts nodes down to v0.3.19 to request new IP addresses from,
but only reports good post-v0.3.24 nodes.
* keeps statistics over (exponential) windows of 2 hours, 8 hours,
1 day and 1 week, to base decisions on.
* very low memory (a few tens of megabytes) and cpu requirements.
* crawlers run in parallel (by default 24 threads simultaneously).
REQUIREMENTS
------------
$ sudo apt-get install build-essential libboost-all-dev libssl-dev
USAGE
-----
Assuming you want to run a dns seed on dnsseed.example.com, you will
need an authorative NS record in example.com's domain record, pointing
to for example vps.example.com:
$ dig -t NS dnsseed.example.com
;; ANSWER SECTION
dnsseed.example.com. 86400 IN NS vps.example.com.
On the system vps.example.com, you can now run dnsseed:
./dnsseed -h dnsseed.example.com -n vps.example.com
If you want the DNS server to report SOA records, please provide an
e-mailadres (with the @ part replaced by .) using -m.
COMPILING
---------
Compiling will require boost and ssl. On debian systems, these are provided
by `libboost-dev` and `libssl-dev` respectively.
$ make
This will produce the `dnsseed` binary.
RUNNING AS NON-ROOT
-------------------
Typically, you'll need root privileges to listen to port 53 (name service).
One solution is using an iptables rule (Linux only) to redirect it to
a non-privileged port:
$ iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-port 5353
If properly configured, this will allow you to run dnsseed in userspace, using
the -p 5353 option.

View file

@ -26,9 +26,9 @@ class CNode {
int GetTimeout() {
if (you.IsTor())
return 60;
return 120;
else
return 10;
return 30;
}
void BeginMessage(const char *pszCommand) {
@ -36,16 +36,16 @@ class CNode {
nHeaderStart = vSend.size();
vSend << CMessageHeader(pszCommand, 0);
nMessageStart = vSend.size();
// printf("%s: SEND %s\n", ToString(you).c_str(), pszCommand);
// printf("%s: SEND %s\n", ToString(you).c_str(), pszCommand);
}
void AbortMessage() {
if (nHeaderStart == -1) return;
vSend.resize(nHeaderStart);
nHeaderStart = -1;
nMessageStart = -1;
}
void EndMessage() {
if (nHeaderStart == -1) return;
unsigned int nSize = vSend.size() - nMessageStart;
@ -60,7 +60,7 @@ class CNode {
nHeaderStart = -1;
nMessageStart = -1;
}
void Send() {
if (sock == INVALID_SOCKET) return;
if (vSend.empty()) return;
@ -72,7 +72,7 @@ class CNode {
sock = INVALID_SOCKET;
}
}
void PushVersion() {
int64 nTime = time(NULL);
uint64 nLocalNonce = BITCOIN_SEED_NONCE;
@ -80,11 +80,12 @@ class CNode {
CAddress me(CService("0.0.0.0"));
BeginMessage("version");
int nBestHeight = GetRequireHeight();
string ver = "/bitcoin-seeder:0.01/";
vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me << nLocalNonce << ver << nBestHeight;
string ver = "/lbry-seeder:0.01/";
uint8_t fRelayTxs = 0;
vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me << nLocalNonce << ver << nBestHeight << fRelayTxs;
EndMessage();
}
void GotVersion() {
// printf("\n%s: version %i\n", ToString(you).c_str(), nVersion);
if (vAddr) {
@ -111,7 +112,7 @@ class CNode {
vRecv >> strSubVer;
if (nVersion >= 209 && !vRecv.empty())
vRecv >> nStartingHeight;
if (nVersion >= 209) {
BeginMessage("verack");
EndMessage();
@ -123,20 +124,22 @@ class CNode {
}
return false;
}
if (strCommand == "verack") {
this->vRecv.SetVersion(min(nVersion, PROTOCOL_VERSION));
GotVersion();
return false;
}
if (strCommand == "addr" && vAddr) {
vector<CAddress> vAddrNew;
vRecv >> vAddrNew;
// printf("%s: got %i addresses\n", ToString(you).c_str(), (int)vAddrNew.size());
int64 now = time(NULL);
vector<CAddress>::iterator it = vAddrNew.begin();
if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1;
if (vAddrNew.size() > 1) {
if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1;
}
while (it != vAddrNew.end()) {
CAddress &addr = *it;
// printf("%s: got address %s\n", ToString(you).c_str(), addr.ToString().c_str(), (int)(vAddr->size()));
@ -150,10 +153,10 @@ class CNode {
}
return false;
}
return false;
}
bool ProcessMessages() {
if (vRecv.empty()) return false;
do {
@ -169,16 +172,16 @@ class CNode {
vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
CMessageHeader hdr;
vRecv >> hdr;
if (!hdr.IsValid()) {
if (!hdr.IsValid()) {
// printf("%s: BAD (invalid header)\n", ToString(you).c_str());
ban = 100000; return true;
}
string strCommand = hdr.GetCommand();
unsigned int nMessageSize = hdr.nMessageSize;
if (nMessageSize > MAX_SIZE) {
if (nMessageSize > MAX_SIZE) {
// printf("%s: BAD (message too large)\n", ToString(you).c_str());
ban = 100000;
return true;
return true;
}
if (nMessageSize > vRecv.size()) {
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
@ -198,7 +201,7 @@ class CNode {
} while(1);
return false;
}
public:
CNode(const CService& ip, vector<CAddress>* vAddrIn) : you(ip), nHeaderStart(-1), nMessageStart(-1), vAddr(vAddrIn), ban(0), doneAfter(0), nVersion(0) {
vSend.SetType(SER_NETWORK);
@ -218,9 +221,11 @@ public:
int64 now;
while (now = time(NULL), ban == 0 && (doneAfter == 0 || doneAfter > now) && sock != INVALID_SOCKET) {
char pchBuf[0x10000];
fd_set set;
FD_ZERO(&set);
FD_SET(sock,&set);
fd_set read_set, except_set;
FD_ZERO(&read_set);
FD_ZERO(&except_set);
FD_SET(sock,&read_set);
FD_SET(sock,&except_set);
struct timeval wa;
if (doneAfter) {
wa.tv_sec = doneAfter - now;
@ -229,7 +234,7 @@ public:
wa.tv_sec = GetTimeout();
wa.tv_usec = 0;
}
int ret = select(sock+1, &set, NULL, &set, &wa);
int ret = select(sock+1, &read_set, NULL, &except_set, &wa);
if (ret != 1) {
if (!doneAfter) res = false;
break;
@ -256,25 +261,29 @@ public:
sock = INVALID_SOCKET;
return (ban == 0) && res;
}
int GetBan() {
return ban;
}
int GetClientVersion() {
return nVersion;
}
std::string GetClientSubVersion() {
return strSubVer;
}
int GetStartingHeight() {
return nStartingHeight;
}
uint64_t GetServices() {
return you.nServices;
}
};
bool TestNode(const CService &cip, int &ban, int &clientV, std::string &clientSV, int &blocks, vector<CAddress>* vAddr) {
bool TestNode(const CService &cip, int &ban, int &clientV, std::string &clientSV, int &blocks, vector<CAddress>* vAddr, uint64_t& services) {
try {
CNode node(cip, vAddr);
bool ret = node.Run();
@ -286,6 +295,7 @@ bool TestNode(const CService &cip, int &ban, int &clientV, std::string &clientSV
clientV = node.GetClientVersion();
clientSV = node.GetClientSubVersion();
blocks = node.GetStartingHeight();
services = node.GetServices();
// printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD");
return ret;
} catch(std::ios_base::failure& e) {
@ -304,4 +314,3 @@ int main(void) {
printf("ret=%s ban=%i vAddr.size()=%i\n", ret ? "good" : "bad", ban, (int)vAddr.size());
}
*/

View file

@ -3,6 +3,6 @@
#include "protocol.h"
bool TestNode(const CService &cip, int &ban, int &client, std::string &clientSV, int &blocks, std::vector<CAddress>* vAddr);
bool TestNode(const CService &cip, int &ban, int &client, std::string &clientSV, int &blocks, std::vector<CAddress>* vAddr, uint64_t& services);
#endif

View file

@ -58,7 +58,7 @@ for my $file (@ARGV) {
}
for my $addr (sort { $res->{$b} <=> $res->{$a} } (keys %{$res})) {
if ($addr =~ /\A(\d+)\.(\d+)\.(\d+)\.(\d+):8333/) {
if ($addr =~ /\A(\d+)\.(\d+)\.(\d+)\.(\d+):9246/) {
my $a = $1*0x1000000 + $2*0x10000 + $3*0x100 + $4;
printf "0x%08x %s %g%%\n",$a,$addr,(1-((1-$res->{$addr}) ** (1/$n)))*100;
}

36
db.cpp
View file

@ -69,7 +69,7 @@ int CAddrDb::Lookup_(const CService &ip) {
return -1;
}
void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV, int blocks) {
void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV, int blocks, uint64_t services) {
int id = Lookup_(addr);
if (id == -1) return;
unkId.erase(id);
@ -78,6 +78,7 @@ void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV, int
info.clientVersion = clientV;
info.clientSubVersion = clientSV;
info.blocks = blocks;
info.services = services;
info.Update(true);
if (info.IsGood() && goodId.count(id)==0) {
goodId.insert(id);
@ -140,12 +141,8 @@ void CAddrDb::Add_(const CAddress &addr, bool force) {
}
if (ipToId.count(ipp)) {
CAddrInfo &ai = idToInfo[ipToId[ipp]];
if (addr.nTime > ai.lastTry || ai.services != addr.nServices)
{
ai.lastTry = addr.nTime;
ai.services |= addr.nServices;
// printf("%s: updated\n", ToString(addr).c_str());
}
if (addr.nTime > ai.lastTry) ai.lastTry = addr.nTime;
// Do not update ai.nServices (data from VERSION from the peer itself is better than random ADDR rumours).
if (force) {
ai.ignoreTill = 0;
}
@ -166,7 +163,7 @@ void CAddrDb::Add_(const CAddress &addr, bool force) {
nDirty++;
}
void CAddrDb::GetIPs_(set<CNetAddr>& ips, int max, const bool* nets) {
void CAddrDb::GetIPs_(set<CNetAddr>& ips, uint64_t requestedFlags, int max, const bool* nets) {
if (goodId.size() == 0) {
int id = -1;
if (ourId.size() == 0) {
@ -175,23 +172,28 @@ void CAddrDb::GetIPs_(set<CNetAddr>& ips, int max, const bool* nets) {
} else {
id = *ourId.begin();
}
if (id >= 0) {
if (id >= 0 && (idToInfo[id].services & requestedFlags) == requestedFlags) {
ips.insert(idToInfo[id].ip);
}
return;
}
if (max > goodId.size() / 2)
max = goodId.size() / 2;
std::vector<int> goodIdFiltered;
for (std::set<int>::const_iterator it = goodId.begin(); it != goodId.end(); it++) {
if ((idToInfo[*it].services & requestedFlags) == requestedFlags)
goodIdFiltered.push_back(*it);
}
if (!goodIdFiltered.size())
return;
if (max > goodIdFiltered.size() / 2)
max = goodIdFiltered.size() / 2;
if (max < 1)
max = 1;
int low = *goodId.begin();
int high = *goodId.rbegin();
set<int> ids;
while (ids.size() < max) {
int range = high-low+1;
int pos = low + (rand() % range);
int id = *(goodId.lower_bound(pos));
ids.insert(id);
ids.insert(goodIdFiltered[rand() % goodIdFiltered.size()]);
}
for (set<int>::const_iterator it = ids.begin(); it != ids.end(); it++) {
CService &ip = idToInfo[*it].ip;

24
db.h
View file

@ -12,11 +12,11 @@
#define MIN_RETRY 1000
#define REQUIRE_VERSION 70001
#define REQUIRE_VERSION 70015
static inline int GetRequireHeight(const bool testnet = fTestNet)
{
return testnet ? 500000 : 350000;
return testnet ? 1000 : 940000;
}
std::string static inline ToString(const CService &ip) {
@ -119,7 +119,7 @@ public:
}
int GetBanTime() const {
if (IsGood()) return 0;
if (clientVersion && clientVersion < 31900) { return 604800; }
if (clientVersion && clientVersion < 31800) { return 604800; }
if (stat1M.reliability - stat1M.weight + 1.0 < 0.15 && stat1M.count > 32) { return 30*86400; }
if (stat1W.reliability - stat1W.weight + 1.0 < 0.10 && stat1W.count > 16) { return 7*86400; }
if (stat1D.reliability - stat1D.weight + 1.0 < 0.05 && stat1D.count > 8) { return 1*86400; }
@ -183,6 +183,7 @@ public:
struct CServiceResult {
CService service;
uint64_t services;
bool fGood;
int nBanTime;
int nHeight;
@ -215,11 +216,11 @@ protected:
void Add_(const CAddress &addr, bool force); // add an address
bool Get_(CServiceResult &ip, int& wait); // get an IP to test (must call Good_, Bad_, or Skipped_ on result afterwards)
bool GetMany_(std::vector<CServiceResult> &ips, int max, int& wait);
void Good_(const CService &ip, int clientV, std::string clientSV, int blocks); // mark an IP as good (must have been returned by Get_)
void Good_(const CService &ip, int clientV, std::string clientSV, int blocks, uint64_t services); // mark an IP as good (must have been returned by Get_)
void Bad_(const CService &ip, int ban); // mark an IP as bad (and optionally ban it) (must have been returned by Get_)
void Skipped_(const CService &ip); // mark an IP as skipped (must have been returned by Get_)
int Lookup_(const CService &ip); // look up id of an IP
void GetIPs_(std::set<CNetAddr>& ips, int max, const bool *nets); // get a random set of IPs (shared lock only)
void GetIPs_(std::set<CNetAddr>& ips, uint64_t requestedFlags, int max, const bool *nets); // get a random set of IPs (shared lock only)
public:
std::map<CService, time_t> banned; // nodes that are banned, with their unban time (a)
@ -281,7 +282,7 @@ public:
} else {
CAddrDb *db = const_cast<CAddrDb*>(this);
db->nId = 0;
int n;
int n = 0;
READWRITE(n);
for (int i=0; i<n; i++) {
CAddrInfo info;
@ -313,9 +314,9 @@ public:
for (int i=0; i<vAddr.size(); i++)
Add_(vAddr[i], fForce);
}
void Good(const CService &addr, int clientVersion, std::string clientSubVersion, int blocks) {
void Good(const CService &addr, int clientVersion, std::string clientSubVersion, int blocks, uint64_t services) {
CRITICAL_BLOCK(cs)
Good_(addr, clientVersion, clientSubVersion, blocks);
Good_(addr, clientVersion, clientSubVersion, blocks, services);
}
void Skipped(const CService &addr) {
CRITICAL_BLOCK(cs)
@ -328,6 +329,7 @@ public:
bool Get(CServiceResult &ip, int& wait) {
CRITICAL_BLOCK(cs)
return Get_(ip, wait);
return false;
}
void GetMany(std::vector<CServiceResult> &ips, int max, int& wait) {
CRITICAL_BLOCK(cs) {
@ -344,15 +346,15 @@ public:
CRITICAL_BLOCK(cs) {
for (int i=0; i<ips.size(); i++) {
if (ips[i].fGood) {
Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV, ips[i].nHeight);
Good_(ips[i].service, ips[i].nClientV, ips[i].strClientV, ips[i].nHeight, ips[i].services);
} else {
Bad_(ips[i].service, ips[i].nBanTime);
}
}
}
}
void GetIPs(std::set<CNetAddr>& ips, int max, const bool *nets) {
void GetIPs(std::set<CNetAddr>& ips, uint64_t requestedFlags, int max, const bool *nets) {
SHARED_CRITICAL_BLOCK(cs)
GetIPs_(ips, max, nets);
GetIPs_(ips, requestedFlags, max, nets);
}
};

View file

@ -16,20 +16,14 @@
#define BUFLEN 512
#if defined IP_RECVDSTADDR
#if defined(IP_RECVDSTADDR)
# define DSTADDR_SOCKOPT IP_RECVDSTADDR
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in_addr)))
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_addr)))
# define dstaddr(x) (CMSG_DATA(x))
#elif defined IP_PKTINFO
struct in_pktinfo {
unsigned int ipi_ifindex; /* Interface index */
struct in_addr ipi_spec_dst; /* Local address */
struct in_addr ipi_addr; /* Header Destination address */
};
# define DSTADDR_SOCKOPT IP_PKTINFO
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in_pktinfo)))
# define dstaddr(x) (&(((struct in_pktinfo *)(CMSG_DATA(x)))->ipi_addr))
#elif defined(IPV6_PKTINFO)
# define DSTADDR_SOCKOPT IPV6_PKTINFO
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_pktinfo)))
# define dstaddr(x) (&(((struct in6_pktinfo *)(CMSG_DATA(x)))->ipi6_addr))
#else
# error "can't determine socket option"
#endif
@ -109,7 +103,7 @@ int static parse_name(const unsigned char **inpos, const unsigned char *inend, c
// -3: two subsequent dots
int static write_name(unsigned char** outpos, const unsigned char *outend, const char *name, int offset) {
while (*name != 0) {
char *dot = strchr(name, '.');
const char *dot = strchr(name, '.');
const char *fin = dot;
if (!dot) fin = name + strlen(name);
if (fin - name > 63) return -1;
@ -138,16 +132,21 @@ int static write_record(unsigned char** outpos, const unsigned char *outend, con
int error = 0;
// name
int ret = write_name(outpos, outend, name, offset);
if (ret) { error = ret; goto error; }
if (outend - *outpos < 8) { error = -4; goto error; }
// type
*((*outpos)++) = typ >> 8; *((*outpos)++) = typ & 0xFF;
// class
*((*outpos)++) = cls >> 8; *((*outpos)++) = cls & 0xFF;
// ttl
*((*outpos)++) = (ttl >> 24) & 0xFF; *((*outpos)++) = (ttl >> 16) & 0xFF; *((*outpos)++) = (ttl >> 8) & 0xFF; *((*outpos)++) = ttl & 0xFF;
return 0;
error:
if (ret) {
error = ret;
} else {
if (outend - *outpos < 8) {
error = -4;
} else {
// type
*((*outpos)++) = typ >> 8; *((*outpos)++) = typ & 0xFF;
// class
*((*outpos)++) = cls >> 8; *((*outpos)++) = cls & 0xFF;
// ttl
*((*outpos)++) = (ttl >> 24) & 0xFF; *((*outpos)++) = (ttl >> 16) & 0xFF; *((*outpos)++) = (ttl >> 8) & 0xFF; *((*outpos)++) = ttl & 0xFF;
return 0;
}
}
*outpos = oldpos;
return error;
}
@ -160,14 +159,16 @@ int static write_record_a(unsigned char** outpos, const unsigned char *outend, c
int error = 0;
int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl);
if (ret) return ret;
if (outend - *outpos < 6) { error = -5; goto error; }
// rdlength
*((*outpos)++) = 0; *((*outpos)++) = 4;
// rdata
for (int i=0; i<4; i++)
*((*outpos)++) = ip->data.v4[i];
return 0;
error:
if (outend - *outpos < 6) {
error = -5;
} else {
// rdlength
*((*outpos)++) = 0; *((*outpos)++) = 4;
// rdata
for (int i=0; i<4; i++)
*((*outpos)++) = ip->data.v4[i];
return 0;
}
*outpos = oldpos;
return error;
}
@ -179,63 +180,92 @@ int static write_record_aaaa(unsigned char** outpos, const unsigned char *outend
int error = 0;
int ret = write_record(outpos, outend, name, offset, TYPE_AAAA, cls, ttl);
if (ret) return ret;
if (outend - *outpos < 6) { error = -5; goto error; }
// rdlength
*((*outpos)++) = 0; *((*outpos)++) = 16;
// rdata
for (int i=0; i<16; i++)
*((*outpos)++) = ip->data.v6[i];
return 0;
error:
if (outend - *outpos < 18) {
error = -5;
} else {
// rdlength
*((*outpos)++) = 0; *((*outpos)++) = 16;
// rdata
for (int i=0; i<16; i++)
*((*outpos)++) = ip->data.v6[i];
return 0;
}
*outpos = oldpos;
return error;
}
int static write_record_ns(unsigned char** outpos, const unsigned char *outend, char *name, int offset, dns_class cls, int ttl, const char *ns) {
int static write_record_ns(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const char *ns) {
unsigned char *oldpos = *outpos;
int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl);
if (ret) return ret;
int error = 0;
if (outend - *outpos < 2) { error = -5; goto error; }
(*outpos) += 2;
unsigned char *curpos = *outpos;
ret = write_name(outpos, outend, ns, -1);
if (ret) { error = ret; goto error; }
curpos[-2] = (*outpos - curpos) >> 8;
curpos[-1] = (*outpos - curpos) & 0xFF;
return 0;
error:
if (outend - *outpos < 2) {
error = -5;
} else {
(*outpos) += 2;
unsigned char *curpos = *outpos;
ret = write_name(outpos, outend, ns, -1);
if (ret) {
error = ret;
} else {
curpos[-2] = (*outpos - curpos) >> 8;
curpos[-1] = (*outpos - curpos) & 0xFF;
return 0;
}
}
*outpos = oldpos;
return error;
}
int static write_record_soa(unsigned char** outpos, const unsigned char *outend, char *name, int offset, dns_class cls, int ttl, const char* mname, const char *rname,
int static write_record_soa(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const char* mname, const char *rname,
uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) {
unsigned char *oldpos = *outpos;
int ret = write_record(outpos, outend, name, offset, TYPE_SOA, cls, ttl);
if (ret) return ret;
int error = 0;
if (outend - *outpos < 2) { error = -5; goto error; }
(*outpos) += 2;
unsigned char *curpos = *outpos;
ret = write_name(outpos, outend, mname, -1);
if (ret) { error = ret; goto error; }
ret = write_name(outpos, outend, rname, -1);
if (ret) { error = ret; goto error; }
if (outend - *outpos < 20) { error = -5; goto error; }
*((*outpos)++) = (serial >> 24) & 0xFF; *((*outpos)++) = (serial >> 16) & 0xFF; *((*outpos)++) = (serial >> 8) & 0xFF; *((*outpos)++) = serial & 0xFF;
*((*outpos)++) = (refresh >> 24) & 0xFF; *((*outpos)++) = (refresh >> 16) & 0xFF; *((*outpos)++) = (refresh >> 8) & 0xFF; *((*outpos)++) = refresh & 0xFF;
*((*outpos)++) = (retry >> 24) & 0xFF; *((*outpos)++) = (retry >> 16) & 0xFF; *((*outpos)++) = (retry >> 8) & 0xFF; *((*outpos)++) = retry & 0xFF;
*((*outpos)++) = (expire >> 24) & 0xFF; *((*outpos)++) = (expire >> 16) & 0xFF; *((*outpos)++) = (expire >> 8) & 0xFF; *((*outpos)++) = expire & 0xFF;
*((*outpos)++) = (minimum >> 24) & 0xFF; *((*outpos)++) = (minimum >> 16) & 0xFF; *((*outpos)++) = (minimum >> 8) & 0xFF; *((*outpos)++) = minimum & 0xFF;
curpos[-2] = (*outpos - curpos) >> 8;
curpos[-1] = (*outpos - curpos) & 0xFF;
return 0;
error:
if (outend - *outpos < 2) {
error = -5;
} else {
(*outpos) += 2;
unsigned char *curpos = *outpos;
ret = write_name(outpos, outend, mname, -1);
if (ret) {
error = ret;
} else {
ret = write_name(outpos, outend, rname, -1);
if (ret) {
error = ret;
} else {
if (outend - *outpos < 20) {
error = -5;
} else {
*((*outpos)++) = (serial >> 24) & 0xFF; *((*outpos)++) = (serial >> 16) & 0xFF; *((*outpos)++) = (serial >> 8) & 0xFF; *((*outpos)++) = serial & 0xFF;
*((*outpos)++) = (refresh >> 24) & 0xFF; *((*outpos)++) = (refresh >> 16) & 0xFF; *((*outpos)++) = (refresh >> 8) & 0xFF; *((*outpos)++) = refresh & 0xFF;
*((*outpos)++) = (retry >> 24) & 0xFF; *((*outpos)++) = (retry >> 16) & 0xFF; *((*outpos)++) = (retry >> 8) & 0xFF; *((*outpos)++) = retry & 0xFF;
*((*outpos)++) = (expire >> 24) & 0xFF; *((*outpos)++) = (expire >> 16) & 0xFF; *((*outpos)++) = (expire >> 8) & 0xFF; *((*outpos)++) = expire & 0xFF;
*((*outpos)++) = (minimum >> 24) & 0xFF; *((*outpos)++) = (minimum >> 16) & 0xFF; *((*outpos)++) = (minimum >> 8) & 0xFF; *((*outpos)++) = minimum & 0xFF;
curpos[-2] = (*outpos - curpos) >> 8;
curpos[-1] = (*outpos - curpos) & 0xFF;
return 0;
}
}
}
}
*outpos = oldpos;
return error;
}
static ssize_t set_error(unsigned char* outbuf, int error) {
// set error
outbuf[3] |= error & 0xF;
// set counts
outbuf[4] = 0; outbuf[5] = 0;
outbuf[6] = 0; outbuf[7] = 0;
outbuf[8] = 0; outbuf[9] = 0;
outbuf[10] = 0; outbuf[11] = 0;
return 12;
}
ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insize, unsigned char* outbuf) {
int error = 0;
if (insize < 12) // DNS header
@ -249,27 +279,27 @@ ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insi
// clear error
outbuf[3] &= ~15;
// check qr
if (inbuf[2] & 128) { /* printf("Got response?\n"); */ error = 1; goto error; }
if (inbuf[2] & 128) return set_error(outbuf, 1); /* printf("Got response?\n"); */
// check opcode
if (((inbuf[2] & 120) >> 3) != 0) { /* printf("Opcode nonzero?\n"); */ error = 4; goto error; }
if (((inbuf[2] & 120) >> 3) != 0) return set_error(outbuf, 1); /* printf("Opcode nonzero?\n"); */
// unset TC
outbuf[2] &= ~2;
// unset RA
outbuf[3] &= ~128;
// check questions
int nquestion = (inbuf[4] << 8) + inbuf[5];
if (nquestion == 0) { /* printf("No questions?\n"); */ error = 0; goto error; }
if (nquestion > 1) { /* printf("Multiple questions %i?\n", nquestion); */ error = 4; goto error; }
if (nquestion == 0) return set_error(outbuf, 0); /* printf("No questions?\n"); */
if (nquestion > 1) return set_error(outbuf, 4); /* printf("Multiple questions %i?\n", nquestion); */
const unsigned char *inpos = inbuf + 12;
const unsigned char *inend = inbuf + insize;
char name[256];
int offset = inpos - inbuf;
int ret = parse_name(&inpos, inend, inbuf, name, 256);
if (ret == -1) { error = 1; goto error; }
if (ret == -2) { error = 5; goto error; }
if (ret == -1) return set_error(outbuf, 1);
if (ret == -2) return set_error(outbuf, 5);
int namel = strlen(name), hostl = strlen(opt->host);
if (strcasecmp(name, opt->host) && (namel<hostl+2 || name[namel-hostl-1]!='.' || strcasecmp(name+namel-hostl,opt->host))) { error = 5; goto error; }
if (inend - inpos < 4) { error = 1; goto error; }
if (strcasecmp(name, opt->host) && (namel<hostl+2 || name[namel-hostl-1]!='.' || strcasecmp(name+namel-hostl,opt->host))) return set_error(outbuf, 5);
if (inend - inpos < 4) return set_error(outbuf, 1);
// copy question to output
memcpy(outbuf+12, inbuf+12, inpos+4 - (inbuf+12));
// set counts
@ -327,7 +357,7 @@ ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insi
// A/AAAA records
if ((typ == TYPE_A || typ == TYPE_AAAA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
addr_t addr[32];
int naddr = opt->cb((void*)opt, addr, 32, typ == TYPE_A || typ == QTYPE_ANY, typ == TYPE_AAAA || typ == QTYPE_ANY);
int naddr = opt->cb((void*)opt, name, addr, 32, typ == TYPE_A || typ == QTYPE_ANY, typ == TYPE_AAAA || typ == QTYPE_ANY);
int n = 0;
while (n < naddr) {
int ret = 1;
@ -366,45 +396,36 @@ ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insi
outbuf[2] |= 4;
return outpos - outbuf;
error:
// set error
outbuf[3] |= error & 0xF;
// set counts
outbuf[4] = 0; outbuf[5] = 0;
outbuf[6] = 0; outbuf[7] = 0;
outbuf[8] = 0; outbuf[9] = 0;
outbuf[10] = 0; outbuf[11] = 0;
return 12;
}
static int listenSocket = -1;
int dnsserver(dns_opt_t *opt) {
struct sockaddr_in si_other;
struct sockaddr_in6 si_other;
int senderSocket = -1;
senderSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
senderSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (senderSocket == -1)
return -3;
int replySocket;
if (listenSocket == -1) {
struct sockaddr_in si_me;
if ((listenSocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
struct sockaddr_in6 si_me;
if ((listenSocket=socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP))==-1) {
listenSocket = -1;
return -1;
}
replySocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
replySocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if (replySocket == -1)
{
close(listenSocket);
return -1;
}
int sockopt = 1;
setsockopt(listenSocket, IPPROTO_IP, DSTADDR_SOCKOPT, &sockopt, sizeof sockopt);
setsockopt(listenSocket, IPPROTO_IPV6, DSTADDR_SOCKOPT, &sockopt, sizeof sockopt);
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;
si_me.sin6_family = AF_INET6;
si_me.sin6_port = htons(opt->port);
inet_pton(AF_INET6, opt->addr, &si_me.sin6_addr);
if (bind(listenSocket, (struct sockaddr*)&si_me, sizeof(si_me))==-1)
return -2;
}
@ -428,7 +449,7 @@ int dnsserver(dns_opt_t *opt) {
for (; 1; ++(opt->nRequests))
{
ssize_t insize = recvmsg(listenSocket, &msg, 0);
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);
if (insize <= 0)
continue;

13
dns.h
View file

@ -3,26 +3,27 @@
#include <stdint.h>
typedef struct {
struct addr_t {
int v;
union {
unsigned char v4[4];
unsigned char v6[16];
} data;
} addr_t;
};
typedef struct {
struct dns_opt_t {
int port;
int datattl;
int nsttl;
const char *host;
const char *addr;
const char *ns;
const char *mbox;
int (*cb)(void *opt, addr_t *addr, int max, int ipv4, int ipv6);
int (*cb)(void *opt, char *requested_hostname, addr_t *addr, int max, int ipv4, int ipv6);
// stats
uint64_t nRequests;
} dns_opt_t;
};
extern int dnsserver(dns_opt_t *opt);
int dnsserver(dns_opt_t *opt);
#endif

190
main.cpp
View file

@ -7,6 +7,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <atomic>
#include "bitcoin.h"
#include "db.h"
@ -27,13 +28,15 @@ public:
const char *ns;
const char *host;
const char *tor;
const char *ip_addr;
const char *ipv4_proxy;
const char *ipv6_proxy;
std::set<uint64_t> filter_whitelist;
CDnsSeedOpts() : nThreads(96), nDnsThreads(4), nPort(53), mbox(NULL), ns(NULL), host(NULL), tor(NULL), fUseTestNet(false), fWipeBan(false), fWipeIgnore(false) {}
CDnsSeedOpts() : nThreads(96), nDnsThreads(4), ip_addr("::"), nPort(53), mbox(NULL), ns(NULL), host(NULL), tor(NULL), fUseTestNet(false), fWipeBan(false), fWipeIgnore(false), ipv4_proxy(NULL), ipv6_proxy(NULL) {}
void ParseCommandLine(int argc, char **argv) {
static const char *help = "Bitcoin-seeder\n"
static const char *help = "LBRY-seeder\n"
"Usage: %s -h <host> -n <ns> [-m <mbox>] [-t <threads>] [-p <port>]\n"
"\n"
"Options:\n"
@ -42,10 +45,12 @@ public:
"-m <mbox> E-Mail address reported in SOA records\n"
"-t <threads> Number of crawlers to run in parallel (default 96)\n"
"-d <threads> Number of DNS server threads (default 4)\n"
"-a <address> Address to listen on (default ::)\n"
"-p <port> UDP port to listen on (default 53)\n"
"-o <ip:port> Tor proxy IP/Port\n"
"-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"
"--testnet Use testnet\n"
"--wipeban Wipe list of banned nodes\n"
"--wipeignore Wipe list of ignored nodes\n"
@ -60,10 +65,12 @@ public:
{"mbox", required_argument, 0, 'm'},
{"threads", required_argument, 0, 't'},
{"dnsthreads", required_argument, 0, 'd'},
{"address", required_argument, 0, 'a'},
{"port", required_argument, 0, 'p'},
{"onion", required_argument, 0, 'o'},
{"proxyipv4", required_argument, 0, 'i'},
{"proxyipv6", required_argument, 0, 'k'},
{"filter", required_argument, 0, 'w'},
{"testnet", no_argument, &fUseTestNet, 1},
{"wipeban", no_argument, &fWipeBan, 1},
{"wipeignore", no_argument, &fWipeBan, 1},
@ -71,24 +78,24 @@ public:
{0, 0, 0, 0}
};
int option_index = 0;
int c = getopt_long(argc, argv, "h:n:m:t:p:d:o:i:k:", long_options, &option_index);
int c = getopt_long(argc, argv, "h:n:m:t:a:p:d:o:i:k:w:?", long_options, &option_index);
if (c == -1) break;
switch (c) {
case 'h': {
host = optarg;
break;
}
case 'm': {
mbox = optarg;
break;
}
case 'n': {
ns = optarg;
break;
}
case 't': {
int n = strtol(optarg, NULL, 10);
if (n > 0 && n < 1000) nThreads = n;
@ -101,6 +108,18 @@ public:
break;
}
case 'a': {
if (strchr(optarg, ':')==NULL) {
char* ip4_addr = (char*) malloc(strlen(optarg)+8);
strcpy(ip4_addr, "::FFFF:");
strcat(ip4_addr, optarg);
ip_addr = ip4_addr;
} else {
ip_addr = optarg;
}
break;
}
case 'p': {
int p = strtol(optarg, NULL, 10);
if (p > 0 && p < 65536) nPort = p;
@ -122,20 +141,44 @@ public:
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()) {
filter_whitelist.insert(NODE_NETWORK); // x1
filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); // x5
filter_whitelist.insert(NODE_NETWORK | NODE_WITNESS); // x9
filter_whitelist.insert(NODE_NETWORK | NODE_WITNESS | NODE_COMPACT_FILTERS); // x49
filter_whitelist.insert(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM); // xd
filter_whitelist.insert(NODE_NETWORK_LIMITED); // x400
filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_BLOOM); // x404
filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_WITNESS); // x408
filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_WITNESS | NODE_COMPACT_FILTERS); // x448
filter_whitelist.insert(NODE_NETWORK_LIMITED | NODE_WITNESS | NODE_BLOOM); // x40c
}
if (host != NULL && ns == NULL) showHelp = true;
if (showHelp) fprintf(stderr, help, argv[0]);
}
};
extern "C" {
#include "dns.h"
}
CAddrDb db;
@ -159,42 +202,51 @@ extern "C" void* ThreadCrawler(void* data) {
res.nClientV = 0;
res.nHeight = 0;
res.strClientV = "";
bool getaddr = res.ourLastSuccess + 604800 < now;
res.fGood = TestNode(res.service,res.nBanTime,res.nClientV,res.strClientV,res.nHeight,getaddr ? &addr : NULL);
res.services = 0;
bool getaddr = res.ourLastSuccess + 86400 < now;
res.fGood = TestNode(res.service,res.nBanTime,res.nClientV,res.strClientV,res.nHeight,getaddr ? &addr : NULL, res.services);
}
db.ResultMany(ips);
db.Add(addr);
} while(1);
return nullptr;
}
extern "C" int GetIPList(void *thread, addr_t *addr, int max, int ipv4, int ipv6);
extern "C" int GetIPList(void *thread, char *requestedHostname, addr_t *addr, int max, int ipv4, int ipv6);
class CDnsThread {
public:
struct FlagSpecificData {
int nIPv4, nIPv6;
std::vector<addr_t> cache;
time_t cacheTime;
unsigned int cacheHits;
FlagSpecificData() : nIPv4(0), nIPv6(0), cacheTime(0), cacheHits(0) {}
};
dns_opt_t dns_opt; // must be first
const int id;
vector<addr_t> cache;
int nIPv4, nIPv6;
time_t cacheTime;
unsigned int cacheHits;
uint64_t dbQueries;
std::map<uint64_t, FlagSpecificData> perflag;
std::atomic<uint64_t> dbQueries;
std::set<uint64_t> filterWhitelist;
void cacheHit(bool force = false) {
void cacheHit(uint64_t requestedFlags, bool force = false) {
static bool nets[NET_MAX] = {};
if (!nets[NET_IPV4]) {
nets[NET_IPV4] = true;
nets[NET_IPV6] = true;
}
time_t now = time(NULL);
cacheHits++;
if (force || cacheHits > (cache.size()*cache.size()/400) || (cacheHits*cacheHits > cache.size() / 20 && (now - cacheTime > 5))) {
FlagSpecificData& thisflag = perflag[requestedFlags];
thisflag.cacheHits++;
if (force || thisflag.cacheHits * 400 > (thisflag.cache.size()*thisflag.cache.size()) || (thisflag.cacheHits*thisflag.cacheHits * 20 > thisflag.cache.size() && (now - thisflag.cacheTime > 5))) {
set<CNetAddr> ips;
db.GetIPs(ips, 1000, nets);
db.GetIPs(ips, requestedFlags, 1000, nets);
dbQueries++;
cache.clear();
nIPv4 = 0;
nIPv6 = 0;
cache.reserve(ips.size());
thisflag.cache.clear();
thisflag.nIPv4 = 0;
thisflag.nIPv6 = 0;
thisflag.cache.reserve(ips.size());
for (set<CNetAddr>::iterator it = ips.begin(); it != ips.end(); it++) {
struct in_addr addr;
struct in6_addr addr6;
@ -202,20 +254,18 @@ public:
addr_t a;
a.v = 4;
memcpy(&a.data.v4, &addr, 4);
cache.push_back(a);
nIPv4++;
#ifdef USE_IPV6
thisflag.cache.push_back(a);
thisflag.nIPv4++;
} else if ((*it).GetIn6Addr(&addr6)) {
addr_t a;
a.v = 6;
memcpy(&a.data.v6, &addr6, 16);
cache.push_back(a);
nIPv6++;
#endif
thisflag.cache.push_back(a);
thisflag.nIPv6++;
}
}
cacheHits = 0;
cacheTime = now;
thisflag.cacheHits = 0;
thisflag.cacheTime = now;
}
}
@ -226,16 +276,12 @@ public:
dns_opt.datattl = 3600;
dns_opt.nsttl = 40000;
dns_opt.cb = GetIPList;
dns_opt.addr = opts->ip_addr;
dns_opt.port = opts->nPort;
dns_opt.nRequests = 0;
cache.clear();
cache.reserve(1000);
cacheTime = 0;
cacheHits = 0;
dbQueries = 0;
nIPv4 = 0;
nIPv6 = 0;
cacheHit(true);
perflag.clear();
filterWhitelist = opts->filter_whitelist;
}
void run() {
@ -243,11 +289,25 @@ public:
}
};
extern "C" int GetIPList(void *data, addr_t* addr, int max, int ipv4, int ipv6) {
extern "C" int GetIPList(void *data, char *requestedHostname, addr_t* addr, int max, int ipv4, int ipv6) {
CDnsThread *thread = (CDnsThread*)data;
thread->cacheHit();
unsigned int size = thread->cache.size();
unsigned int maxmax = (ipv4 ? thread->nIPv4 : 0) + (ipv6 ? thread->nIPv6 : 0);
uint64_t requestedFlags = 0;
int hostlen = strlen(requestedHostname);
if (hostlen > 1 && requestedHostname[0] == 'x' && requestedHostname[1] != '0') {
char *pEnd;
uint64_t flags = (uint64_t)strtoull(requestedHostname+1, &pEnd, 16);
if (*pEnd == '.' && pEnd <= requestedHostname+17 && std::find(thread->filterWhitelist.begin(), thread->filterWhitelist.end(), flags) != thread->filterWhitelist.end())
requestedFlags = flags;
else
return 0;
}
else if (strcasecmp(requestedHostname, thread->dns_opt.host))
return 0;
thread->cacheHit(requestedFlags);
auto& thisflag = thread->perflag[requestedFlags];
unsigned int size = thisflag.cache.size();
unsigned int maxmax = (ipv4 ? thisflag.nIPv4 : 0) + (ipv6 ? thisflag.nIPv6 : 0);
if (max > size)
max = size;
if (max > maxmax)
@ -256,16 +316,16 @@ extern "C" int GetIPList(void *data, addr_t* addr, int max, int ipv4, int ipv6)
while (i<max) {
int j = i + (rand() % (size - i));
do {
bool ok = (ipv4 && thread->cache[j].v == 4) ||
(ipv6 && thread->cache[j].v == 6);
bool ok = (ipv4 && thisflag.cache[j].v == 4) ||
(ipv6 && thisflag.cache[j].v == 6);
if (ok) break;
j++;
if (j==size)
j=i;
} while(1);
addr[i] = thread->cache[j];
thread->cache[j] = thread->cache[i];
thread->cache[i] = addr[i];
addr[i] = thisflag.cache[j];
thisflag.cache[j] = thisflag.cache[i];
thisflag.cache[i] = addr[i];
i++;
}
return max;
@ -276,6 +336,7 @@ vector<CDnsThread*> dnsThread;
extern "C" void* ThreadDNS(void* arg) {
CDnsThread *thread = (CDnsThread*)arg;
thread->run();
return nullptr;
}
int StatCompare(const CAddrReport& a, const CAddrReport& b) {
@ -312,7 +373,7 @@ extern "C" void* ThreadDumper(void*) {
double stat[5]={0,0,0,0,0};
for (vector<CAddrReport>::const_iterator it = v.begin(); it < v.end(); it++) {
CAddrReport rep = *it;
fprintf(d, "%-47s %4d %11"PRId64" %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08"PRIx64" %5i \"%s\"\n", rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, 100.0*rep.uptime[0], 100.0*rep.uptime[1], 100.0*rep.uptime[2], 100.0*rep.uptime[3], 100.0*rep.uptime[4], rep.blocks, rep.services, rep.clientVersion, rep.clientSubVersion.c_str());
fprintf(d, "%-47s %4d %11" PRId64 " %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64 " %5i \"%s\"\n", rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, 100.0*rep.uptime[0], 100.0*rep.uptime[1], 100.0*rep.uptime[2], 100.0*rep.uptime[3], 100.0*rep.uptime[4], rep.blocks, rep.services, rep.clientVersion, rep.clientSubVersion.c_str());
stat[0] += rep.uptime[0];
stat[1] += rep.uptime[1];
stat[2] += rep.uptime[2];
@ -325,6 +386,7 @@ extern "C" void* ThreadDumper(void*) {
fclose(ff);
}
} while(1);
return nullptr;
}
extern "C" void* ThreadStats(void*) {
@ -353,13 +415,12 @@ extern "C" void* ThreadStats(void*) {
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);
} while(1);
return nullptr;
}
static const string mainnet_seeds[] = {"dnsseed.bluematt.me", "bitseed.xf2.org", "dnsseed.bitcoin.dashjr.org", "seed.bitcoin.sipa.be", ""};
static const string testnet_seeds[] = {"testnet-seed.alexykot.me",
"testnet-seed.bitcoin.petertodd.org",
"testnet-seed.bluematt.me",
"testnet-seed.bitcoin.schildbach.de",
static const string mainnet_seeds[] = {"dnsseed1.lbry.io", "dnsseed2.lbry.io", "dnsseed3.lbry.io", ""};
static const string testnet_seeds[] = {"testdnsseed1.lbry.io",
"testdnsseed2.lbry.io",
""};
static const string *seeds = mainnet_seeds;
@ -377,6 +438,7 @@ extern "C" void* ThreadSeeder(void*) {
}
Sleep(1800000);
} while(1);
return nullptr;
}
int main(int argc, char **argv) {
@ -384,6 +446,14 @@ int main(int argc, char **argv) {
setbuf(stdout, NULL);
CDnsSeedOpts opts;
opts.ParseCommandLine(argc, argv);
printf("Supporting whitelisted filters: ");
for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin(); it != opts.filter_whitelist.end(); it++) {
if (it != opts.filter_whitelist.begin()) {
printf(",");
}
printf("0x%lx", (unsigned long)*it);
}
printf("\n");
if (opts.tor) {
CService service(opts.tor, 9050);
if (service.IsValid()) {
@ -408,10 +478,10 @@ int main(int argc, char **argv) {
bool fDNS = true;
if (opts.fUseTestNet) {
printf("Using testnet.\n");
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
pchMessageStart[2] = 0x09;
pchMessageStart[3] = 0x07;
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xe4;
pchMessageStart[2] = 0xaa;
pchMessageStart[3] = 0xe1;
seeds = testnet_seeds;
fTestNet = true;
}
@ -423,6 +493,10 @@ int main(int argc, char **argv) {
fprintf(stderr, "No hostname set. Please use -h.\n");
exit(1);
}
if (fDNS && !opts.mbox) {
fprintf(stderr, "No e-mail address set. Please use -m.\n");
exit(1);
}
FILE *f = fopen("dnsseed.dat","r");
if (f) {
printf("Loading dnsseed.dat...");

View file

@ -74,18 +74,10 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
aiHint.ai_socktype = SOCK_STREAM;
aiHint.ai_protocol = IPPROTO_TCP;
#ifdef WIN32
# ifdef USE_IPV6
aiHint.ai_family = AF_UNSPEC;
# else
aiHint.ai_family = AF_INET;
# endif
aiHint.ai_flags = fAllowLookup ? 0 : AI_NUMERICHOST;
#else
# ifdef USE_IPV6
aiHint.ai_family = AF_UNSPEC;
# else
aiHint.ai_family = AF_INET;
# endif
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
#endif
struct addrinfo *aiRes = NULL;
@ -102,13 +94,11 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
vIP.push_back(CNetAddr(((struct sockaddr_in*)(aiTrav->ai_addr))->sin_addr));
}
#ifdef USE_IPV6
if (aiTrav->ai_family == AF_INET6)
{
assert(aiTrav->ai_addrlen >= sizeof(sockaddr_in6));
vIP.push_back(CNetAddr(((struct sockaddr_in6*)(aiTrav->ai_addr))->sin6_addr));
}
#endif
aiTrav = aiTrav->ai_next;
}
@ -323,11 +313,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
{
hSocketRet = INVALID_SOCKET;
#ifdef USE_IPV6
struct sockaddr_storage sockaddr;
#else
struct sockaddr sockaddr;
#endif
socklen_t len = sizeof(sockaddr);
if (!addrConnect.GetSockAddr((struct sockaddr*)&sockaddr, &len)) {
printf("Cannot connect to %s: unsupported network\n", addrConnect.ToString().c_str());
@ -578,12 +564,10 @@ CNetAddr::CNetAddr(const struct in_addr& ipv4Addr)
memcpy(ip+12, &ipv4Addr, 4);
}
#ifdef USE_IPV6
CNetAddr::CNetAddr(const struct in6_addr& ipv6Addr)
{
memcpy(ip, &ipv6Addr, 16);
}
#endif
CNetAddr::CNetAddr(const char *pszIp, bool fAllowLookup)
{
@ -772,11 +756,7 @@ std::string CNetAddr::ToStringIP() const
if (IsI2P())
return EncodeBase32(&ip[6], 10) + ".oc.b32.i2p";
CService serv(*this, 0);
#ifdef USE_IPV6
struct sockaddr_storage sockaddr;
#else
struct sockaddr sockaddr;
#endif
socklen_t socklen = sizeof(sockaddr);
if (serv.GetSockAddr((struct sockaddr*)&sockaddr, &socklen)) {
char name[1025] = "";
@ -821,13 +801,11 @@ bool CNetAddr::GetInAddr(struct in_addr* pipv4Addr) const
return true;
}
#ifdef USE_IPV6
bool CNetAddr::GetIn6Addr(struct in6_addr* pipv6Addr) const
{
memcpy(pipv6Addr, ip, 16);
return true;
}
#endif
// get canonical identifier of an address' group
// no two connections will be attempted to addresses with the same group
@ -1013,23 +991,19 @@ CService::CService(const struct in_addr& ipv4Addr, unsigned short portIn) : CNet
{
}
#ifdef USE_IPV6
CService::CService(const struct in6_addr& ipv6Addr, unsigned short portIn) : CNetAddr(ipv6Addr), port(portIn)
{
}
#endif
CService::CService(const struct sockaddr_in& addr) : CNetAddr(addr.sin_addr), port(ntohs(addr.sin_port))
{
assert(addr.sin_family == AF_INET);
}
#ifdef USE_IPV6
CService::CService(const struct sockaddr_in6 &addr) : CNetAddr(addr.sin6_addr), port(ntohs(addr.sin6_port))
{
assert(addr.sin6_family == AF_INET6);
}
#endif
bool CService::SetSockAddr(const struct sockaddr *paddr)
{
@ -1037,11 +1011,9 @@ bool CService::SetSockAddr(const struct sockaddr *paddr)
case AF_INET:
*this = CService(*(const struct sockaddr_in*)paddr);
return true;
#ifdef USE_IPV6
case AF_INET6:
*this = CService(*(const struct sockaddr_in6*)paddr);
return true;
#endif
default:
return false;
}
@ -1113,7 +1085,6 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
paddrin->sin_port = htons(port);
return true;
}
#ifdef USE_IPV6
if (IsIPv6()) {
if (*addrlen < (socklen_t)sizeof(struct sockaddr_in6))
return false;
@ -1126,7 +1097,6 @@ bool CService::GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const
paddrin6->sin6_port = htons(port);
return true;
}
#endif
return false;
}

View file

@ -74,10 +74,8 @@ class CNetAddr
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const;
void print() const;
#ifdef USE_IPV6
CNetAddr(const struct in6_addr& pipv6Addr);
bool GetIn6Addr(struct in6_addr* pipv6Addr) const;
#endif
friend bool operator==(const CNetAddr& a, const CNetAddr& b);
friend bool operator!=(const CNetAddr& a, const CNetAddr& b);
@ -118,10 +116,8 @@ class CService : public CNetAddr
std::string ToStringIPPort() const;
void print() const;
#ifdef USE_IPV6
CService(const struct in6_addr& ipv6Addr, unsigned short port);
CService(const struct sockaddr_in6& addr);
#endif
IMPLEMENT_SERIALIZE
(

View file

@ -22,7 +22,7 @@ static const char* ppszTypeName[] =
"block",
};
unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
unsigned char pchMessageStart[4] = { 0xfa, 0xe4, 0xaa, 0xf1 };
CMessageHeader::CMessageHeader()
{
@ -36,7 +36,9 @@ CMessageHeader::CMessageHeader()
CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
{
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
strncpy(pchCommand, pszCommand, COMMAND_SIZE);
size_t command_len = strnlen(pszCommand, COMMAND_SIZE);
memcpy(pchCommand, pszCommand, command_len);
memset(pchCommand + command_len, 0, COMMAND_SIZE - command_len);
nMessageSize = nMessageSizeIn;
nChecksum = 0;
}

View file

@ -18,7 +18,7 @@
extern bool fTestNet;
static inline unsigned short GetDefaultPort(const bool testnet = fTestNet)
{
return testnet ? 18333 : 8333;
return testnet ? 19246 : 9246;
}
//
@ -44,7 +44,7 @@ class CMessageHeader
READWRITE(FLATDATA(pchMessageStart));
READWRITE(FLATDATA(pchCommand));
READWRITE(nMessageSize);
if (nVersion >= 209)
if (nVersion >= 1)
READWRITE(nChecksum);
)
@ -60,6 +60,10 @@ class CMessageHeader
enum
{
NODE_NETWORK = (1 << 0),
NODE_BLOOM = (1 << 2),
NODE_WITNESS = (1 << 3),
NODE_COMPACT_FILTERS = (1 << 6),
NODE_NETWORK_LIMITED = (1 << 10),
};
class CAddress : public CService

128
readme.md Normal file
View file

@ -0,0 +1,128 @@
# seeder
seeder is a crawler for the LBRY network, which exposes a list
of reliable nodes via a built-in DNS server.
Features:
* regularly revisits known nodes to check their availability
* bans nodes after enough failures, or bad behaviour
* accepts nodes down to v0.3.19 to request new IP addresses from,
but only reports good post-v0.3.24 nodes.
* keeps statistics over (exponential) windows of 2 hours, 8 hours,
1 day and 1 week, to base decisions on.
* very low memory (a few tens of megabytes) and cpu requirements.
* crawlers run in parallel (by default 24 threads simultaneously).
## Build
```
sudo apt-get install build-essential libboost-dev libssl-dev
make
```
## Use
Assumptions:
- lbrycrd will use the domain `seed.example.com` to find peer nodes
- you will be running this seeder on a server at domain `vps.example.com`
### Configure DNS
You will need two DNS records:
type | name | value
-----|------------------| ---------------
NS | seed.example.com | vps.example.com
A | vps.example.com | 1.2.3.4
Test your DNS records
```
$ dig -t NS seed.example.com
;; ANSWER SECTION
seed.example.com. 86400 IN NS vps.example.com.
```
### Disable systemd resolver (Ubuntu 18.04+)
You only need this if you want to run the seeder on port 53 and it's taken by
Ubuntu's resolved. Run the following to turn the resolver off and prevent
it from starting on reboot
```
sudo systemctl stop systemd-resolved.service
sudo systemctl disable systemd-resolved.service
```
### Open firewall port
For example, if using UFW, run `ufw allow 53`. Some VPS providers also
have their own firewall that you'll need to configure.
### Run the seeder
On the system vps.example.com, you can now run dnsseed:
```
./dnsseed -h seed.example.com -n vps.example.com
```
If you want the DNS server to report SOA records, please provide an
e-mail address (with the @ part replaced by .) using `-m`.
### Running as non-root
Typically, you'll need root privileges to listen to port 53 (name service).
One solution is using an iptables rule (Linux only) to redirect it to
a non-privileged port:
```
iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-port 5353
```
If properly configured, this will allow you to run dnsseed in userspace, using
the -p 5353 option.
Another solution is allowing a binary to bind to ports < 1024 with setcap (IPv6 access-safe)
```
setcap 'cap_net_bind_service=+ep' /path/to/dnsseed
```
## Debugging
### Server-side
On the server, run `sudo tcpdump port 53`. This will show you all traffic on port 53. As
you send DNS queries, you should see `A` requests come in and response IPs go out.
- no incoming responses: DNS or firewall issues, or DNS request is cached client-side
- no responses: seeder is not running, or running on the wrong port, or broken
- empty responses: requested domain doesn't match configured domain in seeder
You can also look at the output of the running seeder. It looks like this
```
[21-04-12 19:30:49] 28/104 available (104 tried in 994s, 1 new, 30 active), 0 banned; 38 DNS requests, 1 db queries
```
- if # of DNS requests is not going up as you send them, then seeder is not getting your requests
- if DNS requests are increasing but db queries are not, then the -h domain doesn't match
- if seeder didn't find any nodes, then it can't contact the nodes it itself is seeded with
### Client-side
Try `dig +short seed.example.com`. If you get node IPs, your setup is working.
Other things to try
- `dig @1.2.3.4 seed.example.com` to bypass local DNS cache or incorrect DNS records
- `dig +trace seed.example.com` for detailed routing info

View file

@ -60,7 +60,7 @@ class CDataStream;
class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000;
static const int PROTOCOL_VERSION = 60000;
static const int PROTOCOL_VERSION = 70015;
// Used to bypass the rule against non-const reference to temporary
// where it makes sense with wrappers such as CFlatData or CTxDB

148
uint256.h
View file

@ -22,11 +22,6 @@ typedef unsigned long long uint64;
#define for if (false) ; else for
#endif
inline int Testuint256AdHoc(std::vector<std::string> vArg);
// We have to keep a separate base class without constructors
// so the compiler will let us use it in a union
template<unsigned int BITS>
@ -322,7 +317,7 @@ public:
// hex string to uint
static char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
const char* pbegin = psz;
while (phexdigit[*psz] || *psz == '0')
while (phexdigit[(unsigned char)*psz] || *psz == '0')
psz++;
psz--;
unsigned char* p1 = (unsigned char*)pn;
@ -622,145 +617,4 @@ inline const uint256 operator|(const uint256& a, const uint256& b) { return
inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; }
inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; }
inline int Testuint256AdHoc(std::vector<std::string> vArg)
{
uint256 g(0);
printf("%s\n", g.ToString().c_str());
g--; printf("g--\n");
printf("%s\n", g.ToString().c_str());
g--; printf("g--\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
g++; printf("g++\n");
printf("%s\n", g.ToString().c_str());
uint256 a(7);
printf("a=7\n");
printf("%s\n", a.ToString().c_str());
uint256 b;
printf("b undefined\n");
printf("%s\n", b.ToString().c_str());
int c = 3;
a = c;
a.pn[3] = 15;
printf("%s\n", a.ToString().c_str());
uint256 k(c);
a = 5;
a.pn[3] = 15;
printf("%s\n", a.ToString().c_str());
b = 1;
b <<= 52;
a |= b;
a ^= 0x500;
printf("a %s\n", a.ToString().c_str());
a = a | b | (uint256)0x1000;
printf("a %s\n", a.ToString().c_str());
printf("b %s\n", b.ToString().c_str());
a = 0xfffffffe;
a.pn[4] = 9;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a++;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
uint256 d = a--;
printf("%s\n", d.ToString().c_str());
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
a--;
printf("%s\n", a.ToString().c_str());
d = a;
printf("%s\n", d.ToString().c_str());
for (int i = uint256::WIDTH-1; i >= 0; i--) printf("%08x", d.pn[i]); printf("\n");
uint256 neg = d;
neg = ~neg;
printf("%s\n", neg.ToString().c_str());
uint256 e = uint256("0xABCDEF123abcdef12345678909832180000011111111");
printf("\n");
printf("%s\n", e.ToString().c_str());
printf("\n");
uint256 x1 = uint256("0xABCDEF123abcdef12345678909832180000011111111");
uint256 x2;
printf("%s\n", x1.ToString().c_str());
for (int i = 0; i < 270; i += 4)
{
x2 = x1 << i;
printf("%s\n", x2.ToString().c_str());
}
printf("\n");
printf("%s\n", x1.ToString().c_str());
for (int i = 0; i < 270; i += 4)
{
x2 = x1;
x2 >>= i;
printf("%s\n", x2.ToString().c_str());
}
for (int i = 0; i < 100; i++)
{
uint256 k = (~uint256(0) >> i);
printf("%s\n", k.ToString().c_str());
}
for (int i = 0; i < 100; i++)
{
uint256 k = (~uint256(0) << i);
printf("%s\n", k.ToString().c_str());
}
return (0);
}
#endif

2
util.h
View file

@ -82,7 +82,7 @@ void static inline Sleep(int nMilliSec) {
std::string vstrprintf(const std::string &format, va_list ap);
std::string static inline strprintf(const std::string &format, ...) {
std::string static inline strprintf(const std::string format, ...) {
va_list arg_ptr;
va_start(arg_ptr, format);
std::string ret = vstrprintf(format, arg_ptr);