nicer output, dns modular
This commit is contained in:
parent
d0d24282b3
commit
c5fc5b4efb
7 changed files with 173 additions and 122 deletions
14
Makefile
14
Makefile
|
@ -1,6 +1,14 @@
|
||||||
dnsseed: dns.o bitcoin.cpp netbase.cpp protocol.cpp db.cpp main.cpp bitcoin.h netbase.h protocol.h db.h serialize.h uint256.h util.h
|
dnsseed: dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
||||||
g++ -pthread -lssl -O3 -ggdb3 -march=nocona -Wno-invalid-offsetof -o dnsseed bitcoin.cpp netbase.cpp protocol.cpp db.cpp main.cpp dns.o
|
g++ -pthread -lssl -o dnsseed dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
||||||
|
strip -s dnsseed
|
||||||
|
|
||||||
|
dnsseed.dbg: dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
||||||
|
g++ -pthread -lssl -o dnsseed.dbg dns.o bitcoin.o netbase.o protocol.o db.o main.o
|
||||||
|
|
||||||
|
%.o: %.cpp bitcoin.h netbase.h protocol.h db.h serialize.h uint256.h util.h
|
||||||
|
g++ -pthread -O3 -ggdb3 -march=nocona -Wno-invalid-offsetof -c -o $@ $<
|
||||||
|
|
||||||
dns.o: dns.c
|
dns.o: dns.c
|
||||||
gcc -std=c99 -O3 -g0 -march=nocona dns.c -c -o dns.o
|
gcc -pthread -std=c99 -O3 -g0 -march=nocona dns.c -c -o dns.o
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
|
31
bitcoin.cpp
31
bitcoin.cpp
|
@ -32,7 +32,7 @@ class CNode {
|
||||||
nHeaderStart = vSend.size();
|
nHeaderStart = vSend.size();
|
||||||
vSend << CMessageHeader(pszCommand, 0);
|
vSend << CMessageHeader(pszCommand, 0);
|
||||||
nMessageStart = vSend.size();
|
nMessageStart = vSend.size();
|
||||||
printf("%s: SEND %s\n", you.ToString().c_str(), pszCommand);
|
// printf("%s: SEND %s\n", ToString(you).c_str(), pszCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbortMessage() {
|
void AbortMessage() {
|
||||||
|
@ -83,18 +83,18 @@ class CNode {
|
||||||
|
|
||||||
void GotVersion() {
|
void GotVersion() {
|
||||||
if (nVersion < MIN_VERSION) {
|
if (nVersion < MIN_VERSION) {
|
||||||
printf("%s: BAD (version %i is below %i)\n", you.ToString().c_str(), nVersion, MIN_VERSION);
|
printf("%s: BAD (version %i is below %i)\n", ToString(you).c_str(), nVersion, MIN_VERSION);
|
||||||
ban = 1000000;
|
ban = 1000000;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printf("%s: version %i\n", you.ToString().c_str(), nVersion);
|
printf("%s: version %i\n", ToString(you).c_str(), nVersion);
|
||||||
BeginMessage("getaddr");
|
BeginMessage("getaddr");
|
||||||
EndMessage();
|
EndMessage();
|
||||||
doneAfter = time(NULL) + 10;
|
doneAfter = time(NULL) + 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessMessage(string strCommand, CDataStream& vRecv) {
|
bool ProcessMessage(string strCommand, CDataStream& vRecv) {
|
||||||
printf("%s: RECV %s\n", you.ToString().c_str(), strCommand.c_str());
|
// printf("%s: RECV %s\n", ToString(you).c_str(), strCommand.c_str());
|
||||||
if (strCommand == "version") {
|
if (strCommand == "version") {
|
||||||
int64 nTime;
|
int64 nTime;
|
||||||
CAddress addrMe;
|
CAddress addrMe;
|
||||||
|
@ -110,7 +110,7 @@ class CNode {
|
||||||
vRecv >> nStartingHeight;
|
vRecv >> nStartingHeight;
|
||||||
|
|
||||||
if (!(you.nServices & NODE_NETWORK)) {
|
if (!(you.nServices & NODE_NETWORK)) {
|
||||||
printf("%s: BAD (no NODE_NETWORK)\n", you.ToString().c_str());
|
printf("%s: BAD (no NODE_NETWORK)\n", ToString(you).c_str());
|
||||||
ban = 1000000;
|
ban = 1000000;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -136,20 +136,20 @@ class CNode {
|
||||||
if (strCommand == "addr") {
|
if (strCommand == "addr") {
|
||||||
vector<CAddress> vAddrNew;
|
vector<CAddress> vAddrNew;
|
||||||
vRecv >> vAddrNew;
|
vRecv >> vAddrNew;
|
||||||
printf("%s: got %i addresses\n", you.ToString().c_str(), (int)vAddrNew.size());
|
printf("%s: got %i addresses\n", ToString(you).c_str(), (int)vAddrNew.size());
|
||||||
int64 now = time(NULL);
|
int64 now = time(NULL);
|
||||||
vector<CAddress>::iterator it = vAddrNew.begin();
|
vector<CAddress>::iterator it = vAddrNew.begin();
|
||||||
if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1;
|
if (doneAfter == 0 || doneAfter > now + 1) doneAfter = now + 1;
|
||||||
while (it != vAddrNew.end()) {
|
while (it != vAddrNew.end()) {
|
||||||
CAddress &addr = *it;
|
CAddress &addr = *it;
|
||||||
// printf("%s: got address %s\n", you.ToString().c_str(), addr.ToString().c_str(), (int)(vAddr->size()));
|
// printf("%s: got address %s\n", ToString(you).c_str(), addr.ToString().c_str(), (int)(vAddr->size()));
|
||||||
it++;
|
it++;
|
||||||
if (!addr.IsIPv4())
|
if (!addr.IsIPv4())
|
||||||
continue;
|
continue;
|
||||||
if (addr.nTime <= 100000000 || addr.nTime > now + 600)
|
if (addr.nTime <= 100000000 || addr.nTime > now + 600)
|
||||||
addr.nTime = now - 5 * 86400;
|
addr.nTime = now - 5 * 86400;
|
||||||
vAddr->push_back(addr);
|
vAddr->push_back(addr);
|
||||||
// printf("%s: added address %s (#%i)\n", you.ToString().c_str(), addr.ToString().c_str(), (int)(vAddr->size()));
|
// 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; }
|
if (vAddr->size() > 1000) {doneAfter = 1; return true; }
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -174,13 +174,13 @@ class CNode {
|
||||||
CMessageHeader hdr;
|
CMessageHeader hdr;
|
||||||
vRecv >> hdr;
|
vRecv >> hdr;
|
||||||
if (!hdr.IsValid()) {
|
if (!hdr.IsValid()) {
|
||||||
printf("%s: BAD (invalid header)\n", you.ToString().c_str());
|
printf("%s: BAD (invalid header)\n", ToString(you).c_str());
|
||||||
ban = 100000; return true;
|
ban = 100000; return true;
|
||||||
}
|
}
|
||||||
string strCommand = hdr.GetCommand();
|
string strCommand = hdr.GetCommand();
|
||||||
unsigned int nMessageSize = hdr.nMessageSize;
|
unsigned int nMessageSize = hdr.nMessageSize;
|
||||||
if (nMessageSize > MAX_SIZE) {
|
if (nMessageSize > MAX_SIZE) {
|
||||||
printf("%s: BAD (message too large)\n", you.ToString().c_str());
|
printf("%s: BAD (message too large)\n", ToString(you).c_str());
|
||||||
ban = 100000;
|
ban = 100000;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -198,7 +198,7 @@ class CNode {
|
||||||
vRecv.ignore(nMessageSize);
|
vRecv.ignore(nMessageSize);
|
||||||
if (ProcessMessage(strCommand, vMsg))
|
if (ProcessMessage(strCommand, vMsg))
|
||||||
return true;
|
return true;
|
||||||
printf("%s: done processing %s\n", you.ToString().c_str(), strCommand.c_str());
|
// printf("%s: done processing %s\n", ToString(you).c_str(), strCommand.c_str());
|
||||||
} while(1);
|
} while(1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -244,8 +244,12 @@ public:
|
||||||
vRecv.resize(nPos + nBytes);
|
vRecv.resize(nPos + nBytes);
|
||||||
memcpy(&vRecv[nPos], pchBuf, nBytes);
|
memcpy(&vRecv[nPos], pchBuf, nBytes);
|
||||||
} else if (nBytes == 0) {
|
} else if (nBytes == 0) {
|
||||||
Sleep(127);
|
printf("%s: BAD (connection closed prematurely)\n", ToString(you).c_str());
|
||||||
|
res = false;
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
printf("%s: BAD (connection error)\n", ToString(you).c_str());
|
||||||
|
res = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ProcessMessages();
|
ProcessMessages();
|
||||||
|
@ -270,7 +274,7 @@ bool TestNode(const CIPPort &cip, int &ban, vector<CAddress>& vAddr) {
|
||||||
} else {
|
} else {
|
||||||
ban = 0;
|
ban = 0;
|
||||||
}
|
}
|
||||||
printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD");
|
// printf("%s: %s!!!\n", cip.ToString().c_str(), ret ? "GOOD" : "BAD");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,3 +288,4 @@ int main(void) {
|
||||||
printf("ret=%s ban=%i vAddr.size()=%i\n", ret ? "good" : "bad", ban, (int)vAddr.size());
|
printf("ret=%s ban=%i vAddr.size()=%i\n", ret ? "good" : "bad", ban, (int)vAddr.size());
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
45
db.cpp
45
db.cpp
|
@ -5,6 +5,8 @@ using namespace std;
|
||||||
|
|
||||||
void CAddrInfo::Update(bool good) {
|
void CAddrInfo::Update(bool good) {
|
||||||
uint32_t now = time(NULL);
|
uint32_t now = time(NULL);
|
||||||
|
if (ourLastTry == 0)
|
||||||
|
ourLastTry = now - MIN_RETRY;
|
||||||
double f = exp(-(now-ourLastTry)/TAU);
|
double f = exp(-(now-ourLastTry)/TAU);
|
||||||
reliability = reliability * f + (good ? (1.0-f) : 0);
|
reliability = reliability * f + (good ? (1.0-f) : 0);
|
||||||
timing = (timing + (now-ourLastTry) * weight) * f;
|
timing = (timing + (now-ourLastTry) * weight) * f;
|
||||||
|
@ -14,14 +16,11 @@ void CAddrInfo::Update(bool good) {
|
||||||
ourLastTry = now;
|
ourLastTry = now;
|
||||||
total++;
|
total++;
|
||||||
if (good) success++;
|
if (good) success++;
|
||||||
printf("%s: got %s result: weight=%g reliability=%g avgage=%g count=%g success=%i/%i\n", ip.ToString().c_str(), good ? "good" : "bad", weight, reliability/weight, timing/weight, count/weight, success, total);
|
printf("%s: got %s result: weight=%g reliability=%g avgage=%g count=%g success=%i/%i\n", ToString(ip).c_str(), good ? "good" : "bad", weight, GetReliability(), GetAvgAge(), GetCount(), success, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CAddrDb::Get_(CIPPort &ip, int &wait) {
|
bool CAddrDb::Get_(CIPPort &ip, int &wait) {
|
||||||
int cont = 0;
|
|
||||||
int64 now = time(NULL);
|
int64 now = time(NULL);
|
||||||
do {
|
|
||||||
cont = 0;
|
|
||||||
int tot = unkId.size();
|
int tot = unkId.size();
|
||||||
deque<int>::iterator it = ourId.begin();
|
deque<int>::iterator it = ourId.begin();
|
||||||
while (it < ourId.end()) {
|
while (it < ourId.end()) {
|
||||||
|
@ -40,18 +39,18 @@ bool CAddrDb::Get_(CIPPort &ip, int &wait) {
|
||||||
}
|
}
|
||||||
int rnd = rand() % tot;
|
int rnd = rand() % tot;
|
||||||
if (rnd < unkId.size()) {
|
if (rnd < unkId.size()) {
|
||||||
set<int>::iterator it = unkId.begin();
|
set<int>::reverse_iterator it = unkId.rbegin();
|
||||||
ip = idToInfo[*it].ip;
|
ip = idToInfo[*it].ip;
|
||||||
unkId.erase(it);
|
unkId.erase(*it);
|
||||||
printf("From UNK: %s\n", ip.ToString().c_str());
|
printf("%s: new node\n", ToString(ip).c_str());
|
||||||
} else {
|
} else {
|
||||||
int ret = ourId.front();
|
int ret = ourId.front();
|
||||||
if (time(NULL) - idToInfo[ret].ourLastTry < MIN_RETRY) return false;
|
if (time(NULL) - idToInfo[ret].ourLastTry < MIN_RETRY) return false;
|
||||||
ourId.pop_front();
|
ourId.pop_front();
|
||||||
ip = idToInfo[ret].ip;
|
ip = idToInfo[ret].ip;
|
||||||
printf("From OUR: %s (size = %i)\n", ip.ToString().c_str(), (int)ourId.size());
|
printf("%s: old node\n", ToString(ip).c_str());
|
||||||
}
|
}
|
||||||
} while(cont);
|
fDirty = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,18 +61,17 @@ int CAddrDb::Lookup_(const CIPPort &ip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAddrDb::Good_(const CIPPort &addr) {
|
void CAddrDb::Good_(const CIPPort &addr) {
|
||||||
printf("%s: good!\n", addr.ToString().c_str());
|
|
||||||
int id = Lookup_(addr);
|
int id = Lookup_(addr);
|
||||||
printf("%s: good (id=%i)!\n", addr.ToString().c_str(), id);
|
|
||||||
if (id == -1) return;
|
if (id == -1) return;
|
||||||
unkId.erase(id);
|
unkId.erase(id);
|
||||||
banned.erase(addr);
|
banned.erase(addr);
|
||||||
CAddrInfo &info = idToInfo[id];
|
CAddrInfo &info = idToInfo[id];
|
||||||
info.Update(true);
|
info.Update(true);
|
||||||
if (info.IsGood()) {
|
if (info.IsGood() && goodId.count(id)==0) {
|
||||||
goodId.insert(id);
|
goodId.insert(id);
|
||||||
printf("%s: good; %i good nodes now\n", addr.ToString().c_str(), (int)goodId.size());
|
printf("%s: good; %i good nodes now\n", ToString(addr).c_str(), (int)goodId.size());
|
||||||
}
|
}
|
||||||
|
fDirty = true;
|
||||||
ourId.push_back(id);
|
ourId.push_back(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,22 +84,23 @@ void CAddrDb::Bad_(const CIPPort &addr, int ban)
|
||||||
info.Update(false);
|
info.Update(false);
|
||||||
uint32_t now = time(NULL);
|
uint32_t now = time(NULL);
|
||||||
if (info.IsTerrible()) {
|
if (info.IsTerrible()) {
|
||||||
printf("%s: terrible\n", addr.ToString().c_str());
|
printf("%s: terrible\n", ToString(addr).c_str());
|
||||||
if (ban < 604800) ban = 604800;
|
if (ban < 604800) ban = 604800;
|
||||||
}
|
}
|
||||||
if (ban > 0) {
|
if (ban > 0) {
|
||||||
printf("%s: ban %i seconds\n", addr.ToString().c_str(), ban);
|
printf("%s: ban for %i seconds\n", ToString(addr).c_str(), ban);
|
||||||
banned[info.ip] = ban + now;
|
banned[info.ip] = ban + now;
|
||||||
ipToId.erase(info.ip);
|
ipToId.erase(info.ip);
|
||||||
goodId.erase(id);
|
goodId.erase(id);
|
||||||
idToInfo.erase(id);
|
idToInfo.erase(id);
|
||||||
} else {
|
} else {
|
||||||
if (!info.IsGood()) {
|
if (!info.IsGood() && goodId.count(id)==1) {
|
||||||
goodId.erase(id);
|
goodId.erase(id);
|
||||||
printf("%s: not good; %i good nodes left\n", addr.ToString().c_str(), (int)goodId.size());
|
printf("%s: not good; %i good nodes left\n", ToString(addr).c_str(), (int)goodId.size());
|
||||||
}
|
}
|
||||||
ourId.push_back(id);
|
ourId.push_back(id);
|
||||||
}
|
}
|
||||||
|
fDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAddrDb::Skipped_(const CIPPort &addr)
|
void CAddrDb::Skipped_(const CIPPort &addr)
|
||||||
|
@ -110,7 +109,8 @@ void CAddrDb::Skipped_(const CIPPort &addr)
|
||||||
if (id == -1) return;
|
if (id == -1) return;
|
||||||
unkId.erase(id);
|
unkId.erase(id);
|
||||||
ourId.push_back(id);
|
ourId.push_back(id);
|
||||||
printf("%s: skipped\n", addr.ToString().c_str());
|
printf("%s: skipped\n", ToString(addr).c_str());
|
||||||
|
fDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,10 +127,12 @@ void CAddrDb::Add_(const CAddress &addr) {
|
||||||
}
|
}
|
||||||
if (ipToId.count(ipp)) {
|
if (ipToId.count(ipp)) {
|
||||||
CAddrInfo &ai = idToInfo[ipToId[ipp]];
|
CAddrInfo &ai = idToInfo[ipToId[ipp]];
|
||||||
if (addr.nTime > ai.lastTry)
|
if (addr.nTime > ai.lastTry || ai.services != addr.nServices)
|
||||||
|
{
|
||||||
ai.lastTry = addr.nTime;
|
ai.lastTry = addr.nTime;
|
||||||
ai.services |= addr.nServices;
|
ai.services |= addr.nServices;
|
||||||
printf("%s: updated\n", addr.ToString().c_str());
|
// printf("%s: updated\n", ToString(addr).c_str());
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CAddrInfo ai;
|
CAddrInfo ai;
|
||||||
|
@ -145,8 +147,9 @@ void CAddrDb::Add_(const CAddress &addr) {
|
||||||
int id = nId++;
|
int id = nId++;
|
||||||
idToInfo[id] = ai;
|
idToInfo[id] = ai;
|
||||||
ipToId[ipp] = id;
|
ipToId[ipp] = id;
|
||||||
printf("%s: added as id %i\n", ipp.ToString().c_str(), ipToId[ipp]);
|
printf("%s: added\n", ToString(ipp).c_str(), ipToId[ipp]);
|
||||||
unkId.insert(id);
|
unkId.insert(id);
|
||||||
|
fDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAddrDb::GetIPs_(set<CIP>& ips, int max, bool fOnlyIPv4) {
|
void CAddrDb::GetIPs_(set<CIP>& ips, int max, bool fOnlyIPv4) {
|
||||||
|
|
71
db.h
71
db.h
|
@ -13,6 +13,12 @@
|
||||||
#define TAU 86400.0
|
#define TAU 86400.0
|
||||||
#define MIN_RETRY 1000
|
#define MIN_RETRY 1000
|
||||||
|
|
||||||
|
std::string static inline ToString(const CIPPort &ip) {
|
||||||
|
std::string str = ip.ToString();
|
||||||
|
while (str.size() < 22) str += ' ';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
class CAddrInfo {
|
class CAddrInfo {
|
||||||
private:
|
private:
|
||||||
CIPPort ip;
|
CIPPort ip;
|
||||||
|
@ -26,11 +32,14 @@ private:
|
||||||
int total;
|
int total;
|
||||||
int success;
|
int success;
|
||||||
public:
|
public:
|
||||||
|
double GetCount() const { return count; }
|
||||||
|
double GetAvgAge() const { return timing/weight; }
|
||||||
|
double GetReliability() const { return reliability/weight; }
|
||||||
bool IsGood() {
|
bool IsGood() {
|
||||||
return (weight > 0 && reliability/weight > 0.8 && timing/weight < 86400) && ip.GetPort() == 8333;
|
return (weight > 0 && GetReliability() > 0.8 && GetAvgAge() < 86400 && ip.GetPort() == 8333 && ip.IsRoutable());
|
||||||
}
|
}
|
||||||
bool IsTerrible() {
|
bool IsTerrible() {
|
||||||
return (weight > 0.5 & reliability/weight < 0.2 && timing/weight < 86400 && count/weight > 2.0);
|
return ((weight > 0.1 && GetCount() > 5 && GetReliability() < 0.05) || (weight > 0.5 && GetReliability() < 0.2 && GetAvgAge() > 7200 && GetCount() > 5));
|
||||||
}
|
}
|
||||||
void Update(bool good);
|
void Update(bool good);
|
||||||
|
|
||||||
|
@ -54,9 +63,9 @@ public:
|
||||||
|
|
||||||
// seen nodes
|
// seen nodes
|
||||||
// / \
|
// / \
|
||||||
// (a) banned nodes tracked nodes
|
// (a) banned nodes available nodes--------------
|
||||||
// / \
|
// / | \
|
||||||
// tried nodes (b) unknown nodes
|
// tracked nodes (b) unknown nodes (e) active nodes
|
||||||
// / \
|
// / \
|
||||||
// (d) good nodes (c) non-good nodes
|
// (d) good nodes (c) non-good nodes
|
||||||
|
|
||||||
|
@ -64,24 +73,36 @@ class CAddrDb {
|
||||||
private:
|
private:
|
||||||
mutable CCriticalSection cs;
|
mutable CCriticalSection cs;
|
||||||
int nId; // number of address id's
|
int nId; // number of address id's
|
||||||
std::map<int, CAddrInfo> idToInfo; // map address id to address info (b,c,d)
|
std::map<int, CAddrInfo> idToInfo; // map address id to address info (b,c,d,e)
|
||||||
std::map<CIPPort, int> ipToId; // map ip to id (b,c,d)
|
std::map<CIPPort, 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::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> unkId; // set of nodes not yet tried (b)
|
||||||
std::set<int> goodId; // set of good nodes (d)
|
std::set<int> goodId; // set of good nodes (d, good e)
|
||||||
std::map<CIPPort, time_t> banned; // nodes that are banned, with their unban time (a)
|
std::map<CIPPort, time_t> banned; // nodes that are banned, with their unban time (a)
|
||||||
|
bool fDirty;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Add_(const CAddress &addr);
|
// internal routines that assume proper locks are acquired
|
||||||
void Good_(const CIPPort &ip);
|
void Add_(const CAddress &addr); // add an address
|
||||||
void Bad_(const CIPPort &ip, int ban);
|
bool Get_(CIPPort &ip, int& wait); // get an IP to test (must call Good_, Bad_, or Skipped_ on result afterwards)
|
||||||
void Skipped_(const CIPPort &ip);
|
void Good_(const CIPPort &ip); // mark an IP as good (must have been returned by Get_)
|
||||||
bool Get_(CIPPort &ip, int& wait);
|
void Bad_(const CIPPort &ip, int ban); // mark an IP as bad (and optionally ban it) (must have been returned by Get_)
|
||||||
int Lookup_(const CIPPort &ip);
|
void Skipped_(const CIPPort &ip); // mark an IP as skipped (must have been returned by Get_)
|
||||||
void GetIPs_(std::set<CIP>& ips, int max, bool fOnlyIPv4);
|
int Lookup_(const CIPPort &ip); // look up id of an IP
|
||||||
|
void GetIPs_(std::set<CIP>& ips, int max, bool fOnlyIPv4); // get a random set of IPs (shared lock only)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// seriazlization code
|
||||||
|
// format:
|
||||||
|
// nVersion (0 for now)
|
||||||
|
// nOur (number of ips in (c,d))
|
||||||
|
// nUnk (number of ips in (b))
|
||||||
|
// CAddrInfo[nOur]
|
||||||
|
// CAddrInfo[nUnk]
|
||||||
|
// 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 (({
|
IMPLEMENT_SERIALIZE (({
|
||||||
int nVersion = 0;
|
int nVersion = 0;
|
||||||
READWRITE(nVersion);
|
READWRITE(nVersion);
|
||||||
|
@ -109,28 +130,44 @@ public:
|
||||||
for (int i=0; i<nOur; i++) {
|
for (int i=0; i<nOur; i++) {
|
||||||
CAddrInfo info;
|
CAddrInfo info;
|
||||||
READWRITE(info);
|
READWRITE(info);
|
||||||
|
if (!info.IsTerrible()) {
|
||||||
int id = db->nId++;
|
int id = db->nId++;
|
||||||
db->idToInfo[id] = info;
|
db->idToInfo[id] = info;
|
||||||
db->ipToId[info.ip] = id;
|
db->ipToId[info.ip] = id;
|
||||||
db->ourId.push_back(id);
|
db->ourId.push_back(id);
|
||||||
if (info.IsGood()) db->goodId.insert(id);
|
if (info.IsGood()) db->goodId.insert(id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for (int i=0; i<nUnk; i++) {
|
for (int i=0; i<nUnk; i++) {
|
||||||
CAddrInfo info;
|
CAddrInfo info;
|
||||||
READWRITE(info);
|
READWRITE(info);
|
||||||
|
if (!info.IsTerrible()) {
|
||||||
int id = db->nId++;
|
int id = db->nId++;
|
||||||
db->idToInfo[id] = info;
|
db->idToInfo[id] = info;
|
||||||
db->ipToId[info.ip] = id;
|
db->ipToId[info.ip] = id;
|
||||||
db->unkId.insert(id);
|
db->unkId.insert(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
db->fDirty = true;
|
||||||
|
}
|
||||||
READWRITE(banned);
|
READWRITE(banned);
|
||||||
}
|
}
|
||||||
});)
|
});)
|
||||||
|
|
||||||
|
// print statistics
|
||||||
void Stats() {
|
void Stats() {
|
||||||
CRITICAL_BLOCK(cs)
|
SHARED_CRITICAL_BLOCK(cs) {
|
||||||
printf("**** %i good, %lu our, %i unk, %i banned; %i known ips\n", (int)goodId.size(), (unsigned long)ourId.size(), (int)unkId.size(), (int)banned.size(), (int)ipToId.size());
|
if (fDirty) {
|
||||||
|
printf("**** %i available (%i tracked, %i new, %i active), %i banned; %i good\n",
|
||||||
|
(int)idToInfo.size(),
|
||||||
|
(int)ourId.size(),
|
||||||
|
(int)unkId.size(),
|
||||||
|
(int)idToInfo.size() - (int)ourId.size() - (int)unkId.size(),
|
||||||
|
(int)banned.size(),
|
||||||
|
(int)goodId.size());
|
||||||
|
fDirty = false; // hopefully atomic
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void Add(const CAddress &addr) {
|
void Add(const CAddress &addr) {
|
||||||
CRITICAL_BLOCK(cs)
|
CRITICAL_BLOCK(cs)
|
||||||
|
|
53
dns.c
53
dns.c
|
@ -9,17 +9,10 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "dns.h"
|
||||||
|
|
||||||
#define BUFLEN 512
|
#define BUFLEN 512
|
||||||
|
|
||||||
int port = 53;
|
|
||||||
int datattl = 60;
|
|
||||||
int nsttl = 30583;
|
|
||||||
char *host = "seedtest.bitcoin.sipa.be";
|
|
||||||
char *ns = "vps.sipa.be";
|
|
||||||
char *mbox = "sipa.ulyssis.org";
|
|
||||||
|
|
||||||
extern int GetIPList(struct in_addr *addr, int max, int ipv4only);
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CLASS_IN = 1,
|
CLASS_IN = 1,
|
||||||
QCLASS_ANY = 255
|
QCLASS_ANY = 255
|
||||||
|
@ -88,10 +81,10 @@ int static parse_name(const unsigned char **inpos, const unsigned char *inend, c
|
||||||
// -1: component > 63 characters
|
// -1: component > 63 characters
|
||||||
// -2: insufficent space in output
|
// -2: insufficent space in output
|
||||||
// -3: two subsequent dots
|
// -3: two subsequent dots
|
||||||
int static write_name(unsigned char** outpos, unsigned char *outend, char *name, int offset) {
|
int static write_name(unsigned char** outpos, const unsigned char *outend, const char *name, int offset) {
|
||||||
while (*name != 0) {
|
while (*name != 0) {
|
||||||
char *dot = strchr(name, '.');
|
char *dot = strchr(name, '.');
|
||||||
char *fin = dot;
|
const char *fin = dot;
|
||||||
if (!dot) fin = name + strlen(name);
|
if (!dot) fin = name + strlen(name);
|
||||||
if (fin - name > 63) return -1;
|
if (fin - name > 63) return -1;
|
||||||
if (fin == name) return -3;
|
if (fin == name) return -3;
|
||||||
|
@ -114,7 +107,7 @@ int static write_name(unsigned char** outpos, unsigned char *outend, char *name,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int static write_record(unsigned char** outpos, unsigned char *outend, char *name, int offset, dns_type typ, dns_class cls, int ttl) {
|
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;
|
unsigned char *oldpos = *outpos;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
// name
|
// name
|
||||||
|
@ -134,7 +127,7 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int static write_record_a(unsigned char** outpos, unsigned char *outend, char *name, int offset, dns_class cls, int ttl, const struct in_addr *ip) {
|
int static write_record_a(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const struct in_addr *ip) {
|
||||||
unsigned char *oldpos = *outpos;
|
unsigned char *oldpos = *outpos;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl);
|
int ret = write_record(outpos, outend, name, offset, TYPE_A, cls, ttl);
|
||||||
|
@ -152,7 +145,7 @@ error:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int static write_record_aaaa(unsigned char** outpos, unsigned char *outend, char *name, int offset, dns_class cls, int ttl, const struct in6_addr *ip) {
|
int static write_record_aaaa(unsigned char** outpos, const unsigned char *outend, const char *name, int offset, dns_class cls, int ttl, const struct in6_addr *ip) {
|
||||||
unsigned char *oldpos = *outpos;
|
unsigned char *oldpos = *outpos;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int ret = write_record(outpos, outend, name, offset, TYPE_AAAA, cls, ttl);
|
int ret = write_record(outpos, outend, name, offset, TYPE_AAAA, cls, ttl);
|
||||||
|
@ -170,7 +163,7 @@ error:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int static write_record_ns(unsigned char** outpos, unsigned char *outend, char *name, int offset, dns_class cls, int ttl, char *ns) {
|
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;
|
unsigned char *oldpos = *outpos;
|
||||||
int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl);
|
int ret = write_record(outpos, outend, name, offset, TYPE_NS, cls, ttl);
|
||||||
if (ret) return ret;
|
if (ret) return ret;
|
||||||
|
@ -188,7 +181,7 @@ error:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
int static write_record_soa(unsigned char** outpos, unsigned char *outend, char *name, int offset, dns_class cls, int ttl, char* mname, char *rname,
|
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) {
|
uint32_t serial, uint32_t refresh, uint32_t retry, uint32_t expire, uint32_t minimum) {
|
||||||
unsigned char *oldpos = *outpos;
|
unsigned char *oldpos = *outpos;
|
||||||
int ret = write_record(outpos, outend, name, offset, TYPE_SOA, cls, ttl);
|
int ret = write_record(outpos, outend, name, offset, TYPE_SOA, cls, ttl);
|
||||||
|
@ -215,7 +208,7 @@ error:
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t static dnshandle(const unsigned char *inbuf, size_t insize, unsigned char* outbuf) {
|
ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insize, unsigned char* outbuf) {
|
||||||
int error = 0;
|
int error = 0;
|
||||||
if (insize < 12) // DNS header
|
if (insize < 12) // DNS header
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -248,8 +241,8 @@ ssize_t static dnshandle(const unsigned char *inbuf, size_t insize, unsigned cha
|
||||||
int ret = parse_name(&inpos, inend, inbuf, name, 256);
|
int ret = parse_name(&inpos, inend, inbuf, name, 256);
|
||||||
if (ret == -1) { error = 1; goto error; }
|
if (ret == -1) { error = 1; goto error; }
|
||||||
if (ret == -2) { error = 5; goto error; }
|
if (ret == -2) { error = 5; goto error; }
|
||||||
int namel = strlen(name), hostl = strlen(host);
|
int namel = strlen(name), hostl = strlen(opt->host);
|
||||||
if (strcmp(name, host) && (namel<hostl+2 || name[namel-hostl-1]!='.' || strcmp(name+namel-hostl,host))) { error = 5; goto error; }
|
if (strcmp(name, opt->host) && (namel<hostl+2 || name[namel-hostl-1]!='.' || strcmp(name+namel-hostl,opt->host))) { error = 5; goto error; }
|
||||||
if (inend - inpos < 4) { error = 1; goto error; }
|
if (inend - inpos < 4) { error = 1; goto error; }
|
||||||
// copy question to output
|
// copy question to output
|
||||||
memcpy(outbuf+12, inbuf+12, inpos+4 - (inbuf+12));
|
memcpy(outbuf+12, inbuf+12, inpos+4 - (inbuf+12));
|
||||||
|
@ -268,7 +261,7 @@ ssize_t static dnshandle(const unsigned char *inbuf, size_t insize, unsigned cha
|
||||||
unsigned char *outpos = outbuf+(inpos-inbuf);
|
unsigned char *outpos = outbuf+(inpos-inbuf);
|
||||||
unsigned char *outend = outbuf + BUFLEN;
|
unsigned char *outend = outbuf + BUFLEN;
|
||||||
|
|
||||||
printf("Request host='%s' type=%i class=%i\n", name, typ, cls);
|
printf("DNS: Request host='%s' type=%i class=%i\n", name, typ, cls);
|
||||||
|
|
||||||
// calculate size of authority section
|
// calculate size of authority section
|
||||||
|
|
||||||
|
@ -277,7 +270,7 @@ ssize_t static dnshandle(const unsigned char *inbuf, size_t insize, unsigned cha
|
||||||
if (!((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY))) {
|
if (!((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY))) {
|
||||||
// authority section will be necessary
|
// authority section will be necessary
|
||||||
unsigned char *oldpos = outpos;
|
unsigned char *oldpos = outpos;
|
||||||
write_record_ns(&oldpos, outend, "", offset, CLASS_IN, 0, ns);
|
write_record_ns(&oldpos, outend, "", offset, CLASS_IN, 0, opt->ns);
|
||||||
auth_size = oldpos - outpos;
|
auth_size = oldpos - outpos;
|
||||||
// printf("Authority section will claim %i bytes\n", auth_size);
|
// printf("Authority section will claim %i bytes\n", auth_size);
|
||||||
}
|
}
|
||||||
|
@ -288,14 +281,14 @@ ssize_t static dnshandle(const unsigned char *inbuf, size_t insize, unsigned cha
|
||||||
|
|
||||||
// NS records
|
// NS records
|
||||||
if ((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
if ((typ == TYPE_NS || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
||||||
int ret2 = write_record_ns(&outpos, outend - auth_size, "", offset, CLASS_IN, nsttl, ns);
|
int ret2 = write_record_ns(&outpos, outend - auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns);
|
||||||
// printf("wrote NS record: %i\n", ret2);
|
// printf("wrote NS record: %i\n", ret2);
|
||||||
if (!ret2) { outbuf[7]++; have_ns++; }
|
if (!ret2) { outbuf[7]++; have_ns++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// SOA records
|
// SOA records
|
||||||
if ((typ == TYPE_SOA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
if ((typ == TYPE_SOA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
||||||
int ret2 = write_record_soa(&outpos, outend - auth_size, "", offset, CLASS_IN, nsttl, ns, mbox, time(NULL), 604800, 86400, 2592000, 604800);
|
int ret2 = write_record_soa(&outpos, outend - auth_size, "", offset, CLASS_IN, opt->nsttl, opt->ns, opt->mbox, time(NULL), 604800, 86400, 2592000, 604800);
|
||||||
// printf("wrote SOA record: %i\n", ret2);
|
// printf("wrote SOA record: %i\n", ret2);
|
||||||
if (!ret2) { outbuf[7]++; }
|
if (!ret2) { outbuf[7]++; }
|
||||||
}
|
}
|
||||||
|
@ -303,10 +296,10 @@ ssize_t static dnshandle(const unsigned char *inbuf, size_t insize, unsigned cha
|
||||||
// A records
|
// A records
|
||||||
if ((typ == TYPE_A || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
if ((typ == TYPE_A || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
|
||||||
struct in_addr addr[20];
|
struct in_addr addr[20];
|
||||||
int naddr = GetIPList(addr, 20, 1);
|
int naddr = opt->cb(addr, 20, 1);
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (n < naddr) {
|
while (n < naddr) {
|
||||||
int ret = write_record_a(&outpos, outend - auth_size, "", offset, CLASS_IN, datattl, &addr[n]);
|
int ret = write_record_a(&outpos, outend - auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]);
|
||||||
// printf("wrote A record: %i\n", ret);
|
// printf("wrote A record: %i\n", ret);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
n++;
|
n++;
|
||||||
|
@ -318,7 +311,7 @@ ssize_t static dnshandle(const unsigned char *inbuf, size_t insize, unsigned cha
|
||||||
|
|
||||||
// Authority section
|
// Authority section
|
||||||
if (!have_ns) {
|
if (!have_ns) {
|
||||||
int ret2 = write_record_ns(&outpos, outend, "", offset, CLASS_IN, nsttl, ns);
|
int ret2 = write_record_ns(&outpos, outend, "", offset, CLASS_IN, opt->nsttl, opt->ns);
|
||||||
// printf("wrote NS record: %i\n", ret2);
|
// printf("wrote NS record: %i\n", ret2);
|
||||||
if (!ret2) {
|
if (!ret2) {
|
||||||
outbuf[9]++;
|
outbuf[9]++;
|
||||||
|
@ -340,7 +333,7 @@ error:
|
||||||
return 12;
|
return 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dnsserver(void) {
|
int dnsserver(dns_opt_t *opt) {
|
||||||
struct sockaddr_in si_me, si_other;
|
struct sockaddr_in si_me, si_other;
|
||||||
socklen_t s, slen=sizeof(si_other);
|
socklen_t s, slen=sizeof(si_other);
|
||||||
unsigned char inbuf[BUFLEN], outbuf[BUFLEN];
|
unsigned char inbuf[BUFLEN], outbuf[BUFLEN];
|
||||||
|
@ -348,16 +341,16 @@ int dnsserver(void) {
|
||||||
return -1;
|
return -1;
|
||||||
memset((char *) &si_me, 0, sizeof(si_me));
|
memset((char *) &si_me, 0, sizeof(si_me));
|
||||||
si_me.sin_family = AF_INET;
|
si_me.sin_family = AF_INET;
|
||||||
si_me.sin_port = htons(port);
|
si_me.sin_port = htons(opt->port);
|
||||||
si_me.sin_addr.s_addr = INADDR_ANY;
|
si_me.sin_addr.s_addr = INADDR_ANY;
|
||||||
if (bind(s, (struct sockaddr*)&si_me, sizeof(si_me))==-1)
|
if (bind(s, (struct sockaddr*)&si_me, sizeof(si_me))==-1)
|
||||||
return -2;
|
return -2;
|
||||||
do {
|
do {
|
||||||
ssize_t insize = recvfrom(s, inbuf, BUFLEN, 0, (struct sockaddr*)&si_other, &slen);
|
ssize_t insize = recvfrom(s, inbuf, BUFLEN, 0, (struct sockaddr*)&si_other, &slen);
|
||||||
unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr;
|
unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr;
|
||||||
printf("Request from %i.%i.%i.%i:%i of %i bytes\n", addr[0], addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
|
printf("DNS: Request from %i.%i.%i.%i:%i of %i bytes\n", addr[0], addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
|
||||||
if (insize > 0) {
|
if (insize > 0) {
|
||||||
ssize_t ret = dnshandle(inbuf, insize, outbuf);
|
ssize_t ret = dnshandle(opt, inbuf, insize, outbuf);
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
sendto(s, outbuf, ret, 0, (struct sockaddr*)&si_other, slen);
|
sendto(s, outbuf, ret, 0, (struct sockaddr*)&si_other, slen);
|
||||||
}
|
}
|
||||||
|
|
14
main.cpp
14
main.cpp
|
@ -8,7 +8,7 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// #include "dns.h"
|
#include "dns.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
CAddrDb db;
|
CAddrDb db;
|
||||||
|
@ -47,10 +47,16 @@ extern "C" int GetIPList(struct in_addr *addr, int max, int ipv4only) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int dnsserver(void);
|
|
||||||
|
|
||||||
extern "C" void* ThreadDNS(void*) {
|
extern "C" void* ThreadDNS(void*) {
|
||||||
dnsserver();
|
dns_opt_t opt;
|
||||||
|
opt.host = "seedtest.bitcoin.sipa.be";
|
||||||
|
opt.ns = "vps.sipa.be";
|
||||||
|
opt.mbox = "sipa.ulyssis.org";
|
||||||
|
opt.datattl = 60;
|
||||||
|
opt.nsttl = 40000;
|
||||||
|
opt.cb = GetIPList;
|
||||||
|
opt.port = 53;
|
||||||
|
dnsserver(&opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* ThreadDumper(void*) {
|
extern "C" void* ThreadDumper(void*) {
|
||||||
|
|
|
@ -274,7 +274,6 @@ bool CIPPort::ConnectSocket(SOCKET& hSocketRet, int nTimeout) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s: connected\n", ToString().c_str());
|
|
||||||
hSocketRet = hSocket;
|
hSocketRet = hSocket;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue