endpoint auth whitelist

pull/1306/head
Jeff Becker 4 years ago
parent 9f11b03016
commit 5abf111159
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -165,17 +165,24 @@ namespace llarp
conf.defineOption<std::string>("network", "keyfile", false, "", AssignmentAcceptor(m_keyfile)); conf.defineOption<std::string>("network", "keyfile", false, "", AssignmentAcceptor(m_keyfile));
conf.defineOption<std::string>("network", "auth-url", false, "", [this](std::string arg) { conf.defineOption<bool>("network", "auth", false, false, AssignmentAcceptor(m_AuthEnabled));
if (arg.empty())
return;
m_AuthUrl = std::move(arg);
});
conf.defineOption<std::string>("network", "auth-method", false, "", [this](std::string arg) { conf.defineOption<std::string>("network", "auth-url", false, "", AssignmentAcceptor(m_AuthUrl));
if (arg.empty())
return; conf.defineOption<std::string>(
m_AuthMethod = std::move(arg); "network", "auth-method", false, "llarp.auth", [this](std::string arg) {
}); if (arg.empty())
return;
m_AuthMethod = std::move(arg);
});
conf.defineOption<std::string>(
"network", "auth-whitelist", false, true, "", [this](std::string arg) {
service::Address addr;
if (not addr.FromString(arg))
throw std::invalid_argument(stringify("bad loki address: ", arg));
m_AuthWhitelist.emplace(std::move(addr));
});
conf.defineOption<bool>( conf.defineOption<bool>(
"network", "reachable", false, ReachableDefault, AssignmentAcceptor(m_reachable)); "network", "reachable", false, ReachableDefault, AssignmentAcceptor(m_reachable));
@ -864,6 +871,46 @@ namespace llarp
"Permanently map a `.loki` address to an IP owned by the snapp. Example:", "Permanently map a `.loki` address to an IP owned by the snapp. Example:",
"mapaddr=whatever.loki:10.0.10.10 # maps `whatever.loki` to `10.0.10.10`.", "mapaddr=whatever.loki:10.0.10.10 # maps `whatever.loki` to `10.0.10.10`.",
}); });
// extra [network] options
// TODO: probably better to create an [exit] section and only allow it for routers
def.addOptionComments(
"network",
"exit",
{
"Whether or not we should act as an exit node. Beware that this increases demand",
"on the server and may pose liability concerns. Enable at your own risk.",
});
def.addOptionComments(
"network",
"auth",
{
"authenticate remote sessions against a whitelist or an external lmq server",
"true/false",
});
def.addOptionComments(
"network",
"auth-url",
{
"lmq endpoint to talk to for authenticating new sessions",
"ipc:///var/lib/lokinet/auth.socket",
});
def.addOptionComments(
"network",
"auth-method",
{
"lmq function to call for authenticating new sessions",
"llarp.auth",
});
def.addOptionComments(
"network",
"auth-whitelist",
{
"manually add a remote endpoint by .loki address to the access whitelist",
});
return def.generateINIConfig(true); return def.generateINIConfig(true);
} }
@ -908,47 +955,6 @@ namespace llarp
"File containing service node's seed.", "File containing service node's seed.",
}); });
// extra [network] options
// TODO: probably better to create an [exit] section and only allow it for routers
def.addOptionComments(
"network",
"exit",
{
"Whether or not we should act as an exit node. Beware that this increases demand",
"on the server and may pose liability concerns. Enable at your own risk.",
});
def.addOptionComments(
"network",
"auth-url",
{
"lmq endpoint to talk to for authenticating new sessions",
});
def.addOptionComments(
"network",
"auth-method",
{
"lmq function to call for authenticating new sessions",
});
// TODO: define the order of precedence (e.g. is whitelist applied before blacklist?)
// additionally, what's default? What if I don't whitelist anything?
def.addOptionComments(
"network",
"exit-whitelist",
{
"List of destination protocol:port pairs to whitelist, example: udp:*",
"or tcp:80. Multiple values supported.",
});
def.addOptionComments(
"network",
"exit-blacklist",
{
"Blacklist of destinations (same format as whitelist).",
});
return def.generateINIConfig(true); return def.generateINIConfig(true);
} }

@ -82,8 +82,10 @@ namespace llarp
std::optional<service::Address> m_exitNode; std::optional<service::Address> m_exitNode;
std::unordered_map<huint128_t, service::Address> m_mapAddrs; std::unordered_map<huint128_t, service::Address> m_mapAddrs;
bool m_AuthEnabled = false;
std::optional<std::string> m_AuthUrl; std::optional<std::string> m_AuthUrl;
std::optional<std::string> m_AuthMethod; std::optional<std::string> m_AuthMethod;
std::unordered_set<service::Address, service::Address::Hash> m_AuthWhitelist;
// TODO: // TODO:
// on-up // on-up

@ -118,7 +118,11 @@ namespace llarp
if (conf.m_AuthUrl.has_value() and conf.m_AuthMethod.has_value()) if (conf.m_AuthUrl.has_value() and conf.m_AuthMethod.has_value())
{ {
auto auth = std::make_shared<rpc::EndpointAuthRPC>( auto auth = std::make_shared<rpc::EndpointAuthRPC>(
*conf.m_AuthUrl, *conf.m_AuthMethod, Router()->lmq(), shared_from_this()); *conf.m_AuthUrl,
*conf.m_AuthMethod,
conf.m_AuthWhitelist,
Router()->lmq(),
shared_from_this());
auth->Start(); auth->Start();
m_AuthPolicy = std::move(auth); m_AuthPolicy = std::move(auth);
} }

