Browse Source

dhtproxy: tunnel DHT traffic into TCP connections

miguelfreitas
Miguel Freitas 11 years ago
parent
commit
e52f2c2527
  1. 1
      Makefile.am
  2. 330
      src/dhtproxy.cpp
  3. 195
      src/dhtproxy.h
  4. 4
      src/init.cpp
  5. 41
      src/main.cpp
  6. 1
      src/makefile.android
  7. 1
      src/makefile.freebsd
  8. 2
      src/makefile.osx
  9. 1
      src/makefile.unix
  10. 2
      src/net.h
  11. 87
      src/twister.cpp
  12. 11
      src/twister.h
  13. 13
      src/twister_utils.cpp
  14. 3
      src/twister_utils.h
  15. 5
      src/version.h
  16. 2
      twister-qt.pro

1
Makefile.am

@ -156,6 +156,7 @@ BITCOIN_TWISTER_SOURCES = \
src/leveldb.cpp \ src/leveldb.cpp \
src/txdb.cpp \ src/txdb.cpp \
src/chainparams.cpp \ src/chainparams.cpp \
src/dhtproxy.cpp \
src/twister.cpp \ src/twister.cpp \
src/twister_rss.cpp \ src/twister_rss.cpp \
src/twister_utils.cpp \ src/twister_utils.cpp \

330
src/dhtproxy.cpp

