i2pd/libi2pd_client/BOB.cpp

945 lines
27 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2013-2023, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
2014-12-02 20:47:44 +00:00
#include <string.h>
2014-12-02 16:42:35 +00:00
#include "Log.h"
2014-12-03 02:45:01 +00:00
#include "ClientContext.h"
2016-11-04 01:31:21 +00:00
#include "util.h"
2014-12-02 15:34:02 +00:00
#include "BOB.h"
namespace i2p
{
namespace client
{
2018-01-06 03:48:51 +00:00
BOBI2PInboundTunnel::BOBI2PInboundTunnel (const boost::asio::ip::tcp::endpoint& ep, std::shared_ptr<ClientDestination> localDestination):
BOBI2PTunnel (localDestination), m_Acceptor (localDestination->GetService (), ep)
2014-12-03 19:48:41 +00:00
{
}
BOBI2PInboundTunnel::~BOBI2PInboundTunnel ()
{
2014-12-05 00:29:20 +00:00
Stop ();
2014-12-03 19:48:41 +00:00
}
void BOBI2PInboundTunnel::Start ()
{
m_Acceptor.listen ();
Accept ();
}
void BOBI2PInboundTunnel::Stop ()
{
m_Acceptor.close();
ClearHandlers ();
2014-12-03 19:48:41 +00:00
}
void BOBI2PInboundTunnel::Accept ()
{
2015-04-06 19:02:37 +00:00
auto receiver = std::make_shared<AddressReceiver> ();
receiver->socket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
2014-12-07 14:48:03 +00:00
m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this,
std::placeholders::_1, receiver));
2018-01-06 03:48:51 +00:00
}
2014-12-03 19:48:41 +00:00
2015-04-06 19:02:37 +00:00
void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver)
2014-12-03 19:48:41 +00:00
{
if (!ecode)
{
2018-01-06 03:48:51 +00:00
Accept ();
2014-12-07 14:48:03 +00:00
ReceiveAddress (receiver);
2014-12-03 19:48:41 +00:00
}
}
2015-04-06 19:02:37 +00:00
void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr<AddressReceiver> receiver)
2014-12-03 19:48:41 +00:00
{
2014-12-07 14:48:03 +00:00
receiver->socket->async_read_some (boost::asio::buffer(
receiver->buffer + receiver->bufferOffset,
BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset),
2018-01-06 03:48:51 +00:00
std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this,
std::placeholders::_1, std::placeholders::_2, receiver));
2014-12-03 19:48:41 +00:00
}
2018-01-06 03:48:51 +00:00
2014-12-03 19:48:41 +00:00
void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
2015-04-06 19:02:37 +00:00
std::shared_ptr<AddressReceiver> receiver)
2014-12-03 19:48:41 +00:00
{
if (ecode)
LogPrint (eLogError, "BOB: Inbound tunnel read error: ", ecode.message ());
2014-12-03 19:48:41 +00:00
else
{
2014-12-07 14:48:03 +00:00
receiver->bufferOffset += bytes_transferred;
receiver->buffer[receiver->bufferOffset] = 0;
char * eol = strchr (receiver->buffer, '\n');
2014-12-03 19:48:41 +00:00
if (eol)
{
*eol = 0;
2018-01-06 03:48:51 +00:00
if (eol != receiver->buffer && eol[-1] == '\r') eol[-1] = 0; // workaround for Transmission, it sends '\r\n' terminated address
2014-12-07 14:48:03 +00:00
receiver->data = (uint8_t *)eol + 1;
receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1);
2019-03-28 16:19:19 +00:00
auto addr = context.GetAddressBook ().GetAddress (receiver->buffer);
if (!addr)
{
LogPrint (eLogError, "BOB: Address ", receiver->buffer, " not found");
return;
}
2019-03-28 16:19:19 +00:00
if (addr->IsIdentHash ())
{
auto leaseSet = GetLocalDestination ()->FindLeaseSet (addr->identHash);
if (leaseSet)
CreateConnection (receiver, leaseSet);
else
GetLocalDestination ()->RequestDestination (addr->identHash,
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
this, std::placeholders::_1, receiver));
}
2014-12-03 19:48:41 +00:00
else
2019-03-28 16:19:19 +00:00
GetLocalDestination ()->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey,
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
this, std::placeholders::_1, receiver));
2014-12-03 19:48:41 +00:00
}
else
{
2014-12-07 14:48:03 +00:00
if (receiver->bufferOffset < BOB_COMMAND_BUFFER_SIZE)
ReceiveAddress (receiver);
2014-12-06 20:31:39 +00:00
else
LogPrint (eLogError, "BOB: Missing inbound address");
2018-01-06 03:48:51 +00:00
}
2014-12-03 19:48:41 +00:00
}
}
void BOBI2PInboundTunnel::HandleDestinationRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<AddressReceiver> receiver)
2014-12-03 19:48:41 +00:00
{
if (leaseSet)
CreateConnection (receiver, leaseSet);
else
2015-12-18 06:27:35 +00:00
LogPrint (eLogError, "BOB: LeaseSet for inbound destination not found");
2018-01-06 03:48:51 +00:00
}
2014-12-03 19:48:41 +00:00
2015-04-06 19:02:37 +00:00
void BOBI2PInboundTunnel::CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
2014-12-03 19:48:41 +00:00
{
2015-12-18 06:27:35 +00:00
LogPrint (eLogDebug, "BOB: New inbound connection");
2014-12-07 14:48:03 +00:00
auto connection = std::make_shared<I2PTunnelConnection>(this, receiver->socket, leaseSet);
AddHandler (connection);
2014-12-07 14:48:03 +00:00
connection->I2PConnect (receiver->data, receiver->dataLen);
2014-12-03 19:48:41 +00:00
}
BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& outhost, uint16_t port,
2015-02-24 20:40:50 +00:00
std::shared_ptr<ClientDestination> localDestination, bool quiet): BOBI2PTunnel (localDestination),
2019-05-29 16:05:03 +00:00
m_Endpoint (boost::asio::ip::address::from_string (outhost), port), m_IsQuiet (quiet)
2014-12-05 19:13:16 +00:00
{
}
2018-01-06 03:48:51 +00:00
2014-12-05 19:13:16 +00:00
void BOBI2POutboundTunnel::Start ()
{
Accept ();
}
void BOBI2POutboundTunnel::Stop ()
{
ClearHandlers ();
2018-01-06 03:48:51 +00:00
}
2014-12-05 19:13:16 +00:00
void BOBI2POutboundTunnel::Accept ()
{
2018-01-06 03:48:51 +00:00
auto localDestination = GetLocalDestination ();
2014-12-05 19:13:16 +00:00
if (localDestination)
localDestination->AcceptStreams (std::bind (&BOBI2POutboundTunnel::HandleAccept, this, std::placeholders::_1));
else
2015-12-18 06:27:35 +00:00
LogPrint (eLogError, "BOB: Local destination not set for server tunnel");
2014-12-05 19:13:16 +00:00
}
void BOBI2POutboundTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
{
if (stream)
2018-01-06 03:48:51 +00:00
{
2022-10-09 01:41:28 +00:00
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, m_Endpoint, m_IsQuiet);
AddHandler (conn);
2014-12-05 19:13:16 +00:00
conn->Connect ();
2018-01-06 03:48:51 +00:00
}
2014-12-05 19:13:16 +00:00
}
2019-05-29 16:05:03 +00:00
BOBDestination::BOBDestination (std::shared_ptr<ClientDestination> localDestination,
const std::string &nickname, const std::string &inhost, const std::string &outhost,
const uint16_t inport, const uint16_t outport, const bool quiet):
2018-01-06 03:48:51 +00:00
m_LocalDestination (localDestination),
2019-05-29 16:05:03 +00:00
m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr),
m_Nickname(nickname), m_InHost(inhost), m_OutHost(outhost),
m_InPort(inport), m_OutPort(outport), m_Quiet(quiet), m_IsRunning(false)
{
}
2018-01-06 03:48:51 +00:00
BOBDestination::~BOBDestination ()
{
delete m_OutboundTunnel;
delete m_InboundTunnel;
2015-02-24 20:40:50 +00:00
i2p::client::context.DeleteLocalDestination (m_LocalDestination);
2018-01-06 03:48:51 +00:00
}
void BOBDestination::Start ()
{
if (m_OutboundTunnel) m_OutboundTunnel->Start ();
if (m_InboundTunnel) m_InboundTunnel->Start ();
m_IsRunning = true;
}
2018-01-06 03:48:51 +00:00
void BOBDestination::Stop ()
2018-01-06 03:48:51 +00:00
{
2014-12-08 02:04:02 +00:00
StopTunnels ();
2015-02-24 20:40:50 +00:00
m_LocalDestination->Stop ();
2018-01-06 03:48:51 +00:00
}
2014-12-05 19:13:16 +00:00
2014-12-08 02:04:02 +00:00
void BOBDestination::StopTunnels ()
{
m_IsRunning = false;
2014-12-08 02:04:02 +00:00
if (m_OutboundTunnel)
2018-01-06 03:48:51 +00:00
{
2014-12-08 02:04:02 +00:00
m_OutboundTunnel->Stop ();
delete m_OutboundTunnel;
m_OutboundTunnel = nullptr;
2018-01-06 03:48:51 +00:00
}
2014-12-08 02:04:02 +00:00
if (m_InboundTunnel)
2018-01-06 03:48:51 +00:00
{
2014-12-08 02:04:02 +00:00
m_InboundTunnel->Stop ();
delete m_InboundTunnel;
m_InboundTunnel = nullptr;
2018-01-06 03:48:51 +00:00
}
}
void BOBDestination::CreateInboundTunnel (uint16_t port, const std::string& inhost)
{
2014-12-08 02:04:02 +00:00
if (!m_InboundTunnel)
{
2019-05-29 16:05:03 +00:00
// update inport and inhost (user can stop tunnel and change)
m_InPort = port;
m_InHost = inhost;
boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(), port);
2019-05-29 16:05:03 +00:00
if (!inhost.empty ())
{
boost::system::error_code ec;
2019-05-29 16:05:03 +00:00
auto addr = boost::asio::ip::address::from_string (inhost, ec);
if (!ec)
ep.address (addr);
else
2018-01-06 03:48:51 +00:00
LogPrint (eLogError, "BOB: ", ec.message ());
}
m_InboundTunnel = new BOBI2PInboundTunnel (ep, m_LocalDestination);
}
}
2018-01-06 03:48:51 +00:00
void BOBDestination::CreateOutboundTunnel (const std::string& outhost, uint16_t port, bool quiet)
{
2014-12-08 02:04:02 +00:00
if (!m_OutboundTunnel)
2019-05-29 16:05:03 +00:00
{
// update outport and outhost (user can stop tunnel and change)
m_OutPort = port;
m_OutHost = outhost;
m_OutboundTunnel = new BOBI2POutboundTunnel (outhost, port, m_LocalDestination, quiet);
}
2018-01-06 03:48:51 +00:00
}
BOBCommandSession::BOBCommandSession (BOBCommandChannel& owner):
2016-07-19 15:08:28 +00:00
m_Owner (owner), m_Socket (m_Owner.GetService ()),
2019-05-29 16:05:03 +00:00
m_ReceiveBuffer(BOB_COMMAND_BUFFER_SIZE + 1), m_SendBuffer(BOB_COMMAND_BUFFER_SIZE + 1),
m_IsOpen (true), m_IsQuiet (false), m_IsActive (false),
2016-07-11 18:35:59 +00:00
m_InPort (0), m_OutPort (0), m_CurrentDestination (nullptr)
2014-12-02 16:42:35 +00:00
{
}
2014-12-02 20:47:44 +00:00
BOBCommandSession::~BOBCommandSession ()
{
}
2014-12-02 21:45:51 +00:00
void BOBCommandSession::Terminate ()
{
m_Socket.close ();
2018-01-06 03:48:51 +00:00
m_IsOpen = false;
2014-12-02 21:45:51 +00:00
}
2014-12-02 20:47:44 +00:00
void BOBCommandSession::Receive ()
{
2019-05-29 16:05:03 +00:00
boost::asio::async_read_until(m_Socket, m_ReceiveBuffer, '\n',
std::bind(&BOBCommandSession::HandleReceivedLine, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
2014-12-02 20:47:44 +00:00
}
2019-05-29 16:05:03 +00:00
void BOBCommandSession::HandleReceivedLine(const boost::system::error_code& ecode, std::size_t bytes_transferred)
2014-12-02 20:47:44 +00:00
{
2019-05-29 16:05:03 +00:00
if(ecode)
2014-12-02 21:45:51 +00:00
{
LogPrint (eLogError, "BOB: Command channel read error: ", ecode.message());
2014-12-05 00:29:20 +00:00
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
2018-01-06 03:48:51 +00:00
}
2014-12-02 20:47:44 +00:00
else
2018-01-06 03:48:51 +00:00
{
2019-05-29 16:05:03 +00:00
std::string line;
2019-05-29 16:05:03 +00:00
std::istream is(&m_ReceiveBuffer);
std::getline(is, line);
2019-05-29 16:05:03 +00:00
std::string command, operand;
std::istringstream iss(line);
iss >> command >> operand;
2019-05-29 16:05:03 +00:00
// process command
auto& handlers = m_Owner.GetCommandHandlers();
auto it = handlers.find(command);
if(it != handlers.end())
2014-12-02 20:47:44 +00:00
{
2019-05-29 16:05:03 +00:00
(this->*(it->second))(operand.c_str(), operand.length());
2014-12-02 20:47:44 +00:00
}
else
{
LogPrint (eLogError, "BOB: Unknown command ", command.c_str());
2019-05-29 16:05:03 +00:00
SendReplyError ("unknown command");
2018-01-06 03:48:51 +00:00
}
2014-12-02 21:45:51 +00:00
}
}
2019-05-29 16:05:03 +00:00
void BOBCommandSession::Send ()
2014-12-02 21:45:51 +00:00
{
2019-05-29 16:05:03 +00:00
boost::asio::async_write (m_Socket, m_SendBuffer,
2014-12-02 21:45:51 +00:00
boost::asio::transfer_all (),
2018-01-06 03:48:51 +00:00
std::bind(&BOBCommandSession::HandleSent, shared_from_this (),
2014-12-02 21:45:51 +00:00
std::placeholders::_1, std::placeholders::_2));
}
void BOBCommandSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
{
if (ecode)
2019-05-29 16:05:03 +00:00
{
LogPrint (eLogError, "BOB: Command channel send error: ", ecode.message ());
2014-12-05 00:29:20 +00:00
if (ecode != boost::asio::error::operation_aborted)
Terminate ();
2014-12-02 21:45:51 +00:00
}
else
{
2014-12-02 20:47:44 +00:00
if (m_IsOpen)
Receive ();
2014-12-02 21:45:51 +00:00
else
2018-01-06 03:48:51 +00:00
Terminate ();
2014-12-02 20:47:44 +00:00
}
}
2014-12-02 21:45:51 +00:00
void BOBCommandSession::SendReplyOK (const char * msg)
{
2019-05-29 16:05:03 +00:00
std::ostream os(&m_SendBuffer);
os << "OK";
if(msg)
{
os << " " << msg;
}
os << std::endl;
Send ();
2014-12-02 21:45:51 +00:00
}
void BOBCommandSession::SendReplyError (const char * msg)
{
2019-05-29 16:05:03 +00:00
std::ostream os(&m_SendBuffer);
os << "ERROR " << msg << std::endl;
Send ();
2014-12-02 21:45:51 +00:00
}
2018-01-06 03:48:51 +00:00
2014-12-05 21:03:43 +00:00
void BOBCommandSession::SendVersion ()
{
2019-05-29 16:05:03 +00:00
std::ostream os(&m_SendBuffer);
os << "BOB 00.00.10" << std::endl;
SendReplyOK();
}
void BOBCommandSession::SendRaw (const char * data)
2019-05-29 16:05:03 +00:00
{
std::ostream os(&m_SendBuffer);
os << data << std::endl;
2019-05-29 16:05:03 +00:00
}
void BOBCommandSession::BuildStatusLine(bool currentTunnel, std::shared_ptr<BOBDestination> dest, std::string &out)
2019-05-29 16:05:03 +00:00
{
// helper lambdas
const auto issetStr = [](const std::string &str) { return str.empty() ? "not_set" : str; }; // for inhost, outhost
const auto issetNum = [&issetStr](const int p) { return issetStr(p == 0 ? "" : std::to_string(p)); }; // for inport, outport
2019-05-29 16:05:03 +00:00
const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; };
const auto destReady = [](const BOBDestination * const dest) { return dest && dest->IsRunning(); };
2019-05-29 16:05:03 +00:00
const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str
2019-05-29 16:05:03 +00:00
// tunnel info
const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname();
const bool quiet = currentTunnel ? m_IsQuiet : dest->GetQuiet();
const std::string inhost = issetStr(currentTunnel ? m_InHost : dest->GetInHost());
const std::string outhost = issetStr(currentTunnel ? m_OutHost : dest->GetOutHost());
2019-05-29 16:05:03 +00:00
const std::string inport = issetNum(currentTunnel ? m_InPort : dest->GetInPort());
const std::string outport = issetNum(currentTunnel ? m_OutPort : dest->GetOutPort());
const bool keys = destExists(dest.get ()); // key must exist when destination is created
const bool starting = destExists(dest.get ()) && !destReady(dest.get ());
const bool running = destExists(dest.get ()) && destReady(dest.get ());
2019-05-29 16:05:03 +00:00
const bool stopping = false;
2019-05-29 16:05:03 +00:00
// build line
std::stringstream ss;
ss << "DATA "
<< "NICKNAME: " << nickname << " " << "STARTING: " << bool_str(starting) << " "
2019-05-29 16:05:03 +00:00
<< "RUNNING: " << bool_str(running) << " " << "STOPPING: " << bool_str(stopping) << " "
<< "KEYS: " << bool_str(keys) << " " << "QUIET: " << bool_str(quiet) << " "
<< "INPORT: " << inport << " " << "INHOST: " << inhost << " "
<< "OUTPORT: " << outport << " " << "OUTHOST: " << outhost;
out = ss.str();
2014-12-06 03:25:31 +00:00
}
2018-01-06 03:48:51 +00:00
2014-12-02 20:47:44 +00:00
void BOBCommandSession::ZapCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: zap");
2014-12-02 21:45:51 +00:00
Terminate ();
}
void BOBCommandSession::QuitCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: quit");
2014-12-02 20:47:44 +00:00
m_IsOpen = false;
2014-12-02 21:45:51 +00:00
SendReplyOK ("Bye!");
2014-12-02 20:47:44 +00:00
}
2014-12-03 02:45:01 +00:00
void BOBCommandSession::StartCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: start ", m_Nickname);
2016-07-21 18:02:13 +00:00
if (m_IsActive)
{
SendReplyError ("tunnel is active");
2018-01-06 03:48:51 +00:00
return;
2016-07-21 18:02:13 +00:00
}
2019-05-29 16:05:03 +00:00
if (!m_Keys.GetPublic ()) // keys are set ?
{
SendReplyError("Keys must be set.");
return;
}
if (m_InPort == 0
&& m_OutHost.empty() && m_OutPort == 0)
{
SendReplyError("(inhost):inport or outhost:outport must be set.");
return;
}
if(!m_InHost.empty())
{
// TODO: FIXME: temporary validation, until hostname support is added
boost::system::error_code ec;
boost::asio::ip::address::from_string(m_InHost, ec);
if (ec)
{
SendReplyError("inhost must be a valid IPv4 address.");
return;
}
}
if(!m_OutHost.empty())
{
// TODO: FIXME: temporary validation, until hostname support is added
boost::system::error_code ec;
boost::asio::ip::address::from_string(m_OutHost, ec);
if (ec)
{
SendReplyError("outhost must be a IPv4 address.");
return;
}
}
2014-12-08 02:04:02 +00:00
if (!m_CurrentDestination)
2018-01-06 03:48:51 +00:00
{
m_CurrentDestination = std::make_shared<BOBDestination> (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options), // deleted in clear command
m_Nickname, m_InHost, m_OutHost, m_InPort, m_OutPort, m_IsQuiet);
2014-12-08 02:04:02 +00:00
m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
2018-01-06 03:48:51 +00:00
}
if (m_InPort)
2019-05-29 16:05:03 +00:00
m_CurrentDestination->CreateInboundTunnel (m_InPort, m_InHost);
if (m_OutPort && !m_OutHost.empty ())
m_CurrentDestination->CreateOutboundTunnel (m_OutHost, m_OutPort, m_IsQuiet);
2018-01-06 03:48:51 +00:00
m_CurrentDestination->Start ();
2016-07-21 18:02:13 +00:00
SendReplyOK ("Tunnel starting");
m_IsActive = true;
2018-01-06 03:48:51 +00:00
}
2016-07-11 18:35:59 +00:00
2014-12-03 20:24:30 +00:00
void BOBCommandSession::StopCommandHandler (const char * operand, size_t len)
{
2016-07-21 18:02:13 +00:00
LogPrint (eLogDebug, "BOB: stop ", m_Nickname);
if (!m_IsActive)
{
SendReplyError ("tunnel is inactive");
return;
}
auto dest = m_Owner.FindDestination (m_Nickname);
if (dest)
2014-12-03 20:24:30 +00:00
{
2014-12-08 02:04:02 +00:00
dest->StopTunnels ();
2016-07-21 18:02:13 +00:00
SendReplyOK ("Tunnel stopping");
2014-12-03 20:24:30 +00:00
}
else
SendReplyError ("tunnel not found");
2016-07-21 18:02:13 +00:00
m_IsActive = false;
2018-01-06 03:48:51 +00:00
}
2014-12-03 02:45:01 +00:00
void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: setnick ", operand);
if(*operand)
{
auto dest = m_Owner.FindDestination (operand);
if (!dest)
{
m_Nickname = operand;
std::string msg ("Nickname set to ");
msg += m_Nickname;
SendReplyOK (msg.c_str ());
}
else
SendReplyError ("tunnel is active");
}
else
SendReplyError ("no nickname has been set");
2018-01-06 03:48:51 +00:00
}
2014-12-03 02:45:01 +00:00
2014-12-03 20:24:30 +00:00
void BOBCommandSession::GetNickCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: getnick ", operand);
if(*operand)
2018-01-06 03:48:51 +00:00
{
m_CurrentDestination = m_Owner.FindDestination (operand);
if (m_CurrentDestination)
{
m_Keys = m_CurrentDestination->GetKeys ();
m_IsActive = m_CurrentDestination->IsRunning ();
m_Nickname = operand;
}
if (m_Nickname == operand)
{
std::string msg ("Nickname set to ");
msg += m_Nickname;
SendReplyOK (msg.c_str ());
}
else
SendReplyError ("no nickname has been set");
2018-01-06 03:48:51 +00:00
}
2014-12-03 20:24:30 +00:00
else
2018-01-06 03:48:51 +00:00
SendReplyError ("no nickname has been set");
}
2014-12-03 20:24:30 +00:00
2014-12-03 02:45:01 +00:00
void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len)
{
2018-01-06 03:48:51 +00:00
LogPrint (eLogDebug, "BOB: newkeys");
i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1;
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
2017-12-01 21:25:32 +00:00
if (*operand)
{
try
{
char * operand1 = (char *)strchr (operand, ' ');
2018-01-06 03:48:51 +00:00
if (operand1)
2017-12-01 21:25:32 +00:00
{
*operand1 = 0; operand1++;
cryptoType = std::stoi(operand1);
}
2018-01-06 03:48:51 +00:00
signatureType = std::stoi(operand);
2017-12-01 21:25:32 +00:00
}
catch (std::invalid_argument& ex)
{
LogPrint (eLogWarning, "BOB: Error on newkeys: ", ex.what ());
2017-12-01 21:25:32 +00:00
}
2018-01-06 03:48:51 +00:00
}
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType, true);
2015-11-03 14:15:49 +00:00
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
2018-01-06 03:48:51 +00:00
}
2014-12-03 02:45:01 +00:00
2014-12-04 02:01:40 +00:00
void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: setkeys ", operand);
if (*operand && m_Keys.FromBase64 (operand))
2017-03-25 20:53:20 +00:00
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
else
SendReplyError ("invalid keys");
2014-12-04 02:01:40 +00:00
}
2018-01-06 03:48:51 +00:00
2014-12-04 02:01:40 +00:00
void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len)
2018-01-06 03:48:51 +00:00
{
2014-12-04 02:01:40 +00:00
LogPrint (eLogDebug, "BOB: getkeys");
2016-10-11 14:18:42 +00:00
if (m_Keys.GetPublic ()) // keys are set ?
SendReplyOK (m_Keys.ToBase64 ().c_str ());
else
SendReplyError ("keys are not set");
}
2014-12-04 02:01:40 +00:00
void BOBCommandSession::GetdestCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: getdest");
2017-11-10 14:49:50 +00:00
if (m_Keys.GetPublic ()) // keys are set ?
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
else
SendReplyError ("keys are not set");
2018-01-06 03:48:51 +00:00
}
2014-12-03 02:45:01 +00:00
void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: outhost ", operand);
if (*operand)
{
m_OutHost = operand;
SendReplyOK ("outhost set");
}
else
SendReplyError ("empty outhost");
2014-12-03 02:45:01 +00:00
}
2018-01-06 03:48:51 +00:00
2014-12-03 02:45:01 +00:00
void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: outport ", operand);
if (*operand)
{
int port = std::stoi(operand);
if (port >= 0 && port < 65536)
{
m_OutPort = port;
SendReplyOK ("outbound port set");
}
else
SendReplyError ("port out of range");
}
2016-07-21 18:02:13 +00:00
else
SendReplyError ("empty outport");
2018-01-06 03:48:51 +00:00
}
2014-12-03 20:02:19 +00:00
void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: inhost ", operand);
if (*operand)
{
m_InHost = operand;
SendReplyOK ("inhost set");
}
else
SendReplyError ("empty inhost");
2014-12-03 20:02:19 +00:00
}
2018-01-06 03:48:51 +00:00
2014-12-03 20:02:19 +00:00
void BOBCommandSession::InportCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: inport ", operand);
if (*operand)
{
int port = std::stoi(operand);
if (port >= 0 && port < 65536)
{
m_InPort = port;
SendReplyOK ("inbound port set");
}
else
SendReplyError ("port out of range");
}
2016-07-21 18:02:13 +00:00
else
SendReplyError ("empty inport");
2018-01-06 03:48:51 +00:00
}
2014-12-05 19:13:16 +00:00
void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: quiet");
2016-07-21 18:02:13 +00:00
if (m_Nickname.length () > 0)
{
if (!m_IsActive)
{
m_IsQuiet = true;
SendReplyOK ("Quiet set");
}
else
SendReplyError ("tunnel is active");
}
else
SendReplyError ("no nickname has been set");
2018-01-06 03:48:51 +00:00
}
2014-12-05 21:03:43 +00:00
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: lookup ", operand);
if (*operand)
{
auto addr = context.GetAddressBook ().GetAddress (operand);
if (!addr)
{
SendReplyError ("Address Not found");
2019-03-28 16:19:19 +00:00
return;
}
auto localDestination = (m_CurrentDestination && m_CurrentDestination->IsRunning ()) ?
m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
2023-07-06 16:30:33 +00:00
if (!localDestination)
{
SendReplyError ("No local destination");
return;
}
if (addr->IsIdentHash ())
{
// we might have leaseset already
auto leaseSet = localDestination->FindLeaseSet (addr->identHash);
if (leaseSet)
{
SendReplyOK (leaseSet->GetIdentity ()->ToBase64 ().c_str ());
return;
}
}
// trying to request
auto s = shared_from_this ();
auto requstCallback = [s](std::shared_ptr<i2p::data::LeaseSet> ls)
{
if (ls)
s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
else
s->SendReplyError ("LeaseSet Not found");
};
if (addr->IsIdentHash ())
localDestination->RequestDestination (addr->identHash, requstCallback);
else
localDestination->RequestDestinationWithEncryptedLeaseSet (addr->blindedPublicKey, requstCallback);
}
2019-03-28 16:19:19 +00:00
else
SendReplyError ("empty lookup address");
2014-12-05 21:03:43 +00:00
}
2021-02-21 21:20:57 +00:00
void BOBCommandSession::LookupLocalCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: lookup local ", operand);
if (*operand)
2021-02-21 21:20:57 +00:00
{
auto addr = context.GetAddressBook ().GetAddress (operand);
if (!addr)
{
SendReplyError ("Address Not found");
return;
}
auto ls = i2p::data::netdb.FindLeaseSet (addr->identHash);
if (ls)
SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
else
SendReplyError ("Local LeaseSet Not found");
2021-02-21 21:20:57 +00:00
}
else
SendReplyError ("empty lookup address");
2021-02-21 21:20:57 +00:00
}
2014-12-06 00:16:54 +00:00
void BOBCommandSession::ClearCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: clear");
2014-12-08 02:04:02 +00:00
m_Owner.DeleteDestination (m_Nickname);
2016-07-21 18:02:13 +00:00
m_Nickname = "";
2014-12-06 00:16:54 +00:00
SendReplyOK ("cleared");
2018-01-06 03:48:51 +00:00
}
2014-12-05 21:03:43 +00:00
2014-12-06 03:25:31 +00:00
void BOBCommandSession::ListCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: list");
2019-05-29 16:05:03 +00:00
std::string statusLine;
bool sentCurrent = false;
2016-08-05 18:23:54 +00:00
const auto& destinations = m_Owner.GetDestinations ();
for (const auto& it: destinations)
2019-05-29 16:05:03 +00:00
{
BuildStatusLine(false, it.second, statusLine);
SendRaw(statusLine.c_str());
2019-05-29 16:05:03 +00:00
if(m_Nickname.compare(it.second->GetNickname()) == 0)
sentCurrent = true;
}
if(!sentCurrent && !m_Nickname.empty())
{
// add the current tunnel to the list.
// this is for the incomplete tunnel which has not been started yet.
BuildStatusLine(true, m_CurrentDestination, statusLine);
SendRaw(statusLine.c_str());
2019-05-29 16:05:03 +00:00
}
2014-12-06 03:25:31 +00:00
SendReplyOK ("Listing done");
2018-01-06 03:48:51 +00:00
}
2014-12-06 03:25:31 +00:00
void BOBCommandSession::OptionCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: option ", operand);
2014-12-06 20:31:39 +00:00
const char * value = strchr (operand, '=');
if (value)
2018-01-06 03:48:51 +00:00
{
2016-07-21 18:02:13 +00:00
std::string msg ("option ");
2014-12-06 20:31:39 +00:00
*(const_cast<char *>(value)) = 0;
2018-01-06 03:48:51 +00:00
m_Options[operand] = value + 1;
2016-07-21 18:02:13 +00:00
msg += operand;
2014-12-06 20:31:39 +00:00
*(const_cast<char *>(value)) = '=';
2016-07-21 18:02:13 +00:00
msg += " set to ";
msg += value + 1;
2016-07-21 18:02:13 +00:00
SendReplyOK (msg.c_str ());
2018-01-06 03:48:51 +00:00
}
2014-12-06 20:31:39 +00:00
else
SendReplyError ("malformed");
2018-01-06 03:48:51 +00:00
}
2016-07-16 13:31:33 +00:00
void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len)
{
LogPrint (eLogDebug, "BOB: status ", operand);
2019-06-25 17:18:40 +00:00
const std::string name = operand;
2019-05-29 16:05:03 +00:00
std::string statusLine;
2019-06-25 17:18:40 +00:00
// always prefer destination
auto dest = m_Owner.FindDestination(name);
if(dest)
2016-07-19 15:08:28 +00:00
{
2019-06-25 17:18:40 +00:00
// tunnel destination exists
BuildStatusLine(false, dest, statusLine);
2019-05-29 16:05:03 +00:00
SendReplyOK(statusLine.c_str());
}
else
{
2019-06-25 17:18:40 +00:00
if(m_Nickname == name && !name.empty())
2018-01-06 03:48:51 +00:00
{
2019-06-25 17:18:40 +00:00
// tunnel is incomplete / has not been started yet
BuildStatusLine(true, nullptr, statusLine);
2019-05-29 16:05:03 +00:00
SendReplyOK(statusLine.c_str());
2018-01-06 03:48:51 +00:00
}
2016-07-19 15:08:28 +00:00
else
2018-01-06 03:48:51 +00:00
{
2019-05-29 16:05:03 +00:00
SendReplyError("no nickname has been set");
2018-01-06 03:48:51 +00:00
}
2019-05-29 16:05:03 +00:00
}
}
void BOBCommandSession::HelpCommandHandler (const char * operand, size_t len)
{
auto helpStrings = m_Owner.GetHelpStrings();
if(!*operand)
2019-05-29 16:05:03 +00:00
{
std::stringstream ss;
ss << "COMMANDS:";
for (auto const& x : helpStrings)
2018-01-06 03:48:51 +00:00
{
2019-05-29 16:05:03 +00:00
ss << " " << x.first;
2018-01-06 03:48:51 +00:00
}
2019-05-29 16:05:03 +00:00
const std::string &str = ss.str();
SendReplyOK(str.c_str());
2016-07-19 15:08:28 +00:00
}
2016-07-16 13:31:33 +00:00
else
2019-05-29 16:05:03 +00:00
{
auto it = helpStrings.find(operand);
if (it != helpStrings.end ())
{
SendReplyOK(it->second.c_str());
return;
}
SendReplyError("No such command");
}
2018-01-06 03:48:51 +00:00
}
BOBCommandChannel::BOBCommandChannel (const std::string& address, uint16_t port):
RunnableService ("BOB"),
m_Acceptor (GetIOService (), boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
2014-12-02 15:34:02 +00:00
{
2014-12-03 02:45:01 +00:00
// command -> handler
2018-01-06 03:48:51 +00:00
m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler;
2014-12-02 21:45:51 +00:00
m_CommandHandlers[BOB_COMMAND_QUIT] = &BOBCommandSession::QuitCommandHandler;
2014-12-03 02:45:01 +00:00
m_CommandHandlers[BOB_COMMAND_START] = &BOBCommandSession::StartCommandHandler;
2014-12-03 20:24:30 +00:00
m_CommandHandlers[BOB_COMMAND_STOP] = &BOBCommandSession::StopCommandHandler;
2014-12-03 02:45:01 +00:00
m_CommandHandlers[BOB_COMMAND_SETNICK] = &BOBCommandSession::SetNickCommandHandler;
2014-12-03 20:24:30 +00:00
m_CommandHandlers[BOB_COMMAND_GETNICK] = &BOBCommandSession::GetNickCommandHandler;
2014-12-03 02:45:01 +00:00
m_CommandHandlers[BOB_COMMAND_NEWKEYS] = &BOBCommandSession::NewkeysCommandHandler;
2014-12-04 02:01:40 +00:00
m_CommandHandlers[BOB_COMMAND_GETKEYS] = &BOBCommandSession::GetkeysCommandHandler;
m_CommandHandlers[BOB_COMMAND_SETKEYS] = &BOBCommandSession::SetkeysCommandHandler;
m_CommandHandlers[BOB_COMMAND_GETDEST] = &BOBCommandSession::GetdestCommandHandler;
2014-12-03 02:45:01 +00:00
m_CommandHandlers[BOB_COMMAND_OUTHOST] = &BOBCommandSession::OuthostCommandHandler;
m_CommandHandlers[BOB_COMMAND_OUTPORT] = &BOBCommandSession::OutportCommandHandler;
2014-12-03 20:02:19 +00:00
m_CommandHandlers[BOB_COMMAND_INHOST] = &BOBCommandSession::InhostCommandHandler;
m_CommandHandlers[BOB_COMMAND_INPORT] = &BOBCommandSession::InportCommandHandler;
2014-12-05 19:13:16 +00:00
m_CommandHandlers[BOB_COMMAND_QUIET] = &BOBCommandSession::QuietCommandHandler;
2014-12-05 21:03:43 +00:00
m_CommandHandlers[BOB_COMMAND_LOOKUP] = &BOBCommandSession::LookupCommandHandler;
m_CommandHandlers[BOB_COMMAND_LOOKUP_LOCAL] = &BOBCommandSession::LookupLocalCommandHandler;
2014-12-06 00:16:54 +00:00
m_CommandHandlers[BOB_COMMAND_CLEAR] = &BOBCommandSession::ClearCommandHandler;
2014-12-06 03:25:31 +00:00
m_CommandHandlers[BOB_COMMAND_LIST] = &BOBCommandSession::ListCommandHandler;
m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler;
2016-07-16 13:31:33 +00:00
m_CommandHandlers[BOB_COMMAND_STATUS] = &BOBCommandSession::StatusCommandHandler;
2019-05-29 16:05:03 +00:00
m_CommandHandlers[BOB_COMMAND_HELP] = &BOBCommandSession::HelpCommandHandler;
// command -> help string
m_HelpStrings[BOB_COMMAND_ZAP] = BOB_HELP_ZAP;
m_HelpStrings[BOB_COMMAND_QUIT] = BOB_HELP_QUIT;
m_HelpStrings[BOB_COMMAND_START] = BOB_HELP_START;
m_HelpStrings[BOB_COMMAND_STOP] = BOB_HELP_STOP;
m_HelpStrings[BOB_COMMAND_SETNICK] = BOB_HELP_SETNICK;
m_HelpStrings[BOB_COMMAND_GETNICK] = BOB_HELP_GETNICK;
m_HelpStrings[BOB_COMMAND_NEWKEYS] = BOB_HELP_NEWKEYS;
m_HelpStrings[BOB_COMMAND_GETKEYS] = BOB_HELP_GETKEYS;
m_HelpStrings[BOB_COMMAND_SETKEYS] = BOB_HELP_SETKEYS;
m_HelpStrings[BOB_COMMAND_GETDEST] = BOB_HELP_GETDEST;
m_HelpStrings[BOB_COMMAND_OUTHOST] = BOB_HELP_OUTHOST;
m_HelpStrings[BOB_COMMAND_OUTPORT] = BOB_HELP_OUTPORT;
m_HelpStrings[BOB_COMMAND_INHOST] = BOB_HELP_INHOST;
m_HelpStrings[BOB_COMMAND_INPORT] = BOB_HELP_INPORT;
m_HelpStrings[BOB_COMMAND_QUIET] = BOB_HELP_QUIET;
m_HelpStrings[BOB_COMMAND_LOOKUP] = BOB_HELP_LOOKUP;
m_HelpStrings[BOB_COMMAND_CLEAR] = BOB_HELP_CLEAR;
m_HelpStrings[BOB_COMMAND_LIST] = BOB_HELP_LIST;
m_HelpStrings[BOB_COMMAND_OPTION] = BOB_HELP_OPTION;
m_HelpStrings[BOB_COMMAND_STATUS] = BOB_HELP_STATUS;
m_HelpStrings[BOB_COMMAND_HELP] = BOB_HELP_HELP;
2014-12-02 15:34:02 +00:00
}
BOBCommandChannel::~BOBCommandChannel ()
{
if (IsRunning ())
Stop ();
2014-12-02 16:42:35 +00:00
}
void BOBCommandChannel::Start ()
{
Accept ();
StartIOService ();
2014-12-02 16:42:35 +00:00
}
void BOBCommandChannel::Stop ()
{
2016-08-05 18:23:54 +00:00
for (auto& it: m_Destinations)
2014-12-03 20:24:30 +00:00
it.second->Stop ();
2018-01-06 03:48:51 +00:00
m_Acceptor.cancel ();
StopIOService ();
2014-12-02 16:42:35 +00:00
}
void BOBCommandChannel::AddDestination (const std::string& name, std::shared_ptr<BOBDestination> dest)
2014-12-03 02:45:01 +00:00
{
m_Destinations.emplace (name, dest);
2018-01-06 03:48:51 +00:00
}
2014-12-03 20:24:30 +00:00
2014-12-08 02:04:02 +00:00
void BOBCommandChannel::DeleteDestination (const std::string& name)
{
auto it = m_Destinations.find (name);
if (it != m_Destinations.end ())
{
it->second->Stop ();
m_Destinations.erase (it);
2018-01-06 03:48:51 +00:00
}
}
std::shared_ptr<BOBDestination> BOBCommandChannel::FindDestination (const std::string& name)
2014-12-03 20:24:30 +00:00
{
auto it = m_Destinations.find (name);
if (it != m_Destinations.end ())
2014-12-03 20:24:30 +00:00
return it->second;
2018-01-06 03:48:51 +00:00
return nullptr;
2014-12-03 20:24:30 +00:00
}
2018-01-06 03:48:51 +00:00
2014-12-02 16:42:35 +00:00
void BOBCommandChannel::Accept ()
{
2014-12-02 20:47:44 +00:00
auto newSession = std::make_shared<BOBCommandSession> (*this);
m_Acceptor.async_accept (newSession->GetSocket (), std::bind (&BOBCommandChannel::HandleAccept, this,
std::placeholders::_1, newSession));
2014-12-02 16:42:35 +00:00
}
2014-12-02 20:47:44 +00:00
void BOBCommandChannel::HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session)
2014-12-02 16:42:35 +00:00
{
if (ecode != boost::asio::error::operation_aborted)
Accept ();
if (!ecode)
{
2015-12-18 06:27:35 +00:00
LogPrint (eLogInfo, "BOB: New command connection from ", session->GetSocket ().remote_endpoint ());
2018-01-06 03:48:51 +00:00
session->SendVersion ();
2014-12-02 16:42:35 +00:00
}
else
LogPrint (eLogError, "BOB: Accept error: ", ecode.message ());
2014-12-02 15:34:02 +00:00
}
}
}