Merge pull request #2132 from sehraf/pr_add_i2p_sam3

Replace I2P BOB with SAMv3
This commit is contained in:
csoler 2021-10-24 20:39:22 +02:00 committed by GitHub
commit 3ddf3d0853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1797 additions and 1863 deletions

2
.gitignore vendored
View File

@ -15,3 +15,5 @@ Thumbs.db
*.pro.user *.pro.user
.kdev4 .kdev4
*.kdev4 *.kdev4
!supportlibs/libsam3/Makefile

3
.gitmodules vendored
View File

@ -14,3 +14,6 @@
[submodule "supportlibs/rapidjson"] [submodule "supportlibs/rapidjson"]
path = supportlibs/rapidjson path = supportlibs/rapidjson
url = https://github.com/Tencent/rapidjson.git url = https://github.com/Tencent/rapidjson.git
[submodule "supportlibs/libsam3"]
path = supportlibs/libsam3
url = https://github.com/i2p/libsam3.git

View File

@ -393,7 +393,6 @@ HEADERS += pqi/authssl.h \
pqi/pqissl.h \ pqi/pqissl.h \
pqi/pqissllistener.h \ pqi/pqissllistener.h \
pqi/pqisslpersongrp.h \ pqi/pqisslpersongrp.h \
pqi/pqissli2pbob.h \
pqi/pqisslproxy.h \ pqi/pqisslproxy.h \
pqi/pqistore.h \ pqi/pqistore.h \
pqi/pqistreamer.h \ pqi/pqistreamer.h \
@ -454,7 +453,7 @@ HEADERS += rsitems/rsitem.h \
rsitems/rsgxsupdateitems.h \ rsitems/rsgxsupdateitems.h \
rsitems/rsserviceinfoitems.h \ rsitems/rsserviceinfoitems.h \
HEADERS += services/autoproxy/p3i2pbob.h \ HEADERS += \
services/rseventsservice.h \ services/rseventsservice.h \
services/autoproxy/rsautoproxymonitor.h \ services/autoproxy/rsautoproxymonitor.h \
services/p3msgservice.h \ services/p3msgservice.h \
@ -558,7 +557,6 @@ SOURCES += pqi/authgpg.cc \
pqi/pqissl.cc \ pqi/pqissl.cc \
pqi/pqissllistener.cc \ pqi/pqissllistener.cc \
pqi/pqisslpersongrp.cc \ pqi/pqisslpersongrp.cc \
pqi/pqissli2pbob.cpp \
pqi/pqisslproxy.cc \ pqi/pqisslproxy.cc \
pqi/pqistore.cc \ pqi/pqistore.cc \
pqi/pqistreamer.cc \ pqi/pqistreamer.cc \
@ -616,7 +614,6 @@ SOURCES += serialiser/rsbaseserial.cc \
SOURCES += services/autoproxy/rsautoproxymonitor.cc \ SOURCES += services/autoproxy/rsautoproxymonitor.cc \
services/rseventsservice.cc \ services/rseventsservice.cc \
services/autoproxy/p3i2pbob.cc \
services/p3msgservice.cc \ services/p3msgservice.cc \
services/p3service.cc \ services/p3service.cc \
services/p3statusservice.cc \ services/p3statusservice.cc \
@ -1012,6 +1009,34 @@ rs_broadcast_discovery {
} }
} }
rs_sam3 {
SOURCES += \
services/autoproxy/p3i2psam3.cpp \
pqi/pqissli2psam3.cpp \
HEADERS += \
services/autoproxy/p3i2psam3.h \
pqi/pqissli2psam3.h \
}
rs_sam3_libsam3 {
DUMMYQMAKECOMPILERINPUT = FORCE
libsam3.name = Generating libsam3.
libsam3.input = DUMMYQMAKECOMPILERINPUT
libsam3.output = $$clean_path($${LIBSAM3_BUILD_PATH}/libsam3.a)
libsam3.CONFIG += target_predeps combine
libsam3.variable_out = PRE_TARGETDEPS
libsam3.commands = \
cd $${RS_SRC_PATH} && ( \
git submodule update --init supportlibs/libsam3 || \
true ) && \
mkdir -p $${UDP_DISCOVERY_BUILD_PATH} && \
cp -r $${LIBSAM3_SRC_PATH}/* $${LIBSAM3_BUILD_PATH} && \
cd $${LIBSAM3_BUILD_PATH} && \
$(MAKE) build
QMAKE_EXTRA_COMPILERS += libsam3
}
########################################################################################################### ###########################################################################################################
# OLD CONFIG OPTIONS. # OLD CONFIG OPTIONS.
# Not used much - but might be useful one day. # Not used much - but might be useful one day.

View File

@ -1742,6 +1742,13 @@ bool pqissl::moretoread(uint32_t usec)
{ {
rslog(RSL_ALERT, pqisslzone, rslog(RSL_ALERT, pqisslzone,
"pqissl::moretoread() Select ERROR!"); "pqissl::moretoread() Select ERROR!");
RS_WARN(strerror(errno));
if (errno == EBADF) {
// happens when SAM is shut down
rslog(RSL_ALERT, pqisslzone, "pqissl::moretoread() -> calling reset()");
reset_locked();
}
return 0; return 0;
} }

View File

@ -1,52 +0,0 @@
/*******************************************************************************
* libretroshare/src/pqi: pqissli2pbob.cc *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2016 by Sehraf *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "pqissli2pbob.h"
bool pqissli2pbob::connect_parameter(uint32_t type, const std::string &value)
{
if (type == NET_PARAM_CONNECT_DOMAIN_ADDRESS)
{
RS_STACK_MUTEX(mSslMtx);
// a new line must be appended!
mI2pAddr = value + '\n';
return true;
}
return pqissl::connect_parameter(type, value);
}
int pqissli2pbob::Basic_Connection_Complete()
{
int ret;
if ((ret = pqissl::Basic_Connection_Complete()) != 1)
{
// basic connection not complete.
return ret;
}
// send addr. (new line is already appended)
ret = send(sockfd, mI2pAddr.c_str(), mI2pAddr.length(), 0);
if (ret != (int)mI2pAddr.length())
return -1;
return 1;
}

View File

@ -1,52 +0,0 @@
/*******************************************************************************
* libretroshare/src/pqi: pqissli2pbob.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2016 by Sehraf *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifndef PQISSLI2PBOB_H
#define PQISSLI2PBOB_H
#include "pqi/pqissl.h"
/*
* This class is a minimal varied version of pqissl to work with I2P BOB tunnels.
* The only difference is that the [.b32].i2p addresses must be sent first.
*
* Everything else is untouched.
*/
class pqissli2pbob : public pqissl
{
public:
pqissli2pbob(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm)
: pqissl(l, parent, lm) {}
// NetInterface interface
public:
bool connect_parameter(uint32_t type, const std::string &value);
// pqissl interface
protected:
int Basic_Connection_Complete();
private:
std::string mI2pAddr;
};
#endif // PQISSLI2PBOB_H

View File

@ -0,0 +1,261 @@
#include "pqissli2psam3.h"
#include <libsam3.h>
RS_SET_CONTEXT_DEBUG_LEVEL(2)
static constexpr int pqiDone = 1;
static constexpr int pqiWait = 0;
static constexpr int pqiError = -1;
pqissli2psam3::pqissli2psam3(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm)
: pqissl(l, parent, lm), mState(pqisslSam3State::NONE), mI2pAddrB32(), mI2pAddrLong()
{
RS_DBG4();
mConn = nullptr;
}
bool pqissli2psam3::connect_parameter(uint32_t type, const std::string &value)
{
RS_DBG4();
if (type == NET_PARAM_CONNECT_DOMAIN_ADDRESS)
{
RS_DBG1("got addr:", value);
RS_STACK_MUTEX(mSslMtx);
mI2pAddrB32 = value;
return true;
}
return pqissl::connect_parameter(type, value);
}
int pqissli2psam3::Initiate_Connection()
{
RS_DBG4();
if(waiting != WAITING_DELAY)
{
RS_ERR("Already Attempt in Progress!");
return pqiError;
}
switch (mState) {
case(pqisslSam3State::NONE):
RS_DBG2("NONE");
{
if(mConn) {
// how did we end up here?
RS_ERR("state is NONE but a connection is existing?!");
}
mConn = 0;
// get SAM session
mConn = 0;
samSettings ss;
ss.session = nullptr;
rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::getSettings, static_cast<void*>(&ss));
if (!!ss.session) {
RS_DBG3("NONE->DO_LOOKUP");
mState = pqisslSam3State::DO_LOOKUP;
} else {
RS_DBG3("NONE->DO_LOOKUP NOPE", ss.session);
}
}
break;
case(pqisslSam3State::DO_LOOKUP):
RS_DBG1("DO_LOOKUP");
if (!mI2pAddrLong.empty()) {
// skip lookup, it is highly unlikely/impossible for a public key to change (isn't it?)
mState = pqisslSam3State::WAIT_LOOKUP;
break;
}
{
i2p::address *addr = new i2p::address;
addr->clear();
addr->base32 = mI2pAddrB32;
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::lookupKey, this, static_cast<void*>(addr));
}
mState = pqisslSam3State::WAIT_LOOKUP;
break;
case(pqisslSam3State::DO_CONNECT):
RS_DBG2("DO_CONNECT");
{
auto wrapper = new samEstablishConnectionWrapper();
wrapper->address.clear();
wrapper->address.publicKey = mI2pAddrLong;
wrapper->connection = nullptr;
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::establishConnection, this, static_cast<void*>(wrapper));
}
mState = pqisslSam3State::WAIT_CONNECT;
break;
case(pqisslSam3State::DONE):
RS_DBG2("DONE");
if (setupSocket())
return pqiDone;
return pqiError;
/* waiting */
case(pqisslSam3State::WAIT_LOOKUP):
RS_DBG3("WAIT_LOOKUP");
break;
case(pqisslSam3State::WAIT_CONNECT):
RS_DBG3("WAIT_CONNECT");
break;
}
return pqiWait;
}
int pqissli2psam3::net_internal_close(int fd)
{
RS_DBG4();
// sanity check
if (mConn && fd != mConn->fd) {
// this should never happen!
RS_ERR("fd != mConn");
// sam3CloseConnection(mConn);
}
// now to the actuall closing
int ret = pqissl::net_internal_close(fd);
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::closeConnection, this, mConn);
// finally cleanup
mConn = 0;
mState = pqisslSam3State::NONE;
return ret;
}
void pqissli2psam3::taskFinished(taskTicket *&ticket)
{
RS_DBG4();
switch (ticket->task) {
case autoProxyTask::lookupKey:
{
auto addr = static_cast<i2p::address*>(ticket->data);
RS_STACK_MUTEX(mSslMtx);
if (ticket->result == autoProxyStatus::ok) {
mI2pAddrLong = addr->publicKey;
mState = pqisslSam3State::DO_CONNECT;
} else {
waiting = WAITING_FAIL_INTERFACE;
}
delete addr;
ticket->data = nullptr;
addr = nullptr;
}
break;
case autoProxyTask::establishConnection:
{
auto wrapper = static_cast<struct samEstablishConnectionWrapper*>(ticket->data);
RS_STACK_MUTEX(mSslMtx);
if (ticket->result == autoProxyStatus::ok) {
mConn = wrapper->connection;
mState = pqisslSam3State::DONE;
} else {
waiting = WAITING_FAIL_INTERFACE;
}
delete wrapper;
ticket->data = nullptr;
wrapper = nullptr;
}
break;
case autoProxyTask::closeConnection:
// nothing to do here
break;
default:
RS_WARN("unkown task", ticket->task);
}
// clean up!
delete ticket;
ticket = nullptr;
}
bool pqissli2psam3::setupSocket()
{
/*
* This function contains the generis part from pqissl::Initiate_Connection()
*/
int err;
int osock = mConn->fd;
err = unix_fcntl_nonblock(osock);
if (err < 0)
{
RS_ERR("Cannot make socket NON-Blocking:", err);
waiting = WAITING_FAIL_INTERFACE;
net_internal_close(osock);
return false;
}
#ifdef WINDOWS_SYS
/* Set TCP buffer size for Windows systems */
int sockbufsize = 0;
int size = sizeof(int);
err = getsockopt(osock, SOL_SOCKET, SO_RCVBUF, (char *)&sockbufsize, &size);
#ifdef PQISSL_DEBUG
if (err == 0) {
std::cerr << "pqissl::Initiate_Connection: Current TCP receive buffer size " << sockbufsize << std::endl;
} else {
std::cerr << "pqissl::Initiate_Connection: Error getting TCP receive buffer size. Error " << err << std::endl;
}
#endif
sockbufsize = 0;
err = getsockopt(osock, SOL_SOCKET, SO_SNDBUF, (char *)&sockbufsize, &size);
#ifdef PQISSL_DEBUG
if (err == 0) {
std::cerr << "pqissl::Initiate_Connection: Current TCP send buffer size " << sockbufsize << std::endl;
} else {
std::cerr << "pqissl::Initiate_Connection: Error getting TCP send buffer size. Error " << err << std::endl;
}
#endif
sockbufsize = WINDOWS_TCP_BUFFER_SIZE;
err = setsockopt(osock, SOL_SOCKET, SO_RCVBUF, (char *)&sockbufsize, sizeof(sockbufsize));
#ifdef PQISSL_DEBUG
if (err == 0) {
std::cerr << "pqissl::Initiate_Connection: TCP receive buffer size set to " << sockbufsize << std::endl;
} else {
std::cerr << "pqissl::Initiate_Connection: Error setting TCP receive buffer size. Error " << err << std::endl;
}
#endif
err = setsockopt(osock, SOL_SOCKET, SO_SNDBUF, (char *)&sockbufsize, sizeof(sockbufsize));
#ifdef PQISSL_DEBUG
if (err == 0) {
std::cerr << "pqissl::Initiate_Connection: TCP send buffer size set to " << sockbufsize << std::endl;
} else {
std::cerr << "pqissl::Initiate_Connection: Error setting TCP send buffer size. Error " << err << std::endl;
}
#endif
#endif // WINDOWS_SYS
mTimeoutTS = time(NULL) + mConnectTimeout;
//std::cerr << "Setting Connect Timeout " << mConnectTimeout << " Seconds into Future " << std::endl;
waiting = WAITING_SOCK_CONNECT;
sockfd = osock;
return true;
}

View File

@ -0,0 +1,47 @@
#ifndef PQISSLI2PSAM3_H
#define PQISSLI2PSAM3_H
#include "pqi/pqissl.h"
#include "services/autoproxy/rsautoproxymonitor.h"
#include "services/autoproxy/p3i2psam3.h"
// Use a state machine as the whole pqi code is designed around them and some operation (like lookup) might be blocking
enum class pqisslSam3State : uint8_t {
NONE = 0,
DO_LOOKUP,
WAIT_LOOKUP,
DO_CONNECT,
WAIT_CONNECT,
DONE
};
class pqissli2psam3 : public pqissl, public autoProxyCallback
{
public:
pqissli2psam3(pqissllistener *l, PQInterface *parent, p3LinkMgr *lm);
// NetInterface interface
public:
bool connect_parameter(uint32_t type, const std::string &value);
// pqissl interface
protected:
int Initiate_Connection();
int net_internal_close(int fd);
// autoProxyCallback interface
public:
void taskFinished(taskTicket *&ticket);
private:
bool setupSocket();
private:
pqisslSam3State mState;
std::string mI2pAddrB32;
std::string mI2pAddrLong;
Sam3Connection *mConn;
};
#endif // PQISSLI2PSAM3_H

