diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index eda628dda0..a1f84f8893 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -2,6 +2,8 @@ #include "definition.hpp" #include "ini.hpp" +#include +#include #include #include #include @@ -1152,10 +1154,46 @@ namespace llarp "Recommend localhost-only for security purposes.", }); - conf.defineOption("api", "authkey", Deprecated); + conf.defineOption( + "api", + "bind_curve", + Default{""}, + MultiValue, + [this](std::string arg) mutable { + if (arg.empty()) + return; + + auto pipe = arg.find("|"); + + if (pipe == arg.npos) + throw std::invalid_argument( + "Addresses and whitelisted pubkeys must be pipe-delimited key:value pairs"); + + auto key = arg.substr(0, pipe), values = arg.substr(pipe + 1, arg.npos); - // TODO: this was from pre-refactor: - // TODO: add pubkey to whitelist + if (not starts_with(key, "tcp://")) + key = "tcp://" + key; + + auto pubkeys = split(values, ",", true); + oxenmq::address key_addr{key}; + + for (auto& pk : pubkeys) + m_rpcEncryptedAddresses[key_addr].emplace(pk); + }, + Comment{ + "Specify encrypted listener addresses and comma-delimited public keys to be accepted ", + "by exposed encrypted listener. Keys must be attached to a listener address.", + "", + "Example: ", + " bind_curve=tcp://0.0.0.0:1234|pubkeyA,pubkeyB", + " bind_curve=tcp://0.0.0.0:5678|pubkeyC,pubkeyD", + "", + "In the given example above, port 1234 is only accessible by whitelisted ", + "pubkeys A and B, while 5678 is accessible by C and D.", + "", + "Note: tcp addresses passed without \"tcp://\" prefix will have it prepended"}); + + conf.defineOption("api", "authkey", Deprecated); } void diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 3165f03543..5b18636df8 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -2,8 +2,8 @@ #include "ini.hpp" #include "definition.hpp" +#include #include - #include #include #include @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -190,6 +191,7 @@ namespace llarp { bool m_enableRPCServer = false; std::vector m_rpcBindAddresses; + std::unordered_map> m_rpcEncryptedAddresses; void defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params); diff --git a/llarp/rpc/rpc_server.cpp b/llarp/rpc/rpc_server.cpp index 746557f63e..d3a56d18d1 100644 --- a/llarp/rpc/rpc_server.cpp +++ b/llarp/rpc/rpc_server.cpp @@ -1,5 +1,7 @@ #include "rpc_server.hpp" #include "llarp/rpc/rpc_request_definitions.hpp" +#include "llarp/util/logging.hpp" +#include "oxen/log.hpp" #include "rpc_request.hpp" #include "llarp/service/address.hpp" #include @@ -106,7 +108,22 @@ namespace llarp::rpc for (const auto& addr : r.GetConfig()->api.m_rpcBindAddresses) { m_LMQ->listen_plain(addr.zmq_address()); - LogInfo("Bound RPC server to ", addr.full_address()); + log::info(logcat, "Bound RPC server to {}", addr.full_address()); + } + + for (const auto& [address, allowed_keys] : r.GetConfig()->api.m_rpcEncryptedAddresses) + { + m_LMQ->listen_curve( + address.zmq_address(), [allowed_keys = allowed_keys](auto addr, auto pk, ...) { + if (allowed_keys.count(std::string{pk})) + return oxenmq::AuthLevel::admin; + + log::warning( + logcat, + "Curve pubkey not in whitelist, denying incoming RPC connection from {}", + addr); + return oxenmq::AuthLevel::denied; + }); } AddCategories();