initial working code

pull/1306/head
Jeff Becker 4 years ago
parent 78256e3228
commit ad882d0d70
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -276,10 +276,6 @@ if(SUBMODULE_CHECK)
endif()
endif()
add_subdirectory(external/loki-mq)
include_directories(external/loki-mq)
include_directories(external/loki-mq/mapbox-variant/include)
# We only actually need pybind11 with WITH_HIVE, but if we don't load it here then something further
# down loads a broken PythonInterp that loads Python2, but Python2 headers are not C++17 compatible.
# So load this here universally so that pybind's more intelligent python finder finds python3.x

@ -64,13 +64,13 @@ elseif(DOWNLOAD_UV)
endif()
include_directories(${LIBUV_INCLUDE_DIRS})
#find_package(LokiMQ)
#if(LokiMQ_FOUND)
# message(STATUS "using system lokimq")
#else()
message(STATUS "using lokimq submodule")
add_subdirectory(${CMAKE_SOURCE_DIR}/external/loki-mq)
#endif()
find_package(LokiMQ 1.2)
if(LokiMQ_FOUND)
message(STATUS "using system lokimq")
else()
message(STATUS "using lokimq submodule")
add_subdirectory(${CMAKE_SOURCE_DIR}/external/loki-mq EXCLUDE_FROM_ALL)
endif()
if(EMBEDDED_CFG OR ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
link_libatomic()

@ -6,19 +6,6 @@
#include "crypto/crypto.hpp"
#include "crypto/types.hpp"
#ifdef HAVE_CURL
#include <curl/curl.h>
#endif
/// curl callback
static size_t
curl_RecvIdentKey(char* ptr, size_t, size_t nmemb, void* userdata)
{
for (size_t idx = 0; idx < nmemb; idx++)
static_cast<std::vector<char>*>(userdata)->push_back(ptr[idx]);
return nmemb;
}
namespace llarp
{
KeyManager::KeyManager() : m_initialized(false), m_needBackup(false)
@ -55,11 +42,6 @@ namespace llarp
m_encKeyPath = deriveFile(our_enc_key_filename, config.router.m_encryptionKeyFile);
m_transportKeyPath = deriveFile(our_transport_key_filename, config.router.m_transportKeyFile);
m_usingLokid = config.lokid.whitelistRouters;
m_lokidRPCAddr = config.lokid.lokidRPCAddr;
m_lokidRPCUser = config.lokid.lokidRPCUser;
m_lokidRPCPassword = config.lokid.lokidRPCPassword;
RouterContact rc;
bool exists = rc.Read(m_rcPath);
if (not exists and not genIfAbsent)
@ -99,7 +81,7 @@ namespace llarp
}
}
if (not m_usingLokid)
if (not config.lokid.whitelistRouters)
{
// load identity key or create if needed
auto identityKeygen = [](llarp::SecretKey& key) {
@ -109,11 +91,6 @@ namespace llarp
if (not loadOrCreateKey(m_idKeyPath, identityKey, identityKeygen))
return false;
}
else
{
if (not loadIdentityFromLokid())
return false;
}
// load encryption key
auto encryptionKeygen = [](llarp::SecretKey& key) {
@ -227,100 +204,4 @@ namespace llarp
return key.LoadFromFile(filepath);
}
bool
KeyManager::loadIdentityFromLokid()
{
#ifndef HAVE_CURL
LogError("this lokinet was not built with service node mode support");
return false;
#else
CURL* curl = curl_easy_init();
if (curl)
{
bool ret = false;
std::stringstream ss;
ss << "http://" << m_lokidRPCAddr << "/json_rpc";
const auto url = ss.str();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
const auto auth = m_lokidRPCUser + ":" + m_lokidRPCPassword;
curl_easy_setopt(curl, CURLOPT_USERPWD, auth.c_str());
curl_slist* list = nullptr;
list = curl_slist_append(list, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
nlohmann::json request = {
{"id", "0"}, {"jsonrpc", "2.0"}, {"method", "get_service_node_privkey"}};
const auto data = request.dump();
std::vector<char> resp;
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curl_RecvIdentKey);
resp.clear();
LogInfo("Getting Identity Keys from lokid...");
if (curl_easy_perform(curl) == CURLE_OK)
{
try
{
auto j = nlohmann::json::parse(resp);
if (not j.is_object())
return false;
const auto itr = j.find("result");
if (itr == j.end())
return false;
if (not itr->is_object())
return false;
const auto k = (*itr)["service_node_ed25519_privkey"].get<std::string>();
if (k.size() != (identityKey.size() * 2))
{
if (k.empty())
{
LogError("lokid gave no identity key");
}
else
{
LogError("lokid gave invalid identity key");
}
return false;
}
if (not HexDecode(k.c_str(), identityKey.data(), identityKey.size()))
return false;
if (CryptoManager::instance()->check_identity_privkey(identityKey))
{
ret = true;
}
else
{
LogError("lokid gave bogus identity key");
}
}
catch (nlohmann::json::exception& ex)
{
LogError("Bad response from lokid: ", ex.what());
}
}
else
{
LogError("failed to get identity keys");
}
if (ret)
{
LogInfo("Got Identity Keys from lokid: ", RouterID(seckey_topublic(identityKey)));
}
curl_easy_cleanup(curl);
curl_slist_free_all(list);
return ret;
}
else
{
LogError("failed to init curl");
return false;
}
#endif
}
} // namespace llarp

@ -18,7 +18,6 @@ namespace llarp
/// In addition, the KeyManager detects when the keys obsolete (e.g. as a
/// result of a software upgrade) and backs up existing keys before writing
/// out new ones.
struct KeyManager
{
/// Utility function to backup a file by moving it. Attempts to find a new
@ -34,8 +33,7 @@ namespace llarp
/// Constructor
KeyManager();
/// Initializes keys using the provided config, loading from disk and/or
/// lokid via HTTP request.
/// Initializes keys using the provided config, loading from disk
///
/// NOTE: Must be called prior to obtaining any keys.
/// NOTE: blocks on I/O
@ -75,11 +73,6 @@ namespace llarp
std::atomic_bool m_initialized;
std::atomic_bool m_needBackup;
bool m_usingLokid = false;
std::string m_lokidRPCAddr = "127.0.0.1:22023";
std::string m_lokidRPCUser;
std::string m_lokidRPCPassword;
/// Backup each key file (by copying, e.g. foo -> foo.bak)
bool
backupKeyFilesByMoving() const;
@ -92,10 +85,6 @@ namespace llarp
const fs::path& filepath,
llarp::SecretKey& key,
std::function<void(llarp::SecretKey& key)> keygen);
/// Requests the identity key from lokid via HTTP (curl)
bool
loadIdentityFromLokid();
};
} // namespace llarp

