2019-01-14 21:46:07 +00:00
|
|
|
#include <service/context.hpp>
|
|
|
|
|
2018-12-12 01:12:59 +00:00
|
|
|
#include <handlers/null.hpp>
|
2018-12-12 02:15:08 +00:00
|
|
|
#include <handlers/tun.hpp>
|
2019-02-11 19:45:42 +00:00
|
|
|
#include <nodedb.hpp>
|
|
|
|
#include <router/abstractrouter.hpp>
|
2018-12-12 02:15:08 +00:00
|
|
|
#include <service/endpoint.hpp>
|
2018-07-11 16:11:19 +00:00
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
namespace service
|
|
|
|
{
|
2019-05-18 17:34:07 +00:00
|
|
|
namespace
|
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
using EndpointConstructor = std::function<service::Endpoint_ptr(
|
|
|
|
const std::string&, AbstractRouter*, service::Context*)>;
|
|
|
|
using EndpointConstructors = std::map<std::string, EndpointConstructor>;
|
2019-05-18 17:34:07 +00:00
|
|
|
|
|
|
|
static EndpointConstructors endpointConstructors = {
|
|
|
|
{"tun",
|
2020-04-07 18:38:56 +00:00
|
|
|
[](const std::string& nick, AbstractRouter* r, service::Context* c)
|
|
|
|
-> service::Endpoint_ptr {
|
|
|
|
return std::make_shared<handlers::TunEndpoint>(nick, r, c, false);
|
2019-05-18 17:34:07 +00:00
|
|
|
}},
|
2019-10-04 18:10:58 +00:00
|
|
|
{"android",
|
2020-04-07 18:38:56 +00:00
|
|
|
[](const std::string& nick, AbstractRouter* r, service::Context* c)
|
|
|
|
-> service::Endpoint_ptr {
|
|
|
|
return std::make_shared<handlers::TunEndpoint>(nick, r, c, true);
|
2019-05-18 17:34:07 +00:00
|
|
|
}},
|
2019-10-04 18:10:58 +00:00
|
|
|
{"ios",
|
2020-04-07 18:38:56 +00:00
|
|
|
[](const std::string& nick, AbstractRouter* r, service::Context* c)
|
|
|
|
-> service::Endpoint_ptr {
|
|
|
|
return std::make_shared<handlers::TunEndpoint>(nick, r, c, true);
|
2019-05-18 17:34:07 +00:00
|
|
|
}},
|
|
|
|
{"null",
|
2020-04-07 18:38:56 +00:00
|
|
|
[](const std::string& nick, AbstractRouter* r, service::Context* c)
|
|
|
|
-> service::Endpoint_ptr {
|
|
|
|
return std::make_shared<handlers::NullEndpoint>(nick, r, c);
|
2019-05-18 17:34:07 +00:00
|
|
|
}}};
|
|
|
|
|
|
|
|
} // namespace
|
2020-04-07 18:38:56 +00:00
|
|
|
Context::Context(AbstractRouter* r) : m_Router(r)
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-07-30 23:42:13 +00:00
|
|
|
Context::~Context() = default;
|
2018-12-24 16:09:05 +00:00
|
|
|
|
|
|
|
bool
|
|
|
|
Context::StopAll()
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.begin();
|
2020-04-07 18:38:56 +00:00
|
|
|
while (itr != m_Endpoints.end())
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
2018-12-24 16:09:05 +00:00
|
|
|
itr->second->Stop();
|
|
|
|
m_Stopped.emplace_back(std::move(itr->second));
|
2018-07-11 16:11:19 +00:00
|
|
|
itr = m_Endpoints.erase(itr);
|
|
|
|
}
|
2018-12-24 16:09:05 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-11 17:14:43 +00:00
|
|
|
util::StatusObject
|
|
|
|
Context::ExtractStatus() const
|
2019-02-08 19:43:25 +00:00
|
|
|
{
|
2019-02-11 17:14:43 +00:00
|
|
|
util::StatusObject obj{};
|
2019-02-08 19:43:25 +00:00
|
|
|
auto itr = m_Endpoints.begin();
|
2020-04-07 18:38:56 +00:00
|
|
|
while (itr != m_Endpoints.end())
|
2019-02-08 19:43:25 +00:00
|
|
|
{
|
2019-08-19 09:33:26 +00:00
|
|
|
obj[itr->first] = itr->second->ExtractStatus();
|
2019-02-08 19:43:25 +00:00
|
|
|
++itr;
|
|
|
|
}
|
2019-02-11 17:14:43 +00:00
|
|
|
return obj;
|
2019-02-08 19:43:25 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 15:26:35 +00:00
|
|
|
void
|
|
|
|
Context::ForEachService(
|
2020-04-07 18:38:56 +00:00
|
|
|
std::function<bool(const std::string&, const std::shared_ptr<Endpoint>&)> visit) const
|
2019-01-28 15:26:35 +00:00
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.begin();
|
2020-04-07 18:38:56 +00:00
|
|
|
while (itr != m_Endpoints.end())
|
2019-01-28 15:26:35 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if (visit(itr->first, itr->second))
|
2019-01-28 15:26:35 +00:00
|
|
|
++itr;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-24 16:09:05 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
Context::RemoveEndpoint(const std::string& name)
|
2018-12-24 16:09:05 +00:00
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.find(name);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (itr == m_Endpoints.end())
|
2018-12-24 16:09:05 +00:00
|
|
|
return false;
|
2020-04-07 18:38:56 +00:00
|
|
|
std::shared_ptr<Endpoint> ep = std::move(itr->second);
|
2018-12-24 16:09:05 +00:00
|
|
|
m_Endpoints.erase(itr);
|
|
|
|
ep->Stop();
|
|
|
|
m_Stopped.emplace_back(std::move(ep));
|
|
|
|
return true;
|
2018-07-11 16:11:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-11-12 16:43:40 +00:00
|
|
|
Context::Tick(llarp_time_t now)
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
2018-12-24 16:09:05 +00:00
|
|
|
// erase stopped endpoints that are done
|
|
|
|
{
|
|
|
|
auto itr = m_Stopped.begin();
|
2020-04-07 18:38:56 +00:00
|
|
|
while (itr != m_Stopped.end())
|
2018-12-24 16:09:05 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if ((*itr)->ShouldRemove())
|
2018-12-24 16:09:05 +00:00
|
|
|
itr = m_Stopped.erase(itr);
|
|
|
|
else
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// tick active endpoints
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& item : m_Endpoints)
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
2019-05-28 11:35:26 +00:00
|
|
|
item.second->Tick(now);
|
2018-07-11 16:11:19 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-20 12:35:29 +00:00
|
|
|
|
2018-10-03 10:44:58 +00:00
|
|
|
bool
|
|
|
|
Context::hasEndpoints()
|
|
|
|
{
|
|
|
|
return m_Endpoints.size() ? true : false;
|
|
|
|
}
|
|
|
|
|
2020-04-07 18:38:56 +00:00
|
|
|
static const char*
|
2019-10-04 18:10:58 +00:00
|
|
|
DefaultEndpointType()
|
|
|
|
{
|
|
|
|
#ifdef ANDROID
|
|
|
|
return "android";
|
2019-10-30 13:33:23 +00:00
|
|
|
#else
|
|
|
|
#ifdef IOS
|
|
|
|
return "ios";
|
2019-10-04 18:10:58 +00:00
|
|
|
#else
|
|
|
|
return "tun";
|
2019-10-30 13:33:23 +00:00
|
|
|
#endif
|
2019-10-04 18:10:58 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-10-03 10:44:58 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
Context::AddDefaultEndpoint(const std::unordered_multimap<std::string, std::string>& opts)
|
2018-10-03 10:44:58 +00:00
|
|
|
{
|
2018-11-26 13:29:45 +00:00
|
|
|
Config::section_values_t configOpts;
|
2019-10-04 18:10:58 +00:00
|
|
|
configOpts.push_back({"type", DefaultEndpointType()});
|
2020-02-12 14:54:59 +00:00
|
|
|
// non reachable by default as this is the default endpoint
|
2020-02-12 14:56:36 +00:00
|
|
|
// but only if no keyfile option provided
|
2020-04-07 18:38:56 +00:00
|
|
|
if (opts.count("keyfile") == 0)
|
2020-02-12 14:56:36 +00:00
|
|
|
{
|
|
|
|
configOpts.push_back({"reachable", "false"});
|
|
|
|
}
|
|
|
|
|
2018-11-26 13:29:45 +00:00
|
|
|
{
|
|
|
|
auto itr = opts.begin();
|
2020-04-07 18:38:56 +00:00
|
|
|
while (itr != opts.end())
|
2018-11-26 13:29:45 +00:00
|
|
|
{
|
|
|
|
configOpts.push_back({itr->first, itr->second});
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return AddEndpoint({"default", configOpts});
|
2018-10-03 10:44:58 +00:00
|
|
|
}
|
|
|
|
|
2018-07-11 16:11:19 +00:00
|
|
|
bool
|
2018-11-11 13:14:19 +00:00
|
|
|
Context::StartAll()
|
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.begin();
|
2020-04-07 18:38:56 +00:00
|
|
|
while (itr != m_Endpoints.end())
|
2018-11-11 13:14:19 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if (!itr->second->Start())
|
2018-11-11 13:14:19 +00:00
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError(itr->first, " failed to start");
|
2018-11-11 13:14:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
2019-04-22 18:35:19 +00:00
|
|
|
LogInfo(itr->first, " started");
|
2018-11-11 13:14:19 +00:00
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-10-04 18:10:58 +00:00
|
|
|
Endpoint_ptr
|
2020-04-07 18:38:56 +00:00
|
|
|
Context::GetEndpointByName(const std::string& name)
|
2019-10-04 18:10:58 +00:00
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.find(name);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (itr != m_Endpoints.end())
|
2019-10-04 18:10:58 +00:00
|
|
|
return itr->second;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2020-02-28 16:29:15 +00:00
|
|
|
void
|
2020-04-07 18:38:56 +00:00
|
|
|
Context::InjectEndpoint(std::string name, std::shared_ptr<Endpoint> ep)
|
2020-02-28 16:29:15 +00:00
|
|
|
{
|
2020-02-28 18:44:27 +00:00
|
|
|
ep->LoadKeyFile();
|
2020-04-07 18:38:56 +00:00
|
|
|
if (ep->Start())
|
2020-02-28 16:29:15 +00:00
|
|
|
{
|
|
|
|
m_Endpoints.emplace(std::move(name), std::move(ep));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-11 13:14:19 +00:00
|
|
|
bool
|
2020-04-07 18:38:56 +00:00
|
|
|
Context::AddEndpoint(const Config::section_t& conf, bool autostart)
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
|
|
|
{
|
2018-08-23 14:07:53 +00:00
|
|
|
auto itr = m_Endpoints.find(conf.first);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (itr != m_Endpoints.end())
|
2018-08-23 14:07:53 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
LogError("cannot add hidden service with duplicate name: ", conf.first);
|
2018-08-23 14:07:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-07-11 16:11:19 +00:00
|
|
|
}
|
2018-08-23 14:07:53 +00:00
|
|
|
// extract type
|
2019-10-04 18:10:58 +00:00
|
|
|
std::string endpointType = DefaultEndpointType();
|
2019-05-18 17:34:07 +00:00
|
|
|
std::string keyfile;
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& option : conf.second)
|
2018-08-23 14:07:53 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
if (option.first == "type")
|
2018-08-23 14:07:53 +00:00
|
|
|
endpointType = option.second;
|
2020-04-07 18:38:56 +00:00
|
|
|
if (option.first == "keyfile")
|
2019-01-16 21:12:24 +00:00
|
|
|
keyfile = option.second;
|
2018-08-23 14:07:53 +00:00
|
|
|
}
|
|
|
|
|
2019-04-23 16:13:22 +00:00
|
|
|
service::Endpoint_ptr service;
|
2019-04-22 17:38:29 +00:00
|
|
|
|
2018-08-23 14:07:53 +00:00
|
|
|
{
|
|
|
|
// detect type
|
2019-05-18 17:34:07 +00:00
|
|
|
const auto itr = endpointConstructors.find(endpointType);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (itr == endpointConstructors.end())
|
2018-08-23 14:07:53 +00:00
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError("no such endpoint type: ", endpointType);
|
2018-08-23 14:07:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// construct
|
2019-04-22 17:38:29 +00:00
|
|
|
service = itr->second(conf.first, m_Router, this);
|
2020-04-07 18:38:56 +00:00
|
|
|
if (service)
|
2019-01-16 21:12:24 +00:00
|
|
|
{
|
2019-04-23 16:13:22 +00:00
|
|
|
// if ephemeral, then we need to regen key
|
|
|
|
// if privkey file, then set it and load it
|
2020-04-07 18:38:56 +00:00
|
|
|
if (!keyfile.empty())
|
2019-04-23 16:13:22 +00:00
|
|
|
{
|
|
|
|
service->SetOption("keyfile", keyfile);
|
|
|
|
// load keyfile, so we have the correct name for logging
|
|
|
|
}
|
|
|
|
LogInfo("Establishing endpoint identity");
|
|
|
|
service->LoadKeyFile(); // only start endpoint not tun
|
|
|
|
// now Name() will be correct
|
2019-01-16 21:12:24 +00:00
|
|
|
}
|
2018-08-23 14:07:53 +00:00
|
|
|
}
|
2020-04-07 18:38:56 +00:00
|
|
|
if (service == nullptr)
|
2019-04-23 16:13:22 +00:00
|
|
|
return false;
|
2018-08-23 14:07:53 +00:00
|
|
|
// configure
|
2020-04-07 18:38:56 +00:00
|
|
|
for (const auto& option : conf.second)
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
auto& k = option.first;
|
|
|
|
if (k == "type")
|
2018-08-23 14:07:53 +00:00
|
|
|
continue;
|
2020-04-07 18:38:56 +00:00
|
|
|
auto& v = option.second;
|
|
|
|
if (!service->SetOption(k, v))
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
2020-04-07 18:38:56 +00:00
|
|
|
LogError("failed to set ", k, "=", v, " for hidden service endpoint ", conf.first);
|
2018-07-11 16:11:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2020-04-07 18:38:56 +00:00
|
|
|
if (autostart)
|
2018-11-11 13:14:19 +00:00
|
|
|
{
|
|
|
|
// start
|
2020-04-07 18:38:56 +00:00
|
|
|
if (service->Start())
|
2018-11-11 13:14:19 +00:00
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogInfo("autostarting hidden service endpoint ", service->Name());
|
2019-04-23 16:13:22 +00:00
|
|
|
m_Endpoints.emplace(conf.first, service);
|
2018-11-11 13:14:19 +00:00
|
|
|
return true;
|
|
|
|
}
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError("failed to start hidden service endpoint ", conf.first);
|
2018-11-11 13:14:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
2019-07-06 17:03:40 +00:00
|
|
|
|
|
|
|
LogInfo("added hidden service endpoint ", service->Name());
|
|
|
|
m_Endpoints.emplace(conf.first, service);
|
|
|
|
return true;
|
2018-07-11 16:11:19 +00:00
|
|
|
}
|
2018-07-17 04:37:50 +00:00
|
|
|
} // namespace service
|
2018-08-17 19:49:58 +00:00
|
|
|
} // namespace llarp
|