Merge pull request #1971 from sehraf/pr_i2p_refactoring

i2p refactoring
This commit is contained in:
G10h4ck 2020-06-16 18:26:08 +02:00 committed by GitHub
commit 891d7e7c9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 583 additions and 201 deletions

View file

@ -154,6 +154,7 @@ rs_webui {
HEADERS += plugins/pluginmanager.h \ HEADERS += plugins/pluginmanager.h \
plugins/dlfcn_win32.h \ plugins/dlfcn_win32.h \
rsitems/rspluginitems.h \ rsitems/rspluginitems.h \
util/i2pcommon.h \
util/rsinitedptr.h util/rsinitedptr.h
HEADERS += $$PUBLIC_HEADERS HEADERS += $$PUBLIC_HEADERS
@ -517,7 +518,8 @@ SOURCES += ft/ftchunkmap.cc \
ft/ftfilesearch.cc \ ft/ftfilesearch.cc \
ft/ftserver.cc \ ft/ftserver.cc \
ft/fttransfermodule.cc \ ft/fttransfermodule.cc \
ft/ftturtlefiletransferitem.cc ft/ftturtlefiletransferitem.cc \
util/i2pcommon.cpp
SOURCES += crypto/chacha20.cpp \ SOURCES += crypto/chacha20.cpp \
crypto/hashstream.cc\ crypto/hashstream.cc\

View file

@ -161,7 +161,9 @@ public:
p3ChatService *chatSrv; p3ChatService *chatSrv;
p3StatusService *mStatusSrv; p3StatusService *mStatusSrv;
p3GxsTunnelService *mGxsTunnels; p3GxsTunnelService *mGxsTunnels;
#ifdef RS_USE_I2P_BOB
p3I2pBob *mI2pBob; p3I2pBob *mI2pBob;
#endif
// This list contains all threaded services. It will be used to shut them down properly. // This list contains all threaded services. It will be used to shut them down properly.

View file

@ -923,8 +923,10 @@ int RsServer::StartupRetroShare()
mNetMgr->setManagers(mPeerMgr, mLinkMgr); mNetMgr->setManagers(mPeerMgr, mLinkMgr);
rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance(); rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance();
#ifdef RS_USE_I2P_BOB
mI2pBob = new p3I2pBob(mPeerMgr); mI2pBob = new p3I2pBob(mPeerMgr);
autoProxy->addProxy(autoProxyType::I2PBOB, mI2pBob); autoProxy->addProxy(autoProxyType::I2PBOB, mI2pBob);
#endif
//load all the SSL certs as friends //load all the SSL certs as friends
// std::list<std::string> sslIds; // std::list<std::string> sslIds;
@ -1649,7 +1651,9 @@ int RsServer::StartupRetroShare()
mConfigMgr->addConfiguration("wire.cfg", wire_ns); mConfigMgr->addConfiguration("wire.cfg", wire_ns);
#endif #endif
#endif //RS_ENABLE_GXS #endif //RS_ENABLE_GXS
#ifdef RS_USE_I2P_BOB
mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pBob); mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pBob);
#endif
mPluginsManager->addConfigurations(mConfigMgr) ; mPluginsManager->addConfigurations(mConfigMgr) ;
@ -1724,7 +1728,7 @@ int RsServer::StartupRetroShare()
// now enable bob // now enable bob
bobSettings bs; bobSettings bs;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &bs); autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &bs);
bs.enableBob = true; bs.enable = true;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &bs); autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &bs);
} else { } else {
std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl; std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl;
@ -1795,7 +1799,9 @@ int RsServer::StartupRetroShare()
/**************************************************************************/ /**************************************************************************/
// auto proxy threads // auto proxy threads
#ifdef RS_USE_I2P_BOB
startServiceThread(mI2pBob, "I2P-BOB"); startServiceThread(mI2pBob, "I2P-BOB");
#endif
#ifdef RS_ENABLE_GXS #ifdef RS_ENABLE_GXS
// Must Set the GXS pointers before starting threads. // Must Set the GXS pointers before starting threads.

View file

@ -43,21 +43,14 @@ static const std::string kConfigKeyOutLength = "OUT_LENGTH";
static const std::string kConfigKeyOutQuantity = "OUT_QUANTITY"; static const std::string kConfigKeyOutQuantity = "OUT_QUANTITY";
static const std::string kConfigKeyOutVariance = "OUT_VARIANCE"; static const std::string kConfigKeyOutVariance = "OUT_VARIANCE";
static const bool kDefaultBOBEnable = false; /// Sleep duration for receiving loop in error/no-data case
static const int8_t kDefaultLength = 3; static const useconds_t sleepTimeRecv = 250; // times 1000 = 250ms
static const int8_t kDefaultQuantity = 4;
static const int8_t kDefaultVariance = 0;
/// Sleep duration for receiving loop
static const useconds_t sleepTimeRecv = 10; // times 1000 = 10ms
/// Sleep duration for everything else /// Sleep duration for everything else
static const useconds_t sleepTimeWait = 50; // times 1000 = 50ms or 0.05s static const useconds_t sleepTimeWait = 50; // times 1000 = 50ms or 0.05s
static const int sleepFactorDefault = 10; // 0.5s static const int sleepFactorDefault = 10; // 0.5s
static const int sleepFactorFast = 1; // 0.05s static const int sleepFactorFast = 1; // 0.05s
static const int sleepFactorSlow = 20; // 1s static const int sleepFactorSlow = 20; // 1s
static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Default, "p3I2pBob"};
static const rstime_t selfCheckPeroid = 30; static const rstime_t selfCheckPeroid = 30;
void doSleep(useconds_t timeToSleepMS) { void doSleep(useconds_t timeToSleepMS) {
@ -74,15 +67,7 @@ p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr)
mProcessing(NULL), mLock("I2P-BOB") mProcessing(NULL), mLock("I2P-BOB")
{ {
// set defaults // set defaults
mSetting.enableBob = kDefaultBOBEnable; mSetting.initDefault();
mSetting.keys = "";
mSetting.addr = "";
mSetting.inLength = kDefaultLength;
mSetting.inQuantity = kDefaultQuantity;
mSetting.inVariance = kDefaultVariance;
mSetting.outLength = kDefaultLength;
mSetting.outQuantity = kDefaultQuantity;
mSetting.outVariance = kDefaultVariance;
mCommands.clear(); mCommands.clear();
} }
@ -90,12 +75,12 @@ p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr)
bool p3I2pBob::isEnabled() bool p3I2pBob::isEnabled()
{ {
RS_STACK_MUTEX(mLock); RS_STACK_MUTEX(mLock);
return mSetting.enableBob; return mSetting.enable;
} }
bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/) bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
{ {
std::cout << "p3I2pBob::initialSetup" << std::endl; RS_DBG("");
// update config // update config
{ {
@ -108,7 +93,7 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
} }
} }
std::cout << "p3I2pBob::initialSetup config updated" << std::endl; RS_DBG("config updated");
// request keys // request keys
// p3I2pBob::stateMachineBOB expects mProcessing to be set therefore // p3I2pBob::stateMachineBOB expects mProcessing to be set therefore
@ -118,12 +103,12 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
fakeTicket->task = autoProxyTask::receiveKey; fakeTicket->task = autoProxyTask::receiveKey;
processTaskAsync(fakeTicket); processTaskAsync(fakeTicket);
std::cout << "p3I2pBob::initialSetup fakeTicket requested" << std::endl; RS_DBG("fakeTicket requested");
// now start thread // now start thread
start("I2P-BOB gen key"); start("I2P-BOB gen key");
std::cout << "p3I2pBob::initialSetup thread started" << std::endl; RS_DBG("thread started");
int counter = 0; int counter = 0;
// wait for keys // wait for keys
@ -137,24 +122,24 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
break; break;
if (++counter > 30) { if (++counter > 30) {
std::cout << "p3I2pBob::initialSetup timeout!" << std::endl; RS_DBG4("timeout!");
return false; return false;
} }
} }
std::cout << "p3I2pBob::initialSetup got keys" << std::endl; RS_DBG("got keys");
// stop thread // stop thread
fullstop(); fullstop();
std::cout << "p3I2pBob::initialSetup thread stopped" << std::endl; RS_DBG("thread stopped");
{ {
RS_STACK_MUTEX(mLock); RS_STACK_MUTEX(mLock);
addr = mSetting.addr; addr = mSetting.address.base32;
} }
std::cout << "p3I2pBob::initialSetup addr '" << addr << "'" << std::endl; RS_DBG4("addr ", addr);
return true; return true;
} }
@ -172,7 +157,7 @@ void p3I2pBob::processTaskAsync(taskTicket *ticket)
} }
break; break;
default: default:
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskAsync unknown task"); RS_DBG("unknown task");
rsAutoProxyMonitor::taskError(ticket); rsAutoProxyMonitor::taskError(ticket);
break; break;
} }
@ -187,7 +172,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::status: case autoProxyTask::status:
// check if everything needed is set // check if everything needed is set
if (!data) { if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::status autoProxyTask::status data is missing"); RS_DBG("autoProxyTask::status data is missing");
rsAutoProxyMonitor::taskError(ticket); rsAutoProxyMonitor::taskError(ticket);
break; break;
} }
@ -201,7 +186,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::getSettings: case autoProxyTask::getSettings:
// check if everything needed is set // check if everything needed is set
if (!data) { if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getSettings data is missing"); RS_DBG("autoProxyTask::getSettings data is missing");
rsAutoProxyMonitor::taskError(ticket); rsAutoProxyMonitor::taskError(ticket);
break; break;
} }
@ -215,7 +200,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::setSettings: case autoProxyTask::setSettings:
// check if everything needed is set // check if everything needed is set
if (!data) { if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::setSettings data is missing"); RS_DBG("autoProxyTask::setSettings data is missing");
rsAutoProxyMonitor::taskError(ticket); rsAutoProxyMonitor::taskError(ticket);
break; break;
} }
@ -235,7 +220,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
break; break;
case autoProxyTask::getErrorInfo: case autoProxyTask::getErrorInfo:
if (!data) { if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getErrorInfo data is missing"); RS_DBG("autoProxyTask::getErrorInfo data is missing");
rsAutoProxyMonitor::taskError(ticket); rsAutoProxyMonitor::taskError(ticket);
} else { } else {
RS_STACK_MUTEX(mLock); RS_STACK_MUTEX(mLock);
@ -244,34 +229,12 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
} }
break; break;
default: default:
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskSync unknown task"); RS_DBG("unknown task");
rsAutoProxyMonitor::taskError(ticket); rsAutoProxyMonitor::taskError(ticket);
break; break;
} }
} }
std::string p3I2pBob::keyToBase32Addr(const std::string &key)
{
std::string copy(key);
// replace I2P specific chars
std::replace(copy.begin(), copy.end(), '~', '/');
std::replace(copy.begin(), copy.end(), '-', '+');
// decode
std::vector<uint8_t> bin = Radix64::decode(copy);
// hash
std::vector<uint8_t> sha256 = RsUtil::BinToSha256(bin);
// encode
std::string out = Radix32::encode(sha256);
// i2p uses lowercase
std::transform(out.begin(), out.end(), out.begin(), ::tolower);
out.append(".b32.i2p");
return out;
}
bool inline isAnswerOk(const std::string &answer) { bool inline isAnswerOk(const std::string &answer) {
return (answer.compare(0, 2, "OK") == 0); return (answer.compare(0, 2, "OK") == 0);
} }
@ -285,9 +248,7 @@ void p3I2pBob::threadTick()
int sleepTime = 0; int sleepTime = 0;
{ {
RS_STACK_MUTEX(mLock); RS_STACK_MUTEX(mLock);
std::stringstream ss; RS_DBG4("data_tick mState: ", mState, " mTask: ", mTask, " mBOBState: ", mBOBState, " mPending: ", mPending.size());
ss << "data_tick mState: " << mState << " mTask: " << mTask << " mBOBState: " << mBOBState << " mPending: " << mPending.size();
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
} }
sleepTime += stateMachineController(); sleepTime += stateMachineController();
@ -326,15 +287,13 @@ int p3I2pBob::stateMachineBOB()
if (mBOBState == bsList) { if (mBOBState == bsList) {
int counter = 0; int counter = 0;
while (answer.find("OK Listing done") == std::string::npos) { while (answer.find("OK Listing done") == std::string::npos) {
std::stringstream ss; RS_DBG3("stateMachineBOB status check: read loop, counter: ", counter);
ss << "stateMachineBOB status check: read loop, counter: " << counter;
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, ss.str());
answer += recv(); answer += recv();
counter++; counter++;
} }
if (answer.find(mTunnelName) == std::string::npos) { if (answer.find(mTunnelName) == std::string::npos) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB status check: tunnel down!"); RS_DBG("status check: tunnel down!");
// signal error // signal error
*((bool *)mProcessing->data) = true; *((bool *)mProcessing->data) = true;
} }
@ -346,12 +305,12 @@ int p3I2pBob::stateMachineBOB()
switch (mBOBState) { switch (mBOBState) {
case bsNewkeysN: case bsNewkeysN:
key = answer.substr(3, answer.length()-3); key = answer.substr(3, answer.length()-3);
mSetting.addr = keyToBase32Addr(key); mSetting.address.base32 = i2p::keyToBase32Addr(key);
IndicateConfigChanged(); IndicateConfigChanged();
break; break;
case bsGetkeys: case bsGetkeys:
key = answer.substr(3, answer.length()-3); key = answer.substr(3, answer.length()-3);
mSetting.keys = key; mSetting.address.privateKey = key;
IndicateConfigChanged(); IndicateConfigChanged();
break; break;
default: default:
@ -374,8 +333,8 @@ int p3I2pBob::stateMachineBOB_locked_failure(const std::string &answer, const bo
return sleepFactorDefault; return sleepFactorDefault;
} }
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB FAILED to run command '" + currentState.command + "'"); RS_DBG("FAILED to run command: ", currentState.command);
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB '" + answer + "'"); RS_DBG("answer: ", answer);
mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n'); mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n');
mErrorMsg.append("reason '" + answer + "'" + '\n'); mErrorMsg.append("reason '" + answer + "'" + '\n');
@ -422,14 +381,14 @@ int p3I2pBob::stateMachineController()
return stateMachineController_locked_idle(); return stateMachineController_locked_idle();
case csDoConnect: case csDoConnect:
if (!connectI2P()) { if (!connectI2P()) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doConnect: unable to connect"); RS_DBG("doConnect: unable to connect");
mStateOld = mState; mStateOld = mState;
mState = csError; mState = csError;
mErrorMsg = "unable to connect to BOB port"; mErrorMsg = "unable to connect to BOB port";
return sleepFactorSlow; return sleepFactorSlow;
} }
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doConnect: connected"); RS_DBG4("doConnect: connected");
mState = csConnected; mState = csConnected;
break; break;
case csConnected: case csConnected:
@ -437,7 +396,7 @@ int p3I2pBob::stateMachineController()
case csWaitForBob: case csWaitForBob:
// check connection problems // check connection problems
if (mSocket == 0) { if (mSocket == 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController waitForBob: conection lost"); RS_DBG("waitForBob: conection lost");
mStateOld = mState; mStateOld = mState;
mState = csError; mState = csError;
mErrorMsg = "connection lost to BOB"; mErrorMsg = "connection lost to BOB";
@ -447,21 +406,21 @@ int p3I2pBob::stateMachineController()
// check for finished BOB protocol // check for finished BOB protocol
if (mBOBState == bsCleared) { if (mBOBState == bsCleared) {
// done // done
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController waitForBob: mBOBState == bsCleared"); RS_DBG4("waitForBob: mBOBState == bsCleared");
mState = csDoDisconnect; mState = csDoDisconnect;
} }
break; break;
case csDoDisconnect: case csDoDisconnect:
if (!disconnectI2P() || mSocket != 0) { if (!disconnectI2P() || mSocket != 0) {
// just in case // just in case
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doDisconnect: can't disconnect"); RS_DBG("doDisconnect: can't disconnect");
mStateOld = mState; mStateOld = mState;
mState = csError; mState = csError;
mErrorMsg = "unable to disconnect from BOB"; mErrorMsg = "unable to disconnect from BOB";
return sleepFactorDefault; return sleepFactorDefault;
} }
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doDisconnect: disconnected"); RS_DBG4("doDisconnect: disconnected");
mState = csDisconnected; mState = csDisconnected;
break; break;
case csDisconnected: case csDisconnected:
@ -487,12 +446,12 @@ int p3I2pBob::stateMachineController_locked_idle()
mProcessing = mPending.front(); mProcessing = mPending.front();
mPending.pop(); mPending.pop();
if (!mSetting.enableBob && ( if (!mSetting.enable && (
mProcessing->task == autoProxyTask::start || mProcessing->task == autoProxyTask::start ||
mProcessing->task == autoProxyTask::stop || mProcessing->task == autoProxyTask::stop ||
mProcessing->task == autoProxyTask::proxyStatusCheck)) { mProcessing->task == autoProxyTask::proxyStatusCheck)) {
// skip since we are not enabled // skip since we are not enabled
rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle: disabled -> skipping ticket"); RS_DBG1("disabled -> skipping ticket");
rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::disabled); rsAutoProxyMonitor::taskDone(mProcessing, autoProxyStatus::disabled);
mProcessing = NULL; mProcessing = NULL;
} else { } else {
@ -514,7 +473,7 @@ int p3I2pBob::stateMachineController_locked_idle()
mTask = ctRunCheck; mTask = ctRunCheck;
break; break;
default: default:
rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle unknown async task"); RS_DBG1("unknown async task");
rsAutoProxyMonitor::taskError(mProcessing); rsAutoProxyMonitor::taskError(mProcessing);
mProcessing = NULL; mProcessing = NULL;
break; break;
@ -561,29 +520,29 @@ int p3I2pBob::stateMachineController_locked_connected()
switch (mTask) { switch (mTask) {
case ctRunSetUp: case ctRunSetUp:
// when we have a key use it for server tunnel! // when we have a key use it for server tunnel!
if(mSetting.keys.empty()) { if(mSetting.address.privateKey.empty()) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickC"); RS_DBG4("setting mBOBState = setnickC");
mBOBState = bsSetnickC; mBOBState = bsSetnickC;
} else { } else {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickS"); RS_DBG4("setting mBOBState = setnickS");
mBOBState = bsSetnickS; mBOBState = bsSetnickS;
} }
break; break;
case ctRunShutDown: case ctRunShutDown:
// shut down existing tunnel // shut down existing tunnel
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = getnick"); RS_DBG4("setting mBOBState = getnick");
mBOBState = bsGetnick; mBOBState = bsGetnick;
break; break;
case ctRunCheck: case ctRunCheck:
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = list"); RS_DBG4("setting mBOBState = list");
mBOBState = bsList; mBOBState = bsList;
break; break;
case ctRunGetKeys: case ctRunGetKeys:
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickN"); RS_DBG4("setting mBOBState = setnickN");
mBOBState = bsSetnickN; mBOBState = bsSetnickN;
break; break;
case ctIdle: case ctIdle:
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_connected: task is idle. This should not happen!"); RS_DBG("task is idle. This should not happen!");
break; break;
} }
@ -599,7 +558,7 @@ int p3I2pBob::stateMachineController_locked_disconnected()
if(errorHappened) { if(errorHappened) {
// reset old state // reset old state
mStateOld = csIdel; mStateOld = csIdel;
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: error during process!"); RS_DBG("error during process!");
} }
// answer ticket // answer ticket
@ -628,12 +587,12 @@ int p3I2pBob::stateMachineController_locked_disconnected()
mTask = mTaskOld; mTask = mTaskOld;
if (!errorHappened) { if (!errorHappened) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: ok"); RS_DBG4("run check result: ok");
break; break;
} }
// switch to error // switch to error
newState = csError; newState = csError;
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: error"); RS_DBG("run check result: error");
mErrorMsg = "Connection check failed. Will try to restart tunnel."; mErrorMsg = "Connection check failed. Will try to restart tunnel.";
break; break;
@ -656,7 +615,7 @@ int p3I2pBob::stateMachineController_locked_disconnected()
mTask = mTaskOld; mTask = mTaskOld;
break; break;
case ctIdle: case ctIdle:
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: task is idle. This should not happen!"); RS_DBG("task is idle. This should not happen!");
rsAutoProxyMonitor::taskError(mProcessing); rsAutoProxyMonitor::taskError(mProcessing);
} }
mProcessing = NULL; mProcessing = NULL;
@ -672,14 +631,12 @@ int p3I2pBob::stateMachineController_locked_error()
{ {
// wait for bob protocoll // wait for bob protocoll
if (mBOBState != bsCleared) { if (mBOBState != bsCleared) {
rslog(RsLog::Debug_All, &i2pBobLogInfo, "stateMachineController_locked_error: waiting for BOB"); RS_DBG4("waiting for BOB");
return sleepFactorFast; return sleepFactorFast;
} }
#if 0 #if 0
std::stringstream ss; RS_DBG4("stateMachineController_locked_error: mProcessing: ", (mProcessing ? "not null" : "null"));
ss << "stateMachineController_locked_error: mProcessing: " << (mProcessing ? "not null" : "null");
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
#endif #endif
// try to finish ticket // try to finish ticket
@ -687,7 +644,7 @@ int p3I2pBob::stateMachineController_locked_error()
switch (mTask) { switch (mTask) {
case ctRunCheck: case ctRunCheck:
// connection check failed at some point // connection check failed at some point
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to check proxy status (it's likely dead)!"); RS_DBG("failed to check proxy status (it's likely dead)!");
*((bool *)mProcessing->data) = true; *((bool *)mProcessing->data) = true;
mState = csDoDisconnect; mState = csDoDisconnect;
mStateOld = csIdel; mStateOld = csIdel;
@ -695,7 +652,7 @@ int p3I2pBob::stateMachineController_locked_error()
break; break;
case ctRunShutDown: case ctRunShutDown:
// not a big deal though // not a big deal though
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to shut down tunnel (it's likely dead though)!"); RS_DBG("failed to shut down tunnel (it's likely dead though)!");
mState = csDoDisconnect; mState = csDoDisconnect;
mStateOld = csIdel; mStateOld = csIdel;
mErrorMsg.clear(); mErrorMsg.clear();
@ -703,14 +660,14 @@ int p3I2pBob::stateMachineController_locked_error()
case ctIdle: case ctIdle:
// should not happen but we need to deal with it // should not happen but we need to deal with it
// this will produce some error messages in the log and finish the task (marked as failed) // this will produce some error messages in the log and finish the task (marked as failed)
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: task is idle. This should not happen!"); RS_DBG("task is idle. This should not happen!");
mState = csDoDisconnect; mState = csDoDisconnect;
mStateOld = csIdel; mStateOld = csIdel;
mErrorMsg.clear(); mErrorMsg.clear();
break; break;
case ctRunGetKeys: case ctRunGetKeys:
case ctRunSetUp: case ctRunSetUp:
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: failed to receive key / start up"); RS_DBG("failed to receive key / start up");
mStateOld = csError; mStateOld = csError;
mState = csDoDisconnect; mState = csDoDisconnect;
// keep the error message // keep the error message
@ -721,7 +678,7 @@ int p3I2pBob::stateMachineController_locked_error()
// periodically retry // periodically retry
if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) { if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: retrying"); RS_DBG("retrying");
mLastProxyCheck = time(NULL); mLastProxyCheck = time(NULL);
mErrorMsg.clear(); mErrorMsg.clear();
@ -734,7 +691,7 @@ int p3I2pBob::stateMachineController_locked_error()
// check for new tickets // check for new tickets
if (!mPending.empty()) { if (!mPending.empty()) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_error: processing new ticket"); RS_DBG4("processing new ticket");
// reset and try new task // reset and try new task
mTask = ctIdle; mTask = ctIdle;
@ -765,16 +722,16 @@ RsSerialiser *p3I2pBob::setupSerialiser()
bool p3I2pBob::saveList(bool &cleanup, std::list<RsItem *> &lst) bool p3I2pBob::saveList(bool &cleanup, std::list<RsItem *> &lst)
{ {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "saveList"); RS_DBG4("");
cleanup = true; cleanup = true;
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet; RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet;
RsTlvKeyValue kv; RsTlvKeyValue kv;
RS_STACK_MUTEX(mLock); RS_STACK_MUTEX(mLock);
addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enableBob ? "TRUE" : "FALSE") addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enable ? "TRUE" : "FALSE")
addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.keys) addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.address.privateKey)
addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.addr) addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.address.base32)
addKVSInt(vitem, kv, kConfigKeyInLength, mSetting.inLength) addKVSInt(vitem, kv, kConfigKeyInLength, mSetting.inLength)
addKVSInt(vitem, kv, kConfigKeyInQuantity, mSetting.inQuantity) addKVSInt(vitem, kv, kConfigKeyInQuantity, mSetting.inQuantity)
addKVSInt(vitem, kv, kConfigKeyInVariance, mSetting.inVariance) addKVSInt(vitem, kv, kConfigKeyInVariance, mSetting.inVariance)
@ -800,7 +757,7 @@ bool p3I2pBob::saveList(bool &cleanup, std::list<RsItem *> &lst)
bool p3I2pBob::loadList(std::list<RsItem *> &load) bool p3I2pBob::loadList(std::list<RsItem *> &load)
{ {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "loadList"); RS_DBG4("");
for(std::list<RsItem*>::const_iterator it = load.begin(); it!=load.end(); ++it) { for(std::list<RsItem*>::const_iterator it = load.begin(); it!=load.end(); ++it) {
RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet*>(*it); RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet*>(*it);
@ -808,11 +765,11 @@ bool p3I2pBob::loadList(std::list<RsItem *> &load)
RS_STACK_MUTEX(mLock); RS_STACK_MUTEX(mLock);
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) { for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) {
if (kit->key == kConfigKeyBOBEnable) if (kit->key == kConfigKeyBOBEnable)
mSetting.enableBob = kit->value == "TRUE"; mSetting.enable = kit->value == "TRUE";
else if (kit->key == kConfigKeyBOBKey) else if (kit->key == kConfigKeyBOBKey)
mSetting.keys = kit->value; mSetting.address.privateKey = kit->value;
else if (kit->key == kConfigKeyBOBAddr) else if (kit->key == kConfigKeyBOBAddr)
mSetting.addr = kit->value; mSetting.address.base32 = kit->value;
getKVSUInt(kit, kConfigKeyInLength, mSetting.inLength) getKVSUInt(kit, kConfigKeyInLength, mSetting.inLength)
getKVSUInt(kit, kConfigKeyInQuantity, mSetting.inQuantity) getKVSUInt(kit, kConfigKeyInQuantity, mSetting.inQuantity)
getKVSUInt(kit, kConfigKeyInVariance, mSetting.inVariance) getKVSUInt(kit, kConfigKeyInVariance, mSetting.inVariance)
@ -820,7 +777,7 @@ bool p3I2pBob::loadList(std::list<RsItem *> &load)
getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity) getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity)
getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance) getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance)
else else
rslog(RsLog::Warning, &i2pBobLogInfo, "loadList unknown key: " + kit->key); RS_DBG("unknown key: ", kit->key);
} }
} }
delete vitem; delete vitem;
@ -884,7 +841,7 @@ void p3I2pBob::getStates(bobStates *bs)
std::string p3I2pBob::executeCommand(const std::string &command) std::string p3I2pBob::executeCommand(const std::string &command)
{ {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked running '" + command + "'"); RS_DBG4("running: ", command);
std::string copy = command; std::string copy = command;
copy.push_back('\n'); copy.push_back('\n');
@ -896,7 +853,7 @@ std::string p3I2pBob::executeCommand(const std::string &command)
// receive answer (trailing new line is already removed!) // receive answer (trailing new line is already removed!)
std::string ans = recv(); std::string ans = recv();
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked answer '" + ans + "'"); RS_DBG4("answer: ", ans);
return ans; return ans;
} }
@ -906,7 +863,7 @@ bool p3I2pBob::connectI2P()
// there is only one thread that touches mSocket - no need for a lock // there is only one thread that touches mSocket - no need for a lock
if (mSocket != 0) { if (mSocket != 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked mSocket != 0"); RS_DBG("mSocket != 0");
return false; return false;
} }
@ -914,21 +871,21 @@ bool p3I2pBob::connectI2P()
mSocket = unix_socket(PF_INET, SOCK_STREAM, 0); mSocket = unix_socket(PF_INET, SOCK_STREAM, 0);
if (mSocket < 0) if (mSocket < 0)
{ {
rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked Failed to open socket! Socket Error: " + socket_errorType(errno)); RS_DBG("Failed to open socket! Socket Error: ", socket_errorType(errno));
return false; return false;
} }
// connect // connect
int err = unix_connect(mSocket, mI2PProxyAddr); int err = unix_connect(mSocket, mI2PProxyAddr);
if (err != 0) { if (err != 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked Failed to connect to BOB! Socket Error: " + socket_errorType(errno)); RS_DBG("Failed to connect to BOB! Socket Error: ", socket_errorType(errno));
return false; return false;
} }
// receive hello msg // receive hello msg
recv(); recv();
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "connectI2P_locked done"); RS_DBG4("done");
return true; return true;
} }
@ -937,17 +894,17 @@ bool p3I2pBob::disconnectI2P()
// there is only one thread that touches mSocket - no need for a lock // there is only one thread that touches mSocket - no need for a lock
if (mSocket == 0) { if (mSocket == 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked mSocket == 0"); RS_DBG("mSocket == 0");
return true; return true;
} }
int err = unix_close(mSocket); int err = unix_close(mSocket);
if (err != 0) { if (err != 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked Failed to close socket! Socket Error: " + socket_errorType(errno)); RS_DBG("Failed to close socket! Socket Error: ", socket_errorType(errno));
return false; return false;
} }
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "disconnectI2P_locked done"); RS_DBG4("done");
mSocket = 0; mSocket = 0;
return true; return true;
} }
@ -968,7 +925,7 @@ std::string toString(const std::string &a, const int8_t b) {
void p3I2pBob::finalizeSettings_locked() void p3I2pBob::finalizeSettings_locked()
{ {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked"); RS_DBG4("");
sockaddr_storage_clear(mI2PProxyAddr); sockaddr_storage_clear(mI2PProxyAddr);
// get i2p proxy addr // get i2p proxy addr
@ -979,8 +936,8 @@ void p3I2pBob::finalizeSettings_locked()
sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy); sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy);
sockaddr_storage_setport(mI2PProxyAddr, 2827); sockaddr_storage_setport(mI2PProxyAddr, 2827);
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + sockaddr_storage_tostring(mI2PProxyAddr)); RS_DBG4("using ", mI2PProxyAddr);
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + mSetting.addr); RS_DBG4("using ", mSetting.address.base32);
peerState ps; peerState ps;
mPeerMgr->getOwnNetStatus(ps); mPeerMgr->getOwnNetStatus(ps);
@ -988,21 +945,17 @@ void p3I2pBob::finalizeSettings_locked()
// setup commands // setup commands
// new lines are appended later! // new lines are appended later!
// generate random suffix for name // generate 8 characater long random suffix for name
// RSRandom::random_alphaNumericString can return very weird looking strings like: ,,@z+M constexpr size_t len = 8;
// use base32 instead const std::string location = RsRandom::alphaNumeric(len);
size_t len = 5; // 5 characters = 8 base32 symbols RS_DBG4("using suffix ", location);
std::vector<uint8_t> tmp(len);
RSRandom::random_bytes(tmp.data(), len);
const std::string location = Radix32::encode(tmp.data(), len);
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using suffix " + location);
mTunnelName = "RetroShare-" + location; mTunnelName = "RetroShare-" + location;
const std::string setnick = "setnick RetroShare-" + location; const std::string setnick = "setnick RetroShare-" + location;
const std::string getnick = "getnick RetroShare-" + location; const std::string getnick = "getnick RetroShare-" + location;
const std::string newkeys = "newkeys"; const std::string newkeys = "newkeys";
const std::string getkeys = "getkeys"; const std::string getkeys = "getkeys";
const std::string setkeys = "setkeys " + mSetting.keys; const std::string setkeys = "setkeys " + mSetting.address.privateKey;
const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy); const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy);
const std::string inport = toString("inport ", sockaddr_storage_port(proxy)); const std::string inport = toString("inport ", sockaddr_storage_port(proxy));
const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr); const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr);
@ -1063,7 +1016,7 @@ void p3I2pBob::finalizeSettings_locked()
void p3I2pBob::updateSettings_locked() void p3I2pBob::updateSettings_locked()
{ {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "updateSettings_locked"); RS_DBG4("");
sockaddr_storage proxy; sockaddr_storage proxy;
mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy); mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy);
@ -1071,7 +1024,7 @@ void p3I2pBob::updateSettings_locked()
peerState ps; peerState ps;
mPeerMgr->getOwnNetStatus(ps); mPeerMgr->getOwnNetStatus(ps);
const std::string setkeys = "setkeys " + mSetting.keys; const std::string setkeys = "setkeys " + mSetting.address.privateKey;
const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy); const std::string inhost = "inhost " + sockaddr_storage_iptostring(proxy);
const std::string inport = toString("inport ", sockaddr_storage_port(proxy)); const std::string inport = toString("inport ", sockaddr_storage_port(proxy));
const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr); const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr);
@ -1103,38 +1056,62 @@ void p3I2pBob::updateSettings_locked()
std::string p3I2pBob::recv() std::string p3I2pBob::recv()
{ {
// BOB works line based
// -> \n indicates and of the line
constexpr uint16_t bufferSize = 128;
char buffer[bufferSize];
std::string ans; std::string ans;
ssize_t length; uint16_t retry = 10;
const uint16_t bufferSize = 128;
std::vector<char> buffer(bufferSize);
do { do {
memset(buffer, 0, bufferSize);
// peek at data
auto length = ::recv(mSocket, buffer, bufferSize, MSG_PEEK);
if (length <= 0) {
if (length < 0) {
// error
perror(__PRETTY_FUNCTION__);
}
retry--;
doSleep(sleepTimeRecv); doSleep(sleepTimeRecv);
// there is only one thread that touches mSocket - no need for a lock
length = ::recv(mSocket, buffer.data(), buffer.size(), 0);
if (length < 0)
continue; continue;
}
ans.append(buffer.begin(), buffer.end()); // at least one byte was read
// clean received string // search for new line
ans.erase(std::remove(ans.begin(), ans.end(), '\0'), ans.end()); auto bufferStr = std::string(buffer);
ans.erase(std::remove(ans.begin(), ans.end(), '\n'), ans.end()); size_t pos = bufferStr.find('\n');
#if 0 if (pos == std::string::npos) {
std::stringstream ss; // no new line found -> more to read
ss << "recv length: " << length << " (bufferSize: " << bufferSize << ") ans: " << ans.length();
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
#endif
// clear and resize buffer again // sanity check
buffer.clear(); if (length != bufferSize) {
buffer.resize(bufferSize); // expectation: a full buffer was peeked)
RS_DBG1("peeked less than bufferSize but also didn't found a new line character");
}
// this should never happen
assert(length <= bufferSize);
} else {
// new line found -> end of message
if (this->shouldStop()) // calculate how much there is to read, read the \n, too!
break; length = pos + 1;
} while(length == bufferSize || ans.size() < 4);
// end loop
retry = 0;
}
// now read for real
memset(buffer, 0, bufferSize);
length = ::recv(mSocket, buffer, length, 0);
bufferStr = std::string(buffer);
ans.append(bufferStr);
} while(retry > 0);
return ans; return ans;
} }

