working new endpoints

- added hotswap functionality
- map_exit and unmap_exit working
pull/2121/head
dan 1 year ago
parent 0632e88de0
commit b2e8cde64b

@ -95,5 +95,5 @@ else:
socket.close(linger=0)
sys.exit(1)
# ./lmq-rpc.py ipc://$HOME/.oxen/testnet/oxend.sock 'llarp.get_service_nodes' | jq
# sample usage:
# ./omq-rpc.py ipc://$HOME/.oxen/testnet/oxend.sock 'llarp.get_service_nodes' | jq

@ -5,10 +5,12 @@
#include <vector>
#include <array>
#include <llarp/net/net.hpp>
#include <string_view>
#include <CLI/App.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/Config.hpp>
#include "oxenmq/address.h"
#ifdef _WIN32
// add the unholy windows headers for iphlpapi
@ -56,7 +58,6 @@ OMQ_Request(
namespace
{
struct command_line_options
{
// bool options
@ -64,6 +65,7 @@ namespace
bool help = false;
bool vpnUp = false;
bool vpnDown = false;
bool swap = false;
bool printStatus = false;
bool killDaemon = false;
@ -73,9 +75,10 @@ namespace
std::string endpoint = "default";
std::string token;
std::optional<std::string> range;
std::vector<std::string> swapExits;
// oxenmq
oxenmq::address rpcURL{"tcp://127.0.0.1:1190"};
oxenmq::address rpcURL{};
oxenmq::LogLevel logLevel = oxenmq::LogLevel::warn;
};
@ -109,15 +112,23 @@ main(int argc, char* argv[])
// flags: boolean values in command_line_options struct
cli.add_flag("-v,--verbose", options.verbose, "Verbose");
cli.add_flag("--up", options.vpnUp, "Put VPN up");
cli.add_flag("--down", options.vpnDown, "Put VPN down");
cli.add_flag("--add,--up", options.vpnUp, "Map VPN connection to exit node [--up is deprecated]");
cli.add_flag(
"--remove,--down",
options.vpnDown,
"Unmap VPN connection to exit node [--down is deprecated]");
cli.add_flag("--status", options.printStatus, "Print VPN status and exit");
cli.add_flag("-k,--kill", options.killDaemon, "Kill lokinet daemon");
// options: string values in command_line_options struct
cli.add_option("--exit", options.exitAddress, "Specify exit node address")->capture_default_str();
cli.add_option("--endpoint", options.endpoint, "Endpoint to use")->capture_default_str();
cli.add_option("--token", options.token, "Exit auth token to use")->capture_default_str();
cli.add_option("--token,--auth", options.token, "Exit auth token to use")->capture_default_str();
cli.add_option("--range", options.range, "IP range to map exit to")->capture_default_str();
cli.add_option(
"--swap", options.swapExits, "Exit addresses to swap mapped connection to [old] [new]")
->expected(2)
->capture_default_str();
// options: oxenmq values in command_line_options struct
cli.add_option("--rpc", options.rpc, "Specify RPC URL for lokinet")->capture_default_str();
@ -149,16 +160,17 @@ main(int argc, char* argv[])
cli.exit(e);
};
int numCommands = options.vpnUp + options.vpnDown + options.printStatus + options.killDaemon;
int numCommands = options.vpnUp + options.vpnDown + options.printStatus + options.killDaemon
+ (not options.swapExits.empty());
switch (numCommands)
{
case 0:
return exit_error(3, "One of --up/--down/--status/--kill must be specified");
return exit_error(3, "One of --add/--remove/--swap/--status/--kill must be specified");
case 1:
break;
default:
return exit_error(3, "Only one of --up/--down/--status/--kill may be specified");
return exit_error(3, "Only one of --add/--remove/--swap/--status/--kill may be specified");
}
if (options.vpnUp and options.exitAddress.empty())
@ -170,12 +182,14 @@ main(int argc, char* argv[])
},
options.logLevel};
options.rpcURL = oxenmq::address{(options.rpc.empty()) ? "tcp://127.0.0.1:1190" : options.rpc};
omq.start();
std::promise<bool> connectPromise;
const auto connectionID = omq.connect_remote(
options.rpc,
options.rpcURL,
[&connectPromise](auto) { connectPromise.set_value(true); },
[&connectPromise](auto, std::string_view msg) {
std::cout << "Failed to connect to lokinet RPC: " << msg << std::endl;
@ -201,15 +215,15 @@ main(int argc, char* argv[])
try
{
const auto& ep = maybe_status->at("result").at("services").at(options.endpoint);
const auto exitMap = ep.at("exitMap");
if (exitMap.empty())
const auto& ep = maybe_status->at("result").at("services").at(options.endpoint).at("exitMap");
if (ep.empty())
{
std::cout << "no exits" << std::endl;
}
else
{
for (const auto& [range, exit] : exitMap.items())
for (const auto& [range, exit] : ep.items())
{
std::cout << range << " via " << exit.get<std::string>() << std::endl;
}
@ -221,6 +235,15 @@ main(int argc, char* argv[])
}
return 0;
}
if (not options.swapExits.empty())
{
nlohmann::json opts{{"exit_addresses", std::move(options.swapExits)}};
if (not OMQ_Request(omq, connectionID, "llarp.swap_exits", std::move(opts)))
return exit_error("Failed to swap exit node connections");
}
if (options.vpnUp)
{
nlohmann::json opts{{"address", options.exitAddress}, {"token", options.token}};
@ -244,7 +267,7 @@ main(int argc, char* argv[])
if (options.range)
opts["ip_range"] = *options.range;
if (not OMQ_Request(omq, connectionID, "llarp.unmap_exit", std::move(opts)))
return exit_error("failed to unmap exit");
return exit_error("Failed to unmap exit node connection");
}
return 0;

@ -31,21 +31,6 @@ namespace llarp
throw std::invalid_argument{"IP string '{}' cannot be parsed as IP range"_format(_range)};
}
static IPRange
StringInit(std::string _range)
{
IPRange range{};
range.FromString(_range);
return range;
}
static bool
IsValidString(std::string _range)
{
IPRange range;
return (range.FromString(_range));
}
static constexpr IPRange
V4MappedRange()
{
@ -62,7 +47,8 @@ namespace llarp
FromIPv4(net::ipv4addr_t addr, net::ipv4addr_t netmask)
{
return IPRange{
net::ExpandV4(ToHost(addr)), netmask_ipv6_bits(bits::count_bits(netmask) + 96)};
net::ExpandV4(llarp::net::ToHost(addr)),
netmask_ipv6_bits(bits::count_bits(netmask) + 96)};
}
/// return true if this iprange is in the IPv4 mapping range for containing ipv4 addresses
@ -125,7 +111,7 @@ namespace llarp
inline bool
Contains(const net::ipaddr_t& ip) const
{
return var::visit([this](auto&& ip) { return Contains(ToHost(ip)); }, ip);
return var::visit([this](auto&& ip) { return Contains(llarp::net::ToHost(ip)); }, ip);
}
/// get the highest address on this range

@ -2,6 +2,7 @@
#include "ip_range.hpp"
#include <llarp/util/status.hpp>
#include <set>
#include <vector>
namespace llarp

@ -25,10 +25,14 @@ namespace llarp::rpc
auto& rpc = handler.rpc;
if (m.data.size() > 1)
m.send_reply(CreateJSONError(
"Bad Request: RPC requests must have at most one data part (received {})"_format(
m.data.size())));
{
m.send_reply(nlohmann::json{
{"error",
"Bad Request: RPC requests must have at most one data part (received {})"_format(
m.data.size())}}
.dump());
return;
}
// parsing input as bt or json
// hand off to parse_request (overloaded versions)
try
@ -49,7 +53,7 @@ namespace llarp::rpc
}
catch (const std::exception& e)
{
m.send_reply(CreateJSONError("Failed to parse request parameters: "s + e.what()));
m.send_reply(nlohmann::json{{"Failed to parse request parameters: "s + e.what()}}.dump());
return;
}

