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 \
plugins/dlfcn_win32.h \
rsitems/rspluginitems.h \
util/i2pcommon.h \
util/rsinitedptr.h
HEADERS += $$PUBLIC_HEADERS
@ -517,7 +518,8 @@ SOURCES += ft/ftchunkmap.cc \
ft/ftfilesearch.cc \
ft/ftserver.cc \
ft/fttransfermodule.cc \
ft/ftturtlefiletransferitem.cc
ft/ftturtlefiletransferitem.cc \
util/i2pcommon.cpp
SOURCES += crypto/chacha20.cpp \
crypto/hashstream.cc\

View File

@ -161,7 +161,9 @@ public:
p3ChatService *chatSrv;
p3StatusService *mStatusSrv;
p3GxsTunnelService *mGxsTunnels;
#ifdef RS_USE_I2P_BOB
p3I2pBob *mI2pBob;
#endif
// 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);
rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance();
#ifdef RS_USE_I2P_BOB
mI2pBob = new p3I2pBob(mPeerMgr);
autoProxy->addProxy(autoProxyType::I2PBOB, mI2pBob);
#endif
//load all the SSL certs as friends
// std::list<std::string> sslIds;
@ -1649,7 +1651,9 @@ int RsServer::StartupRetroShare()
mConfigMgr->addConfiguration("wire.cfg", wire_ns);
#endif
#endif //RS_ENABLE_GXS
#ifdef RS_USE_I2P_BOB
mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pBob);
#endif
mPluginsManager->addConfigurations(mConfigMgr) ;
@ -1724,7 +1728,7 @@ int RsServer::StartupRetroShare()
// now enable bob
bobSettings bs;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &bs);
bs.enableBob = true;
bs.enable = true;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &bs);
} else {
std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl;
@ -1795,7 +1799,9 @@ int RsServer::StartupRetroShare()
/**************************************************************************/
// auto proxy threads
#ifdef RS_USE_I2P_BOB
startServiceThread(mI2pBob, "I2P-BOB");
#endif
#ifdef RS_ENABLE_GXS
// 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 kConfigKeyOutVariance = "OUT_VARIANCE";
static const bool kDefaultBOBEnable = false;
static const int8_t kDefaultLength = 3;
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 receiving loop in error/no-data case
static const useconds_t sleepTimeRecv = 250; // times 1000 = 250ms
/// Sleep duration for everything else
static const useconds_t sleepTimeWait = 50; // times 1000 = 50ms or 0.05s
static const int sleepFactorDefault = 10; // 0.5s
static const int sleepFactorFast = 1; // 0.05s
static const int sleepFactorSlow = 20; // 1s
static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Default, "p3I2pBob"};
static const rstime_t selfCheckPeroid = 30;
void doSleep(useconds_t timeToSleepMS) {
@ -74,15 +67,7 @@ p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr)
mProcessing(NULL), mLock("I2P-BOB")
{
// set defaults
mSetting.enableBob = kDefaultBOBEnable;
mSetting.keys = "";
mSetting.addr = "";
mSetting.inLength = kDefaultLength;
mSetting.inQuantity = kDefaultQuantity;
mSetting.inVariance = kDefaultVariance;
mSetting.outLength = kDefaultLength;
mSetting.outQuantity = kDefaultQuantity;
mSetting.outVariance = kDefaultVariance;
mSetting.initDefault();
mCommands.clear();
}
@ -90,12 +75,12 @@ p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr)
bool p3I2pBob::isEnabled()
{
RS_STACK_MUTEX(mLock);
return mSetting.enableBob;
return mSetting.enable;
}
bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
{
std::cout << "p3I2pBob::initialSetup" << std::endl;
RS_DBG("");
// 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
// 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;
processTaskAsync(fakeTicket);
std::cout << "p3I2pBob::initialSetup fakeTicket requested" << std::endl;
RS_DBG("fakeTicket requested");
// now start thread
start("I2P-BOB gen key");
std::cout << "p3I2pBob::initialSetup thread started" << std::endl;
RS_DBG("thread started");
int counter = 0;
// wait for keys
@ -137,24 +122,24 @@ bool p3I2pBob::initialSetup(std::string &addr, uint16_t &/*port*/)
break;
if (++counter > 30) {
std::cout << "p3I2pBob::initialSetup timeout!" << std::endl;
RS_DBG4("timeout!");
return false;
}
}
std::cout << "p3I2pBob::initialSetup got keys" << std::endl;
RS_DBG("got keys");
// stop thread
fullstop();
std::cout << "p3I2pBob::initialSetup thread stopped" << std::endl;
RS_DBG("thread stopped");
{
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;
}
@ -172,7 +157,7 @@ void p3I2pBob::processTaskAsync(taskTicket *ticket)
}
break;
default:
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskAsync unknown task");
RS_DBG("unknown task");
rsAutoProxyMonitor::taskError(ticket);
break;
}
@ -187,7 +172,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::status:
// check if everything needed is set
if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::status autoProxyTask::status data is missing");
RS_DBG("autoProxyTask::status data is missing");
rsAutoProxyMonitor::taskError(ticket);
break;
}
@ -201,7 +186,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::getSettings:
// check if everything needed is set
if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getSettings data is missing");
RS_DBG("autoProxyTask::getSettings data is missing");
rsAutoProxyMonitor::taskError(ticket);
break;
}
@ -215,7 +200,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
case autoProxyTask::setSettings:
// check if everything needed is set
if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::setSettings data is missing");
RS_DBG("autoProxyTask::setSettings data is missing");
rsAutoProxyMonitor::taskError(ticket);
break;
}
@ -235,7 +220,7 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
break;
case autoProxyTask::getErrorInfo:
if (!data) {
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::data_tick autoProxyTask::getErrorInfo data is missing");
RS_DBG("autoProxyTask::getErrorInfo data is missing");
rsAutoProxyMonitor::taskError(ticket);
} else {
RS_STACK_MUTEX(mLock);
@ -244,34 +229,12 @@ void p3I2pBob::processTaskSync(taskTicket *ticket)
}
break;
default:
rslog(RsLog::Warning, &i2pBobLogInfo, "p3I2pBob::processTaskSync unknown task");
RS_DBG("unknown task");
rsAutoProxyMonitor::taskError(ticket);
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) {
return (answer.compare(0, 2, "OK") == 0);
}
@ -284,10 +247,8 @@ void p3I2pBob::threadTick()
{
int sleepTime = 0;
{
RS_STACK_MUTEX(mLock);
std::stringstream ss;
ss << "data_tick mState: " << mState << " mTask: " << mTask << " mBOBState: " << mBOBState << " mPending: " << mPending.size();
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
RS_STACK_MUTEX(mLock);
RS_DBG4("data_tick mState: ", mState, " mTask: ", mTask, " mBOBState: ", mBOBState, " mPending: ", mPending.size());
}
sleepTime += stateMachineController();
@ -326,15 +287,13 @@ int p3I2pBob::stateMachineBOB()
if (mBOBState == bsList) {
int counter = 0;
while (answer.find("OK Listing done") == std::string::npos) {
std::stringstream ss;
ss << "stateMachineBOB status check: read loop, counter: " << counter;
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, ss.str());
RS_DBG3("stateMachineBOB status check: read loop, counter: ", counter);
answer += recv();
counter++;
}
if (answer.find(mTunnelName) == std::string::npos) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB status check: tunnel down!");
RS_DBG("status check: tunnel down!");
// signal error
*((bool *)mProcessing->data) = true;
}
@ -346,12 +305,12 @@ int p3I2pBob::stateMachineBOB()
switch (mBOBState) {
case bsNewkeysN:
key = answer.substr(3, answer.length()-3);
mSetting.addr = keyToBase32Addr(key);
mSetting.address.base32 = i2p::keyToBase32Addr(key);
IndicateConfigChanged();
break;
case bsGetkeys:
key = answer.substr(3, answer.length()-3);
mSetting.keys = key;
mSetting.address.privateKey = key;
IndicateConfigChanged();
break;
default:
@ -374,8 +333,8 @@ int p3I2pBob::stateMachineBOB_locked_failure(const std::string &answer, const bo
return sleepFactorDefault;
}
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB FAILED to run command '" + currentState.command + "'");
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineBOB '" + answer + "'");
RS_DBG("FAILED to run command: ", currentState.command);
RS_DBG("answer: ", answer);
mErrorMsg.append("FAILED to run command '" + currentState.command + "'" + '\n');
mErrorMsg.append("reason '" + answer + "'" + '\n');
@ -422,14 +381,14 @@ int p3I2pBob::stateMachineController()
return stateMachineController_locked_idle();
case csDoConnect:
if (!connectI2P()) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doConnect: unable to connect");
RS_DBG("doConnect: unable to connect");
mStateOld = mState;
mState = csError;
mErrorMsg = "unable to connect to BOB port";
return sleepFactorSlow;
}
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doConnect: connected");
RS_DBG4("doConnect: connected");
mState = csConnected;
break;
case csConnected:
@ -437,7 +396,7 @@ int p3I2pBob::stateMachineController()
case csWaitForBob:
// check connection problems
if (mSocket == 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController waitForBob: conection lost");
RS_DBG("waitForBob: conection lost");
mStateOld = mState;
mState = csError;
mErrorMsg = "connection lost to BOB";
@ -447,21 +406,21 @@ int p3I2pBob::stateMachineController()
// check for finished BOB protocol
if (mBOBState == bsCleared) {
// done
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController waitForBob: mBOBState == bsCleared");
RS_DBG4("waitForBob: mBOBState == bsCleared");
mState = csDoDisconnect;
}
break;
case csDoDisconnect:
if (!disconnectI2P() || mSocket != 0) {
// just in case
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController doDisconnect: can't disconnect");
RS_DBG("doDisconnect: can't disconnect");
mStateOld = mState;
mState = csError;
mErrorMsg = "unable to disconnect from BOB";
return sleepFactorDefault;
}
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController doDisconnect: disconnected");
RS_DBG4("doDisconnect: disconnected");
mState = csDisconnected;
break;
case csDisconnected:
@ -487,12 +446,12 @@ int p3I2pBob::stateMachineController_locked_idle()
mProcessing = mPending.front();
mPending.pop();
if (!mSetting.enableBob && (
if (!mSetting.enable && (
mProcessing->task == autoProxyTask::start ||
mProcessing->task == autoProxyTask::stop ||
mProcessing->task == autoProxyTask::proxyStatusCheck)) {
// 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);
mProcessing = NULL;
} else {
@ -514,7 +473,7 @@ int p3I2pBob::stateMachineController_locked_idle()
mTask = ctRunCheck;
break;
default:
rslog(RsLog::Debug_Alert, &i2pBobLogInfo, "stateMachineController_locked_idle unknown async task");
RS_DBG1("unknown async task");
rsAutoProxyMonitor::taskError(mProcessing);
mProcessing = NULL;
break;
@ -561,29 +520,29 @@ int p3I2pBob::stateMachineController_locked_connected()
switch (mTask) {
case ctRunSetUp:
// when we have a key use it for server tunnel!
if(mSetting.keys.empty()) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickC");
if(mSetting.address.privateKey.empty()) {
RS_DBG4("setting mBOBState = setnickC");
mBOBState = bsSetnickC;
} else {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickS");
RS_DBG4("setting mBOBState = setnickS");
mBOBState = bsSetnickS;
}
break;
case ctRunShutDown:
// shut down existing tunnel
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = getnick");
RS_DBG4("setting mBOBState = getnick");
mBOBState = bsGetnick;
break;
case ctRunCheck:
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = list");
RS_DBG4("setting mBOBState = list");
mBOBState = bsList;
break;
case ctRunGetKeys:
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_connected: setting mBOBState = setnickN");
RS_DBG4("setting mBOBState = setnickN");
mBOBState = bsSetnickN;
break;
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;
}
@ -599,7 +558,7 @@ int p3I2pBob::stateMachineController_locked_disconnected()
if(errorHappened) {
// reset old state
mStateOld = csIdel;
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_disconnected: error during process!");
RS_DBG("error during process!");
}
// answer ticket
@ -628,12 +587,12 @@ int p3I2pBob::stateMachineController_locked_disconnected()
mTask = mTaskOld;
if (!errorHappened) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_disconnected: run check result: ok");
RS_DBG4("run check result: ok");
break;
}
// switch to error
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.";
break;
@ -656,7 +615,7 @@ int p3I2pBob::stateMachineController_locked_disconnected()
mTask = mTaskOld;
break;
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);
}
mProcessing = NULL;
@ -672,14 +631,12 @@ int p3I2pBob::stateMachineController_locked_error()
{
// wait for bob protocoll
if (mBOBState != bsCleared) {
rslog(RsLog::Debug_All, &i2pBobLogInfo, "stateMachineController_locked_error: waiting for BOB");
RS_DBG4("waiting for BOB");
return sleepFactorFast;
}
#if 0
std::stringstream ss;
ss << "stateMachineController_locked_error: mProcessing: " << (mProcessing ? "not null" : "null");
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
RS_DBG4("stateMachineController_locked_error: mProcessing: ", (mProcessing ? "not null" : "null"));
#endif
// try to finish ticket
@ -687,7 +644,7 @@ int p3I2pBob::stateMachineController_locked_error()
switch (mTask) {
case ctRunCheck:
// 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;
mState = csDoDisconnect;
mStateOld = csIdel;
@ -695,7 +652,7 @@ int p3I2pBob::stateMachineController_locked_error()
break;
case ctRunShutDown:
// 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;
mStateOld = csIdel;
mErrorMsg.clear();
@ -703,14 +660,14 @@ int p3I2pBob::stateMachineController_locked_error()
case ctIdle:
// 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)
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;
mStateOld = csIdel;
mErrorMsg.clear();
break;
case ctRunGetKeys:
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;
mState = csDoDisconnect;
// keep the error message
@ -721,7 +678,7 @@ int p3I2pBob::stateMachineController_locked_error()
// periodically retry
if (mLastProxyCheck < time(NULL) - (selfCheckPeroid >> 1) && mTask == ctRunSetUp) {
rslog(RsLog::Warning, &i2pBobLogInfo, "stateMachineController_locked_error: retrying");
RS_DBG("retrying");
mLastProxyCheck = time(NULL);
mErrorMsg.clear();
@ -734,7 +691,7 @@ int p3I2pBob::stateMachineController_locked_error()
// check for new tickets
if (!mPending.empty()) {
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "stateMachineController_locked_error: processing new ticket");
RS_DBG4("processing new ticket");
// reset and try new task
mTask = ctIdle;
@ -765,16 +722,16 @@ RsSerialiser *p3I2pBob::setupSerialiser()
bool p3I2pBob::saveList(bool &cleanup, std::list<RsItem *> &lst)
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "saveList");
RS_DBG4("");
cleanup = true;
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet;
RsTlvKeyValue kv;
RS_STACK_MUTEX(mLock);
addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enableBob ? "TRUE" : "FALSE")
addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.keys)
addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.addr)
addKVS(vitem, kv, kConfigKeyBOBEnable, mSetting.enable ? "TRUE" : "FALSE")
addKVS(vitem, kv, kConfigKeyBOBKey, mSetting.address.privateKey)
addKVS(vitem, kv, kConfigKeyBOBAddr, mSetting.address.base32)
addKVSInt(vitem, kv, kConfigKeyInLength, mSetting.inLength)
addKVSInt(vitem, kv, kConfigKeyInQuantity, mSetting.inQuantity)
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)
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "loadList");
RS_DBG4("");
for(std::list<RsItem*>::const_iterator it = load.begin(); it!=load.end(); ++it) {
RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet*>(*it);
@ -808,11 +765,11 @@ bool p3I2pBob::loadList(std::list<RsItem *> &load)
RS_STACK_MUTEX(mLock);
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) {
if (kit->key == kConfigKeyBOBEnable)
mSetting.enableBob = kit->value == "TRUE";
mSetting.enable = kit->value == "TRUE";
else if (kit->key == kConfigKeyBOBKey)
mSetting.keys = kit->value;
mSetting.address.privateKey = kit->value;
else if (kit->key == kConfigKeyBOBAddr)
mSetting.addr = kit->value;
mSetting.address.base32 = kit->value;
getKVSUInt(kit, kConfigKeyInLength, mSetting.inLength)
getKVSUInt(kit, kConfigKeyInQuantity, mSetting.inQuantity)
getKVSUInt(kit, kConfigKeyInVariance, mSetting.inVariance)
@ -820,7 +777,7 @@ bool p3I2pBob::loadList(std::list<RsItem *> &load)
getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity)
getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance)
else
rslog(RsLog::Warning, &i2pBobLogInfo, "loadList unknown key: " + kit->key);
RS_DBG("unknown key: ", kit->key);
}
}
delete vitem;
@ -884,7 +841,7 @@ void p3I2pBob::getStates(bobStates *bs)
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;
copy.push_back('\n');
@ -896,7 +853,7 @@ std::string p3I2pBob::executeCommand(const std::string &command)
// receive answer (trailing new line is already removed!)
std::string ans = recv();
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "executeCommand_locked answer '" + ans + "'");
RS_DBG4("answer: ", ans);
return ans;
}
@ -906,7 +863,7 @@ bool p3I2pBob::connectI2P()
// there is only one thread that touches mSocket - no need for a lock
if (mSocket != 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "connectI2P_locked mSocket != 0");
RS_DBG("mSocket != 0");
return false;
}
@ -914,21 +871,21 @@ bool p3I2pBob::connectI2P()
mSocket = unix_socket(PF_INET, SOCK_STREAM, 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;
}
// connect
int err = unix_connect(mSocket, mI2PProxyAddr);
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;
}
// receive hello msg
recv();
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "connectI2P_locked done");
RS_DBG4("done");
return true;
}
@ -937,17 +894,17 @@ bool p3I2pBob::disconnectI2P()
// there is only one thread that touches mSocket - no need for a lock
if (mSocket == 0) {
rslog(RsLog::Warning, &i2pBobLogInfo, "disconnectI2P_locked mSocket == 0");
RS_DBG("mSocket == 0");
return true;
}
int err = unix_close(mSocket);
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;
}
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "disconnectI2P_locked done");
RS_DBG4("done");
mSocket = 0;
return true;
}
@ -968,7 +925,7 @@ std::string toString(const std::string &a, const int8_t b) {
void p3I2pBob::finalizeSettings_locked()
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked");
RS_DBG4("");
sockaddr_storage_clear(mI2PProxyAddr);
// get i2p proxy addr
@ -979,8 +936,8 @@ void p3I2pBob::finalizeSettings_locked()
sockaddr_storage_setipv4(mI2PProxyAddr, (sockaddr_in*)&proxy);
sockaddr_storage_setport(mI2PProxyAddr, 2827);
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + sockaddr_storage_tostring(mI2PProxyAddr));
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "finalizeSettings_locked using " + mSetting.addr);
RS_DBG4("using ", mI2PProxyAddr);
RS_DBG4("using ", mSetting.address.base32);
peerState ps;
mPeerMgr->getOwnNetStatus(ps);
@ -988,21 +945,17 @@ void p3I2pBob::finalizeSettings_locked()
// setup commands
// new lines are appended later!
// generate random suffix for name
// RSRandom::random_alphaNumericString can return very weird looking strings like: ,,@z+M
// use base32 instead
size_t len = 5; // 5 characters = 8 base32 symbols
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);
// generate 8 characater long random suffix for name
constexpr size_t len = 8;
const std::string location = RsRandom::alphaNumeric(len);
RS_DBG4("using suffix ", location);
mTunnelName = "RetroShare-" + location;
const std::string setnick = "setnick RetroShare-" + location;
const std::string getnick = "getnick RetroShare-" + location;
const std::string newkeys = "newkeys";
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 inport = toString("inport ", sockaddr_storage_port(proxy));
const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr);
@ -1063,7 +1016,7 @@ void p3I2pBob::finalizeSettings_locked()
void p3I2pBob::updateSettings_locked()
{
rslog(RsLog::Debug_Basic, &i2pBobLogInfo, "updateSettings_locked");
RS_DBG4("");
sockaddr_storage proxy;
mPeerMgr->getProxyServerAddress(RS_HIDDEN_TYPE_I2P, proxy);
@ -1071,7 +1024,7 @@ void p3I2pBob::updateSettings_locked()
peerState 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 inport = toString("inport ", sockaddr_storage_port(proxy));
const std::string outhost = "outhost " + sockaddr_storage_iptostring(ps.localaddr);
@ -1103,38 +1056,62 @@ void p3I2pBob::updateSettings_locked()
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;
ssize_t length;
const uint16_t bufferSize = 128;
std::vector<char> buffer(bufferSize);
uint16_t retry = 10;
do {
doSleep(sleepTimeRecv);
memset(buffer, 0, bufferSize);
// there is only one thread that touches mSocket - no need for a lock
length = ::recv(mSocket, buffer.data(), buffer.size(), 0);
if (length < 0)
// peek at data
auto length = ::recv(mSocket, buffer, bufferSize, MSG_PEEK);
if (length <= 0) {
if (length < 0) {
// error
perror(__PRETTY_FUNCTION__);
}
retry--;
doSleep(sleepTimeRecv);
continue;
}
ans.append(buffer.begin(), buffer.end());
// at least one byte was read
// clean received string
ans.erase(std::remove(ans.begin(), ans.end(), '\0'), ans.end());
ans.erase(std::remove(ans.begin(), ans.end(), '\n'), ans.end());
// search for new line
auto bufferStr = std::string(buffer);
size_t pos = bufferStr.find('\n');
#if 0
std::stringstream ss;
ss << "recv length: " << length << " (bufferSize: " << bufferSize << ") ans: " << ans.length();
rslog(RsLog::Debug_All, &i2pBobLogInfo, ss.str());
#endif
if (pos == std::string::npos) {
// no new line found -> more to read
// clear and resize buffer again
buffer.clear();
buffer.resize(bufferSize);
// sanity check
if (length != 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())
break;
} while(length == bufferSize || ans.size() < 4);
// calculate how much there is to read, read the \n, too!
length = pos + 1;
// 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;
}

View File

@ -30,9 +30,10 @@
#include <sys/socket.h>
#endif
#include "pqi/p3cfgmgr.h"
#include "services/autoproxy/rsautoproxymonitor.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
@ -49,7 +50,7 @@
*
* Note 3:
* 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:
* The service uses three state machines to manage its task:
@ -72,7 +73,7 @@
* mCommands[bobState::quit] = {quit, bobState::cleared};
*
* stateMachineController:
* This state machone manages the high level tasks.
* This state machine manages the high level tasks.
* It is controlled by mState and mTask.
*
* mTast:
@ -162,19 +163,7 @@ struct bobStateInfo {
bobState nextState;
};
struct bobSettings {
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;
};
struct bobSettings : i2p::settings {};
///
/// \brief The bobStates struct
@ -203,8 +192,6 @@ public:
void processTaskAsync(taskTicket *ticket);
void processTaskSync(taskTicket *ticket);
static std::string keyToBase32Addr(const std::string &key);
void threadTick() override; /// @see RsTickingThread
private:

View File

@ -22,6 +22,7 @@
#include "rsautoproxymonitor.h"
#include <unistd.h> /* for usleep() */
#include "util/rsdebug.h"
#include "util/rstime.h"
rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL;
@ -42,8 +43,10 @@ rsAutoProxyMonitor *rsAutoProxyMonitor::instance()
void rsAutoProxyMonitor::addProxy(autoProxyType::autoProxyType_enum type, autoProxyService *service)
{
RS_STACK_MUTEX(mLock);
if (mProxies.find(type) != mProxies.end())
std::cerr << "sAutoProxyMonitor::addProxy type " << type << " already added - OVERWRITING" << std::endl;
if (mProxies.find(type) != mProxies.end()) {
RS_ERR("type ", type, " already added - OVERWRITING");
print_stacktrace();
}
mProxies[type] = service;
}
@ -117,7 +120,7 @@ void rsAutoProxyMonitor::stopAllRSShutdown()
do {
rstime::rs_usleep(1000 * 1000);
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())
break;
t++;
@ -146,13 +149,16 @@ void rsAutoProxyMonitor::task(taskTicket *ticket)
{
// sanity checks
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) {
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) {
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;
@ -168,7 +174,11 @@ void rsAutoProxyMonitor::task(taskTicket *ticket)
*tt = *ticket;
tt->types.clear();
tt->types.push_back(*it);
s->processTaskAsync(tt);
// it's async!
RsThread::async([s, tt] {
s->processTaskAsync(tt);
});
} else {
s->processTaskSync(ticket);
}
@ -187,7 +197,8 @@ void rsAutoProxyMonitor::taskAsync(std::vector<autoProxyType::autoProxyType_enum
if (!isAsyncTask(task)) {
// Usually the services will reject this ticket.
// 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();
@ -215,7 +226,8 @@ void rsAutoProxyMonitor::taskSync(std::vector<autoProxyType::autoProxyType_enum>
if (isAsyncTask(task)) {
// Usually the services will reject this ticket.
// 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();
@ -244,7 +256,8 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu
t->cb->taskFinished(t);
if (t != NULL) {
// 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;
}
} else if (t->async){
@ -252,12 +265,13 @@ void rsAutoProxyMonitor::taskDone(taskTicket *t, autoProxyStatus::autoProxyStatu
// we must take care of deleting
cleanUp = true;
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 (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 ignored "-Wdelete-incomplete"
delete t->data;
@ -290,7 +304,8 @@ void rsAutoProxyMonitor::taskFinished(taskTicket *&ticket)
// clean up
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 ignored "-Wdelete-incomplete"
delete ticket->data;
@ -308,7 +323,7 @@ autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType
if ((itService = mProxies.find(t)) != mProxies.end()) {
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;
}

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.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)
{

View File

@ -23,6 +23,7 @@
#include <gui/notifyqt.h>
#include "rshare.h"
#include "rsharesettings.h"
#include "util/i2pcommon.h"
#include "util/RsNetUtil.h"
#include "util/misc.h"
@ -82,6 +83,10 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
manager = NULL ;
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::isTorAuto())
@ -1352,7 +1357,7 @@ void ServerPage::updateInProxyIndicator()
ui.iconlabel_service_incoming->setMovie(movie);
movie->start();
if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enableBob) {
if (mHiddenType == RS_HIDDEN_TYPE_I2P && mBobSettings.enable) {
QTcpSocket tcpSocket;
@ -1439,15 +1444,16 @@ void ServerPage::getNewKey()
void ServerPage::loadKey()
{
mBobSettings.keys = ui.pteBobServerKey->toPlainText().toStdString();
mBobSettings.addr = p3I2pBob::keyToBase32Addr(mBobSettings.keys);
mBobSettings.address.privateKey = ui.pteBobServerKey->toPlainText().toStdString();
mBobSettings.address.publicKey = i2p::publicKeyFromPrivate(mBobSettings.address.privateKey);
mBobSettings.address.base32 = i2p::keyToBase32Addr(mBobSettings.address.publicKey);
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings);
}
void ServerPage::enableBob(bool checked)
{
mBobSettings.enableBob = checked;
mBobSettings.enable = checked;
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings);
@ -1487,7 +1493,7 @@ void ServerPage::toggleBobAdvancedSettings(bool checked)
{
ui.swBobAdvanced->setCurrentIndex(checked ? 1 : 0);
if (!mBobSettings.keys.empty()) {
if (!mBobSettings.address.privateKey.empty()) {
if (checked) {
ui.pbBobGenAddr->show();
} else {
@ -1578,9 +1584,9 @@ void ServerPage::loadCommon()
whileBlocking(ui.hiddenpage_proxyPort_i2p_2)->setValue(proxyport); // this one is for bob tab
// 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.leBobB32Addr->show();
}
@ -1623,13 +1629,13 @@ void ServerPage::saveBob()
void ServerPage::updateStatusBob()
{
QString addr = QString::fromStdString(mBobSettings.addr);
QString addr = QString::fromStdString(mBobSettings.address.base32);
if (ui.leBobB32Addr->text() != addr) {
ui.leBobB32Addr->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
ui.lBobB32Addr->show();
ui.leBobB32Addr->show();
@ -1655,7 +1661,7 @@ void ServerPage::updateStatusBob()
QString bobSimpleText = QString();
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").
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_proxyPort_i2p_2->text(),
bs.tunnelName.empty() ? tr("unknown") :
@ -1777,15 +1783,15 @@ void ServerPage::updateStatusBob()
void ServerPage::setUpBobElements()
{
ui.gbBob->setEnabled(mBobSettings.enableBob);
if (mBobSettings.enableBob) {
ui.gbBob->setEnabled(mBobSettings.enable);
if (mBobSettings.enable) {
ui.hiddenpage_proxyAddress_i2p->setEnabled(false);
ui.hiddenpage_proxyAddress_i2p->setToolTip("Use I2P/BOB settings to change this value");
ui.hiddenpage_proxyPort_i2p->setEnabled(false);
ui.hiddenpage_proxyPort_i2p->setToolTip("Use I2P/BOB settings to change this value");
ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.addr));
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.keys));
ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.address.base32));
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.address.privateKey));
// cast to int to avoid problems
int li, lo, qi, qo, vi, vo;

View File

@ -140,6 +140,11 @@ rs_macos10.15:CONFIG -= rs_macos10.11
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
# line "CONFIG+=rs_deep_channel_index"
CONFIG *= no_rs_deep_channel_index
@ -550,6 +555,10 @@ rs_webui {
DEFINES *= RS_WEBUI
}
rs_bob {
DEFINES *= RS_USE_I2P_BOB
}
rs_deep_channels_index:DEFINES *= RS_DEEP_CHANNEL_INDEX
rs_deep_files_index:DEFINES *= RS_DEEP_FILES_INDEX