Merge pull request #1319 from majestrate/clean-up-dev-2020-07-27

exit tool rewrite in C++ (without macos support yet)
pull/1332/head
Jeff 4 years ago committed by GitHub
commit 521765b5a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -85,6 +85,7 @@ local windows_cross_pipeline(name, image,
[if allow_fail then "failure"]: "ignore",
environment: { SSH_KEY: { from_secret: "SSH_KEY" }, WINDOWS_BUILD_NAME: toolchain+"bit" },
commands: [
'apk update && apk upgrade',
'apk add cmake git ninja pkgconf ccache patch make ' + deps,
'git clone https://github.com/despair86/libuv.git win32-setup/libuv',
'mkdir build',
@ -225,7 +226,7 @@ local mac_builder(name, build_type='Release', werror=true, cmake_extra='', extra
// integration tests
debian_pipeline("Router Hive", "ubuntu:focal", deps='python3-dev python3-pytest python3-pybind11 ' + default_deps,
cmake_extra='-DWITH_HIVE=ON', extra_cmds=['../contrib/ci/drone-run-router-hive.sh']),
cmake_extra='-DWITH_HIVE=ON'),
// Deb builds:
deb_builder("debian:sid", "sid", "debian/sid"),

@ -154,7 +154,7 @@ if(LokiMQ_FOUND)
message(STATUS "using system lokimq")
else()
message(STATUS "using lokimq submodule")
add_subdirectory(${CMAKE_SOURCE_DIR}/external/loki-mq EXCLUDE_FROM_ALL)
add_subdirectory(${CMAKE_SOURCE_DIR}/external/loki-mq)
endif()

@ -205,8 +205,9 @@ add_static_target(sqlite3 sqlite3_external libsqlite3.a)
if(ZMQ_VERSION VERSION_LESS 4.3.3 AND CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
set(zmq_patch PATCH_COMMAND patch -p1 -i ${PROJECT_SOURCE_DIR}/contrib/cross/patches/libzmq-pr3601-mingw-build-fix.patch
COMMAND patch -p1 -i ${PROJECT_SOURCE_DIR}/contrib/cross/patches/libzmq-win32-release.patch)
set(zmq_patch
#PATCH_COMMAND patch -p1 -i ${PROJECT_SOURCE_DIR}/contrib/cross/patches/libzmq-pr3601-mingw-build-fix.patch)
PATCH_COMMAND patch -p1 -i ${PROJECT_SOURCE_DIR}/contrib/cross/patches/libzmq-win32-release.patch)
endif()
build_external(zmq
DEPENDS sodium_external

@ -35,12 +35,12 @@ fi
mkdir -v "$base"
if [ -e daemon/lokinet.exe ]; then
cp -av daemon/lokinet.exe ../lokinet-bootstrap.ps1 "$base"
cp -av daemon/lokinet.exe daemon/lokinet-vpn.exe ../lokinet-bootstrap.ps1 "$base"
# zipit up yo
archive="$base.zip"
zip -r "$archive" "$base"
else
cp -av daemon/lokinet ../lokinet-bootstrap "$base"
cp -av daemon/lokinet daemon/lokinet-vpn ../lokinet-bootstrap "$base"
# tar dat shiz up yo
archive="$base.tar.xz"
tar cJvf "$archive" "$base"

@ -5,14 +5,14 @@ if(SHADOW)
enable_lto(shadow-plugin)
else()
add_executable(lokinet main.cpp)
add_executable(lokinetctl lokinetctl.cpp)
enable_lto(lokinet lokinetctl)
add_executable(lokinet-vpn lokinet-vpn.cpp)
enable_lto(lokinet lokinet-vpn)
if(TRACY_ROOT)
target_sources(lokinet PRIVATE ${TRACY_ROOT}/TracyClient.cpp)
endif()
foreach(exe lokinet lokinetctl)
foreach(exe lokinet lokinet-vpn)
if(WIN32 AND NOT MSVC_VERSION)
target_sources(${exe} PRIVATE ../llarp/win32/version.rc)
target_link_libraries(${exe} PRIVATE ws2_32 iphlpapi)
@ -25,9 +25,9 @@ else()
endif()
target_compile_definitions(${exe} PRIVATE -DVERSIONTAG=${GIT_VERSION_REAL})
add_log_tag(${exe})
install(TARGETS ${exe} RUNTIME DESTINATION bin COMPONENT lokinet)
endforeach()
install(TARGETS lokinet RUNTIME DESTINATION bin COMPONENT lokinet)
if(WIN32)
install(PROGRAMS ${CMAKE_SOURCE_DIR}/lokinet-bootstrap.ps1 DESTINATION bin COMPONENT lokinet)
else()
@ -38,12 +38,7 @@ else()
install(CODE "execute_process(COMMAND setcap cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)")
endif()
if(CURL_FOUND)
target_include_directories(lokinetctl PRIVATE ${CURL_INCLUDE_DIRS})
target_link_libraries(lokinetctl PRIVATE ${CURL_LIBRARIES})
endif(CURL_FOUND)
install(PROGRAMS lokinet-vpn DESTINATION bin COMPONENT lokinet)
install(TARGETS lokinet-vpn RUNTIME DESTINATION bin COMPONENT lokinet)
endif()

@ -0,0 +1,229 @@
#include <lokimq/lokimq.h>
#include <nlohmann/json.hpp>
#include <cxxopts.hpp>
#include <future>
#include <vector>
#include <array>
#include <net/net.hpp>
#ifdef _WIN32
// add the unholy windows headers for iphlpapi
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <strsafe.h>
#else
#include <sys/wait.h>
#endif
/// do a lokimq request on an lmq instance blocking style
/// returns a json object parsed from the result
std::optional<nlohmann::json>
LMQ_Request(
lokimq::LokiMQ& lmq,
const lokimq::ConnectionID& id,
std::string_view method,
std::optional<nlohmann::json> args = std::nullopt)
{
std::promise<std::optional<std::string>> result_promise;
auto handleRequest = [&result_promise](bool success, std::vector<std::string> result) {
if ((not success) or result.empty())
{
result_promise.set_value(std::nullopt);
return;
}
result_promise.set_value(result[0]);
};
if (args.has_value())
{
lmq.request(id, method, handleRequest, args->dump());
}
else
{
lmq.request(id, method, handleRequest);
}
auto ftr = result_promise.get_future();
const auto str = ftr.get();
if (str.has_value())
return nlohmann::json::parse(*str);
return std::nullopt;
}
int
main(int argc, char* argv[])
{
cxxopts::Options opts("lokinet-vpn", "LokiNET vpn control utility");
opts.add_options()("v,verbose", "Verbose", cxxopts::value<bool>())(
"h,help", "help", cxxopts::value<bool>())("up", "put vpn up", cxxopts::value<bool>())(
"down", "put vpn down", cxxopts::value<bool>())(
"exit", "specify exit node address", cxxopts::value<std::string>())(
"rpc", "rpc url for lokinet", cxxopts::value<std::string>())(
"endpoint", "endpoint to use", cxxopts::value<std::string>())(
"token", "exit auth token to use", cxxopts::value<std::string>());
lokimq::address rpcURL("tcp://127.0.0.1:1190");
std::string exitAddress;
std::string endpoint = "default";
std::optional<std::string> token;
lokimq::LogLevel logLevel = lokimq::LogLevel::warn;
bool goUp = false;
bool goDown = false;
try
{
const auto result = opts.parse(argc, argv);
if (result.count("help") > 0)
{
std::cout << opts.help() << std::endl;
return 0;
}
if (result.count("verbose") > 0)
{
logLevel = lokimq::LogLevel::debug;
}
if (result.count("rpc") > 0)
{
rpcURL = lokimq::address(result["rpc"].as<std::string>());
}
if (result.count("exit") > 0)
{
exitAddress = result["exit"].as<std::string>();
}
goUp = result.count("up") > 0;
goDown = result.count("down") > 0;
if (result.count("endpoint") > 0)
{
endpoint = result["endpoint"].as<std::string>();
}
if (result.count("token") > 0)
{
token = result["token"].as<std::string>();
}
}
catch (const cxxopts::option_not_exists_exception& ex)
{
std::cerr << ex.what();
std::cout << opts.help() << std::endl;
return 1;
}
catch (std::exception& ex)
{
std::cout << ex.what() << std::endl;
return 1;
}
if ((not goUp) and (not goDown))
{
std::cout << opts.help() << std::endl;
return 1;
}
if (goUp and exitAddress.empty())
{
std::cout << "no exit address provided" << std::endl;
return 1;
}
lokimq::LokiMQ lmq{[](lokimq::LogLevel lvl, const char* file, int line, std::string msg) {
std::cout << lvl << " [" << file << ":" << line << "] " << msg << std::endl;
},
logLevel};
lmq.start();
std::promise<bool> connectPromise;
const auto connID = lmq.connect_remote(
rpcURL,
[&connectPromise](auto) { connectPromise.set_value(true); },
[&connectPromise](auto, std::string_view msg) {
std::cout << "failed to connect to lokinet RPC: " << msg << std::endl;
connectPromise.set_value(false);
});
auto ftr = connectPromise.get_future();
if (not ftr.get())
{
return 1;
}
std::vector<std::string> firstHops;
std::string ifname;
const auto maybe_status = LMQ_Request(lmq, connID, "llarp.status");
if (not maybe_status.has_value())
{
std::cout << "call to llarp.status failed" << std::endl;
return 1;
}
try
{
// extract first hops
const auto& links = maybe_status->at("result")["links"]["outbound"];
for (const auto& link : links)
{
const auto& sessions = link["sessions"]["established"];
for (const auto& session : sessions)
{
std::string addr = session["remoteAddr"];
const auto pos = addr.find(":");
firstHops.push_back(addr.substr(0, pos));
}
}
// get interface name
#ifdef _WIN32
// strip off the "::ffff."
ifname = maybe_status->at("result")["services"][endpoint]["ifaddr"];
const auto pos = ifname.find("/");
if (pos != std::string::npos)
{
ifname = ifname.substr(0, pos);
}
#else
ifname = maybe_status->at("result")["services"][endpoint]["ifname"];
#endif
}
catch (std::exception& ex)
{
std::cout << "failed to parse result: " << ex.what() << std::endl;
return 1;
}
if (goUp)
{
std::optional<nlohmann::json> maybe_result;
if (token.has_value())
{
maybe_result = LMQ_Request(
lmq,
connID,
"llarp.exit",
nlohmann::json{{"exit", exitAddress}, {"range", "0.0.0.0/0"}, {"token", *token}});
}
else
{
maybe_result = LMQ_Request(
lmq, connID, "llarp.exit", nlohmann::json{{"exit", exitAddress}, {"range", "0.0.0.0/0"}});
}
if (not maybe_result.has_value())
{
std::cout << "could not add exit" << std::endl;
return 1;
}
if (maybe_result->contains("error") and maybe_result->at("error").is_string())
{
std::cout << maybe_result->at("error").get<std::string>() << std::endl;
return 1;
}
}
if (goDown)
{
LMQ_Request(lmq, connID, "llarp.exit", nlohmann::json{{"range", "0.0.0.0/0"}, {"unmap", true}});
}
return 0;
}

@ -293,8 +293,8 @@ main(int argc, char* argv[])
#ifndef _WIN32
return lokinet_main(argc, argv);
#else
SERVICE_TABLE_ENTRY DispatchTable[] = {
{"lokinet", (LPSERVICE_MAIN_FUNCTION)win32_daemon_entry}, {NULL, NULL}};
SERVICE_TABLE_ENTRY DispatchTable[] = {{"lokinet", (LPSERVICE_MAIN_FUNCTION)win32_daemon_entry},
{NULL, NULL}};
if (lstrcmpi(argv[1], "--win32-daemon") == 0)
{
StartServiceCtrlDispatcher(DispatchTable);
@ -326,15 +326,15 @@ lokinet_main(int argc, char* argv[])
"LokiNET is a free, open source, private, "
"decentralized, \"market based sybil resistant\" "
"and IP based onion routing network");
options.add_options()("v,verbose", "Verbose", cxxopts::value<bool>())(
"h,help", "help", cxxopts::value<bool>())("version", "version", cxxopts::value<bool>())
options.add_options()("v,verbose", "Verbose", cxxopts::value<bool>())
#ifdef _WIN32
("install", "install win32 daemon to SCM", cxxopts::value<bool>())(
"remove", "remove win32 daemon from SCM", cxxopts::value<bool>())(
"win32-daemon", "do not use interactively", cxxopts::value<bool>())
#endif
("g,generate", "generate client config", cxxopts::value<bool>())(
"r,relay", "run as relay instead of client", cxxopts::value<bool>())(
("h,help", "help", cxxopts::value<bool>())("version", "version", cxxopts::value<bool>())(
"g,generate", "generate client config", cxxopts::value<bool>())(
"r,router", "run as router instead of client", cxxopts::value<bool>())(
"f,force", "overwrite", cxxopts::value<bool>())(
"c,colour", "colour output", cxxopts::value<bool>()->default_value("true"))(
"b,background",
@ -464,27 +464,26 @@ lokinet_main(int argc, char* argv[])
// do periodic non lokinet related tasks here
if (ctx and ctx->IsUp() and not ctx->LooksAlive())
{
for (const auto& wtf :
{"you have been visited by the mascott of the "
"deadlocked router.",
"⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⣀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⢀⣀⣀⡀⠄⠄⠄⡠⢲⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠄⠄",
"⠄⠄⠄⠔⣈⣀⠄⢔⡒⠳⡴⠊⠄⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣧⠄⠄",
"⠄⢜⡴⢑⠖⠊⢐⣤⠞⣩⡇⠄⠄⠄⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠄⠝⠛⠋⠐",
"⢸⠏⣷⠈⠄⣱⠃⠄⢠⠃⠐⡀⠄⠄⠄⠄⠙⠻⢿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠸⠄⠄⠄⠄",
"⠈⣅⠞⢁⣿⢸⠘⡄⡆⠄⠄⠈⠢⡀⠄⠄⠄⠄⠄⠄⠉⠙⠛⠛⠛⠉⠉⡀⠄⠡⢀⠄⣀",
"⠄⠙⡎⣹⢸⠄⠆⢘⠁⠄⠄⠄⢸⠈⠢⢄⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠃⠄⠄⠄⠄⠄",
"⠄⠄⠑⢿⠈⢆⠘⢼⠄⠄⠄⠄⠸⢐⢾⠄⡘⡏⠲⠆⠠⣤⢤⢤⡤⠄⣖⡇⠄⠄⠄⠄⠄",
"⣴⣶⣿⣿⣣⣈⣢⣸⠄⠄⠄⠄⡾⣷⣾⣮⣤⡏⠁⠘⠊⢠⣷⣾⡛⡟⠈⠄⠄⠄⠄⠄⠄",
"⣿⣿⣿⣿⣿⠉⠒⢽⠄⠄⠄⠄⡇⣿⣟⣿⡇⠄⠄⠄⠄⢸⣻⡿⡇⡇⠄⠄⠄⠄⠄⠄⠄",
"⠻⣿⣿⣿⣿⣄⠰⢼⠄⠄⠄⡄⠁⢻⣍⣯⠃⠄⠄⠄⠄⠈⢿⣻⠃⠈⡆⡄⠄⠄⠄⠄⠄",
"⠄⠙⠿⠿⠛⣿⣶⣤⡇⠄⠄⢣⠄⠄⠈⠄⢠⠂⠄⠁⠄⡀⠄⠄⣀⠔⢁⠃⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⣿⣿⣿⣿⣾⠢⣖⣶⣦⣤⣤⣬⣤⣤⣤⣴⣶⣶⡏⠠⢃⠌⠄⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⠿⠿⠟⠛⡹⠉⠛⠛⠿⠿⣿⣿⣿⣿⣿⡿⠂⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄",
"⠠⠤⠤⠄⠄⣀⠄⠄⠄⠑⠠⣤⣀⣀⣀⡘⣿⠿⠙⠻⡍⢀⡈⠂⠄⠄⠄⠄⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⠄⠑⠠⣠⣴⣾⣿⣿⣿⣿⣿⣿⣇⠉⠄⠻⣿⣷⣄⡀⠄⠄⠄⠄⠄⠄⠄⠄",
"file a bug report now or be cursed with this "
"annoying image in your syslog for all time."})
for (const auto& wtf : {"you have been visited by the mascott of the "
"deadlocked router.",
"⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⣀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⢀⣀⣀⡀⠄⠄⠄⡠⢲⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠄⠄",
"⠄⠄⠄⠔⣈⣀⠄⢔⡒⠳⡴⠊⠄⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣧⠄⠄",
"⠄⢜⡴⢑⠖⠊⢐⣤⠞⣩⡇⠄⠄⠄⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠄⠝⠛⠋⠐",
"⢸⠏⣷⠈⠄⣱⠃⠄⢠⠃⠐⡀⠄⠄⠄⠄⠙⠻⢿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠸⠄⠄⠄⠄",
"⠈⣅⠞⢁⣿⢸⠘⡄⡆⠄⠄⠈⠢⡀⠄⠄⠄⠄⠄⠄⠉⠙⠛⠛⠛⠉⠉⡀⠄⠡⢀⠄⣀",
"⠄⠙⡎⣹⢸⠄⠆⢘⠁⠄⠄⠄⢸⠈⠢⢄⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠃⠄⠄⠄⠄⠄",
"⠄⠄⠑⢿⠈⢆⠘⢼⠄⠄⠄⠄⠸⢐⢾⠄⡘⡏⠲⠆⠠⣤⢤⢤⡤⠄⣖⡇⠄⠄⠄⠄⠄",
"⣴⣶⣿⣿⣣⣈⣢⣸⠄⠄⠄⠄⡾⣷⣾⣮⣤⡏⠁⠘⠊⢠⣷⣾⡛⡟⠈⠄⠄⠄⠄⠄⠄",
"⣿⣿⣿⣿⣿⠉⠒⢽⠄⠄⠄⠄⡇⣿⣟⣿⡇⠄⠄⠄⠄⢸⣻⡿⡇⡇⠄⠄⠄⠄⠄⠄⠄",
"⠻⣿⣿⣿⣿⣄⠰⢼⠄⠄⠄⡄⠁⢻⣍⣯⠃⠄⠄⠄⠄⠈⢿⣻⠃⠈⡆⡄⠄⠄⠄⠄⠄",
"⠄⠙⠿⠿⠛⣿⣶⣤⡇⠄⠄⢣⠄⠄⠈⠄⢠⠂⠄⠁⠄⡀⠄⠄⣀⠔⢁⠃⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⣿⣿⣿⣿⣾⠢⣖⣶⣦⣤⣤⣬⣤⣤⣤⣴⣶⣶⡏⠠⢃⠌⠄⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⠿⠿⠟⠛⡹⠉⠛⠛⠿⠿⣿⣿⣿⣿⣿⡿⠂⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄",
"⠠⠤⠤⠄⠄⣀⠄⠄⠄⠑⠠⣤⣀⣀⣀⡘⣿⠿⠙⠻⡍⢀⡈⠂⠄⠄⠄⠄⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⠄⠑⠠⣠⣴⣾⣿⣿⣿⣿⣿⣿⣇⠉⠄⠻⣿⣷⣄⡀⠄⠄⠄⠄⠄⠄⠄⠄",
"file a bug report now or be cursed with this "
"annoying image in your syslog for all time."})
{
LogError(wtf);
llarp::LogContext::Instance().ImmediateFlush();

@ -0,0 +1,12 @@
to configure lokinet to be an exit add into `lokinet.ini` `[network]` section the following:
exit=true
keyfile=/var/lib/lokinet/exit.private
reachable=1
ifaddr=10.0.0.1/16
post setup for exit (as root) given `eth0` is used to get to the internet:
# echo 1 > /proc/sys/net/ipv4/ip_forward
# iptables -t nat -A POSTROUTING -s 10.0.0.0/16 -o eth0 -j MASQUERADE

2
external/nlohmann vendored

@ -1 +1 @@
Subproject commit e7b3b40b5a95bc74b9a7f662830a27c49ffc01b4
Subproject commit db78ac1d7716f56fc9f1b030b715f872f93964e4

@ -43,6 +43,8 @@ namespace llarp
llarp_ev_loop_ptr mainloop;
std::string nodedb_dir;
virtual ~Context() = default;
void
Close();
@ -64,6 +66,10 @@ namespace llarp
void
Configure(Config conf);
/// handle SIGHUP
void
Reload();
bool
IsUp() const;
@ -87,12 +93,10 @@ namespace llarp
/// Creates a router. Can be overridden to allow a different class of router
/// to be created instead. Defaults to llarp::Router.
virtual std::unique_ptr<AbstractRouter>
makeRouter(
llarp_ev_loop_ptr __netloop,
std::shared_ptr<Logic> logic);
makeRouter(llarp_ev_loop_ptr __netloop, std::shared_ptr<Logic> logic);
protected:
std::unique_ptr<Config> config = nullptr;
std::shared_ptr<Config> config = nullptr;
private:
void

@ -59,6 +59,7 @@ add_library(lokinet-platform
net/ip_range.cpp
net/net.cpp
net/net_int.cpp
net/route.cpp
net/sock_addr.cpp
$<TARGET_OBJECTS:tuntap>
)
@ -205,15 +206,6 @@ add_library(liblokinet
service/tag.cpp
)
if(TARGET curl)
# key_manager needs curl for now (to fetch service node keys from lokid)
target_link_libraries(liblokinet PUBLIC curl)
target_compile_definitions(liblokinet PRIVATE HAVE_CURL)
if(TARGET libcurl_external)
add_dependencies(liblokinet libcurl_external)
endif()
endif()
set_target_properties(liblokinet PROPERTIES OUTPUT_NAME lokinet)
enable_lto(lokinet-util lokinet-platform liblokinet)

@ -130,20 +130,13 @@ namespace llarp
conf.defineOption<std::string>(
"router", "transport-privkey", false, "", AssignmentAcceptor(m_transportKeyFile));
if (not params.isRelay)
{
// TODO: remove this -- all service nodes should run peer db
conf.defineOption<bool>(
"router",
"enable-peer-stats",
false,
DefaultEnablePeerStats,
AssignmentAcceptor(m_enablePeerStats));
}
else
{
m_enablePeerStats = true;
}
conf.defineOption<bool>(
"router",
"enable-peer-stats",
false,
DefaultEnablePeerStats,
AssignmentAcceptor(m_enablePeerStats));
m_isRelay = params.isRelay;
}
void
@ -219,6 +212,26 @@ namespace llarp
m_Paths = arg;
});
conf.defineOption<std::string>("network", "exit-auth", false, "", [this](std::string arg) {
if (arg.empty())
return;
service::Address exit;
service::AuthInfo auth;
const auto pos = arg.find(":");
if (pos == std::string::npos)
{
throw std::invalid_argument(
"[network]:exit-auth invalid format, expects exit-address.loki:auth-code-goes-here");
}
const auto exit_str = arg.substr(0, pos);
auth.token = arg.substr(pos + 1);
if (not exit.FromString(exit_str))
{
throw std::invalid_argument("[network]:exit-auth invalid exit address");
}
m_ExitAuths.emplace(exit, auth);
});
conf.defineOption<std::string>("network", "exit-node", false, "", [this](std::string arg) {
if (arg.empty())
return;
@ -351,7 +364,7 @@ namespace llarp
const IpAddress addr{value};
if (not addr.hasPort())
throw std::invalid_argument("no port provided in link address");
info.interface = addr.getIpAddr();
info.interface = addr.toHost();
info.port = *addr.getPort();
}
else
@ -433,7 +446,17 @@ namespace llarp
"api", "enabled", false, DefaultRPCEnabled, AssignmentAcceptor(m_enableRPCServer));
conf.defineOption<std::string>(
"api", "bind", false, DefaultRPCBindAddr, AssignmentAcceptor(m_rpcBindAddr));
"api", "bind", false, DefaultRPCBindAddr, [this](std::string arg) {
if (arg.empty())
{
arg = DefaultRPCBindAddr;
}
if (arg.find("://") == std::string::npos)
{
arg = "tcp://" + arg;
}
m_rpcBindAddr = std::move(arg);
});
// TODO: this was from pre-refactor:
// TODO: add pubkey to whitelist
@ -524,6 +547,18 @@ namespace llarp
"logging", "file", false, DefaultLogFile, AssignmentAcceptor(m_logFile));
}
void
Config::Save() const
{
m_Parser.Save();
}
void
Config::Override(std::string section, std::string key, std::string value)
{
m_Parser.AddOverride(std::move(section), std::move(key), std::move(value));
}
bool
Config::Load(const fs::path fname, bool isRelay, fs::path defaultDataDir)
{
@ -536,14 +571,13 @@ namespace llarp
ConfigDefinition conf;
initializeConfig(conf, params);
addBackwardsCompatibleConfigOptions(conf);
ConfigParser parser;
if (!parser.LoadFile(fname))
m_Parser.Clear();
if (!m_Parser.LoadFile(fname))
{
return false;
}
parser.IterAll([&](std::string_view section, const SectionValues_t& values) {
m_Parser.IterAll([&](std::string_view section, const SectionValues_t& values) {
for (const auto& pair : values)
{
conf.addConfigValue(section, pair.first, pair.second);

@ -63,6 +63,7 @@ namespace llarp
std::string m_transportKeyFile;
bool m_enablePeerStats = false;
bool m_isRelay = false;
void
defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params);
@ -84,6 +85,7 @@ namespace llarp
bool m_AllowExit = false;
std::set<RouterID> m_snodeBlacklist;
net::IPRangeMap<service::Address> m_ExitMap;
std::unordered_map<service::Address, service::AuthInfo, service::Address::Hash> m_ExitAuths;
std::unordered_map<huint128_t, service::Address> m_mapAddrs;
service::AuthType m_AuthType = service::AuthType::eAuthTypeNone;
@ -222,6 +224,15 @@ namespace llarp
std::string
generateBaseRouterConfig(fs::path defaultDataDir);
void
Save() const;
void
Override(std::string section, std::string key, std::string value);
private:
ConfigParser m_Parser;
};
void

@ -40,6 +40,7 @@ namespace llarp
void
ConfigParser::Clear()
{
m_Overrides.clear();
m_Config.clear();
m_Data.clear();
}
@ -162,4 +163,32 @@ namespace llarp
return false;
return visit(itr->second);
}
void
ConfigParser::AddOverride(std::string section, std::string key, std::string value)
{
m_Overrides[section].emplace(key, value);
}
void
ConfigParser::Save() const
{
// if we have no overrides keep the config the same on disk
if (m_Overrides.empty())
return;
std::ofstream ofs(m_FileName);
// write existing config data
ofs.write(m_Data.data(), m_Data.size());
// write overrides
ofs << std::endl << std::endl << "# overrides" << std::endl;
for (const auto& [section, values] : m_Overrides)
{
ofs << std::endl << "[" << section << "]" << std::endl;
for (const auto& [key, value] : values)
{
ofs << key << "=" << value << std::endl;
}
}
}
} // namespace llarp

@ -40,12 +40,21 @@ namespace llarp
bool
VisitSection(const char* name, std::function<bool(const SectionValues_t&)> visit) const;
/// add a config option that is appended at the end of the config buffer with no comments
void
AddOverride(std::string section, std::string key, std::string value);
/// save config and any overrides to the file it was loaded from
void
Save() const;
private:
bool
Parse();
std::vector<char> m_Data;
Config_impl_t m_Config;
Config_impl_t m_Overrides;
fs::path m_FileName;
};

@ -33,7 +33,7 @@ namespace llarp
if (nullptr != config.get())
throw std::runtime_error("Config already exists");
config = std::make_unique<Config>(std::move(conf));
config = std::make_shared<Config>(std::move(conf));
logic = std::make_shared<Logic>();
@ -85,7 +85,7 @@ namespace llarp
nodedb = std::make_unique<llarp_nodedb>(
nodedb_dir, [r = router.get()](auto call) { r->QueueDiskIO(std::move(call)); });
if (!router->Configure(*config.get(), opts.isRouter, nodedb.get()))
if (!router->Configure(config, opts.isRouter, nodedb.get()))
throw std::runtime_error("Failed to configure router");
// must be done after router is made so we can use its disk io worker
@ -96,9 +96,7 @@ namespace llarp
}
std::unique_ptr<AbstractRouter>
Context::makeRouter(
llarp_ev_loop_ptr netloop,
std::shared_ptr<Logic> logic)
Context::makeRouter(llarp_ev_loop_ptr netloop, std::shared_ptr<Logic> logic)
{
return std::make_unique<Router>(netloop, logic);
}
@ -159,8 +157,17 @@ namespace llarp
{
SigINT();
}
// TODO: Hot reloading would be kewl
// (it used to exist here, but wasn't maintained)
#ifndef _WIN32
if (sig == SIGHUP)
{
Reload();
}
#endif
}
void
Context::Reload()
{
}
void
@ -184,7 +191,7 @@ namespace llarp
Context::Close()
{
llarp::LogDebug("free config");
config.release();
config.reset();
llarp::LogDebug("free nodedb");
nodedb.release();

@ -29,7 +29,7 @@ namespace llarp
ExitHandlerFlush(llarp_tun_io* tun)
{
auto* ep = static_cast<ExitEndpoint*>(tun->user);
LogicCall(ep->GetRouter()->logic(), std::bind(&ExitEndpoint::Flush, ep));
ep->Flush();
}
ExitEndpoint::ExitEndpoint(const std::string& name, AbstractRouter* r)

@ -22,6 +22,12 @@ namespace llarp
return true;
}
std::string
GetIfName() const override
{
return "";
}
path::PathSet_ptr
GetSelf() override
{
@ -36,6 +42,12 @@ namespace llarp
void
SendPacketToRemote(const llarp_buffer_t&) override{};
huint128_t
ObtainIPForAddr(const AlignedBuffer<32>&, bool) override
{
return {0};
}
};
} // namespace handlers
} // namespace llarp