@ -95,12 +95,23 @@ namespace llarp::rpc
llarp::rpc::json_binary_proxy response_b64{
response, llarp::rpc::json_binary_proxy::fmt::base64};
// The oxenmq deferred send object into which the response will be set. If this optional is
// still set when the `invoke` call returns then the response is sent at that point; if it has
// been moved out (i.e. either just this instance or the whole request struct is stolen/moved
// by the invoke function) then it is the invoke function's job to send a reply. Typically
// this is done when a response cannot be sent immediately
// The oxenmq deferred send object into which the response will be sent when the `invoke`
// method returns. If the response needs to happen later (i.e. not immediately after `invoke`
// returns) then you should call `defer()` to extract and clear this and then send the response
// via the returned DeferredSend object yourself.
std::optional<oxenmq::Message::DeferredSend> replier;
// Called to clear the current replier and return it. After this call the automatic reply will
// not be generated; the caller is responsible for calling `->reply` on the returned optional
// itself. This is typically used where a call has to be deferred, for example because it
// depends on some network response to build the reply.
oxenmq::Message::DeferredSend
move()
{
auto r{std::move(*replier)};
replier.reset();
return r;
}
};
// Tag types that are inherited to set RPC endpoint properties

@ -110,7 +110,7 @@ namespace llarp::rpc
} request;
};
// RPC: quick_listener
// RPC: quic_listener
// Connects to QUIC interface on local endpoint
// Passes request parameters in nlohmann::json format
//
@ -171,6 +171,14 @@ namespace llarp::rpc
//
struct MapExit : RPCRequest
{
MapExit()
{
if constexpr (platform::supports_ipv6)
request.ip_range.emplace_back("::/0");
else
request.ip_range.emplace_back("0.0.0.0/0");
}
static constexpr auto name = "map_exit"sv;
struct request_parameters
@ -205,6 +213,14 @@ namespace llarp::rpc
//
struct UnmapExit : RPCRequest
{
UnmapExit()
{
if constexpr (platform::supports_ipv6)
request.ip_range.emplace_back("::/0");
else
request.ip_range.emplace_back("0.0.0.0/0");
}
static constexpr auto name = "unmap_exit"sv;
struct request_parameters
@ -213,6 +229,25 @@ namespace llarp::rpc
} request;
};
// RPC: swap_exit
// Swap a connection from one exit to another
//
// Inputs:
// "exits" : exit nodes to swap mappings from (index 0 = old exit, index 1 = new exit)
//
// Returns:
//
struct SwapExits : RPCRequest
{
static constexpr auto name = "swap_exits"sv;
struct request_parameters
{
std::vector<std::string> exit_addresses;
std::string token;
} request;
};
// RPC: dns_query
// Attempts to query endpoint by domain name
//
@ -268,6 +303,7 @@ namespace llarp::rpc
LookupSnode,
MapExit,
ListExits,
SwapExits,
UnmapExit,
DNSQuery,
Config>;