@ -0,0 +1,330 @@
// Copyright (c) 2014 Miguel Freitas
// tunnel DHT requests into tcp connection
// see: https://groups.google.com/forum/#!topic/twister-dev/uKjFGSw24yA
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/assign.hpp>
#include <boost/foreach.hpp>
#include <algorithm> // std::random_shuffle
#include "dhtproxy.h"
#include "libtorrent/alert_manager.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/bencode.hpp"
#include "main.h"
#include "uint256.h"
#include "script.h"
#include "init.h"
#include "twister.h"
#include "twister_utils.h"
//#define dbgprintf OutputDebugStringF
#define dbgprintf(...) // no debug printf
using namespace libtorrent;
namespace DhtProxy
{
bool fEnabled = true;
CCriticalSection cs_dhtProxy;
map<sha1_hash, std::list<alert_manager*> > m_dhtgetMap;
map<sha1_hash, std::list<CService> > m_dhtgetPeersReq;
class PeerBanStats {
public:
PeerBanStats() : active(0), count(0), limit(time_now()) {}
int active;
int count;
ptime limit;
};
map<CService, PeerBanStats> m_peerBanStats;
size_t numProxiesToUse = 4;
void dhtgetMapAdd(sha1_hash &ih, alert_manager *am)
{
LOCK(cs_dhtProxy);
m_dhtgetMap[ih].push_back(am);
}
void dhtgetMapRemove(sha1_hash &ih, alert_manager *am)
{
LOCK(cs_dhtProxy);
std::map<sha1_hash, std::list<alert_manager*> >::iterator mi = m_dhtgetMap.find(ih);
if( mi != m_dhtgetMap.end() ) {
std::list<alert_manager *> &amList = (*mi).second;
amList.remove(am);
if( !amList.size() ) {
m_dhtgetMap.erase(ih);
}
}
}
void dhtgetMapPost(sha1_hash &ih, const alert &a)
{
LOCK(cs_dhtProxy);
std::map<sha1_hash, std::list<alert_manager*> >::iterator mi = m_dhtgetMap.find(ih);
if( mi != m_dhtgetMap.end() ) {
std::list<alert_manager *> &amList = (*mi).second;
BOOST_FOREACH(alert_manager *am, amList) {
am->post_alert(a);
}
}
}
vector<CNode*> getRandomDhtProxies()
{
// (cs_vNodes) lock must be held!
vector<CNode*> vNodesProxy;
BOOST_FOREACH(CNode* pnode, vNodes) {
if (pnode->nVersion >= DHT_PROXY_VERSION && !pnode->fNoDhtProxy) {
vNodesProxy.push_back(pnode);
}
}
std::random_shuffle(vNodesProxy.begin(),vNodesProxy.end());
if(vNodesProxy.size() > numProxiesToUse) {
vNodesProxy.resize(numProxiesToUse);
}
return vNodesProxy;
}
vector<CNode*> dhtgetStartRequest(std::string const &username, std::string const &resource, bool multi)
{
CDHTGetRequest req;
req.vchUsername = std::vector<char>(username.begin(), username.end());
req.vchResource = std::vector<char>(resource.begin(), resource.end());
req.resTypeMulti = multi;
req.stopReq = false;
LOCK(cs_vNodes);
vector<CNode*> vNodesReq = getRandomDhtProxies();
BOOST_FOREACH(CNode* pnode, vNodesReq) {
dbgprintf("DhtProxy::dhtgetStartRequest: pushMessage to %s\n", pnode->addr.ToString().c_str());
pnode->PushMessage("dhtgetreq", req);
pnode->AddRef();
}
if( !vNodesReq.size() ) {
dbgprintf("DhtProxy::dhtgetStartRequest: sorry, no dht proxy found.\n");
// fake no data to wakeup listener
dht_reply_data_done_alert dd("","",false,false,false);
sha1_hash ih = dhtTargetHash(username, resource, multi ? "m" : "s");
dhtgetMapPost(ih, dd);
}
return vNodesReq;
}
void dhtgetStopRequest(vector<CNode*> vNodesReq, std::string const &username, std::string const &resource, bool multi)
{
CDHTGetRequest req;
req.vchUsername = std::vector<char>(username.begin(), username.end());
req.vchResource = std::vector<char>(resource.begin(), resource.end());
req.resTypeMulti = multi;
req.stopReq = true;
BOOST_FOREACH(CNode* pnode, vNodesReq) {
dbgprintf("DhtProxy::dhtgetStopRequest: pushMessage to %s\n", pnode->addr.ToString().c_str());
pnode->PushMessage("dhtgetreq", req);
pnode->Release();
}
}
void dhtgetPeerReqAdd(sha1_hash &ih, const CNode *pnode)
{
LOCK(cs_dhtProxy);
m_dhtgetPeersReq[ih].push_back(pnode->addr);
m_peerBanStats[pnode->addr].active++;
}
void dhtgetPeerReqRemove(sha1_hash &ih, const CNode *pnode)
{
LOCK(cs_dhtProxy);
std::map<sha1_hash, std::list<CService> >::iterator mi = m_dhtgetPeersReq.find(ih);
if( mi != m_dhtgetPeersReq.end() ) {
std::list<CService> &addrList = (*mi).second;
addrList.remove(pnode->addr);
if( !addrList.size() ) {
m_dhtgetPeersReq.erase(ih);
}
m_peerBanStats[pnode->addr].active--;
}
}
void dhtgetPeerReqReply(sha1_hash &ih, const alert *a)
{
CDHTGetReply reply;
reply.vchTargetHash = std::vector<char>(ih.begin(), ih.end());
dht_reply_data_alert const* rd = alert_cast<dht_reply_data_alert>(a);
if (rd) {
bencode(std::back_inserter(reply.vchBencodedData), rd->m_lst);
}
LOCK(cs_dhtProxy);
std::map<sha1_hash, std::list<CService> >::iterator mi = m_dhtgetPeersReq.find(ih);
if( mi != m_dhtgetPeersReq.end() ) {
std::list<CService> &addrList = (*mi).second;
BOOST_FOREACH(CService &addr, addrList) {
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) {
if ((CService)pnode->addr == addr) {
dbgprintf("DhtProxy::dhtgetPeerReqReply: pushMessage to %s\n", pnode->addr.ToString().c_str());
pnode->PushMessage("dhtgetreply", reply);
}
}
}
}
}
bool checkForAbuse(CNode* pfrom)
{
LOCK(cs_dhtProxy);
// logic inspired/copied from dht_tracker.cpp:incoming_packet
ptime now = time_now();
PeerBanStats *match = &m_peerBanStats[pfrom->addr];
match->count++;
if( match->count >= 500 ) {
if (now < match->limit) {
if( match->count == 500 ) {
dbgprintf("DhtProxy::checkForAbuse: %s misbehaving, too much requests.\n",
pfrom->addr.ToString().c_str());
}
match->limit = now + minutes(5);
return true;
}
match->count = 0;
match->limit = now + seconds(5);
}
if( match->active > 10 ) {
dbgprintf("DhtProxy::checkForAbuse: %s misbehaving, max active requests reached.\n",
pfrom->addr.ToString().c_str());
return true;
}
return false;
}
bool dhtgetRequestReceived(const CDHTGetRequest& req, CNode* pfrom)
{
if( fEnabled ) {
// we are using proxy ourselves, we can't be proxy to anyone else
pfrom->PushMessage("nodhtproxy");
return true;
} else if( !req.stopReq && checkForAbuse(pfrom) ) {
return false;
} else {
std::string username(req.vchUsername.data(), req.vchUsername.size());
std::string resource(req.vchResource.data(), req.vchResource.size());
bool multi(req.resTypeMulti);
dbgprintf("DhtProxy::dhtgetRequestReceived: (%s,%s,%d,stop=%d) from %s\n",
username.c_str(), resource.c_str(), multi, req.stopReq,
pfrom->addr.ToString().c_str());
sha1_hash ih = dhtTargetHash(username, resource, multi ? "m" : "s");
if( !req.stopReq ) {
dhtgetPeerReqAdd(ih, pfrom);
dhtGetData(username, resource, multi);
} else {
dhtgetPeerReqRemove(ih, pfrom);
}
return true;
}
}
bool dhtgetReplyReceived(const CDHTGetReply& reply, CNode* pfrom)
{
std::string strTargetHash(reply.vchTargetHash.data(), reply.vchTargetHash.size());
sha1_hash ih(strTargetHash);
if( !reply.vchBencodedData.size() ) {
dbgprintf("DhtProxy::dhtgetReplyReceived: empty data from %s\n",
pfrom->addr.ToString().c_str());
// No reply - these fields are not used, we just want cast in twister.cpp:dhtget to fail
dht_reply_data_done_alert dd("","",false,false,false);
dhtgetMapPost(ih, dd);
} else {
lazy_entry v;
int pos;
libtorrent::error_code ec;
if (lazy_bdecode(reply.vchBencodedData.data(), reply.vchBencodedData.data() +
reply.vchBencodedData.size(), v, ec, &pos) == 0 && v.type() == lazy_entry::list_t ) {
entry lst;
lst = v;
dbgprintf("DhtProxy::dhtgetReplyReceived: %zd entries from %s\n",
lst.list().size(), pfrom->addr.ToString().c_str());
dht_reply_data_alert rd(lst.list());
dhtgetMapPost(ih, rd);
} else {
dbgprintf("DhtProxy::dhtgetReplyReceived: parsing error (data from %s)\n",
pfrom->addr.ToString().c_str());
return false;
}
}
return true;
}
void dhtputRequest(std::string const &username, std::string const &resource, bool multi,
std::string const &str_p, std::string const &sig_p, std::string const &sig_user)
{
CDHTPutRequest req;
req.vchUsername = std::vector<char>(username.begin(), username.end());
req.vchResource = std::vector<char>(resource.begin(), resource.end());
req.resTypeMulti = multi;
req.vchStr_p = std::vector<char>(str_p.begin(), str_p.end());
req.vchSig_p = std::vector<char>(sig_p.begin(), sig_p.end());
req.vchSig_user = std::vector<char>(sig_user.begin(), sig_user.end());
LOCK(cs_vNodes);
vector<CNode*> vNodesReq = getRandomDhtProxies();
BOOST_FOREACH(CNode* pnode, vNodesReq) {
dbgprintf("DhtProxy::dhtputRequest: pushMessage to %s\n", pnode->addr.ToString().c_str());
pnode->PushMessage("dhtputreq", req);
}
if( !vNodesReq.size() ) {
dbgprintf("DhtProxy::dhtputRequest: sorry, no dht proxy found.\n");
}
}
bool dhtputRequestReceived(const CDHTPutRequest& req, CNode* pfrom)
{
if( fEnabled ) {
// we are using proxy ourselves, we can't be proxy to anyone else
pfrom->PushMessage("nodhtproxy");
return true;
} else if( checkForAbuse(pfrom) ) {
return false;
} else {
std::string username(req.vchUsername.data(), req.vchUsername.size());
std::string resource(req.vchResource.data(), req.vchResource.size());
bool multi(req.resTypeMulti);
dbgprintf("DhtProxy::dhtputRequestReceived: (%s,%s,%d) from %s\n",
username.c_str(), resource.c_str(), multi,
pfrom->addr.ToString().c_str());
lazy_entry v;
int pos;
libtorrent::error_code ec;
if (lazy_bdecode(req.vchStr_p.data(), req.vchStr_p.data() +
req.vchStr_p.size(), v, ec, &pos) == 0 ) {
entry p;
p = v;
std::string sig_p(req.vchSig_p.data(), req.vchSig_p.size());
std::string sig_user(req.vchSig_user.data(), req.vchSig_user.size());
dhtPutDataSigned(username,resource,multi,p,sig_p,sig_user, false);
} else {
dbgprintf("DhtProxy::dhtputRequestReceived: parsing error (data from %s)\n",
pfrom->addr.ToString().c_str());
return false;
}
return true;
}
}
}