View File

@ -186,8 +186,8 @@ public:
virtual int finaliseConnection(int fd, SSL *ssl, const RsPeerId& peerId, virtual int finaliseConnection(int fd, SSL *ssl, const RsPeerId& peerId,
const sockaddr_storage &raddr); const sockaddr_storage &raddr);
RS_SET_CONTEXT_DEBUG_LEVEL(2)
private: private:
std::map<RsPeerId, pqissl*> listenaddr; std::map<RsPeerId, pqissl*> listenaddr;
RS_SET_CONTEXT_DEBUG_LEVEL(2)
}; };

View File

@ -46,7 +46,7 @@ static struct RsLog::logInfo pqipersongrpzoneInfo = {RsLog::Default, "pqipersong
#endif #endif
#include "pqi/pqisslproxy.h" #include "pqi/pqisslproxy.h"
#include "pqi/pqissli2pbob.h" #include "pqi/pqissli2psam3.h"
pqilistener * pqisslpersongrp::locked_createListener(const struct sockaddr_storage &laddr) pqilistener * pqisslpersongrp::locked_createListener(const struct sockaddr_storage &laddr)
{ {
@ -74,26 +74,26 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
// Use pqicI2PBOB for I2P // Use pqicI2P for I2P
pqiconnect *pqicSOCKSProxy, *pqicI2PBOB; pqiconnect *pqicSOCKSProxy, *pqicI2P;
{ {
pqisslproxy *pqis = new pqisslproxy((pqissllistener *) listener, pqip, mLinkMgr); pqisslproxy *pqis = new pqisslproxy((pqissllistener *) listener, pqip, mLinkMgr);
RsSerialiser *rss = new RsSerialiser(); RsSerialiser *rss = new RsSerialiser();
rss->addSerialType(new RsRawSerialiser()); rss->addSerialType(new RsRawSerialiser());
pqicSOCKSProxy = new pqiconnect(pqip, rss, pqis); pqicSOCKSProxy = new pqiconnect(pqip, rss, pqis);
} }
if (rsAutoProxyMonitor::instance()->isEnabled(autoProxyType::I2PBOB))
if (rsAutoProxyMonitor::instance()->isEnabled(autoProxyType::I2PSAM3))
{ {
pqissli2pbob *pqis = new pqissli2pbob((pqissllistener *) listener, pqip, mLinkMgr); pqissli2psam3 *pqis = new pqissli2psam3((pqissllistener *) listener, pqip, mLinkMgr);
RsSerialiser *rss = new RsSerialiser(); RsSerialiser *rss = new RsSerialiser();
rss->addSerialType(new RsRawSerialiser()); rss->addSerialType(new RsRawSerialiser());
pqicI2PBOB = new pqiconnect(pqip, rss, pqis); pqicI2P = new pqiconnect(pqip, rss, pqis);
} else { } else {
pqicI2PBOB = pqicSOCKSProxy; pqicI2P = pqicSOCKSProxy;
} }
/* first select type based on peer */ /* first select type based on peer */
uint32_t typePeer = mPeerMgr->getHiddenType(id); uint32_t typePeer = mPeerMgr->getHiddenType(id);
switch (typePeer) { switch (typePeer) {
@ -101,7 +101,7 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqicSOCKSProxy); pqip -> addChildInterface(PQI_CONNECT_HIDDEN_TOR_TCP, pqicSOCKSProxy);
break; break;
case RS_HIDDEN_TYPE_I2P: case RS_HIDDEN_TYPE_I2P:
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqicI2PBOB); pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqicI2P);
break; break;
default: default:
/* peer is not a hidden one but we are */ /* peer is not a hidden one but we are */
@ -109,7 +109,7 @@ pqiperson * pqisslpersongrp::locked_createPerson(const RsPeerId& id, pqilistener
uint32_t typeOwn = mPeerMgr->getHiddenType(AuthSSL::getAuthSSL()->OwnId()); uint32_t typeOwn = mPeerMgr->getHiddenType(AuthSSL::getAuthSSL()->OwnId());
switch (typeOwn) { switch (typeOwn) {
case RS_HIDDEN_TYPE_I2P: case RS_HIDDEN_TYPE_I2P:
pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqicI2PBOB); pqip -> addChildInterface(PQI_CONNECT_HIDDEN_I2P_TCP, pqicI2P);
break; break;
default: default:
/* this case shouldn't happen! */ /* this case shouldn't happen! */

View File

@ -195,7 +195,7 @@ public:
/* /*
* Setup Hidden Location; * Setup Hidden Location;
*/ */
static void SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useBob); static void SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useI2p);
static bool LoadPassword(const std::string& passwd) ; static bool LoadPassword(const std::string& passwd) ;

View File

@ -43,7 +43,7 @@
class p3heartbeat; class p3heartbeat;
class p3discovery2; class p3discovery2;
class p3I2pBob; class p3I2pSam3;
/* GXS Classes - just declare the classes. /* GXS Classes - just declare the classes.
so we don't have to totally recompile to switch */ so we don't have to totally recompile to switch */
@ -161,8 +161,8 @@ public:
p3ChatService *chatSrv; p3ChatService *chatSrv;
p3StatusService *mStatusSrv; p3StatusService *mStatusSrv;
p3GxsTunnelService *mGxsTunnels; p3GxsTunnelService *mGxsTunnels;
#ifdef RS_USE_I2P_BOB #ifdef RS_USE_I2P_SAM3
p3I2pBob *mI2pBob; p3I2pSam3 *mI2pSam3;
#endif #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

@ -170,7 +170,7 @@ struct RsInitConfig
std::string hiddenNodeAddress; std::string hiddenNodeAddress;
uint16_t hiddenNodePort; uint16_t hiddenNodePort;
bool hiddenNodeI2PBOB; bool hiddenNodeI2P;
/* Logging */ /* Logging */
bool haveLogFile; bool haveLogFile;
@ -664,13 +664,13 @@ void RsInit::setAutoLogin(bool autoLogin){
} }
/* Setup Hidden Location; */ /* Setup Hidden Location; */
void RsInit::SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useBob) void RsInit::SetHiddenLocation(const std::string& hiddenaddress, uint16_t port, bool useI2p)
{ {
/* parse the bugger (todo) */ /* parse the bugger (todo) */
rsInitConfig->hiddenNodeSet = true; rsInitConfig->hiddenNodeSet = true;
rsInitConfig->hiddenNodeAddress = hiddenaddress; rsInitConfig->hiddenNodeAddress = hiddenaddress;
rsInitConfig->hiddenNodePort = port; rsInitConfig->hiddenNodePort = port;
rsInitConfig->hiddenNodeI2PBOB = useBob; rsInitConfig->hiddenNodeI2P = useI2p;
} }
@ -717,7 +717,7 @@ RsGRouter *rsGRouter = NULL ;
# include "rs_upnp/upnphandler_miniupnp.h" # include "rs_upnp/upnphandler_miniupnp.h"
#endif // def RS_USE_LIBUPNP #endif // def RS_USE_LIBUPNP
#include "services/autoproxy/p3i2pbob.h" #include "services/autoproxy/p3i2psam3.h"
#include "services/autoproxy/rsautoproxymonitor.h" #include "services/autoproxy/rsautoproxymonitor.h"
#include "services/p3gxsreputation.h" #include "services/p3gxsreputation.h"
@ -923,9 +923,9 @@ int RsServer::StartupRetroShare()
mNetMgr->setManagers(mPeerMgr, mLinkMgr); mNetMgr->setManagers(mPeerMgr, mLinkMgr);
rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance(); rsAutoProxyMonitor *autoProxy = rsAutoProxyMonitor::instance();
#ifdef RS_USE_I2P_BOB #ifdef RS_USE_I2P_SAM3
mI2pBob = new p3I2pBob(mPeerMgr); mI2pSam3 = new p3I2pSam3(mPeerMgr);
autoProxy->addProxy(autoProxyType::I2PBOB, mI2pBob); autoProxy->addProxy(autoProxyType::I2PSAM3, mI2pSam3);
#endif #endif
//load all the SSL certs as friends //load all the SSL certs as friends
@ -1655,8 +1655,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 #ifdef RS_USE_I2P_SAM3
mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pBob); // to make migration easiert, SAM will use BOBs configuration, as they are compatible / the same.
mConfigMgr->addConfiguration("I2PBOB.cfg", mI2pSam3);
#endif #endif
mPluginsManager->addConfigurations(mConfigMgr) ; mPluginsManager->addConfigurations(mConfigMgr) ;
@ -1709,34 +1710,33 @@ int RsServer::StartupRetroShare()
{ {
std::cout << "RsServer::StartupRetroShare setting up hidden locations" << std::endl; std::cout << "RsServer::StartupRetroShare setting up hidden locations" << std::endl;
if (rsInitConfig->hiddenNodeI2PBOB) { if (rsInitConfig->hiddenNodeI2P) {
std::cout << "RsServer::StartupRetroShare setting up BOB" << std::endl; std::cout << "RsServer::StartupRetroShare setting up SAMv3" << std::endl;
// we need a local port! // we need a local port!
mNetMgr->checkNetAddress(); mNetMgr->checkNetAddress();
// add i2p proxy // add i2p proxy
// bob will use this address
sockaddr_storage i2pInstance; sockaddr_storage i2pInstance;
sockaddr_storage_ipv4_aton(i2pInstance, rsInitConfig->hiddenNodeAddress.c_str()); sockaddr_storage_ipv4_aton(i2pInstance, rsInitConfig->hiddenNodeAddress.c_str());
mPeerMgr->setProxyServerAddress(RS_HIDDEN_TYPE_I2P, i2pInstance); mPeerMgr->setProxyServerAddress(RS_HIDDEN_TYPE_I2P, i2pInstance);
std::string addr; // will be set by auto proxy service std::string addr; // will be set by auto proxy service
uint16_t port = rsInitConfig->hiddenNodePort; // unused by bob uint16_t port; // unused by SAM
bool r = autoProxy->initialSetup(autoProxyType::I2PBOB, addr, port); bool r = autoProxy->initialSetup(autoProxyType::I2PSAM3, addr, port);
if (r && !addr.empty()) { if (r && !addr.empty()) {
mPeerMgr->setupHiddenNode(addr, port); mPeerMgr->setupHiddenNode(addr, port);
// now enable bob // now enable SAM
bobSettings bs; samSettings ss;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &bs); autoProxy->taskSync(autoProxyType::I2PSAM3, autoProxyTask::getSettings, &ss);
bs.enable = true; ss.enable = true;
autoProxy->taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &bs); autoProxy->taskSync(autoProxyType::I2PSAM3, autoProxyTask::setSettings, &ss);
} else { } else {
std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl; std::cerr << "RsServer::StartupRetroShare failed to receive keys" << std::endl;
/// TODO add notify for failed bob setup /// TODO add notify for failed i2p setup
} }
} else { } else {
mPeerMgr->setupHiddenNode(rsInitConfig->hiddenNodeAddress, rsInitConfig->hiddenNodePort); mPeerMgr->setupHiddenNode(rsInitConfig->hiddenNodeAddress, rsInitConfig->hiddenNodePort);
@ -1758,19 +1758,17 @@ int RsServer::StartupRetroShare()
if (rsInitConfig->hiddenNodeSet) { if (rsInitConfig->hiddenNodeSet) {
// newly created location // newly created location
// mNetMgr->checkNetAddress() will setup ports for us // mNetMgr->checkNetAddress() will setup ports for us
#if 0 // this was used for BOB but is not requires for SAMv3
// trigger updates for auto proxy services // trigger updates for auto proxy services
std::vector<autoProxyType::autoProxyType_enum> types; std::vector<autoProxyType::autoProxyType_enum> types;
// i2p bob need to rebuild its command map
types.push_back(autoProxyType::I2PBOB);
rsAutoProxyMonitor::taskSync(types, autoProxyTask::reloadConfig); rsAutoProxyMonitor::taskSync(types, autoProxyTask::reloadConfig);
#endif
} }
/**************************************************************************/ /**************************************************************************/
/* startup (stuff dependent on Ids/peers is after this point) */ /* startup (stuff dependent on Ids/peers is after this point) */
/**************************************************************************/ /**************************************************************************/
autoProxy->startAll(); autoProxy->startAll();
pqih->init_listener(); pqih->init_listener();
@ -1803,8 +1801,8 @@ int RsServer::StartupRetroShare()
/**************************************************************************/ /**************************************************************************/
// auto proxy threads // auto proxy threads
#ifdef RS_USE_I2P_BOB #ifdef RS_USE_I2P_SAM3
startServiceThread(mI2pBob, "I2P-BOB"); startServiceThread(mI2pSam3, "I2P-SAM3");
#endif #endif
#ifdef RS_ENABLE_GXS #ifdef RS_ENABLE_GXS

File diff suppressed because it is too large Load Diff

View File

@ -1,256 +0,0 @@
/*******************************************************************************
* libretroshare/src/services/autoproxy: p3i2pbob.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2016 by Sehraf *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifndef P3I2PBOB_H
#define P3I2PBOB_H
#include <map>
#include <queue>
#include <sys/types.h>
#include "util/rstime.h"
#ifndef WINDOWS_SYS
#include <sys/socket.h>
#endif
#include "pqi/p3cfgmgr.h"
#include "services/autoproxy/rsautoproxymonitor.h"
#include "util/rsthreads.h"
#include "util/i2pcommon.h"
/*
* This class implements I2P BOB (BASIC OPEN BRIDGE) communication to allow RS
* to automatically remote control I2P to setup the needed tunnel.
* BOB is a simple text-based interface: https://geti2p.net/en/docs/api/bob
*
* Note 1:
* One tunnel is enough even for hidden locations since it can be used
* bidirectional. (In contrast to what RS I2P users had to set up manually.)
*
* Note 2:
* BOB tunnels are no SOCKS tunnel. Therefore pqissli2pbob implements a simplified
* proxy specially for BOB tunnels.
*
* Note 3:
* BOB needs a unique name as an ID for each tunnel.
* We use 'RetroShare-' + 8 random base32 characters.
*
* Design:
* The service uses three state machines to manage its task:
* int stateMachineBOB();
* mBOBState
* int stateMachineController();
* mState
* mTask
*
* stateMachineBOB:
* This state machine manages the low level communication with BOB. It basically has a linked
* list (currently a implemented as a std::map) that contains a command and the next
* state.
* Each high level operation (start up / shut down / get keys) is represented by a
* chain of states. E.g. the chain to retrieve new keys:
* mCommands[bobState::setnickN] = {setnick, bobState::newkeysN};
* mCommands[bobState::newkeysN] = {newkeys, bobState::getkeys};
* mCommands[bobState::getkeys] = {getkeys, bobState::clear};
* mCommands[bobState::clear] = {clear, bobState::quit};
* mCommands[bobState::quit] = {quit, bobState::cleared};
*
* stateMachineController:
* This state machine manages the high level tasks.
* It is controlled by mState and mTask.
*
* mTast:
* Tracks the high level operation (like start up).
* It will keep its value even when a task is done to track
* the requested BOB state.
* When other operations are performed like a conection check
* the last task gets backed up and is later restored again
*
* mState:
* This state lives only for one operation an manages the communication
* with the BOB instance. This is basically connecting, starting BOB
* protocol and disconnecting
*
* How a task looks like:
* 1) RS sets task using the ticket system
* 2) stateMachineController connects to BOBs control port, sets mBobState to a lists head
* 3) stateMachineBOB processes command chain
* 4) stateMachineBOB is done and sets mBobState to cleared signaling that the connection
* is cleared and can be closed
* 5) stateMachineController disconnects from BOBs control port and updates mState
*/
///
/// \brief The controllerState enum
/// States for the controller to keep track of what he is currently doing
enum controllerState {
csIdel,
csDoConnect,
csConnected,
csWaitForBob,
csDoDisconnect,
csDisconnected,
csError
};
///
/// \brief The controllerTask enum
/// This state tracks the controllers tast (e.g. setup a BOB tunnel or shut down
/// an existing one).
enum controllerTask {
ctIdle,
ctRunSetUp,
ctRunShutDown,
ctRunGetKeys,
ctRunCheck
};
///
/// \brief The bobState enum
/// One state for each message
///
enum bobState {
bsCleared,
bsSetnickC, // chain head for only client tunnel
bsSetnickN, // chain head for getting new (server) keys
bsSetnickS, // chain head for client and server tunnel
bsGetnick,
bsNewkeysC, // part of chain for only client tunnel
bsNewkeysN, // part of chain for getting new (server) keys
bsGetkeys,
bsSetkeys,
bsInhost,
bsOuthost,
bsInport,
bsOutport,
bsInlength,
bsOutlength,
bsInvariance,
bsOutvariance,
bsInquantity,
bsOutquantity,
bsQuiet,
bsStart,
bsStop,
bsClear,
bsList, // chain head for 'list' command
bsQuit
};
///
/// \brief The bobStateInfo struct
/// State machine with commands
/// \todo This could be replaced by a linked list instead of a map
struct bobStateInfo {
std::string command;
bobState nextState;
};
struct bobSettings : i2p::settings {};
///
/// \brief The bobStates struct
/// This container struct is used to pass all states.
/// Additionally, the tunnel name is included to to show it in the GUI.
/// The advantage of a struct is that it can be forward declared.
struct bobStates {
bobState bs;
controllerState cs;
controllerTask ct;
std::string tunnelName;
};
class p3PeerMgr;
class p3I2pBob : public RsTickingThread, public p3Config, public autoProxyService
{
public:
explicit p3I2pBob(p3PeerMgr *peerMgr);
// autoProxyService interface
public:
bool isEnabled();
bool initialSetup(std::string &addr, uint16_t &);
void processTaskAsync(taskTicket *ticket);
void processTaskSync(taskTicket *ticket);
void threadTick() override; /// @see RsTickingThread
private:
int stateMachineBOB();
int stateMachineBOB_locked_failure(const std::string &answer, const bobStateInfo &currentState);
int stateMachineController();
int stateMachineController_locked_idle();
int stateMachineController_locked_connected();
int stateMachineController_locked_disconnected();
int stateMachineController_locked_error();
// p3Config interface
protected:
RsSerialiser *setupSerialiser();
bool saveList(bool &cleanup, std::list<RsItem *> &lst);
bool loadList(std::list<RsItem *> &load);
private:
// helpers
void getBOBSettings(bobSettings *settings);
void setBOBSettings(const bobSettings *settings);
void getStates(bobStates *bs);
std::string executeCommand(const std::string &command);
bool connectI2P();
bool disconnectI2P();
void finalizeSettings_locked();
void updateSettings_locked();
std::string recv();
// states for state machines
controllerState mState;
controllerTask mTask;
// used to store old state when in error state
// mStateOld is also used as a flag when an error occured in BOB protocol
controllerState mStateOld;
// mTaskOld is used to keep the previous task (start up / shut down) when requesting keys or checking the connection
controllerTask mTaskOld;
bobSettings mSetting;
bobState mBOBState;
// used variables
p3PeerMgr *mPeerMgr;
bool mConfigLoaded;
int mSocket;
rstime_t mLastProxyCheck;
sockaddr_storage mI2PProxyAddr;
std::map<bobState, bobStateInfo> mCommands;
std::string mErrorMsg;
std::string mTunnelName;
std::queue<taskTicket *> mPending;
taskTicket *mProcessing;
// mutex
RsMutex mLock;
};
#endif // P3I2PBOB_H

View File

@ -0,0 +1,798 @@
#include "p3i2psam3.h"
#include <libsam3.h>
#include "pqi/p3peermgr.h"
#include "rsitems/rsconfigitems.h"
static const std::string kConfigKeySAM3Enable = "SAM3_ENABLE";
static const std::string kConfigKeyDestPriv = "DEST_PRIV";
static const std::string kConfigKeyInLength = "IN_LENGTH";
static const std::string kConfigKeyInQuantity = "IN_QUANTITY";
static const std::string kConfigKeyInVariance = "IN_VARIANCE";
static const std::string kConfigKeyInBackupQuantity = "IN_BACKUPQUANTITY";
static const std::string kConfigKeyOutLength = "OUT_LENGTH";
static const std::string kConfigKeyOutQuantity = "OUT_QUANTITY";
static const std::string kConfigKeyOutVariance = "OUT_VARIANCE";
static const std::string kConfigKeyOutBackupQuantity = "OUT_BACKUPQUANTITY";
#ifdef RS_I2P_SAM3_BOB_COMPAT
// used for migration from BOB to SAM
static const std::string kConfigKeyBOBEnable = "BOB_ENABLE";
static const std::string kConfigKeyBOBKey = "BOB_KEY";
static const std::string kConfigKeyBOBAddr = "BOB_ADDR";
#endif
static constexpr bool kDefaultSAM3Enable = false;
RS_SET_CONTEXT_DEBUG_LEVEL(2)
static void inline doSleep(std::chrono::duration<long, std::ratio<1,1000>> timeToSleepMS) {
std::this_thread::sleep_for(timeToSleepMS);
}
p3I2pSam3::p3I2pSam3(p3PeerMgr *peerMgr) :
mConfigLoaded(false), mPeerMgr(peerMgr), mPending(), mLock("p3i2p-sam3")
#ifdef RS_USE_I2P_SAM3_LIBSAM3
, mLockSam3Access("p3i2p-sam3-access")
#endif
{
RS_DBG4();
// set defaults
mSetting.initDefault();
mSetting.enable = kDefaultSAM3Enable;
mSetting.session = nullptr;
libsam3_debug = 0;
}
bool p3I2pSam3::isEnabled()
{
RS_STACK_MUTEX(mLock);
return mSetting.enable;
}
bool p3I2pSam3::initialSetup(std::string &addr, uint16_t &/*port*/)
{
RS_DBG4();
RS_STACK_MUTEX(mLock);
if (!mSetting.address.publicKey.empty() || !mSetting.address.privateKey.empty())
RS_WARN("overwriting keys!");
bool success = generateKey(mSetting.address.publicKey, mSetting.address.privateKey);
if (!success) {
RS_WARN("failed to retrieve keys");
return false;
} else {
std::string s, c;
i2p::getKeyTypes(mSetting.address.publicKey, s, c);
RS_INFO("received key ", s, " ", c);
RS_INFO("public key: ", mSetting.address.publicKey);
RS_INFO("private key: ", mSetting.address.privateKey);
RS_INFO("address: ", i2p::keyToBase32Addr(mSetting.address.publicKey));
// sanity check
auto pub = i2p::publicKeyFromPrivate(mSetting.address.privateKey);
RS_INFO("pub key derived: ", pub);
RS_INFO("address: ", i2p::keyToBase32Addr(pub));
if (pub != mSetting.address.publicKey) {
RS_WARN("public key does not match private key! fixing ...");
mSetting.address.publicKey = pub;
}
mSetting.address.base32 = i2p::keyToBase32Addr(mSetting.address.publicKey);
IndicateConfigChanged();
}
addr = mSetting.address.base32;
return true;
}
void p3I2pSam3::processTaskAsync(taskTicket *ticket)
{
RS_DBG4();
switch (ticket->task) {
case autoProxyTask::stop: [[fallthrough]];
case autoProxyTask::start: [[fallthrough]];
case autoProxyTask::receiveKey: [[fallthrough]];
case autoProxyTask::lookupKey: [[fallthrough]];
case autoProxyTask::proxyStatusCheck: [[fallthrough]];
case autoProxyTask::establishConnection: [[fallthrough]];
case autoProxyTask::closeConnection:
{
RS_STACK_MUTEX(mLock);
mPending.push(ticket);
}
break;
case autoProxyTask::status: [[fallthrough]];
case autoProxyTask::getSettings: [[fallthrough]];
case autoProxyTask::setSettings: [[fallthrough]];
case autoProxyTask::getErrorInfo: [[fallthrough]];
case autoProxyTask::reloadConfig:
// These are supposed to be sync!
RS_DBG("unknown task or sync one!");
rsAutoProxyMonitor::taskError(ticket);
break;
}
}
void p3I2pSam3::processTaskSync(taskTicket *ticket)
{
// RS_DBG4();
const bool data = !!ticket->data;
switch (ticket->task) {
case autoProxyTask::status:
{
samStatus *ss = static_cast<struct samStatus *>(ticket->data);
RS_STACK_MUTEX(mLock);
ss->state = mState;
if (mSetting.session)
ss->sessionName = mSetting.session->channel;
else
ss->sessionName = "none";
}
rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok);
break;
case autoProxyTask::getSettings:
// check if everything needed is set
if (!data) {
RS_DBG("autoProxyTask::getSettings data is missing");
rsAutoProxyMonitor::taskError(ticket);
break;
}
// get settings
{
RS_STACK_MUTEX(mLock);
*static_cast<struct samSettings *>(ticket->data) = mSetting;
}
// finish task
rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok);
break;
case autoProxyTask::setSettings:
// check if everything needed is set
if (!data) {
RS_DBG("autoProxyTask::setSettings data is missing");
rsAutoProxyMonitor::taskError(ticket);
break;
}
// set settings
{
RS_STACK_MUTEX(mLock);
mSetting = *static_cast<struct samSettings *>(ticket->data);
updateSettings_locked();
}
// finish task
rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok);
break;
case autoProxyTask::getErrorInfo:
*static_cast<std::string *>(ticket->data) = mSetting.session->error;
rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok);
break;
case autoProxyTask::reloadConfig:
{
RS_STACK_MUTEX(mLock);
updateSettings_locked();
}
rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok);
break;
case autoProxyTask::stop:
#if 0 // doesn't seem to work, socket stays "CLOSE_WAIT"
// there can be a case where libsam3 will block forever because for some reason it does not detect that the socket it has is dead
// as a workaroung kill it from here
if (mState == samStatus::samState::connectSession || mState == samStatus::samState::connectForward) {
// lock should be held by the main thread
if (!mTmpSession) {
// now it's getting weird
RS_WARN("session is nullptr but mState says it is connecting.");
// no break! just ignore for now ...
} else {
// just close it from here, libsam3 is not thread safe.
// a bit of a hack but should do the trick
// sam3CloseSession(mSetting.session);
sam3tcpDisconnect(mTmpSession->fd);
// no break! continue as usual to keep everything in line
}
}
#endif
[[fallthrough]];
case autoProxyTask::start: [[fallthrough]];
case autoProxyTask::receiveKey: [[fallthrough]];
case autoProxyTask::lookupKey: [[fallthrough]];
case autoProxyTask::proxyStatusCheck: [[fallthrough]];
case autoProxyTask::establishConnection: [[fallthrough]];
case autoProxyTask::closeConnection:
// These are supposed to be async!
RS_WARN("unknown task or async one!");
rsAutoProxyMonitor::taskError(ticket);
break;
}
}
void p3I2pSam3::threadTick()
{
// {
// RS_STACK_MUTEX(mLock);
// Dbg4() << __PRETTY_FUNCTION__ << " mPending: " << mPending.size() << std::endl;
// }
if(mPending.empty()) {
// sleep outisde of lock!
doSleep(std::chrono::milliseconds(250));
return;
}
// get task
taskTicket *tt = nullptr;
{
RS_STACK_MUTEX(mLock);
tt = mPending.front();
mPending.pop();
}
switch (tt->task) {
case autoProxyTask::stop:
mState = samStatus::samState::offline;
stopForwarding();
stopSession();
rsAutoProxyMonitor::taskDone(tt, autoProxyStatus::offline);
break;
case autoProxyTask::start:
{
if (!mSetting.enable) {
rsAutoProxyMonitor::taskDone(tt, autoProxyStatus::disabled);
break;
}
// create main session
mState = samStatus::samState::connectSession;
bool ret = startSession();
if (!ret) {
mState = samStatus::samState::offline;
rsAutoProxyMonitor::taskError(tt);
break;
}
// start forwarding
mState = samStatus::samState::connectForward;
ret = startForwarding();
// finish ticket
if (ret) {
mState = samStatus::samState::online;
rsAutoProxyMonitor::taskDone(tt, autoProxyStatus::online);
} else {
mState = samStatus::samState::offline;
rsAutoProxyMonitor::taskError(tt);
}
}
break;
case autoProxyTask::receiveKey:
{
i2p::address *addr = static_cast<i2p::address *>(tt->data);
if (generateKey(addr->publicKey, addr->privateKey)) {
addr->base32 = i2p::keyToBase32Addr(addr->publicKey);
rsAutoProxyMonitor::taskDone(tt, autoProxyStatus::ok);
} else {
rsAutoProxyMonitor::taskError(tt);
}
}
break;
case autoProxyTask::lookupKey:
lookupKey(tt);
break;
case autoProxyTask::proxyStatusCheck:
{
// TODO better detection of status
bool ok;
ok = !!mSetting.session->fd;
ok &= !!mSetting.session->fwd_fd;
*static_cast<bool*>(tt->data) = ok;
rsAutoProxyMonitor::taskDone(tt, ok ? autoProxyStatus::ok : autoProxyStatus::error);
}
break;
case autoProxyTask::establishConnection:
establishConnection(tt);
break;
case autoProxyTask::closeConnection:
closeConnection(tt);
break;
case autoProxyTask::status: [[fallthrough]];
case autoProxyTask::getSettings: [[fallthrough]];
case autoProxyTask::setSettings: [[fallthrough]];
case autoProxyTask::getErrorInfo: [[fallthrough]];
case autoProxyTask::reloadConfig:
RS_ERR("unable to handle! This is a bug! task:", tt->task);
rsAutoProxyMonitor::taskError(tt);
break;
}
tt = nullptr;
// give i2p backend some time
doSleep(std::chrono::milliseconds(100));
}
RsSerialiser *p3I2pSam3::setupSerialiser()
{
RsSerialiser* rsSerialiser = new RsSerialiser();
rsSerialiser->addSerialType(new RsGeneralConfigSerialiser());
return rsSerialiser;
}
#define addKVS(_key, _value) \
kv.key = _key;\
kv.value = _value;\
vitem->tlvkvs.pairs.push_back(kv);
#define addKVSInt(_key, _value) \
kv.key = _key;\
rs_sprintf(kv.value, "%d", _value);\
vitem->tlvkvs.pairs.push_back(kv);
bool p3I2pSam3::saveList(bool &cleanup, std::list<RsItem *> &lst)
{
RS_DBG4();
cleanup = true;
RsConfigKeyValueSet *vitem = new RsConfigKeyValueSet;
RsTlvKeyValue kv;
RS_STACK_MUTEX(mLock);
addKVS(kConfigKeySAM3Enable, mSetting.enable ? "TRUE" : "FALSE")
addKVS(kConfigKeyDestPriv, mSetting.address.privateKey);
addKVSInt(kConfigKeyInLength, mSetting.inLength)
addKVSInt(kConfigKeyInQuantity, mSetting.inQuantity)
addKVSInt(kConfigKeyInVariance, mSetting.inVariance)
addKVSInt(kConfigKeyInBackupQuantity, mSetting.inBackupQuantity)
addKVSInt(kConfigKeyOutLength, mSetting.outLength)
addKVSInt(kConfigKeyOutQuantity, mSetting.outQuantity)
addKVSInt(kConfigKeyOutVariance, mSetting.outVariance)
addKVSInt(kConfigKeyOutBackupQuantity, mSetting.outBackupQuantity)
#ifdef RS_I2P_SAM3_BOB_COMPAT
// these allow SAMv3 users to switch back to BOB
// remove after some time
addKVS(kConfigKeyBOBEnable, mSetting.enable ? "TRUE" : "FALSE")
addKVS(kConfigKeyBOBKey, mSetting.address.privateKey)
addKVS(kConfigKeyBOBAddr, mSetting.address.base32)
#endif
lst.push_back(vitem);
return true;
}
#undef addKVS
#undef addKVSUInt
#define getKVSUInt(_kit, _key, _value) \
else if (_kit->key == _key) {\
std::istringstream is(_kit->value);\
int tmp;\
is >> tmp;\
_value = (int8_t)tmp;\
}
bool p3I2pSam3::loadList(std::list<RsItem *> &load)
{
RS_DBG4();
std::string priv;
priv.clear();
for(std::list<RsItem*>::const_iterator it = load.begin(); it!=load.end(); ++it) {
RsConfigKeyValueSet *vitem = dynamic_cast<RsConfigKeyValueSet*>(*it);
if(vitem != NULL) {
RS_STACK_MUTEX(mLock);
for(std::list<RsTlvKeyValue>::const_iterator kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit) {
if (kit->key == kConfigKeySAM3Enable)
mSetting.enable = kit->value == "TRUE";
else if (kit->key == kConfigKeyDestPriv)
priv = kit->value;
getKVSUInt(kit, kConfigKeyInLength, mSetting.inLength)
getKVSUInt(kit, kConfigKeyInQuantity, mSetting.inQuantity)
getKVSUInt(kit, kConfigKeyInVariance, mSetting.inVariance)
getKVSUInt(kit, kConfigKeyInBackupQuantity, mSetting.inBackupQuantity)
getKVSUInt(kit, kConfigKeyOutLength, mSetting.outLength)
getKVSUInt(kit, kConfigKeyOutQuantity, mSetting.outQuantity)
getKVSUInt(kit, kConfigKeyOutVariance, mSetting.outVariance)
getKVSUInt(kit, kConfigKeyOutBackupQuantity, mSetting.outBackupQuantity)
#ifdef RS_I2P_SAM3_BOB_COMPAT
// import BOB settings
else if (kit->key == kConfigKeyBOBEnable)
mSetting.enable = kit->value == "TRUE";
else if (kit->key == kConfigKeyBOBKey) {
// don't overwirte, just import when not set already!
if (priv.empty())
priv = kit->value;
}
#endif
else
RS_INFO("unknown key:", kit->key);
}
}
delete vitem;
}
// get the pub key
std::string pub = i2p::publicKeyFromPrivate(priv);
if (pub.empty() || priv.empty())
RS_DBG("no destination to load");
else {
RS_STACK_MUTEX(mLock);
mSetting.address.publicKey = pub;
mSetting.address.privateKey = priv;
mSetting.address.base32 = i2p::keyToBase32Addr(pub);
}
RS_STACK_MUTEX(mLock);
mConfigLoaded = true;
return true;
}
#undef getKVSUInt
bool p3I2pSam3::startSession()
{
RS_DBG4();
constexpr size_t len = 8;
const std::string location = RsRandom::alphaNumeric(len);
const std::string nick = "RetroShare-" + location;
std::vector<std::string> params;
{
RS_STACK_MUTEX(mLock);
// length
params.push_back(i2p::makeOption("inbound.length", mSetting.inLength));
params.push_back(i2p::makeOption("outbound.length", mSetting.outLength));
// variance
params.push_back(i2p::makeOption("inbound.lengthVariance", + mSetting.inVariance));
params.push_back(i2p::makeOption("outbound.lengthVariance", + mSetting.outVariance));
// quantity
params.push_back(i2p::makeOption("inbound.quantity", + mSetting.inQuantity));
params.push_back(i2p::makeOption("outbound.quantity", + mSetting.outQuantity));
// backup quantity
params.push_back(i2p::makeOption("inbound.backupQuantity", + mSetting.inBackupQuantity));
params.push_back(i2p::makeOption("outbound.backupQuantity", + mSetting.outBackupQuantity));
}
std::string paramsStr;
for (auto &&p : params)
paramsStr.append(p + " ");
// keep trailing space for easier extending when necessary
int ret;
if (mSetting.session) {
stopSession();
}
auto session = (Sam3Session*)rs_malloc(sizeof (Sam3Session));
// add nick
paramsStr.append("inbound.nickname=" + nick); // leading space is already there
{
RS_STACK_MUTEX(mLockSam3Access);
if(!mSetting.address.privateKey.empty()) {
RS_DBG3("with destination");
ret = sam3CreateSession(session, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, mSetting.address.privateKey.c_str(), Sam3SessionType::SAM3_SESSION_STREAM, Sam3SigType::EdDSA_SHA512_Ed25519, paramsStr.c_str());
} else {
RS_DBG("without destination");
ret = sam3CreateSession(session, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, SAM3_DESTINATION_TRANSIENT, Sam3SessionType::SAM3_SESSION_STREAM, Sam3SigType::EdDSA_SHA512_Ed25519, paramsStr.c_str());
}
}
if (ret != 0) {
delete session;
session = nullptr;
return false;
}
#if 0 // this check is useless. For non i2p hidden locations the public key is temporal anyway and for i2p hidden ones, it is part of the (fixed) private key.
if (!mSetting.address.publicKey.empty() && mSetting.address.publicKey != session->pubkey)
// This should be ok for non hidden locations. This should be a problem for hidden i2p locations...
RS_DBG("public key changed! Yet unsure if this is ok or a problem. Should be fine for non i2p hidden locations or clear net.");
#endif
/*
* Note: sam3CreateSession will issue a name looup of "ME" to receive its public key, thus it is always correct.
* No need to use i2p::publicKeyFromPrivate()
*/
RS_STACK_MUTEX(mLock);
mSetting.session = session;
mSetting.address.publicKey = session->pubkey;
mSetting.address.base32 = i2p::keyToBase32Addr(session->pubkey);
// do not overwrite the private key, if any!!
RS_DBG1("nick: ", nick, " address: ", mSetting.address.base32);
RS_DBG2(" myDestination.pub ", mSetting.address.publicKey);
RS_DBG2(" myDestination.priv ", mSetting.address.privateKey);
return true;
}
bool p3I2pSam3::startForwarding()
{
RS_DBG4();
if(mSetting.address.privateKey.empty()) {
RS_DBG3("no private key set");
// IMPORANT: return true here!
// since there is no forward session for non hidden nodes, this funtion is successfull by doing nothing
return true;
}
if (!mSetting.session) {
RS_WARN("no session found!");
return false;
}
peerState ps;
mPeerMgr->getOwnNetStatus(ps);
RS_STACK_MUTEX(mLockSam3Access);
mSetting.session->silent = true;
int ret = sam3StreamForward(mSetting.session, sockaddr_storage_iptostring(ps.localaddr).c_str(), sockaddr_storage_port(ps.localaddr));
if (ret < 0) {
RS_DBG("forward failed, due to", mSetting.session->error);
return false;
}
return true;
}
void p3I2pSam3::stopSession()
{
RS_DBG4();
{
RS_STACK_MUTEX(mLock);
if (!mSetting.session)
return;
// swap connections
mInvalidConnections = mValidConnections;
mValidConnections.clear();
RS_STACK_MUTEX(mLockSam3Access);
sam3CloseSession(mSetting.session);
free(mSetting.session);
mSetting.session = nullptr;
mState = samStatus::samState::offline;
}
// At least i2pd doesn't like to instantaniously stop and (re)start a session, wait here just a little bit.
// Not ideal but does the trick.
// (This happens when using the "restart" button in the settings.)
doSleep(std::chrono::seconds(10));
}
void p3I2pSam3::stopForwarding()
{
// nothing to do here, forwarding is stop when closing the seassion
}
bool p3I2pSam3::generateKey(std::string &pub, std::string &priv)
{
RS_DBG4();
pub.clear();
priv.clear();
// The session is only usef for transporting the data
Sam3Session ss;
if (0 > sam3GenerateKeys(&ss, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, Sam3SigType::EdDSA_SHA512_Ed25519)) {
RS_DBG("got error: ", ss.error);
return false;
}
pub = std::string(ss.pubkey);
priv = std::string(ss.privkey);
// sanity check
auto p = i2p::publicKeyFromPrivate(priv);
if (p != pub) {
RS_WARN("public key does not match private key! fixing ...");
pub = p;
}
RS_DBG2("publuc key / address ", pub);
RS_DBG2("private key ", priv);
return true;
}
void p3I2pSam3::lookupKey(taskTicket *ticket)
{
// this can be called independend of the main SAM session!
auto addr = static_cast<i2p::address*>(ticket->data);
if (addr->base32.empty()) {
RS_ERR("lookupKey: called with empty address");
rsAutoProxyMonitor::taskError(ticket);
return;
}
RsThread::async([ticket]()
{
auto addr = static_cast<i2p::address*>(ticket->data);
// The session is only usef for transporting the data
Sam3Session ss;
int ret = sam3NameLookup(&ss, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, addr->base32.c_str());
if (ret < 0) {
// get error
RS_DBG("key: ", addr->base32);
RS_DBG("got error: ", ss.error);
rsAutoProxyMonitor::taskError(ticket);
} else {
addr->publicKey = ss.destkey;
rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok);
RS_DBG1("success");
}
});
}
void p3I2pSam3::establishConnection(taskTicket *ticket)
{
if (mState != samStatus::samState::online || !mSetting.session) {
RS_WARN("no session found!");
rsAutoProxyMonitor::taskError(ticket);
return;
}
samEstablishConnectionWrapper *wrapper = static_cast<samEstablishConnectionWrapper*>(ticket->data);
if (wrapper->address.publicKey.empty()) {
RS_ERR("no public key given");
rsAutoProxyMonitor::taskError(ticket);
return;
}
RsThread::async([ticket, this]() {
auto wrapper = static_cast<samEstablishConnectionWrapper*>(ticket->data);
struct Sam3Connection *connection;
{
auto l = this->mLockSam3Access;
RS_STACK_MUTEX(l);
mSetting.session->silent = false;
connection = sam3StreamConnect(this->mSetting.session, wrapper->address.publicKey.c_str());
}
if (!connection) {
// get error
RS_DBG("got error:", this->mSetting.session->error);
rsAutoProxyMonitor::taskError(ticket);
} else {
wrapper->connection = connection;
{
auto l = this->mLockSam3Access;
RS_STACK_MUTEX(l);
this->mValidConnections.push_back(connection);
}
RS_DBG1("success");
rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok);
}
});
}
void p3I2pSam3::closeConnection(taskTicket *ticket)
{
Sam3Connection *conn = static_cast<Sam3Connection*>(ticket->data);
if (mState == samStatus::samState::offline || !mSetting.session) {
// no session found, sam was likely stopped
RS_DBG2("no session found");
auto it = std::find(mInvalidConnections.begin(), mInvalidConnections.end(), conn);
if (it != mInvalidConnections.end()) {
// this is the expected case
mInvalidConnections.erase(it);
} else {
// this is unexpected but not a big deal, just warn
RS_WARN("cannot find connection in mInvalidConnections");
it = std::find(mValidConnections.begin(), mValidConnections.end(), conn);
if (it != mValidConnections.end()) {
mValidConnections.erase(it);
// now it is getting even weirder, still not a big deal, just warn
RS_WARN("found connection in mValidConnections");
}
}
// when libsam3 has already handled closing of the connection - which should be the case here - the memory has been freed already (-> pointer is invalid)
conn = nullptr;
} else {
RS_STACK_MUTEX(mLock);
bool callClose = true;
// search in current connections
auto it = std::find(mValidConnections.begin(), mValidConnections.end(), conn);
if (it != mValidConnections.end()) {
RS_DBG2("found valid connection");
mValidConnections.erase(it);
} else {
// search in old connections
it = std::find(mInvalidConnections.begin(), mInvalidConnections.end(), conn);
if (it != mInvalidConnections.end()) {
// old connection, just ignore. *should* be freed already
mInvalidConnections.erase(it);
RS_DBG2("found old (invalid) connection");
callClose = false;
conn = nullptr;
} else {
// weird
RS_WARN("could'n find connection!");
// best thing we can do here
callClose = false;
conn = nullptr;
}
}
if (callClose) {
RS_DBG2("closing connection");
RS_STACK_MUTEX(mLockSam3Access);
sam3CloseConnection(conn);
conn = nullptr; // freed by above call
}
}
if (conn) {
free(conn);
conn = nullptr;
}
ticket->data = nullptr;
rsAutoProxyMonitor::taskDone(ticket, autoProxyStatus::ok);
return;
}
void p3I2pSam3::updateSettings_locked()
{
RS_DBG4();
IndicateConfigChanged();
#if 0 // TODO recreat session when active, can we just recreat it?
if (mSs) {
stopSession();
startSession();
}
#endif
}