@ -14,6 +14,7 @@
#include <router/abstractrouter.hpp>
#include <service/context.hpp>
#include <service/endpoint_state.hpp>
#include <service/outbound_context.hpp>
#include <util/meta/memfn.hpp>
#include <util/thread/logic.hpp>
#include <nodedb.hpp>
@ -549,6 +550,12 @@ namespace llarp
return true;
}
std::string
TunEndpoint::GetIfName() const
{
return m_IfName;
}
bool
TunEndpoint::Start()
{
@ -661,6 +668,7 @@ namespace llarp
ifaddr = vpn.info.ifaddr;
netmask = vpn.info.netmask;
}
m_IfName = ifname;
if (ip.FromString(ifaddr))
{
m_OurIP = net::ExpandV4(ip);
@ -786,7 +794,11 @@ namespace llarp
MarkAddressOutbound(addr);
EnsurePathToService(
addr,
[addr, pkt, self = this](service::Address, service::OutboundContext*) {
[addr, pkt, self = this](service::Address, service::OutboundContext* ctx) {
if (ctx)
{
ctx->sendTimeout = 5s;
}
self->SendToServiceOrQueue(addr, pkt.ConstBuffer(), service::eProtocolExit);
},
1s);

@ -36,6 +36,9 @@ namespace llarp
void
SendPacketToRemote(const llarp_buffer_t&) override{};
std::string
GetIfName() const override;
void
Tick(llarp_time_t now) override;
@ -164,7 +167,7 @@ namespace llarp
/// get ip address for key unconditionally
huint128_t
ObtainIPForAddr(const AlignedBuffer<32>& addr, bool serviceNode);
ObtainIPForAddr(const AlignedBuffer<32>& addr, bool serviceNode) override;
/// flush network traffic
void
@ -270,6 +273,7 @@ namespace llarp
llarp_vpn_io* io;
};
std::promise<lazy_vpn> m_LazyVPNPromise;
std::string m_IfName;
/// send packets on endpoint to user using send function
/// send function returns true to indicate stop iteration and do codel

@ -146,8 +146,8 @@ namespace llarp
catch (const std::exception& e)
{
LogError(stringify("Could not use ifname ", ifname, " to configure ILinkLayer"));
throw e;
}
throw;
}
}
m_ourAddr.setPort(port);