@ -70,6 +70,17 @@ namespace llarp::rpc
get_values(input, "ip_range", unmapexit.request.ip_range);
}
void
parse_request(SwapExits& swapexits, rpc_input input)
{
get_values(
input,
"exit_addresses",
swapexits.request.exit_addresses,
"token",
swapexits.request.token);
}
void
parse_request(DNSQuery& dnsquery, rpc_input input)
{

@ -26,6 +26,8 @@ namespace llarp::rpc
void
parse_request(UnmapExit& unmapexit, rpc_input input);
void
parse_request(SwapExits& swapexits, rpc_input input);
void
parse_request(DNSQuery& dnsquery, rpc_input input);
void
parse_request(Config& config, rpc_input input);

@ -2,6 +2,7 @@
#include "llarp/rpc/rpc_request_definitions.hpp"
#include "rpc_request.hpp"
#include "llarp/service/address.hpp"
#include <cmath>
#include <exception>
#include <llarp/router/route_poker.hpp>
#include <llarp/config/config.hpp>
@ -147,10 +148,10 @@ namespace llarp::rpc
{
if (not m_Router.IsRunning())
{
halt.response = CreateJSONError("Router is not running");
SetJSONError("Router is not running", halt.response);
return;
}
halt.response = CreateJSONResponse("OK");
SetJSONResponse("OK", halt.response);
m_Router.Stop();
}
@ -160,20 +161,20 @@ namespace llarp::rpc
util::StatusObject result{
{"version", llarp::VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}};
version.response = CreateJSONResponse(result);
SetJSONResponse(result, version.response);
}
void
RPCServer::invoke(Status& status)
{
status.response = (m_Router.IsRunning()) ? CreateJSONResponse(m_Router.ExtractStatus())
: CreateJSONError("Router is not yet ready");
(m_Router.IsRunning()) ? SetJSONResponse(m_Router.ExtractStatus(), status.response)
: SetJSONError("Router is not yet ready", status.response);
}
void
RPCServer::invoke(GetStatus& getstatus)
{
getstatus.response = CreateJSONResponse(m_Router.ExtractSummaryStatus());
SetJSONResponse(m_Router.ExtractSummaryStatus(), getstatus.response);
}
void
@ -181,13 +182,13 @@ namespace llarp::rpc
{
if (quicconnect.request.port == 0 and quicconnect.request.closeID == 0)
{
quicconnect.response = CreateJSONError("Port not provided");
SetJSONError("Port not provided", quicconnect.response);
return;
}
if (quicconnect.request.remoteHost.empty() and quicconnect.request.closeID == 0)
{
quicconnect.response = CreateJSONError("Host not provided");
SetJSONError("Host not provided", quicconnect.response);
return;
}
@ -197,7 +198,7 @@ namespace llarp::rpc
if (not endpoint)
{
quicconnect.response = CreateJSONError("No such local endpoint found.");
SetJSONError("No such local endpoint found.", quicconnect.response);
return;
}
@ -205,15 +206,16 @@ namespace llarp::rpc
if (not quic)
{
quicconnect.response = CreateJSONError(
"No quic interface available on endpoint " + quicconnect.request.endpoint);
SetJSONError(
"No quic interface available on endpoint " + quicconnect.request.endpoint,
quicconnect.response);
return;
}
if (quicconnect.request.closeID)
{
quic->forget(quicconnect.request.closeID);
quicconnect.response = CreateJSONResponse("OK");
SetJSONResponse("OK", quicconnect.response);
return;
}
@ -228,11 +230,11 @@ namespace llarp::rpc
status["addr"] = addr.ToString();
status["id"] = id;
quicconnect.response = CreateJSONResponse(status);
SetJSONResponse(status, quicconnect.response);
}
catch (std::exception& e)
{
quicconnect.response = CreateJSONError(e.what());
SetJSONError(e.what(), quicconnect.response);
}
}
@ -241,7 +243,7 @@ namespace llarp::rpc
{
if (quiclistener.request.port == 0 and quiclistener.request.closeID == 0)
{
quiclistener.response = CreateJSONError("Invalid arguments");
SetJSONError("Invalid arguments", quiclistener.response);
return;
}
@ -251,7 +253,7 @@ namespace llarp::rpc
if (not endpoint)
{
quiclistener.response = CreateJSONError("No such local endpoint found");
SetJSONError("No such local endpoint found", quiclistener.response);
return;
}
@ -259,15 +261,16 @@ namespace llarp::rpc
if (not quic)
{
quiclistener.response = CreateJSONError(
"No quic interface available on endpoint " + quiclistener.request.endpoint);
SetJSONError(
"No quic interface available on endpoint " + quiclistener.request.endpoint,
quiclistener.response);
return;
}
if (quiclistener.request.closeID)
{
quic->forget(quiclistener.request.closeID);
quiclistener.response = CreateJSONResponse("OK");
SetJSONResponse("OK", quiclistener.response);
return;
}
@ -281,7 +284,7 @@ namespace llarp::rpc
}
catch (std::exception& e)
{
quiclistener.response = CreateJSONError(e.what());
SetJSONError(e.what(), quiclistener.response);
return;
}
@ -298,30 +301,31 @@ namespace llarp::rpc
endpoint->PutSRVRecord(std::move(srvData));
}
quiclistener.response = CreateJSONResponse(result);
SetJSONResponse(result, quiclistener.response);
return;
}
}
// TODO: fix this because it's bad
void
RPCServer::invoke(LookupSnode& lookupsnode)
{
if (not m_Router.IsServiceNode())
{
lookupsnode.response = CreateJSONError("Not supported");
SetJSONError("Not supported", lookupsnode.response);
return;
}
RouterID routerID;
if (lookupsnode.request.routerID.empty())
{
lookupsnode.response = CreateJSONError("No remote ID provided");
SetJSONError("No remote ID provided", lookupsnode.response);
return;
}
if (not routerID.FromString(lookupsnode.request.routerID))
{
lookupsnode.response = CreateJSONError("Invalid remote: " + lookupsnode.request.routerID);
SetJSONError("Invalid remote: " + lookupsnode.request.routerID, lookupsnode.response);
return;
}
@ -330,7 +334,7 @@ namespace llarp::rpc
if (endpoint == nullptr)
{
lookupsnode.response = CreateJSONError("Cannot find local endpoint: default");
SetJSONError("Cannot find local endpoint: default", lookupsnode.response);
return;
}
@ -339,11 +343,11 @@ namespace llarp::rpc
{
const auto ip = net::TruncateV6(endpoint->GetIPForIdent(PubKey{routerID}));
util::StatusObject status{{"ip", ip.ToString()}};
lookupsnode.response = CreateJSONResponse(status);
SetJSONResponse(status, lookupsnode.response);
return;
}
lookupsnode.response = CreateJSONError("Failed to obtain snode session");
SetJSONError("Failed to obtain snode session", lookupsnode.response);
return;
});
});
@ -353,8 +357,8 @@ namespace llarp::rpc
RPCServer::invoke(MapExit& mapexit)
{
MapExit exit_request;
// steal replier from exit RPC endpoint
exit_request.replier.emplace(std::move(*mapexit.replier));
// steal replier from exit RPC endpoint
exit_request.replier.emplace(mapexit.move());
m_Router.hiddenServiceContext().GetDefault()->map_exit(
mapexit.request.address,
@ -372,35 +376,104 @@ namespace llarp::rpc
RPCServer::invoke(ListExits& listexits)
{
if (not m_Router.hiddenServiceContext().hasEndpoints())
listexits.response = CreateJSONError("No mapped endpoints found");
else
listexits.response =
CreateJSONResponse(m_Router.hiddenServiceContext().GetDefault()->ExtractStatus()["m_"
"ExitMa"
"p"]);
{
SetJSONError("No mapped endpoints found", listexits.response);
return;
}
auto status = m_Router.hiddenServiceContext().GetDefault()->ExtractStatus()["exitMap"];
SetJSONResponse((status.empty()) ? "No exits" : status, listexits.response);
}
void
RPCServer::invoke(UnmapExit& unmapexit)
{
if (unmapexit.request.ip_range.empty())
{
unmapexit.response = CreateJSONError("No IP range provided");
return;
}
try
{
m_Router.routePoker()->Down();
for (auto& ip : unmapexit.request.ip_range)
m_Router.hiddenServiceContext().GetDefault()->UnmapExitRange(ip);
}
catch (std::exception& e)
{
unmapexit.response = CreateJSONError("Unable to unmap to given range");
SetJSONError("Unable to unmap to given range", unmapexit.response);
return;
}
SetJSONResponse("OK", unmapexit.response);
}
// Sequentially calls map_exit and unmap_exit to hotswap mapped connection from old exit
// to new exit. Similar to how map_exit steals the oxenmq deferredsend object, swapexit
// moves the replier object to the unmap_exit struct, as that is called second. Rather than
// the nested lambda within map_exit making the reply call, it instead calls the unmap_exit logic
// and leaves the message handling to the unmap_exit struct
void
RPCServer::invoke(SwapExits& swapexits)
{
MapExit map_request;
UnmapExit unmap_request;
auto endpoint = m_Router.hiddenServiceContext().GetDefault();
auto current_exits = endpoint->ExtractStatus()["exitMap"];
if (current_exits.empty())
{
SetJSONError("Cannot swap to new exit: no exits currently mapped", swapexits.response);
return;
}
unmapexit.response = CreateJSONResponse("OK");
// steal replier from swapexit RPC endpoint
unmap_request.replier.emplace(swapexits.move());
// set map_exit request to new address
map_request.request.address = swapexits.request.exit_addresses[1];
// set token for new exit node mapping
if (not swapexits.request.token.empty())
map_request.request.token = swapexits.request.token;
// populate map_exit request with old IP ranges
for (auto& [range, exit] : current_exits.items())
{
if (exit.get<std::string>() == swapexits.request.exit_addresses[0])
{
map_request.request.ip_range.emplace_back(range);
unmap_request.request.ip_range.emplace_back(range);
}
}
if (map_request.request.ip_range.empty() or unmap_request.request.ip_range.empty())
{
SetJSONError("No mapped ranges found matching requested swap", swapexits.response);
return;
}
endpoint->map_exit(
map_request.request.address,
map_request.request.token,
map_request.request.ip_range,
[unmap = std::move(unmap_request),
ep = endpoint,
old_exit = swapexits.request.exit_addresses[0]](bool success, std::string result) mutable {
if (not success)
unmap.send_response({{"error"}, std::move(result)});
else
{
try
{
for (auto& ip : unmap.request.ip_range)
ep->UnmapRangeByExit(ip, old_exit);
}
catch (std::exception& e)
{
SetJSONError("Unable to unmap to given range", unmap.response);
return;
}
SetJSONResponse("OK", unmap.response);
unmap.send_response();
}
});
}
void
@ -417,7 +490,7 @@ namespace llarp::rpc
if (endpoint == nullptr)
{
dnsquery.response = CreateJSONError("No such endpoint found for dns query");
SetJSONError("No such endpoint found for dns query", dnsquery.response);
return;
}
@ -425,16 +498,16 @@ namespace llarp::rpc
{
auto packet_src = std::make_shared<DummyPacketSource>([&](auto result) {
if (result)
dnsquery.response = CreateJSONResponse(result->ToJSON());
SetJSONResponse(result->ToJSON(), dnsquery.response);
else
dnsquery.response = CreateJSONError("No response from DNS");
SetJSONError("No response from DNS", dnsquery.response);
});
if (not dns->MaybeHandlePacket(
packet_src, packet_src->dumb, packet_src->dumb, msg.ToBuffer()))
dnsquery.response = CreateJSONError("DNS query not accepted by endpoint");
SetJSONError("DNS query not accepted by endpoint", dnsquery.response);
}
else
dnsquery.response = CreateJSONError("Endpoint does not have dns");
SetJSONError("Endpoint does not have dns", dnsquery.response);
return;
}
@ -443,24 +516,24 @@ namespace llarp::rpc
{
if (config.request.filename.empty() and not config.request.ini.empty())
{
config.response = CreateJSONError("No filename specified for .ini file");
SetJSONError("No filename specified for .ini file", config.response);
return;
}
if (config.request.ini.empty() and not config.request.filename.empty())
{
config.response = CreateJSONError("No .ini chunk provided");
SetJSONError("No .ini chunk provided", config.response);
return;
}
if (not ends_with(config.request.filename, ".ini"))
{
config.response = CreateJSONError("Must append '.ini' to filename");
SetJSONError("Must append '.ini' to filename", config.response);
return;
}
if (not check_path(config.request.filename))
{
config.response = CreateJSONError("Bad filename passed");
SetJSONError("Bad filename passed", config.response);
return;
}
@ -475,7 +548,7 @@ namespace llarp::rpc
}
catch (std::exception& e)
{
config.response = CreateJSONError(e.what());
SetJSONError(e.what(), config.response);
return;
}
}
@ -496,12 +569,12 @@ namespace llarp::rpc
}
catch (std::exception& e)
{
config.response = CreateJSONError(e.what());
SetJSONError(e.what(), config.response);
return;
}
}
config.response = CreateJSONResponse("OK");
SetJSONResponse("OK", config.response);
}
void
@ -538,4 +611,4 @@ namespace llarp::rpc
}
}
} // namespace llarp::rpc
} // namespace llarp::rpc