View file

@ -30,9 +30,10 @@
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include "pqi/p3cfgmgr.h"
#include "services/autoproxy/rsautoproxymonitor.h" #include "services/autoproxy/rsautoproxymonitor.h"
#include "util/rsthreads.h" #include "util/rsthreads.h"
#include "pqi/p3cfgmgr.h" #include "util/i2pcommon.h"
/* /*
* This class implements I2P BOB (BASIC OPEN BRIDGE) communication to allow RS * This class implements I2P BOB (BASIC OPEN BRIDGE) communication to allow RS
@ -49,7 +50,7 @@
* *
* Note 3: * Note 3:
* BOB needs a unique name as an ID for each tunnel. * BOB needs a unique name as an ID for each tunnel.
* We use 'RetroShare-' + 8 base32 characters. * We use 'RetroShare-' + 8 random base32 characters.
* *
* Design: * Design:
* The service uses three state machines to manage its task: * The service uses three state machines to manage its task:
@ -72,7 +73,7 @@
* mCommands[bobState::quit] = {quit, bobState::cleared}; * mCommands[bobState::quit] = {quit, bobState::cleared};
* *
* stateMachineController: * stateMachineController:
* This state machone manages the high level tasks. * This state machine manages the high level tasks.
* It is controlled by mState and mTask. * It is controlled by mState and mTask.
* *
* mTast: * mTast:
@ -162,19 +163,7 @@ struct bobStateInfo {
bobState nextState; bobState nextState;
}; };
struct bobSettings { struct bobSettings : i2p::settings {};
bool enableBob; ///< This field is used by the pqi subsystem to determinine whether SOCKS proxy or BOB is used for I2P connections
std::string keys; ///< (optional) server keys
std::string addr; ///< (optional) hidden service addr. in base32 form
int8_t inLength;
int8_t inQuantity;
int8_t inVariance;
int8_t outLength;
int8_t outQuantity;
int8_t outVariance;
};
/// ///
/// \brief The bobStates struct /// \brief The bobStates struct
@ -203,8 +192,6 @@ public:
void processTaskAsync(taskTicket *ticket); void processTaskAsync(taskTicket *ticket);
void processTaskSync(taskTicket *ticket); void processTaskSync(taskTicket *ticket);
static std::string keyToBase32Addr(const std::string &key);
void threadTick() override; /// @see RsTickingThread void threadTick() override; /// @see RsTickingThread
private: private:

View file

@ -22,6 +22,7 @@
#include "rsautoproxymonitor.h" #include "rsautoproxymonitor.h"
#include <unistd.h> /* for usleep() */ #include <unistd.h> /* for usleep() */
#include "util/rsdebug.h"
#include "util/rstime.h" #include "util/rstime.h"
rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL; rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL;
@ -42,8 +43,10 @@ rsAutoProxyMonitor *rsAutoProxyMonitor::instance()
void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service) void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service)
{ {
RS_STACK_MUTEX(mLock); RS_STACK_MUTEX(mLock);
if (mProxies.find(type) != mProxies.end()) if (mProxies.find(type) != mProxies.end()) {
std::cerr << "sAutoProxyMonitor::addProxy type " << type << " already added - OVERWRITING" << std::endl; RS_ERR("type ", type, " already added - OVERWRITING");
print_stacktrace();
}
mProxies[type] = service; mProxies[type] = service;
} }
@ -117,7 +120,7 @@ void rsAutoProxyMonitor::stopAllRSShutdown()
do { do {
rstime::rs_usleep(1000 * 1000); rstime::rs_usleep(1000 * 1000);
RS_STACK_MUTEX(mLock); RS_STACK_MUTEX(mLock);
std::cout << "(II) waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl; RS_DBG("waiting for auto proxy service(s) to shut down ", t, "/", timeout, " (remaining: ", mProxies.size(), ")");
if (mProxies.empty()) if (mProxies.empty())
break; break;
t++; t++;
@ -146,13 +149,16 @@ void rsAutoProxyMonitor::task(taskTicket *ticket)
{ {
// sanity checks // sanity checks
if (!ticket->async && ticket->types.size() > 1) { if (!ticket->async && ticket->types.size() > 1) {
std::cerr << "(WW) rsAutoProxyMonitor::task synchronous call to multiple services. This can cause problems!" << std::endl; RS_ERR("synchronous call to multiple services. This can cause problems!");
print_stacktrace();
} }
if (ticket->async && !ticket->cb && ticket->data) { if (ticket->async && !ticket->cb && ticket->data) {
std::cerr << "(WW) rsAutoProxyMonitor::task asynchronous call with data but no callback. This will likely causes memory leak!" << std::endl; RS_ERR("asynchronous call with data but no callback. This will likely causes memory leak!");
print_stacktrace();
} }
if (ticket->types.size() > 1 && ticket->data) { if (ticket->types.size() > 1 && ticket->data) {
std::cerr << "(WW) rsAutoProxyMonitor::task call with data to multiple services. This will likely causes memory leak!" << std::endl; RS_ERR("call with data to multiple services. This will likely causes memory leak!");
print_stacktrace();
} }
std::vector<autoProxyType::autoProxyType_enum>::const_iterator it; std::vector<autoProxyType::autoProxyType_enum>::const_iterator it;
@ -168,7 +174,11 @@ void rsAutoProxyMonitor::task(taskTicket *ticket)
*tt = *ticket; *tt = *ticket;
tt->types.clear(); tt->types.clear();
tt->types.push_back(*it); tt->types.push_back(*it);
// it's async!
RsThread::async([s, tt] {
s->processTaskAsync(tt); s->processTaskAsync(tt);
});
} else { } else {
s->processTaskSync(ticket); s->processTaskSync(ticket);
} }
@ -187,7 +197,8 @@ void rsAutoProxyMonitor::taskAsync(std::vector<autoProxyType::autoProxyType_enum
if (!isAsyncTask(task)) { if (!isAsyncTask(task)) {
// Usually the services will reject this ticket. // Usually the services will reject this ticket.
// Just print a warning - maybe there is some special case where this is a good idea. // Just print a warning - maybe there is some special case where this is a good idea.
std::cerr << "(WW) rsAutoProxyMonitor::taskAsync called with a synchronous task!" << std::endl; RS_ERR("called with a synchronous task!");
print_stacktrace();
} }
taskTicket *tt = getTicket(); taskTicket *tt = getTicket();
@ -215,7 +226,8 @@ void rsAutoProxyMonitor::taskSync(std::vector<autoProxyType::autoProxyType_enum>
if (isAsyncTask(task)) { if (isAsyncTask(task)) {
// Usually the services will reject this ticket. // Usually the services will reject this ticket.
// Just print a warning - maybe there is some special case where this is a good idea. // Just print a warning - maybe there is some special case where this is a good idea.
std::cerr << "(WW) rsAutoProxyMonitor::taskSync called with an asynchronous task!" << std::endl; RS_ERR("called with an asynchronous task!");
print_stacktrace();
} }
taskTicket *tt = getTicket(); taskTicket *tt = getTicket();
@ -244,7 +256,8 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu
t->cb->taskFinished(t); t->cb->taskFinished(t);
if (t != NULL) { if (t != NULL) {
// callack did not clean up properly // callack did not clean up properly
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish callback did not clean up!" << std::endl; RS_ERR("callback did not clean up!");
print_stacktrace();
cleanUp = true; cleanUp = true;
} }
} else if (t->async){ } else if (t->async){
@ -252,12 +265,13 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu
// we must take care of deleting // we must take care of deleting
cleanUp = true; cleanUp = true;
if(t->data) if(t->data)
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish async call with data attached but no callback set!" << std::endl; RS_ERR("async call with data attached but no callback set!");
} }
if (cleanUp) { if (cleanUp) {
if (t->data) { if (t->data) {
std::cerr << "(WW) rsAutoProxyMonitor::taskFinish will try to delete void pointer!" << std::endl; RS_ERR("will try to delete void pointer!");
print_stacktrace();
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-incomplete" #pragma GCC diagnostic ignored "-Wdelete-incomplete"
delete t->data; delete t->data;
@ -290,7 +304,8 @@ void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket)
// clean up // clean up
if (ticket->data) { if (ticket->data) {
std::cerr << "rsAutoProxyMonitor::taskFinished data set. Will try to delete void pointer" << std::endl; RS_ERR(" data set. Will try to delete void pointer");
print_stacktrace();
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdelete-incomplete" #pragma GCC diagnostic ignored "-Wdelete-incomplete"
delete ticket->data; delete ticket->data;
@ -308,7 +323,7 @@ autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType
if ((itService = mProxies.find(t)) != mProxies.end()) { if ((itService = mProxies.find(t)) != mProxies.end()) {
return itService->second; return itService->second;
} }
std::cerr << "sAutoProxyMonitor::lookUpService no service for type " << t << " found!" << std::endl; RS_DBG("no service for type ", t, " found!");
return NULL; return NULL;
} }

View file

@ -0,0 +1,163 @@
#include "i2pcommon.h"
#include "util/rsbase64.h"
#include "util/rsdebug.h"
namespace i2p {
std::string keyToBase32Addr(const std::string &key)
{
std::string copy(key);
// replace I2P specific chars
std::replace(copy.begin(), copy.end(), '~', '/');
// replacing the - with a + is not necessary, as RsBase64 can handle base64url encoding, too
// std::replace(copy.begin(), copy.end(), '-', '+');
// decode
std::vector<uint8_t> bin;
RsBase64::decode(copy, bin);
// hash
std::vector<uint8_t> sha256 = RsUtil::BinToSha256(bin);
// encode
std::string out = Radix32::encode(sha256);
// i2p uses lowercase
std::transform(out.begin(), out.end(), out.begin(), ::tolower);
out.append(".b32.i2p");
return out;
}
const std::string makeOption(const std::string &lhs, const int8_t &rhs) {
return lhs + "=" + std::to_string(rhs);
}
uint16_t readTwoBytesBE(std::vector<uint8_t>::const_iterator &p)
{
uint16_t val = 0;
val += *p++;
val <<= 8;
val += *p++;
return val;
}
std::string publicKeyFromPrivate(std::string const &priv)
{
/*
* https://geti2p.net/spec/common-structures#destination
* https://geti2p.net/spec/common-structures#keysandcert
* https://geti2p.net/spec/common-structures#certificate
*/
if (priv.length() < 884) // base64 ( = 663 bytes = KeyCert + priv Keys)
return std::string();
// creat a copy to work on, need to convert it to standard base64
auto priv_copy(priv);
std::replace(priv_copy.begin(), priv_copy.end(), '~', '/');
// replacing the - with a + is not necessary, as RsBase64 can handle base64url encoding, too
// std::replace(copy.begin(), copy.end(), '-', '+');
// get raw data
std::vector<uint8_t> dataPriv;
RsBase64::decode(priv_copy, dataPriv);
auto p = dataPriv.cbegin();
RS_DBG("dataPriv.size ", dataPriv.size());
size_t publicKeyLen = 256 + 128; // default length (bytes)
uint8_t certType = 0;
uint16_t len = 0;
uint16_t signingKeyType = 0;
uint16_t cryptKey = 0;
// only used for easy break
do {
try {
// jump to certificate
p += publicKeyLen;
// try to read type and length
certType = *p++;
len = readTwoBytesBE(p);
// only 0 and 5 are used / valid at this point
// check for == 0
if (certType == static_cast<typename std::underlying_type<CertType>::type>(CertType::Null)) {
/*
* CertType.Null
* type null is followed by 0x00 0x00 <END>
* so has to be 0!
*/
RS_DBG("cert is CertType.Null");
publicKeyLen += 3; // add 0x00 0x00 0x00
if (len != 0)
// weird
RS_DBG("cert is CertType.Null but len != 0");
break;
}
// check for != 5
if (certType != static_cast<typename std::underlying_type<CertType>::type>(CertType::Key)) {
// unsupported
RS_DBG("cert type ", certType, " is unsupported");
return std::string();
}
RS_DBG("cert is CertType.Key");
publicKeyLen += 7; // <type 1B> <len 2B> <keyType1 2B> <keyType2 2B> = 1 + 2 + 2 + 2 = 7 bytes
/*
* "Key certificates were introduced in release 0.9.12. Prior to that release, all PublicKeys were 256-byte ElGamal keys, and all SigningPublicKeys were 128-byte DSA-SHA1 keys."
* --> there is space for 256+128 bytes, longer keys are splitted and appended to the certificate
* We don't need to bother with the splitting here as only the lenght is important!
*/
// Signing Public Key
// likely 7
signingKeyType = readTwoBytesBE(p);
RS_DBG("signing pubkey type ", certType);
if (signingKeyType >= 3 && signingKeyType <= 6) {
RS_DBG("signing pubkey type ", certType, " has oversize");
// calculate oversize
if (signingKeyType >= signingKeyLengths.size()) {
// just in case
RS_DBG("signing pubkey type ", certType, " cannot be found in size data!");
return std::string();
}
auto values = signingKeyLengths[signingKeyType];
if (values.first <= 128) {
// just in case, it's supposed to be larger!
RS_DBG("signing pubkey type ", certType, " is oversize but size calculation would underflow!");
return std::string();
}
publicKeyLen += values.first - 128; // 128 = default DSA key length = the space than can be used before the key must be splitted
}
// Crypto Public Key
// likely 0
cryptKey = readTwoBytesBE(p);
RS_DBG("crypto pubkey type ", cryptKey);
// info: these are all smaller than the default 256 bytes, so no oversize calculation is needed
break;
} catch (const std::out_of_range &e) {
RS_DBG("hit exception! ", e.what());
return std::string();
}
} while(false);
std::string pub;
auto data2 = std::vector<uint8_t>(dataPriv.cbegin(), dataPriv.cbegin() + publicKeyLen);
RsBase64::encode(data2.data(), data2.size(), pub, false, false);
return pub;
}
} // namespace i2p

View file

@ -0,0 +1,211 @@
#ifndef I2PCOMMON_H
#define I2PCOMMON_H
#include <algorithm>
#include <map>
#include "util/rsrandom.h"
#include "util/radix32.h"
#include "util/rsbase64.h"
#include "util/rsprint.h"
#include "util/rsdebug.h"
/*
* This header provides common code for i2p related code, namely BOB and SAM3 support.
*/
namespace i2p {
static constexpr int8_t kDefaultLength = 3; // i2p default
static constexpr int8_t kDefaultQuantity = 3; // i2p default + 1
static constexpr int8_t kDefaultVariance = 0;
static constexpr int8_t kDefaultBackupQuantity = 0;
/**
* @brief The address struct
* This structure is a container for any i2p address/key. The public key is used for addressing and can be (optionally) hashed to generate the .b32.i2p address.
*/
struct address {
std::string base32;
std::string publicKey;
std::string privateKey;
void clear() {
base32.clear();
publicKey.clear();
privateKey.clear();
}
};
/**
* @brief The settings struct
* Common structure with all settings that are shared between any i2p backends
*/
struct settings {
bool enable;
struct address address;
// connection parameter
int8_t inLength;
int8_t inQuantity;
int8_t inVariance;
int8_t inBackupQuantity;
int8_t outLength;
int8_t outQuantity;
int8_t outVariance;
int8_t outBackupQuantity;
void initDefault() {
enable = false;
address.clear();
inLength = kDefaultLength;
inQuantity = kDefaultQuantity;
inVariance = kDefaultVariance;
inBackupQuantity = kDefaultBackupQuantity;
outLength = kDefaultLength;
outQuantity = kDefaultQuantity;
outVariance = kDefaultVariance;
outBackupQuantity = kDefaultBackupQuantity;
}
};
/*
Type Type Code Payload Length Total Length Notes
Null 0 0 3
HashCash 1 varies varies Experimental, unused. Payload contains an ASCII colon-separated hashcash string.
Hidden 2 0 3 Experimental, unused. Hidden routers generally do not announce that they are hidden.
Signed 3 40 or 72 43 or 75 Experimental, unused. Payload contains a 40-byte DSA signature, optionally followed by the 32-byte Hash of the signing Destination.
Multiple 4 varies varies Experimental, unused. Payload contains multiple certificates.
Key 5 4+ 7+ Since 0.9.12. See below for details.
*/
enum class CertType : uint8_t {
Null = 0,
HashCash = 1,
Hidden = 2,
Signed = 3,
Multiple = 4,
Key = 5
};
/*
* public
Type Type Code Total Public Key Length Since Usage
DSA_SHA1 0 128 0.9.12 Legacy Router Identities and Destinations, never explicitly set
ECDSA_SHA256_P256 1 64 0.9.12 Older Destinations
ECDSA_SHA384_P384 2 96 0.9.12 Rarely if ever used for Destinations
ECDSA_SHA512_P521 3 132 0.9.12 Rarely if ever used for Destinations
RSA_SHA256_2048 4 256 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
RSA_SHA384_3072 5 384 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
RSA_SHA512_4096 6 512 0.9.12 Offline only; never used in Key Certificates for Router Identities or Destinations
EdDSA_SHA512_Ed25519 7 32 0.9.15 Recent Router Identities and Destinations
EdDSA_SHA512_Ed25519ph 8 32 0.9.25 Offline only; never used in Key Certificates for Router Identities or Destinations
reserved (GOST) 9 64 Reserved, see proposal 134
reserved (GOST) 10 128 Reserved, see proposal 134
RedDSA_SHA512_Ed25519 11 32 0.9.39 For Destinations and encrypted leasesets only; never used for Router Identities
reserved 65280-65534 Reserved for experimental use
reserved 65535 Reserved for future expansion
* private
Type Length (bytes) Since Usage
DSA_SHA1 20 Legacy Router Identities and Destinations
ECDSA_SHA256_P256 32 0.9.12 Recent Destinations
ECDSA_SHA384_P384 48 0.9.12 Rarely used for Destinations
ECDSA_SHA512_P521 66 0.9.12 Rarely used for Destinations
RSA_SHA256_2048 512 0.9.12 Offline signing, never used for Router Identities or Destinations
RSA_SHA384_3072 768 0.9.12 Offline signing, never used for Router Identities or Destinations
RSA_SHA512_4096 1024 0.9.12 Offline signing, never used for Router Identities or Destinations
EdDSA_SHA512_Ed25519 32 0.9.15 Recent Router Identities and Destinations
EdDSA_SHA512_Ed25519ph 32 0.9.25 Offline signing, never used for Router Identities or Destinations
RedDSA_SHA512_Ed25519 32 0.9.39 For Destinations and encrypted leasesets only, never used for Router Identities
*/
enum class SigningKeyType : uint16_t {
DSA_SHA1 = 0,
ECDSA_SHA256_P256 = 1,
ECDSA_SHA384_P384 = 2,
ECDSA_SHA512_P521 = 3,
RSA_SHA256_2048 = 4,
RSA_SHA384_3072 = 5,
RSA_SHA512_4096 = 6,
EdDSA_SHA512_Ed25519 = 7,
EdDSA_SHA512_Ed25519ph = 8,
RedDSA_SHA512_Ed25519 = 11
};
/*
* public
Type Type Code Total Public Key Length Usage
ElGamal 0 256 All Router Identities and Destinations
P256 1 64 Reserved, see proposal 145
P384 2 96 Reserved, see proposal 145
P521 3 132 Reserved, see proposal 145
X25519 4 32 Not for use in key certs. See proposal 144
reserved 65280-65534 Reserved for experimental use
reserved 65535 Reserved for future expansion
* private
Type Length (bytes) Since Usage
ElGamal 256 All Router Identities and Destinations
P256 32 TBD Reserved, see proposal 145
P384 48 TBD Reserved, see proposal 145
P521 66 TBD Reserved, see proposal 145
X25519 32 0.9.38 Little-endian. See proposal 144
*/
enum class CryptoKeyType : uint16_t {
ElGamal = 0,
P256 = 1,
P384 = 2,
P521 = 3,
X25519 = 4
};
static const std::array<std::pair<uint16_t, uint16_t>, 5> cryptoKeyLengths {
/*CryptoKeyType::ElGamal*/ std::make_pair<uint16_t, uint16_t>(256, 256),
/*CryptoKeyType::P256, */ std::make_pair<uint16_t, uint16_t>( 64, 32),
/*CryptoKeyType::P384, */ std::make_pair<uint16_t, uint16_t>( 96, 48),
/*CryptoKeyType::P521, */ std::make_pair<uint16_t, uint16_t>(132, 66),
/*CryptoKeyType::X25519,*/ std::make_pair<uint16_t, uint16_t>( 32, 32),
};
static const std::array<std::pair<uint16_t, uint16_t>, 12> signingKeyLengths {
/*SigningKeyType::DSA_SHA1, */ std::make_pair<uint16_t, uint16_t>(128, 128),
/*SigningKeyType::ECDSA_SHA256_P256, */ std::make_pair<uint16_t, uint16_t>( 64, 32),
/*SigningKeyType::ECDSA_SHA384_P384, */ std::make_pair<uint16_t, uint16_t>( 96, 48),
/*SigningKeyType::ECDSA_SHA512_P521, */ std::make_pair<uint16_t, uint16_t>(132, 66),
/*SigningKeyType::RSA_SHA256_2048, */ std::make_pair<uint16_t, uint16_t>(256, 512),
/*SigningKeyType::RSA_SHA384_3072, */ std::make_pair<uint16_t, uint16_t>(384, 768),
/*SigningKeyType::RSA_SHA512_4096, */ std::make_pair<uint16_t, uint16_t>(512,1024),
/*SigningKeyType::EdDSA_SHA512_Ed25519 */ std::make_pair<uint16_t, uint16_t>( 32, 32),
/*SigningKeyType::EdDSA_SHA512_Ed25519ph */ std::make_pair<uint16_t, uint16_t>( 32, 32),
/*reserved (GOST) */ std::make_pair<uint16_t, uint16_t>( 64, 0),
/*reserved (GOST) */ std::make_pair<uint16_t, uint16_t>(128, 0),
/*SigningKeyType::RedDSA_SHA512_Ed25519 */ std::make_pair<uint16_t, uint16_t>( 32, 32),
};
/**
* @brief makeOption Creates the string "lhs=rhs" used by BOB and SAM. Converts rhs
* @param lhs option to set
* @param rhs value to set
* @return concatenated string
*/
const std::string makeOption(const std::string &lhs, const int8_t &rhs);
/**
* @brief keyToBase32Addr generated a base32 address (.b32.i2p) from a given public key
* @param key public key
* @return generated base32 address
*/
std::string keyToBase32Addr(const std::string &key);
/**
* @brief publicKeyFromPrivate parses the private key and calculates the lenght of the public key
* @param priv private key (which includes the public key) to read
* @return public key used for addressing
*/
std::string publicKeyFromPrivate(const std::string &priv);
} // namespace i2p
#endif // I2PCOMMON_H

View file

@ -340,6 +340,10 @@ void GenCertDialog::setupState()
ui.hiddenport_spinBox->setVisible(hidden_state && !tor_auto); ui.hiddenport_spinBox->setVisible(hidden_state && !tor_auto);
ui.cbUseBob->setVisible(hidden_state && !tor_auto); ui.cbUseBob->setVisible(hidden_state && !tor_auto);
#ifndef RS_USE_I2P_BOB
ui.cbUseBob->setDisabled(true);
ui.cbUseBob->setToolTip(tr("BOB support is not available"));
#endif
if(!mAllFieldsOk) if(!mAllFieldsOk)
{ {

View file

@ -23,6 +23,7 @@
#include <gui/notifyqt.h> #include <gui/notifyqt.h>
#include "rshare.h" #include "rshare.h"
#include "rsharesettings.h" #include "rsharesettings.h"
#include "util/i2pcommon.h"
#include "util/RsNetUtil.h" #include "util/RsNetUtil.h"
#include "util/misc.h" #include "util/misc.h"
@ -82,6 +83,10 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
manager = NULL ; manager = NULL ;
mOngoingConnectivityCheck = -1; mOngoingConnectivityCheck = -1;
#ifndef RS_USE_I2P_BOB
ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB); // warning: the order of operation here is very important.
#endif
if(RsAccounts::isHiddenNode()) if(RsAccounts::isHiddenNode())
{ {
if(RsAccounts::isTorAuto()) if(RsAccounts::isTorAuto())
@ -1352,7 +1357,7 @@ void ServerPage::updateInProxyIndicator()
ui.iconlabel_service_incoming->setMovie(movie); ui.iconlabel_service_incoming->setMovie(movie);
movie->start(); movie->start();
if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enableBob) { if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enable) {
QTcpSocket tcpSocket; QTcpSocket tcpSocket;
@ -1439,15 +1444,16 @@ void ServerPage::getNewKey()
void ServerPage::loadKey() void ServerPage::loadKey()
{ {
mBobSettings.keys = ui.pteBobServerKey->toPlainText().toStdString(); mBobSettings.address.privateKey = ui.pteBobServerKey->toPlainText().toStdString();
mBobSettings.addr = p3I2pBob::keyToBase32Addr(mBobSettings.keys); mBobSettings.address.publicKey = i2p::publicKeyFromPrivate(mBobSettings.address.privateKey);
mBobSettings.address.base32 = i2p::keyToBase32Addr(mBobSettings.address.publicKey);
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings);
} }
void ServerPage::enableBob(bool checked) void ServerPage::enableBob(bool checked)
{ {
mBobSettings.enableBob = checked; mBobSettings.enable = checked;
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings);
@ -1487,7 +1493,7 @@ void ServerPage::toggleBobAdvancedSettings(bool checked)
{ {
ui.swBobAdvanced->setCurrentIndex(checked ? 1 : 0); ui.swBobAdvanced->setCurrentIndex(checked ? 1 : 0);
if (!mBobSettings.keys.empty()) { if (!mBobSettings.address.privateKey.empty()) {
if (checked) { if (checked) {
ui.pbBobGenAddr->show(); ui.pbBobGenAddr->show();
} else { } else {
@ -1578,9 +1584,9 @@ void ServerPage::loadCommon()
whileBlocking(ui.hiddenpage_proxyPort_i2p_2)->setValue(proxyport); // this one is for bob tab whileBlocking(ui.hiddenpage_proxyPort_i2p_2)->setValue(proxyport); // this one is for bob tab
// don't use whileBlocking here // don't use whileBlocking here
ui.cb_enableBob->setChecked(mBobSettings.enableBob); ui.cb_enableBob->setChecked(mBobSettings.enable);
if (!mBobSettings.keys.empty()) { if (!mBobSettings.address.privateKey.empty()) {
ui.lBobB32Addr->show(); ui.lBobB32Addr->show();
ui.leBobB32Addr->show(); ui.leBobB32Addr->show();
} }
@ -1623,13 +1629,13 @@ void ServerPage::saveBob()
void ServerPage::updateStatusBob() void ServerPage::updateStatusBob()
{ {
QString addr = QString::fromStdString(mBobSettings.addr); QString addr = QString::fromStdString(mBobSettings.address.base32);
if (ui.leBobB32Addr->text() != addr) { if (ui.leBobB32Addr->text() != addr) {
ui.leBobB32Addr->setText(addr); ui.leBobB32Addr->setText(addr);
ui.hiddenpage_serviceAddress->setText(addr); ui.hiddenpage_serviceAddress->setText(addr);
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys)); ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.address.privateKey));
if (!mBobSettings.keys.empty()) { if (!mBobSettings.address.privateKey.empty()) {
// we have an addr -> show fields // we have an addr -> show fields
ui.lBobB32Addr->show(); ui.lBobB32Addr->show();
ui.leBobB32Addr->show(); ui.leBobB32Addr->show();
@ -1655,7 +1661,7 @@ void ServerPage::updateStatusBob()
QString bobSimpleText = QString(); QString bobSimpleText = QString();
bobSimpleText.append(tr("RetroShare uses BOB to set up a %1 tunnel at %2:%3 (named %4)\n\n" bobSimpleText.append(tr("RetroShare uses BOB to set up a %1 tunnel at %2:%3 (named %4)\n\n"
"When changing options (e.g. port) use the buttons at the bottom to restart BOB.\n\n"). "When changing options (e.g. port) use the buttons at the bottom to restart BOB.\n\n").
arg(mBobSettings.keys.empty() ? tr("client") : tr("server"), arg(mBobSettings.address.privateKey.empty() ? tr("client") : tr("server"),
ui.hiddenpage_proxyAddress_i2p_2->text(), ui.hiddenpage_proxyAddress_i2p_2->text(),
ui.hiddenpage_proxyPort_i2p_2->text(), ui.hiddenpage_proxyPort_i2p_2->text(),
bs.tunnelName.empty() ? tr("unknown") : bs.tunnelName.empty() ? tr("unknown") :
@ -1777,15 +1783,15 @@ void ServerPage::updateStatusBob()
void ServerPage::setUpBobElements() void ServerPage::setUpBobElements()
{ {
ui.gbBob->setEnabled(mBobSettings.enableBob); ui.gbBob->setEnabled(mBobSettings.enable);
if (mBobSettings.enableBob) { if (mBobSettings.enable) {
ui.hiddenpage_proxyAddress_i2p->setEnabled(false); ui.hiddenpage_proxyAddress_i2p->setEnabled(false);
ui.hiddenpage_proxyAddress_i2p->setToolTip("Use I2P/BOB settings to change this value"); ui.hiddenpage_proxyAddress_i2p->setToolTip("Use I2P/BOB settings to change this value");
ui.hiddenpage_proxyPort_i2p->setEnabled(false); ui.hiddenpage_proxyPort_i2p->setEnabled(false);
ui.hiddenpage_proxyPort_i2p->setToolTip("Use I2P/BOB settings to change this value"); ui.hiddenpage_proxyPort_i2p->setToolTip("Use I2P/BOB settings to change this value");
ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.addr)); ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.address.base32));
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys)); ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.address.privateKey));
// cast to int to avoid problems // cast to int to avoid problems
int li, lo, qi, qo, vi, vo; int li, lo, qi, qo, vi, vo;

View file

@ -140,6 +140,11 @@ rs_macos10.15:CONFIG -= rs_macos10.11
CONFIG *= no_rs_jsonapi CONFIG *= no_rs_jsonapi
rs_jsonapi:CONFIG -= no_rs_jsonapi rs_jsonapi:CONFIG -= no_rs_jsonapi
# Disable i2p BOB support for automatically setting up an i2p tunnel for RS
# "CONFIG+=no_rs_bob"
CONFIG *= rs_bob
no_rs_bob:CONFIG -= rs_bob
# To enable channel indexing append the following assignation to qmake command # To enable channel indexing append the following assignation to qmake command
# line "CONFIG+=rs_deep_channel_index" # line "CONFIG+=rs_deep_channel_index"
CONFIG *= no_rs_deep_channel_index CONFIG *= no_rs_deep_channel_index
@ -550,6 +555,10 @@ rs_webui {
DEFINES *= RS_WEBUI DEFINES *= RS_WEBUI
} }
rs_bob {
DEFINES *= RS_USE_I2P_BOB
}
rs_deep_channels_index:DEFINES *= RS_DEEP_CHANNEL_INDEX rs_deep_channels_index:DEFINES *= RS_DEEP_CHANNEL_INDEX
rs_deep_files_index:DEFINES *= RS_DEEP_FILES_INDEX rs_deep_files_index:DEFINES *= RS_DEEP_FILES_INDEX