mirror of https://github.com/oxen-io/lokinet
working new endpoints
- added hotswap functionality - map_exit and unmap_exit working
This commit is contained in:
parent
0632e88de0
commit
b2e8cde64b
|
@ -95,5 +95,5 @@ else:
|
||||||
socket.close(linger=0)
|
socket.close(linger=0)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# sample usage:
|
||||||
# ./lmq-rpc.py ipc://$HOME/.oxen/testnet/oxend.sock 'llarp.get_service_nodes' | jq
|
# ./omq-rpc.py ipc://$HOME/.oxen/testnet/oxend.sock 'llarp.get_service_nodes' | jq
|
||||||
|
|
|
@ -5,10 +5,12 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <llarp/net/net.hpp>
|
#include <llarp/net/net.hpp>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#include <CLI/App.hpp>
|
#include <CLI/App.hpp>
|
||||||
#include <CLI/Formatter.hpp>
|
#include <CLI/Formatter.hpp>
|
||||||
#include <CLI/Config.hpp>
|
#include <CLI/Config.hpp>
|
||||||
|
#include "oxenmq/address.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// add the unholy windows headers for iphlpapi
|
// add the unholy windows headers for iphlpapi
|
||||||
|
@ -56,7 +58,6 @@ OMQ_Request(
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
struct command_line_options
|
struct command_line_options
|
||||||
{
|
{
|
||||||
// bool options
|
// bool options
|
||||||
|
@ -64,6 +65,7 @@ namespace
|
||||||
bool help = false;
|
bool help = false;
|
||||||
bool vpnUp = false;
|
bool vpnUp = false;
|
||||||
bool vpnDown = false;
|
bool vpnDown = false;
|
||||||
|
bool swap = false;
|
||||||
bool printStatus = false;
|
bool printStatus = false;
|
||||||
bool killDaemon = false;
|
bool killDaemon = false;
|
||||||
|
|
||||||
|
@ -73,9 +75,10 @@ namespace
|
||||||
std::string endpoint = "default";
|
std::string endpoint = "default";
|
||||||
std::string token;
|
std::string token;
|
||||||
std::optional<std::string> range;
|
std::optional<std::string> range;
|
||||||
|
std::vector<std::string> swapExits;
|
||||||
|
|
||||||
// oxenmq
|
// oxenmq
|
||||||
oxenmq::address rpcURL{"tcp://127.0.0.1:1190"};
|
oxenmq::address rpcURL{};
|
||||||
oxenmq::LogLevel logLevel = oxenmq::LogLevel::warn;
|
oxenmq::LogLevel logLevel = oxenmq::LogLevel::warn;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -109,15 +112,23 @@ main(int argc, char* argv[])
|
||||||
|
|
||||||
// flags: boolean values in command_line_options struct
|
// flags: boolean values in command_line_options struct
|
||||||
cli.add_flag("-v,--verbose", options.verbose, "Verbose");
|
cli.add_flag("-v,--verbose", options.verbose, "Verbose");
|
||||||
cli.add_flag("--up", options.vpnUp, "Put VPN up");
|
cli.add_flag("--add,--up", options.vpnUp, "Map VPN connection to exit node [--up is deprecated]");
|
||||||
cli.add_flag("--down", options.vpnDown, "Put VPN down");
|
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("--status", options.printStatus, "Print VPN status and exit");
|
||||||
cli.add_flag("-k,--kill", options.killDaemon, "Kill lokinet daemon");
|
cli.add_flag("-k,--kill", options.killDaemon, "Kill lokinet daemon");
|
||||||
|
|
||||||
// options: string values in command_line_options struct
|
// options: string values in command_line_options struct
|
||||||
cli.add_option("--exit", options.exitAddress, "Specify exit node address")->capture_default_str();
|
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("--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
|
// options: oxenmq values in command_line_options struct
|
||||||
cli.add_option("--rpc", options.rpc, "Specify RPC URL for lokinet")->capture_default_str();
|
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);
|
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)
|
switch (numCommands)
|
||||||
{
|
{
|
||||||
case 0:
|
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:
|
case 1:
|
||||||
break;
|
break;
|
||||||
default:
|
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())
|
if (options.vpnUp and options.exitAddress.empty())
|
||||||
|
@ -170,12 +182,14 @@ main(int argc, char* argv[])
|
||||||
},
|
},
|
||||||
options.logLevel};
|
options.logLevel};
|
||||||
|
|
||||||
|
options.rpcURL = oxenmq::address{(options.rpc.empty()) ? "tcp://127.0.0.1:1190" : options.rpc};
|
||||||
|
|
||||||
omq.start();
|
omq.start();
|
||||||
|
|
||||||
std::promise<bool> connectPromise;
|
std::promise<bool> connectPromise;
|
||||||
|
|
||||||
const auto connectionID = omq.connect_remote(
|
const auto connectionID = omq.connect_remote(
|
||||||
options.rpc,
|
options.rpcURL,
|
||||||
[&connectPromise](auto) { connectPromise.set_value(true); },
|
[&connectPromise](auto) { connectPromise.set_value(true); },
|
||||||
[&connectPromise](auto, std::string_view msg) {
|
[&connectPromise](auto, std::string_view msg) {
|
||||||
std::cout << "Failed to connect to lokinet RPC: " << msg << std::endl;
|
std::cout << "Failed to connect to lokinet RPC: " << msg << std::endl;
|
||||||
|
@ -201,15 +215,15 @@ main(int argc, char* argv[])
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const auto& ep = maybe_status->at("result").at("services").at(options.endpoint);
|
const auto& ep = maybe_status->at("result").at("services").at(options.endpoint).at("exitMap");
|
||||||
const auto exitMap = ep.at("exitMap");
|
|
||||||
if (exitMap.empty())
|
if (ep.empty())
|
||||||
{
|
{
|
||||||
std::cout << "no exits" << std::endl;
|
std::cout << "no exits" << std::endl;
|
||||||
}
|
}
|
||||||
else
|
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;
|
std::cout << range << " via " << exit.get<std::string>() << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -221,6 +235,15 @@ main(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
return 0;
|
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)
|
if (options.vpnUp)
|
||||||
{
|
{
|
||||||
nlohmann::json opts{{"address", options.exitAddress}, {"token", options.token}};
|
nlohmann::json opts{{"address", options.exitAddress}, {"token", options.token}};
|
||||||
|
@ -244,7 +267,7 @@ main(int argc, char* argv[])
|
||||||
if (options.range)
|
if (options.range)
|
||||||
opts["ip_range"] = *options.range;
|
opts["ip_range"] = *options.range;
|
||||||
if (not OMQ_Request(omq, connectionID, "llarp.unmap_exit", std::move(opts)))
|
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;
|
return 0;
|
||||||
|
|
|
@ -31,21 +31,6 @@ namespace llarp
|
||||||
throw std::invalid_argument{"IP string '{}' cannot be parsed as IP range"_format(_range)};
|
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
|
static constexpr IPRange
|
||||||
V4MappedRange()
|
V4MappedRange()
|
||||||
{
|
{
|
||||||
|
@ -62,7 +47,8 @@ namespace llarp
|
||||||
FromIPv4(net::ipv4addr_t addr, net::ipv4addr_t netmask)
|
FromIPv4(net::ipv4addr_t addr, net::ipv4addr_t netmask)
|
||||||
{
|
{
|
||||||
return IPRange{
|
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
|
/// return true if this iprange is in the IPv4 mapping range for containing ipv4 addresses
|
||||||
|
@ -125,7 +111,7 @@ namespace llarp
|
||||||
inline bool
|
inline bool
|
||||||
Contains(const net::ipaddr_t& ip) const
|
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
|
/// get the highest address on this range
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "ip_range.hpp"
|
#include "ip_range.hpp"
|
||||||
#include <llarp/util/status.hpp>
|
#include <llarp/util/status.hpp>
|
||||||
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace llarp
|
namespace llarp
|
||||||
|
|
|
@ -25,10 +25,14 @@ namespace llarp::rpc
|
||||||
auto& rpc = handler.rpc;
|
auto& rpc = handler.rpc;
|
||||||
|
|
||||||
if (m.data.size() > 1)
|
if (m.data.size() > 1)
|
||||||
m.send_reply(CreateJSONError(
|
{
|
||||||
"Bad Request: RPC requests must have at most one data part (received {})"_format(
|
m.send_reply(nlohmann::json{
|
||||||
m.data.size())));
|
{"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
|
// parsing input as bt or json
|
||||||
// hand off to parse_request (overloaded versions)
|
// hand off to parse_request (overloaded versions)
|
||||||
try
|
try
|
||||||
|
@ -49,7 +53,7 @@ namespace llarp::rpc
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,12 +95,23 @@ namespace llarp::rpc
|
||||||
llarp::rpc::json_binary_proxy response_b64{
|
llarp::rpc::json_binary_proxy response_b64{
|
||||||
response, llarp::rpc::json_binary_proxy::fmt::base64};
|
response, llarp::rpc::json_binary_proxy::fmt::base64};
|
||||||
|
|
||||||
// The oxenmq deferred send object into which the response will be set. If this optional is
|
// The oxenmq deferred send object into which the response will be sent when the `invoke`
|
||||||
// still set when the `invoke` call returns then the response is sent at that point; if it has
|
// method returns. If the response needs to happen later (i.e. not immediately after `invoke`
|
||||||
// been moved out (i.e. either just this instance or the whole request struct is stolen/moved
|
// returns) then you should call `defer()` to extract and clear this and then send the response
|
||||||
// by the invoke function) then it is the invoke function's job to send a reply. Typically
|
// via the returned DeferredSend object yourself.
|
||||||
// this is done when a response cannot be sent immediately
|
|
||||||
std::optional<oxenmq::Message::DeferredSend> replier;
|
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
|
// Tag types that are inherited to set RPC endpoint properties
|
||||||
|
|
|
@ -110,7 +110,7 @@ namespace llarp::rpc
|
||||||
} request;
|
} request;
|
||||||
};
|
};
|
||||||
|
|
||||||
// RPC: quick_listener
|
// RPC: quic_listener
|
||||||
// Connects to QUIC interface on local endpoint
|
// Connects to QUIC interface on local endpoint
|
||||||
// Passes request parameters in nlohmann::json format
|
// Passes request parameters in nlohmann::json format
|
||||||
//
|
//
|
||||||
|
@ -171,6 +171,14 @@ namespace llarp::rpc
|
||||||
//
|
//
|
||||||
struct MapExit : RPCRequest
|
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;
|
static constexpr auto name = "map_exit"sv;
|
||||||
|
|
||||||
struct request_parameters
|
struct request_parameters
|
||||||
|
@ -205,6 +213,14 @@ namespace llarp::rpc
|
||||||
//
|
//
|
||||||
struct UnmapExit : RPCRequest
|
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;
|
static constexpr auto name = "unmap_exit"sv;
|
||||||
|
|
||||||
struct request_parameters
|
struct request_parameters
|
||||||
|
@ -213,6 +229,25 @@ namespace llarp::rpc
|
||||||
} request;
|
} 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
|
// RPC: dns_query
|
||||||
// Attempts to query endpoint by domain name
|
// Attempts to query endpoint by domain name
|
||||||
//
|
//
|
||||||
|
@ -268,6 +303,7 @@ namespace llarp::rpc
|
||||||
LookupSnode,
|
LookupSnode,
|
||||||
MapExit,
|
MapExit,
|
||||||
ListExits,
|
ListExits,
|
||||||
|
SwapExits,
|
||||||
UnmapExit,
|
UnmapExit,
|
||||||
DNSQuery,
|
DNSQuery,
|
||||||
Config>;
|
Config>;
|
||||||
|
|
|
@ -70,6 +70,17 @@ namespace llarp::rpc
|
||||||
get_values(input, "ip_range", unmapexit.request.ip_range);
|
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
|
void
|
||||||
parse_request(DNSQuery& dnsquery, rpc_input input)
|
parse_request(DNSQuery& dnsquery, rpc_input input)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace llarp::rpc
|
||||||
void
|
void
|
||||||
parse_request(UnmapExit& unmapexit, rpc_input input);
|
parse_request(UnmapExit& unmapexit, rpc_input input);
|
||||||
void
|
void
|
||||||
|
parse_request(SwapExits& swapexits, rpc_input input);
|
||||||
|
void
|
||||||
parse_request(DNSQuery& dnsquery, rpc_input input);
|
parse_request(DNSQuery& dnsquery, rpc_input input);
|
||||||
void
|
void
|
||||||
parse_request(Config& config, rpc_input input);
|
parse_request(Config& config, rpc_input input);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "llarp/rpc/rpc_request_definitions.hpp"
|
#include "llarp/rpc/rpc_request_definitions.hpp"
|
||||||
#include "rpc_request.hpp"
|
#include "rpc_request.hpp"
|
||||||
#include "llarp/service/address.hpp"
|
#include "llarp/service/address.hpp"
|
||||||
|
#include <cmath>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <llarp/router/route_poker.hpp>
|
#include <llarp/router/route_poker.hpp>
|
||||||
#include <llarp/config/config.hpp>
|
#include <llarp/config/config.hpp>
|
||||||
|
@ -147,10 +148,10 @@ namespace llarp::rpc
|
||||||
{
|
{
|
||||||
if (not m_Router.IsRunning())
|
if (not m_Router.IsRunning())
|
||||||
{
|
{
|
||||||
halt.response = CreateJSONError("Router is not running");
|
SetJSONError("Router is not running", halt.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
halt.response = CreateJSONResponse("OK");
|
SetJSONResponse("OK", halt.response);
|
||||||
m_Router.Stop();
|
m_Router.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,20 +161,20 @@ namespace llarp::rpc
|
||||||
util::StatusObject result{
|
util::StatusObject result{
|
||||||
{"version", llarp::VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}};
|
{"version", llarp::VERSION_FULL}, {"uptime", to_json(m_Router.Uptime())}};
|
||||||
|
|
||||||
version.response = CreateJSONResponse(result);
|
SetJSONResponse(result, version.response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RPCServer::invoke(Status& status)
|
RPCServer::invoke(Status& status)
|
||||||
{
|
{
|
||||||
status.response = (m_Router.IsRunning()) ? CreateJSONResponse(m_Router.ExtractStatus())
|
(m_Router.IsRunning()) ? SetJSONResponse(m_Router.ExtractStatus(), status.response)
|
||||||
: CreateJSONError("Router is not yet ready");
|
: SetJSONError("Router is not yet ready", status.response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RPCServer::invoke(GetStatus& getstatus)
|
RPCServer::invoke(GetStatus& getstatus)
|
||||||
{
|
{
|
||||||
getstatus.response = CreateJSONResponse(m_Router.ExtractSummaryStatus());
|
SetJSONResponse(m_Router.ExtractSummaryStatus(), getstatus.response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -181,13 +182,13 @@ namespace llarp::rpc
|
||||||
{
|
{
|
||||||
if (quicconnect.request.port == 0 and quicconnect.request.closeID == 0)
|
if (quicconnect.request.port == 0 and quicconnect.request.closeID == 0)
|
||||||
{
|
{
|
||||||
quicconnect.response = CreateJSONError("Port not provided");
|
SetJSONError("Port not provided", quicconnect.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quicconnect.request.remoteHost.empty() and quicconnect.request.closeID == 0)
|
if (quicconnect.request.remoteHost.empty() and quicconnect.request.closeID == 0)
|
||||||
{
|
{
|
||||||
quicconnect.response = CreateJSONError("Host not provided");
|
SetJSONError("Host not provided", quicconnect.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +198,7 @@ namespace llarp::rpc
|
||||||
|
|
||||||
if (not endpoint)
|
if (not endpoint)
|
||||||
{
|
{
|
||||||
quicconnect.response = CreateJSONError("No such local endpoint found.");
|
SetJSONError("No such local endpoint found.", quicconnect.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,15 +206,16 @@ namespace llarp::rpc
|
||||||
|
|
||||||
if (not quic)
|
if (not quic)
|
||||||
{
|
{
|
||||||
quicconnect.response = CreateJSONError(
|
SetJSONError(
|
||||||
"No quic interface available on endpoint " + quicconnect.request.endpoint);
|
"No quic interface available on endpoint " + quicconnect.request.endpoint,
|
||||||
|
quicconnect.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quicconnect.request.closeID)
|
if (quicconnect.request.closeID)
|
||||||
{
|
{
|
||||||
quic->forget(quicconnect.request.closeID);
|
quic->forget(quicconnect.request.closeID);
|
||||||
quicconnect.response = CreateJSONResponse("OK");
|
SetJSONResponse("OK", quicconnect.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,11 +230,11 @@ namespace llarp::rpc
|
||||||
status["addr"] = addr.ToString();
|
status["addr"] = addr.ToString();
|
||||||
status["id"] = id;
|
status["id"] = id;
|
||||||
|
|
||||||
quicconnect.response = CreateJSONResponse(status);
|
SetJSONResponse(status, quicconnect.response);
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
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)
|
if (quiclistener.request.port == 0 and quiclistener.request.closeID == 0)
|
||||||
{
|
{
|
||||||
quiclistener.response = CreateJSONError("Invalid arguments");
|
SetJSONError("Invalid arguments", quiclistener.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +253,7 @@ namespace llarp::rpc
|
||||||
|
|
||||||
if (not endpoint)
|
if (not endpoint)
|
||||||
{
|
{
|
||||||
quiclistener.response = CreateJSONError("No such local endpoint found");
|
SetJSONError("No such local endpoint found", quiclistener.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,15 +261,16 @@ namespace llarp::rpc
|
||||||
|
|
||||||
if (not quic)
|
if (not quic)
|
||||||
{
|
{
|
||||||
quiclistener.response = CreateJSONError(
|
SetJSONError(
|
||||||
"No quic interface available on endpoint " + quiclistener.request.endpoint);
|
"No quic interface available on endpoint " + quiclistener.request.endpoint,
|
||||||
|
quiclistener.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quiclistener.request.closeID)
|
if (quiclistener.request.closeID)
|
||||||
{
|
{
|
||||||
quic->forget(quiclistener.request.closeID);
|
quic->forget(quiclistener.request.closeID);
|
||||||
quiclistener.response = CreateJSONResponse("OK");
|
SetJSONResponse("OK", quiclistener.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +284,7 @@ namespace llarp::rpc
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
quiclistener.response = CreateJSONError(e.what());
|
SetJSONError(e.what(), quiclistener.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,30 +301,31 @@ namespace llarp::rpc
|
||||||
endpoint->PutSRVRecord(std::move(srvData));
|
endpoint->PutSRVRecord(std::move(srvData));
|
||||||
}
|
}
|
||||||
|
|
||||||
quiclistener.response = CreateJSONResponse(result);
|
SetJSONResponse(result, quiclistener.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: fix this because it's bad
|
||||||
void
|
void
|
||||||
RPCServer::invoke(LookupSnode& lookupsnode)
|
RPCServer::invoke(LookupSnode& lookupsnode)
|
||||||
{
|
{
|
||||||
if (not m_Router.IsServiceNode())
|
if (not m_Router.IsServiceNode())
|
||||||
{
|
{
|
||||||
lookupsnode.response = CreateJSONError("Not supported");
|
SetJSONError("Not supported", lookupsnode.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RouterID routerID;
|
RouterID routerID;
|
||||||
if (lookupsnode.request.routerID.empty())
|
if (lookupsnode.request.routerID.empty())
|
||||||
{
|
{
|
||||||
lookupsnode.response = CreateJSONError("No remote ID provided");
|
SetJSONError("No remote ID provided", lookupsnode.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not routerID.FromString(lookupsnode.request.routerID))
|
if (not routerID.FromString(lookupsnode.request.routerID))
|
||||||
{
|
{
|
||||||
lookupsnode.response = CreateJSONError("Invalid remote: " + lookupsnode.request.routerID);
|
SetJSONError("Invalid remote: " + lookupsnode.request.routerID, lookupsnode.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +334,7 @@ namespace llarp::rpc
|
||||||
|
|
||||||
if (endpoint == nullptr)
|
if (endpoint == nullptr)
|
||||||
{
|
{
|
||||||
lookupsnode.response = CreateJSONError("Cannot find local endpoint: default");
|
SetJSONError("Cannot find local endpoint: default", lookupsnode.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,11 +343,11 @@ namespace llarp::rpc
|
||||||
{
|
{
|
||||||
const auto ip = net::TruncateV6(endpoint->GetIPForIdent(PubKey{routerID}));
|
const auto ip = net::TruncateV6(endpoint->GetIPForIdent(PubKey{routerID}));
|
||||||
util::StatusObject status{{"ip", ip.ToString()}};
|
util::StatusObject status{{"ip", ip.ToString()}};
|
||||||
lookupsnode.response = CreateJSONResponse(status);
|
SetJSONResponse(status, lookupsnode.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lookupsnode.response = CreateJSONError("Failed to obtain snode session");
|
SetJSONError("Failed to obtain snode session", lookupsnode.response);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -353,8 +357,8 @@ namespace llarp::rpc
|
||||||
RPCServer::invoke(MapExit& mapexit)
|
RPCServer::invoke(MapExit& mapexit)
|
||||||
{
|
{
|
||||||
MapExit exit_request;
|
MapExit exit_request;
|
||||||
// steal replier from exit RPC endpoint
|
// steal replier from exit RPC endpoint
|
||||||
exit_request.replier.emplace(std::move(*mapexit.replier));
|
exit_request.replier.emplace(mapexit.move());
|
||||||
|
|
||||||
m_Router.hiddenServiceContext().GetDefault()->map_exit(
|
m_Router.hiddenServiceContext().GetDefault()->map_exit(
|
||||||
mapexit.request.address,
|
mapexit.request.address,
|
||||||
|
@ -372,35 +376,104 @@ namespace llarp::rpc
|
||||||
RPCServer::invoke(ListExits& listexits)
|
RPCServer::invoke(ListExits& listexits)
|
||||||
{
|
{
|
||||||
if (not m_Router.hiddenServiceContext().hasEndpoints())
|
if (not m_Router.hiddenServiceContext().hasEndpoints())
|
||||||
listexits.response = CreateJSONError("No mapped endpoints found");
|
{
|
||||||
else
|
SetJSONError("No mapped endpoints found", listexits.response);
|
||||||
listexits.response =
|
return;
|
||||||
CreateJSONResponse(m_Router.hiddenServiceContext().GetDefault()->ExtractStatus()["m_"
|
}
|
||||||
"ExitMa"
|
|
||||||
"p"]);
|
auto status = m_Router.hiddenServiceContext().GetDefault()->ExtractStatus()["exitMap"];
|
||||||
|
|
||||||
|
SetJSONResponse((status.empty()) ? "No exits" : status, listexits.response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
RPCServer::invoke(UnmapExit& unmapexit)
|
RPCServer::invoke(UnmapExit& unmapexit)
|
||||||
{
|
{
|
||||||
if (unmapexit.request.ip_range.empty())
|
|
||||||
{
|
|
||||||
unmapexit.response = CreateJSONError("No IP range provided");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_Router.routePoker()->Down();
|
|
||||||
for (auto& ip : unmapexit.request.ip_range)
|
for (auto& ip : unmapexit.request.ip_range)
|
||||||
m_Router.hiddenServiceContext().GetDefault()->UnmapExitRange(ip);
|
m_Router.hiddenServiceContext().GetDefault()->UnmapExitRange(ip);
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
unmapexit.response = CreateJSONError("Unable to unmap to given range");
|
SetJSONError("Unable to unmap to given range", unmapexit.response);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unmapexit.response = CreateJSONResponse("OK");
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
void
|
||||||
|
@ -417,7 +490,7 @@ namespace llarp::rpc
|
||||||
|
|
||||||
if (endpoint == nullptr)
|
if (endpoint == nullptr)
|
||||||
{
|
{
|
||||||
dnsquery.response = CreateJSONError("No such endpoint found for dns query");
|
SetJSONError("No such endpoint found for dns query", dnsquery.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,16 +498,16 @@ namespace llarp::rpc
|
||||||
{
|
{
|
||||||
auto packet_src = std::make_shared<DummyPacketSource>([&](auto result) {
|
auto packet_src = std::make_shared<DummyPacketSource>([&](auto result) {
|
||||||
if (result)
|
if (result)
|
||||||
dnsquery.response = CreateJSONResponse(result->ToJSON());
|
SetJSONResponse(result->ToJSON(), dnsquery.response);
|
||||||
else
|
else
|
||||||
dnsquery.response = CreateJSONError("No response from DNS");
|
SetJSONError("No response from DNS", dnsquery.response);
|
||||||
});
|
});
|
||||||
if (not dns->MaybeHandlePacket(
|
if (not dns->MaybeHandlePacket(
|
||||||
packet_src, packet_src->dumb, packet_src->dumb, msg.ToBuffer()))
|
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
|
else
|
||||||
dnsquery.response = CreateJSONError("Endpoint does not have dns");
|
SetJSONError("Endpoint does not have dns", dnsquery.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,24 +516,24 @@ namespace llarp::rpc
|
||||||
{
|
{
|
||||||
if (config.request.filename.empty() and not config.request.ini.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
if (config.request.ini.empty() and not config.request.filename.empty())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not ends_with(config.request.filename, ".ini"))
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not check_path(config.request.filename))
|
if (not check_path(config.request.filename))
|
||||||
{
|
{
|
||||||
config.response = CreateJSONError("Bad filename passed");
|
SetJSONError("Bad filename passed", config.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +548,7 @@ namespace llarp::rpc
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
config.response = CreateJSONError(e.what());
|
SetJSONError(e.what(), config.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,12 +569,12 @@ namespace llarp::rpc
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
config.response = CreateJSONError(e.what());
|
SetJSONError(e.what(), config.response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.response = CreateJSONResponse("OK");
|
SetJSONResponse("OK", config.response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -538,4 +611,4 @@ namespace llarp::rpc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace llarp::rpc
|
} // namespace llarp::rpc
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#include "rpc_request_definitions.hpp"
|
#include "rpc_request_definitions.hpp"
|
||||||
#include "json_bt.hpp"
|
#include "json_bt.hpp"
|
||||||
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <llarp/config/config.hpp>
|
#include <llarp/config/config.hpp>
|
||||||
#include <oxenmq/oxenmq.h>
|
#include <oxenmq/oxenmq.h>
|
||||||
|
@ -64,16 +66,16 @@ namespace llarp::rpc
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Result_t>
|
template <typename Result_t>
|
||||||
std::string
|
void
|
||||||
CreateJSONResponse(Result_t result)
|
SetJSONResponse(Result_t result, json& j)
|
||||||
{
|
{
|
||||||
return nlohmann::json{{"result", result}}.dump();
|
j["result"] = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string
|
inline void
|
||||||
CreateJSONError(std::string_view msg)
|
SetJSONError(std::string_view msg, json& j)
|
||||||
{
|
{
|
||||||
return nlohmann::json{{"error", msg}}.dump();
|
j["error"] = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RPCServer
|
class RPCServer
|
||||||
|
@ -109,6 +111,8 @@ namespace llarp::rpc
|
||||||
void
|
void
|
||||||
invoke(UnmapExit& unmapexit);
|
invoke(UnmapExit& unmapexit);
|
||||||
void
|
void
|
||||||
|
invoke(SwapExits& swapexits);
|
||||||
|
void
|
||||||
invoke(DNSQuery& dnsquery);
|
invoke(DNSQuery& dnsquery);
|
||||||
void
|
void
|
||||||
invoke(Config& config);
|
invoke(Config& config);
|
||||||
|
@ -140,18 +144,21 @@ namespace llarp::rpc
|
||||||
catch (const rpc_error& e)
|
catch (const rpc_error& e)
|
||||||
{
|
{
|
||||||
log::info(logcat, "RPC request 'rpc.{}' failed with: {}", rpc.name, e.what());
|
log::info(logcat, "RPC request 'rpc.{}' failed with: {}", rpc.name, e.what());
|
||||||
rpc.response = CreateJSONError(
|
SetJSONError(
|
||||||
fmt::format("RPC request 'rpc.{}' failed with: {}", rpc.name, e.what()));
|
fmt::format("RPC request 'rpc.{}' failed with: {}", rpc.name, e.what()), rpc.response);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
log::info(logcat, "RPC request 'rpc.{}' raised an exception: {}", rpc.name, e.what());
|
log::info(logcat, "RPC request 'rpc.{}' raised an exception: {}", rpc.name, e.what());
|
||||||
rpc.response = CreateJSONError(
|
SetJSONError(
|
||||||
fmt::format("RPC request 'rpc.{}' raised an exception: {}", rpc.name, e.what()));
|
fmt::format("RPC request 'rpc.{}' raised an exception: {}", rpc.name, e.what()),
|
||||||
|
rpc.response);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rpc.replier.has_value())
|
if (rpc.replier.has_value())
|
||||||
|
{
|
||||||
rpc.send_response();
|
rpc.send_response();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "endpoint_util.hpp"
|
#include "endpoint_util.hpp"
|
||||||
#include "hidden_service_address_lookup.hpp"
|
#include "hidden_service_address_lookup.hpp"
|
||||||
#include "auth.hpp"
|
#include "auth.hpp"
|
||||||
|
#include "llarp/util/logging.hpp"
|
||||||
#include "outbound_context.hpp"
|
#include "outbound_context.hpp"
|
||||||
#include "protocol.hpp"
|
#include "protocol.hpp"
|
||||||
#include "info.hpp"
|
#include "info.hpp"
|
||||||
|
@ -2188,6 +2189,26 @@ namespace llarp
|
||||||
LogInfo(Name(), " unmap ", item.first, " exit range mapping");
|
LogInfo(Name(), " unmap ", item.first, " exit range mapping");
|
||||||
return true;
|
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>
|
std::optional<AuthInfo>
|
||||||
|
|
|
@ -284,6 +284,9 @@ namespace llarp
|
||||||
void
|
void
|
||||||
UnmapExitRange(IPRange range);
|
UnmapExitRange(IPRange range);
|
||||||
|
|
||||||
|
void
|
||||||
|
UnmapRangeByExit(IPRange range, std::string exit);
|
||||||
|
|
||||||
void
|
void
|
||||||
map_exit(
|
map_exit(
|
||||||
std::string name,
|
std::string name,
|
||||||
|
|
Loading…
Reference in New Issue