@ -2,6 +2,8 @@
#include "rpc_request_definitions.hpp"
#include "json_bt.hpp"
#include <nlohmann/json_fwd.hpp>
#include <stdexcept>
#include <string_view>
#include <llarp/config/config.hpp>
#include <oxenmq/oxenmq.h>
@ -64,16 +66,16 @@ namespace llarp::rpc
};
template <typename Result_t>
std::string
CreateJSONResponse(Result_t result)
void
SetJSONResponse(Result_t result, json& j)
{
return nlohmann::json{{"result", result}}.dump();
j["result"] = result;
}
inline std::string
CreateJSONError(std::string_view msg)
inline void
SetJSONError(std::string_view msg, json& j)
{
return nlohmann::json{{"error", msg}}.dump();
j["error"] = msg;
}
class RPCServer
@ -109,6 +111,8 @@ namespace llarp::rpc
void
invoke(UnmapExit& unmapexit);
void
invoke(SwapExits& swapexits);
void
invoke(DNSQuery& dnsquery);
void
invoke(Config& config);
@ -140,18 +144,21 @@ namespace llarp::rpc
catch (const rpc_error& e)
{
log::info(logcat, "RPC request 'rpc.{}' failed with: {}", rpc.name, e.what());
rpc.response = CreateJSONError(
fmt::format("RPC request 'rpc.{}' failed with: {}", rpc.name, e.what()));
SetJSONError(
fmt::format("RPC request 'rpc.{}' failed with: {}", rpc.name, e.what()), rpc.response);
}
catch (const std::exception& e)
{
log::info(logcat, "RPC request 'rpc.{}' raised an exception: {}", rpc.name, e.what());
rpc.response = CreateJSONError(
fmt::format("RPC request 'rpc.{}' raised an exception: {}", rpc.name, e.what()));
SetJSONError(
fmt::format("RPC request 'rpc.{}' raised an exception: {}", rpc.name, e.what()),
rpc.response);
}
if (rpc.replier.has_value())
{
rpc.send_response();
}
}
};

@ -3,6 +3,7 @@
#include "endpoint_util.hpp"
#include "hidden_service_address_lookup.hpp"
#include "auth.hpp"
#include "llarp/util/logging.hpp"
#include "outbound_context.hpp"
#include "protocol.hpp"
#include "info.hpp"
@ -2188,6 +2189,26 @@ namespace llarp
LogInfo(Name(), " unmap ", item.first, " exit range mapping");
return true;
});
if (m_ExitMap.Empty())
m_router->routePoker()->Down();
}
void
Endpoint::UnmapRangeByExit(IPRange range, std::string exit)
{
// unmap all ranges that match the given exit when hot swapping
m_ExitMap.RemoveIf([&](const auto& item) -> bool {
if ((range.Contains(item.first)) and (item.second.ToString() == exit))
{
log::info(logcat, "{} unmap {} range mapping to exit node {}", Name(), item.first, exit);
return true;
}
return false;
});
if (m_ExitMap.Empty())
m_router->routePoker()->Down();
}
std::optional<AuthInfo>

@ -284,6 +284,9 @@ namespace llarp
void
UnmapExitRange(IPRange range);
void
UnmapRangeByExit(IPRange range, std::string exit);
void
map_exit(
std::string name,

Loading…
Cancel
Save