View File

@ -0,0 +1,110 @@
#ifndef P3I2PSAM3_H
#define P3I2PSAM3_H
#include <queue>
#include <list>
#include "services/autoproxy/rsautoproxymonitor.h"
#include "pqi/p3cfgmgr.h"
#include "util/i2pcommon.h"
#include "util/rsthreads.h"
/*
* This class implements I2P SAMv3 (Simple Anonymous Messaging) to allow RS
* to automatically setup tunnel to and from I2P.
* SAMv3 is a simple text-based interface: https://geti2p.net/de/docs/api/samv3
*
* For the actual SAM commands / low level stuff libsam3 (https://github.com/i2p/libsam3)
* is used with some minor adjustments, for exmaple, the FORWARD session is always silent.
*
* SAM in a nutshell works like this:
* 1) setup main/control session which configures everything (destination ID, tunnel number, hops number, and so on)
* 2) setup a forward session, so that I2P will establish a connection to RS for each incoming connection to our i2p destination
* 3a) query/lookup the destination (public key) for a given i2p address
* 3b) connect to the given destination
*
* An established connection (both incoming or outgoing) are then handed over to RS.
* The lifetime of a session (and its subordinates connections) is bound to their tcp socket. When the socket closes, the session is closed, too.
*
*/
class p3PeerMgr;
class Sam3Session;
class Sam3Connection;
typedef Sam3Session samSession;
struct samSettings : i2p::settings {
samSession *session;
};
struct samEstablishConnectionWrapper {
i2p::address address;
Sam3Connection *connection;
};
struct samStatus {
std::string sessionName;
enum samState {
offline,
connectSession,
connectForward,
online
} state; // the name is kinda redundant ...
};
class p3I2pSam3 : public RsTickingThread, public p3Config, public autoProxyService
{
public:
p3I2pSam3(p3PeerMgr *peerMgr);
// autoProxyService interface
public:
bool isEnabled();
bool initialSetup(std::string &addr, uint16_t &port);
void processTaskAsync(taskTicket *ticket);
void processTaskSync(taskTicket *ticket);
// RsTickingThread interface
public:
void threadTick(); /// @see RsTickingThread
// p3Config interface
protected:
RsSerialiser *setupSerialiser();
bool saveList(bool &cleanup, std::list<RsItem *> &);
bool loadList(std::list<RsItem *> &load);
private:
bool startSession();
bool startForwarding();
void stopSession();
void stopForwarding();
bool generateKey(std::string &pub, std::string &priv);
void lookupKey(taskTicket *ticket);
void establishConnection(taskTicket *ticket);
void closeConnection(taskTicket *ticket);
void updateSettings_locked();
bool mConfigLoaded;
samSettings mSetting;
p3PeerMgr *mPeerMgr;
std::queue<taskTicket *> mPending;
// Used to report the state to the gui
// (Since the create session call/will can block and there is no easy way from outside the main thread to see
// what is going on, it is easier to store the current state in an extra variable independen from the main thread)
samStatus::samState mState;
// used to keep track of connections, libsam3 does it internally but it can be unreliable since pointers are shared
std::list<Sam3Connection *> mValidConnections, mInvalidConnections;
// mutex
RsMutex mLock;
RsMutex mLockSam3Access; // libsam3 is not thread safe! (except for key lookup)
};
#endif // P3I2PSAM3_H

View File

@ -329,14 +329,22 @@ autoProxyService *rsAutoProxyMonitor::lookUpService(autoProxyType::autoProxyType
bool rsAutoProxyMonitor::isAsyncTask(autoProxyTask::autoProxyTask_enum t) bool rsAutoProxyMonitor::isAsyncTask(autoProxyTask::autoProxyTask_enum t)
{ {
// Explicit list all values, so that missing ones will be detected by the compiler.
switch (t) { switch (t) {
case autoProxyTask::start: case autoProxyTask::start: [[fallthrough]];
case autoProxyTask::stop: case autoProxyTask::stop: [[fallthrough]];
case autoProxyTask::receiveKey: case autoProxyTask::receiveKey: [[fallthrough]];
case autoProxyTask::lookupKey: [[fallthrough]];
case autoProxyTask::establishConnection: [[fallthrough]];
case autoProxyTask::closeConnection:
return true; return true;
break; case autoProxyTask::status: [[fallthrough]];
default: case autoProxyTask::getSettings: [[fallthrough]];
break; case autoProxyTask::setSettings: [[fallthrough]];
case autoProxyTask::getErrorInfo: [[fallthrough]];
case autoProxyTask::reloadConfig: [[fallthrough]];
case autoProxyTask::proxyStatusCheck:
return false;
} }
return false; return false;
} }

View File

@ -31,7 +31,8 @@ class autoProxyCallback;
namespace autoProxyType { namespace autoProxyType {
enum autoProxyType_enum { enum autoProxyType_enum {
I2PBOB // I2PBOB,
I2PSAM3
}; };
} }
@ -41,7 +42,10 @@ namespace autoProxyTask {
start, ///< start up proxy start, ///< start up proxy
stop, ///< shut down proxy stop, ///< shut down proxy
receiveKey, ///< renew proxy key (if any) receiveKey, ///< renew proxy key (if any)
lookupKey, ///< look up a base32 addr
proxyStatusCheck, ///< use to check if the proxy is still running proxyStatusCheck, ///< use to check if the proxy is still running
establishConnection, ///< create a connection to a given public key or base32 address
closeConnection, ///< closes a connection
/* sync tasks */ /* sync tasks */
status, ///< get status from auto proxy status, ///< get status from auto proxy
getSettings, ///< get setting from auto proxy getSettings, ///< get setting from auto proxy

View File

@ -90,6 +90,15 @@ rs_broadcast_discovery {
win32-g++|win32-clang-g++:dLibs *= wsock32 win32-g++|win32-clang-g++:dLibs *= wsock32
} }
rs_sam3_libsam3 {
LIBSAM3_SRC_PATH=$$clean_path($${RS_SRC_PATH}/supportlibs/libsam3/)
LIBSAM3_BUILD_PATH=$$clean_path($${RS_BUILD_PATH}/supportlibs/libsam3/)
INCLUDEPATH *= $$clean_path($${LIBSAM3_SRC_PATH}/src/libsam3/)
DEPENDPATH *= $$clean_path($${LIBSAM3_BUILD_PATH})
QMAKE_LIBDIR *= $$clean_path($${LIBSAM3_BUILD_PATH})
LIBS *= -L$$clean_path($${LIBSAM3_BUILD_PATH}) -lsam3
}
static { static {
sLibs *= $$mLibs sLibs *= $$mLibs
} else { } else {

View File

@ -50,8 +50,10 @@ std::string publicKeyFromPrivate(std::string const &priv)
* https://geti2p.net/spec/common-structures#keysandcert * https://geti2p.net/spec/common-structures#keysandcert
* https://geti2p.net/spec/common-structures#certificate * https://geti2p.net/spec/common-structures#certificate
*/ */
if (priv.length() < 884) // base64 ( = 663 bytes = KeyCert + priv Keys) if (priv.length() < privKeyMinLenth_b64) {
RS_WARN("key to short!");
return std::string(); return std::string();
}
// creat a copy to work on, need to convert it to standard base64 // creat a copy to work on, need to convert it to standard base64
auto priv_copy(priv); auto priv_copy(priv);
@ -70,13 +72,14 @@ std::string publicKeyFromPrivate(std::string const &priv)
uint8_t certType = 0; uint8_t certType = 0;
uint16_t len = 0; uint16_t len = 0;
uint16_t signingKeyType = 0; uint16_t signingKeyType = 0;
uint16_t cryptKey = 0; uint16_t cryptKeyType = 0;
// only used for easy break // only used for easy break
do { do {
try { try {
// jump to certificate // jump to certificate
p += publicKeyLen; p += publicKeyLen;
// try to read type and length // try to read type and length
certType = *p++; certType = *p++;
len = readTwoBytesBE(p); len = readTwoBytesBE(p);
@ -87,7 +90,7 @@ std::string publicKeyFromPrivate(std::string const &priv)
/* /*
* CertType.Null * CertType.Null
* type null is followed by 0x00 0x00 <END> * type null is followed by 0x00 0x00 <END>
* so has to be 0! * so len has to be 0!
*/ */
RS_DBG("cert is CertType.Null"); RS_DBG("cert is CertType.Null");
publicKeyLen += 3; // add 0x00 0x00 0x00 publicKeyLen += 3; // add 0x00 0x00 0x00
@ -119,7 +122,7 @@ std::string publicKeyFromPrivate(std::string const &priv)
// likely 7 // likely 7
signingKeyType = readTwoBytesBE(p); signingKeyType = readTwoBytesBE(p);
RS_DBG("signing pubkey type ", certType); RS_DBG("signing pubkey type ", signingKeyType);
if (signingKeyType >= 3 && signingKeyType <= 6) { if (signingKeyType >= 3 && signingKeyType <= 6) {
RS_DBG("signing pubkey type ", certType, " has oversize"); RS_DBG("signing pubkey type ", certType, " has oversize");
// calculate oversize // calculate oversize
@ -137,18 +140,18 @@ std::string publicKeyFromPrivate(std::string const &priv)
return std::string(); return std::string();
} }
publicKeyLen += values.first - 128; // 128 = default DSA key length = the space than can be used before the key must be splitted publicKeyLen += values.first - 128; // 128 = default DSA key length = the space that can be used before the key must be splitted
} }
// Crypto Public Key // Crypto Public Key
// likely 0 // likely 0
cryptKey = readTwoBytesBE(p); cryptKeyType = readTwoBytesBE(p);
RS_DBG("crypto pubkey type ", cryptKey); RS_DBG("crypto pubkey type ", cryptKeyType);
// info: these are all smaller than the default 256 bytes, so no oversize calculation is needed // info: these are all smaller than the default 256 bytes, so no oversize calculation is needed
break; break;
} catch (const std::out_of_range &e) { } catch (const std::out_of_range &e) {
RS_DBG("hit exception! ", e.what()); RS_DBG("hit an exception! ", e.what());
return std::string(); return std::string();
} }
} while(false); } while(false);
@ -160,4 +163,107 @@ std::string publicKeyFromPrivate(std::string const &priv)
return pub; return pub;
} }
bool getKeyTypes(const std::string &key, std::string &signingKey, std::string &cryptoKey)
{
if (key.length() < pubKeyMinLenth_b64) {
RS_WARN("key to short!");
return false;
}
// creat a copy to work on, need to convert it to standard base64
auto key_copy(key);
std::replace(key_copy.begin(), key_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> data;
RsBase64::decode(key_copy, data);
auto p = data.cbegin();
constexpr size_t publicKeyLen = 256 + 128; // default length (bytes)
uint8_t certType = 0;
uint16_t signingKeyType = 0;
uint16_t cryptKeyType = 0;
// try to read types
try {
// jump to certificate
p += publicKeyLen;
// try to read type and skip length
certType = *p++;
p += 2;
// 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)) {
RS_DBG("cert is CertType.Null");
signingKey = "DSA_SHA1";
cryptoKey = "ElGamal";
return true;
}
// check for != 5
if (certType != static_cast<typename std::underlying_type<CertType>::type>(CertType::Key)) {
// unsupported
RS_DBG("cert type ", certType, " is unsupported");
return false;
}
RS_DBG("cert is CertType.Key");
// Signing Public Key
// likely 7
signingKeyType = readTwoBytesBE(p);
RS_DBG("signing pubkey type ", signingKeyType);
// Crypto Public Key
// likely 0
cryptKeyType = readTwoBytesBE(p);
RS_DBG("crypto pubkey type ", cryptKeyType);
} catch (const std::out_of_range &e) {
RS_DBG("hit an exception! ", e.what());
return false;
}
// now convert to string (this would be easier with c++17)
#define HELPER(a, b, c) \
case static_cast<typename std::underlying_type<a>::type>(a::c): \
b = #c; \
break;
switch (signingKeyType) {
HELPER(SigningKeyType, signingKey, DSA_SHA1)
HELPER(SigningKeyType, signingKey, ECDSA_SHA256_P256)
HELPER(SigningKeyType, signingKey, ECDSA_SHA384_P384)
HELPER(SigningKeyType, signingKey, ECDSA_SHA512_P521)
HELPER(SigningKeyType, signingKey, RSA_SHA256_2048)
HELPER(SigningKeyType, signingKey, RSA_SHA384_3072)
HELPER(SigningKeyType, signingKey, RSA_SHA512_4096)
HELPER(SigningKeyType, signingKey, EdDSA_SHA512_Ed25519)
HELPER(SigningKeyType, signingKey, EdDSA_SHA512_Ed25519ph)
HELPER(SigningKeyType, signingKey, RedDSA_SHA512_Ed25519)
default:
RsWarn("unkown signing key type:", signingKeyType);
return false;
}
switch (cryptKeyType) {
HELPER(CryptoKeyType, cryptoKey, ElGamal)
HELPER(CryptoKeyType, cryptoKey, P256)
HELPER(CryptoKeyType, cryptoKey, P384)
HELPER(CryptoKeyType, cryptoKey, P521)
HELPER(CryptoKeyType, cryptoKey, X25519)
default:
RsWarn("unkown crypto key type:", cryptKeyType);
return false;
}
#undef HELPER
return true;
}
} // namespace i2p } // namespace i2p

View File

@ -186,6 +186,39 @@ static const std::array<std::pair<uint16_t, uint16_t>, 12> signingKeyLengths {
/*SigningKeyType::RedDSA_SHA512_Ed25519 */ std::make_pair<uint16_t, uint16_t>( 32, 32), /*SigningKeyType::RedDSA_SHA512_Ed25519 */ std::make_pair<uint16_t, uint16_t>( 32, 32),
}; };
/*
* Key length infos:
*
* BOB private key
* len b64: 884
* len pln: 663
*
* BOB public key / destination
* len b64: 516
* len pln: 387
*
* SAMv3 private key
* len b64: 908
* len pln: 679
*
* SAMv3 public key
* len b64: 516
* len pln: 387
*
* Example:
* in bytes, public key only
* 384 (Key) + 3 (Null certificate) = 387 bytes
* 384 (Key) + 7 (key certificate) = 391 bytes
*
* in bytes public + private key
* 384 (Key) + 3 (Null certificate) + 256 (ElGamal) + 20 (DSA_SHA1) = 663 bytes
* 384 (Key) + 7 (key certificate) + 256 (ElGamal) + 32 (EdDSA_SHA512_Ed25519) = 679 bytes
*/
constexpr size_t pubKeyMinLenth_b64 = 516;
constexpr size_t pubKeyMinLenth_bin = 387;
constexpr size_t privKeyMinLenth_b64 = 884;
constexpr size_t privKeyMinLenth_bin = 663;
/** /**
* @brief makeOption Creates the string "lhs=rhs" used by BOB and SAM. Converts rhs * @brief makeOption Creates the string "lhs=rhs" used by BOB and SAM. Converts rhs
* @param lhs option to set * @param lhs option to set
@ -208,6 +241,15 @@ std::string keyToBase32Addr(const std::string &key);
*/ */
std::string publicKeyFromPrivate(const std::string &priv); std::string publicKeyFromPrivate(const std::string &priv);
/**
* @brief getKeyTypes returns the name of the utilized algorithms used by the key
* @param key public key
* @param signingKey name of the signing key, e.g. DSA_SHA1
* @param cryptoKey name of the crpyto key, e.g. ElGamal
* @return true on success, false otherwise
*/
bool getKeyTypes(const std::string &key, std::string &signingKey, std::string &cryptoKey);
} // namespace i2p } // namespace i2p
#endif // I2PCOMMON_H #endif // I2PCOMMON_H

View File

