diff --git a/libi2pd_client/BOB.cpp b/libi2pd_client/BOB.cpp index 8d94e94b..3f02f779 100644 --- a/libi2pd_client/BOB.cpp +++ b/libi2pd_client/BOB.cpp @@ -383,6 +383,15 @@ namespace client const auto destExists = [](const BOBDestination * const dest) { return dest != nullptr; }; const auto destReady = [](const BOBDestination * const dest) { return dest && dest->IsRunning(); }; const auto bool_str = [](const bool v) { return v ? "true" : "false"; }; // bool -> str + const auto getProxyType = [](const i2p::client::I2PService* proxy) -> std::string { + if (!proxy) return "NONE"; + if (dynamic_cast(proxy)) return "SOCKS"; + if (dynamic_cast(proxy)) return "HTTPPROXY"; + return "UNKNOWN"; + }; + const auto isProxyRunning = [](const i2p::client::I2PService* proxy) -> bool { + return proxy != nullptr; + }; // tunnel info const std::string nickname = currentTunnel ? m_Nickname : dest->GetNickname(); @@ -395,6 +404,10 @@ namespace client const bool starting = destExists(dest.get ()) && !destReady(dest.get ()); const bool running = destExists(dest.get ()) && destReady(dest.get ()); const bool stopping = false; + + const i2p::client::I2PService* proxy = m_Owner.GetProxy(nickname); + const std::string proxyType = getProxyType(proxy); + const bool proxyStatus = isProxyRunning(proxy); // build line std::stringstream ss; @@ -403,7 +416,8 @@ namespace client << "RUNNING: " << bool_str(running) << " " << "STOPPING: " << bool_str(stopping) << " " << "KEYS: " << bool_str(keys) << " " << "QUIET: " << bool_str(quiet) << " " << "INPORT: " << inport << " " << "INHOST: " << inhost << " " - << "OUTPORT: " << outport << " " << "OUTHOST: " << outhost; + << "OUTPORT: " << outport << " " << "OUTHOST: " << outhost << " " + << "PROXYTYPE: "<< proxyType << " " << "PROXYSTART: " << bool_str(proxyStatus); out = ss.str(); } @@ -468,11 +482,51 @@ namespace client m_Nickname, m_InHost, m_OutHost, m_InPort, m_OutPort, m_IsQuiet); m_Owner.AddDestination (m_Nickname, m_CurrentDestination); } - if (m_InPort) - m_CurrentDestination->CreateInboundTunnel (m_InPort, m_InHost); - if (m_OutPort && !m_OutHost.empty ()) - m_CurrentDestination->CreateOutboundTunnel (m_OutHost, m_OutPort, m_IsQuiet); - m_CurrentDestination->Start (); + if (!m_tunnelType.has_value()) + { + if (m_InPort) + m_CurrentDestination->CreateInboundTunnel (m_InPort, m_InHost); + if (m_OutPort && !m_OutHost.empty ()) + m_CurrentDestination->CreateOutboundTunnel (m_OutHost, m_OutPort, m_IsQuiet); + m_CurrentDestination->Start (); + } + else + { + switch (*m_tunnelType) + { + case TunnelType::SOCKS: + try + { + auto SocksProxy = std::make_unique(m_Nickname, m_InHost, m_InPort, + false, m_OutHost, m_OutPort, m_CurrentDestination->GetLocalDestination()); + SocksProxy->Start(); + m_Owner.SetProxy(m_Nickname, std::move(SocksProxy)); + } + catch (std::exception& e) + { + LogPrint(eLogCritical, "Clients: Exception in SOCKS Proxy: ", e.what()); + ThrowFatal ("Unable to start SOCKS Proxy at ", m_InHost, ":", m_InPort, ": ", e.what ()); + } + break; + case TunnelType::HTTP_PROXY: + try + { + auto HttpProxy = std::make_unique(m_Nickname, m_InHost, m_InPort, + m_OutHost, true, true, m_CurrentDestination->GetLocalDestination()); + HttpProxy->Start(); + m_Owner.SetProxy(m_Nickname, std::move(HttpProxy)); + } + catch (std::exception& e) + { + LogPrint(eLogCritical, "Clients: Exception in HTTP Proxy: ", e.what()); + ThrowFatal ("Unable to start HTTP Proxy at ", m_InHost, ":", m_InPort, ": ", e.what ()); + } + break; + default: + SendReplyError("Unsupported tunnel type."); + return; + } + } SendReplyOK ("Tunnel starting"); m_IsActive = true; } @@ -486,10 +540,15 @@ namespace client return; } auto dest = m_Owner.FindDestination (m_Nickname); + auto proxy = m_Owner.GetProxy (m_Nickname); if (dest) { dest->StopTunnels (); SendReplyOK ("Tunnel stopping"); + if (proxy) + { + m_Owner.RemoveProxy (m_Nickname); + } } else SendReplyError ("tunnel not found"); @@ -522,10 +581,13 @@ namespace client if(*operand) { m_CurrentDestination = m_Owner.FindDestination (operand); + auto proxy = m_Owner.GetProxy (operand); if (m_CurrentDestination) { m_Keys = m_CurrentDestination->GetKeys (); m_IsActive = m_CurrentDestination->IsRunning (); + if(proxy) + m_IsActive = true; m_Nickname = operand; } if (m_Nickname == operand) @@ -843,6 +905,27 @@ namespace client SendReplyError("No such command"); } } + + void BOBCommandSession::SetTunnelTypeCommandHandler (const char * operand, size_t len) + { + std::string_view sv(operand, len); + LogPrint (eLogDebug, "BOB: settunneltype ", operand); + if (sv == "socks") + { + m_tunnelType = TunnelType::SOCKS; + SendReplyOK ("tunnel type set to SOCKS"); + } + else if (sv == "httpproxy") + { + m_tunnelType = TunnelType::HTTP_PROXY; + SendReplyOK ("tunnel type set to HTTP proxy"); + } + else + { + m_tunnelType.reset(); + SendReplyError ("no tunnel type has been set"); + } + } BOBCommandChannel::BOBCommandChannel (const std::string& address, uint16_t port): RunnableService ("BOB"), @@ -871,6 +954,7 @@ namespace client m_CommandHandlers[BOB_COMMAND_OPTION] = &BOBCommandSession::OptionCommandHandler; m_CommandHandlers[BOB_COMMAND_STATUS] = &BOBCommandSession::StatusCommandHandler; m_CommandHandlers[BOB_COMMAND_HELP] = &BOBCommandSession::HelpCommandHandler; + m_CommandHandlers[BOB_COMMAND_SETTUNNELTYPE] = &BOBCommandSession::SetTunnelTypeCommandHandler; // command -> help string m_HelpStrings[BOB_COMMAND_ZAP] = BOB_HELP_ZAP; m_HelpStrings[BOB_COMMAND_QUIT] = BOB_HELP_QUIT; @@ -893,6 +977,7 @@ namespace client m_HelpStrings[BOB_COMMAND_OPTION] = BOB_HELP_OPTION; m_HelpStrings[BOB_COMMAND_STATUS] = BOB_HELP_STATUS; m_HelpStrings[BOB_COMMAND_HELP] = BOB_HELP_HELP; + m_HelpStrings[BOB_COMMAND_SETTUNNELTYPE] = BOB_HELP_SETTUNNELTYPE; } BOBCommandChannel::~BOBCommandChannel () @@ -937,6 +1022,28 @@ namespace client return it->second; return nullptr; } + + void BOBCommandChannel::SetProxy (const std::string& name, std::unique_ptr proxy) + { + m_proxy[name] = std::move(proxy); + } + + const I2PService* BOBCommandChannel::GetProxy(const std::string& name) const + { + auto it = m_proxy.find(name); + if (it != m_proxy.end() && it->second) + return it->second.get(); + return nullptr; + } + + void BOBCommandChannel::RemoveProxy(const std::string& name) + { + auto it = m_proxy.find (name); + if (it != m_proxy.end ()) + { + m_proxy.erase (it); + } + } void BOBCommandChannel::Accept () { diff --git a/libi2pd_client/BOB.h b/libi2pd_client/BOB.h index f5aefd0a..7b92c85d 100644 --- a/libi2pd_client/BOB.h +++ b/libi2pd_client/BOB.h @@ -14,12 +14,15 @@ #include #include #include +#include #include #include "util.h" #include "I2PTunnel.h" #include "I2PService.h" #include "Identity.h" #include "LeaseSet.h" +#include "SOCKS.h" +#include "HTTPProxy.h" namespace i2p { @@ -48,7 +51,9 @@ namespace client 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."; @@ -70,6 +75,7 @@ namespace client const char BOB_HELP_OPTION[] = "option = - Set an option. NOTE: Don't use any spaces."; const char BOB_HELP_STATUS[] = "status - Display status of a nicknamed tunnel."; const char BOB_HELP_HELP [] = "help - Get help on a command."; + const char BOB_HELP_SETTUNNELTYPE[] = "settunneltype - Sets socks or http proxy tunnel type."; class BOBI2PTunnelIncomingConnection: public I2PTunnelConnection { @@ -232,6 +238,7 @@ namespace client 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: @@ -258,6 +265,13 @@ namespace client i2p::data::PrivateKeys m_Keys; std::map m_Options; std::shared_ptr m_CurrentDestination; + + enum class TunnelType + { + SOCKS = 0, + HTTP_PROXY = 1 + }; + std::optional m_tunnelType; }; typedef void (BOBCommandSession::*BOBCommandHandler)(const char * operand, size_t len); @@ -275,6 +289,9 @@ namespace client void AddDestination (const std::string& name, std::shared_ptr dest); void DeleteDestination (const std::string& name); std::shared_ptr FindDestination (const std::string& name); + void SetProxy (const std::string& name, std::unique_ptr proxy); + const I2PService* GetProxy(const std::string& name) const; + void RemoveProxy(const std::string& name); private: @@ -287,6 +304,7 @@ namespace client std::map > m_Destinations; std::map m_CommandHandlers; std::map m_HelpStrings; + std::map> m_proxy; public: