i2pd/libi2pd_client/BOB.h
nobs2p 1b068618ba
Add settunneltype parameter to BOB API for i2pd to configure proxy tunnel type
This update introduces the settunneltype <socks|httpproxy> command to the BOB API, allowing users to specify the tunnel type as either SOCKS or HTTP proxy. When the tunnel type is set, the corresponding proxy service is automatically started. This enhances flexibility in tunnel configuration through the BOB interface.

Signed-off-by: nobs2p <nobs2p@i2pmail.org>
2025-05-29 12:35:10 +03:00

318 lines
12 KiB
C++

/*
* Copyright (c) 2013-2025, 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
*/
#ifndef BOB_H__
#define BOB_H__
#include <inttypes.h>
#include <thread>
#include <memory>
#include <map>
#include <string>
#include <optional>
#include <boost/asio.hpp>
#include "util.h"
#include "I2PTunnel.h"
#include "I2PService.h"
#include "Identity.h"
#include "LeaseSet.h"
#include "SOCKS.h"
#include "HTTPProxy.h"
namespace i2p
{
namespace client
{
const size_t BOB_COMMAND_BUFFER_SIZE = 1024;
const char BOB_COMMAND_ZAP[] = "zap";
const char BOB_COMMAND_QUIT[] = "quit";
const char BOB_COMMAND_START[] = "start";
const char BOB_COMMAND_STOP[] = "stop";
const char BOB_COMMAND_SETNICK[] = "setnick";
const char BOB_COMMAND_GETNICK[] = "getnick";
const char BOB_COMMAND_NEWKEYS[] = "newkeys";
const char BOB_COMMAND_GETKEYS[] = "getkeys";
const char BOB_COMMAND_SETKEYS[] = "setkeys";
const char BOB_COMMAND_GETDEST[] = "getdest";
const char BOB_COMMAND_OUTHOST[] = "outhost";
const char BOB_COMMAND_OUTPORT[] = "outport";
const char BOB_COMMAND_INHOST[] = "inhost";
const char BOB_COMMAND_INPORT[] = "inport";
const char BOB_COMMAND_QUIET[] = "quiet";
const char BOB_COMMAND_LOOKUP[] = "lookup";
const char BOB_COMMAND_LOOKUP_LOCAL[] = "lookuplocal";
const char BOB_COMMAND_CLEAR[] = "clear";
const char BOB_COMMAND_LIST[] = "list";
const char BOB_COMMAND_OPTION[] = "option";
const char BOB_COMMAND_STATUS[] = "status";
const char BOB_COMMAND_HELP[] = "help";
const char BOB_COMMAND_SETTUNNELTYPE[] = "settunneltype";
const char BOB_HELP_ZAP[] = "zap - Shuts down BOB.";
const char BOB_HELP_QUIT[] = "quit - Quits this session with BOB.";
const char BOB_HELP_START[] = "start - Starts the current nicknamed tunnel.";
const char BOB_HELP_STOP[] = "stop - Stops the current nicknamed tunnel.";
const char BOB_HELP_SETNICK[] = "setnick <NICKNAME> - Creates a new nickname.";
const char BOB_HELP_GETNICK[] = "getnick <TUNNELNAME> - Sets the nickname from the database.";
const char BOB_HELP_NEWKEYS[] = "newkeys - Generate a new keypair for the current nickname.";
const char BOB_HELP_GETKEYS[] = "getkeys - Return the keypair for the current nickname.";
const char BOB_HELP_SETKEYS[] = "setkeys <BASE64_KEYPAIR> - Sets the keypair for the current nickname.";
const char BOB_HELP_GETDEST[] = "getdest - Return the destination for the current nickname.";
const char BOB_HELP_OUTHOST[] = "outhost <HOSTNAME|IP> - Set the outhound hostname or IP.";
const char BOB_HELP_OUTPORT[] = "outport <PORT_NUMBER> - Set the outbound port that nickname contacts.";
const char BOB_HELP_INHOST[] = "inhost <HOSTNAME|IP> - Set the inbound hostname or IP.";
const char BOB_HELP_INPORT[] = "inport <PORT_NUMBER> - Set the inbound port number nickname listens on.";
const char BOB_HELP_QUIET[] = "quiet <True|False> - Whether to send the incoming destination.";
const char BOB_HELP_LOOKUP[] = "lookup <I2P_HOSTNAME> - Look up an I2P hostname.";
const char BOB_HELP_CLEAR[] = "clear - Clear the current nickname out of the list.";
const char BOB_HELP_LIST[] = "list - List all tunnels.";
const char BOB_HELP_OPTION[] = "option <KEY>=<VALUE> - Set an option. NOTE: Don't use any spaces.";
const char BOB_HELP_STATUS[] = "status <NICKNAME> - Display status of a nicknamed tunnel.";
const char BOB_HELP_HELP [] = "help <COMMAND> - Get help on a command.";
const char BOB_HELP_SETTUNNELTYPE[] = "settunneltype <socks|httpproxy> - Sets socks or http proxy tunnel type.";
class BOBI2PTunnelIncomingConnection: public I2PTunnelConnection
{
public:
BOBI2PTunnelIncomingConnection (I2PService * owner, std::shared_ptr<i2p::stream::Stream> stream,
const boost::asio::ip::tcp::endpoint& target, bool quiet):
I2PTunnelConnection (owner, stream, target), m_IsQuiet (quiet) {};
protected:
void Established () override;
private:
bool m_IsQuiet; // don't send destination
};
class BOBI2PTunnel: public I2PService
{
public:
BOBI2PTunnel (std::shared_ptr<ClientDestination> localDestination):
I2PService (localDestination) {};
virtual void Start () {};
virtual void Stop () {};
};
class BOBI2PInboundTunnel: public BOBI2PTunnel
{
struct AddressReceiver
{
std::shared_ptr<boost::asio::ip::tcp::socket> socket;
char buffer[BOB_COMMAND_BUFFER_SIZE + 1]; // for destination base64 address
uint8_t * data; // pointer to buffer
size_t dataLen, bufferOffset;
AddressReceiver (): data (nullptr), dataLen (0), bufferOffset (0) {};
};
public:
BOBI2PInboundTunnel (const boost::asio::ip::tcp::endpoint& ep, std::shared_ptr<ClientDestination> localDestination);
~BOBI2PInboundTunnel ();
void Start ();
void Stop ();
private:
void Accept ();
void HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver);
void ReceiveAddress (std::shared_ptr<AddressReceiver> receiver);
void HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<AddressReceiver> receiver);
void HandleDestinationRequestComplete (std::shared_ptr<i2p::data::LeaseSet> leaseSet, std::shared_ptr<AddressReceiver> receiver);
void CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet);
private:
boost::asio::ip::tcp::acceptor m_Acceptor;
};
class BOBI2POutboundTunnel: public BOBI2PTunnel
{
public:
BOBI2POutboundTunnel (const std::string& outhost, uint16_t port, std::shared_ptr<ClientDestination> localDestination, bool quiet);
void Start ();
void Stop ();
void SetQuiet () { m_IsQuiet = true; };
private:
void Accept ();
void HandleAccept (std::shared_ptr<i2p::stream::Stream> stream);
private:
boost::asio::ip::tcp::endpoint m_Endpoint;
bool m_IsQuiet;
};
class BOBDestination
{
public:
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);
~BOBDestination ();
void Start ();
void Stop ();
void StopTunnels ();
void CreateInboundTunnel (uint16_t port, const std::string& inhost);
void CreateOutboundTunnel (const std::string& outhost, uint16_t port, bool quiet);
const std::string& GetNickname() const { return m_Nickname; }
const std::string& GetInHost() const { return m_InHost; }
const std::string& GetOutHost() const { return m_OutHost; }
uint16_t GetInPort() const { return m_InPort; }
uint16_t GetOutPort() const { return m_OutPort; }
bool GetQuiet() const { return m_Quiet; }
bool IsRunning() const { return m_IsRunning; }
const i2p::data::PrivateKeys& GetKeys () const { return m_LocalDestination->GetPrivateKeys (); };
std::shared_ptr<ClientDestination> GetLocalDestination () const { return m_LocalDestination; };
private:
std::shared_ptr<ClientDestination> m_LocalDestination;
BOBI2POutboundTunnel * m_OutboundTunnel;
BOBI2PInboundTunnel * m_InboundTunnel;
std::string m_Nickname;
std::string m_InHost, m_OutHost;
uint16_t m_InPort, m_OutPort;
bool m_Quiet;
bool m_IsRunning;
};
class BOBCommandChannel;
class BOBCommandSession: public std::enable_shared_from_this<BOBCommandSession>
{
public:
BOBCommandSession (BOBCommandChannel& owner);
~BOBCommandSession ();
void Terminate ();
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
void SendVersion ();
// command handlers
void ZapCommandHandler (const char * operand, size_t len);
void QuitCommandHandler (const char * operand, size_t len);
void StartCommandHandler (const char * operand, size_t len);
void StopCommandHandler (const char * operand, size_t len);
void SetNickCommandHandler (const char * operand, size_t len);
void GetNickCommandHandler (const char * operand, size_t len);
void NewkeysCommandHandler (const char * operand, size_t len);
void SetkeysCommandHandler (const char * operand, size_t len);
void GetkeysCommandHandler (const char * operand, size_t len);
void GetdestCommandHandler (const char * operand, size_t len);
void OuthostCommandHandler (const char * operand, size_t len);
void OutportCommandHandler (const char * operand, size_t len);
void InhostCommandHandler (const char * operand, size_t len);
void InportCommandHandler (const char * operand, size_t len);
void QuietCommandHandler (const char * operand, size_t len);
void LookupCommandHandler (const char * operand, size_t len);
void LookupLocalCommandHandler (const char * operand, size_t len);
void ClearCommandHandler (const char * operand, size_t len);
void ListCommandHandler (const char * operand, size_t len);
void OptionCommandHandler (const char * operand, size_t len);
void StatusCommandHandler (const char * operand, size_t len);
void HelpCommandHandler (const char * operand, size_t len);
void SetTunnelTypeCommandHandler (const char * operand, size_t len);
private:
void Receive ();
void HandleReceivedLine(const boost::system::error_code& ecode, std::size_t bytes_transferred);
void HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void Send ();
void HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
void SendReplyOK (const char * msg = nullptr);
void SendReplyError (const char * msg);
void SendRaw (const char * data);
void BuildStatusLine(bool currentTunnel, std::shared_ptr<BOBDestination> destination, std::string &out);
private:
BOBCommandChannel& m_Owner;
boost::asio::ip::tcp::socket m_Socket;
boost::asio::streambuf m_ReceiveBuffer, m_SendBuffer;
bool m_IsOpen, m_IsQuiet, m_IsActive;
std::string m_Nickname, m_InHost, m_OutHost;
uint16_t m_InPort, m_OutPort;
i2p::data::PrivateKeys m_Keys;
std::map<std::string, std::string> m_Options;
std::shared_ptr<BOBDestination> m_CurrentDestination;
enum class TunnelType
{
SOCKS = 0,
HTTP_PROXY = 1
};
std::optional<TunnelType> m_tunnelType;
};
typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len);
class BOBCommandChannel: private i2p::util::RunnableService
{
public:
BOBCommandChannel (const std::string& address, uint16_t port);
~BOBCommandChannel ();
void Start ();
void Stop ();
auto& GetService () { return GetIOService (); };
void AddDestination (const std::string& name, std::shared_ptr<BOBDestination> dest);
void DeleteDestination (const std::string& name);
std::shared_ptr<BOBDestination> FindDestination (const std::string& name);
void SetProxy (const std::string& name, std::unique_ptr<I2PService> proxy);
const I2PService* GetProxy(const std::string& name) const;
void RemoveProxy(const std::string& name);
private:
void Accept ();
void HandleAccept(const boost::system::error_code& ecode, std::shared_ptr<BOBCommandSession> session);
private:
boost::asio::ip::tcp::acceptor m_Acceptor;
std::map<std::string, std::shared_ptr<BOBDestination> > m_Destinations;
std::map<std::string, BOBCommandHandler> m_CommandHandlers;
std::map<std::string, std::string> m_HelpStrings;
std::map<std::string, std::unique_ptr<I2PService>> m_proxy;
public:
const decltype(m_CommandHandlers)& GetCommandHandlers () const { return m_CommandHandlers; };
const decltype(m_HelpStrings)& GetHelpStrings () const { return m_HelpStrings; };
const decltype(m_Destinations)& GetDestinations () const { return m_Destinations; };
};
}
}
#endif