195
src/dhtproxy.h

@ -0,0 +1,195 @@
// Copyright (c) 2014 Miguel Freitas
#ifndef DHTPROXY_H
#define DHTPROXY_H
#include "serialize.h"
#include "net.h"
#include "uint256.h"
#include <vector>
// just a small set of declarations to avoid main.c depending on libtorrent headers
namespace libtorrent {
class alert_manager;
class big_number;
typedef big_number sha1_hash;
class alert;
}
class CDHTTarget;
class CDHTGetRequest;
class CDHTGetReply;
class CDHTPutRequest;
/**
* DHTGet Sequence:
*
* Client Server
* 1) dhtgetMapAdd
* 2) dhtgetStartRequest
* => CDHTGetRequest =>
* 3) dhtgetRequestReceived(stopReq=False)
* 4) (dhtgetPeerReqAdd)
* 5) (ses->dht_getData)
* 6.1) dhtgetPeerReqReply (from ThreadSessionAlerts)
* 6.2) <= CDHTGetReply <=
* 6.3) dhtgetReplyReceived
* 6.4) (dhtgetMapPost)
* [ ..item 6 repeats... ]
* 7) dhtgetMapRemove
* 8) dhtgetStopRequest
* => CDHTGetRequest =>
* 9) dhtgetRequestReceived(stopReq=True)
* 10) (dhtgetPeerReqRemove)
*
**
* DHTPut Sequence:
*
* Client Server
* 1) dhtputRequest
* => CDHTPutRequest =>
* 2) dhtputRequestReceived
* 3) (ses->dht_putDataSigned)
*/
namespace DhtProxy
{
extern bool fEnabled;
// Register a listener for dhtget requests (client side)
void dhtgetMapAdd(libtorrent::sha1_hash &ih, libtorrent::alert_manager *am);
// Unregister the dhtget listener (client side)
void dhtgetMapRemove(libtorrent::sha1_hash &ih, libtorrent::alert_manager *am);
// Request a dhtget. Returns the list of node the request was sent to. (client side)
vector<CNode*> dhtgetStartRequest(std::string const &username, std::string const &resource, bool multi);
// Stop a dhtget request to the nodes listed. (client side)
void dhtgetStopRequest(vector<CNode*> vNodesReq, std::string const &username, std::string const &resource, bool multi);
// Handle a dhtget request received from TCP. send request to UDP. (server side)
// return true if accepted.
bool dhtgetRequestReceived(const CDHTGetRequest& req, CNode* pfrom);
// Handle a dhtget reply received from UDP, send it to the peers that made the request. (server side)
void dhtgetPeerReqReply(libtorrent::sha1_hash &ih, const libtorrent::alert *a);
// Handle a dhtget reply received from TCP. Will call dhtgetMapPost as needed. (client side)
// return true if accepted.
bool dhtgetReplyReceived(const CDHTGetReply& reply, CNode* pfrom);
// Request a dhtput.
void dhtputRequest(std::string const &username, std::string const &resource, bool multi,
std::string const &str_p, std::string const &sig_p, std::string const &sig_user);
// Handle a dhtput request received from TCP. send request to UDP. (server side)
// return true if accepted.
bool dhtputRequestReceived(const CDHTPutRequest& req, CNode* pfrom);
}
class CDHTTarget
{
public:
std::vector<char> vchUsername;
std::vector<char> vchResource;
bool resTypeMulti;
CDHTTarget()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(vchUsername);
READWRITE(vchResource);
READWRITE(resTypeMulti);
)
void SetNull()
{
vchUsername.clear();
vchResource.clear();
resTypeMulti = false;
}
};
class CDHTGetRequest : public CDHTTarget
{
public:
bool stopReq;
CDHTGetRequest() : CDHTTarget()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
CDHTTarget* pthis = (CDHTTarget*)(this);
READWRITE(*pthis);
READWRITE(stopReq);
)
void SetNull()
{
stopReq = false;
}
};
class CDHTGetReply
{
public:
std::vector<char> vchTargetHash;
std::vector<char> vchBencodedData;
CDHTGetReply()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
READWRITE(vchTargetHash);
READWRITE(vchBencodedData);
)
void SetNull()
{
vchTargetHash.clear();
vchBencodedData.clear();
}
};
class CDHTPutRequest : public CDHTTarget
{
public:
std::vector<char> vchStr_p;
std::vector<char> vchSig_p;
std::vector<char> vchSig_user;
CDHTPutRequest() : CDHTTarget()
{
SetNull();
}
IMPLEMENT_SERIALIZE
(
CDHTTarget* pthis = (CDHTTarget*)(this);
READWRITE(*pthis);
READWRITE(vchStr_p);
READWRITE(vchSig_p);
READWRITE(vchSig_user);
)
void SetNull()
{
vchStr_p.clear();
vchSig_p.clear();
vchSig_user.clear();
}
};
#endif