@ -117,9 +117,6 @@ namespace llarp
llarp::LogError("cannot run non configured context");
return 1;
}
// run
if (!router->StartJsonRpc())
return 1;
if (!opts.background)
{

@ -47,6 +47,11 @@ namespace llarp
struct Context;
}
namespace rpc
{
struct LokidRpcClient;
}
namespace path
{
struct PathContext;
@ -83,6 +88,9 @@ namespace llarp
virtual LMQ_ptr
lmq() const = 0;
virtual std::shared_ptr<rpc::LokidRpcClient>
RpcClient() const = 0;
virtual std::shared_ptr<Logic>
logic() const = 0;
@ -153,7 +161,7 @@ namespace llarp
IsServiceNode() const = 0;
virtual bool
StartJsonRpc() = 0;
StartRpcServer() = 0;
virtual bool
Run() = 0;

@ -64,7 +64,7 @@ namespace llarp
#else
, _randomStartDelay(std::chrono::seconds((llarp::randint() % 30) + 10))
#endif
, m_lokidRpcClient(m_lmq, this)
, m_lokidRpcClient(std::make_shared<rpc::LokidRpcClient>(m_lmq, this))
{
m_keyManager = std::make_shared<KeyManager>();
@ -203,6 +203,8 @@ namespace llarp
bool
Router::EnsureIdentity()
{
_encryption = m_keyManager->encryptionKey;
if (whitelistRouters)
{
#if defined(ANDROID) || defined(IOS)
@ -214,10 +216,14 @@ namespace llarp
return false;
#endif
#endif
const auto maybe = RpcClient()->ObtainIdentityKey();
if (maybe.has_value())
_identity = *maybe;
}
else
{
_identity = m_keyManager->identityKey;
}
_identity = m_keyManager->identityKey;
_encryption = m_keyManager->encryptionKey;
if (_identity.IsZero())
return false;
@ -236,6 +242,23 @@ namespace llarp
}
_nodedb = nodedb;
// we need this first so we can start lmq to fetch keys
enableRPCServer = conf->api.m_enableRPCServer;
rpcBindAddr = conf->api.m_rpcBindAddr;
whitelistRouters = conf->lokid.whitelistRouters;
lokidRPCAddr = conf->lokid.lokidRPCAddr;
if (not StartRpcServer())
throw std::runtime_error("Failed to start rpc server");
m_lmq->start();
if (whitelistRouters)
{
m_lokidRpcClient->ConnectAsync(std::string_view{lokidRPCAddr});
}
// fetch keys
if (not m_keyManager->initialize(*conf, true, isRouter))
throw std::runtime_error("KeyManager failed to initialize");
@ -555,8 +578,6 @@ namespace llarp
}
// API config
enableRPCServer = conf->api.m_enableRPCServer;
rpcBindAddr = IpAddress(conf->api.m_rpcBindAddr); // TODO: make this an IpAddress in config
if (not IsServiceNode())
{
hiddenServiceContext().AddEndpoint(*conf);
@ -818,18 +839,19 @@ namespace llarp
}
bool
Router::StartJsonRpc()
Router::StartRpcServer()
{
if (_running || _stopping)
return false;
if (enableRPCServer)
{
if (rpcBindAddr.isEmpty())
if (rpcBindAddr.empty())
{
rpcBindAddr = DefaultRPCBindAddr;
}
LogInfo("Bound RPC server to ", rpcBindAddr);
// TODO: set up rpc server
// LogInfo("Bound RPC server to ", rpcBindAddr);
}
return true;
@ -841,13 +863,6 @@ namespace llarp
if (_running || _stopping)
return false;
if (whitelistRouters)
{
m_lokidRpcClient.ConnectAsync(std::string_view{lokidRPCAddr});
}
m_lmq->start();
if (!cryptoworker->start())
{
LogError("crypto worker failed to start");

@ -81,6 +81,12 @@ namespace llarp
return m_lmq;
}
std::shared_ptr<rpc::LokidRpcClient>
RpcClient() const override
{
return m_lokidRpcClient;
}
std::shared_ptr<Logic>
logic() const override
{
@ -250,12 +256,12 @@ namespace llarp
NetworkConfig networkConfig;
DnsConfig dnsConfig;
const IpAddress DefaultRPCBindAddr = IpAddress("127.0.0.1:1190");
const std::string DefaultRPCBindAddr = "127.0.0.1:1190";
bool enableRPCServer = false;
IpAddress rpcBindAddr = DefaultRPCBindAddr;
std::string rpcBindAddr = DefaultRPCBindAddr;
const llarp_time_t _randomStartDelay;
rpc::LokidRpcClient m_lokidRpcClient;
std::shared_ptr<rpc::LokidRpcClient> m_lokidRpcClient;
std::string lokidRPCAddr = "ipc://loki.sock";
std::string lokidRPCUser;
@ -337,7 +343,7 @@ namespace llarp
Configure(Config* conf, bool isRouter, llarp_nodedb* nodedb = nullptr) override;
bool
StartJsonRpc() override;
StartRpcServer() override;
bool
Run() override;

@ -61,52 +61,53 @@ namespace llarp
m_lokiMQ->send(*m_Connection, std::move(cmd));
}
void
LokidRpcClient::UpdateServiceNodeList()
{
nlohmann::json request;
request["pubkey_ed25519"] = true;
request["active_only"] = true;
if (not m_CurrentBlockHash.empty())
request["poll_block_hash"] = m_CurrentBlockHash;
Request(
"rpc.get_service_nodes",
[self = shared_from_this()](bool success, std::vector<std::string> data) {
if (not success)
{
LogWarn("failed to update service node list");
return;
}
if (data.size() < 2)
{
LogWarn("lokid gave empty reply for service node list");
return;
}
try
{
self->HandleGotServiceNodeList(std::move(data[1]));
}
catch (std::exception& ex)
{
LogError("failed to process service node list: ", ex.what());
}
},
request.dump());
}
void
LokidRpcClient::Connected()
{
constexpr auto PingInterval = 1min;
constexpr auto NodeListUpdateInterval = 90s;
constexpr auto NodeListUpdateInterval = 30s;
LogInfo("we connected to lokid [", *m_Connection, "]");
Command("admin.lokinet_ping");
m_lokiMQ->add_timer(
[self = shared_from_this()]() {
LogInfo("Telling lokid we are live");
self->Command("rpc.lokinet_ping");
},
PingInterval);
[self = shared_from_this()]() { self->Command("admin.lokinet_ping"); }, PingInterval);
UpdateServiceNodeList();
m_lokiMQ->add_timer(
[self = shared_from_this()]() {
nlohmann::json request;
request["pubkey_ed25519"] = true;
request["active_only"] = true;
if (not self->m_CurrentBlockHash.empty())
request["poll_block_hash"] = self->m_CurrentBlockHash;
self->Request(
"rpc.get_service_nodes",
[self](bool success, std::vector<std::string> data) {
if (not success)
{
LogWarn("failed to update service node list");
return;
}
if (data.size() < 2)
{
LogWarn("lokid gave empty reply for service node list");
return;
}
try
{
self->HandleGotServiceNodeList(std::move(data[1]));
}
catch (std::exception& ex)
{
LogError("failed to process service node list: ", ex.what());
}
},
request.dump());
},
NodeListUpdateInterval);
[self = shared_from_this()]() { self->UpdateServiceNodeList(); }, NodeListUpdateInterval);
}
void
@ -154,10 +155,49 @@ namespace llarp
LogWarn("got empty service node list from lokid");
return;
}
// inform router about the new list
LogicCall(m_Router->logic(), [r = m_Router, nodeList]() { r->SetRouterWhitelist(nodeList); });
}
std::optional<SecretKey>
LokidRpcClient::ObtainIdentityKey()
{
std::promise<std::optional<SecretKey>> promise;
Request(
"admin.get_service_privkeys",
[self = shared_from_this(), &promise](bool success, std::vector<std::string> data) {
if (not success)
{
LogError("failed to get private key");
promise.set_value(std::nullopt);
return;
}
if (data.size() < 2)
{
LogError("failed to get private key, no response");
promise.set_value(std::nullopt);
return;
}
try
{
auto j = nlohmann::json::parse(data[1]);
SecretKey k;
if (not k.FromHex(j.at("service_node_ed25519_privkey").get<std::string>()))
{
promise.set_value(std::nullopt);
return;
}
promise.set_value(k);
}
catch (std::exception& ex)
{
LogError("failed to get private key: ", ex.what());
promise.set_value(std::nullopt);
}
});
return promise.get_future().get();
}
} // namespace rpc
} // namespace llarp

@ -3,6 +3,7 @@
#include <router_id.hpp>
#include <lokimq/lokimq.h>
#include <crypto/types.hpp>
namespace llarp
{
@ -20,6 +21,10 @@ namespace llarp
void
ConnectAsync(std::string_view url);
/// blocking request identity key from lokid
std::optional<SecretKey>
ObtainIdentityKey();
private:
/// called when we have connected to lokid via lokimq
void
@ -29,6 +34,9 @@ namespace llarp
void
Command(std::string_view cmd);
void
UpdateServiceNodeList();
template <typename HandlerFunc_t, typename Args_t>
void
Request(std::string_view cmd, HandlerFunc_t func, const Args_t& args)
@ -36,6 +44,13 @@ namespace llarp
m_lokiMQ->request(*m_Connection, std::move(cmd), std::move(func), args);
}
template <typename HandlerFunc_t>
void
Request(std::string_view cmd, HandlerFunc_t func)
{
m_lokiMQ->request(*m_Connection, std::move(cmd), std::move(func));
}
void
HandleGotServiceNodeList(std::string json);

@ -388,7 +388,8 @@ namespace llarp
// we need to dh
auto dh = new AsyncFrameDecrypt(logic, localIdent, handler, msg, *this, recvPath->intro);
dh->path = recvPath;
return worker->addJob(std::bind(&AsyncFrameDecrypt::Work, dh));
worker->addJob(std::bind(&AsyncFrameDecrypt::Work, dh));
return true;
}
auto v = new AsyncDecrypt();
@ -407,7 +408,7 @@ namespace llarp
return false;
}
v->frame = *this;
return worker->addJob([v, msg = std::move(msg), recvPath = std::move(recvPath)]() {
worker->addJob([v, msg = std::move(msg), recvPath = std::move(recvPath)]() {
if (not v->frame.Verify(v->si))
{
LogError("Signature failure from ", v->si.Addr());
@ -427,6 +428,7 @@ namespace llarp
msg->handler->QueueRecvData(std::move(ev));
delete v;
});
return true;
}
bool

Loading…
Cancel
Save