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-02-11 19:45:42 +00:00
|
|
|
Context::Context(AbstractRouter *r) : m_Router(r)
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Context::~Context()
|
2018-12-24 16:09:05 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
Context::StopAll()
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.begin();
|
|
|
|
while(itr != m_Endpoints.end())
|
|
|
|
{
|
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();
|
|
|
|
while(itr != m_Endpoints.end())
|
|
|
|
{
|
2019-02-11 17:14:43 +00:00
|
|
|
obj.Put(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(
|
|
|
|
std::function< bool(const std::string &,
|
|
|
|
const std::unique_ptr< Endpoint > &) >
|
|
|
|
visit)
|
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.begin();
|
|
|
|
while(itr != m_Endpoints.end())
|
|
|
|
{
|
|
|
|
if(visit(itr->first, itr->second))
|
|
|
|
++itr;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-24 16:09:05 +00:00
|
|
|
bool
|
|
|
|
Context::RemoveEndpoint(const std::string &name)
|
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.find(name);
|
|
|
|
if(itr == m_Endpoints.end())
|
|
|
|
return false;
|
|
|
|
std::unique_ptr< Endpoint > ep = std::move(itr->second);
|
|
|
|
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();
|
|
|
|
while(itr != m_Stopped.end())
|
|
|
|
{
|
|
|
|
if((*itr)->ShouldRemove())
|
|
|
|
itr = m_Stopped.erase(itr);
|
|
|
|
else
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// tick active endpoints
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
2018-12-24 16:09:05 +00:00
|
|
|
auto itr = m_Endpoints.begin();
|
|
|
|
while(itr != m_Endpoints.end())
|
|
|
|
{
|
|
|
|
itr->second->Tick(now);
|
|
|
|
++itr;
|
|
|
|
}
|
2018-07-11 16:11:19 +00:00
|
|
|
}
|
2019-02-08 13:04:12 +00:00
|
|
|
|
|
|
|
auto ep = getFirstEndpoint();
|
|
|
|
if(!ep)
|
|
|
|
return;
|
|
|
|
std::vector< RouterID > expired;
|
2019-01-29 02:16:31 +00:00
|
|
|
m_Router->nodedb()->visit([&](const RouterContact &rc) -> bool {
|
2018-12-19 17:48:29 +00:00
|
|
|
if(rc.IsExpired(now))
|
2019-02-08 13:04:12 +00:00
|
|
|
expired.emplace_back(rc.pubkey);
|
2018-12-19 17:48:29 +00:00
|
|
|
return true;
|
|
|
|
});
|
2019-02-08 13:05:09 +00:00
|
|
|
// TODO: we need to stop looking up service nodes that are gone forever
|
|
|
|
// how do?
|
2019-02-08 13:04:12 +00:00
|
|
|
for(const auto &k : expired)
|
|
|
|
ep->LookupRouterAnon(k);
|
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;
|
|
|
|
}
|
|
|
|
|
2019-04-22 18:35:19 +00:00
|
|
|
service::Endpoint *
|
2018-09-22 10:23:23 +00:00
|
|
|
Context::getFirstEndpoint()
|
2018-09-20 12:35:29 +00:00
|
|
|
{
|
2018-09-22 10:23:23 +00:00
|
|
|
if(!m_Endpoints.size())
|
2018-09-20 12:35:29 +00:00
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError("No endpoints found");
|
2018-09-20 12:35:29 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2018-12-02 18:07:07 +00:00
|
|
|
auto itr = m_Endpoints.begin();
|
2018-11-26 22:46:22 +00:00
|
|
|
if(itr == m_Endpoints.end())
|
|
|
|
return nullptr;
|
|
|
|
return itr->second.get();
|
2018-09-22 10:23:23 +00:00
|
|
|
}
|
|
|
|
|
2018-10-03 10:44:58 +00:00
|
|
|
bool
|
|
|
|
Context::iterate(struct endpoint_iter &i)
|
|
|
|
{
|
|
|
|
if(!m_Endpoints.size())
|
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError("No endpoints found");
|
2018-10-03 10:44:58 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
i.index = 0;
|
2019-04-22 18:35:19 +00:00
|
|
|
// util::Lock lock(access);
|
2018-10-03 10:44:58 +00:00
|
|
|
auto itr = m_Endpoints.begin();
|
|
|
|
while(itr != m_Endpoints.end())
|
|
|
|
{
|
|
|
|
i.endpoint = itr->second.get();
|
2018-10-18 12:14:26 +00:00
|
|
|
if(!i.visit(&i))
|
|
|
|
return false;
|
2018-10-03 10:44:58 +00:00
|
|
|
// advance
|
|
|
|
i.index++;
|
|
|
|
itr++;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-04-22 18:35:19 +00:00
|
|
|
handlers::TunEndpoint *
|
2018-09-22 10:23:23 +00:00
|
|
|
Context::getFirstTun()
|
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
service::Endpoint *endpointer = this->getFirstEndpoint();
|
2018-09-22 10:23:23 +00:00
|
|
|
if(!endpointer)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2019-04-22 18:35:19 +00:00
|
|
|
handlers::TunEndpoint *tunEndpoint =
|
|
|
|
static_cast< handlers::TunEndpoint * >(endpointer);
|
2018-09-20 12:35:29 +00:00
|
|
|
return tunEndpoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
llarp_tun_io *
|
|
|
|
Context::getRange()
|
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
handlers::TunEndpoint *tunEndpoint = this->getFirstTun();
|
2018-09-22 10:23:23 +00:00
|
|
|
if(!tunEndpoint)
|
2018-09-20 12:35:29 +00:00
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError("No tunnel endpoint found");
|
2018-09-20 12:35:29 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return &tunEndpoint->tunif;
|
|
|
|
}
|
|
|
|
|
2018-10-23 21:28:01 +00:00
|
|
|
bool
|
2019-04-22 18:35:19 +00:00
|
|
|
Context::FindBestAddressFor(const AlignedBuffer< 32 > &addr, bool isSNode,
|
|
|
|
huint32_t &ip)
|
2018-10-23 18:00:55 +00:00
|
|
|
{
|
|
|
|
auto itr = m_Endpoints.begin();
|
|
|
|
while(itr != m_Endpoints.end())
|
|
|
|
{
|
2018-11-29 14:01:13 +00:00
|
|
|
if(itr->second->HasAddress(addr))
|
2018-10-23 18:00:55 +00:00
|
|
|
{
|
2018-11-29 14:01:13 +00:00
|
|
|
ip = itr->second->ObtainIPForAddr(addr, isSNode);
|
2018-10-23 21:28:01 +00:00
|
|
|
return true;
|
2018-10-23 18:00:55 +00:00
|
|
|
}
|
|
|
|
++itr;
|
|
|
|
}
|
2018-10-23 21:28:01 +00:00
|
|
|
itr = m_Endpoints.find("default");
|
|
|
|
if(itr != m_Endpoints.end())
|
|
|
|
{
|
2018-11-29 14:01:13 +00:00
|
|
|
ip = itr->second->ObtainIPForAddr(addr, isSNode);
|
2018-10-23 21:28:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2018-10-23 18:00:55 +00:00
|
|
|
}
|
|
|
|
|
2018-09-21 12:53:20 +00:00
|
|
|
bool
|
2019-04-22 18:35:19 +00:00
|
|
|
Context::Prefetch(const service::Address &addr)
|
2018-09-21 12:53:20 +00:00
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
handlers::TunEndpoint *tunEndpoint = this->getFirstTun();
|
2018-09-22 10:23:23 +00:00
|
|
|
if(!tunEndpoint)
|
2018-09-21 12:53:20 +00:00
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError("No tunnel endpoint found");
|
2018-09-21 12:53:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-09-22 10:23:23 +00:00
|
|
|
// HiddenServiceAddresslookup *lookup = new
|
|
|
|
// HiddenServiceEndpoint(tunEndpoint, callback, addr,
|
|
|
|
// tunEndpoint->GenTXID());
|
|
|
|
return tunEndpoint->EnsurePathToService(
|
2018-11-07 15:30:22 +00:00
|
|
|
addr,
|
|
|
|
[](__attribute__((unused)) Address addr,
|
|
|
|
__attribute__((unused)) void *ctx) {},
|
|
|
|
10000);
|
2018-09-21 12:53:20 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 17:35:51 +00:00
|
|
|
bool
|
2018-10-18 12:14:26 +00:00
|
|
|
MapAddressAllIter(struct Context::endpoint_iter *endpointCfg)
|
2018-10-02 17:35:51 +00:00
|
|
|
{
|
2018-10-03 10:44:58 +00:00
|
|
|
Context::mapAddressAll_context *context =
|
|
|
|
(Context::mapAddressAll_context *)endpointCfg->user;
|
2019-04-22 18:35:19 +00:00
|
|
|
handlers::TunEndpoint *tunEndpoint =
|
|
|
|
(handlers::TunEndpoint *)endpointCfg->endpoint;
|
2018-10-03 10:44:58 +00:00
|
|
|
if(!tunEndpoint)
|
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError("No tunnel endpoint found");
|
2018-10-18 12:14:26 +00:00
|
|
|
return true; // still continue
|
2018-10-03 10:44:58 +00:00
|
|
|
}
|
2018-12-02 18:07:07 +00:00
|
|
|
return tunEndpoint->MapAddress(
|
|
|
|
context->serviceAddr, context->localPrivateIpAddr.xtohl(), false);
|
2018-10-02 17:35:51 +00:00
|
|
|
}
|
2018-10-03 10:44:58 +00:00
|
|
|
|
|
|
|
bool
|
2019-04-22 18:35:19 +00:00
|
|
|
Context::MapAddressAll(const service::Address &addr,
|
|
|
|
Addr &localPrivateIpAddr)
|
2018-10-03 10:44:58 +00:00
|
|
|
{
|
|
|
|
struct Context::mapAddressAll_context context;
|
|
|
|
context.serviceAddr = addr;
|
|
|
|
context.localPrivateIpAddr = localPrivateIpAddr;
|
|
|
|
|
|
|
|
struct Context::endpoint_iter i;
|
|
|
|
i.user = &context;
|
|
|
|
i.index = 0;
|
2018-10-18 12:14:26 +00:00
|
|
|
i.visit = &MapAddressAllIter;
|
2018-10-03 10:44:58 +00:00
|
|
|
return this->iterate(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2018-11-26 13:29:45 +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;
|
|
|
|
configOpts.push_back({"type", "tun"});
|
|
|
|
{
|
|
|
|
auto itr = opts.begin();
|
|
|
|
while(itr != opts.end())
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
while(itr != m_Endpoints.end())
|
|
|
|
{
|
|
|
|
if(!itr->second->Start())
|
|
|
|
{
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
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);
|
|
|
|
if(itr != m_Endpoints.end())
|
|
|
|
{
|
2019-04-22 18:35:19 +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
|
|
|
|
std::string endpointType = "tun";
|
2019-01-16 21:12:24 +00:00
|
|
|
std::string keyfile = "";
|
2018-08-23 14:07:53 +00:00
|
|
|
for(const auto &option : conf.second)
|
|
|
|
{
|
|
|
|
if(option.first == "type")
|
|
|
|
endpointType = option.second;
|
2019-01-16 21:12:24 +00:00
|
|
|
if(option.first == "keyfile")
|
|
|
|
keyfile = option.second;
|
2018-08-23 14:07:53 +00:00
|
|
|
}
|
|
|
|
|
2019-04-22 17:38:29 +00:00
|
|
|
std::unique_ptr< service::Endpoint > service;
|
|
|
|
|
|
|
|
static std::map<
|
|
|
|
std::string,
|
|
|
|
std::function< std::unique_ptr< service::Endpoint >(
|
|
|
|
const std::string &, AbstractRouter *, service::Context *) > >
|
2018-08-23 14:07:53 +00:00
|
|
|
endpointConstructors = {
|
|
|
|
{"tun",
|
2019-02-11 19:45:42 +00:00
|
|
|
[](const std::string &nick, AbstractRouter *r,
|
2019-04-22 18:35:19 +00:00
|
|
|
service::Context *c) -> std::unique_ptr< service::Endpoint > {
|
2019-04-22 17:38:29 +00:00
|
|
|
return std::make_unique< handlers::TunEndpoint >(nick, r, c);
|
2018-08-23 14:07:53 +00:00
|
|
|
}},
|
|
|
|
{"null",
|
2019-02-11 19:45:42 +00:00
|
|
|
[](const std::string &nick, AbstractRouter *r,
|
2019-04-22 17:38:29 +00:00
|
|
|
service::Context *c) -> std::unique_ptr< service::Endpoint > {
|
|
|
|
return std::make_unique< handlers::NullEndpoint >(nick, r, c);
|
2018-08-23 14:07:53 +00:00
|
|
|
}}};
|
2018-08-17 19:49:58 +00:00
|
|
|
|
2018-08-23 14:07:53 +00:00
|
|
|
{
|
|
|
|
// detect type
|
|
|
|
auto itr = endpointConstructors.find(endpointType);
|
|
|
|
if(itr == endpointConstructors.end())
|
|
|
|
{
|
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);
|
2019-01-18 02:28:30 +00:00
|
|
|
|
|
|
|
// if ephemeral, then we need to regen key
|
|
|
|
// if privkey file, then set it and load it
|
2019-01-16 21:12:24 +00:00
|
|
|
if(keyfile != "")
|
|
|
|
{
|
|
|
|
service->SetOption("keyfile", keyfile);
|
|
|
|
// load keyfile, so we have the correct name for logging
|
|
|
|
}
|
2019-04-22 18:35:19 +00:00
|
|
|
LogInfo("Establishing endpoint identity");
|
2019-01-18 02:28:30 +00:00
|
|
|
service->LoadKeyFile(); // only start endpoint not tun
|
|
|
|
// now Name() will be correct
|
2018-08-23 14:07:53 +00:00
|
|
|
}
|
|
|
|
// configure
|
2018-07-11 16:11:19 +00:00
|
|
|
for(const auto &option : conf.second)
|
|
|
|
{
|
|
|
|
auto &k = option.first;
|
2018-08-23 14:07:53 +00:00
|
|
|
if(k == "type")
|
|
|
|
continue;
|
2018-07-11 16:11:19 +00:00
|
|
|
auto &v = option.second;
|
|
|
|
if(!service->SetOption(k, v))
|
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogError("failed to set ", k, "=", v, " for hidden service endpoint ",
|
|
|
|
conf.first);
|
2018-07-11 16:11:19 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2018-11-11 13:14:19 +00:00
|
|
|
if(autostart)
|
|
|
|
{
|
|
|
|
// start
|
|
|
|
if(service->Start())
|
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogInfo("autostarting hidden service endpoint ", service->Name());
|
2019-02-18 10:35:16 +00:00
|
|
|
m_Endpoints.emplace(conf.first, std::move(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;
|
|
|
|
}
|
|
|
|
else
|
2018-07-11 16:11:19 +00:00
|
|
|
{
|
2019-04-22 18:35:19 +00:00
|
|
|
LogInfo("added hidden service endpoint ", service->Name());
|
2019-02-18 10:35:16 +00:00
|
|
|
m_Endpoints.emplace(conf.first, std::move(service));
|
2018-07-11 16:11:19 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2018-07-17 04:37:50 +00:00
|
|
|
} // namespace service
|
2018-08-17 19:49:58 +00:00
|
|
|
} // namespace llarp
|