4
src/init.cpp

@ -432,6 +432,10 @@ bool AppInit2(boost::thread_group& threadGroup)
SoftSetBoolArg("-listen", false); SoftSetBoolArg("-listen", false);
} }
if (mapArgs.count("-proxy") || mapArgs.count("-tor")) {
SoftSetBoolArg("-dhtproxy", true);
}
if (!GetBoolArg("-listen", true)) { if (!GetBoolArg("-listen", true)) {
// do not map ports or try to retrieve public IP when not listening (pointless) // do not map ports or try to retrieve public IP when not listening (pointless)
SoftSetBoolArg("-upnp", false); SoftSetBoolArg("-upnp", false);

41
src/main.cpp

@ -13,6 +13,7 @@
#include "ui_interface.h" #include "ui_interface.h"
#include "checkqueue.h" #include "checkqueue.h"
#include "chainparams.h" #include "chainparams.h"
#include "dhtproxy.h"
#include "twister.h" #include "twister.h"
#include "utf8core.h" #include "utf8core.h"
@ -3185,6 +3186,46 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
pfrom->fRelayTxes = true; pfrom->fRelayTxes = true;
} }
else if (strCommand == "dhtgetreq")
{
CDHTGetRequest req;
vRecv >> req;
if( DhtProxy::dhtgetRequestReceived(req, pfrom) ) {
// ok
} else {
pfrom->Misbehaving(20);
}
}
else if (strCommand == "dhtputreq")
{
CDHTPutRequest req;
vRecv >> req;
if( DhtProxy::dhtputRequestReceived(req, pfrom) ) {
// ok
} else {
pfrom->Misbehaving(20);
}
}
else if (strCommand == "dhtgetreply")
{
CDHTGetReply reply;
vRecv >> reply;
if( DhtProxy::dhtgetReplyReceived(reply, pfrom) ) {
// ok
} else {
pfrom->Misbehaving(20);
}
}
else if (strCommand == "nodhtproxy")
{
pfrom->fNoDhtProxy = true;
}
else else
{ {

1
src/makefile.android

@ -133,6 +133,7 @@ OBJS= \
obj/leveldb.o \ obj/leveldb.o \
obj/txdb.o \ obj/txdb.o \
obj/chainparams.o \ obj/chainparams.o \
obj/dhtproxy.o \
obj/twister.o \ obj/twister.o \
obj/twister_rss.o \ obj/twister_rss.o \
obj/twister_utils.o obj/twister_utils.o

1
src/makefile.freebsd

@ -148,6 +148,7 @@ OBJS= \
obj/leveldb.o \ obj/leveldb.o \
obj/txdb.o \ obj/txdb.o \
obj/chainparams.o \ obj/chainparams.o \
obj/dhtproxy.o \
obj/twister.o \ obj/twister.o \
obj/twister_rss.o \ obj/twister_rss.o \
obj/twister_utils.o obj/twister_utils.o

2
src/makefile.osx vendored

@ -148,7 +148,9 @@ OBJS= \
obj/leveldb.o \ obj/leveldb.o \
obj/txdb.o \ obj/txdb.o \
obj/chainparams.o \ obj/chainparams.o \
obj/dhtproxy.o \
obj/twister.o \ obj/twister.o \
obj/twister_rss.o \
obj/twister_utils.o obj/twister_utils.o
ifdef USE_SSE2 ifdef USE_SSE2

1
src/makefile.unix

@ -150,6 +150,7 @@ OBJS= \
obj/leveldb.o \ obj/leveldb.o \
obj/txdb.o \ obj/txdb.o \
obj/chainparams.o \ obj/chainparams.o \
obj/dhtproxy.o \
obj/twister.o \ obj/twister.o \
obj/twister_rss.o \ obj/twister_rss.o \
obj/twister_utils.o obj/twister_utils.o

2
src/net.h

@ -203,6 +203,7 @@ public:
// b) the peer may tell us in their version message that we should not relay tx invs // b) the peer may tell us in their version message that we should not relay tx invs
// until they have initialized their bloom filter. // until they have initialized their bloom filter.
bool fRelayTxes; bool fRelayTxes;
bool fNoDhtProxy;
CSemaphoreGrant grantOutbound; CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter; CCriticalSection cs_filter;
CBloomFilter* pfilter; CBloomFilter* pfilter;
@ -266,6 +267,7 @@ public:
fGetAddr = false; fGetAddr = false;
nMisbehavior = 0; nMisbehavior = 0;
fRelayTxes = false; fRelayTxes = false;
fNoDhtProxy = false;
setInventoryKnown.max_size(SendBufferSize() / 1000); setInventoryKnown.max_size(SendBufferSize() / 1000);
pfilter = NULL; pfilter = NULL;

87
src/twister.cpp

@ -1,6 +1,7 @@
#include "twister.h" #include "twister.h"
#include "twister_utils.h" #include "twister_utils.h"
#include "dhtproxy.h"
#include "main.h" #include "main.h"
#include "init.h" #include "init.h"
@ -91,18 +92,6 @@ private:
#define USER_DATA_FILE "user_data" #define USER_DATA_FILE "user_data"
#define GLOBAL_DATA_FILE "global_data" #define GLOBAL_DATA_FILE "global_data"
sha1_hash dhtTargetHash(std::string const &username, std::string const &resource, std::string const &type)
{
entry target;
target["n"] = username;
target["r"] = resource;
target["t"] = type;
std::vector<char> buf;
bencode(std::back_inserter(buf), target);
return hasher(buf.data(), buf.size()).final();
}
void dhtgetMapAdd(sha1_hash &ih, alert_manager *am) void dhtgetMapAdd(sha1_hash &ih, alert_manager *am)
{ {
LOCK(cs_dhtgetMap); LOCK(cs_dhtgetMap);
@ -337,7 +326,12 @@ void ThreadWaitExtIP()
//dhts.restrict_routing_ips = false; //dhts.restrict_routing_ips = false;
//dhts.restrict_search_ips = false; //dhts.restrict_search_ips = false;
ses->set_dht_settings(dhts); ses->set_dht_settings(dhts);
ses->start_dht();
if( !DhtProxy::fEnabled ) {
ses->start_dht();
} else {
ses->stop_dht();
}
} }
session_settings settings; session_settings settings;
@ -495,7 +489,7 @@ void ThreadMaintainDHTNodes()
vNodesSize = vNodes.size(); vNodesSize = vNodes.size();
} }
if( !ses->is_paused() ) { if( !ses->is_paused() && !DhtProxy::fEnabled ) {
vector<CAddress> vAddr = addrman.GetAddr(); vector<CAddress> vAddr = addrman.GetAddr();
int totalNodesCandidates = (int)(vNodesSize + vAddr.size()); int totalNodesCandidates = (int)(vNodesSize + vAddr.size());
if( ((!dht_nodes && totalNodesCandidates) || if( ((!dht_nodes && totalNodesCandidates) ||
@ -630,6 +624,7 @@ void ThreadSessionAlerts()
t && t->type() == entry::string_t) { t && t->type() == entry::string_t) {
sha1_hash ih = dhtTargetHash(n->string(), r->string(), t->string()); sha1_hash ih = dhtTargetHash(n->string(), r->string(), t->string());
dhtgetMapPost(ih,*rd); dhtgetMapPost(ih,*rd);
DhtProxy::dhtgetPeerReqReply(ih,rd);
} }
} }
} }
@ -675,7 +670,7 @@ void ThreadSessionAlerts()
t->string().c_str()); t->string().c_str());
#endif #endif
neighborCheck[ih] = false; neighborCheck[ih] = false;
ses->dht_getData(n->string(), r->string(), t->string() == "m"); dhtGetData(n->string(), r->string(), t->string() == "m");
} else if( neighborCheck[ih] ) { } else if( neighborCheck[ih] ) {
sha1_hash ihStatus = dhtTargetHash(n->string(), "status", "s"); sha1_hash ihStatus = dhtTargetHash(n->string(), "status", "s");
@ -686,7 +681,7 @@ void ThreadSessionAlerts()
n->string().c_str(), "status", "s"); n->string().c_str(), "status", "s");
#endif #endif
statusCheck[ihStatus] = GetTime(); statusCheck[ihStatus] = GetTime();
ses->dht_getData(n->string(), "status", false); dhtGetData(n->string(), "status", false);
} }
} }
} }
@ -710,6 +705,7 @@ void ThreadSessionAlerts()
if( !dd->m_got_data ) { if( !dd->m_got_data ) {
// no data: post alert to return from wait_for_alert in dhtget() // no data: post alert to return from wait_for_alert in dhtget()
dhtgetMapPost(ih,*dd); dhtgetMapPost(ih,*dd);
DhtProxy::dhtgetPeerReqReply(ih,dd);
} }
if( neighborCheck.count(ih) ) { if( neighborCheck.count(ih) ) {
@ -721,7 +717,7 @@ void ThreadSessionAlerts()
#endif #endif
sha1_hash ihStatus = dhtTargetHash(dd->m_username, "status", "s"); sha1_hash ihStatus = dhtTargetHash(dd->m_username, "status", "s");
statusCheck[ihStatus] = GetTime(); statusCheck[ihStatus] = GetTime();
ses->dht_getData(dd->m_username, "status", false); dhtGetData(dd->m_username, "status", false);
} }
} }
if( statusCheck.count(ih) ) { if( statusCheck.count(ih) ) {
@ -766,6 +762,8 @@ void startSessionTorrent(boost::thread_group& threadGroup)
m_noExpireResources["status"] = SimpleNoExpire; m_noExpireResources["status"] = SimpleNoExpire;
m_noExpireResources["post"] = PostNoExpireRecent; m_noExpireResources["post"] = PostNoExpireRecent;
DhtProxy::fEnabled = GetBoolArg("-dhtproxy", false);
m_threadsToJoin = 0; m_threadsToJoin = 0;
threadGroup.create_thread(boost::bind(&ThreadWaitExtIP)); threadGroup.create_thread(boost::bind(&ThreadWaitExtIP));
threadGroup.create_thread(boost::bind(&ThreadMaintainDHTNodes)); threadGroup.create_thread(boost::bind(&ThreadMaintainDHTNodes));
@ -1334,16 +1332,24 @@ entry formatSpamPost(const string &msg, const string &username, uint64_t utcTime
} }
void dhtPutData(std::string const &username, std::string const &resource, bool multi, void dhtGetData(std::string const &username, std::string const &resource, bool multi)
entry const &value, std::string const &sig_user,
boost::int64_t timeutc, int seq)
{ {
if( DhtProxy::fEnabled ) {
printf("dhtGetData: not allowed - using proxy (bug!)\n");
return;
}
boost::shared_ptr<session> ses(m_ses); boost::shared_ptr<session> ses(m_ses);
if( !ses ) { if( !ses ) {
printf("dhtPutData: libtorrent session not ready\n"); printf("dhtGetData: libtorrent session not ready\n");
return; return;
} }
ses->dht_getData(username,resource,multi);
}
void dhtPutData(std::string const &username, std::string const &resource, bool multi,
entry const &value, std::string const &sig_user,
boost::int64_t timeutc, int seq)
{
// construct p dictionary and sign it // construct p dictionary and sign it
entry p; entry p;
entry& target = p["target"]; entry& target = p["target"];
@ -1365,7 +1371,27 @@ void dhtPutData(std::string const &username, std::string const &resource, bool m
return; return;
} }
ses->dht_putDataSigned(username,resource,multi,p,sig_p,sig_user, true); if( !DhtProxy::fEnabled ) {
dhtPutDataSigned(username,resource,multi,p,sig_p,sig_user, true);
} else {
DhtProxy::dhtputRequest(username,resource,multi,str_p,sig_p,sig_user);
}
}
void dhtPutDataSigned(std::string const &username, std::string const &resource, bool multi,
libtorrent::entry const &p, std::string const &sig_p, std::string const &sig_user, bool local)
{
if( DhtProxy::fEnabled ) {
printf("dhtputDataSigned: not allowed - using proxy (bug!)\n");
return;
}
boost::shared_ptr<session> ses(m_ses);
if( !ses ) {
printf("dhtPutData: libtorrent session not ready\n");
return;
}
ses->dht_putDataSigned(username,resource,multi,p,sig_p,sig_user, local);
} }
Value dhtput(const Array& params, bool fHelp) Value dhtput(const Array& params, bool fHelp)
@ -1441,9 +1467,15 @@ Value dhtget(const Array& params, bool fHelp)
alert_manager am(10, alert::dht_notification); alert_manager am(10, alert::dht_notification);
sha1_hash ih = dhtTargetHash(strUsername,strResource,strMulti); sha1_hash ih = dhtTargetHash(strUsername,strResource,strMulti);
dhtgetMapAdd(ih, &am);
ses->dht_getData(strUsername, strResource, multi); vector<CNode*> dhtProxyNodes;
if( !DhtProxy::fEnabled ) {
dhtgetMapAdd(ih, &am);
dhtGetData(strUsername, strResource, multi);
} else {
DhtProxy::dhtgetMapAdd(ih, &am);
dhtProxyNodes = DhtProxy::dhtgetStartRequest(strUsername, strResource, multi);
}
Array ret; Array ret;
std::set<std::string> uniqueSigPs; std::set<std::string> uniqueSigPs;
@ -1488,7 +1520,12 @@ Value dhtget(const Array& params, bool fHelp)
} }
} }
dhtgetMapRemove(ih,&am); if( !DhtProxy::fEnabled ) {
dhtgetMapRemove(ih,&am);
} else {
DhtProxy::dhtgetMapRemove(ih,&am);
DhtProxy::dhtgetStopRequest(dhtProxyNodes, strUsername, strResource, multi);
}
return ret; return ret;
} }

