diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index 3c83afc6a..2e9b0314d 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -165,17 +165,24 @@ namespace llarp conf.defineOption("network", "keyfile", false, "", AssignmentAcceptor(m_keyfile)); - conf.defineOption("network", "auth-url", false, "", [this](std::string arg) { - if (arg.empty()) - return; - m_AuthUrl = std::move(arg); - }); + conf.defineOption("network", "auth", false, false, AssignmentAcceptor(m_AuthEnabled)); - conf.defineOption("network", "auth-method", false, "", [this](std::string arg) { - if (arg.empty()) - return; - m_AuthMethod = std::move(arg); - }); + conf.defineOption("network", "auth-url", false, "", AssignmentAcceptor(m_AuthUrl)); + + conf.defineOption( + "network", "auth-method", false, "llarp.auth", [this](std::string arg) { + if (arg.empty()) + return; + m_AuthMethod = std::move(arg); + }); + + conf.defineOption( + "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( "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:", "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); } @@ -908,47 +955,6 @@ namespace llarp "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); } diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 4187405cd..020f3787e 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -82,8 +82,10 @@ namespace llarp std::optional m_exitNode; std::unordered_map m_mapAddrs; + bool m_AuthEnabled = false; std::optional m_AuthUrl; std::optional m_AuthMethod; + std::unordered_set m_AuthWhitelist; // TODO: // on-up diff --git a/llarp/handlers/tun.cpp b/llarp/handlers/tun.cpp index 43f8f9fc3..ef2eaee3f 100644 --- a/llarp/handlers/tun.cpp +++ b/llarp/handlers/tun.cpp @@ -118,7 +118,11 @@ namespace llarp if (conf.m_AuthUrl.has_value() and conf.m_AuthMethod.has_value()) { auto auth = std::make_shared( - *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(); m_AuthPolicy = std::move(auth); } diff --git a/llarp/rpc/endpoint_rpc.cpp b/llarp/rpc/endpoint_rpc.cpp index a2e57e093..64de9bd4c 100644 --- a/llarp/rpc/endpoint_rpc.cpp +++ b/llarp/rpc/endpoint_rpc.cpp @@ -4,9 +4,14 @@ namespace llarp::rpc { 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_AuthMethod(std::move(method)) + , m_AuthWhitelist(std::move(whitelist)) , m_LMQ(std::move(lmq)) , m_Endpoint(std::move(endpoint)) { @@ -15,11 +20,13 @@ namespace llarp::rpc void EndpointAuthRPC::Start() { + if (m_AuthURL.empty()) + return; m_LMQ->connect_remote( m_AuthURL, [self = shared_from_this()](lokimq::ConnectionID 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) { LogWarn("failed to connect to endpoint auth server: ", fail); @@ -33,13 +40,16 @@ namespace llarp::rpc llarp::service::ConvoTag, std::function hook) { + if (m_AuthWhitelist.count(from)) + { + m_Endpoint->RouterLogic()->Call([hook]() { hook(service::AuthResult::eAuthAccepted); }); + return; + } if (not m_Conn.has_value()) { - LogWarn("No connection to ", m_AuthURL); m_Endpoint->RouterLogic()->Call([hook]() { hook(service::AuthResult::eAuthFailed); }); return; } - LogInfo("try auth: ", m_AuthMethod); // call method with 1 parameter: the loki address of the remote m_LMQ->request( *m_Conn, @@ -49,14 +59,12 @@ namespace llarp::rpc service::AuthResult result = service::AuthResult::eAuthFailed; if (success and not data.empty()) { - LogInfo("auth reply: ", data[0]); const auto maybe = service::ParseAuthResult(data[0]); if (maybe.has_value()) { result = *maybe; } } - LogInfo("auth result for ", from, " ", result); self->m_Endpoint->RouterLogic()->Call([hook, result]() { hook(result); }); }, from.ToString()); diff --git a/llarp/rpc/endpoint_rpc.hpp b/llarp/rpc/endpoint_rpc.hpp index 282ae723d..406e24f00 100644 --- a/llarp/rpc/endpoint_rpc.hpp +++ b/llarp/rpc/endpoint_rpc.hpp @@ -15,9 +15,14 @@ namespace llarp::rpc { using LMQ_ptr = std::shared_ptr; using Endpoint_ptr = std::shared_ptr; + using Whitelist_t = std::unordered_set; 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; void @@ -32,6 +37,7 @@ namespace llarp::rpc private: const std::string m_AuthURL; const std::string m_AuthMethod; + const Whitelist_t m_AuthWhitelist; LMQ_ptr m_LMQ; Endpoint_ptr m_Endpoint; std::optional m_Conn; diff --git a/llarp/service/auth.hpp b/llarp/service/auth.hpp index 4c6735861..8f8fdc2d9 100644 --- a/llarp/service/auth.hpp +++ b/llarp/service/auth.hpp @@ -4,6 +4,7 @@ #include #include "address.hpp" #include "handler.hpp" +#include namespace llarp::service {