Madbuda
7 years ago
commit
cd47f66c1e
22 changed files with 6212 additions and 0 deletions
@ -0,0 +1,6 @@ |
|||
*.o |
|||
dnsseed* |
|||
dnsstats.log |
|||
.idea/ |
|||
cmake-build-debug/ |
|||
dnsseed |
@ -0,0 +1,20 @@ |
|||
CXXFLAGS = -O3 -g0 -march=native |
|||
LDFLAGS = $(CXXFLAGS) |
|||
|
|||
COMMIT_HASH=`git rev-parse --short HEAD 2>/dev/null` |
|||
BUILD_DATE=`date +%FT%T%z` |
|||
|
|||
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++ -pthread $(CXXFLAGS) -Wno-invalid-offsetof -c -o $@ $< |
|||
|
|||
dns.o: dns.c |
|||
gcc -pthread -std=c99 $(CXXFLAGS) dns.c -c -o dns.o |
|||
|
|||
%.o: %.cpp |
|||
|
|||
help: |
|||
echo ${COMMIT_HASH} |
|||
echo ${BUILD_DATE} |
@ -0,0 +1,60 @@ |
|||
hush-seeder |
|||
============== |
|||
|
|||
Hush-seeder is a crawler for the Hush 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 |
|||
* 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-mail address (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. |
@ -0,0 +1,309 @@ |
|||
#include <algorithm> |
|||
|
|||
#include "db.h" |
|||
#include "netbase.h" |
|||
#include "protocol.h" |
|||
#include "serialize.h" |
|||
#include "uint256.h" |
|||
|
|||
#define BITCOIN_SEED_NONCE 0x0539a019ca550825ULL |
|||
|
|||
using namespace std; |
|||
|
|||
class CNode { |
|||
SOCKET sock; |
|||
CDataStream vSend; |
|||
CDataStream vRecv; |
|||
unsigned int nHeaderStart; |
|||
unsigned int nMessageStart; |
|||
int nVersion; |
|||
string strSubVer; |
|||
int nStartingHeight; |
|||
vector<CAddress> *vAddr; |
|||
int ban; |
|||
int64 doneAfter; |
|||
CAddress you; |
|||
|
|||
int GetTimeout() { |
|||
if (you.IsTor()) |
|||
return 120; |
|||
else |
|||
return 30; |
|||
} |
|||
|
|||
void BeginMessage(const char *pszCommand) { |
|||
if (nHeaderStart != -1) AbortMessage(); |
|||
nHeaderStart = vSend.size(); |
|||
vSend << CMessageHeader(pszCommand, 0); |
|||
nMessageStart = vSend.size(); |
|||
// 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; |
|||
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize)); |
|||
if (vSend.GetVersion() >= 209) { |
|||
uint256 hash = Hash(vSend.begin() + nMessageStart, vSend.end()); |
|||
unsigned int nChecksum = 0; |
|||
memcpy(&nChecksum, &hash, sizeof(nChecksum)); |
|||
assert(nMessageStart - nHeaderStart >= offsetof(CMessageHeader, nChecksum) + sizeof(nChecksum)); |
|||
memcpy((char*)&vSend[nHeaderStart] + offsetof(CMessageHeader, nChecksum), &nChecksum, sizeof(nChecksum)); |
|||
} |
|||
nHeaderStart = -1; |
|||
nMessageStart = -1; |
|||
} |
|||
|
|||
void Send() { |
|||
if (sock == INVALID_SOCKET) return; |
|||
if (vSend.empty()) return; |
|||
int nBytes = send(sock, &vSend[0], vSend.size(), 0); |
|||
if (nBytes > 0) { |
|||
vSend.erase(vSend.begin(), vSend.begin() + nBytes); |
|||
} else { |
|||
close(sock); |
|||
sock = INVALID_SOCKET; |
|||
} |
|||
} |
|||
|
|||
void PushVersion() { |
|||
int64 nTime = time(NULL); |
|||
uint64 nLocalNonce = BITCOIN_SEED_NONCE; |
|||
int64 nLocalServices = 0; |
|||
CAddress me(CService("0.0.0.0")); |
|||
BeginMessage("version"); |
|||
int nBestHeight = GetRequireHeight(); |
|||
string ver = "/hush-seeder:0.01/"; |
|||
vSend << PROTOCOL_VERSION << nLocalServices << nTime << you << me << nLocalNonce << ver << nBestHeight; |
|||
EndMessage(); |
|||
} |
|||
|
|||
void GotVersion() { |
|||
// printf("\n%s: version %i\n", ToString(you).c_str(), nVersion);
|
|||
if (vAddr) { |
|||
BeginMessage("getaddr"); |
|||
EndMessage(); |
|||
doneAfter = time(NULL) + GetTimeout(); |
|||
} else { |
|||
doneAfter = time(NULL) + 1; |
|||
} |
|||
} |
|||
|
|||
bool ProcessMessage(string strCommand, CDataStream& vRecv) { |
|||
// printf("%s: RECV %s\n", ToString(you).c_str(), strCommand.c_str());
|
|||
if (strCommand == "version") { |
|||
int64 nTime; |
|||
CAddress addrMe; |
|||
CAddress addrFrom; |
|||
uint64 nNonce = 1; |
|||
vRecv >> nVersion >> you.nServices >> nTime >> addrMe; |
|||
if (nVersion == 10300) nVersion = 300; |
|||
if (nVersion >= 106 && !vRecv.empty()) |
|||
vRecv >> addrFrom >> nNonce; |
|||
if (nVersion >= 106 && !vRecv.empty()) |
|||
vRecv >> strSubVer; |
|||
if (nVersion >= 209 && !vRecv.empty()) |
|||
vRecv >> nStartingHeight; |
|||
|
|||
if (nVersion >= 209) { |
|||
BeginMessage("verack"); |
|||
EndMessage(); |
|||
} |
|||
vSend.SetVersion(min(nVersion, PROTOCOL_VERSION)); |
|||
if (nVersion < 209) { |
|||
this->vRecv.SetVersion(min(nVersion, PROTOCOL_VERSION)); |
|||
GotVersion(); |
|||
} |
|||
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 (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()));
|
|||
it++; |
|||
if (addr.nTime <= 100000000 || addr.nTime > now + 600) |
|||
addr.nTime = now - 5 * 86400; |
|||
if (addr.nTime > now - 604800) |
|||
vAddr->push_back(addr); |
|||
// printf("%s: added address %s (#%i)\n", ToString(you).c_str(), addr.ToString().c_str(), (int)(vAddr->size()));
|
|||
if (vAddr->size() > 1000) {doneAfter = 1; return true; } |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
bool ProcessMessages() { |
|||
if (vRecv.empty()) return false; |
|||
do { |
|||
CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart)); |
|||
int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader()); |
|||
if (vRecv.end() - pstart < nHeaderSize) { |
|||
if (vRecv.size() > nHeaderSize) { |
|||
vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize); |
|||
} |
|||
break; |
|||
} |
|||
vRecv.erase(vRecv.begin(), pstart); |
|||
vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize); |
|||
CMessageHeader hdr; |
|||
vRecv >> hdr; |
|||
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) { |
|||
// printf("%s: BAD (message too large)\n", ToString(you).c_str());
|
|||
ban = 100000; |
|||
return true; |
|||
} |
|||
if (nMessageSize > vRecv.size()) { |
|||
vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end()); |
|||
break; |
|||
} |
|||
if (vRecv.GetVersion() >= 209) { |
|||
uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize); |
|||
unsigned int nChecksum = 0; |
|||
memcpy(&nChecksum, &hash, sizeof(nChecksum)); |
|||
if (nChecksum != hdr.nChecksum) continue; |
|||
} |
|||
CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion); |
|||
vRecv.ignore(nMessageSize); |
|||
if (ProcessMessage(strCommand, vMsg)) |
|||
return true; |
|||
// printf("%s: done processing %s\n", ToString(you).c_str(), strCommand.c_str());
|
|||
} 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); |
|||
vSend.SetVersion(0); |
|||
vRecv.SetType(SER_NETWORK); |
|||
vRecv.SetVersion(0); |
|||
if (time(NULL) > 1329696000) { |
|||
vSend.SetVersion(209); |
|||
vRecv.SetVersion(209); |
|||
} |
|||
} |
|||
bool Run() { |
|||
bool res = true; |
|||
if (!ConnectSocket(you, sock)) return false; |
|||
PushVersion(); |
|||
Send(); |
|||
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); |
|||
struct timeval wa; |
|||
if (doneAfter) { |
|||
wa.tv_sec = doneAfter - now; |
|||
wa.tv_usec = 0; |
|||
} else { |
|||
wa.tv_sec = GetTimeout(); |
|||
wa.tv_usec = 0; |
|||
} |
|||
int ret = select(sock+1, &set, NULL, &set, &wa); |
|||
if (ret != 1) { |
|||
if (!doneAfter) res = false; |
|||
break; |
|||
} |
|||
int nBytes = recv(sock, pchBuf, sizeof(pchBuf), 0); |
|||
int nPos = vRecv.size(); |
|||
if (nBytes > 0) { |
|||
vRecv.resize(nPos + nBytes); |
|||
memcpy(&vRecv[nPos], pchBuf, nBytes); |
|||
} else if (nBytes == 0) { |
|||
// printf("%s: BAD (connection closed prematurely)\n", ToString(you).c_str());
|
|||
res = false; |
|||
break; |
|||
} else { |
|||
// printf("%s: BAD (connection error)\n", ToString(you).c_str());
|
|||
res = false; |
|||
break; |
|||
} |
|||
ProcessMessages(); |
|||
Send(); |
|||
} |
|||
if (sock == INVALID_SOCKET) res = false; |
|||
close(sock); |
|||
sock = INVALID_SOCKET; |
|||
return (ban == 0) && res; |
|||
} |
|||
|
|||
int GetBan() { |
|||
return ban; |
|||
} |
|||
|
|||
int GetClientVersion() { |
|||
return nVersion; |
|||
} |
|||
|
|||
std::string GetClientSubVersion() { |
|||
return strSubVer; |
|||
} |
|||
|
|||
int GetStartingHeight() { |
|||
return nStartingHeight; |
|||
} |
|||
}; |
|||
|
|||
bool TestNode(const CService &cip, int &ban, int &clientV, std::string &clientSV, int &blocks, vector<CAddress>* vAddr) { |
|||
try { |
|||
CNode node(cip, vAddr); |
|||
bool ret = node.Run(); |
|||
if (!ret) { |
|||
ban = node.GetBan(); |
|||
} else { |
|||
ban = 0; |
|||
} |
|||
clientV = node.GetClientVersion(); |
|||
clientSV = node.GetClientSubVersion(); |
|||
blocks = node.GetStartingHeight(); |
|||
// printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD");
|
|||
return ret; |
|||
} catch(std::ios_base::failure& e) { |
|||
ban = 0; |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
int main(void) { |
|||
CService ip("bitcoin.sipa.be", 8333, true); |
|||
vector<CAddress> vAddr; |
|||
vAddr.clear(); |
|||
int ban = 0; |
|||
bool ret = TestNode(ip, ban, vAddr); |
|||
printf("ret=%s ban=%i vAddr.size()=%i\n", ret ? "good" : "bad", ban, (int)vAddr.size()); |
|||
} |
|||
*/ |
|||
|
@ -0,0 +1,8 @@ |
|||
#ifndef _BITCOIN_H_ |
|||
#define _BITCOIN_H_ 1 |
|||
|
|||
#include "protocol.h" |
|||
|
|||
bool TestNode(const CService &cip, int &ban, int &client, std::string &clientSV, int &blocks, std::vector<CAddress>* vAddr); |
|||
|
|||
#endif |
@ -0,0 +1,66 @@ |
|||
#!/usr/bin/perl -w |
|||
|
|||
use strict; |
|||
use warnings FATAL => 'all'; |
|||
|
|||
sub loadFile { |
|||
my ($file) = @_; |
|||
my %ret; |
|||
my $max = 0; |
|||
open FILE,$file; |
|||
while (<FILE>) { |
|||
my ($addr,$p2h,$p8h,$p1d,$p1w,$p1m) = split(/\s+/,$_); |
|||
if ($p1m =~ /\A([1-9.]+)%\Z/) { |
|||
my $x = $1*0.01; |
|||
$max=$x if ($x > $max); |
|||
$ret{$addr} = $x; |
|||
} |
|||
} |
|||
for my $k (keys %ret) { |
|||
$ret{$k} /= $max; |
|||
} |
|||
close FILE; |
|||
return \%ret; |
|||
} |
|||
|
|||
sub merge { |
|||
my ($a,$b) = @_; |
|||
return 1-(1-$a)*(1-$b); |
|||
} |
|||
|
|||
sub combine { |
|||
my ($f1,$f2) = @_; |
|||
my %ret; |
|||
for my $k1 (keys %{$f1}) { |
|||
if (defined $f2->{$k1}) { |
|||
$ret{$k1} = merge($f1->{$k1}, $f2->{$k1}); |
|||
} else { |
|||
$ret{$k1} = merge($f1->{$k1}, 0); |
|||
} |
|||
} |
|||
for my $k2 (keys %{$f2}) { |
|||
if (!defined $f1->{$k2}) { |
|||
$ret{$k2} = merge(0, $f2->{$k2}); |
|||
} |
|||
} |
|||
return \%ret; |
|||
} |
|||
|
|||
my $res; |
|||
my $n=0; |
|||
for my $file (@ARGV) { |
|||
my $r = loadFile($file); |
|||
if ($res) { |
|||
$res = combine($res,$r); |
|||
} else { |
|||
$res = $r; |
|||
} |
|||
$n++; |
|||
} |
|||
|
|||
for my $addr (sort { $res->{$b} <=> $res->{$a} } (keys %{$res})) { |
|||
if ($addr =~ /\A(\d+)\.(\d+)\.(\d+)\.(\d+):8333/) { |
|||
my $a = $1*0x1000000 + $2*0x10000 + $3*0x100 + $4; |
|||
printf "0x%08x %s %g%%\n",$a,$addr,(1-((1-$res->{$addr}) ** (1/$n)))*100; |
|||
} |
|||
} |
@ -0,0 +1,66 @@ |
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|||
// Copyright (c) 2009-2012 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
#ifndef _BITCOIN_COMPAT_H |
|||
#define _BITCOIN_COMPAT_H 1 |
|||
|
|||
#ifdef WIN32 |
|||
#define _WIN32_WINNT 0x0501 |
|||
#define WIN32_LEAN_AND_MEAN 1 |
|||
#ifndef NOMINMAX |
|||
#define NOMINMAX |
|||
#endif |
|||
#include <winsock2.h> |
|||
#include <mswsock.h> |
|||
#include <ws2tcpip.h> |
|||
#else |
|||
#include <sys/types.h> |
|||
#include <sys/socket.h> |
|||
#include <sys/fcntl.h> |
|||
#include <arpa/inet.h> |
|||
#include <netdb.h> |
|||
#include <net/if.h> |
|||
#include <netinet/in.h> |
|||
#include <ifaddrs.h> |
|||
#endif |
|||
|
|||
typedef u_int SOCKET; |
|||
#ifdef __APPLE__ |
|||
#define MSG_NOSIGNAL 0 |
|||
#endif |
|||
#ifdef WIN32 |
|||
#define MSG_NOSIGNAL 0 |
|||
#define MSG_DONTWAIT 0 |
|||
typedef int socklen_t; |
|||
#else |
|||
#include "errno.h" |
|||
#define WSAGetLastError() errno |
|||
#define WSAEINVAL EINVAL |
|||
#define WSAEALREADY EALREADY |
|||
#define WSAEWOULDBLOCK EWOULDBLOCK |
|||
#define WSAEMSGSIZE EMSGSIZE |
|||
#define WSAEINTR EINTR |
|||
#define WSAEINPROGRESS EINPROGRESS |
|||
#define WSAEADDRINUSE EADDRINUSE |
|||
#define WSAENOTSOCK EBADF |
|||
#define INVALID_SOCKET (SOCKET)(~0) |
|||
#define SOCKET_ERROR -1 |
|||
#endif |
|||
|
|||
inline int myclosesocket(SOCKET& hSocket) |
|||
{ |
|||
if (hSocket == INVALID_SOCKET) |
|||
return WSAENOTSOCK; |
|||
#ifdef WIN32 |
|||
int ret = closesocket(hSocket); |
|||
#else |
|||
int ret = close(hSocket); |
|||
#endif |
|||
hSocket = INVALID_SOCKET; |
|||
return ret; |
|||
} |
|||
#define closesocket(s) myclosesocket(s) |
|||
|
|||
|
|||
#endif |
@ -0,0 +1,206 @@ |
|||
#include "db.h" |
|||
#include <stdlib.h> |
|||
|
|||
using namespace std; |
|||
|
|||
void CAddrInfo::Update(bool good) { |
|||
uint32_t now = time(NULL); |
|||
if (ourLastTry == 0) |
|||
ourLastTry = now - MIN_RETRY; |
|||
int age = now - ourLastTry; |
|||
lastTry = now; |
|||
ourLastTry = now; |
|||
total++; |
|||
if (good) |
|||
{ |
|||
success++; |
|||
ourLastSuccess = now; |
|||
} |
|||
stat2H.Update(good, age, 3600*2); |
|||
stat8H.Update(good, age, 3600*8); |
|||
stat1D.Update(good, age, 3600*24); |
|||
stat1W.Update(good, age, 3600*24*7); |
|||
stat1M.Update(good, age, 3600*24*30); |
|||
int ign = GetIgnoreTime(); |
|||
if (ign && (ignoreTill==0 || ignoreTill < ign+now)) ignoreTill = ign+now; |
|||
// printf("%s: got %s result: success=%i/%i; 2H:%.2f%%-%.2f%%(%.2f) 8H:%.2f%%-%.2f%%(%.2f) 1D:%.2f%%-%.2f%%(%.2f) 1W:%.2f%%-%.2f%%(%.2f) \n", ToString(ip).c_str(), good ? "good" : "bad", success, total,
|
|||
// 100.0 * stat2H.reliability, 100.0 * (stat2H.reliability + 1.0 - stat2H.weight), stat2H.count,
|
|||
// 100.0 * stat8H.reliability, 100.0 * (stat8H.reliability + 1.0 - stat8H.weight), stat8H.count,
|
|||
// 100.0 * stat1D.reliability, 100.0 * (stat1D.reliability + 1.0 - stat1D.weight), stat1D.count,
|
|||
// 100.0 * stat1W.reliability, 100.0 * (stat1W.reliability + 1.0 - stat1W.weight), stat1W.count);
|
|||
} |
|||
|
|||
bool CAddrDb::Get_(CServiceResult &ip, int &wait) { |
|||
int64 now = time(NULL); |
|||
int cont = 0; |
|||
int tot = unkId.size() + ourId.size(); |
|||
if (tot == 0) { |
|||
wait = 5; |
|||
return false; |
|||
} |
|||
do { |
|||
int rnd = rand() % tot; |
|||
int ret; |
|||
if (rnd < unkId.size()) { |
|||
set<int>::iterator it = unkId.end(); it--; |
|||
ret = *it; |
|||
unkId.erase(it); |
|||
} else { |
|||
ret = ourId.front(); |
|||
if (time(NULL) - idToInfo[ret].ourLastTry < MIN_RETRY) return false; |
|||
ourId.pop_front(); |
|||
} |
|||
if (idToInfo[ret].ignoreTill && idToInfo[ret].ignoreTill < now) { |
|||
ourId.push_back(ret); |
|||
idToInfo[ret].ourLastTry = now; |
|||
} else { |
|||
ip.service = idToInfo[ret].ip; |
|||
ip.ourLastSuccess = idToInfo[ret].ourLastSuccess; |
|||
break; |
|||
} |
|||
} while(1); |
|||
nDirty++; |
|||
return true; |
|||
} |
|||
|
|||
int CAddrDb::Lookup_(const CService &ip) { |
|||
if (ipToId.count(ip)) |
|||
return ipToId[ip]; |
|||
return -1; |
|||
} |
|||
|
|||
void CAddrDb::Good_(const CService &addr, int clientV, std::string clientSV, int blocks) { |
|||
int id = Lookup_(addr); |
|||
if (id == -1) return; |
|||
unkId.erase(id); |
|||
banned.erase(addr); |
|||
CAddrInfo &info = idToInfo[id]; |
|||
info.clientVersion = clientV; |
|||
info.clientSubVersion = clientSV; |
|||
info.blocks = blocks; |
|||
info.Update(true); |
|||
if (info.IsGood() && goodId.count(id)==0) { |
|||
goodId.insert(id); |
|||
// printf("%s: good; %i good nodes now\n", ToString(addr).c_str(), (int)goodId.size());
|
|||
} |
|||
nDirty++; |
|||
ourId.push_back(id); |
|||
} |
|||
|
|||
void CAddrDb::Bad_(const CService &addr, int ban) |
|||
{ |
|||
int id = Lookup_(addr); |
|||
if (id == -1) return; |
|||
unkId.erase(id); |
|||
CAddrInfo &info = idToInfo[id]; |
|||
info.Update(false); |
|||
uint32_t now = time(NULL); |
|||
int ter = info.GetBanTime(); |
|||
if (ter) { |
|||
// printf("%s: terrible\n", ToString(addr).c_str());
|
|||
if (ban < ter) ban = ter; |
|||
} |
|||
if (ban > 0) { |
|||
// printf("%s: ban for %i seconds\n", ToString(addr).c_str(), ban);
|
|||
banned[info.ip] = ban + now; |
|||
ipToId.erase(info.ip); |
|||
goodId.erase(id); |
|||
idToInfo.erase(id); |
|||
} else { |
|||
if (/*!info.IsGood() && */ goodId.count(id)==1) { |
|||
goodId.erase(id); |
|||
// printf("%s: not good; %i good nodes left\n", ToString(addr).c_str(), (int)goodId.size());
|
|||
} |
|||
ourId.push_back(id); |
|||
} |
|||
nDirty++; |
|||
} |
|||
|
|||
void CAddrDb::Skipped_(const CService &addr) |
|||
{ |
|||
int id = Lookup_(addr); |
|||
if (id == -1) return; |
|||
unkId.erase(id); |
|||
ourId.push_back(id); |
|||
// printf("%s: skipped\n", ToString(addr).c_str());
|
|||
nDirty++; |
|||
} |
|||
|
|||
|
|||
void CAddrDb::Add_(const CAddress &addr, bool force) { |
|||
if (!force && !addr.IsRoutable()) |
|||
return; |
|||
CService ipp(addr); |
|||
if (banned.count(ipp)) { |
|||
time_t bantime = banned[ipp]; |
|||
if (force || (bantime < time(NULL) && addr.nTime > bantime)) |
|||
banned.erase(ipp); |
|||
else |
|||
return; |
|||
} |
|||
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 (force) { |
|||
ai.ignoreTill = 0; |
|||
} |
|||
return; |
|||
} |
|||
CAddrInfo ai; |
|||
ai.ip = ipp; |
|||
ai.services = addr.nServices; |
|||
ai.lastTry = addr.nTime; |
|||
ai.ourLastTry = 0; |
|||
ai.total = 0; |
|||
ai.success = 0; |
|||
int id = nId++; |
|||
idToInfo[id] = ai; |
|||
ipToId[ipp] = id; |
|||
// printf("%s: added\n", ToString(ipp).c_str(), ipToId[ipp]);
|
|||
unkId.insert(id); |
|||
nDirty++; |
|||
} |
|||
|
|||
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) { |
|||
if (unkId.size() == 0) return; |
|||
id = *unkId.begin(); |
|||
} else { |
|||
id = *ourId.begin(); |
|||
} |
|||
if (id >= 0 && (idToInfo[id].services & requestedFlags) == requestedFlags) { |
|||
ips.insert(idToInfo[id].ip); |
|||
} |
|||
return; |
|||
} |
|||
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; |
|||
|
|||
set<int> ids; |
|||
while (ids.size() < max) { |
|||
ids.insert(goodIdFiltered[rand() % goodIdFiltered.size()]); |
|||
} |
|||
for (set<int>::const_iterator it = ids.begin(); it != ids.end(); it++) { |
|||
CService &ip = idToInfo[*it].ip; |
|||
if (nets[ip.GetNetwork()]) |
|||
ips.insert(ip); |
|||
} |
|||
} |
@ -0,0 +1,359 @@ |
|||
#include <stdint.h> |
|||
#include <math.h> |
|||
|
|||
#include <set> |
|||
#include <map> |
|||
#include <vector> |
|||
#include <deque> |
|||
|
|||
#include "netbase.h" |
|||
#include "protocol.h" |
|||
#include "util.h" |
|||
|
|||
#define MIN_RETRY 1000 |
|||
|
|||
#define REQUIRE_VERSION 170002 |
|||
|
|||
static inline int GetRequireHeight(const bool testnet = fTestNet) |
|||
{ |
|||
// return testnet ? 500000 : 350000;
|
|||
return 0; |
|||
} |
|||
|
|||
std::string static inline ToString(const CService &ip) { |
|||
std::string str = ip.ToString(); |
|||
while (str.size() < 22) str += ' '; |
|||
return str; |
|||
} |
|||
|
|||
class CAddrStat { |
|||
private: |
|||
float weight; |
|||
float count; |
|||
float reliability; |
|||
public: |
|||
CAddrStat() : weight(0), count(0), reliability(0) {} |
|||
|
|||
void Update(bool good, int64 age, double tau) { |
|||
double f = exp(-age/tau); |
|||
reliability = reliability * f + (good ? (1.0-f) : 0); |
|||
count = count * f + 1; |
|||
weight = weight * f + (1.0-f); |
|||
} |
|||
|
|||
IMPLEMENT_SERIALIZE ( |
|||
READWRITE(weight); |
|||
READWRITE(count); |
|||
READWRITE(reliability); |
|||
) |
|||
|
|||
friend class CAddrInfo; |
|||
}; |
|||
|
|||
class CAddrReport { |
|||
public: |
|||
CService ip; |
|||
int clientVersion; |
|||
int blocks; |
|||
double uptime[5]; |
|||
std::string clientSubVersion; |
|||
int64_t lastSuccess; |
|||
bool fGood; |
|||
uint64_t services; |
|||
}; |
|||
|
|||
|
|||
class CAddrInfo { |
|||
private: |
|||
CService ip; |
|||
uint64_t services; |
|||
int64 lastTry; |
|||
int64 ourLastTry; |
|||
int64 ourLastSuccess; |
|||
int64 ignoreTill; |
|||
CAddrStat stat2H; |
|||
CAddrStat stat8H; |
|||
CAddrStat stat1D; |
|||
CAddrStat stat1W; |
|||
CAddrStat stat1M; |
|||
int clientVersion; |
|||
int blocks; |
|||
int total; |
|||
int success; |
|||
std::string clientSubVersion; |
|||
public: |
|||
CAddrInfo() : services(0), lastTry(0), ourLastTry(0), ourLastSuccess(0), ignoreTill(0), clientVersion(0), blocks(0), total(0), success(0) {} |
|||
|
|||
CAddrReport GetReport() const { |
|||
CAddrReport ret; |
|||
ret.ip = ip; |
|||
ret.clientVersion = clientVersion; |
|||
ret.clientSubVersion = clientSubVersion; |
|||
ret.blocks = blocks; |
|||
ret.uptime[0] = stat2H.reliability; |
|||
ret.uptime[1] = stat8H.reliability; |
|||
ret.uptime[2] = stat1D.reliability; |
|||
ret.uptime[3] = stat1W.reliability; |
|||
ret.uptime[4] = stat1M.reliability; |
|||
ret.lastSuccess = ourLastSuccess; |
|||
ret.fGood = IsGood(); |
|||
ret.services = services; |
|||
return ret; |
|||
} |
|||
|
|||
bool IsGood() const { |
|||
if (ip.GetPort() != GetDefaultPort()) return false; |
|||
if (!(services & NODE_NETWORK)) return false; |
|||
if (!ip.IsRoutable()) return false; |
|||
if (clientVersion && clientVersion < REQUIRE_VERSION) return false; |
|||
if (blocks && blocks < GetRequireHeight()) return false; |
|||
|
|||
if (total <= 3 && success * 2 >= total) return true; |
|||
|
|||
if (stat2H.reliability > 0.85 && stat2H.count > 2) return true; |
|||
if (stat8H.reliability > 0.70 && stat8H.count > 4) return true; |
|||
if (stat1D.reliability > 0.55 && stat1D.count > 8) return true; |
|||
if (stat1W.reliability > 0.45 && stat1W.count > 16) return true; |
|||
if (stat1M.reliability > 0.35 && stat1M.count > 32) return true; |
|||
|
|||
return false; |
|||
} |
|||
int GetBanTime() const { |
|||
if (IsGood()) return 0; |
|||
if (clientVersion && clientVersion < 31900) { 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; } |
|||
return 0; |
|||
} |
|||
int GetIgnoreTime() const { |
|||
if (IsGood()) return 0; |
|||
if (stat1M.reliability - stat1M.weight + 1.0 < 0.20 && stat1M.count > 2) { return 10*86400; } |
|||
if (stat1W.reliability - stat1W.weight + 1.0 < 0.16 && stat1W.count > 2) { return 3*86400; } |
|||
if (stat1D.reliability - stat1D.weight + 1.0 < 0.12 && stat1D.count > 2) { return 8*3600; } |
|||
if (stat8H.reliability - stat8H.weight + 1.0 < 0.08 && stat8H.count > 2) { return 2*3600; } |
|||
return 0; |
|||
} |
|||
|
|||
void Update(bool good); |
|||
|
|||
friend class CAddrDb; |
|||
|
|||
IMPLEMENT_SERIALIZE ( |
|||
unsigned char version = 4; |
|||
READWRITE(version); |
|||
READWRITE(ip); |
|||
READWRITE(services); |
|||
READWRITE(lastTry); |
|||
unsigned char tried = ourLastTry != 0; |
|||
READWRITE(tried); |
|||
if (tried) { |
|||
READWRITE(ourLastTry); |
|||
READWRITE(ignoreTill); |
|||
READWRITE(stat2H); |
|||
READWRITE(stat8H); |
|||
READWRITE(stat1D); |
|||
READWRITE(stat1W); |
|||
if (version >= 1) |
|||
READWRITE(stat1M); |
|||
else |
|||
if (!fWrite) |
|||
*((CAddrStat*)(&stat1M)) = stat1W; |
|||
READWRITE(total); |
|||
READWRITE(success); |
|||
READWRITE(clientVersion); |
|||
if (version >= 2) |
|||
READWRITE(clientSubVersion); |
|||
if (version >= 3) |
|||
READWRITE(blocks); |
|||
if (version >= 4) |
|||
READWRITE(ourLastSuccess); |
|||
} |
|||
) |
|||
}; |
|||
|
|||
class CAddrDbStats { |
|||
public: |
|||
int nBanned; |
|||
int nAvail; |
|||
int nTracked; |
|||
int nNew; |
|||
int nGood; |
|||
int nAge; |
|||
}; |
|||
|
|||
struct CServiceResult { |
|||
CService service; |
|||
bool fGood; |
|||
int nBanTime; |
|||
int nHeight; |
|||
int nClientV; |
|||
std::string strClientV; |
|||
int64 ourLastSuccess; |
|||
}; |
|||
|
|||
// seen nodes
|
|||
// / \ |
|||
// (a) banned nodes available nodes--------------
|
|||
// / | \ |
|||
// tracked nodes (b) unknown nodes (e) active nodes
|
|||
// / \ |
|||
// (d) good nodes (c) non-good nodes
|
|||
|
|||
class CAddrDb { |
|||
private: |
|||
mutable CCriticalSection cs; |
|||
int nId; // number of address id's
|
|||
std::map<int, CAddrInfo> idToInfo; // map address id to address info (b,c,d,e)
|
|||
std::map<CService, int> ipToId; // map ip to id (b,c,d,e)
|
|||
std::deque<int> ourId; // sequence of tried nodes, in order we have tried connecting to them (c,d)
|
|||
std::set<int> unkId; // set of nodes not yet tried (b)
|
|||
std::set<int> goodId; // set of good nodes (d, good e)
|
|||
int nDirty; |
|||
|
|||
protected: |
|||
// internal routines that assume proper locks are acquired
|
|||
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 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, 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)
|
|||
|
|||
void GetStats(CAddrDbStats &stats) { |
|||
SHARED_CRITICAL_BLOCK(cs) { |
|||
stats.nBanned = banned.size(); |
|||
stats.nAvail = idToInfo.size(); |
|||
stats.nTracked = ourId.size(); |
|||
stats.nGood = goodId.size(); |
|||
stats.nNew = unkId.size(); |
|||
stats.nAge = time(NULL) - idToInfo[ourId[0]].ourLastTry; |
|||
} |
|||
} |
|||
|
|||
void ResetIgnores() { |
|||
for (std::map<int, CAddrInfo>::iterator it = idToInfo.begin(); it != idToInfo.end(); it++) { |
|||
(*it).second.ignoreTill = 0; |
|||
} |
|||
} |
|||
|
|||
std::vector<CAddrReport> GetAll() { |
|||
std::vector<CAddrReport> ret; |
|||
SHARED_CRITICAL_BLOCK(cs) { |
|||
for (std::deque<int>::const_iterator it = ourId.begin(); it != ourId.end(); it++) { |
|||
const CAddrInfo &info = idToInfo[*it]; |
|||
if (info.success > 0) { |
|||
ret.push_back(info.GetReport()); |
|||
} |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
// serialization code
|
|||
// format:
|
|||
// nVersion (0 for now)
|
|||
// n (number of ips in (b,c,d))
|
|||
// CAddrInfo[n]
|
|||
// banned
|
|||
// acquires a shared lock (this does not suffice for read mode, but we assume that only happens at startup, single-threaded)
|
|||
// this way, dumping does not interfere with GetIPs_, which is called from the DNS thread
|
|||
IMPLEMENT_SERIALIZE (({ |
|||
int nVersion = 0; |
|||
READWRITE(nVersion); |
|||
SHARED_CRITICAL_BLOCK(cs) { |
|||
if (fWrite) { |
|||
CAddrDb *db = const_cast<CAddrDb*>(this); |
|||
int n = ourId.size() + unkId.size(); |
|||
READWRITE(n); |
|||
for (std::deque<int>::const_iterator it = ourId.begin(); it != ourId.end(); it++) { |
|||
std::map<int, CAddrInfo>::iterator ci = db->idToInfo.find(*it); |
|||
READWRITE((*ci).second); |
|||
} |
|||
for (std::set<int>::const_iterator it = unkId.begin(); it != unkId.end(); it++) { |
|||
std::map<int, CAddrInfo>::iterator ci = db->idToInfo.find(*it); |
|||
READWRITE((*ci).second); |
|||
} |
|||
} else { |
|||
CAddrDb *db = const_cast<CAddrDb*>(this); |
|||
db->nId = 0; |
|||
int n; |
|||
READWRITE(n); |
|||
for (int i=0; i<n; i++) { |
|||
CAddrInfo info; |
|||
READWRITE(info); |
|||
if (!info.GetBanTime()) { |
|||
int id = db->nId++; |
|||
db->idToInfo[id] = info; |
|||
db->ipToId[info.ip] = id; |
|||
if (info.ourLastTry) { |
|||
db->ourId.push_back(id); |
|||
if (info.IsGood()) db->goodId.insert(id); |
|||
} else { |
|||
db->unkId.insert(id); |
|||
} |
|||
} |
|||
} |
|||
db->nDirty++; |
|||
} |
|||
READWRITE(banned); |
|||
} |
|||
});) |
|||
|
|||
void Add(const CAddress &addr, bool fForce = false) { |
|||
CRITICAL_BLOCK(cs) |
|||
Add_(addr, fForce); |
|||
} |
|||
void Add(const std::vector<CAddress> &vAddr, bool fForce = false) { |
|||
CRITICAL_BLOCK(cs) |
|||
for (int i=0; i<vAddr.size(); i++) |
|||
Add_(vAddr[i], fForce); |
|||
} |
|||
void Good(const CService &addr, int clientVersion, std::string clientSubVersion, int blocks) { |
|||
CRITICAL_BLOCK(cs) |
|||
Good_(addr, clientVersion, clientSubVersion, blocks); |
|||
} |
|||
void Skipped(const CService &addr) { |
|||
CRITICAL_BLOCK(cs) |
|||
Skipped_(addr); |
|||
} |
|||
void Bad(const CService &addr, int ban = 0) { |
|||
CRITICAL_BLOCK(cs) |
|||
Bad_(addr, ban); |
|||
} |
|||
bool Get(CServiceResult &ip, int& wait) { |
|||
CRITICAL_BLOCK(cs) |
|||
return Get_(ip, wait); |
|||
} |
|||
void GetMany(std::vector<CServiceResult> &ips, int max, int& wait) { |
|||
CRITICAL_BLOCK(cs) { |
|||
while (max > 0) { |
|||
CServiceResult ip = {}; |
|||
if (!Get_(ip, wait)) |
|||
return; |
|||
ips.push_back(ip); |
|||
max--; |
|||
} |
|||
} |
|||
} |
|||
void ResultMany(const std::vector<CServiceResult> &ips) { |
|||
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); |
|||
} else { |
|||
Bad_(ips[i].service, ips[i].nBanTime); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
void GetIPs(std::set<CNetAddr>& ips, uint64_t requestedFlags, int max, const bool *nets) { |
|||
SHARED_CRITICAL_BLOCK(cs) |
|||
GetIPs_(ips, requestedFlags, max, nets); |
|||
} |
|||
}; |
@ -0,0 +1,457 @@ |
|||
#include <stdbool.h> |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include <strings.h> |
|||
#include <stdlib.h> |
|||
#include <sys/socket.h> |
|||
#include <netinet/in.h> |
|||
#include <stdint.h> |
|||
#include <sys/types.h> |
|||
#include <arpa/inet.h> |
|||
#include <time.h> |
|||
#include <ctype.h> |
|||
#include <unistd.h> |
|||
|
|||
#include "dns.h" |
|||
|
|||
#define BUFLEN 512 |
|||
|
|||
#if defined IP_RECVDSTADDR |
|||
# define DSTADDR_SOCKOPT IP_RECVDSTADDR |
|||
# define DSTADDR_DATASIZE (CMSG_SPACE(sizeof(struct in6_addr))) |
|||
# define dstaddr(x) (CMSG_DATA(x)) |
|||
#elif defined IPV6_PKTINFO |
|||
struct in6_pktinfo |
|||
{ |
|||
struct in6_addr ipi6_addr; /* src/dst IPv6 address */ |
|||
unsigned int ipi6_ifindex; /* send/recv interface index */ |
|||
}; |
|||
|
|||
# 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 |
|||
|
|||
union control_data { |
|||
struct cmsghdr cmsg; |
|||
unsigned char data[DSTADDR_DATASIZE]; |
|||
}; |
|||
|
|||
typedef enum { |
|||
CLASS_IN = 1, |
|||
QCLASS_ANY = 255 |
|||
} dns_class; |
|||
|
|||
typedef enum { |
|||
TYPE_A = 1, |
|||
TYPE_NS = 2, |
|||
TYPE_CNAME = 5, |
|||
TYPE_SOA = 6, |
|||
TYPE_MX = 15, |
|||
TYPE_AAAA = 28, |
|||
TYPE_SRV = 33, |
|||
QTYPE_ANY = 255 |
|||
} dns_type; |
|||
|
|||
|
|||
// 0: ok
|
|||
// -1: premature end of input, forward reference, component > 63 char, invalid character
|
|||
// -2: insufficient space in output
|
|||
int static parse_name(const unsigned char **inpos, const unsigned char *inend, const unsigned char *inbuf, char *buf, size_t bufsize) { |
|||
size_t bufused = 0; |
|||
int init = 1; |
|||
do { |
|||
if (*inpos == inend) |
|||
return -1; |
|||
// read length of next component
|
|||
int octet = *((*inpos)++); |
|||
if (octet == 0) { |
|||
buf[bufused] = 0; |
|||
return 0; |
|||
} |
|||
// add dot in output
|
|||
if (!init) { |
|||
if (bufused == bufsize-1) |
|||
return -2; |
|||
buf[bufused++] = '.'; |
|||
} else |
|||
init = 0; |
|||
// handle references
|
|||
if ((octet & 0xC0) == 0xC0) { |
|||
if (*inpos == inend) |
|||
return -1; |
|||
int ref = ((octet - 0xC0) << 8) + *((*inpos)++); |
|||
if (ref < 0 || ref >= (*inpos)-inbuf-2) return -1; |
|||
const unsigned char *newbuf = inbuf + ref; |
|||
return parse_name(&newbuf, (*inpos) - 2, inbuf, buf+bufused, bufsize-bufused); |
|||
} |
|||
if (octet > 63) return -1; |
|||
// copy label
|
|||
while (octet) { |
|||
if (*inpos == inend) |
|||
return -1; |
|||
if (bufused == bufsize-1) |
|||
return -2; |
|||
int c = *((*inpos)++); |
|||
if (c == '.') |
|||
return -1; |
|||
octet--; |
|||
buf[bufused++] = c; |
|||
} |
|||
} while(1); |
|||
} |
|||
|
|||
// 0: k
|
|||
// -1: component > 63 characters
|
|||
// -2: insufficent space in output
|
|||
// -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 *fin = dot; |
|||
if (!dot) fin = name + strlen(name); |
|||
if (fin - name > 63) return -1; |
|||
if (fin == name) return -3; |
|||
if (outend - *outpos < fin - name + 2) return -2; |
|||
*((*outpos)++) = fin - name; |
|||
memcpy(*outpos, name, fin - name); |
|||
*outpos += fin - name; |
|||
if (!dot) break; |
|||
name = dot + 1; |
|||
} |
|||
if (offset < 0) { |
|||
// no reference
|
|||
if (outend == *outpos) return -2; |
|||
*((*outpos)++) = 0; |
|||
} else { |
|||
if (outend - *outpos < 2) return -2; |
|||
*((*outpos)++) = (offset >> 8) | 0xC0; |
|||
*((*outpos)++) = offset & 0xFF; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
int static write_record(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_type typ, dns_class cls, int ttl) { |
|||
unsigned char *oldpos = *outpos; |
|||
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: |
|||
*outpos = oldpos; |
|||
return error; |
|||
} |
|||
|
|||
|
|||
int static write_record_a(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const addr_t *ip) { |
|||
if (ip->v != 4) |
|||
return -6; |
|||
unsigned char *oldpos = *outpos; |
|||
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: |
|||
*outpos = oldpos; |
|||
return error; |
|||
} |
|||
|
|||
int static write_record_aaaa(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const addr_t *ip) { |
|||
if (ip->v != 6) |
|||
return -6; |
|||
unsigned char *oldpos = *outpos; |
|||
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: |
|||
*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) { |
|||
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: |
|||
*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, |
|||
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: |
|||
*outpos = oldpos; |
|||
return error; |
|||
} |
|||
|
|||
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
|
|||
return -1; |
|||
// copy id
|
|||
outbuf[0] = inbuf[0]; |
|||
outbuf[1] = inbuf[1]; |
|||
// copy flags;
|
|||
outbuf[2] = inbuf[2]; |
|||
outbuf[3] = inbuf[3]; |
|||
// clear error
|
|||
outbuf[3] &= ~15; |
|||
// check qr
|
|||
if (inbuf[2] & 128) { /* printf("Got response?\n"); */ error = 1; goto error; } |
|||
// check opcode
|
|||
if (((inbuf[2] & 120) >> 3) != 0) { /* printf("Opcode nonzero?\n"); */ error = 4; goto error; } |
|||
// 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; } |
|||
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; } |
|||
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; } |
|||
// copy question to output
|
|||
memcpy(outbuf+12, inbuf+12, inpos+4 - (inbuf+12)); |
|||
// set counts
|
|||
outbuf[4] = 0; outbuf[5] = 1; |
|||
outbuf[6] = 0; outbuf[7] = 0; |
|||
outbuf[8] = 0; outbuf[9] = 0; |
|||
outbuf[10] = 0; outbuf[11] = 0; |
|||
// set qr
|
|||
outbuf[2] |= 128; |
|||
|
|||
int typ = (inpos[0] << 8) + inpos[1]; |
|||
int cls = (inpos[2] << 8) + inpos[3]; |
|||
inpos += 4; |
|||
|
|||
unsigned char *outpos = outbuf+(inpos-inbuf); |
|||
unsigned char *outend = outbuf + BUFLEN; |
|||
|
|||
// printf("DNS: Request host='%s' type=%i class=%i\n", name, typ, cls);
|
|||
|
|||
// calculate max size of authority section
|
|||
|
|||
int max_auth_size = 0; |
|||
|
|||
if (!((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY))) { |
|||
// authority section will be necessary, either NS or SOA
|
|||
unsigned char *newpos = outpos; |
|||
write_record_ns(&newpos, outend, "", offset, CLASS_IN, 0, opt->ns); |
|||
max_auth_size = newpos - outpos; |
|||
|
|||
newpos = outpos; |
|||
write_record_soa(&newpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); |
|||
if (max_auth_size < newpos - outpos) |
|||
max_auth_size = newpos - outpos; |
|||
// printf("Authority section will claim %i bytes max\n", max_auth_size);
|
|||
} |
|||
|
|||
// Answer section
|
|||
|
|||
int have_ns = 0; |
|||
|
|||
// NS records
|
|||
if ((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) { |
|||
int ret2 = write_record_ns(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns); |
|||
// printf("wrote NS record: %i\n", ret2);
|
|||
if (!ret2) { outbuf[7]++; have_ns++; } |
|||
} |
|||
|
|||
// SOA records
|
|||
if ((typ == TYPE_SOA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY) && opt->mbox) { |
|||
int ret2 = write_record_soa(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); |
|||
// printf("wrote SOA record: %i\n", ret2);
|
|||
if (!ret2) { outbuf[7]++; } |
|||
} |
|||
|
|||
// 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, name, addr, 32, typ == TYPE_A || typ == QTYPE_ANY, typ == TYPE_AAAA || typ == QTYPE_ANY); |
|||
int n = 0; |
|||
while (n < naddr) { |
|||
int ret = 1; |
|||
if (addr[n].v == 4) |
|||
ret = write_record_a(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]); |
|||
else if (addr[n].v == 6) |
|||
ret = write_record_aaaa(&outpos, outend - max_auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]); |
|||
// printf("wrote A record: %i\n", ret);
|
|||
if (!ret) { |
|||
n++; |
|||
outbuf[7]++; |
|||
} else |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// Authority section
|
|||
if (!have_ns && outbuf[7]) { |
|||
int ret2 = write_record_ns(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns); |
|||
// printf("wrote NS record: %i\n", ret2);
|
|||
if (!ret2) { |
|||
outbuf[9]++; |
|||
} |
|||
} |
|||
else if (!outbuf[7]) { |
|||
// Didn't include any answers, so reply with SOA as this is a negative
|
|||
// response. If we replied with NS above we'd create a bad horizontal
|
|||
// referral loop, as the NS response indicates where the resolver should
|
|||
// try next.
|
|||
int ret2 = write_record_soa(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800); |
|||
// printf("wrote SOA record: %i\n", ret2);
|
|||
if (!ret2) { outbuf[9]++; } |
|||
} |
|||
|
|||
// set AA
|
|||
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_in6 si_other; |
|||
int senderSocket = -1; |
|||
senderSocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
|||
if (senderSocket == -1) |
|||
return -3; |
|||
|
|||
int replySocket; |
|||
if (listenSocket == -1) { |
|||
struct sockaddr_in6 si_me; |
|||
if ((listenSocket=socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP))==-1) { |
|||
listenSocket = -1; |
|||
return -1; |
|||
} |
|||
replySocket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
|||
if (replySocket == -1) |
|||
{ |
|||
close(listenSocket); |
|||
return -1; |
|||
} |
|||
int sockopt = 1; |
|||
setsockopt(listenSocket, IPPROTO_IPV6, DSTADDR_SOCKOPT, &sockopt, sizeof sockopt); |
|||
memset((char *) &si_me, 0, sizeof(si_me)); |
|||
si_me.sin6_family = AF_INET6; |
|||
si_me.sin6_port = htons(opt->port); |
|||
si_me.sin6_addr = in6addr_any; |
|||
if (bind(listenSocket, (struct sockaddr*)&si_me, sizeof(si_me))==-1) |
|||
return -2; |
|||
} |
|||
|
|||
unsigned char inbuf[BUFLEN], outbuf[BUFLEN]; |
|||
struct iovec iov[1] = { |
|||
{ |
|||
.iov_base = inbuf, |
|||
.iov_len = sizeof(inbuf), |
|||
}, |
|||
}; |
|||
union control_data cmsg; |
|||
struct msghdr msg = { |
|||
.msg_name = &si_other, |
|||
.msg_namelen = sizeof(si_other), |
|||
.msg_iov = iov, |
|||
.msg_iovlen = 1, |
|||
.msg_control = &cmsg, |
|||
.msg_controllen = sizeof(cmsg), |
|||
}; |
|||
for (; 1; ++(opt->nRequests)) |
|||
{ |
|||
ssize_t insize = recvmsg(listenSocket, &msg, 0); |
|||
// 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; |
|||
|
|||
ssize_t ret = dnshandle(opt, inbuf, insize, outbuf); |
|||
if (ret <= 0) |
|||
continue; |
|||
|
|||
bool handled = false; |
|||
for (struct cmsghdr*hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) |
|||
{ |
|||
if (hdr->cmsg_level == IPPROTO_IP && hdr->cmsg_type == DSTADDR_SOCKOPT) |
|||
{ |
|||
msg.msg_iov[0].iov_base = outbuf; |
|||
msg.msg_iov[0].iov_len = ret; |
|||
sendmsg(listenSocket, &msg, 0); |
|||
msg.msg_iov[0].iov_base = inbuf; |
|||
msg.msg_iov[0].iov_len = sizeof(inbuf); |
|||
handled = true; |
|||
} |
|||
} |
|||
if (!handled) |
|||
sendto(listenSocket, outbuf, ret, 0, (struct sockaddr*)&si_other, sizeof(si_other)); |
|||
} |
|||
return 0; |
|||
} |
@ -0,0 +1,28 @@ |
|||
#ifndef _DNS_H_ |
|||
#define _DNS_H_ 1 |
|||
|
|||
#include <stdint.h> |
|||
|
|||
typedef struct { |
|||
int v; |
|||
union { |
|||
unsigned char v4[4]; |
|||
unsigned char v6[16]; |
|||
} data; |
|||
} addr_t; |
|||
|
|||
typedef struct { |
|||
int port; |
|||
int datattl; |
|||
int nsttl; |
|||
const char *host; |
|||
const char *ns; |
|||
const char *mbox; |
|||
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); |
|||
|
|||
#endif |
@ -0,0 +1,509 @@ |
|||
#include <algorithm> |
|||
|
|||
#define __STDC_FORMAT_MACROS |
|||
#include <inttypes.h> |
|||
#include <pthread.h> |
|||
#include <signal.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <getopt.h> |
|||
|
|||
#include "bitcoin.h" |
|||
#include "db.h" |
|||
|
|||
using namespace std; |
|||
|
|||
bool fTestNet = false; |
|||
|
|||
class CDnsSeedOpts { |
|||
public: |
|||
int nThreads; |
|||
int nPort; |
|||
int nDnsThreads; |
|||
int fUseTestNet; |
|||
int fWipeBan; |
|||
int fWipeIgnore; |
|||
const char *mbox; |
|||
const char *ns; |
|||
const char *host; |
|||
const char *tor; |
|||
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), ipv4_proxy(NULL), ipv6_proxy(NULL) {} |
|||
|
|||
void ParseCommandLine(int argc, char **argv) { |
|||
static const char *help = "Bitcoin-seeder\n" |
|||
"Usage: %s -h <host> -n <ns> [-m <mbox>] [-t <threads>] [-p <port>]\n" |
|||
"\n" |
|||
"Options:\n" |
|||
"-h <host> Hostname of the DNS seed\n" |
|||
"-n <ns> Hostname of the nameserver\n" |
|||
"-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" |
|||
"-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" |
|||
"-?, --help Show this text\n" |
|||
"\n"; |
|||
bool showHelp = false; |
|||
|
|||
while(1) { |
|||
static struct option long_options[] = { |
|||
{"host", required_argument, 0, 'h'}, |
|||
{"ns", required_argument, 0, 'n'}, |
|||
{"mbox", required_argument, 0, 'm'}, |
|||
{"threads", required_argument, 0, 't'}, |
|||
{"dnsthreads", required_argument, 0, 'd'}, |
|||
{"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}, |
|||
{"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 = 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; |
|||
break; |
|||
} |
|||
|
|||
case 'd': { |
|||
int n = strtol(optarg, NULL, 10); |
|||
if (n > 0 && n < 1000) nDnsThreads = n; |
|||
break; |
|||
} |
|||
|
|||
case 'p': { |
|||
int p = strtol(optarg, NULL, 10); |
|||
if (p > 0 && p < 65536) nPort = p; |
|||
break; |
|||
} |
|||
|
|||
case 'o': { |
|||
tor = optarg; |
|||
break; |
|||
} |
|||
|
|||
case 'i': { |
|||
ipv4_proxy = optarg; |
|||
break; |
|||
} |
|||
|
|||
case 'k': { |
|||
ipv6_proxy = 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()) { |
|||
filter_whitelist.insert(1); |
|||
filter_whitelist.insert(5); |
|||
filter_whitelist.insert(9); |
|||
filter_whitelist.insert(13); |
|||
} |
|||
if (host != NULL && ns == NULL) showHelp = true; |
|||
if (showHelp) fprintf(stderr, help, argv[0]); |
|||
} |
|||
}; |
|||
|
|||
extern "C" { |
|||
#include "dns.h" |
|||
} |
|||
|
|||
CAddrDb db; |
|||
|
|||
extern "C" void* ThreadCrawler(void* data) { |
|||
int *nThreads=(int*)data; |
|||
do { |
|||
std::vector<CServiceResult> ips; |
|||
int wait = 5; |
|||
db.GetMany(ips, 16, wait); |
|||
int64 now = time(NULL); |
|||
if (ips.empty()) { |
|||
wait *= 1000; |
|||
wait += rand() % (500 * *nThreads); |
|||
Sleep(wait); |
|||
continue; |
|||
} |
|||
vector<CAddress> addr; |
|||
for (int i=0; i<ips.size(); i++) { |
|||
CServiceResult &res = ips[i]; |
|||
res.nBanTime = 0; |
|||
res.nClientV = 0; |
|||
res.nHeight = 0; |
|||
res.strClientV = ""; |
|||
bool getaddr = res.ourLastSuccess + 86400 < now; |
|||
res.fGood = TestNode(res.service,res.nBanTime,res.nClientV,res.strClientV,res.nHeight,getaddr ? &addr : NULL); |
|||
} |
|||
db.ResultMany(ips); |
|||
db.Add(addr); |
|||
} while(1); |
|||
} |
|||
|
|||
extern "C" int GetIPList(void *thread, char *requestedHostname, addr_t *addr, int max, int ipv4, int ipv6); |
|||
|
|||
class CDnsThread { |
|||
public: |
|||
dns_opt_t dns_opt; // must be first
|
|||
const int id; |
|||
std::map<uint64_t, vector<addr_t> > cache; |
|||
int nIPv4, nIPv6; |
|||
std::map<uint64_t, time_t> cacheTime; |
|||
unsigned int cacheHits; |
|||
uint64_t dbQueries; |
|||
std::set<uint64_t> filterWhitelist; |
|||
|
|||
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[requestedFlags].size()*cache[requestedFlags].size()/400) || (cacheHits*cacheHits > cache[requestedFlags].size() / 20 && (now - cacheTime[requestedFlags] > 5))) { |
|||
set<CNetAddr> ips; |
|||
db.GetIPs(ips, requestedFlags, 1000, nets); |
|||
dbQueries++; |
|||
cache[requestedFlags].clear(); |
|||
nIPv4 = 0; |
|||
nIPv6 = 0; |
|||
cache[requestedFlags].reserve(ips.size()); |
|||
for (set<CNetAddr>::iterator it = ips.begin(); it != ips.end(); it++) { |
|||
struct in_addr addr; |
|||
struct in6_addr addr6; |
|||
if ((*it).GetInAddr(&addr)) { |
|||
addr_t a; |
|||
a.v = 4; |
|||
memcpy(&a.data.v4, &addr, 4); |
|||
cache[requestedFlags].push_back(a); |
|||
nIPv4++; |
|||
} else if ((*it).GetIn6Addr(&addr6)) { |
|||
addr_t a; |
|||
a.v = 6; |
|||
memcpy(&a.data.v6, &addr6, 16); |
|||
cache[requestedFlags].push_back(a); |
|||
nIPv6++; |
|||
} |
|||
} |
|||
cacheHits = 0; |
|||
cacheTime[requestedFlags] = now; |
|||
} |
|||
} |
|||
|
|||
CDnsThread(CDnsSeedOpts* opts, int idIn) : id(idIn) { |
|||
dns_opt.host = opts->host; |
|||
dns_opt.ns = opts->ns; |
|||
dns_opt.mbox = opts->mbox; |
|||
dns_opt.datattl = 3600; |
|||
dns_opt.nsttl = 40000; |
|||
dns_opt.cb = GetIPList; |
|||
dns_opt.port = opts->nPort; |
|||
dns_opt.nRequests = 0; |
|||
cache.clear(); |
|||
cacheTime.clear(); |
|||
cacheHits = 0; |
|||
dbQueries = 0; |
|||
nIPv4 = 0; |
|||
nIPv6 = 0; |
|||
filterWhitelist = opts->filter_whitelist; |
|||
} |
|||
|
|||
void run() { |
|||
dnsserver(&dns_opt); |
|||
} |
|||
}; |
|||
|
|||
extern "C" int GetIPList(void *data, char *requestedHostname, addr_t* addr, int max, int ipv4, int ipv6) { |
|||
CDnsThread *thread = (CDnsThread*)data; |
|||
|
|||
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); |
|||
unsigned int size = thread->cache[requestedFlags].size(); |
|||
unsigned int maxmax = (ipv4 ? thread->nIPv4 : 0) + (ipv6 ? thread->nIPv6 : 0); |
|||
if (max > size) |
|||
max = size; |
|||
if (max > maxmax) |
|||
max = maxmax; |
|||
int i=0; |
|||
while (i<max) { |
|||
int j = i + (rand() % (size - i)); |
|||
do { |
|||
bool ok = (ipv4 && thread->cache[requestedFlags][j].v == 4) || |
|||
(ipv6 && thread->cache[requestedFlags][j].v == 6); |
|||
if (ok) break; |
|||
j++; |
|||
if (j==size) |
|||
j=i; |
|||
} while(1); |
|||
addr[i] = thread->cache[requestedFlags][j]; |
|||
thread->cache[requestedFlags][j] = thread->cache[requestedFlags][i]; |
|||
thread->cache[requestedFlags][i] = addr[i]; |
|||
i++; |
|||
} |
|||
return max; |
|||
} |
|||
|
|||
vector<CDnsThread*> dnsThread; |
|||
|
|||
extern "C" void* ThreadDNS(void* arg) { |
|||
CDnsThread *thread = (CDnsThread*)arg; |
|||
thread->run(); |
|||
} |
|||
|
|||
int StatCompare(const CAddrReport& a, const CAddrReport& b) { |
|||
if (a.uptime[4] == b.uptime[4]) { |
|||
if (a.uptime[3] == b.uptime[3]) { |
|||
return a.clientVersion > b.clientVersion; |
|||
} else { |
|||
return a.uptime[3] > b.uptime[3]; |
|||
} |
|||
} else { |
|||
return a.uptime[4] > b.uptime[4]; |
|||
} |
|||
} |
|||
|
|||
extern "C" void* ThreadDumper(void*) { |
|||
int count = 0; |
|||
do { |
|||
Sleep(100000 << count); // First 100s, than 200s, 400s, 800s, 1600s, and then 3200s forever
|
|||
if (count < 5) |
|||
count++; |
|||
{ |
|||
vector<CAddrReport> v = db.GetAll(); |
|||
sort(v.begin(), v.end(), StatCompare); |
|||
FILE *f = fopen("dnsseed.dat.new","w+"); |
|||
if (f) { |
|||
{ |
|||
CAutoFile cf(f); |
|||
cf << db; |
|||
} |
|||
rename("dnsseed.dat.new", "dnsseed.dat"); |
|||
} |
|||
FILE *d = fopen("dnsseed.dump", "w"); |
|||
fprintf(d, "# address good lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) %%(30d) blocks svcs version\n"); |
|||
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()); |
|||
stat[0] += rep.uptime[0]; |
|||
stat[1] += rep.uptime[1]; |
|||
stat[2] += rep.uptime[2]; |
|||
stat[3] += rep.uptime[3]; |
|||
stat[4] += rep.uptime[4]; |
|||
} |
|||
fclose(d); |
|||
FILE *ff = fopen("dnsstats.log", "a"); |
|||
fprintf(ff, "%llu %g %g %g %g %g\n", (unsigned long long)(time(NULL)), stat[0], stat[1], stat[2], stat[3], stat[4]); |
|||
fclose(ff); |
|||
} |
|||
} while(1); |
|||
} |
|||
|
|||
extern "C" void* ThreadStats(void*) { |
|||
bool first = true; |
|||
do { |
|||
char c[256]; |
|||
time_t tim = time(NULL); |
|||
struct tm *tmp = localtime(&tim); |
|||
strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp); |
|||
CAddrDbStats stats; |
|||
db.GetStats(stats); |
|||
if (first) |
|||
{ |
|||
first = false; |
|||
printf("\n\n\n\x1b[3A"); |
|||
} |
|||
else |
|||
printf("\x1b[2K\x1b[u"); |
|||
printf("\x1b[s"); |
|||
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); |
|||
} while(1); |
|||
} |
|||
|
|||
static const string mainnet_seeds[] = {"mainnet.myhush.org", "us.madmining.club", ""}; |
|||
static const string testnet_seeds[] = {"testnet.myhush.org", ""}; |
|||
static const string *seeds = mainnet_seeds; |
|||
|
|||
extern "C" void* ThreadSeeder(void*) { |
|||
//if (!fTestNet){
|
|||
// db.Add(CService("kjy2eqzk4zwi5zd3.onion", 8333), true);
|
|||
//}
|
|||
do { |
|||
for (int i=0; seeds[i] != ""; i++) { |
|||
vector<CNetAddr> ips; |
|||
LookupHost(seeds[i].c_str(), ips); |
|||
for (vector<CNetAddr>::iterator it = ips.begin(); it != ips.end(); it++) { |
|||
db.Add(CService(*it, GetDefaultPort()), true); |
|||
} |
|||
} |
|||
Sleep(1800000); |
|||
} while(1); |
|||
} |
|||
|
|||
int main(int argc, char **argv) { |
|||
signal(SIGPIPE, SIG_IGN); |
|||
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()) { |
|||
printf("Using Tor proxy at %s\n", service.ToStringIPPort().c_str()); |
|||
SetProxy(NET_TOR, service); |
|||
} |
|||
} |
|||
if (opts.ipv4_proxy) { |
|||
CService service(opts.ipv4_proxy, 9050); |
|||
if (service.IsValid()) { |
|||
printf("Using IPv4 proxy at %s\n", service.ToStringIPPort().c_str()); |
|||
SetProxy(NET_IPV4, service); |
|||
} |
|||
} |
|||
if (opts.ipv6_proxy) { |
|||
CService service(opts.ipv6_proxy, 9050); |
|||
if (service.IsValid()) { |
|||
printf("Using IPv6 proxy at %s\n", service.ToStringIPPort().c_str()); |
|||
SetProxy(NET_IPV6, service); |
|||
} |
|||
} |
|||
bool fDNS = true; |
|||
if (opts.fUseTestNet) { |
|||
printf("Using testnet.\n"); |
|||
pchMessageStart[0] = 0xFA; |
|||
pchMessageStart[1] = 0x1A; |
|||
pchMessageStart[2] = 0x24; |
|||
pchMessageStart[3] = 0xB6; |
|||
seeds = testnet_seeds; |
|||
fTestNet = true; |
|||
} |
|||
if (!opts.ns) { |
|||
printf("No nameserver set. Not starting DNS server.\n"); |
|||
fDNS = false; |
|||
} |
|||
if (fDNS && !opts.host) { |
|||
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..."); |
|||
CAutoFile cf(f); |
|||
cf >> db; |
|||
if (opts.fWipeBan) |
|||
db.banned.clear(); |
|||
if (opts.fWipeIgnore) |
|||
db.ResetIgnores(); |
|||
printf("done\n"); |
|||
} |
|||
pthread_t threadDns, threadSeed, threadDump, threadStats; |
|||
if (fDNS) { |
|||
printf("Starting %i DNS threads for %s on %s (port %i)...", opts.nDnsThreads, opts.host, opts.ns, opts.nPort); |
|||
dnsThread.clear(); |
|||
for (int i=0; i<opts.nDnsThreads; i++) { |
|||
dnsThread.push_back(new CDnsThread(&opts, i)); |
|||
pthread_create(&threadDns, NULL, ThreadDNS, dnsThread[i]); |
|||
printf("."); |
|||
Sleep(20); |
|||
} |
|||
printf("done\n"); |
|||
} |
|||
printf("Starting seeder..."); |
|||
pthread_create(&threadSeed, NULL, ThreadSeeder, NULL); |
|||
printf("done\n"); |
|||
printf("Starting %i crawler threads...", opts.nThreads); |
|||
pthread_attr_t attr_crawler; |
|||
pthread_attr_init(&attr_crawler); |
|||
pthread_attr_setstacksize(&attr_crawler, 0x20000); |
|||
for (int i=0; i<opts.nThreads; i++) { |
|||
pthread_t thread; |
|||
pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); |
|||
} |
|||
pthread_attr_destroy(&attr_crawler); |
|||
printf("done\n"); |
|||
pthread_create(&threadStats, NULL, ThreadStats, NULL); |
|||
pthread_create(&threadDump, NULL, ThreadDumper, NULL); |
|||
void* res; |
|||
pthread_join(threadDump, &res); |
|||
return 0; |
|||
} |
File diff suppressed because it is too large
@ -0,0 +1,148 @@ |
|||
// Copyright (c) 2009-2012 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
#ifndef BITCOIN_NETBASE_H |
|||
#define BITCOIN_NETBASE_H |
|||
|
|||
#include <string> |
|||
#include <vector> |
|||
|
|||
#include "serialize.h" |
|||
#include "compat.h" |
|||
|
|||
extern int nConnectTimeout; |
|||
|
|||
#ifdef WIN32 |
|||
// In MSVC, this is defined as a macro, undefine it to prevent a compile and link error
|
|||
#undef SetPort |
|||
#endif |
|||
|
|||
enum Network |
|||
{ |
|||
NET_UNROUTABLE, |
|||
NET_IPV4, |
|||
NET_IPV6, |
|||
NET_TOR, |
|||
NET_I2P, |
|||
|
|||
NET_MAX, |
|||
}; |
|||
|
|||
extern int nConnectTimeout; |
|||
extern bool fNameLookup; |
|||
|
|||
/** IP address (IPv6, or IPv4 using mapped IPv6 range (::FFFF:0:0/96)) */ |
|||
class CNetAddr |
|||
{ |
|||
protected: |
|||
unsigned char ip[16]; // in network byte order
|
|||
|
|||
public: |
|||
CNetAddr(); |
|||
CNetAddr(const struct in_addr& ipv4Addr); |
|||
explicit CNetAddr(const char *pszIp, bool fAllowLookup = false); |
|||
explicit CNetAddr(const std::string &strIp, bool fAllowLookup = false); |
|||
void Init(); |
|||
void SetIP(const CNetAddr& ip); |
|||
bool SetSpecial(const std::string &strName); // for Tor and I2P addresses
|
|||
bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0)
|
|||
bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor/I2P)
|
|||
bool IsReserved() const; // Against Hetzners Abusal/Netscan Bot
|
|||
bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12)
|
|||
bool IsRFC3849() const; // IPv6 documentation address (2001:0DB8::/32)
|
|||
bool IsRFC3927() const; // IPv4 autoconfig (169.254.0.0/16)
|
|||
bool IsRFC3964() const; // IPv6 6to4 tunnelling (2002::/16)
|
|||
bool IsRFC4193() const; // IPv6 unique local (FC00::/15)
|
|||
bool IsRFC4380() const; // IPv6 Teredo tunnelling (2001::/32)
|
|||
bool IsRFC4843() const; // IPv6 ORCHID (2001:10::/28)
|
|||
bool IsRFC4862() const; // IPv6 autoconfig (FE80::/64)
|
|||
bool IsRFC6052() const; // IPv6 well-known prefix (64:FF9B::/96)
|
|||
bool IsRFC6145() const; // IPv6 IPv4-translated address (::FFFF:0:0:0/96)
|
|||
bool IsTor() const; |
|||
bool IsI2P() const; |
|||
bool IsLocal() const; |
|||
bool IsRoutable() const; |
|||
bool IsValid() const; |
|||
bool IsMulticast() const; |
|||
enum Network GetNetwork() const; |
|||
std::string ToString() const; |
|||
std::string ToStringIP() const; |
|||
unsigned int GetByte(int n) const; |
|||
uint64 GetHash() const; |
|||
bool GetInAddr(struct in_addr* pipv4Addr) const; |
|||
std::vector<unsigned char> GetGroup() const; |
|||
int GetReachabilityFrom(const CNetAddr *paddrPartner = NULL) const; |
|||
void print() const; |
|||
|
|||
CNetAddr(const struct in6_addr& pipv6Addr); |
|||
bool GetIn6Addr(struct in6_addr* pipv6Addr) const; |
|||
|
|||
friend bool operator==(const CNetAddr& a, const CNetAddr& b); |
|||
friend bool operator!=(const CNetAddr& a, const CNetAddr& b); |
|||
friend bool operator<(const CNetAddr& a, const CNetAddr& b); |
|||
|
|||
IMPLEMENT_SERIALIZE |
|||
( |
|||
READWRITE(FLATDATA(ip)); |
|||
) |
|||
}; |
|||
|
|||
/** A combination of a network address (CNetAddr) and a (TCP) port */ |
|||
class CService : public CNetAddr |
|||
{ |
|||
protected: |
|||
unsigned short port; // host order
|
|||
|
|||
public: |
|||
CService(); |
|||
CService(const CNetAddr& ip, unsigned short port); |
|||
CService(const struct in_addr& ipv4Addr, unsigned short port); |
|||
CService(const struct sockaddr_in& addr); |
|||
explicit CService(const char *pszIpPort, int portDefault, bool fAllowLookup = false); |
|||
explicit CService(const char *pszIpPort, bool fAllowLookup = false); |
|||
explicit CService(const std::string& strIpPort, int portDefault, bool fAllowLookup = false); |
|||
explicit CService(const std::string& strIpPort, bool fAllowLookup = false); |
|||
void Init(); |
|||
void SetPort(unsigned short portIn); |
|||
unsigned short GetPort() const; |
|||
bool GetSockAddr(struct sockaddr* paddr, socklen_t *addrlen) const; |
|||
bool SetSockAddr(const struct sockaddr* paddr); |
|||
friend bool operator==(const CService& a, const CService& b); |
|||
friend bool operator!=(const CService& a, const CService& b); |
|||
friend bool operator<(const CService& a, const CService& b); |
|||
std::vector<unsigned char> GetKey() const; |
|||
std::string ToString() const; |
|||
std::string ToStringPort() const; |
|||
std::string ToStringIPPort() const; |
|||
void print() const; |
|||
|
|||
CService(const struct in6_addr& ipv6Addr, unsigned short port); |
|||
CService(const struct sockaddr_in6& addr); |
|||
|
|||
IMPLEMENT_SERIALIZE |
|||
( |
|||
CService* pthis = const_cast<CService*>(this); |
|||
READWRITE(FLATDATA(ip)); |
|||
unsigned short portN = htons(port); |
|||
READWRITE(portN); |
|||
if (fRead) |
|||
pthis->port = ntohs(portN); |
|||
) |
|||
}; |
|||
|
|||
enum Network ParseNetwork(std::string net); |
|||
void SplitHostPort(std::string in, int &portOut, std::string &hostOut); |
|||
bool SetProxy(enum Network net, CService addrProxy, int nSocksVersion = 5); |
|||
bool GetProxy(enum Network net, CService &addrProxy); |
|||
bool IsProxy(const CNetAddr &addr); |
|||
bool SetNameProxy(CService addrProxy, int nSocksVersion = 5); |
|||
bool GetNameProxy(); |
|||
bool LookupHost(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0, bool fAllowLookup = true); |
|||
bool LookupHostNumeric(const char *pszName, std::vector<CNetAddr>& vIP, unsigned int nMaxSolutions = 0); |
|||
bool Lookup(const char *pszName, CService& addr, int portDefault = 0, bool fAllowLookup = true); |
|||
bool Lookup(const char *pszName, std::vector<CService>& vAddr, int portDefault = 0, bool fAllowLookup = true, unsigned int nMaxSolutions = 0); |
|||
bool LookupNumeric(const char *pszName, CService& addr, int portDefault = 0); |
|||
bool ConnectSocket(const CService &addr, SOCKET& hSocketRet, int nTimeout = nConnectTimeout); |
|||
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault = 0, int nTimeout = nConnectTimeout); |
|||
|
|||
#endif |
@ -0,0 +1,159 @@ |
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|||
// Copyright (c) 2011 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#include <vector> |
|||
#include <stdexcept> |
|||
|
|||
#include "protocol.h" |
|||
#include "util.h" |
|||
#include "netbase.h" |
|||
|
|||
|
|||
#ifndef WIN32 |
|||
# include <arpa/inet.h> |
|||
#endif |
|||
|
|||
static const char* ppszTypeName[] = |
|||
{ |
|||
"ERROR", |
|||
"tx", |
|||
"block", |
|||
}; |
|||
|
|||
unsigned char pchMessageStart[4] = { 0x24, 0xE9, 0x27, 0x64 }; |
|||
|
|||
CMessageHeader::CMessageHeader() |
|||
{ |
|||
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); |
|||
memset(pchCommand, 0, sizeof(pchCommand)); |
|||
pchCommand[1] = 1; |
|||
nMessageSize = -1; |
|||
nChecksum = 0; |
|||
} |
|||
|
|||
CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) |
|||
{ |
|||
memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)); |
|||
strncpy(pchCommand, pszCommand, COMMAND_SIZE); |
|||
nMessageSize = nMessageSizeIn; |
|||
nChecksum = 0; |
|||
} |
|||
|
|||
std::string CMessageHeader::GetCommand() const |
|||
{ |
|||
if (pchCommand[COMMAND_SIZE-1] == 0) |
|||
return std::string(pchCommand, pchCommand + strlen(pchCommand)); |
|||
else |
|||
return std::string(pchCommand, pchCommand + COMMAND_SIZE); |
|||
} |
|||
|
|||
bool CMessageHeader::IsValid() const |
|||
{ |
|||
// Check start string
|
|||
if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0) |
|||
return false; |
|||
|
|||
// Check the command string for errors
|
|||
for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++) |
|||
{ |
|||
if (*p1 == 0) |
|||
{ |
|||
// Must be all zeros after the first zero
|
|||
for (; p1 < pchCommand + COMMAND_SIZE; p1++) |
|||
if (*p1 != 0) |
|||
return false; |
|||
} |
|||
else if (*p1 < ' ' || *p1 > 0x7E) |
|||
return false; |
|||
} |
|||
|
|||
// Message size
|
|||
if (nMessageSize > MAX_SIZE) |
|||
{ |
|||
printf("CMessageHeader::IsValid() : (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand().c_str(), nMessageSize); |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
|
|||
CAddress::CAddress() : CService() |
|||
{ |
|||
Init(); |
|||
} |
|||
|
|||
CAddress::CAddress(CService ipIn, uint64 nServicesIn) : CService(ipIn) |
|||
{ |
|||
Init(); |
|||
nServices = nServicesIn; |
|||
} |
|||
|
|||
void CAddress::Init() |
|||
{ |
|||
nServices = NODE_NETWORK; |
|||
nTime = 100000000; |
|||
} |
|||
|
|||
void CAddress::print() const |
|||
{ |
|||
printf("CAddress(%s)\n", ToString().c_str()); |
|||
} |
|||
|
|||
CInv::CInv() |
|||
{ |
|||
type = 0; |
|||
hash = 0; |
|||
} |
|||
|
|||
CInv::CInv(int typeIn, const uint256& hashIn) |
|||
{ |
|||
type = typeIn; |
|||
hash = hashIn; |
|||
} |
|||
|
|||
CInv::CInv(const std::string& strType, const uint256& hashIn) |
|||
{ |
|||
int i; |
|||
for (i = 1; i < ARRAYLEN(ppszTypeName); i++) |
|||
{ |
|||
if (strType == ppszTypeName[i]) |
|||
{ |
|||
type = i; |
|||
break; |
|||
} |
|||
} |
|||
if (i == ARRAYLEN(ppszTypeName)) |
|||
throw std::out_of_range("CInv::CInv(string, uint256) : unknown type"); |
|||
hash = hashIn; |
|||
} |
|||
|
|||
bool operator<(const CInv& a, const CInv& b) |
|||
{ |
|||
return (a.type < b.type || (a.type == b.type && a.hash < b.hash)); |
|||
} |
|||
|
|||
bool CInv::IsKnownType() const |
|||
{ |
|||
return (type >= 1 && type < ARRAYLEN(ppszTypeName)); |
|||
} |
|||
|
|||
const char* CInv::GetCommand() const |
|||
{ |
|||
if (!IsKnownType()) |
|||
throw std::out_of_range("CInv::GetCommand() : unknown type"); |
|||
return ppszTypeName[type]; |
|||
} |
|||
|
|||
std::string CInv::ToString() const |
|||
{ |
|||
return "CInv()"; |
|||
} |
|||
|
|||
void CInv::print() const |
|||
{ |
|||
printf("CInv\n"); |
|||
} |
@ -0,0 +1,123 @@ |
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|||
// Copyright (c) 2011 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
|||
|
|||
#ifndef __cplusplus |
|||
# error This header can only be compiled as C++. |
|||
#endif |
|||
|
|||
#ifndef __INCLUDED_PROTOCOL_H__ |
|||
#define __INCLUDED_PROTOCOL_H__ |
|||
|
|||
#include "netbase.h" |
|||
#include "serialize.h" |
|||
#include <string> |
|||
#include "uint256.h" |
|||
|
|||
extern bool fTestNet; |
|||
static inline unsigned short GetDefaultPort(const bool testnet = fTestNet) |
|||
{ |
|||
return testnet ? 18888 : 8888; |
|||
} |
|||
|
|||
//
|
|||
// Message header
|
|||
// (4) message start
|
|||
// (12) command
|
|||
// (4) size
|
|||
// (4) checksum
|
|||
|
|||
extern unsigned char pchMessageStart[4]; |
|||
|
|||
class CMessageHeader |
|||
{ |
|||
public: |
|||
CMessageHeader(); |
|||
CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn); |
|||
|
|||
std::string GetCommand() const; |
|||
bool IsValid() const; |
|||
|
|||
IMPLEMENT_SERIALIZE |
|||
( |
|||
READWRITE(FLATDATA(pchMessageStart)); |
|||
READWRITE(FLATDATA(pchCommand)); |
|||
READWRITE(nMessageSize); |
|||
if (nVersion >= 209) |
|||
READWRITE(nChecksum); |
|||
) |
|||
|
|||
// TODO: make private (improves encapsulation)
|
|||
public: |
|||
enum { COMMAND_SIZE=12 }; |
|||
char pchMessageStart[sizeof(::pchMessageStart)]; |
|||
char pchCommand[COMMAND_SIZE]; |
|||
unsigned int nMessageSize; |
|||
unsigned int nChecksum; |
|||
}; |
|||
|
|||
enum |
|||
{ |
|||
NODE_NETWORK = (1 << 0), |
|||
}; |
|||
|
|||
class CAddress : public CService |
|||
{ |
|||
public: |
|||
CAddress(); |
|||
CAddress(CService ipIn, uint64 nServicesIn=NODE_NETWORK); |
|||
|
|||
void Init(); |
|||
|
|||
IMPLEMENT_SERIALIZE |
|||
( |
|||
CAddress* pthis = const_cast<CAddress*>(this); |
|||
CService* pip = (CService*)pthis; |
|||
if (fRead) |
|||
pthis->Init(); |
|||
if (nType & SER_DISK) |
|||
READWRITE(nVersion); |
|||
if ((nType & SER_DISK) || (nVersion >= 31402 && !(nType & SER_GETHASH))) |
|||
READWRITE(nTime); |
|||
READWRITE(nServices); |
|||
READWRITE(*pip); |
|||
) |
|||
|
|||
void print() const; |
|||
|
|||
// TODO: make private (improves encapsulation)
|
|||
public: |
|||
uint64 nServices; |
|||
|
|||
// disk and network only
|
|||
unsigned int nTime; |
|||
}; |
|||
|
|||
class CInv |
|||
{ |
|||
public: |
|||
CInv(); |
|||
CInv(int typeIn, const uint256& hashIn); |
|||
CInv(const std::string& strType, const uint256& hashIn); |
|||
|
|||
IMPLEMENT_SERIALIZE |
|||
( |
|||
READWRITE(type); |
|||
READWRITE(hash); |
|||
) |
|||
|
|||
friend bool operator<(const CInv& a, const CInv& b); |
|||
|
|||
bool IsKnownType() const; |
|||
const char* GetCommand() const; |
|||
std::string ToString() const; |
|||
void print() const; |
|||
|
|||
// TODO: make private (improves encapsulation)
|
|||
public: |
|||
int type; |
|||
uint256 hash; |
|||
}; |
|||
|
|||
#endif // __INCLUDED_PROTOCOL_H__
|
File diff suppressed because it is too large
@ -0,0 +1,90 @@ |
|||
/*
|
|||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> |
|||
* |
|||
* Permission to use, copy, modify, and distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
|||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
|||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
|||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
*/ |
|||
#ifndef BITCOIN_STRLCPY_H |
|||
#define BITCOIN_STRLCPY_H |
|||
|
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
|
|||
/*
|
|||
* Copy src to string dst of size siz. At most siz-1 characters |
|||
* will be copied. Always NUL terminates (unless siz == 0). |
|||
* Returns strlen(src); if retval >= siz, truncation occurred. |
|||
*/ |
|||
inline size_t strlcpy(char *dst, const char *src, size_t siz) |
|||
{ |
|||
char *d = dst; |
|||
const char *s = src; |
|||
size_t n = siz; |
|||
|
|||
/* Copy as many bytes as will fit */ |
|||
if (n != 0) |
|||
{ |
|||
while (--n != 0) |
|||
{ |
|||
if ((*d++ = *s++) == '\0') |
|||
break; |
|||
} |
|||
} |
|||
|
|||
/* Not enough room in dst, add NUL and traverse rest of src */ |
|||
if (n == 0) |
|||
{ |
|||
if (siz != 0) |
|||
*d = '\0'; /* NUL-terminate dst */ |
|||
while (*s++) |
|||
; |
|||
} |
|||
|
|||
return(s - src - 1); /* count does not include NUL */ |
|||
} |
|||
|
|||
/*
|
|||
* Appends src to string dst of size siz (unlike strncat, siz is the |
|||
* full size of dst, not space left). At most siz-1 characters |
|||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)). |
|||
* Returns strlen(src) + MIN(siz, strlen(initial dst)). |
|||
* If retval >= siz, truncation occurred. |
|||
*/ |
|||
inline size_t strlcat(char *dst, const char *src, size_t siz) |
|||
{ |
|||
char *d = dst; |
|||
const char *s = src; |
|||
size_t n = siz; |
|||
size_t dlen; |
|||
|
|||
/* Find the end of dst and adjust bytes left but don't go past end */ |
|||
while (n-- != 0 && *d != '\0') |
|||
d++; |
|||
dlen = d - dst; |
|||
n = siz - dlen; |
|||
|
|||
if (n == 0) |
|||
return(dlen + strlen(s)); |
|||
while (*s != '\0') |
|||
{ |
|||
if (n != 1) |
|||
{ |
|||
*d++ = *s; |
|||
n--; |
|||
} |
|||
s++; |
|||
} |
|||
*d = '\0'; |
|||
|
|||
return(dlen + (s - src)); /* count does not include NUL */ |
|||
} |
|||
#endif |
@ -0,0 +1,68 @@ |
|||
#!/usr/bin/perl |
|||
|
|||
use warnings FATAL => 'all'; |
|||
use threads; |
|||
use threads::shared; |
|||
use bytes; |
|||
use IO::Socket; |
|||
use strict; |
|||
|
|||
my @dom = ("seed","bitcoin","sipa","be"); |
|||
|
|||
my $run :shared = 1; |
|||
|
|||
sub go { |
|||
my ($idx) = @_; |
|||
|
|||
my $runs = 0; |
|||
|
|||
my $sock = IO::Socket::INET->new( |
|||
Proto => 'udp', |
|||
PeerPort => 53, |
|||
PeerAddr => "vps.sipa.be", |
|||
) or die "Could not create socket: $!\n"; |
|||
|
|||
while($run) { |
|||
|
|||
my $id = int(rand(65536)); |
|||
my $qr = 0; |
|||
my $opcode = 0; |
|||
my $aa = 0; |
|||
my $tc = 0; |
|||
my $rd = 0; |
|||
my $ra = 0; |
|||
my $z = 0; |
|||
my $rcode = 0; |
|||
my $qdcount = 1; |
|||
my $ancount = 0; |
|||
my $nscount = 0; |
|||
my $arcount = 0; |
|||
my $header = pack('nnnnnn',$id,1*$qr + 2*$opcode + 32*$aa + 64*$tc + 128*$rd + 256*$ra + 512*$z + 4096*$rcode, $qdcount, $ancount, $nscount, $arcount); |
|||
my $qtype = 1; # A record |
|||
my $qclass = 1; # IN class |
|||
my $query = (join("", map { chr(length($_)) . $_ } (@dom,""))) . pack('nn',$qtype,$qclass); |
|||
my $msg = $header . $query; |
|||
$sock->send($msg); |
|||
my $resp; |
|||
$runs++ if ($sock->recv($resp, 512, 0)); |
|||
|
|||
# $sock->close(); |
|||
} |
|||
return $runs; |
|||
} |
|||
|
|||
my @threads; |
|||
|
|||
for my $i (0..500) { |
|||
$threads[$i] = threads->create(\&go, $i); |
|||
} |
|||
|
|||
sleep 10; |
|||
|
|||
$run=0; |
|||
my $runs = 0; |
|||
foreach my $thr (@threads) { |
|||
$runs += $thr->join(); |
|||
} |
|||
|
|||
print "$runs runs\n"; |
@ -0,0 +1,766 @@ |
|||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|||
// Copyright (c) 2011 The Bitcoin developers
|
|||
// Distributed under the MIT/X11 software license, see the accompanying
|
|||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
|||
#ifndef BITCOIN_UINT256_H |
|||
#define BITCOIN_UINT256_H |
|||
|
|||
#include "serialize.h" |
|||
|
|||
#include <limits.h> |
|||
#include <string> |
|||
#include <vector> |
|||
|
|||
#if defined(_MSC_VER) || defined(__BORLANDC__) |
|||
typedef __int64 int64; |
|||
typedef unsigned __int64 uint64; |
|||
#else |
|||
typedef long long int64; |
|||
typedef unsigned long long uint64; |
|||
#endif |
|||
#if defined(_MSC_VER) && _MSC_VER < 1300 |
|||
#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> |
|||
class base_uint |
|||
{ |
|||
protected: |
|||
enum { WIDTH=BITS/32 }; |
|||
unsigned int pn[WIDTH]; |
|||
public: |
|||
|
|||
bool operator!() const |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
if (pn[i] != 0) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
const base_uint operator~() const |
|||
{ |
|||
base_uint ret; |
|||
for (int i = 0; i < WIDTH; i++) |
|||
ret.pn[i] = ~pn[i]; |
|||
return ret; |
|||
} |
|||
|
|||
const base_uint operator-() const |
|||
{ |
|||
base_uint ret; |
|||
for (int i = 0; i < WIDTH; i++) |
|||
ret.pn[i] = ~pn[i]; |
|||
ret++; |
|||
return ret; |
|||
} |
|||
|
|||
|
|||
base_uint& operator=(uint64 b) |
|||
{ |
|||
pn[0] = (unsigned int)b; |
|||
pn[1] = (unsigned int)(b >> 32); |
|||
for (int i = 2; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator^=(const base_uint& b) |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] ^= b.pn[i]; |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator&=(const base_uint& b) |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] &= b.pn[i]; |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator|=(const base_uint& b) |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] |= b.pn[i]; |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator^=(uint64 b) |
|||
{ |
|||
pn[0] ^= (unsigned int)b; |
|||
pn[1] ^= (unsigned int)(b >> 32); |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator&=(uint64 b) |
|||
{ |
|||
pn[0] &= (unsigned int)b; |
|||
pn[1] &= (unsigned int)(b >> 32); |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator|=(uint64 b) |
|||
{ |
|||
pn[0] |= (unsigned int)b; |
|||
pn[1] |= (unsigned int)(b >> 32); |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator<<=(unsigned int shift) |
|||
{ |
|||
base_uint a(*this); |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
int k = shift / 32; |
|||
shift = shift % 32; |
|||
for (int i = 0; i < WIDTH; i++) |
|||
{ |
|||
if (i+k+1 < WIDTH && shift != 0) |
|||
pn[i+k+1] |= (a.pn[i] >> (32-shift)); |
|||
if (i+k < WIDTH) |
|||
pn[i+k] |= (a.pn[i] << shift); |
|||
} |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator>>=(unsigned int shift) |
|||
{ |
|||
base_uint a(*this); |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
int k = shift / 32; |
|||
shift = shift % 32; |
|||
for (int i = 0; i < WIDTH; i++) |
|||
{ |
|||
if (i-k-1 >= 0 && shift != 0) |
|||
pn[i-k-1] |= (a.pn[i] << (32-shift)); |
|||
if (i-k >= 0) |
|||
pn[i-k] |= (a.pn[i] >> shift); |
|||
} |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator+=(const base_uint& b) |
|||
{ |
|||
uint64 carry = 0; |
|||
for (int i = 0; i < WIDTH; i++) |
|||
{ |
|||
uint64 n = carry + pn[i] + b.pn[i]; |
|||
pn[i] = n & 0xffffffff; |
|||
carry = n >> 32; |
|||
} |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator-=(const base_uint& b) |
|||
{ |
|||
*this += -b; |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator+=(uint64 b64) |
|||
{ |
|||
base_uint b; |
|||
b = b64; |
|||
*this += b; |
|||
return *this; |
|||
} |
|||
|
|||
base_uint& operator-=(uint64 b64) |
|||
{ |
|||
base_uint b; |
|||
b = b64; |
|||
*this += -b; |
|||
return *this; |
|||
} |
|||
|
|||
|
|||
base_uint& operator++() |
|||
{ |
|||
// prefix operator
|
|||
int i = 0; |
|||
while (++pn[i] == 0 && i < WIDTH-1) |
|||
i++; |
|||
return *this; |
|||
} |
|||
|
|||
const base_uint operator++(int) |
|||
{ |
|||
// postfix operator
|
|||
const base_uint ret = *this; |
|||
++(*this); |
|||
return ret; |
|||
} |
|||
|
|||
base_uint& operator--() |
|||
{ |
|||
// prefix operator
|
|||
int i = 0; |
|||
while (--pn[i] == -1 && i < WIDTH-1) |
|||
i++; |
|||
return *this; |
|||
} |
|||
|
|||
const base_uint operator--(int) |
|||
{ |
|||
// postfix operator
|
|||
const base_uint ret = *this; |
|||
--(*this); |
|||
return ret; |
|||
} |
|||
|
|||
|
|||
friend inline bool operator<(const base_uint& a, const base_uint& b) |
|||
{ |
|||
for (int i = base_uint::WIDTH-1; i >= 0; i--) |
|||
{ |
|||
if (a.pn[i] < b.pn[i]) |
|||
return true; |
|||
else if (a.pn[i] > b.pn[i]) |
|||
return false; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
friend inline bool operator<=(const base_uint& a, const base_uint& b) |
|||
{ |
|||
for (int i = base_uint::WIDTH-1; i >= 0; i--) |
|||
{ |
|||
if (a.pn[i] < b.pn[i]) |
|||
return true; |
|||
else if (a.pn[i] > b.pn[i]) |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
friend inline bool operator>(const base_uint& a, const base_uint& b) |
|||
{ |
|||
for (int i = base_uint::WIDTH-1; i >= 0; i--) |
|||
{ |
|||
if (a.pn[i] > b.pn[i]) |
|||
return true; |
|||
else if (a.pn[i] < b.pn[i]) |
|||
return false; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
friend inline bool operator>=(const base_uint& a, const base_uint& b) |
|||
{ |
|||
for (int i = base_uint::WIDTH-1; i >= 0; i--) |
|||
{ |
|||
if (a.pn[i] > b.pn[i]) |
|||
return true; |
|||
else if (a.pn[i] < b.pn[i]) |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
friend inline bool operator==(const base_uint& a, const base_uint& b) |
|||
{ |
|||
for (int i = 0; i < base_uint::WIDTH; i++) |
|||
if (a.pn[i] != b.pn[i]) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
friend inline bool operator==(const base_uint& a, uint64 b) |
|||
{ |
|||
if (a.pn[0] != (unsigned int)b) |
|||
return false; |
|||
if (a.pn[1] != (unsigned int)(b >> 32)) |
|||
return false; |
|||
for (int i = 2; i < base_uint::WIDTH; i++) |
|||
if (a.pn[i] != 0) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
friend inline bool operator!=(const base_uint& a, const base_uint& b) |
|||
{ |
|||
return (!(a == b)); |
|||
} |
|||
|
|||
friend inline bool operator!=(const base_uint& a, uint64 b) |
|||
{ |
|||
return (!(a == b)); |
|||
} |
|||
|
|||
|
|||
|
|||
std::string GetHex() const |
|||
{ |
|||
char psz[sizeof(pn)*2 + 1]; |
|||
for (int i = 0; i < sizeof(pn); i++) |
|||
sprintf(psz + i*2, "%02x", ((unsigned char*)pn)[sizeof(pn) - i - 1]); |
|||
return std::string(psz, psz + sizeof(pn)*2); |
|||
} |
|||
|
|||
void SetHex(const char* psz) |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
|
|||
// skip leading spaces
|
|||
while (isspace(*psz)) |
|||
psz++; |
|||
|
|||
// skip 0x
|
|||
if (psz[0] == '0' && tolower(psz[1]) == 'x') |
|||
psz += 2; |
|||
|
|||
// 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') |
|||
psz++; |
|||
psz--; |
|||
unsigned char* p1 = (unsigned char*)pn; |
|||
unsigned char* pend = p1 + WIDTH * 4; |
|||
while (psz >= pbegin && p1 < pend) |
|||
{ |
|||
*p1 = phexdigit[(unsigned char)*psz--]; |
|||
if (psz >= pbegin) |
|||
{ |
|||
*p1 |= (phexdigit[(unsigned char)*psz--] << 4); |
|||
p1++; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void SetHex(const std::string& str) |
|||
{ |
|||
SetHex(str.c_str()); |
|||
} |
|||
|
|||
std::string ToString() const |
|||
{ |
|||
return (GetHex()); |
|||
} |
|||
|
|||
unsigned char* begin() |
|||
{ |
|||
return (unsigned char*)&pn[0]; |
|||
} |
|||
|
|||
unsigned char* end() |
|||
{ |
|||
return (unsigned char*)&pn[WIDTH]; |
|||
} |
|||
|
|||
unsigned int size() |
|||
{ |
|||
return sizeof(pn); |
|||
} |
|||
|
|||
|
|||
unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const |
|||
{ |
|||
return sizeof(pn); |
|||
} |
|||
|
|||
template<typename Stream> |
|||
void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const |
|||
{ |
|||
s.write((char*)pn, sizeof(pn)); |
|||
} |
|||
|
|||
template<typename Stream> |
|||
void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) |
|||
{ |
|||
s.read((char*)pn, sizeof(pn)); |
|||
} |
|||
|
|||
|
|||
friend class uint160; |
|||
friend class uint256; |
|||
friend inline int Testuint256AdHoc(std::vector<std::string> vArg); |
|||
}; |
|||
|
|||
typedef base_uint<160> base_uint160; |
|||
typedef base_uint<256> base_uint256; |
|||
|
|||
|
|||
|
|||
//
|
|||
// uint160 and uint256 could be implemented as templates, but to keep
|
|||
// compile errors and debugging cleaner, they're copy and pasted.
|
|||
//
|
|||
|
|||
|
|||
|
|||
//////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// uint160
|
|||
//
|
|||
|
|||
class uint160 : public base_uint160 |
|||
{ |
|||
public: |
|||
typedef base_uint160 basetype; |
|||
|
|||
uint160() |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
} |
|||
|
|||
uint160(const basetype& b) |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = b.pn[i]; |
|||
} |
|||
|
|||
uint160& operator=(const basetype& b) |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = b.pn[i]; |
|||
return *this; |
|||
} |
|||
|
|||
uint160(uint64 b) |
|||
{ |
|||
pn[0] = (unsigned int)b; |
|||
pn[1] = (unsigned int)(b >> 32); |
|||
for (int i = 2; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
} |
|||
|
|||
uint160& operator=(uint64 b) |
|||
{ |
|||
pn[0] = (unsigned int)b; |
|||
pn[1] = (unsigned int)(b >> 32); |
|||
for (int i = 2; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
return *this; |
|||
} |
|||
|
|||
explicit uint160(const std::string& str) |
|||
{ |
|||
SetHex(str); |
|||
} |
|||
|
|||
explicit uint160(const std::vector<unsigned char>& vch) |
|||
{ |
|||
if (vch.size() == sizeof(pn)) |
|||
memcpy(pn, &vch[0], sizeof(pn)); |
|||
else |
|||
*this = 0; |
|||
} |
|||
}; |
|||
|
|||
inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } |
|||
inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } |
|||
inline const uint160 operator<<(const base_uint160& a, unsigned int shift) { return uint160(a) <<= shift; } |
|||
inline const uint160 operator>>(const base_uint160& a, unsigned int shift) { return uint160(a) >>= shift; } |
|||
inline const uint160 operator<<(const uint160& a, unsigned int shift) { return uint160(a) <<= shift; } |
|||
inline const uint160 operator>>(const uint160& a, unsigned int shift) { return uint160(a) >>= shift; } |
|||
|
|||
inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } |
|||
inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } |
|||
inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } |
|||
inline const uint160 operator+(const base_uint160& a, const base_uint160& b) { return uint160(a) += b; } |
|||
inline const uint160 operator-(const base_uint160& a, const base_uint160& b) { return uint160(a) -= b; } |
|||
|
|||
inline bool operator<(const base_uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } |
|||
inline bool operator<=(const base_uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } |
|||
inline bool operator>(const base_uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } |
|||
inline bool operator>=(const base_uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } |
|||
inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } |
|||
inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } |
|||
inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } |
|||
inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } |
|||
inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } |
|||
inline const uint160 operator+(const base_uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } |
|||
inline const uint160 operator-(const base_uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } |
|||
|
|||
inline bool operator<(const uint160& a, const base_uint160& b) { return (base_uint160)a < (base_uint160)b; } |
|||
inline bool operator<=(const uint160& a, const base_uint160& b) { return (base_uint160)a <= (base_uint160)b; } |
|||
inline bool operator>(const uint160& a, const base_uint160& b) { return (base_uint160)a > (base_uint160)b; } |
|||
inline bool operator>=(const uint160& a, const base_uint160& b) { return (base_uint160)a >= (base_uint160)b; } |
|||
inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } |
|||
inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } |
|||
inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } |
|||
inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } |
|||
inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } |
|||
inline const uint160 operator+(const uint160& a, const base_uint160& b) { return (base_uint160)a + (base_uint160)b; } |
|||
inline const uint160 operator-(const uint160& a, const base_uint160& b) { return (base_uint160)a - (base_uint160)b; } |
|||
|
|||
inline bool operator<(const uint160& a, const uint160& b) { return (base_uint160)a < (base_uint160)b; } |
|||
inline bool operator<=(const uint160& a, const uint160& b) { return (base_uint160)a <= (base_uint160)b; } |
|||
inline bool operator>(const uint160& a, const uint160& b) { return (base_uint160)a > (base_uint160)b; } |
|||
inline bool operator>=(const uint160& a, const uint160& b) { return (base_uint160)a >= (base_uint160)b; } |
|||
inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } |
|||
inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } |
|||
inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } |
|||
inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } |
|||
inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } |
|||
inline const uint160 operator+(const uint160& a, const uint160& b) { return (base_uint160)a + (base_uint160)b; } |
|||
inline const uint160 operator-(const uint160& a, const uint160& b) { return (base_uint160)a - (base_uint160)b; } |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
//////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// uint256
|
|||
//
|
|||
|
|||
class uint256 : public base_uint256 |
|||
{ |
|||
public: |
|||
typedef base_uint256 basetype; |
|||
|
|||
uint256() |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
} |
|||
|
|||
uint256(const basetype& b) |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = b.pn[i]; |
|||
} |
|||
|
|||
uint256& operator=(const basetype& b) |
|||
{ |
|||
for (int i = 0; i < WIDTH; i++) |
|||
pn[i] = b.pn[i]; |
|||
return *this; |
|||
} |
|||
|
|||
uint256(uint64 b) |
|||
{ |
|||
pn[0] = (unsigned int)b; |
|||
pn[1] = (unsigned int)(b >> 32); |
|||
for (int i = 2; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
} |
|||
|
|||
uint256& operator=(uint64 b) |
|||
{ |
|||
pn[0] = (unsigned int)b; |
|||
pn[1] = (unsigned int)(b >> 32); |
|||
for (int i = 2; i < WIDTH; i++) |
|||
pn[i] = 0; |
|||
return *this; |
|||
} |
|||
|
|||
explicit uint256(const std::string& str) |
|||
{ |
|||
SetHex(str); |
|||
} |
|||
|
|||
explicit uint256(const std::vector<unsigned char>& vch) |
|||
{ |
|||
if (vch.size() == sizeof(pn)) |
|||
memcpy(pn, &vch[0], sizeof(pn)); |
|||
else |
|||
*this = 0; |
|||
} |
|||
}; |
|||
|
|||
inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; } |
|||
inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; } |
|||
inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; } |
|||
inline const uint256 operator>>(const base_uint256& a, unsigned int shift) { return uint256(a) >>= shift; } |
|||
inline const uint256 operator<<(const uint256& a, unsigned int shift) { return uint256(a) <<= shift; } |
|||
inline const uint256 operator>>(const uint256& a, unsigned int shift) { return uint256(a) >>= shift; } |
|||
|
|||
inline const uint256 operator^(const base_uint256& a, const base_uint256& b) { return uint256(a) ^= b; } |
|||
inline const uint256 operator&(const base_uint256& a, const base_uint256& b) { return uint256(a) &= b; } |
|||
inline const uint256 operator|(const base_uint256& a, const base_uint256& b) { return uint256(a) |= b; } |
|||
inline const uint256 operator+(const base_uint256& a, const base_uint256& b) { return uint256(a) += b; } |
|||
inline const uint256 operator-(const base_uint256& a, const base_uint256& b) { return uint256(a) -= b; } |
|||
|
|||
inline bool operator<(const base_uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } |
|||
inline bool operator<=(const base_uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } |
|||
inline bool operator>(const base_uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } |
|||
inline bool operator>=(const base_uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } |
|||
inline bool operator==(const base_uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } |
|||
inline bool operator!=(const base_uint256& a, const uint256& b) { return (base_uint256)a != (base_uint256)b; } |
|||
inline const uint256 operator^(const base_uint256& a, const uint256& b) { return (base_uint256)a ^ (base_uint256)b; } |
|||
inline const uint256 operator&(const base_uint256& a, const uint256& b) { return (base_uint256)a & (base_uint256)b; } |
|||
inline const uint256 operator|(const base_uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } |
|||
inline const uint256 operator+(const base_uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } |
|||
inline const uint256 operator-(const base_uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } |
|||
|
|||
inline bool operator<(const uint256& a, const base_uint256& b) { return (base_uint256)a < (base_uint256)b; } |
|||
inline bool operator<=(const uint256& a, const base_uint256& b) { return (base_uint256)a <= (base_uint256)b; } |
|||
inline bool operator>(const uint256& a, const base_uint256& b) { return (base_uint256)a > (base_uint256)b; } |
|||
inline bool operator>=(const uint256& a, const base_uint256& b) { return (base_uint256)a >= (base_uint256)b; } |
|||
inline bool operator==(const uint256& a, const base_uint256& b) { return (base_uint256)a == (base_uint256)b; } |
|||
inline bool operator!=(const uint256& a, const base_uint256& b) { return (base_uint256)a != (base_uint256)b; } |
|||
inline const uint256 operator^(const uint256& a, const base_uint256& b) { return (base_uint256)a ^ (base_uint256)b; } |
|||
inline const uint256 operator&(const uint256& a, const base_uint256& b) { return (base_uint256)a & (base_uint256)b; } |
|||
inline const uint256 operator|(const uint256& a, const base_uint256& b) { return (base_uint256)a | (base_uint256)b; } |
|||
inline const uint256 operator+(const uint256& a, const base_uint256& b) { return (base_uint256)a + (base_uint256)b; } |
|||
inline const uint256 operator-(const uint256& a, const base_uint256& b) { return (base_uint256)a - (base_uint256)b; } |
|||
|
|||
inline bool operator<(const uint256& a, const uint256& b) { return (base_uint256)a < (base_uint256)b; } |
|||
inline bool operator<=(const uint256& a, const uint256& b) { return (base_uint256)a <= (base_uint256)b; } |
|||
inline bool operator>(const uint256& a, const uint256& b) { return (base_uint256)a > (base_uint256)b; } |
|||
inline bool operator>=(const uint256& a, const uint256& b) { return (base_uint256)a >= (base_uint256)b; } |
|||
inline bool operator==(const uint256& a, const uint256& b) { return (base_uint256)a == (base_uint256)b; } |
|||
inline bool 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 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 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 |
@ -0,0 +1,218 @@ |
|||
#include <stdio.h> |
|||
#include "util.h" |
|||
|
|||
using namespace std; |
|||
|
|||
string vstrprintf(const std::string &format, va_list ap) |
|||
{ |
|||
char buffer[50000]; |
|||
char* p = buffer; |
|||
int limit = sizeof(buffer); |
|||
int ret; |
|||
loop |
|||
{ |
|||
va_list arg_ptr; |
|||
va_copy(arg_ptr, ap); |
|||
ret = vsnprintf(p, limit, format.c_str(), arg_ptr); |
|||
va_end(arg_ptr); |
|||
if (ret >= 0 && ret < limit) |
|||
break; |
|||
if (p != buffer) |
|||
delete[] p; |
|||
limit *= 2; |
|||
p = new char[limit]; |
|||
if (p == NULL) |
|||
throw std::bad_alloc(); |
|||
} |
|||
string str(p, p+ret); |
|||
if (p != buffer) |
|||
delete[] p; |
|||
return str; |
|||
} |
|||
|
|||
string EncodeBase32(const unsigned char* pch, size_t len) |
|||
{ |
|||
static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; |
|||
|
|||
string strRet=""; |
|||
strRet.reserve((len+4)/5*8); |
|||
|
|||
int mode=0, left=0; |
|||
const unsigned char *pchEnd = pch+len; |
|||
|
|||
while (pch<pchEnd) |
|||
{ |
|||
int enc = *(pch++); |
|||
switch (mode) |
|||
{ |
|||
case 0: // we have no bits
|
|||
strRet += pbase32[enc >> 3]; |
|||
left = (enc & 7) << 2; |
|||
mode = 1; |
|||
break; |
|||
|
|||
case 1: // we have three bits
|
|||
strRet += pbase32[left | (enc >> 6)]; |
|||
strRet += pbase32[(enc >> 1) & 31]; |
|||
left = (enc & 1) << 4; |
|||
mode = 2; |
|||
break; |
|||
|
|||
case 2: // we have one bit
|
|||
strRet += pbase32[left | (enc >> 4)]; |
|||
left = (enc & 15) << 1; |
|||
mode = 3; |
|||
break; |
|||
|
|||
case 3: // we have four bits
|
|||
strRet += pbase32[left | (enc >> 7)]; |
|||
strRet += pbase32[(enc >> 2) & 31]; |
|||
left = (enc & 3) << 3; |
|||
mode = 4; |
|||
break; |
|||
|
|||
case 4: // we have two bits
|
|||
strRet += pbase32[left | (enc >> 5)]; |
|||
strRet += pbase32[enc & 31]; |
|||
mode = 0; |
|||
} |
|||
} |
|||
|
|||
static const int nPadding[5] = {0, 6, 4, 3, 1}; |
|||
if (mode) |
|||
{ |
|||
strRet += pbase32[left]; |
|||
for (int n=0; n<nPadding[mode]; n++) |
|||
strRet += '='; |
|||
} |
|||
|
|||
return strRet; |
|||
} |
|||
|
|||
string EncodeBase32(const string& str) |
|||
{ |
|||
return EncodeBase32((const unsigned char*)str.c_str(), str.size()); |
|||
} |
|||
|
|||
vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid) |
|||
{ |
|||
static const int decode32_table[256] = |
|||
{ |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
|||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 0, 1, 2, |
|||
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, |
|||
23, 24, 25, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
|||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 |
|||
}; |
|||
|
|||
if (pfInvalid) |
|||
*pfInvalid = false; |
|||
|
|||
vector<unsigned char> vchRet; |
|||
vchRet.reserve((strlen(p))*5/8); |
|||
|
|||
int mode = 0; |
|||
int left = 0; |
|||
|
|||
while (1) |
|||
{ |
|||
int dec = decode32_table[(unsigned char)*p]; |
|||
if (dec == -1) break; |
|||
p++; |
|||
switch (mode) |
|||
{ |
|||
case 0: // we have no bits and get 5
|
|||
left = dec; |
|||
mode = 1; |
|||
break; |
|||
|
|||
case 1: // we have 5 bits and keep 2
|
|||
vchRet.push_back((left<<3) | (dec>>2)); |
|||
left = dec & 3; |
|||
mode = 2; |
|||
break; |
|||
|
|||
case 2: // we have 2 bits and keep 7
|
|||
left = left << 5 | dec; |
|||
mode = 3; |
|||
break; |
|||
|
|||
case 3: // we have 7 bits and keep 4
|
|||
vchRet.push_back((left<<1) | (dec>>4)); |
|||
left = dec & 15; |
|||
mode = 4; |
|||
break; |
|||
|
|||
case 4: // we have 4 bits, and keep 1
|
|||
vchRet.push_back((left<<4) | (dec>>1)); |
|||
left = dec & 1; |
|||
mode = 5; |
|||
break; |
|||
|
|||
case 5: // we have 1 bit, and keep 6
|
|||
left = left << 5 | dec; |
|||
mode = 6; |
|||
break; |
|||
|
|||
case 6: // we have 6 bits, and keep 3
|
|||
vchRet.push_back((left<<2) | (dec>>3)); |
|||
left = dec & 7; |
|||
mode = 7; |
|||
break; |
|||
|
|||
case 7: // we have 3 bits, and keep 0
|
|||
vchRet.push_back((left<<5) | dec); |
|||
mode = 0; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
if (pfInvalid) |
|||
switch (mode) |
|||
{ |
|||
case 0: // 8n base32 characters processed: ok
|
|||
break; |
|||
|
|||
case 1: // 8n+1 base32 characters processed: impossible
|
|||
case 3: // +3
|
|||
case 6: // +6
|
|||
*pfInvalid = true; |
|||
break; |
|||
|
|||
case 2: // 8n+2 base32 characters processed: require '======'
|
|||
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || p[4] != '=' || p[5] != '=' || decode32_table[(unsigned char)p[6]] != -1) |
|||
*pfInvalid = true; |
|||
break; |
|||
|
|||
case 4: // 8n+4 base32 characters processed: require '===='
|
|||
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || p[3] != '=' || decode32_table[(unsigned char)p[4]] != -1) |
|||
*pfInvalid = true; |
|||
break; |
|||
|
|||
case 5: // 8n+5 base32 characters processed: require '==='
|
|||
if (left || p[0] != '=' || p[1] != '=' || p[2] != '=' || decode32_table[(unsigned char)p[3]] != -1) |
|||
*pfInvalid = true; |
|||
break; |
|||
|
|||
case 7: // 8n+7 base32 characters processed: require '='
|
|||
if (left || p[0] != '=' || decode32_table[(unsigned char)p[1]] != -1) |
|||
*pfInvalid = true; |
|||
break; |
|||
} |
|||
|
|||
return vchRet; |
|||
} |
|||
|
|||
string DecodeBase32(const string& str) |
|||
{ |
|||
vector<unsigned char> vchRet = DecodeBase32(str.c_str()); |
|||
return string((const char*)&vchRet[0], vchRet.size()); |
|||
} |
@ -0,0 +1,106 @@ |
|||
#ifndef _UTIL_H_ |
|||
#define _UTIL_H_ 1 |
|||
|
|||
#include <pthread.h> |
|||
#include <errno.h> |
|||
#include <openssl/sha.h> |
|||
#include <stdarg.h> |
|||
|
|||
#include "uint256.h" |
|||
|
|||
#define loop for (;;) |
|||
#define BEGIN(a) ((char*)&(a)) |
|||
#define END(a) ((char*)&((&(a))[1])) |
|||
#define UBEGIN(a) ((unsigned char*)&(a)) |
|||
#define UEND(a) ((unsigned char*)&((&(a))[1])) |
|||
#define ARRAYLEN(array) (sizeof(array)/sizeof((array)[0])) |
|||
|
|||
#define WSAGetLastError() errno |
|||
#define WSAEINVAL EINVAL |
|||
#define WSAEALREADY EALREADY |
|||
#define WSAEWOULDBLOCK EWOULDBLOCK |
|||
#define WSAEMSGSIZE EMSGSIZE |
|||
#define WSAEINTR EINTR |
|||
#define WSAEINPROGRESS EINPROGRESS |
|||
#define WSAEADDRINUSE EADDRINUSE |
|||
#define WSAENOTSOCK EBADF |
|||
#define INVALID_SOCKET (SOCKET)(~0) |
|||
#define SOCKET_ERROR -1 |
|||
|
|||
// Wrapper to automatically initialize mutex
|
|||
class CCriticalSection |
|||
{ |
|||
protected: |
|||
pthread_rwlock_t mutex; |
|||
public: |
|||
explicit CCriticalSection() { pthread_rwlock_init(&mutex, NULL); } |
|||
~CCriticalSection() { pthread_rwlock_destroy(&mutex); } |
|||
void Enter(bool fShared = false) { |
|||
if (fShared) { |
|||
pthread_rwlock_rdlock(&mutex); |
|||
} else { |
|||
pthread_rwlock_wrlock(&mutex); |
|||
} |
|||
} |
|||
void Leave() { pthread_rwlock_unlock(&mutex); } |
|||
}; |
|||
|
|||
// Automatically leave critical section when leaving block, needed for exception safety
|
|||
class CCriticalBlock |
|||
{ |
|||
protected: |
|||
CCriticalSection* pcs; |
|||
public: |
|||
CCriticalBlock(CCriticalSection& cs, bool fShared = false) : pcs(&cs) { pcs->Enter(fShared); } |
|||
operator bool() const { return true; } |
|||
~CCriticalBlock() { pcs->Leave(); } |
|||
}; |
|||
|
|||
#define CRITICAL_BLOCK(cs) \ |
|||
if (CCriticalBlock criticalblock = CCriticalBlock(cs)) |
|||
|
|||
#define SHARED_CRITICAL_BLOCK(cs) \ |
|||
if (CCriticalBlock criticalblock = CCriticalBlock(cs, true)) |
|||
|
|||
template<typename T1> inline uint256 Hash(const T1 pbegin, const T1 pend) |
|||
{ |
|||
static unsigned char pblank[1]; |
|||
uint256 hash1; |
|||
SHA256((pbegin == pend ? pblank : (unsigned char*)&pbegin[0]), (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1); |
|||
uint256 hash2; |
|||
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2); |
|||
return hash2; |
|||
} |
|||
|
|||
void static inline Sleep(int nMilliSec) { |
|||
struct timespec wa; |
|||
wa.tv_sec = nMilliSec/1000; |
|||
wa.tv_nsec = (nMilliSec % 1000) * 1000000; |
|||
nanosleep(&wa, NULL); |
|||
} |
|||
|
|||
|
|||
std::string vstrprintf(const std::string &format, va_list ap); |
|||
|
|||
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); |
|||
va_end(arg_ptr); |
|||
return ret; |
|||
} |
|||
|
|||
bool static inline error(std::string err, ...) { |
|||
return false; |
|||
} |
|||
|
|||
bool static inline my_printf(std::string err, ...) { |
|||
return true; |
|||
} |
|||
|
|||
std::vector<unsigned char> DecodeBase32(const char* p, bool* pfInvalid = NULL); |
|||
std::string DecodeBase32(const std::string& str); |
|||
std::string EncodeBase32(const unsigned char* pch, size_t len); |
|||
std::string EncodeBase32(const std::string& str); |
|||
|
|||
#endif |
Loading…
Reference in new issue