11
src/twister.h

@ -13,6 +13,9 @@
#define BLOCK_AGE_TO_EXPIRE_DHT_ENTRY (2016) // about 2 weeks #define BLOCK_AGE_TO_EXPIRE_DHT_ENTRY (2016) // about 2 weeks
#define BLOCK_AGE_TO_EXPIRE_DHT_POSTS (4320*2) // about 2 months #define BLOCK_AGE_TO_EXPIRE_DHT_POSTS (4320*2) // about 2 months
namespace libtorrent {
class entry;
}
class twister class twister
{ {
@ -41,4 +44,12 @@ int getDhtNodes(boost::int64_t *dht_global_nodes = NULL);
void updateSeenHashtags(std::string &message, int64_t msgTime); void updateSeenHashtags(std::string &message, int64_t msgTime);
// interface to dht api of the libtorrent current session
void dhtGetData(std::string const &username, std::string const &resource, bool multi);
void dhtPutData(std::string const &username, std::string const &resource, bool multi,
libtorrent::entry const &value, std::string const &sig_user,
boost::int64_t timeutc, int seq);
void dhtPutDataSigned(std::string const &username, std::string const &resource, bool multi,
libtorrent::entry const &p, std::string const &sig_p, std::string const &sig_user, bool local);
#endif // TWISTER_H #endif // TWISTER_H

13
src/twister_utils.cpp

@ -360,3 +360,16 @@ libtorrent::entry safeGetEntryDict(libtorrent::entry const &e, std::string const
} }
} }
sha1_hash dhtTargetHash(std::string const &username, std::string const &resource, std::string const &type)
{
entry target;
target["n"] = username;
target["r"] = resource;
target["t"] = type;
std::vector<char> buf;
bencode(std::back_inserter(buf), target);
return hasher(buf.data(), buf.size()).final();
}