@ -4,9 +4,14 @@
namespace llarp::rpc namespace llarp::rpc
{ {
EndpointAuthRPC::EndpointAuthRPC( EndpointAuthRPC::EndpointAuthRPC(
std::string url, std::string method, LMQ_ptr lmq, Endpoint_ptr endpoint) std::string url,
std::string method,
Whitelist_t whitelist,
LMQ_ptr lmq,
Endpoint_ptr endpoint)
: m_AuthURL(std::move(url)) : m_AuthURL(std::move(url))
, m_AuthMethod(std::move(method)) , m_AuthMethod(std::move(method))
, m_AuthWhitelist(std::move(whitelist))
, m_LMQ(std::move(lmq)) , m_LMQ(std::move(lmq))
, m_Endpoint(std::move(endpoint)) , m_Endpoint(std::move(endpoint))
{ {
@ -15,11 +20,13 @@ namespace llarp::rpc
void void
EndpointAuthRPC::Start() EndpointAuthRPC::Start()
{ {
if (m_AuthURL.empty())
return;
m_LMQ->connect_remote( m_LMQ->connect_remote(
m_AuthURL, m_AuthURL,
[self = shared_from_this()](lokimq::ConnectionID c) { [self = shared_from_this()](lokimq::ConnectionID c) {
self->m_Conn = std::move(c); self->m_Conn = std::move(c);
LogInfo("connected to endpoint auth server via ", c); LogInfo("connected to endpoint auth server via ", *self->m_Conn);
}, },
[self = shared_from_this()](lokimq::ConnectionID, std::string_view fail) { [self = shared_from_this()](lokimq::ConnectionID, std::string_view fail) {
LogWarn("failed to connect to endpoint auth server: ", fail); LogWarn("failed to connect to endpoint auth server: ", fail);
@ -33,13 +40,16 @@ namespace llarp::rpc
llarp::service::ConvoTag, llarp::service::ConvoTag,
std::function<void(service::AuthResult)> hook) std::function<void(service::AuthResult)> hook)
{ {
if (m_AuthWhitelist.count(from))
{
m_Endpoint->RouterLogic()->Call([hook]() { hook(service::AuthResult::eAuthAccepted); });
return;
}
if (not m_Conn.has_value()) if (not m_Conn.has_value())
{ {
LogWarn("No connection to ", m_AuthURL);
m_Endpoint->RouterLogic()->Call([hook]() { hook(service::AuthResult::eAuthFailed); }); m_Endpoint->RouterLogic()->Call([hook]() { hook(service::AuthResult::eAuthFailed); });
return; return;
} }
LogInfo("try auth: ", m_AuthMethod);
// call method with 1 parameter: the loki address of the remote // call method with 1 parameter: the loki address of the remote
m_LMQ->request( m_LMQ->request(
*m_Conn, *m_Conn,
@ -49,14 +59,12 @@ namespace llarp::rpc
service::AuthResult result = service::AuthResult::eAuthFailed; service::AuthResult result = service::AuthResult::eAuthFailed;
if (success and not data.empty()) if (success and not data.empty())
{ {
LogInfo("auth reply: ", data[0]);
const auto maybe = service::ParseAuthResult(data[0]); const auto maybe = service::ParseAuthResult(data[0]);
if (maybe.has_value()) if (maybe.has_value())
{ {
result = *maybe; result = *maybe;
} }
} }
LogInfo("auth result for ", from, " ", result);
self->m_Endpoint->RouterLogic()->Call([hook, result]() { hook(result); }); self->m_Endpoint->RouterLogic()->Call([hook, result]() { hook(result); });
}, },
from.ToString()); from.ToString());

@ -15,9 +15,14 @@ namespace llarp::rpc
{ {
using LMQ_ptr = std::shared_ptr<lokimq::LokiMQ>; using LMQ_ptr = std::shared_ptr<lokimq::LokiMQ>;
using Endpoint_ptr = std::shared_ptr<llarp::service::Endpoint>; using Endpoint_ptr = std::shared_ptr<llarp::service::Endpoint>;
using Whitelist_t = std::unordered_set<llarp::service::Address, llarp::service::Address::Hash>;
explicit EndpointAuthRPC( explicit EndpointAuthRPC(
std::string url, std::string method, LMQ_ptr lmq, Endpoint_ptr endpoint); std::string url,
std::string method,
Whitelist_t whitelist,
LMQ_ptr lmq,
Endpoint_ptr endpoint);
~EndpointAuthRPC() = default; ~EndpointAuthRPC() = default;
void void
@ -32,6 +37,7 @@ namespace llarp::rpc
private: private:
const std::string m_AuthURL; const std::string m_AuthURL;
const std::string m_AuthMethod; const std::string m_AuthMethod;
const Whitelist_t m_AuthWhitelist;
LMQ_ptr m_LMQ; LMQ_ptr m_LMQ;
Endpoint_ptr m_Endpoint; Endpoint_ptr m_Endpoint;
std::optional<lokimq::ConnectionID> m_Conn; std::optional<lokimq::ConnectionID> m_Conn;

@ -4,6 +4,7 @@
#include <functional> #include <functional>
#include "address.hpp" #include "address.hpp"
#include "handler.hpp" #include "handler.hpp"
#include <crypto/types.hpp>
namespace llarp::service namespace llarp::service
{ {

Loading…
Cancel
Save