@ -150,7 +150,7 @@ GenCertDialog::GenCertDialog(bool onlyGenerateIdentity, QWidget *parent)
connect(ui.node_input, SIGNAL(textChanged(QString)), this, SLOT(updateCheckLabels())); connect(ui.node_input, SIGNAL(textChanged(QString)), this, SLOT(updateCheckLabels()));
connect(ui.reuse_existing_node_CB, SIGNAL(toggled(bool)), this, SLOT(updateCheckLabels())); connect(ui.reuse_existing_node_CB, SIGNAL(toggled(bool)), this, SLOT(updateCheckLabels()));
connect(ui.cbUseBob, SIGNAL(clicked(bool)), this, SLOT(useBobChecked(bool)));; connect(ui.cbUseBob, SIGNAL(clicked(bool)), this, SLOT(useI2pChecked(bool)));;
entropy_timer = new QTimer ; entropy_timer = new QTimer ;
entropy_timer->start(20) ; entropy_timer->start(20) ;
@ -341,9 +341,9 @@ 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 #ifndef RS_USE_I2P_SAM3
ui.cbUseBob->setDisabled(true); ui.cbUseBob->setDisabled(true);
ui.cbUseBob->setToolTip(tr("BOB support is not available")); ui.cbUseBob->setToolTip(tr("SAMv3 support is not available"));
#endif #endif
if(!mAllFieldsOk) if(!mAllFieldsOk)
@ -440,10 +440,10 @@ void GenCertDialog::updateCheckLabels()
setupState(); setupState();
} }
void GenCertDialog::useBobChecked(bool checked) void GenCertDialog::useI2pChecked(bool checked)
{ {
if (checked) { if (checked) {
ui.hiddenaddr_input->setPlaceholderText(tr("I2P instance address with BOB enabled")); ui.hiddenaddr_input->setPlaceholderText(tr("I2P instance address with SAMv3 enabled"));
ui.hiddenaddr_label->setText(tr("I2P instance address")); ui.hiddenaddr_label->setText(tr("I2P instance address"));
ui.hiddenport_spinBox->setEnabled(false); ui.hiddenport_spinBox->setEnabled(false);
@ -539,12 +539,12 @@ void GenCertDialog::genPerson()
std::string hl = ui.hiddenaddr_input->text().toStdString(); std::string hl = ui.hiddenaddr_input->text().toStdString();
uint16_t port = ui.hiddenport_spinBox->value(); uint16_t port = ui.hiddenport_spinBox->value();
bool useBob = ui.cbUseBob->isChecked(); bool useI2p = ui.cbUseBob->isChecked();
if (useBob && hl.empty()) if (useI2p && hl.empty())
hl = "127.0.0.1"; hl = "127.0.0.1";
RsInit::SetHiddenLocation(hl, port, useBob); /* parses it */ RsInit::SetHiddenLocation(hl, port, useI2p); /* parses it */
} }

View File

@ -44,7 +44,7 @@ private slots:
void switchReuseExistingNode(); void switchReuseExistingNode();
void grabMouse(); void grabMouse();
void updateCheckLabels(); void updateCheckLabels();
void useBobChecked(bool checked); void useI2pChecked(bool checked);
private: private:
void initKeyList(); void initKeyList();

View File

@ -496,7 +496,7 @@
<item> <item>
<widget class="QCheckBox" name="cbUseBob"> <widget class="QCheckBox" name="cbUseBob">
<property name="text"> <property name="text">
<string>Use BOB</string> <string>Use I2P</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -764,8 +764,8 @@
<tabstop>importIdentity_PB</tabstop> <tabstop>importIdentity_PB</tabstop>
</tabstops> </tabstops>
<resources> <resources>
<include location="icons.qrc"/>
<include location="images.qrc"/> <include location="images.qrc"/>
<include location="icons.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -47,6 +47,8 @@
#include <QTcpSocket> #include <QTcpSocket>
#include <QTimer> #include <QTimer>
#include <libsam3.h>
#define ICON_STATUS_UNKNOWN ":/images/ledoff1.png" #define ICON_STATUS_UNKNOWN ":/images/ledoff1.png"
#define ICON_STATUS_WORKING ":/images/yellowled.png" #define ICON_STATUS_WORKING ":/images/yellowled.png"
#define ICON_STATUS_OK ":/images/ledon1.png" #define ICON_STATUS_OK ":/images/ledon1.png"
@ -66,7 +68,7 @@
// Tabs numbers *after* non relevant tabs are removed. So do not use them to add/remove tabs!! // Tabs numbers *after* non relevant tabs are removed. So do not use them to add/remove tabs!!
const static uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0; const static uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0;
const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 1; const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 1;
const static uint32_t TAB_HIDDEN_SERVICE_I2P_BOB = 2; const static uint32_t TAB_HIDDEN_SERVICE_I2P = 2;
const static uint32_t TAB_NETWORK = 0; const static uint32_t TAB_NETWORK = 0;
const static uint32_t TAB_HIDDEN_SERVICE = 1; const static uint32_t TAB_HIDDEN_SERVICE = 1;
@ -79,14 +81,14 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
: ConfigPage(parent, flags) : ConfigPage(parent, flags)
, manager(NULL), mOngoingConnectivityCheck(-1) , manager(NULL), mOngoingConnectivityCheck(-1)
, mIsHiddenNode(false), mHiddenType(RS_HIDDEN_TYPE_NONE) , mIsHiddenNode(false), mHiddenType(RS_HIDDEN_TYPE_NONE)
, mBobAccessible(false) , mSamAccessible(false)
, mEventHandlerId(0) , mEventHandlerId(0)
{ {
/* Invoke the Qt Designer generated object setup routine */ /* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this); ui.setupUi(this);
#ifndef RS_USE_I2P_BOB #ifndef RS_USE_I2P_SAM3
ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB); // warning: the order of operation here is very important. ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P); // warning: the order of operation here is very important.
#endif #endif
if(RsAccounts::isHiddenNode()) if(RsAccounts::isHiddenNode())
@ -111,7 +113,7 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
ui.hiddenpage_outHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ; ui.hiddenpage_outHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ;
ui.hiddenpage_inHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ; ui.hiddenpage_inHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ;
ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P_BOB); // warning: the order of operation here is very important. ui.hiddenServiceTab->removeTab(TAB_HIDDEN_SERVICE_I2P); // warning: the order of operation here is very important.
} }
} }
else else
@ -166,14 +168,14 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
QObject::connect(ui.filteredIpsTable,SIGNAL(currentCellChanged(int,int,int,int)),this,SLOT(updateSelectedBlackListIP(int,int,int,int))); QObject::connect(ui.filteredIpsTable,SIGNAL(currentCellChanged(int,int,int,int)),this,SLOT(updateSelectedBlackListIP(int,int,int,int)));
QObject::connect(ui.whiteListIpsTable,SIGNAL(currentCellChanged(int,int,int,int)),this,SLOT(updateSelectedWhiteListIP(int,int,int,int))); QObject::connect(ui.whiteListIpsTable,SIGNAL(currentCellChanged(int,int,int,int)),this,SLOT(updateSelectedWhiteListIP(int,int,int,int)));
QObject::connect(ui.pbBobStart, SIGNAL(clicked()), this, SLOT(startBOB())); QObject::connect(ui.pbBobStart, SIGNAL(clicked()), this, SLOT(startSam()));
QObject::connect(ui.pbBobRestart, SIGNAL(clicked()), this, SLOT(restartBOB())); QObject::connect(ui.pbBobRestart, SIGNAL(clicked()), this, SLOT(restartSam()));
QObject::connect(ui.pbBobStop, SIGNAL(clicked()), this, SLOT(stopBOB())); QObject::connect(ui.pbBobStop, SIGNAL(clicked()), this, SLOT(stopSam()));
QObject::connect(ui.pbBobGenAddr, SIGNAL(clicked()), this, SLOT(getNewKey())); QObject::connect(ui.pbBobGenAddr, SIGNAL(clicked()), this, SLOT(getNewKey()));
QObject::connect(ui.pbBobLoadKey, SIGNAL(clicked()), this, SLOT(loadKey())); QObject::connect(ui.pbBobLoadKey, SIGNAL(clicked()), this, SLOT(loadKey()));
QObject::connect(ui.cb_enableBob, SIGNAL(toggled(bool)), this, SLOT(enableBob(bool))); QObject::connect(ui.cb_enableBob, SIGNAL(toggled(bool)), this, SLOT(enableSam(bool)));
QObject::connect(ui.cbBobAdvanced, SIGNAL(toggled(bool)), this, SLOT(toggleBobAdvancedSettings(bool))); QObject::connect(ui.cbBobAdvanced, SIGNAL(toggled(bool)), this, SLOT(toggleSamAdvancedSettings(bool)));
QObject::connect(ui.sbBobLengthIn, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); QObject::connect(ui.sbBobLengthIn, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int)));
QObject::connect(ui.sbBobLengthOut, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); QObject::connect(ui.sbBobLengthOut, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int)));
@ -182,13 +184,9 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
QObject::connect(ui.sbBobVarianceIn, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); QObject::connect(ui.sbBobVarianceIn, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int)));
QObject::connect(ui.sbBobVarianceOut, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int))); QObject::connect(ui.sbBobVarianceOut, SIGNAL(valueChanged(int)), this, SLOT(tunnelSettingsChanged(int)));
// These two spin boxes are used for the same thing - keep them in sync!
QObject::connect(ui.hiddenpage_proxyPort_i2p, SIGNAL(valueChanged(int)), this, SLOT(syncI2PProxyPortNormal(int)));
QObject::connect(ui.hiddenpage_proxyPort_i2p_2, SIGNAL(valueChanged(int)), this, SLOT(syncI2PProxyPortBob(int)));
// These two line edits are used for the same thing - keep them in sync! // These two line edits are used for the same thing - keep them in sync!
QObject::connect(ui.hiddenpage_proxyAddress_i2p, SIGNAL(textChanged(QString)), this, SLOT(syncI2PProxyAddrNormal(QString))); QObject::connect(ui.hiddenpage_proxyAddress_i2p, SIGNAL(textChanged(QString)), this, SLOT(syncI2PProxyAddrNormal(QString)));
QObject::connect(ui.hiddenpage_proxyAddress_i2p_2, SIGNAL(textChanged(QString)), this, SLOT(syncI2PProxyAddrBob(QString))); QObject::connect(ui.hiddenpage_proxyAddress_i2p_2, SIGNAL(textChanged(QString)), this, SLOT(syncI2PProxyAddrSam(QString)));
connect(NotifyQt::getInstance(), SIGNAL(connectionWithoutCert()), this, SLOT(connectionWithoutCert())); connect(NotifyQt::getInstance(), SIGNAL(connectionWithoutCert()), this, SLOT(connectionWithoutCert()));
@ -373,7 +371,7 @@ void ServerPage::load()
} }
mIsHiddenNode = (detail.netMode == RS_NETMODE_HIDDEN); mIsHiddenNode = (detail.netMode == RS_NETMODE_HIDDEN);
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::getSettings, &mBobSettings); rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::getSettings, &mSamSettings);
loadCommon(); loadCommon();
updateStatus(); updateStatus();
@ -870,9 +868,9 @@ void ServerPage::updateStatus()
loadFilteredIps() ; loadFilteredIps() ;
updateStatusBob(); updateStatusSam();
// this is used by BOB // this is used by SAM
if (mOngoingConnectivityCheck > 0) { if (mOngoingConnectivityCheck > 0) {
mOngoingConnectivityCheck--; mOngoingConnectivityCheck--;
@ -1349,9 +1347,11 @@ void ServerPage::updateOutProxyIndicator()
ui.iconlabel_tor_outgoing->setToolTip(tr("Tor proxy is not enabled")) ; ui.iconlabel_tor_outgoing->setToolTip(tr("Tor proxy is not enabled")) ;
} }
// I2P // I2P - SAM
socket.connectToHost(ui.hiddenpage_proxyAddress_i2p->text(),ui.hiddenpage_proxyPort_i2p->text().toInt()); // Note: there is only "the SAM port", there is no additional proxy port!
if(socket.waitForConnected(500)) samStatus ss;
rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::status, &ss);
if(ss.state == samStatus::samState::online)
{ {
socket.disconnectFromHost(); socket.disconnectFromHost();
ui.iconlabel_i2p_outgoing->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_OK)) ; ui.iconlabel_i2p_outgoing->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_OK)) ;
@ -1363,18 +1363,17 @@ void ServerPage::updateOutProxyIndicator()
ui.iconlabel_i2p_outgoing->setToolTip(tr("I2P proxy is not enabled")) ; ui.iconlabel_i2p_outgoing->setToolTip(tr("I2P proxy is not enabled")) ;
} }
// I2P - BOB socket.connectToHost(ui.hiddenpage_proxyAddress_i2p_2->text(), 7656);
socket.connectToHost(ui.hiddenpage_proxyAddress_i2p_2->text(), 2827); if(true == (mSamAccessible = socket.waitForConnected(1000)))
if(true == (mBobAccessible = socket.waitForConnected(500)))
{ {
socket.disconnectFromHost(); socket.disconnectFromHost();
ui.iconlabel_i2p_outgoing_2->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_OK)) ; ui.iconlabel_i2p_outgoing_2->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_OK)) ;
ui.iconlabel_i2p_outgoing_2->setToolTip(tr("BOB is running and accessible")) ; ui.iconlabel_i2p_outgoing_2->setToolTip(tr("SAMv3 is running and accessible")) ;
} }
else else
{ {
ui.iconlabel_i2p_outgoing_2->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_UNKNOWN)) ; ui.iconlabel_i2p_outgoing_2->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_UNKNOWN)) ;
ui.iconlabel_i2p_outgoing_2->setToolTip(tr("BOB is not accessible! Is it running?")) ; ui.iconlabel_i2p_outgoing_2->setToolTip(tr("SAMv3 is not accessible! Is i2p running and SAM enabled?")) ;
} }
} }
@ -1391,22 +1390,12 @@ 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.enable) { if (mHiddenType == RS_HIDDEN_TYPE_I2P && mSamSettings.enable) {
// there is no inproxy for SAMv3, since every connection goes through sam itself
QTcpSocket tcpSocket; auto secw = new samEstablishConnectionWrapper();
secw->address = mSamSettings.address;
const QString host = ui.hiddenpage_proxyAddress_i2p->text(); secw->connection = nullptr;
qint16 port = ui.hiddenpage_proxyPort_i2p->text().toInt(); rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::establishConnection, this, secw);
QByteArray addr = ui.leBobB32Addr->text().toUtf8();
addr.push_back('\n');
mOngoingConnectivityCheck = 5; // timeout in sec
tcpSocket.connectToHost(host, port);
tcpSocket.write(addr); // write addr
tcpSocket.write(addr); // trigger connection error since RS expects a tls connection
tcpSocket.close();
tcpSocket.waitForDisconnected(5 * 1000);
return; return;
} }
@ -1419,18 +1408,10 @@ void ServerPage::updateInProxyIndicator()
QNetworkProxy proxy ; QNetworkProxy proxy ;
proxy.setType(QNetworkProxy::Socks5Proxy); proxy.setType(QNetworkProxy::Socks5Proxy);
switch (mHiddenType) {
case RS_HIDDEN_TYPE_I2P:
proxy.setHostName(ui.hiddenpage_proxyAddress_i2p->text());
proxy.setPort(ui.hiddenpage_proxyPort_i2p->text().toInt());
break;
case RS_HIDDEN_TYPE_TOR:
proxy.setHostName(ui.hiddenpage_proxyAddress_tor->text()); proxy.setHostName(ui.hiddenpage_proxyAddress_tor->text());
proxy.setPort(ui.hiddenpage_proxyPort_tor->text().toInt()); proxy.setPort(ui.hiddenpage_proxyPort_tor->text().toInt());
break;
default:
return;
}
proxy.setCapabilities(QNetworkProxy::HostNameLookupCapability | proxy.capabilities()) ; proxy.setCapabilities(QNetworkProxy::HostNameLookupCapability | proxy.capabilities()) ;
QNetworkProxy::setApplicationProxy(proxy) ; QNetworkProxy::setApplicationProxy(proxy) ;
@ -1445,53 +1426,58 @@ void ServerPage::updateInProxyIndicator()
QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy) ; QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy) ;
} }
void ServerPage::startBOB() void ServerPage::startSam()
{ {
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::start); rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::start);
updateStatus(); updateStatus();
} }
void ServerPage::restartBOB() void ServerPage::restartSam()
{ {
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::stop); rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::stop);
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::start); rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::start);
updateStatus(); updateStatus();
} }
void ServerPage::stopBOB() void ServerPage::stopSam()
{ {
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::stop); rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::stop);
updateStatus(); updateStatus();
} }
void ServerPage::getNewKey() void ServerPage::getNewKey()
{ {
bobSettings *bs = new bobSettings(); i2p::address *addr = new i2p::address();
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PSAM3, autoProxyTask::receiveKey, this, addr);
rsAutoProxyMonitor::taskAsync(autoProxyType::I2PBOB, autoProxyTask::receiveKey, this, bs);
updateStatus();
} }
void ServerPage::loadKey() void ServerPage::loadKey()
{ {
mBobSettings.address.privateKey = ui.pteBobServerKey->toPlainText().toStdString(); auto priv = ui.pteBobServerKey->toPlainText().toStdString();
mBobSettings.address.publicKey = i2p::publicKeyFromPrivate(mBobSettings.address.privateKey); auto pub = i2p::publicKeyFromPrivate(priv);
mBobSettings.address.base32 = i2p::keyToBase32Addr(mBobSettings.address.publicKey); if (pub.empty()) {
// something went wrong!
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); ui.pteBobServerKey->setPlainText("FAILED! Something went wrong while parsing the key!");
return;
} }
void ServerPage::enableBob(bool checked) mSamSettings.address.privateKey = priv;
mSamSettings.address.publicKey = pub;
mSamSettings.address.base32 = i2p::keyToBase32Addr(mSamSettings.address.publicKey);
rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::setSettings, &mSamSettings);
}
void ServerPage::enableSam(bool checked)
{ {
mBobSettings.enable = checked; mSamSettings.enable = checked;
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::setSettings, &mSamSettings);
setUpBobElements(); setUpSamElements();
} }
int8_t fitRange(int i, int min, int max) { int8_t fitRange(int i, int min, int max) {
@ -1513,21 +1499,21 @@ void ServerPage::tunnelSettingsChanged(int)
vi = ui.sbBobVarianceIn->value(); vi = ui.sbBobVarianceIn->value();
vo = ui.sbBobVarianceOut->value(); vo = ui.sbBobVarianceOut->value();
mBobSettings.inLength = fitRange(li, 0, 7); mSamSettings.inLength = fitRange(li, 0, 7);
mBobSettings.outLength = fitRange(lo, 0, 7); mSamSettings.outLength = fitRange(lo, 0, 7);
mBobSettings.inQuantity = fitRange(qi, 1, 16); mSamSettings.inQuantity = fitRange(qi, 1, 16);
mBobSettings.outQuantity = fitRange(qo, 1, 16); mSamSettings.outQuantity = fitRange(qo, 1, 16);
mBobSettings.inVariance = fitRange(vi, -1, 2); mSamSettings.inVariance = fitRange(vi, -1, 2);
mBobSettings.outVariance = fitRange(vo, -1, 2); mSamSettings.outVariance = fitRange(vo, -1, 2);
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::setSettings, &mBobSettings); rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::setSettings, &mSamSettings);
} }
void ServerPage::toggleBobAdvancedSettings(bool checked) void ServerPage::toggleSamAdvancedSettings(bool checked)
{ {
ui.swBobAdvanced->setCurrentIndex(checked ? 1 : 0); ui.swBobAdvanced->setCurrentIndex(checked ? 1 : 0);
if (!mBobSettings.address.privateKey.empty()) { if (!mSamSettings.address.privateKey.empty()) {
if (checked) { if (checked) {
ui.pbBobGenAddr->show(); ui.pbBobGenAddr->show();
} else { } else {
@ -1536,57 +1522,89 @@ void ServerPage::toggleBobAdvancedSettings(bool checked)
} }
} }
void ServerPage::syncI2PProxyPortNormal(int i)
{
ui.hiddenpage_proxyPort_i2p_2->setValue(i);
}
void ServerPage::syncI2PProxyPortBob(int i)
{
ui.hiddenpage_proxyPort_i2p->setValue(i);
// update port
saveBob();
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::reloadConfig);
}
void ServerPage::syncI2PProxyAddrNormal(QString t) void ServerPage::syncI2PProxyAddrNormal(QString t)
{ {
ui.hiddenpage_proxyAddress_i2p_2->setText(t); ui.hiddenpage_proxyAddress_i2p_2->setText(t);
} }
void ServerPage::syncI2PProxyAddrBob(QString t) void ServerPage::syncI2PProxyAddrSam(QString t)
{ {
ui.hiddenpage_proxyAddress_i2p->setText(t); ui.hiddenpage_proxyAddress_i2p->setText(t);
// update addr // update addr
saveBob(); saveSam();
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::reloadConfig); rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::reloadConfig);
} }
void ServerPage::taskFinished(taskTicket *&ticket) void ServerPage::taskFinished(taskTicket *&ticket)
{ {
if (ticket->task == autoProxyTask::receiveKey) { switch (ticket->task) {
bobSettings *s = NULL; case autoProxyTask::receiveKey:
switch (ticket->types.front()) { {
case autoProxyType::I2PBOB: i2p::address *addr = nullptr;
addr = static_cast<i2p::address *>(ticket->data);
if (ticket->types.front() != autoProxyType::I2PSAM3)
RS_WARN("auto proxy task finished but not for SMA, not exptected! Also not a serious problem.");
else {
// update settings // update settings
s = (struct bobSettings *)ticket->data; auto copy = *addr;
mBobSettings = *s; RsQThreadUtils::postToObject(
delete s; [this, copy]()
s = NULL; {
ticket->data = NULL; mSamSettings.address = copy;
break; rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::setSettings, &mSamSettings);
default: updateStatusSam();
});
}
delete addr;
addr = nullptr;
ticket->data = nullptr;
break; break;
} }
case autoProxyTask::establishConnection:
{
samEstablishConnectionWrapper *secw = nullptr;
secw = static_cast<samEstablishConnectionWrapper *>(ticket->data);
if (ticket->types.front() != autoProxyType::I2PSAM3)
RS_WARN("auto proxy task finished but not for SMA, not exptected! Also not a serious problem.");
else {
bool res = ticket->result == autoProxyStatus::ok && !!secw->connection->ses;
// update settings
if (res) {
sam3CloseConnection(secw->connection);
secw->connection = nullptr; // freed by above call
}
RsQThreadUtils::postToObject(
[this, res]()
{
updateInProxyIndicatorResult(res);
});
}
if (secw->connection)
delete secw->connection;
delete secw;
secw = nullptr;
ticket->data = nullptr;
break;
}
default:
RS_DBG("unsupported task!", ticket->task);
} }
if (ticket->data) if (ticket->data)
std::cerr << "(WW) ServerPage::taskFinished data set. This should NOT happen - check the code!" << std::endl; std::cerr << "(WW) ServerPage::taskFinished data set. This should NOT happen - check the code!" << std::endl;
delete ticket; delete ticket;
ticket = NULL; ticket = nullptr;
} }
void ServerPage::connectionWithoutCert() void ServerPage::connectionWithoutCert()
@ -1613,14 +1631,13 @@ void ServerPage::loadCommon()
// I2P // I2P
rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, proxyaddr, proxyport, status); rsPeers->getProxyServer(RS_HIDDEN_TYPE_I2P, proxyaddr, proxyport, status);
whileBlocking(ui.hiddenpage_proxyAddress_i2p) -> setText(QString::fromStdString(proxyaddr)); whileBlocking(ui.hiddenpage_proxyAddress_i2p) -> setText(QString::fromStdString(proxyaddr));
whileBlocking(ui.hiddenpage_proxyAddress_i2p_2)->setText(QString::fromStdString(proxyaddr)); // this one is for bob tab whileBlocking(ui.hiddenpage_proxyAddress_i2p_2)->setText(QString::fromStdString(proxyaddr)); // this one is for sam tab
whileBlocking(ui.hiddenpage_proxyPort_i2p) -> setValue(proxyport); whileBlocking(ui.hiddenpage_proxyPort_i2p) -> setValue(proxyport);
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.enable); ui.cb_enableBob->setChecked(mSamSettings.enable);
if (!mBobSettings.address.privateKey.empty()) { if (!mSamSettings.address.privateKey.empty()) {
ui.lBobB32Addr->show(); ui.lBobB32Addr->show();
ui.leBobB32Addr->show(); ui.leBobB32Addr->show();
} }
@ -1642,10 +1659,10 @@ void ServerPage::saveCommon()
rsPeers->setProxyServer(RS_HIDDEN_TYPE_TOR, new_proxyaddr, new_proxyport); rsPeers->setProxyServer(RS_HIDDEN_TYPE_TOR, new_proxyaddr, new_proxyport);
} }
saveBob(); saveSam();
} }
void ServerPage::saveBob() void ServerPage::saveSam()
{ {
std::string orig_proxyaddr, new_proxyaddr; std::string orig_proxyaddr, new_proxyaddr;
uint16_t orig_proxyport, new_proxyport; uint16_t orig_proxyport, new_proxyport;
@ -1656,20 +1673,29 @@ void ServerPage::saveBob()
new_proxyaddr = ui.hiddenpage_proxyAddress_i2p -> text().toStdString(); new_proxyaddr = ui.hiddenpage_proxyAddress_i2p -> text().toStdString();
new_proxyport = ui.hiddenpage_proxyPort_i2p -> value(); new_proxyport = ui.hiddenpage_proxyPort_i2p -> value();
if ((new_proxyaddr != orig_proxyaddr) || (new_proxyport != orig_proxyport)) { // SAMv3 has no proxy port, everything goes through the SAM port.
if ((new_proxyaddr != orig_proxyaddr) /* || (new_proxyport != orig_proxyport) */) {
rsPeers->setProxyServer(RS_HIDDEN_TYPE_I2P, new_proxyaddr, new_proxyport); rsPeers->setProxyServer(RS_HIDDEN_TYPE_I2P, new_proxyaddr, new_proxyport);
} }
} }
void ServerPage::updateStatusBob() void ServerPage::updateStatusSam()
{ {
QString addr = QString::fromStdString(mBobSettings.address.base32); QString addr = QString::fromStdString(mSamSettings.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.address.privateKey)); ui.pteBobServerKey->setPlainText(QString::fromStdString(mSamSettings.address.privateKey));
if (!mBobSettings.address.privateKey.empty()) { std::string signingKeyType, cryptoKeyType;
if (i2p::getKeyTypes(mSamSettings.address.publicKey, signingKeyType, cryptoKeyType))
ui.samKeyInfo->setText(tr("Your key uses the following algorithms: %1 and %2").
arg(QString::fromStdString(signingKeyType)).
arg(QString::fromStdString(cryptoKeyType)));
else
ui.samKeyInfo->setText(tr("unkown key type"));
if (!mSamSettings.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();
@ -1689,125 +1715,79 @@ void ServerPage::updateStatusBob()
saveAddresses(); saveAddresses();
} }
bobStates bs; samStatus ss;
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::status, &bs); rsAutoProxyMonitor::taskSync(autoProxyType::I2PSAM3, autoProxyTask::status, &ss);
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 SAMv3 to set up a %1 tunnel at %2:%3\n(id: %4)\n\n"
"When changing options (e.g. port) use the buttons at the bottom to restart BOB.\n\n"). "When changing options use the buttons at the bottom to restart SAMv3.\n\n").
arg(mBobSettings.address.privateKey.empty() ? tr("client") : tr("server"), arg(mSamSettings.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(), "7656",
bs.tunnelName.empty() ? tr("unknown") : ss.sessionName.empty() ? tr("unknown") :
QString::fromStdString(bs.tunnelName))); QString::fromStdString(ss.sessionName)));
// update BOB UI based on state // update SAM UI based on state
std::string errorString;
switch (bs.cs) {
case csDoConnect:
case csConnected:
case csDoDisconnect:
case csWaitForBob:
ui.iconlabel_i2p_bob->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_WORKING));
ui.iconlabel_i2p_bob->setToolTip(tr("BOB is processing a request"));
enableBobElements(false);
{
QString s; QString s;
switch (bs.ct) { QString icon;
case ctRunCheck: switch (ss.state) {
s = tr("connectivity check"); case samStatus::samState::offline:
break; enableSamElements(false);
case ctRunGetKeys:
s = tr("generating key");
break;
case ctRunSetUp:
s = tr("starting up");
break;
case ctRunShutDown:
s = tr("shuting down");
default:
break;
}
bobSimpleText.append(tr("BOB is processing a request: %1").arg(s));
}
ui.pbBobStart->setEnabled(false);
ui.pbBobRestart->setEnabled(false);
ui.pbBobStop->setEnabled(false);
break;
case csError:
// get error msg from bob
rsAutoProxyMonitor::taskSync(autoProxyType::I2PBOB, autoProxyTask::getErrorInfo, &errorString);
ui.iconlabel_i2p_bob->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_ERROR));
ui.iconlabel_i2p_bob->setToolTip(tr("BOB is broken\n") + QString::fromStdString(errorString));
enableBobElements(false);
bobSimpleText.append(tr("BOB encountered an error:\n"));
bobSimpleText.append(QString::fromStdString(errorString));
ui.pbBobStart->setEnabled(true); ui.pbBobStart->setEnabled(true);
ui.pbBobRestart->setEnabled(false); ui.pbBobRestart->setEnabled(false);
ui.pbBobStop->setEnabled(true); ui.pbBobStop->setEnabled(false);
s = tr("Offline, no SAM session is established yet.\n");
icon = ICON_STATUS_ERROR;
break; break;
case csDisconnected: case samStatus::samState::connectSession:
case csIdel: enableSamElements(false);
switch (bs.ct) {
case ctRunSetUp:
ui.iconlabel_i2p_bob->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_OK));
ui.iconlabel_i2p_bob->setToolTip(tr("BOB tunnel is running"));
enableBobElements(false); ui.pbBobStart->setEnabled(false);
ui.pbBobRestart->setEnabled(false);
ui.pbBobStop->setEnabled(true);
bobSimpleText.append(tr("BOB is working fine: tunnel established")); s = tr("SAM is trying to establish a session ... this can take some time.\n");
icon = ICON_STATUS_WORKING;
break;
case samStatus::samState::connectForward:
enableSamElements(false);
ui.pbBobStart->setEnabled(false);
ui.pbBobRestart->setEnabled(false);
ui.pbBobStop->setEnabled(true);
s = tr("SAM session established! Now setting up a forward session ...\n");
icon = ICON_STATUS_WORKING;
break;
case samStatus::samState::online:
enableSamElements(true);
ui.pbBobStart->setEnabled(false); ui.pbBobStart->setEnabled(false);
ui.pbBobRestart->setEnabled(true); ui.pbBobRestart->setEnabled(true);
ui.pbBobStop->setEnabled(true); ui.pbBobStop->setEnabled(true);
break;
case ctRunCheck:
case ctRunGetKeys:
ui.iconlabel_i2p_bob->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_WORKING));
ui.iconlabel_i2p_bob->setToolTip(tr("BOB is processing a request"));
enableBobElements(false); s = tr("Online, SAM is working as exptected\n");
icon = ICON_STATUS_OK;
bobSimpleText.append(tr("BOB is processing a request"));
ui.pbBobStart->setEnabled(false);
ui.pbBobRestart->setEnabled(false);
ui.pbBobStop->setEnabled(false);
break;
case ctRunShutDown:
case ctIdle:
ui.iconlabel_i2p_bob->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ICON_STATUS_UNKNOWN));
ui.iconlabel_i2p_bob->setToolTip(tr("BOB tunnel is not running"));
enableBobElements(true);
bobSimpleText.append(tr("BOB is inactive: tunnel closed"));
ui.pbBobStart->setEnabled(true);
ui.pbBobRestart->setEnabled(false);
ui.pbBobStop->setEnabled(false);
break; break;
} }
break; ui.iconlabel_i2p_bob->setPixmap(icon);
ui.iconlabel_i2p_bob->setToolTip(s);
bobSimpleText.append(s);
}
ui.pteBobSimple->setPlainText(bobSimpleText); ui.pteBobSimple->setPlainText(bobSimpleText);
// disable elements when BOB is not accessible // disable elements when BOB is not accessible
if (!mBobAccessible) { if (!mSamAccessible) {
ui.pbBobStart->setEnabled(false); ui.pbBobStart->setEnabled(false);
ui.pbBobStart->setToolTip("BOB is not accessible"); ui.pbBobStart->setToolTip("SAMv3 is not accessible");
ui.pbBobRestart->setEnabled(false); ui.pbBobRestart->setEnabled(false);
ui.pbBobRestart->setToolTip("BOB is not accessible"); ui.pbBobRestart->setToolTip("SAMv3 is not accessible");
// don't disable the stop button! (in case bob is running you are otherwise unable to stop and disable it) // don't disable the stop button! (in case SAM is running you are otherwise unable to stop and disable it)
ui.pbBobStop->setToolTip("BOB is not accessible"); ui.pbBobStop->setToolTip("SAMv3 is not accessible");
} else { } else {
ui.pbBobStart->setToolTip(""); ui.pbBobStart->setToolTip("");
ui.pbBobRestart->setToolTip(""); ui.pbBobRestart->setToolTip("");
@ -1815,26 +1795,34 @@ void ServerPage::updateStatusBob()
} }
} }
void ServerPage::setUpBobElements() void ServerPage::setUpSamElements()
{ {
ui.gbBob->setEnabled(mBobSettings.enable); ui.gbBob->setEnabled(mSamSettings.enable);
if (mBobSettings.enable) { if (mSamSettings.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 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 settings to change this value");
ui.leBobB32Addr->setText(QString::fromStdString(mBobSettings.address.base32)); ui.leBobB32Addr->setText(QString::fromStdString(mSamSettings.address.base32));
ui.pteBobServerKey->setPlainText(QString::fromStdString(mBobSettings.address.privateKey)); ui.pteBobServerKey->setPlainText(QString::fromStdString(mSamSettings.address.privateKey));
std::string signingKeyType, cryptoKeyType;
if (i2p::getKeyTypes(mSamSettings.address.publicKey, signingKeyType, cryptoKeyType))
ui.samKeyInfo->setText(tr("You key uses %1 for signing and %2 for crypto").
arg(QString::fromStdString(signingKeyType)).
arg(QString::fromStdString(cryptoKeyType)));
else
ui.samKeyInfo->setText(tr("unkown key type"));
// 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;
li = mBobSettings.inLength; li = mSamSettings.inLength;
lo = mBobSettings.outLength; lo = mSamSettings.outLength;
qi = mBobSettings.inQuantity; qi = mSamSettings.inQuantity;
qo = mBobSettings.outQuantity; qo = mSamSettings.outQuantity;
vi = mBobSettings.inVariance; vi = mSamSettings.inVariance;
vo = mBobSettings.outVariance; vo = mSamSettings.outVariance;
ui.sbBobLengthIn ->setValue(li); ui.sbBobLengthIn ->setValue(li);
ui.sbBobLengthOut ->setValue(lo); ui.sbBobLengthOut ->setValue(lo);
@ -1850,7 +1838,7 @@ void ServerPage::setUpBobElements()
} }
} }
void ServerPage::enableBobElements(bool enable) void ServerPage::enableSamElements(bool enable)
{ {
if (enable) { if (enable) {
ui.pbBobGenAddr->setEnabled(true); ui.pbBobGenAddr->setEnabled(true);
@ -1863,13 +1851,13 @@ void ServerPage::enableBobElements(bool enable)
ui.cb_enableBob->setToolTip(tr("")); ui.cb_enableBob->setToolTip(tr(""));
} else { } else {
ui.pbBobGenAddr->setEnabled(false); ui.pbBobGenAddr->setEnabled(false);
ui.pbBobGenAddr->setToolTip(tr("stop BOB tunnel first to generate a new key")); ui.pbBobGenAddr->setToolTip(tr("stop SAM tunnel first to generate a new key"));
ui.pbBobLoadKey->setEnabled(false); ui.pbBobLoadKey->setEnabled(false);
ui.pbBobLoadKey->setToolTip(tr("stop BOB tunnel first to load a key")); ui.pbBobLoadKey->setToolTip(tr("stop SAM tunnel first to load a key"));
ui.cb_enableBob->setEnabled(false); ui.cb_enableBob->setEnabled(false);
ui.cb_enableBob->setToolTip(tr("stop BOB tunnel first to disable BOB")); ui.cb_enableBob->setToolTip(tr("stop SAM tunnel first to disable SAM"));
} }
} }
@ -1896,6 +1884,7 @@ void ServerPage::handleNetworkReply(QNetworkReply *reply)
{ {
int error = reply->error() ; int error = reply->error() ;
RS_INFO("error:", error);
if(reply->isOpen() && error == QNetworkReply::SslHandshakeFailedError) if(reply->isOpen() && error == QNetworkReply::SslHandshakeFailedError)
updateInProxyIndicatorResult(true); updateInProxyIndicatorResult(true);
else else

View File

@ -34,7 +34,7 @@
#endif #endif
#include <services/autoproxy/rsautoproxymonitor.h> #include <services/autoproxy/rsautoproxymonitor.h>
#include <services/autoproxy/p3i2pbob.h> #include <services/autoproxy/p3i2psam3.h>
#include "retroshare-gui/configpage.h" #include "retroshare-gui/configpage.h"
#include "retroshare-gui/RsAutoUpdatePage.h" #include "retroshare-gui/RsAutoUpdatePage.h"
@ -97,22 +97,19 @@ private slots:
void handleNetworkReply(QNetworkReply *reply); void handleNetworkReply(QNetworkReply *reply);
void updateInProxyIndicator(); void updateInProxyIndicator();
// i2p bob // i2p SAMv3
void startBOB(); void startSam();
void restartBOB(); void restartSam();
void stopBOB(); void stopSam();
void getNewKey(); void getNewKey();
void loadKey(); void loadKey();
void enableBob(bool checked); void enableSam(bool checked);
void tunnelSettingsChanged(int); void tunnelSettingsChanged(int);
void toggleBobAdvancedSettings(bool checked); void toggleSamAdvancedSettings(bool checked);
void syncI2PProxyPortNormal(int i);
void syncI2PProxyPortBob(int i);
void syncI2PProxyAddrNormal(QString); void syncI2PProxyAddrNormal(QString);
void syncI2PProxyAddrBob(QString); void syncI2PProxyAddrSam(QString);
void connectionWithoutCert(); void connectionWithoutCert();
@ -133,11 +130,11 @@ public:
private: private:
void loadCommon(); void loadCommon();
void saveCommon(); void saveCommon();
void saveBob(); void saveSam();
void updateStatusBob(); void updateStatusSam();
void setUpBobElements(); void setUpSamElements();
void enableBobElements(bool enable); void enableSamElements(bool enable);
void updateInProxyIndicatorResult(bool success); void updateInProxyIndicatorResult(bool success);
@ -160,8 +157,8 @@ private:
bool mIsHiddenNode; bool mIsHiddenNode;
uint32_t mHiddenType; uint32_t mHiddenType;
bobSettings mBobSettings; samSettings mSamSettings;
bool mBobAccessible; // keeps track wether bob is accessable or not to en/disable the corresponding buttons bool mSamAccessible; // keeps track wether SAM is accessable or not to en/disable the corresponding buttons
RsEventsHandlerId_t mEventHandlerId; RsEventsHandlerId_t mEventHandlerId;
void handleEvent(std::shared_ptr<const RsEvent> event); void handleEvent(std::shared_ptr<const RsEvent> event);

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>712</width> <width>726</width>
<height>502</height> <height>579</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="ServerPageVLayout"> <layout class="QVBoxLayout" name="ServerPageVLayout">
@ -908,9 +908,9 @@ If you have issues connecting over Tor check the Tor logs too.</string>
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="hiddenServiceTabI2PBOB"> <widget class="QWidget" name="hiddenServiceTabI2P">
<attribute name="title"> <attribute name="title">
<string>Automatic I2P/BOB</string> <string>Automatic I2P</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="hiddenServiceTabI2PBOBVLayout"> <layout class="QVBoxLayout" name="hiddenServiceTabI2PBOBVLayout">
<item> <item>
@ -918,7 +918,7 @@ If you have issues connecting over Tor check the Tor logs too.</string>
<item> <item>
<widget class="QCheckBox" name="cb_enableBob"> <widget class="QCheckBox" name="cb_enableBob">
<property name="text"> <property name="text">
<string>Enable I2P BOB - changing this requires a restart to fully take effect</string> <string>Enable I2P SAMv3 - changing this requires a restart to fully take effect</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -950,7 +950,7 @@ If you have issues connecting over Tor check the Tor logs too.</string>
<item> <item>
<widget class="QGroupBox" name="gbBob"> <widget class="QGroupBox" name="gbBob">
<property name="title"> <property name="title">
<string>I2P Basic Open Bridge</string> <string>I2P Simple Anonymous Messaging</string>
</property> </property>
<layout class="QVBoxLayout" name="gbBobVLayout"> <layout class="QVBoxLayout" name="gbBobVLayout">
<item> <item>
@ -982,21 +982,17 @@ If you have issues connecting over Tor check the Tor logs too.</string>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="i2pProxyPortLabel"> <spacer name="horizontalSpacer">
<property name="text"> <property name="orientation">
<string>I2P proxy port</string> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> <property name="sizeHint" stdset="0">
</item> <size>
<item> <width>40</width>
<widget class="QSpinBox" name="hiddenpage_proxyPort_i2p_2"> <height>20</height>
<property name="minimum"> </size>
<number>10</number>
</property> </property>
<property name="maximum"> </spacer>
<number>65535</number>
</property>
</widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="bobAccHLayout"> <layout class="QHBoxLayout" name="bobAccHLayout">
@ -1016,7 +1012,7 @@ If you have issues connecting over Tor check the Tor logs too.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This led is green when the port listen on the left is active on your computer. It does not&lt;/p&gt;&lt;p&gt;mean that your Retroshare traffic transits though I2P. It will do so only if &lt;/p&gt;&lt;p&gt;you connect to Hidden nodes, or if you are running a Hidden node yourself.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This led is green when the port listen on the left is active on your computer. It does not&lt;/p&gt;&lt;p&gt;mean that your Retroshare traffic transits though I2P. It will do so only if &lt;/p&gt;&lt;p&gt;you connect to Hidden nodes, or if you are running a Hidden node yourself.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>BOB accessible</string> <string>SAM accessible</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -1304,6 +1300,13 @@ If you have issues connecting over Tor check the Tor logs too.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="samKeyInfo">
<property name="text">
<string notr="true">&lt;key info&gt;</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@ -1359,7 +1362,7 @@ If you have issues connecting over Tor check the Tor logs too.</string>
<item> <item>
<widget class="QLabel" name="lBobStatus"> <widget class="QLabel" name="lBobStatus">
<property name="text"> <property name="text">
<string>BOB status</string> <string>SAM status</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -140,11 +140,6 @@ 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_channels_index" # line "CONFIG+=rs_deep_channels_index"
CONFIG *= no_rs_deep_channels_index CONFIG *= no_rs_deep_channels_index
@ -209,6 +204,9 @@ no_rs_dh_init_check:CONFIG -= rs_dh_init_check
# many exported symbols. # many exported symbols.
retroshare_plugins:win32:CONFIG *= libretroshare_shared retroshare_plugins:win32:CONFIG *= libretroshare_shared
CONFIG+=rs_sam3
CONFIG+=rs_sam3_libsam3
# Specify host precompiled jsonapi-generator path, appending the following # Specify host precompiled jsonapi-generator path, appending the following
# assignation to qmake command line # assignation to qmake command line
# 'JSONAPI_GENERATOR_EXE=/myBuildDir/jsonapi-generator'. Required for JSON API # 'JSONAPI_GENERATOR_EXE=/myBuildDir/jsonapi-generator'. Required for JSON API
@ -559,10 +557,6 @@ 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
@ -576,6 +570,13 @@ rs_broadcast_discovery:DEFINES *= RS_BROADCAST_DISCOVERY
no_rs_dh_init_check:DEFINES *= RS_DISABLE_DIFFIE_HELLMAN_INIT_CHECK no_rs_dh_init_check:DEFINES *= RS_DISABLE_DIFFIE_HELLMAN_INIT_CHECK
rs_sam3: {
DEFINES *= RS_USE_I2P_SAM3
# this allows a downgrade from a SAMv3 build to a BOB build, can be removed in the future
DEFINES *= RS_I2P_SAM3_BOB_COMPAT
}
rs_sam3_libsam3: DEFINES *= RS_USE_I2P_SAM3_LIBSAM3
debug { debug {
rs_mutex_debug:DEFINES *= RS_MUTEX_DEBUG rs_mutex_debug:DEFINES *= RS_MUTEX_DEBUG

1
supportlibs/libsam3 Submodule

@ -0,0 +1 @@
Subproject commit 8623304b62294dafbe477573f321a464fef721dd