@ -137,18 +137,23 @@ namespace llarp
return m_ipAddress; // TODO: port
}
std::string
IpAddress::getIpAddr() const
{
return m_ipAddress;
}
bool
IpAddress::hasPort() const
{
return m_port.has_value();
}
std::string
IpAddress::toHost() const
{
const auto pos = m_ipAddress.find(":");
if (pos != std::string::npos)
{
return m_ipAddress.substr(0, pos);
}
return m_ipAddress;
}
bool
IpAddress::operator<(const IpAddress& other) const
{

@ -118,9 +118,8 @@ namespace llarp
std::string
toString() const;
/// get ip address component
std::string
getIpAddr() const;
toHost() const;
// TODO: other utility functions left over from Addr which may be useful
// IsBogon() const;

@ -365,7 +365,7 @@ llarp_getifaddr(const char* ifname, int af, struct sockaddr* addr)
{
// llarp::LogInfo(__FILE__, "scanning ", i->ifa_name, " af: ",
// std::to_string(i->ifa_addr->sa_family));
if (llarp::StrEq(i->ifa_name, ifname) && i->ifa_addr->sa_family == af)
if (std::string_view{i->ifa_name} == std::string_view{ifname} && i->ifa_addr->sa_family == af)
{
// can't do this here
// llarp::Addr a(*i->ifa_addr);

@ -0,0 +1,443 @@
#include "route.hpp"
#ifdef __linux__
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <linux/rtnetlink.h>
#include <net/net.hpp>
#include <exception>
#endif
#ifdef __APPLE__
#include <net/net.hpp>
#endif
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <strsafe.h>
#endif
#include <sstream>
#include <util/logging/logger.hpp>
namespace llarp::net
{
#ifndef __linux__
void
Execute(std::string cmd)
{
std::cout << cmd << std::endl;
#ifdef _WIN32
system(cmd.c_str());
#else
std::vector<std::string> parts_str;
std::vector<const char*> parts_raw;
std::stringstream in(cmd);
for (std::string part; std::getline(in, part, ' ');)
{
if (part.empty())
continue;
parts_str.push_back(part);
}
for (const auto& part : parts_str)
{
parts_raw.push_back(part.c_str());
}
parts_raw.push_back(nullptr);
const auto pid = fork();
if (pid == -1)
{
throw std::runtime_error("failed to fork");
}
else if (pid == 0)
{
char* const* args = (char* const*)parts_raw.data();
const auto result = execv(parts_raw[0], args);
if (result)
{
std::cout << "failed: " << result << std::endl;
}
else
{
std::cout << "ok" << std::endl;
}
exit(result);
}
else
{
waitpid(pid, 0, 0);
}
#endif
}
#endif
#ifdef __linux__
struct NLSocket
{
NLSocket() : fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE))
{
if (fd == -1)
throw std::runtime_error("failed to make netlink socket");
}
~NLSocket()
{
if (fd != -1)
close(fd);
}
const int fd;
};
/* Helper structure for ip address data and attributes */
typedef struct
{
unsigned char family;
unsigned char bitlen;
unsigned char data[sizeof(struct in6_addr)];
} _inet_addr;
/* */
#define NLMSG_TAIL(nmsg) ((struct rtattr*)(((intptr_t)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
/* Add new data to rtattr */
int
rtattr_add(struct nlmsghdr* n, unsigned int maxlen, int type, const void* data, int alen)
{
int len = RTA_LENGTH(alen);
struct rtattr* rta;
if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
{
fprintf(stderr, "rtattr_add error: message exceeded bound of %d\n", maxlen);
return -1;
}
rta = NLMSG_TAIL(n);
rta->rta_type = type;
rta->rta_len = len;
if (alen)
{
memcpy(RTA_DATA(rta), data, alen);
}
n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
return 0;
}
int
do_route(int sock, int cmd, int flags, _inet_addr* dst, _inet_addr* gw, int def_gw, int if_idx)
{
struct
{
struct nlmsghdr n;
struct rtmsg r;
char buf[4096];
} nl_request{};
/* Initialize request structure */
nl_request.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
nl_request.n.nlmsg_flags = NLM_F_REQUEST | flags;
nl_request.n.nlmsg_type = cmd;
nl_request.n.nlmsg_pid = getpid();
nl_request.r.rtm_family = dst->family;
nl_request.r.rtm_table = RT_TABLE_MAIN;
if (if_idx)
{
nl_request.r.rtm_scope = RT_SCOPE_LINK;
}
else
{
nl_request.r.rtm_scope = RT_SCOPE_NOWHERE;
}
/* Set additional flags if NOT deleting route */
if (cmd != RTM_DELROUTE)
{
nl_request.r.rtm_protocol = RTPROT_BOOT;
nl_request.r.rtm_type = RTN_UNICAST;
}
nl_request.r.rtm_family = dst->family;
nl_request.r.rtm_dst_len = dst->bitlen;
/* Select scope, for simplicity we supports here only IPv6 and IPv4 */
if (nl_request.r.rtm_family == AF_INET6)
{
nl_request.r.rtm_scope = RT_SCOPE_UNIVERSE;
}
else
{
nl_request.r.rtm_scope = RT_SCOPE_LINK;
}
/* Set gateway */
if (gw->bitlen != 0)
{
rtattr_add(&nl_request.n, sizeof(nl_request), RTA_GATEWAY, &gw->data, gw->bitlen / 8);
nl_request.r.rtm_scope = 0;
nl_request.r.rtm_family = gw->family;
}
/* Don't set destination and interface in case of default gateways */
if (!def_gw)
{
/* Set destination network */
rtattr_add(
&nl_request.n, sizeof(nl_request), /*RTA_NEWDST*/ RTA_DST, &dst->data, dst->bitlen / 8);
/* Set interface */
rtattr_add(&nl_request.n, sizeof(nl_request), RTA_OIF, &if_idx, sizeof(int));
}
/* Send message to the netlink */
return send(sock, &nl_request, sizeof(nl_request), 0);
}
int
read_addr(const char* addr, _inet_addr* res)
{
if (strchr(addr, ':'))
{
res->family = AF_INET6;
res->bitlen = 128;
}
else
{
res->family = AF_INET;
res->bitlen = 32;
}
return inet_pton(res->family, addr, res->data);
}
#endif
void
AddRoute(std::string ip, std::string gateway)
{
#ifdef __linux__
NLSocket sock;
int default_gw = 0;
int if_idx = 0;
_inet_addr to_addr{};
_inet_addr gw_addr{};
int nl_cmd = RTM_NEWROUTE;
int nl_flags = NLM_F_CREATE | NLM_F_EXCL;
read_addr(gateway.c_str(), &gw_addr);
read_addr(ip.c_str(), &to_addr);
LogInfo("add route: ", ip, " via ", gateway);
do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, default_gw, if_idx);
#else
std::stringstream ss;
#if _WIN32
ss << "route ADD " << ip << " MASK 255.255.255.255 " << gateway << " METRIC 2";
#elif __APPLE__
ss << "route -n add -host " << ip << " " << gateway;
#else
#error unsupported platform
#endif
Execute(ss.str());
#endif
}
void
DelRoute(std::string ip, std::string gateway)
{
#ifdef __linux__
NLSocket sock;
int default_gw = 0;
int if_idx = 0;
_inet_addr to_addr{};
_inet_addr gw_addr{};
int nl_cmd = RTM_DELROUTE;
int nl_flags = 0;
read_addr(gateway.c_str(), &gw_addr);
read_addr(ip.c_str(), &to_addr);
do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, default_gw, if_idx);
#else
std::stringstream ss;
#if _WIN32
ss << "route DELETE " << ip << " MASK 255.255.255.255 " << gateway << " METRIC 2";
#elif __APPLE__
ss << "route -n delete -host " << ip << " " << gateway;
#else
#error unsupported platform
#endif
Execute(ss.str());
#endif
}
void
AddDefaultRouteViaInterface(std::string ifname)
{
#ifdef __linux__
NLSocket sock;
int default_gw = 1;
int if_idx = if_nametoindex(ifname.c_str());
_inet_addr to_addr{};
_inet_addr gw_addr{};
const auto maybe = GetIFAddr(ifname);
if (not maybe.has_value())
throw std::runtime_error("we dont have our own net interface?");
int nl_cmd = RTM_NEWROUTE;
int nl_flags = NLM_F_CREATE | NLM_F_EXCL;
read_addr(maybe->toHost().c_str(), &gw_addr);
LogInfo("default route via ", ifname, " (", if_idx, ")");
do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, default_gw, if_idx);
#elif _WIN32
ifname.back()++;
Execute("route ADD 0.0.0.0 MASK 128.0.0.0 " + ifname);
Execute("route ADD 128.0.0.0 MASK 128.0.0.0 " + ifname);
#elif __APPLE__
Execute("route -cloning add -net 0.0.0.0 -netmask 0.0.0.0 -interface " + ifname);
#else
#error unsupported platform
#endif
}
void
DelDefaultRouteViaInterface(std::string ifname)
{
#ifdef __linux__
NLSocket sock;
int default_gw = 1;
int if_idx = if_nametoindex(ifname.c_str());
_inet_addr to_addr{};
_inet_addr gw_addr{};
const auto maybe = GetIFAddr(ifname);
if (not maybe.has_value())
throw std::runtime_error("we dont have our own net interface?");
int nl_cmd = RTM_DELROUTE;
int nl_flags = 0;
read_addr(maybe->toHost().c_str(), &gw_addr);
do_route(sock.fd, nl_cmd, nl_flags, &to_addr, &gw_addr, default_gw, if_idx);
#elif _WIN32
ifname.back()++;
Execute("route DELETE 0.0.0.0 MASK 128.0.0.0 " + ifname);
Execute("route DELETE 128.0.0.0 MASK 128.0.0.0 " + ifname);
#elif __APPLE__
Execute("route -cloning delete -net 0.0.0.0 -netmask 0.0.0.0 -interface " + ifname);
#else
#error unsupported platform
#endif
}
std::vector<std::string>
GetGatewaysNotOnInterface(std::string ifname)
{
std::vector<std::string> gateways;
#ifdef __linux__
FILE* p = popen("ip route", "r");
if (p == nullptr)
return gateways;
char* line = nullptr;
size_t len = 0;
ssize_t read = 0;
while ((read = getline(&line, &len, p)) != -1)
{
std::string line_str(line, len);
std::vector<std::string> words;
std::istringstream instr(line_str);
for (std::string word; std::getline(instr, word, ' ');)
{
words.emplace_back(std::move(word));
}
if (words[0] == "default" and words[1] == "via" and words[3] == "dev" and words[4] != ifname)
{
gateways.emplace_back(std::move(words[2]));
}
}
pclose(p);
return gateways;
#elif _WIN32
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
MIB_IPFORWARDTABLE* pIpForwardTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(sizeof(MIB_IPFORWARDTABLE));
if (pIpForwardTable == nullptr)
return gateways;
if (GetIpForwardTable(pIpForwardTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
{
FREE(pIpForwardTable);
pIpForwardTable = (MIB_IPFORWARDTABLE*)MALLOC(dwSize);
if (pIpForwardTable == nullptr)
{
return gateways;
}
}
if ((dwRetVal = GetIpForwardTable(pIpForwardTable, &dwSize, 0)) == NO_ERROR)
{
for (int i = 0; i < (int)pIpForwardTable->dwNumEntries; i++)
{
struct in_addr gateway, interface_addr;
gateway.S_un.S_addr = (u_long)pIpForwardTable->table[i].dwForwardDest;
interface_addr.S_un.S_addr = (u_long)pIpForwardTable->table[i].dwForwardNextHop;
std::array<char, 128> interface_str{};
StringCchCopy(interface_str.data(), interface_str.size(), inet_ntoa(interface_addr));
std::string interface_name{interface_str.data()};
if ((!gateway.S_un.S_addr) and interface_name != ifname)
{
gateways.push_back(std::move(interface_name));
}
}
}
FREE(pIpForwardTable);
#undef MALLOC
#undef FREE
return gateways;
#elif __APPLE__
const auto maybe = GetIFAddr(ifname);
if (not maybe.has_value())
return gateways;
const auto interface = maybe->toString();
// mac os is so godawful man
FILE* p = popen("netstat -rn -f inet", "r");
if (p == nullptr)
return gateways;
char* line = nullptr;
size_t len = 0;
ssize_t read = 0;
while ((read = getline(&line, &len, p)) != -1)
{
std::string line_str(line, len);
if (line_str.find("default") == 0)
{
line_str = line_str.substr(7);
while (line_str[0] == ' ')
{
line_str = line_str.substr(1);
}
const auto pos = line_str.find(" ");
if (pos != std::string::npos)
{
auto gateway = line_str.substr(0, pos);
if (gateway != interface)
gateways.emplace_back(std::move(gateway));
}
}
}
pclose(p);
return gateways;
#else
#error unsupported platform
#endif
}
} // namespace llarp::net

@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <vector>
namespace llarp::net
{
/// get every ip address that is a gateway that isn't owned by interface with name ifname
std::vector<std::string>
GetGatewaysNotOnInterface(std::string ifname);
/// add route to ipaddr via gateway ip
void
AddRoute(std::string ipaddr, std::string gateway);
/// delete route to ipaddr via gateway ip
void
DelRoute(std::string ipaddr, std::string gateway);
/// add default route via interface with name ifname
void
AddDefaultRouteViaInterface(std::string ifname);
/// delete default route via interface with name ifname
void
DelDefaultRouteViaInterface(std::string ifname);
} // namespace llarp::net

@ -88,10 +88,9 @@ namespace llarp
LogDebug("forwarding LRCM to ", nextHop);
m_Router->SendToOrQueue(nextHop, msg.get(), handler);
return true;
return m_Router->SendToOrQueue(nextHop, msg.get(), handler);
}
template <
typename Lock_t,
typename Map_t,