3
src/twister_utils.h

@ -3,6 +3,7 @@
#include "json/json_spirit.h" #include "json/json_spirit.h"
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#include "libtorrent/peer_id.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
@ -48,4 +49,6 @@ std::string safeGetEntryString(libtorrent::entry const &e, std::string const& ke
int safeGetEntryInt(libtorrent::entry const &e, std::string const& key); int safeGetEntryInt(libtorrent::entry const &e, std::string const& key);
libtorrent::entry safeGetEntryDict(libtorrent::entry const &e, std::string const& key); libtorrent::entry safeGetEntryDict(libtorrent::entry const &e, std::string const& key);
libtorrent::sha1_hash dhtTargetHash(std::string const &username, std::string const &resource, std::string const &type);
#endif // TWISTER_UTILS_H #endif // TWISTER_UTILS_H

5
src/version.h

@ -25,7 +25,7 @@ extern const std::string CLIENT_DATE;
// network protocol versioning // network protocol versioning
// //
static const int PROTOCOL_VERSION = 70002; static const int PROTOCOL_VERSION = 70003;
// earlier versions not supported as of Feb 2012, and are disconnected // earlier versions not supported as of Feb 2012, and are disconnected
static const int MIN_PROTO_VERSION = 209; static const int MIN_PROTO_VERSION = 209;
@ -44,6 +44,9 @@ static const int BIP0031_VERSION = 60000;
// soft checkpoint min version // soft checkpoint min version
static const int SOFT_CHECKPOINT_VERSION = 70002; static const int SOFT_CHECKPOINT_VERSION = 70002;
// dht proxy min version
static const int DHT_PROXY_VERSION = 70003;
// "mempool" command, enhanced "getdata" behavior starts with this version: // "mempool" command, enhanced "getdata" behavior starts with this version:
static const int MEMPOOL_GD_VERSION = 60002; static const int MEMPOOL_GD_VERSION = 60002;

2
twister-qt.pro

@ -200,6 +200,7 @@ HEADERS += \
src/limitedmap.h \ src/limitedmap.h \
src/scrypt.h \ src/scrypt.h \
src/utf8core.h \ src/utf8core.h \
src/dhtproxy.h \
src/twister.h \ src/twister.h \
src/twister_rss.h \ src/twister_rss.h \
src/twister_utils.h src/twister_utils.h
@ -277,6 +278,7 @@ SOURCES += \ #src/qt/bitcoin.cpp \
src/leveldb.cpp \ src/leveldb.cpp \
src/txdb.cpp \ src/txdb.cpp \
src/scrypt.cpp \ src/scrypt.cpp \
src/dhtproxy.cpp \
src/twister.cpp \ src/twister.cpp \
src/twister_rss.cpp \ src/twister_rss.cpp \
src/twister_utils.cpp src/twister_utils.cpp

Loading…
Cancel
Save