@ -1,12 +1,11 @@
#include <peerstats/types.hpp>
#include <util/str.hpp>
#include <lokimq/bt_serialize.h>
#include <stdexcept>
namespace llarp
{
constexpr auto RouterIdKey = "routerId";
constexpr auto NumConnectionAttemptsKey = "numConnectionAttempts";
constexpr auto NumConnectionSuccessesKey = "numConnectionSuccesses";
@ -105,37 +104,26 @@ namespace llarp
{
if (not buf)
throw std::runtime_error("PeerStats: Can't use null buf");
auto encodeUint64Entry = [&](std::string_view key, uint64_t value) {
if (not bencode_write_uint64_entry(buf, key.data(), key.size(), value))
throw std::runtime_error(stringify("PeerStats: Could not encode ", key));
const lokimq::bt_dict data = {
{NumConnectionAttemptsKey, numConnectionAttempts},
{NumConnectionSuccessesKey, numConnectionSuccesses},
{NumConnectionRejectionsKey, numConnectionRejections},
{NumConnectionTimeoutsKey, numConnectionTimeouts},
{NumPathBuildsKey, numPathBuilds},
{NumPacketsAttemptedKey, numPacketsAttempted},
{NumPacketsSentKey, numPacketsSent},
{NumPacketsDroppedKey, numPacketsDropped},
{NumPacketsResentKey, numPacketsResent},
{NumDistinctRCsReceivedKey, numDistinctRCsReceived},
{NumLateRCsKey, numLateRCs},
{PeakBandwidthBytesPerSecKey, (uint64_t)peakBandwidthBytesPerSec},
{LongestRCReceiveIntervalKey, longestRCReceiveInterval.count()},
{LeastRCRemainingLifetimeKey, leastRCRemainingLifetime.count()},
{LastRCUpdatedKey, lastRCUpdated.count()},
};
if (not bencode_start_dict(buf))
throw std::runtime_error("PeerStats: Could not create bencode dict");
// TODO: we don't have bencode support for dict entries other than uint64...?
// encodeUint64Entry(RouterIdKey, routerId);
encodeUint64Entry(NumConnectionAttemptsKey, numConnectionAttempts);
encodeUint64Entry(NumConnectionSuccessesKey, numConnectionSuccesses);
encodeUint64Entry(NumConnectionRejectionsKey, numConnectionRejections);
encodeUint64Entry(NumConnectionTimeoutsKey, numConnectionTimeouts);
encodeUint64Entry(NumPathBuildsKey, numPathBuilds);
encodeUint64Entry(NumPacketsAttemptedKey, numPacketsAttempted);
encodeUint64Entry(NumPacketsSentKey, numPacketsSent);
encodeUint64Entry(NumPacketsDroppedKey, numPacketsDropped);
encodeUint64Entry(NumPacketsResentKey, numPacketsResent);
encodeUint64Entry(NumDistinctRCsReceivedKey, numDistinctRCsReceived);
encodeUint64Entry(NumLateRCsKey, numLateRCs);
encodeUint64Entry(PeakBandwidthBytesPerSecKey, (uint64_t)peakBandwidthBytesPerSec);
encodeUint64Entry(LongestRCReceiveIntervalKey, longestRCReceiveInterval.count());
encodeUint64Entry(LeastRCRemainingLifetimeKey, leastRCRemainingLifetime.count());
encodeUint64Entry(LastRCUpdatedKey, lastRCUpdated.count());
if (not bencode_end(buf))
throw std::runtime_error("PeerStats: Could not end bencode dict");
const auto serialized = lokimq::bt_serialize(data);
if (not buf->write(serialized.begin(), serialized.end()))
throw std::runtime_error("PeerStats: buffer too small");
}
void

@ -1,6 +1,7 @@
#ifndef LLARP_ABSTRACT_ROUTER_HPP
#define LLARP_ABSTRACT_ROUTER_HPP
#include <config/config.hpp>
#include <config/key_manager.hpp>
#include <memory>
#include <util/types.hpp>
@ -134,6 +135,12 @@ namespace llarp
/// call function in disk io thread
virtual void QueueDiskIO(std::function<void(void)>) = 0;
virtual std::shared_ptr<Config>
GetConfig() const
{
return nullptr;
}
virtual service::Context&
hiddenServiceContext() = 0;
@ -159,7 +166,7 @@ namespace llarp
Sign(Signature& sig, const llarp_buffer_t& buf) const = 0;
virtual bool
Configure(const Config& conf, bool isRouter, llarp_nodedb* nodedb) = 0;
Configure(std::shared_ptr<Config> conf, bool isRouter, llarp_nodedb* nodedb) = 0;
virtual bool
IsServiceNode() const = 0;
@ -241,6 +248,8 @@ namespace llarp
virtual void
HandleDHTLookupForExplore(RouterID remote, const std::vector<RouterContact>& results) = 0;
virtual void SetDownHook(std::function<void(void)>){};
/// lookup router by pubkey
/// if we are a service node this is done direct otherwise it's done via
/// path

@ -262,8 +262,10 @@ namespace llarp
}
bool
Router::Configure(const Config& conf, bool isRouter, llarp_nodedb* nodedb)
Router::Configure(std::shared_ptr<Config> c, bool isRouter, llarp_nodedb* nodedb)
{
m_Config = c;
auto& conf = *m_Config;
whitelistRouters = conf.lokid.whitelistRouters;
if (whitelistRouters)
lokidRPCAddr = lokimq::address(conf.lokid.lokidRPCAddr);
@ -330,6 +332,8 @@ namespace llarp
void
Router::Close()
{
if (_onDown)
_onDown();
LogInfo("closing router");
llarp_ev_loop_stop(_netloop);
_running.store(false);
@ -449,11 +453,7 @@ namespace llarp
if (usingSNSeed)
ident_keyfile = conf.lokid.ident_keyfile;
// TODO: add config flag for "is service node"
if (conf.links.m_InboundLinks.size())
{
m_isServiceNode = true;
}
m_isServiceNode = conf.router.m_isRelay;
networkConfig = conf.network;
@ -591,6 +591,11 @@ namespace llarp
_linkManager.AddLink(std::move(server), true);
}
if (conf.links.m_InboundLinks.empty() and m_isServiceNode)
{
throw std::runtime_error("service node enabled but have no inbound links");
}
// Network config
if (conf.network.m_enableProfiling.has_value() and not*conf.network.m_enableProfiling)
{
@ -618,9 +623,9 @@ namespace llarp
m_peerDb = std::make_shared<PeerDb>();
m_peerDb->configure(conf.router);
}
else
else if (IsServiceNode())
{
assert(not IsServiceNode()); // enable peer stats must be enabled for service nodes
throw std::runtime_error("peer stats must be enabled when running as relay");
}
// Logging config
@ -957,15 +962,21 @@ namespace llarp
return;
LogInfo("adding address: ", ai);
_rc.addrs.push_back(ai);
if (ExitEnabled())
{
const IpAddress address = ai.toIpAddress();
_rc.exits.emplace_back(_rc.pubkey, address);
LogInfo("Exit relay started, advertised as exiting at: ", address);
}
}
});
if (ExitEnabled() and IsServiceNode())
{
LogError("exit mode not supported while service node");
return false;
}
if (IsServiceNode() and not _rc.IsPublicRouter())
{
LogError("we are configured as relay but have no reachable addresses");
return false;
}
// set public encryption key
_rc.enckey = seckey_topublic(encryption());

@ -228,6 +228,14 @@ namespace llarp
llarp_time_t _lastTick = 0s;
std::function<void(void)> _onDown;
void
SetDownHook(std::function<void(void)> hook) override
{
_onDown = hook;
}
bool
LooksAlive() const override
{
@ -345,7 +353,7 @@ namespace llarp
Close();
bool
Configure(const Config& conf, bool isRouter, llarp_nodedb* nodedb = nullptr) override;
Configure(std::shared_ptr<Config> conf, bool isRouter, llarp_nodedb* nodedb = nullptr) override;
bool
StartRpcServer() override;
@ -491,6 +499,14 @@ namespace llarp
void
AfterStopIssued();
std::shared_ptr<Config> m_Config;
std::shared_ptr<Config>
GetConfig() const override
{
return m_Config;
}
private:
std::atomic<bool> _stopping;
std::atomic<bool> _running;

@ -140,12 +140,16 @@ namespace llarp
if (!bencode_write_uint64_entry(buf, "v", 1, version))
return false;
/* write xi if they exist */
if (!bencode_write_bytestring(buf, "x", 1))
return false;
if (!BEncodeWriteList(exits.begin(), exits.end(), buf))
return false;
if (serializeExit)
{
/* write xi if they exist */
if (!bencode_write_bytestring(buf, "x", 1))
return false;
/* no exits anymore in RCs */
const std::vector<AlignedBuffer<8>> exits{};
if (!BEncodeWriteList(exits.begin(), exits.end(), buf))
return false;
}
/* write signature */
if (!bencode_write_bytestring(buf, "z", 1))
return false;
@ -158,7 +162,6 @@ namespace llarp
RouterContact::Clear()
{
addrs.clear();
exits.clear();
signature.Zero();
nickname.Zero();
enckey.Zero();
@ -171,7 +174,6 @@ namespace llarp
RouterContact::ExtractStatus() const
{
util::StatusObject obj{{"lastUpdated", last_updated.count()},
{"exit", IsExit()},
{"publicRouter", IsPublicRouter()},
{"identity", pubkey.ToString()},
{"addresses", addrs}};
@ -234,8 +236,10 @@ namespace llarp
if (!BEncodeMaybeReadDictInt("v", version, read, key, buf))
return false;
if (!BEncodeMaybeReadDictList("x", exits, read, key, buf))
return false;
if (key == "x" and serializeExit)
{
return bencode_discard(buf);
}
if (!BEncodeMaybeReadDictEntry("z", signature, read, key, buf))
return false;
@ -342,16 +346,6 @@ namespace llarp
return false;
}
}
for (const auto& exit : exits)
{
// TODO: see if exit's range overlaps with bogon...?
// e.g. "IsBogonRange(address, netmask)"
if (exit.ipAddress.isBogon())
{
llarp::LogError("bogon exit: ", exit);
return false;
}
}
if (!VerifySignature())
{
llarp::LogError("invalid signature: ", *this);
@ -434,7 +428,6 @@ namespace llarp
printer.printAttribute("netid", netID);
printer.printAttribute("v", version);
printer.printAttribute("ai", addrs);
printer.printAttribute("xi", exits);
printer.printAttribute("e", enckey);
printer.printAttribute("z", signature);

@ -96,8 +96,6 @@ namespace llarp
llarp::PubKey enckey;
// public signing public key
llarp::PubKey pubkey;
// advertised exits
std::vector<ExitInfo> exits;
// signature
llarp::Signature signature;
/// node nickname, yw kee
@ -106,6 +104,8 @@ namespace llarp
llarp_time_t last_updated = 0s;
uint64_t version = LLARP_PROTO_VERSION;
std::optional<RouterVersion> routerVersion;
/// should we serialize the exit info?
const static bool serializeExit = true;
util::StatusObject
ExtractStatus() const;
@ -151,7 +151,7 @@ namespace llarp
bool
IsExit() const
{
return !exits.empty();
return false;
}
bool

@ -4,6 +4,7 @@
#include <constants/version.hpp>
#include <nlohmann/json.hpp>
#include <net/ip_range.hpp>
#include <net/route.hpp>
#include <service/context.hpp>
#include <service/auth.hpp>
@ -109,78 +110,175 @@ namespace llarp::rpc
auto ftr = result.get_future();
msg.send_reply(CreateJSONResponse(ftr.get()));
})
.add_request_command("exit", [&](lokimq::Message& msg) {
HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) {
std::optional<service::Address> exit;
IPRange range;
bool map = true;
const auto exit_itr = obj.find("exit");
if (exit_itr != obj.end())
{
service::Address addr;
if (not addr.FromString(exit_itr->get<std::string>()))
{
reply(CreateJSONError("invalid exit address"));
return;
}
exit = addr;
}
.add_request_command(
"exit",
[&](lokimq::Message& msg) {
HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) {
if (r->IsServiceNode())
{
reply(CreateJSONError("not supported"));
return;
}
std::optional<service::Address> exit;
IPRange range;
bool map = true;
const auto exit_itr = obj.find("exit");
if (exit_itr != obj.end())
{
service::Address addr;
if (not addr.FromString(exit_itr->get<std::string>()))
{
reply(CreateJSONError("invalid exit address"));
return;
}
exit = addr;
}
const auto unmap_itr = obj.find("unmap");
if (unmap_itr != obj.end() and unmap_itr->get<bool>())
{
map = false;
}
const auto unmap_itr = obj.find("unmap");
if (unmap_itr != obj.end() and unmap_itr->get<bool>())
{
map = false;
}
const auto range_itr = obj.find("range");
if (range_itr == obj.end())
{
range.FromString("0.0.0.0/0");
}
else if (not range.FromString(range_itr->get<std::string>()))
{
reply(CreateJSONError("invalid ip range"));
return;
}
std::optional<std::string> token;
const auto token_itr = obj.find("token");
if (token_itr != obj.end())
{
token = token_itr->get<std::string>();
}
const auto range_itr = obj.find("range");
if (range_itr == obj.end())
{
range.FromString("0.0.0.0/0");
}
else if (not range.FromString(range_itr->get<std::string>()))
{
reply(CreateJSONError("invalid ip range"));
return;
}
std::optional<std::string> token;
const auto token_itr = obj.find("token");
if (token_itr != obj.end())
{
token = token_itr->get<std::string>();
}
std::string endpoint = "default";
const auto endpoint_itr = obj.find("endpoint");
if (endpoint_itr != obj.end())
{
endpoint = endpoint_itr->get<std::string>();
}
LogicCall(r->logic(), [map, exit, range, token, endpoint, r, reply]() {
auto ep = r->hiddenServiceContext().GetEndpointByName(endpoint);
if (ep == nullptr)
{
reply(CreateJSONError("no endpoint with name " + endpoint));
return;
}
if (map and exit.has_value())
{
const auto gateways = net::GetGatewaysNotOnInterface(ep->GetIfName());
if (gateways.empty())
{
reply(CreateJSONError("no gateway found"));
return;
}
ep->MapExitRange(range, *exit);
if (token.has_value())
{
ep->SetAuthInfoForEndpoint(*exit, service::AuthInfo{*token});
}
ep->EnsurePathToService(
*exit,
[r, gateway = gateways[0], reply, ep](auto, service::OutboundContext* ctx) {
if (ctx == nullptr)
{
reply(CreateJSONError("could not find exit"));
return;
}
std::vector<std::string> firsthops;
r->ForEachPeer(
[&firsthops](const auto* link, bool) {
firsthops.emplace_back(link->GetRemoteEndpoint().toHost());
},
false);
for (const auto& hop : firsthops)
{
net::AddRoute(hop, gateway);
}
net::AddDefaultRouteViaInterface(ep->GetIfName());
r->SetDownHook([firsthops, gateway]() {
for (const auto& hop : firsthops)
{
net::DelRoute(hop, gateway);
}
});
reply(CreateJSONResponse("OK"));
},
5s);
return;
}
else if (map and not exit.has_value())
{
reply(CreateJSONError("no exit address provided"));
return;
}
else if (not map)
{
const auto gateways = net::GetGatewaysNotOnInterface(ep->GetIfName());
if (gateways.empty())
{
reply(CreateJSONError("no gateway found"));
return;
}
net::DelDefaultRouteViaInterface(ep->GetIfName());
r->ForEachPeer(
[gateway = gateways[0]](const auto* link, bool) {
net::DelRoute(link->GetRemoteEndpoint().toHost(), gateway);
},
false);
std::string endpoint = "default";
const auto endpoint_itr = obj.find("endpoint");
if (endpoint_itr != obj.end())
ep->UnmapExitRange(range);
}
reply(CreateJSONResponse("OK"));
});
});
})
.add_request_command("config", [&](lokimq::Message& msg) {
HandleJSONRequest(msg, [r = m_Router](nlohmann::json obj, ReplyFunction_t reply) {
{
endpoint = endpoint_itr->get<std::string>();
}
LogicCall(r->logic(), [map, exit, range, token, endpoint, r, reply]() {
auto ep = r->hiddenServiceContext().GetEndpointByName(endpoint);
if (ep == nullptr)
const auto itr = obj.find("override");
if (itr != obj.end())
{
reply(CreateJSONError("no endpoint with name " + endpoint));
return;
}
if (map and exit.has_value())
{
ep->MapExitRange(range, *exit);
if (token.has_value())
if (not itr->is_object())
{
ep->SetAuthInfoForEndpoint(*exit, service::AuthInfo{*token});
reply(CreateJSONError(stringify("override is not an object")));
return;
}
for (const auto& [section, value] : itr->items())
{
if (not value.is_object())
{
reply(CreateJSONError(
stringify("failed to set [", section, "] section is not an object")));
return;
}
for (const auto& [key, value] : value.items())
{
if (not value.is_string())
{
reply(CreateJSONError(stringify(
"failed to set [", section, "]:", key, " value is not a string")));
return;
}
r->GetConfig()->Override(section, key, value.get<std::string>());
}
}
}
else if (map and not exit.has_value())
{
reply(CreateJSONError("no exit address provided"));
return;
}
else if (not map)
}
{
const auto itr = obj.find("reload");
if (itr != obj.end() and itr->get<bool>())
{
ep->UnmapExitRange(range);
r->QueueDiskIO([conf = r->GetConfig()]() { conf->Save(); });
}
reply(CreateJSONResponse("OK"));
});
}
reply(CreateJSONResponse("OK"));
});
});
}

@ -54,6 +54,11 @@ namespace llarp
conf.m_ExitMap.ForEachEntry(
[&](const IPRange& range, const service::Address& addr) { MapExitRange(range, addr); });
for (auto [exit, auth] : conf.m_ExitAuths)
{
SetAuthInfoForEndpoint(exit, auth);
}
return m_state->Configure(conf);
}
@ -912,25 +917,7 @@ namespace llarp
RemoveConvoTag(frame.T);
return true;
}
if (!frame.AsyncDecryptAndVerify(EndpointLogic(), p, m_Identity, this))
{
// send discard
ProtocolFrame f;
f.R = 1;
f.T = frame.T;
f.F = p->intro.pathID;
if (!f.Sign(m_Identity))
return false;
{
LogWarn("invalidating convotag T=", frame.T);
util::Lock lock(m_state->m_SendQueueMutex);
m_state->m_SendQueue.emplace_back(
std::make_shared<const routing::PathTransferMessage>(f, frame.F), p);
}
return true;
}
return true;
return frame.AsyncDecryptAndVerify(EndpointLogic(), p, m_Identity, this);
}
void Endpoint::HandlePathDied(path::Path_ptr)
@ -1071,11 +1058,18 @@ namespace llarp
// TODO: check for collision lol no we don't but maybe we will...
// some day :DDDDD
tag.Randomize();
const auto src = xhtonl(net::TruncateV6(GetIfAddr()));
const auto dst = xhtonl(net::TruncateV6(ObtainIPForAddr(snode, true)));
auto session = std::make_shared<exit::SNodeSession>(
snode,
[=](const llarp_buffer_t& pkt) -> bool {
[=](const llarp_buffer_t& buf) -> bool {
net::IPPacket pkt;
if (not pkt.Load(buf))
return false;
pkt.UpdateIPv4Address(src, dst);
/// TODO: V6
return HandleInboundPacket(tag, pkt, eProtocolTrafficV4);
return HandleInboundPacket(tag, pkt.ConstBuffer(), eProtocolTrafficV4);
},
Router(),
numPaths,
@ -1190,6 +1184,7 @@ namespace llarp
{
auto transfer = std::make_shared<routing::PathTransferMessage>();
ProtocolFrame& f = transfer->T;
f.R = 0;
std::shared_ptr<path::Path> p;
std::set<ConvoTag> tags;
if (GetConvoTagsForService(remote, tags))

@ -108,6 +108,9 @@ namespace llarp
return false;
}
virtual std::string
GetIfName() const = 0;
/// inject vpn io
/// return false if not supported
virtual bool
@ -182,8 +185,8 @@ namespace llarp
void
SetAuthInfoForEndpoint(Address remote, AuthInfo info);
// virtual huint128_t
// ObtainIPForAddr(const AlignedBuffer< 32 >& addr, bool serviceNode) = 0;
virtual huint128_t
ObtainIPForAddr(const AlignedBuffer<32>& addr, bool serviceNode) = 0;
// virtual bool
// HasServiceAddress(const AlignedBuffer< 32 >& addr) const = 0;

@ -70,6 +70,7 @@ namespace llarp
{
SharedSecret shared;
auto f = std::make_shared<ProtocolFrame>();
f->R = 0;
f->N.Randomize();
f->T = currentConvoTag;
f->S = ++sequenceNo;

@ -9,9 +9,7 @@ namespace tooling
}
std::unique_ptr<llarp::AbstractRouter>
HiveContext::makeRouter(
llarp_ev_loop_ptr netloop,
std::shared_ptr<llarp::Logic> logic)
HiveContext::makeRouter(llarp_ev_loop_ptr netloop, std::shared_ptr<llarp::Logic> logic)
{
return std::make_unique<HiveRouter>(netloop, logic, m_hive);
}

@ -12,9 +12,7 @@ namespace tooling
HiveContext(RouterHive* hive);
std::unique_ptr<llarp::AbstractRouter>
makeRouter(
llarp_ev_loop_ptr netloop,
std::shared_ptr<llarp::Logic> logic) override;
makeRouter(llarp_ev_loop_ptr netloop, std::shared_ptr<llarp::Logic> logic) override;
/// Get this context's router as a HiveRouter.
///

@ -10,10 +10,7 @@ namespace tooling
/// code.
struct HiveRouter : public llarp::Router
{
HiveRouter(
llarp_ev_loop_ptr netloop,
std::shared_ptr<llarp::Logic> logic,
RouterHive* hive);
HiveRouter(llarp_ev_loop_ptr netloop, std::shared_ptr<llarp::Logic> logic, RouterHive* hive);
virtual ~HiveRouter() = default;

@ -46,19 +46,6 @@ namespace llarp
return vals.count(str) > 0;
}
bool
StrEq(const char* s1, const char* s2)
{
size_t sz1 = strlen(s1);
size_t sz2 = strlen(s2);
if (sz1 == sz2)
{
return strncmp(s1, s2, sz1) == 0;
}
return false;
}
constexpr static char whitespace[] = " \t\n\r\f\v";
std::string_view

@ -7,9 +7,6 @@
namespace llarp
{
bool
StrEq(const char* s1, const char* s2);
bool
IsFalseValue(std::string_view str);

@ -56,6 +56,18 @@ namespace llarp
return false;
}
llarp::huint128_t
ObtainIPForAddr(const llarp::AlignedBuffer<32>&, bool) override
{
return {0};
}
std::string
GetIfName() const override
{
return "";
}
using PacketHandler_t =
std::function<void(service::Address, std::vector<byte_t>, service::ProtocolType)>;

@ -11,17 +11,19 @@ static const llarp::RuntimeOptions opts = {.background = false, .debug = false,
std::shared_ptr<llarp::Context>
make_context()
{
llarp::Config conf;
llarp::Config conf{};
conf.LoadDefault(true, fs::current_path());
// set testing defaults
conf.network.m_endpointType = "null";
conf.bootstrap.skipBootstrap = true;
conf.api.m_enableRPCServer = false;
conf.router.m_enablePeerStats = true;
conf.router.m_publicAddress = llarp::IpAddress("1.1.1.1");
// make a fake inbound link
conf.links.m_InboundLinks.emplace_back();
auto& link = conf.links.m_InboundLinks.back();
link.interface = llarp::net::LoopbackInterfaceName();
link.interface = "0.0.0.0";
link.addressFamily = AF_INET;
link.port = 0;
// configure

@ -30,8 +30,8 @@ def HiveArbitrary():
return router_hive
yield _make
router_hive.Stop()
if router_hive:
router_hive.Stop()
@pytest.fixture()
def HiveForPeerStats():
@ -43,5 +43,5 @@ def HiveForPeerStats():
return router_hive
yield _make
router_hive.Stop()
if router_hive:
router_hive.Stop()

@ -2,7 +2,7 @@ import pyllarp
from time import time
def test_peer_stats(HiveForPeerStats):
return
numRelays = 12
hive = HiveForPeerStats(n_relays=numRelays, n_clients=0, netid="hive")

@ -40,38 +40,51 @@ TEST_CASE("Test PeerStats BEncode", "[PeerStats]")
stats.numPacketsResent = 9;
stats.numDistinctRCsReceived = 10;
stats.numLateRCs = 11;
stats.peakBandwidthBytesPerSec = 12.1; // should truncate to 12
stats.peakBandwidthBytesPerSec = 12.1; // should truncate to 12
stats.longestRCReceiveInterval = 13ms;
stats.leastRCRemainingLifetime = 14ms;
stats.lastRCUpdated = 15ms;
constexpr int bufSize = 4096;
byte_t* raw = new byte_t[bufSize];
llarp_buffer_t buf(raw, bufSize);
constexpr size_t bufSize = 4096;
std::array<byte_t, bufSize> raw{};
llarp_buffer_t buf(raw);
CHECK_NOTHROW(stats.BEncode(&buf));
std::string asString = (const char*)raw;
std::string asString = (const char*)raw.data();
constexpr std::string_view expected =
"d"
"21:numConnectionAttempts" "i1e"
"22:numConnectionSuccesses" "i2e"
"23:numConnectionRejections" "i3e"
"21:numConnectionTimeouts" "i4e"
"13:numPathBuilds" "i5e"
"19:numPacketsAttempted" "i6e"
"14:numPacketsSent" "i7e"
"17:numPacketsDropped" "i8e"
"16:numPacketsResent" "i9e"
"22:numDistinctRCsReceived" "i10e"
"10:numLateRCs" "i11e"
"24:peakBandwidthBytesPerSec" "i12e"
"24:longestRCReceiveInterval" "i13e"
"24:leastRCRemainingLifetime" "i14e"
"13:lastRCUpdated" "i15e"
"e";
"d"
"13:lastRCUpdated"
"i15e"
"24:leastRCRemainingLifetime"
"i14e"
"24:longestRCReceiveInterval"
"i13e"
"21:numConnectionAttempts"
"i1e"
"23:numConnectionRejections"
"i3e"
"22:numConnectionSuccesses"
"i2e"
"21:numConnectionTimeouts"
"i4e"
"22:numDistinctRCsReceived"
"i10e"
"10:numLateRCs"
"i11e"
"19:numPacketsAttempted"
"i6e"
"17:numPacketsDropped"
"i8e"
"16:numPacketsResent"
"i9e"
"14:numPacketsSent"
"i7e"
"13:numPathBuilds"
"i5e"
"24:peakBandwidthBytesPerSec"
"i12e"
"e";
CHECK(asString == expected);
delete [] raw;
}

@ -38,7 +38,6 @@ TEST_F(RCTest, TestSignVerify)
rc.enckey = encr.toPublic();
rc.pubkey = sign.toPublic();
rc.exits.emplace_back(rc.pubkey, IpAddress("1.1.1.1"));
ASSERT_TRUE(rc.netID == netid);
ASSERT_TRUE(rc.netID == NetID::DefaultValue());

@ -382,6 +382,12 @@ tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask)
uint8_t length;
uint32_t value[2];
} dns;
struct
{
uint8_t dhcp_opt;
uint8_t length;
uint32_t value;
} gateway;
#pragma pack(pop)
sock[0] = s->S_un.S_addr;
@ -398,10 +404,10 @@ tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask)
ep[0] = s->S_un.S_addr;
ep[1] = mask;
ep[2] = (s->S_un.S_addr | ~mask)
- (mask + 1); /* For the 10.x.0.y subnet (in a class C config), _should_
ep[2] = (s->S_un.S_addr | ~mask) - htonl(1);
/*+ (mask + 1);*/ /* For the 10.x.0.y subnet (in a class C config), _should_
be 10.x.0.254 i think */
ep[3] = 3153600; /* one year */
ep[3] = 31536000; /* one year */
ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_MASQ, ep, sizeof(ep),
ep, sizeof(ep), &len, NULL);
@ -427,6 +433,14 @@ tuntap_sys_set_ipv4(struct device *dev, t_tun_in_addr *s, uint32_t mask)
ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_SET_OPT, &dns,
sizeof(dns), &dns, sizeof(dns), &len, NULL);
/* set router address to interface address */
gateway.dhcp_opt = 3;
gateway.length = 4;
gateway.value = (s->S_un.S_addr)+htonl(1);
ret = DeviceIoControl(dev->tun_fd, TAP_IOCTL_CONFIG_DHCP_SET_OPT, &gateway,
sizeof(gateway), &gateway, sizeof(gateway), &len, NULL);
if(!ret)
{
int errcode = GetLastError();
@ -519,4 +533,4 @@ tuntap_set_ifname(struct device *dev, const char *name)
tuntap_log(TUNTAP_LOG_NOTICE,
"Your system does not support tuntap_set_ifname()");
return -1;
}
}

Loading…
Cancel
Save