Merge remote-tracking branch 'origin/dev' into debian/bookworm

debian/bookworm
Jason Rhinelander 2 years ago
commit 358ff282e5
No known key found for this signature in database
GPG Key ID: C4992CE7A88D4262

@ -11,25 +11,25 @@ set(OPENSSL_SOURCE openssl-${OPENSSL_VERSION}.tar.gz)
set(OPENSSL_HASH SHA256=aa7d8d9bef71ad6525c55ba11e5f4397889ce49c2c9349dcea6d3e4f0b024a7a set(OPENSSL_HASH SHA256=aa7d8d9bef71ad6525c55ba11e5f4397889ce49c2c9349dcea6d3e4f0b024a7a
CACHE STRING "openssl source hash") CACHE STRING "openssl source hash")
set(EXPAT_VERSION 2.4.8 CACHE STRING "expat version") set(EXPAT_VERSION 2.4.9 CACHE STRING "expat version")
string(REPLACE "." "_" EXPAT_TAG "R_${EXPAT_VERSION}") string(REPLACE "." "_" EXPAT_TAG "R_${EXPAT_VERSION}")
set(EXPAT_MIRROR ${LOCAL_MIRROR} https://github.com/libexpat/libexpat/releases/download/${EXPAT_TAG} set(EXPAT_MIRROR ${LOCAL_MIRROR} https://github.com/libexpat/libexpat/releases/download/${EXPAT_TAG}
CACHE STRING "expat download mirror(s)") CACHE STRING "expat download mirror(s)")
set(EXPAT_SOURCE expat-${EXPAT_VERSION}.tar.xz) set(EXPAT_SOURCE expat-${EXPAT_VERSION}.tar.xz)
set(EXPAT_HASH SHA256=f79b8f904b749e3e0d20afeadecf8249c55b2e32d4ebb089ae378df479dcaf25 set(EXPAT_HASH SHA512=8508379b4915d84d50f3638678a90792179c98247d1cb5e6e6387d117af4dc148ac7031c1debea8b96e7b710ef436cf0dd5da91f3d22b8186a00cfafe1201169
CACHE STRING "expat source hash") CACHE STRING "expat source hash")
set(UNBOUND_VERSION 1.16.2 CACHE STRING "unbound version") set(UNBOUND_VERSION 1.17.0 CACHE STRING "unbound version")
set(UNBOUND_MIRROR ${LOCAL_MIRROR} https://nlnetlabs.nl/downloads/unbound CACHE STRING "unbound download mirror(s)") set(UNBOUND_MIRROR ${LOCAL_MIRROR} https://nlnetlabs.nl/downloads/unbound CACHE STRING "unbound download mirror(s)")
set(UNBOUND_SOURCE unbound-${UNBOUND_VERSION}.tar.gz) set(UNBOUND_SOURCE unbound-${UNBOUND_VERSION}.tar.gz)
set(UNBOUND_HASH SHA512=0ea65ea63265be677441bd2a28df12098ec5e86c3372240c2874f9bd13752b8b818da81ae6076cf02cbeba3d36e397698a4c2b50570be1a6a8e47f57a0251572 set(UNBOUND_HASH SHA512=f6b9f279330fb19b5feca09524959940aad8c4e064528aa82b369c726d77e9e8e5ca23f366f6e9edcf2c061b96f482ed7a2c26ac70fc15ae5762b3d7e36a5284
CACHE STRING "unbound source hash") CACHE STRING "unbound source hash")
set(SQLITE3_VERSION 3380500 CACHE STRING "sqlite3 version") set(SQLITE3_VERSION 3390400 CACHE STRING "sqlite3 version")
set(SQLITE3_MIRROR ${LOCAL_MIRROR} https://www.sqlite.org/2022 set(SQLITE3_MIRROR ${LOCAL_MIRROR} https://www.sqlite.org/2022
CACHE STRING "sqlite3 download mirror(s)") CACHE STRING "sqlite3 download mirror(s)")
set(SQLITE3_SOURCE sqlite-autoconf-${SQLITE3_VERSION}.tar.gz) set(SQLITE3_SOURCE sqlite-autoconf-${SQLITE3_VERSION}.tar.gz)
set(SQLITE3_HASH SHA3_256=ab649fea76f49a6ec7f907f001d87b8bd76dec0679c783e3992284c5a882a98c set(SQLITE3_HASH SHA3_256=431328e30d12c551da9ba7ef2122b269076058512014afa799caaf62ca567090
CACHE STRING "sqlite3 source hash") CACHE STRING "sqlite3 source hash")
set(SODIUM_VERSION 1.0.18 CACHE STRING "libsodium version") set(SODIUM_VERSION 1.0.18 CACHE STRING "libsodium version")
@ -48,25 +48,25 @@ set(ZMQ_SOURCE zeromq-${ZMQ_VERSION}.tar.gz)
set(ZMQ_HASH SHA512=e198ef9f82d392754caadd547537666d4fba0afd7d027749b3adae450516bcf284d241d4616cad3cb4ad9af8c10373d456de92dc6d115b037941659f141e7c0e set(ZMQ_HASH SHA512=e198ef9f82d392754caadd547537666d4fba0afd7d027749b3adae450516bcf284d241d4616cad3cb4ad9af8c10373d456de92dc6d115b037941659f141e7c0e
CACHE STRING "libzmq source hash") CACHE STRING "libzmq source hash")
set(LIBUV_VERSION 1.44.1 CACHE STRING "libuv version") set(LIBUV_VERSION 1.44.2 CACHE STRING "libuv version")
set(LIBUV_MIRROR ${LOCAL_MIRROR} https://dist.libuv.org/dist/v${LIBUV_VERSION} set(LIBUV_MIRROR ${LOCAL_MIRROR} https://dist.libuv.org/dist/v${LIBUV_VERSION}
CACHE STRING "libuv mirror(s)") CACHE STRING "libuv mirror(s)")
set(LIBUV_SOURCE libuv-v${LIBUV_VERSION}.tar.gz) set(LIBUV_SOURCE libuv-v${LIBUV_VERSION}.tar.gz)
set(LIBUV_HASH SHA512=b4f8944e2c79e3a6a31ded6cccbe4c0eeada50db6bc8a448d7015642795012a4b80ffeef7ca455bb093c59a8950d0e1430566c3c2fa87b73f82699098162d834 set(LIBUV_HASH SHA512=91197ff9303112567bbb915bbb88058050e2ad1c048815a3b57c054635d5dc7df458b956089d785475290132236cb0edcfae830f5d749de29a9a3213eeaf0b20
CACHE STRING "libuv source hash") CACHE STRING "libuv source hash")
set(ZLIB_VERSION 1.2.12 CACHE STRING "zlib version") set(ZLIB_VERSION 1.2.13 CACHE STRING "zlib version")
set(ZLIB_MIRROR ${LOCAL_MIRROR} https://zlib.net set(ZLIB_MIRROR ${LOCAL_MIRROR} https://zlib.net
CACHE STRING "zlib mirror(s)") CACHE STRING "zlib mirror(s)")
set(ZLIB_SOURCE zlib-${ZLIB_VERSION}.tar.gz) set(ZLIB_SOURCE zlib-${ZLIB_VERSION}.tar.xz)
set(ZLIB_HASH SHA256=91844808532e5ce316b3c010929493c0244f3d37593afd6de04f71821d5136d9 set(ZLIB_HASH SHA256=d14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98
CACHE STRING "zlib source hash") CACHE STRING "zlib source hash")
set(CURL_VERSION 7.83.1 CACHE STRING "curl version") set(CURL_VERSION 7.85.0 CACHE STRING "curl version")
set(CURL_MIRROR ${LOCAL_MIRROR} https://curl.haxx.se/download https://curl.askapache.com set(CURL_MIRROR ${LOCAL_MIRROR} https://curl.haxx.se/download https://curl.askapache.com
CACHE STRING "curl mirror(s)") CACHE STRING "curl mirror(s)")
set(CURL_SOURCE curl-${CURL_VERSION}.tar.xz) set(CURL_SOURCE curl-${CURL_VERSION}.tar.xz)
set(CURL_HASH SHA256=2cb9c2356e7263a1272fd1435ef7cdebf2cd21400ec287b068396deb705c22c4 set(CURL_HASH SHA512=b57cc31649a4f47cc4b482f56a85c86c8e8aaeaf01bc1b51b065fdb9145a9092bc52535e52a85a66432eb163605b2edbf5bc5c33ea6e40e50f26a69ad1365cbd
CACHE STRING "curl source hash") CACHE STRING "curl source hash")
include(ExternalProject) include(ExternalProject)
@ -167,6 +167,11 @@ if(APPLE)
set(deps_CXXFLAGS "${deps_CXXFLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") set(deps_CXXFLAGS "${deps_CXXFLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}")
endif() endif()
if(_winver)
set(deps_CFLAGS "${deps_CFLAGS} -D_WIN32_WINNT=${_winver}")
set(deps_CXXFLAGS "${deps_CXXFLAGS} -D_WIN32_WINNT=${_winver}")
endif()
if("${CMAKE_GENERATOR}" STREQUAL "Unix Makefiles") if("${CMAKE_GENERATOR}" STREQUAL "Unix Makefiles")
set(_make $(MAKE)) set(_make $(MAKE))

@ -13,9 +13,6 @@ option(WITH_WINDOWS_32 "build 32 bit windows" OFF)
# GNU ld sees fit to merge *all* the .ident sections in object files # GNU ld sees fit to merge *all* the .ident sections in object files
# to .r[o]data section one after the other! # to .r[o]data section one after the other!
add_compile_options(-fno-ident -Wa,-mbig-obj) add_compile_options(-fno-ident -Wa,-mbig-obj)
# the minimum windows version, set to 6 rn because supporting older windows is hell
set(_winver 0x0600)
add_definitions(-D_WIN32_WINNT=${_winver})
if(EMBEDDED_CFG) if(EMBEDDED_CFG)
link_libatomic() link_libatomic()

@ -8,7 +8,7 @@ set -o errexit
bad= bad=
if [ "$DRONE_STAGE_OS" == "darwin" ]; then if [ "$DRONE_STAGE_OS" == "darwin" ]; then
if otool -L llarp/apple/org.lokinet.network-extension.systemextension/Contents/MacOS/org.lokinet.network-extension | \ if otool -L llarp/apple/org.lokinet.network-extension.systemextension/Contents/MacOS/org.lokinet.network-extension | \
grep -Ev '^llarp/apple:|^\t(/usr/lib/lib(System\.|c\+\+|objc)|/System/Library/Frameworks/(CoreFoundation|NetworkExtension|Foundation|Network)\.framework'; then grep -Ev '^llarp/apple:|^\t(/usr/lib/lib(System\.|c\+\+|objc))|/System/Library/Frameworks/(CoreFoundation|NetworkExtension|Foundation|Network)\.framework'; then
bad=1 bad=1
fi fi
elif [ "$DRONE_STAGE_OS" == "linux" ]; then elif [ "$DRONE_STAGE_OS" == "linux" ]; then

@ -1,6 +1,9 @@
#!/usr/bin/env bash #!/usr/bin/env bash
test "x$IGNORE" != "x" && exit 0 test "x$IGNORE" != "x" && exit 0
. $(dirname $0)/../format-version.sh
repo=$(readlink -e $(dirname $0)/../../) repo=$(readlink -e $(dirname $0)/../../)
clang-format-11 -i $(find $repo/jni $repo/daemon $repo/llarp $repo/include $repo/pybind | grep -E '\.[hc](pp)?$') $CLANG_FORMAT -i $(find $repo/jni $repo/daemon $repo/llarp $repo/include $repo/pybind | grep -E '\.[hc](pp)?$')
jsonnetfmt -i $repo/.drone.jsonnet jsonnetfmt -i $repo/.drone.jsonnet
git --no-pager diff --exit-code --color || (echo -ne '\n\n\e[31;1mLint check failed; please run ./contrib/format.sh\e[0m\n\n' ; exit 1) git --no-pager diff --exit-code --color || (echo -ne '\n\n\e[31;1mLint check failed; please run ./contrib/format.sh\e[0m\n\n' ; exit 1)

@ -19,9 +19,15 @@ set -o xtrace # Don't start tracing until *after* we write the ssh key
chmod 600 ssh_key chmod 600 ssh_key
os="${UPLOAD_OS:-$DRONE_STAGE_OS-$DRONE_STAGE_ARCH}" os="$UPLOAD_OS"
if [ -n "$WINDOWS_BUILD_NAME" ]; then if [ -z "$os" ]; then
os="windows-$WINDOWS_BUILD_NAME" if [ "$DRONE_STAGE_OS" == "darwin" ]; then
os="macos-$DRONE_STAGE_ARCH"
elif [ -n "$WINDOWS_BUILD_NAME" ]; then
os="windows-$WINDOWS_BUILD_NAME"
else
os="$DRONE_STAGE_OS-$DRONE_STAGE_ARCH"
fi
fi fi
if [ -n "$DRONE_TAG" ]; then if [ -n "$DRONE_TAG" ]; then
@ -55,8 +61,8 @@ elif [ -e build-mac ]; then
mv build-mac/Lokinet*/ "$base" mv build-mac/Lokinet*/ "$base"
tar cJvf "$archive" "$base" tar cJvf "$archive" "$base"
else else
cp -av daemon/lokinet daemon/lokinet-vpn "$base" cp -av build/daemon/lokinet{,-vpn} "$base"
cp -av ../contrib/bootstrap/mainnet.signed "$base/bootstrap.signed" cp -av contrib/bootstrap/mainnet.signed "$base/bootstrap.signed"
# tar dat shiz up yo # tar dat shiz up yo
archive="$base.tar.xz" archive="$base.tar.xz"
tar cJvf "$archive" "$base" tar cJvf "$archive" "$base"

@ -1,4 +1,8 @@
set(CMAKE_SYSTEM_VERSION 5.0) set(CMAKE_SYSTEM_VERSION 6.0)
# the minimum windows version, set to 6 rn because supporting older windows is hell
set(_winver 0x0600)
add_definitions(-D_WIN32_WINNT=${_winver})
# target environment on the build host system # target environment on the build host system
# second one is for non-root installs # second one is for non-root installs

@ -0,0 +1,19 @@
CLANG_FORMAT_DESIRED_VERSION=14
CLANG_FORMAT=$(command -v clang-format-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null)
if [ $? -ne 0 ]; then
CLANG_FORMAT=$(command -v clang-format-mp-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null)
fi
if [ $? -ne 0 ]; then
CLANG_FORMAT=$(command -v clang-format 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Please install clang-format version $CLANG_FORMAT_DESIRED_VERSION and re-run this script."
exit 1
fi
version=$(clang-format --version)
if [[ ! $version == *"clang-format version $CLANG_FORMAT_DESIRED_VERSION"* ]]; then
echo "Please install clang-format version $CLANG_FORMAT_DESIRED_VERSION and re-run this script."
exit 1
fi
fi

@ -1,31 +1,15 @@
#!/usr/bin/env bash #!/usr/bin/env bash
CLANG_FORMAT_DESIRED_VERSION=11 . $(dirname $0)/format-version.sh
binary=$(command -v clang-format-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null)
if [ $? -ne 0 ]; then
binary=$(command -v clang-format-mp-$CLANG_FORMAT_DESIRED_VERSION 2>/dev/null)
fi
if [ $? -ne 0 ]; then
binary=$(command -v clang-format 2>/dev/null)
if [ $? -ne 0 ]; then
echo "Please install clang-format version $CLANG_FORMAT_DESIRED_VERSION and re-run this script."
exit 1
fi
version=$(clang-format --version)
if [[ ! $version == *"clang-format version $CLANG_FORMAT_DESIRED_VERSION"* ]]; then
echo "Please install clang-format version $CLANG_FORMAT_DESIRED_VERSION and re-run this script."
exit 1
fi
fi
cd "$(dirname $0)/../" cd "$(dirname $0)/../"
if [ "$1" = "verify" ] ; then if [ "$1" = "verify" ] ; then
if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') | grep '</replacement>' | wc -l) -ne 0 ] ; then if [ $($CLANG_FORMAT --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') | grep '</replacement>' | wc -l) -ne 0 ] ; then
exit 2 exit 2
fi fi
else else
$binary -i $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') &> /dev/null $CLANG_FORMAT -i $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') &> /dev/null
fi fi
swift_format=$(command -v swiftformat 2>/dev/null) swift_format=$(command -v swiftformat 2>/dev/null)

@ -329,9 +329,8 @@ class WindowsServiceStopped
LONG LONG
GenerateDump(EXCEPTION_POINTERS* pExceptionPointers) GenerateDump(EXCEPTION_POINTERS* pExceptionPointers)
{ {
const auto flags = (MINIDUMP_TYPE)( const auto flags =
MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | MiniDumpWithHandleData (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithThreadInfo);
| MiniDumpWithUnloadedModules | MiniDumpWithThreadInfo);
std::stringstream ss; std::stringstream ss;
ss << "C:\\ProgramData\\lokinet\\crash-" << llarp::time_now_ms().count() << ".dmp"; ss << "C:\\ProgramData\\lokinet\\crash-" << llarp::time_now_ms().count() << ".dmp";

@ -124,4 +124,19 @@ if(WITH_BOOTSTRAP)
target_include_directories(cpr PUBLIC cpr/include) target_include_directories(cpr PUBLIC cpr/include)
target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL) target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL)
add_library(cpr::cpr ALIAS cpr) add_library(cpr::cpr ALIAS cpr)
file(READ cpr/CMakeLists.txt cpr_cmake_head LIMIT 1000)
if(cpr_cmake_head MATCHES "project\\(cpr VERSION ([0-9]+)\.([0-9]+)\.([0-9]+) LANGUAGES CXX\\)")
set(cpr_VERSION_MAJOR ${CMAKE_MATCH_1})
set(cpr_VERSION_MINOR ${CMAKE_MATCH_2})
set(cpr_VERSION_PATCH ${CMAKE_MATCH_3})
set(cpr_VERSION "${cpr_VERSION_MAJOR}.${cpr_VERSION_MINOR}.${cpr_VERSION_PATCH}")
set(cpr_VERSION_NUM "(${cpr_VERSION_MAJOR} * 0x10000 + ${cpr_VERSION_MINOR} * 0x100 + ${cpr_VERSION_PATCH})")
configure_file(cpr/cmake/cprver.h.in "${CMAKE_CURRENT_BINARY_DIR}/cpr_generated_includes/cpr/cprver.h")
target_include_directories(cpr PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/cpr_generated_includes")
else()
message(FATAL_ERROR "Could not identify cpr submodule version!")
endif()
endif() endif()

2
external/cpr vendored

@ -1 +1 @@
Subproject commit aac5058a15e9ad5ad393973dc6fe44d7614a7f55 Subproject commit f88fd7737de3e640c61703eb57a0fa0ce00c60cd

2
external/cxxopts vendored

@ -1 +1 @@
Subproject commit 6fa46a748838d5544ff8e9ab058906ba2c4bc0f3 Subproject commit c74846a891b3cc3bfa992d588b1295f528d43039

@ -1 +1 @@
Subproject commit 2a8b380f8d4e77b389c42a194ab9c70d8e3a0f1e Subproject commit cd6805e94dd5d6346be1b75a54cdc27787319dd2

2
external/nlohmann vendored

@ -1 +1 @@
Subproject commit db78ac1d7716f56fc9f1b030b715f872f93964e4 Subproject commit bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d

2
external/pybind11 vendored

@ -1 +1 @@
Subproject commit 8de7772cc72daca8e947b79b83fea46214931604 Subproject commit aa304c9c7d725ffb9d10af08a3b34cb372307020

@ -1 +1 @@
Subproject commit 4c6a46bd4dcfba14a650e0fafb86331526878587 Subproject commit fdcc1da46fbd90feb886c0588462a62d29eb5a06

@ -15,10 +15,12 @@ namespace llarp::apple
/// These are called for poking route holes, but we don't have to do that at all on macos /// These are called for poking route holes, but we don't have to do that at all on macos
/// because the appex isn't subject to its own rules. /// because the appex isn't subject to its own rules.
void AddRoute(net::ipaddr_t /*ip*/, net::ipaddr_t /*gateway*/) override void
AddRoute(net::ipaddr_t /*ip*/, net::ipaddr_t /*gateway*/) override
{} {}
void DelRoute(net::ipaddr_t /*ip*/, net::ipaddr_t /*gateway*/) override void
DelRoute(net::ipaddr_t /*ip*/, net::ipaddr_t /*gateway*/) override
{} {}
void void

@ -300,9 +300,9 @@ namespace llarp
throw std::invalid_argument{"duplicate strict connect snode: " + value}; throw std::invalid_argument{"duplicate strict connect snode: " + value};
}, },
Comment{ Comment{
"Public key of a router which will act as a pinned first-hop. This may be used to", "Public keys of routers which will act as pinned first-hops. This may be used to",
"provide a trusted router (consider that you are not fully anonymous with your", "provide a trusted router (consider that you are not fully anonymous with your",
"first hop).", "first hop). This REQUIRES two or more nodes to be specified.",
}); });
conf.defineOption<std::string>( conf.defineOption<std::string>(
@ -459,9 +459,8 @@ namespace llarp
"owned-range", "owned-range",
MultiValue, MultiValue,
Comment{ Comment{
"When in exit mode announce we allow a private range in our introset" "When in exit mode announce we allow a private range in our introset. For example:",
"exmaple:", " owned-range=10.0.0.0/24",
"owned-range=10.0.0.0/24",
}, },
[this](std::string arg) { [this](std::string arg) {
IPRange range; IPRange range;
@ -475,12 +474,17 @@ namespace llarp
"traffic-whitelist", "traffic-whitelist",
MultiValue, MultiValue,
Comment{ Comment{
"List of ip traffic whitelist, anything not specified will be dropped by us." "Adds an IP traffic type whitelist; can be specified multiple times. If any are",
"examples:", "specified then only matched traffic will be allowed and all other traffic will be",
"tcp for all tcp traffic regardless of port", "dropped. Examples:",
"0x69 for all packets using ip protocol 0x69" " traffic-whitelist=tcp",
"udp/53 for udp port 53", "would allow all TCP/IP packets (regardless of port);",
"tcp/smtp for smtp port", " traffic-whitelist=0x69",
"would allow IP traffic with IP protocol 0x69;",
" traffic-whitelist=udp/53",
"would allow UDP port 53; and",
" traffic-whitelist=tcp/smtp",
"would allow TCP traffic on the standard smtp port (21).",
}, },
[this](std::string arg) { [this](std::string arg) {
if (not m_TrafficPolicy) if (not m_TrafficPolicy)
@ -497,9 +501,12 @@ namespace llarp
MultiValue, MultiValue,
Comment{ Comment{
"Specify a `.loki` address and an optional ip range to use as an exit broker.", "Specify a `.loki` address and an optional ip range to use as an exit broker.",
"Example:", "Examples:",
"exit-node=whatever.loki # maps all exit traffic to whatever.loki", " exit-node=whatever.loki",
"exit-node=stuff.loki:100.0.0.0/24 # maps 100.0.0.0/24 to stuff.loki", "would map all exit traffic through whatever.loki; and",
" exit-node=stuff.loki:100.0.0.0/24",
"would map the IP range 100.0.0.0/24 through stuff.loki.",
"This option can be specified multiple times (to map different IP ranges).",
}, },
[this](std::string arg) { [this](std::string arg) {
if (arg.empty()) if (arg.empty())
@ -580,10 +587,10 @@ namespace llarp
Default{true}, Default{true},
Comment{ Comment{
"Enable / disable automatic route configuration.", "Enable / disable automatic route configuration.",
"When this is enabled and an exit is used Lokinet will automatically configure " "When this is enabled and an exit is used Lokinet will automatically configure the",
"operating system routes to route traffic through the exit node.", "operating system routes to route public internet traffic through the exit node.",
"This is enabled by default, but can be disabled to perform advanced exit routing " "This is enabled by default, but can be disabled if advanced/manual exit routing",
"configuration manually."}, "configuration is desired."},
AssignmentAcceptor(m_EnableRoutePoker)); AssignmentAcceptor(m_EnableRoutePoker));
conf.defineOption<bool>( conf.defineOption<bool>(
@ -593,8 +600,8 @@ namespace llarp
Default{true}, Default{true},
Comment{ Comment{
"Enable / disable route configuration blackholes.", "Enable / disable route configuration blackholes.",
"When enabled lokinet will drop ip4 and ip6 not included in exit config.", "When enabled lokinet will drop IPv4 and IPv6 traffic (when in exit mode) that is not",
"Enabled by default."}, "handled in the exit configuration. Enabled by default."},
AssignmentAcceptor(m_BlackholeRoutes)); AssignmentAcceptor(m_BlackholeRoutes));
conf.defineOption<std::string>( conf.defineOption<std::string>(
@ -602,7 +609,7 @@ namespace llarp
"ifname", "ifname",
Comment{ Comment{
"Interface name for lokinet traffic. If unset lokinet will look for a free name", "Interface name for lokinet traffic. If unset lokinet will look for a free name",
"lokinetN, starting at 0 (e.g. lokinet0, lokinet1, ...).", "matching 'lokinetN', starting at N=0 (e.g. lokinet0, lokinet1, ...).",
}, },
AssignmentAcceptor(m_ifname)); AssignmentAcceptor(m_ifname));
@ -626,10 +633,10 @@ namespace llarp
"ip6-range", "ip6-range",
ClientOnly, ClientOnly,
Comment{ Comment{
"For all ipv6 exit traffic you will use this as the base address bitwised or'd with " "For all IPv6 exit traffic you will use this as the base address bitwised or'd with ",
"the v4 address in use.", "the v4 address in use.",
"To disable ipv6 set this to an empty value.", "To disable ipv6 set this to an empty value.",
"!!! WARNING !!! Disabling ipv6 tunneling when you have ipv6 routes WILL lead to " "!!! WARNING !!! Disabling ipv6 tunneling when you have ipv6 routes WILL lead to ",
"de-anonymization as lokinet will no longer carry your ipv6 traffic.", "de-anonymization as lokinet will no longer carry your ipv6 traffic.",
}, },
IP6RangeDefault, IP6RangeDefault,
@ -720,9 +727,13 @@ namespace llarp
ClientOnly, ClientOnly,
MultiValue, MultiValue,
Comment{ Comment{
"Specify SRV Records for services hosted on the SNApp", "Specify SRV Records for services hosted on the SNApp for protocols that use SRV",
"for more info see https://docs.loki.network/Lokinet/Guides/HostingSNApps/", "records for service discovery. Each line specifies a single SRV record as:",
"srv=_service._protocol priority weight port target.loki", " srv=_service._protocol priority weight port target.loki",
"and can be specified multiple times as needed.",
"For more info see",
"https://docs.oxen.io/products-built-on-oxen/lokinet/snapps/hosting-snapps",
"and general description of DNS SRV record configuration.",
}, },
[this](std::string arg) { [this](std::string arg) {
llarp::dns::SRVData newSRV; llarp::dns::SRVData newSRV;
@ -737,8 +748,8 @@ namespace llarp
"path-alignment-timeout", "path-alignment-timeout",
ClientOnly, ClientOnly,
Comment{ Comment{
"time in seconds how long to wait for a path to align to pivot routers", "How long to wait (in seconds) for a path to align to a pivot router when establishing",
"if not provided a sensible default will be used", "a path through the network to a remote .loki address.",
}, },
[this](int val) { [this](int val) {
if (val <= 0) if (val <= 0)
@ -753,9 +764,10 @@ namespace llarp
ClientOnly, ClientOnly,
Default{fs::path{params.defaultDataDir / "addrmap.dat"}}, Default{fs::path{params.defaultDataDir / "addrmap.dat"}},
Comment{ Comment{
"persist mapped ephemeral addresses to a file", "If given this specifies a file in which to record mapped local tunnel addresses so",
"on restart the mappings will be loaded so that ip addresses will not be mapped to a " "the same local address will be used for the same lokinet address on reboot. If this",
"different address", "is not specified then the local IP of remote lokinet targets will not persist across",
"restarts of lokinet.",
}, },
[this](fs::path arg) { [this](fs::path arg) {
if (arg.empty()) if (arg.empty())
@ -879,7 +891,7 @@ namespace llarp
"on systems which use resolveconf)", "on systems which use resolveconf)",
}); });
// forwad the rest to libunbound // forward the rest to libunbound
conf.addUndeclaredHandler("dns", [this](auto, std::string_view key, std::string_view val) { conf.addUndeclaredHandler("dns", [this](auto, std::string_view key, std::string_view val) {
m_ExtraOpts.emplace(key, val); m_ExtraOpts.emplace(key, val);
}); });
@ -1150,7 +1162,7 @@ namespace llarp
RelayOnly, RelayOnly,
Default{true}, Default{true},
Comment{ Comment{
"Whether or not we should talk to lokid. Must be enabled for staked routers.", "Whether or not we should talk to oxend. Must be enabled for staked routers.",
}, },
AssignmentAcceptor(whitelistRouters)); AssignmentAcceptor(whitelistRouters));
@ -1159,8 +1171,8 @@ namespace llarp
return; return;
throw std::invalid_argument( throw std::invalid_argument(
"the [lokid]:jsonrpc option is no longer supported; please use the [lokid]:rpc config " "the [lokid]:jsonrpc option is no longer supported; please use the [lokid]:rpc config "
"option instead with lokid's lmq-local-control address -- typically a value such as " "option instead with oxend's lmq-local-control address -- typically a value such as "
"rpc=ipc:///var/lib/loki/lokid.sock or rpc=ipc:///home/snode/.loki/lokid.sock"); "rpc=ipc:///var/lib/oxen/oxend.sock or rpc=ipc:///home/snode/.oxen/oxend.sock");
}); });
conf.defineOption<std::string>( conf.defineOption<std::string>(
@ -1168,12 +1180,12 @@ namespace llarp
"rpc", "rpc",
RelayOnly, RelayOnly,
Comment{ Comment{
"lokimq control address for for communicating with lokid. Depends on lokid's", "oxenmq control address for for communicating with oxend. Depends on oxend's",
"lmq-local-control configuration option. By default this value should be", "lmq-local-control configuration option. By default this value should be",
"ipc://LOKID-DATA-DIRECTORY/lokid.sock, such as:", "ipc://OXEND-DATA-DIRECTORY/oxend.sock, such as:",
" rpc=ipc:///var/lib/loki/lokid.sock", " rpc=ipc:///var/lib/oxen/oxend.sock",
" rpc=ipc:///home/USER/.loki/lokid.sock", " rpc=ipc:///home/USER/.oxen/oxend.sock",
"but can use (non-default) TCP if lokid is configured that way:", "but can use (non-default) TCP if oxend is configured that way:",
" rpc=tcp://127.0.0.1:5678", " rpc=tcp://127.0.0.1:5678",
}, },
[this](std::string arg) { lokidRPCAddr = oxenmq::address(arg); }); [this](std::string arg) { lokidRPCAddr = oxenmq::address(arg); });
@ -1202,7 +1214,7 @@ namespace llarp
"add-node", "add-node",
MultiValue, MultiValue,
Comment{ Comment{
"Specify a bootstrap file containing a signed RouterContact of a service node", "Specify a bootstrap file containing a list of signed RouterContacts of service nodes",
"which can act as a bootstrap. Can be specified multiple times.", "which can act as a bootstrap. Can be specified multiple times.",
}, },
[this](std::string arg) { [this](std::string arg) {
@ -1292,9 +1304,9 @@ namespace llarp
m_UniqueHopsNetmaskSize = arg; m_UniqueHopsNetmaskSize = arg;
}, },
Comment{ Comment{
"Netmask for router path selection; each router must be from a distinct IP subnet " "Netmask for router path selection; each router must be from a distinct IPv4 subnet",
"of the given size.", "of the given size.",
"E.g. 16 ensures that all routers are using distinct /16 IP addresses."}); "E.g. 16 ensures that all routers are using IPs from distinct /16 IP ranges."});
#ifdef WITH_GEOIP #ifdef WITH_GEOIP
conf.defineOption<std::string>( conf.defineOption<std::string>(
@ -1306,9 +1318,11 @@ namespace llarp
m_ExcludeCountries.emplace(lowercase_ascii_string(std::move(arg))); m_ExcludeCountries.emplace(lowercase_ascii_string(std::move(arg)));
}, },
Comment{ Comment{
"exclude a country given its 2 letter country code from being used in path builds", "Exclude a country given its 2 letter country code from being used in path builds.",
"e.g. exclude-country=DE", "For example:",
"can be listed multiple times to exclude multiple countries"}); " exclude-country=DE",
"would avoid building paths through routers with IPs in Germany.",
"This option can be specified multiple times to exclude multiple countries"});
#endif #endif
} }
@ -1399,6 +1413,7 @@ namespace llarp
params->isRelay = isRelay; params->isRelay = isRelay;
params->defaultDataDir = m_DataDir; params->defaultDataDir = m_DataDir;
ConfigDefinition conf{isRelay}; ConfigDefinition conf{isRelay};
addBackwardsCompatibleConfigOptions(conf);
initializeConfig(conf, *params); initializeConfig(conf, *params);
for (const auto& item : m_Additional) for (const auto& item : m_Additional)
@ -1616,11 +1631,11 @@ namespace llarp
initializeConfig(def, *params); initializeConfig(def, *params);
generateCommonConfigComments(def); generateCommonConfigComments(def);
// lokid // oxend
def.addSectionComments( def.addSectionComments(
"lokid", "lokid",
{ {
"Settings for communicating with lokid", "Settings for communicating with oxend",
}); });
return def.generateINIConfig(true); return def.generateINIConfig(true);

@ -441,7 +441,7 @@ namespace llarp
Context::CleanupTX() Context::CleanupTX()
{ {
auto now = Now(); auto now = Now();
llarp::LogDebug("DHT tick"); llarp::LogTrace("DHT tick");
pendingRouterLookups().Expire(now); pendingRouterLookups().Expire(now);
_pendingIntrosetLookups.Expire(now); _pendingIntrosetLookups.Expire(now);

@ -160,7 +160,8 @@ namespace llarp
return OwnedBuffer::copy_used(buf); return OwnedBuffer::copy_used(buf);
} }
void Message::AddServFail(RR_TTL_t) void
Message::AddServFail(RR_TTL_t)
{ {
if (questions.size()) if (questions.size())
{ {
@ -386,7 +387,8 @@ namespace llarp
std::copy_n(buf.base, buf.sz, rec.rData.data()); std::copy_n(buf.base, buf.sz, rec.rData.data());
} }
void Message::AddNXReply(RR_TTL_t) void
Message::AddNXReply(RR_TTL_t)
{ {
if (questions.size()) if (questions.size())
{ {

@ -89,7 +89,6 @@ namespace llarp::dns
class Query : public QueryJob_Base class Query : public QueryJob_Base
{ {
std::weak_ptr<Resolver> parent;
std::shared_ptr<PacketSource_Base> src; std::shared_ptr<PacketSource_Base> src;
SockAddr resolverAddr; SockAddr resolverAddr;
SockAddr askerAddr; SockAddr askerAddr;
@ -102,11 +101,13 @@ namespace llarp::dns
SockAddr toaddr, SockAddr toaddr,
SockAddr fromaddr) SockAddr fromaddr)
: QueryJob_Base{std::move(query)} : QueryJob_Base{std::move(query)}
, parent{parent_}
, src{std::move(pktsrc)} , src{std::move(pktsrc)}
, resolverAddr{std::move(toaddr)} , resolverAddr{std::move(toaddr)}
, askerAddr{std::move(fromaddr)} , askerAddr{std::move(fromaddr)}
, parent{parent_}
{} {}
std::weak_ptr<Resolver> parent;
int id{};
virtual void virtual void
SendReply(llarp::OwnedBuffer replyBuf) const override; SendReply(llarp::OwnedBuffer replyBuf) const override;
@ -126,6 +127,7 @@ namespace llarp::dns
#endif #endif
std::optional<SockAddr> m_LocalAddr; std::optional<SockAddr> m_LocalAddr;
std::set<int> m_Pending;
struct ub_result_deleter struct ub_result_deleter
{ {
@ -166,7 +168,9 @@ namespace llarp::dns
hdr.id = query->Underlying().hdr_id; hdr.id = query->Underlying().hdr_id;
buf.cur = buf.base; buf.cur = buf.base;
hdr.Encode(&buf); hdr.Encode(&buf);
// remove pending query
if (auto ptr = query->parent.lock())
ptr->call([id = query->id, ptr]() { ptr->m_Pending.erase(id); });
// send reply // send reply
query->SendReply(std::move(pkt)); query->SendReply(std::move(pkt));
} }
@ -407,6 +411,13 @@ namespace llarp::dns
#endif #endif
if (m_ctx) if (m_ctx)
{ {
// cancel pending queries
// make copy as ub_cancel modifies m_Pending
const auto pending = m_Pending;
for (auto id : pending)
::ub_cancel(m_ctx, id);
m_Pending.clear();
::ub_ctx_delete(m_ctx); ::ub_ctx_delete(m_ctx);
m_ctx = nullptr; m_ctx = nullptr;
} }
@ -478,6 +489,12 @@ namespace llarp::dns
return true; return true;
} }
} }
if (not m_ctx)
{
// we are down
tmp->Cancel();
return true;
}
const auto& q = query.questions[0]; const auto& q = query.questions[0];
if (auto err = ub_resolve_async( if (auto err = ub_resolve_async(
m_ctx, m_ctx,
@ -486,7 +503,7 @@ namespace llarp::dns
q.qclass, q.qclass,
tmp.get(), tmp.get(),
&Resolver::Callback, &Resolver::Callback,
nullptr)) &tmp->id))
{ {
log::warning( log::warning(
logcat, "failed to send upstream query with libunbound: {}", ub_strerror(err)); logcat, "failed to send upstream query with libunbound: {}", ub_strerror(err));
@ -494,6 +511,7 @@ namespace llarp::dns
} }
else else
{ {
m_Pending.insert(tmp->id);
// Leak the bare pointer we gave to unbound; we'll recapture it in Callback // Leak the bare pointer we gave to unbound; we'll recapture it in Callback
(void)tmp.release(); (void)tmp.release();
} }

@ -10,7 +10,7 @@
namespace llarp::dns namespace llarp::dns
{ {
typedef std::tuple<std::string, uint16_t, uint16_t, uint16_t, std::string> SRVTuple; using SRVTuple = std::tuple<std::string, uint16_t, uint16_t, uint16_t, std::string>;
struct SRVData struct SRVData
{ {
@ -38,19 +38,23 @@ namespace llarp::dns
SRVTuple SRVTuple
toTuple() const; toTuple() const;
auto
toTupleRef() const
{
return std::tie(service_proto, priority, weight, port, target);
}
/// so we can put SRVData in a std::set /// so we can put SRVData in a std::set
bool bool
operator<(const SRVData& other) const operator<(const SRVData& other) const
{ {
return service_proto < other.service_proto or priority < other.priority return toTupleRef() < other.toTupleRef();
or weight < other.weight or port < other.port or target < other.target;
} }
bool bool
operator==(const SRVData& other) const operator==(const SRVData& other) const
{ {
return service_proto == other.service_proto and priority == other.priority return toTupleRef() == other.toTupleRef();
and weight == other.weight and port == other.port and target == other.target;
} }
bool bool

@ -613,7 +613,8 @@ namespace llarp
}); });
} }
std::optional<EndpointBase::SendStat> ExitEndpoint::GetStatFor(AddressVariant_t) const std::optional<EndpointBase::SendStat>
ExitEndpoint::GetStatFor(AddressVariant_t) const
{ {
/// TODO: implement me /// TODO: implement me
return std::nullopt; return std::nullopt;

@ -101,13 +101,14 @@ namespace llarp::handlers
void void
SendPacketToRemote(const llarp_buffer_t&, service::ProtocolType) override{}; SendPacketToRemote(const llarp_buffer_t&, service::ProtocolType) override{};
huint128_t ObtainIPForAddr(std::variant<service::Address, RouterID>) override huint128_t
ObtainIPForAddr(std::variant<service::Address, RouterID>) override
{ {
return {0}; return {0};
} }
std::optional<std::variant<service::Address, RouterID>> ObtainAddrForIP( std::optional<std::variant<service::Address, RouterID>>
huint128_t) const override ObtainAddrForIP(huint128_t) const override
{ {
return std::nullopt; return std::nullopt;
} }

@ -26,7 +26,7 @@ namespace llarp::iwp
, m_Inbound{allowInbound} , m_Inbound{allowInbound}
{} {}
const char* std::string_view
LinkLayer::Name() const LinkLayer::Name() const
{ {
return "iwp"; return "iwp";

@ -35,7 +35,7 @@ namespace llarp::iwp
std::shared_ptr<ILinkSession> std::shared_ptr<ILinkSession>
NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) override; NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) override;
const char* std::string_view
Name() const override; Name() const override;
uint16_t uint16_t

@ -53,11 +53,12 @@ namespace llarp
uint16_t m_ResendPriority; uint16_t m_ResendPriority;
bool bool
operator<(const OutboundMessage& msg) const operator<(const OutboundMessage& other) const
{ {
// yes, the first order is reversed as higher means more important // yes, the first order is reversed as higher means more important
// second part is for queue order // second part is for queue order
return msg.m_ResendPriority < m_ResendPriority or m_MsgID < msg.m_MsgID; int prioA = -m_ResendPriority, prioB = -other.m_ResendPriority;
return std::tie(prioA, m_MsgID) < std::tie(prioB, other.m_MsgID);
} }
ILinkSession::Packet_t ILinkSession::Packet_t

@ -924,13 +924,15 @@ namespace llarp
} }
} }
void Session::HandleCLOS(Packet_t) void
Session::HandleCLOS(Packet_t)
{ {
LogInfo("remote closed by ", m_RemoteAddr); LogInfo("remote closed by ", m_RemoteAddr);
Close(); Close();
} }
void Session::HandlePING(Packet_t) void
Session::HandlePING(Packet_t)
{ {
m_LastRX = m_Parent->Now(); m_LastRX = m_Parent->Now();
} }

@ -249,7 +249,7 @@ namespace llarp
bool bool
ILinkLayer::PickAddress(const RouterContact& rc, llarp::AddressInfo& picked) const ILinkLayer::PickAddress(const RouterContact& rc, llarp::AddressInfo& picked) const
{ {
std::string OurDialect = Name(); auto OurDialect = Name();
for (const auto& addr : rc.addrs) for (const auto& addr : rc.addrs)
{ {
if (addr.dialect == OurDialect) if (addr.dialect == OurDialect)

@ -135,7 +135,7 @@ namespace llarp
virtual void virtual void
Stop(); Stop();
virtual const char* virtual std::string_view
Name() const = 0; Name() const = 0;
util::StatusObject util::StatusObject
@ -179,7 +179,7 @@ namespace llarp
bool bool
IsCompatable(const llarp::RouterContact& other) const IsCompatable(const llarp::RouterContact& other) const
{ {
const std::string us = Name(); const auto us = Name();
for (const auto& ai : other.addrs) for (const auto& ai : other.addrs)
if (ai.dialect == us) if (ai.dialect == us)
return true; return true;
@ -207,7 +207,9 @@ namespace llarp
bool bool
operator<(const ILinkLayer& other) const operator<(const ILinkLayer& other) const
{ {
return Rank() < other.Rank() || Name() < other.Name() || m_ourAddr < other.m_ourAddr; auto rankA = Rank(), rankB = other.Rank();
auto nameA = Name(), nameB = other.Name();
return std::tie(rankA, nameA, m_ourAddr) < std::tie(rankB, nameB, other.m_ourAddr);
} }
/// called by link session to remove a pending session who is timed out /// called by link session to remove a pending session who is timed out

@ -68,7 +68,8 @@ namespace llarp
/// recv packet on low layer /// recv packet on low layer
/// not used by utp /// not used by utp
virtual bool Recv_LL(Packet_t) virtual bool
Recv_LL(Packet_t)
{ {
return true; return true;
} }

@ -23,7 +23,7 @@ namespace llarp
bool bool
operator<(const AddressInfo& lhs, const AddressInfo& rhs) operator<(const AddressInfo& lhs, const AddressInfo& rhs)
{ {
return lhs.rank < rhs.rank || lhs.ip < rhs.ip || lhs.port < rhs.port; return std::tie(lhs.rank, lhs.ip, lhs.port) < std::tie(rhs.rank, rhs.ip, rhs.port);
} }
std::variant<nuint32_t, nuint128_t> std::variant<nuint32_t, nuint128_t>

@ -117,8 +117,8 @@ namespace llarp
bool bool
operator<(const IPRange& other) const operator<(const IPRange& other) const
{ {
return (this->addr & this->netmask_bits) < (other.addr & other.netmask_bits) auto maskedA = addr & netmask_bits, maskedB = other.addr & other.netmask_bits;
|| this->netmask_bits < other.netmask_bits; return std::tie(maskedA, netmask_bits) < std::tie(maskedB, other.netmask_bits);
} }
bool bool

@ -34,62 +34,16 @@
namespace llarp namespace llarp
{ {
inline bool inline int
operator==(const in_addr& a, const in_addr& b) cmp(const in_addr& a, const in_addr& b)
{ {
return memcmp(&a, &b, sizeof(in_addr)) == 0; return memcmp(&a, &b, sizeof(in_addr));
} }
inline bool inline int
operator==(const in6_addr& a, const in6_addr& b) cmp(const in6_addr& a, const in6_addr& b)
{ {
return memcmp(&a, &b, sizeof(in6_addr)) == 0; return memcmp(&a, &b, sizeof(in6_addr));
}
inline bool
operator==(const sockaddr_in& a, const sockaddr_in& b)
{
return a.sin_port == b.sin_port and a.sin_addr.s_addr == b.sin_addr.s_addr;
}
inline bool
operator==(const sockaddr_in6& a, const sockaddr_in6& b)
{
return a.sin6_port == b.sin6_port and a.sin6_addr == b.sin6_addr;
}
inline bool
operator==(const sockaddr& a, const sockaddr& b)
{
if (a.sa_family != b.sa_family)
return false;
switch (a.sa_family)
{
case AF_INET:
return reinterpret_cast<const sockaddr_in&>(a) == reinterpret_cast<const sockaddr_in&>(b);
case AF_INET6:
return reinterpret_cast<const sockaddr_in6&>(a) == reinterpret_cast<const sockaddr_in6&>(b);
default:
return false;
}
}
inline bool
operator<(const in_addr& a, const in_addr& b)
{
return memcmp(&a, &b, sizeof(in_addr)) < 0;
}
inline bool
operator<(const in6_addr& a, const in6_addr& b)
{
return memcmp(&a, &b, sizeof(in6_addr)) < 0;
}
inline bool
operator<(const sockaddr_in6& a, const sockaddr_in6& b)
{
return a.sin6_addr < b.sin6_addr or a.sin6_port < b.sin6_port;
} }
namespace net namespace net
@ -261,3 +215,61 @@ namespace llarp
} // namespace net } // namespace net
} // namespace llarp } // namespace llarp
inline bool
operator==(const in_addr& a, const in_addr& b)
{
return llarp::cmp(a, b) == 0;
}
inline bool
operator==(const in6_addr& a, const in6_addr& b)
{
return llarp::cmp(a, b) == 0;
}
inline bool
operator==(const sockaddr_in& a, const sockaddr_in& b)
{
return a.sin_port == b.sin_port and a.sin_addr.s_addr == b.sin_addr.s_addr;
}
inline bool
operator==(const sockaddr_in6& a, const sockaddr_in6& b)
{
return a.sin6_port == b.sin6_port and a.sin6_addr == b.sin6_addr;
}
inline bool
operator==(const sockaddr& a, const sockaddr& b)
{
if (a.sa_family != b.sa_family)
return false;
switch (a.sa_family)
{
case AF_INET:
return reinterpret_cast<const sockaddr_in&>(a) == reinterpret_cast<const sockaddr_in&>(b);
case AF_INET6:
return reinterpret_cast<const sockaddr_in6&>(a) == reinterpret_cast<const sockaddr_in6&>(b);
default:
return false;
}
}
inline bool
operator<(const in_addr& a, const in_addr& b)
{
return llarp::cmp(a, b) < 0;
}
inline bool
operator<(const in6_addr& a, const in6_addr& b)
{
return llarp::cmp(a, b) < 0;
}
inline bool
operator<(const sockaddr_in6& a, const sockaddr_in6& b)
{
return std::tie(a.sin6_addr, a.sin6_port) < std::tie(b.sin6_addr, b.sin6_port);
}

@ -93,7 +93,8 @@ namespace llarp::net
return IPRange::FindPrivateRange(currentRanges); return IPRange::FindPrivateRange(currentRanges);
} }
std::optional<int> GetInterfaceIndex(ipaddr_t) const override std::optional<int>
GetInterfaceIndex(ipaddr_t) const override
{ {
// todo: implement me // todo: implement me
return std::nullopt; return std::nullopt;

@ -206,15 +206,13 @@ namespace llarp
bool bool
SockAddr::operator<(const SockAddr& other) const SockAddr::operator<(const SockAddr& other) const
{ {
return (m_addr.sin6_addr < other.m_addr.sin6_addr) return m_addr < other.m_addr;
or (m_addr.sin6_port < other.m_addr.sin6_port);
} }
bool bool
SockAddr::operator==(const SockAddr& other) const SockAddr::operator==(const SockAddr& other) const
{ {
return m_addr.sin6_addr == other.m_addr.sin6_addr return m_addr == other.m_addr;
and m_addr.sin6_port == other.m_addr.sin6_port;
} }
huint128_t huint128_t

@ -33,11 +33,7 @@ namespace llarp::net
bool bool
operator<(const ProtocolInfo& other) const operator<(const ProtocolInfo& other) const
{ {
if (port and other.port) return std::tie(protocol, port) < std::tie(other.protocol, other.port);
{
return protocol < other.protocol or *port < *other.port;
}
return protocol < other.protocol;
} }
ProtocolInfo() = default; ProtocolInfo() = default;

@ -141,25 +141,25 @@ namespace llarp
constexpr bool constexpr bool
operator<(const uint128_t& b) const operator<(const uint128_t& b) const
{ {
return upper < b.upper || (upper == b.upper && lower < b.lower); return std::tie(upper, lower) < std::tie(b.upper, b.lower);
} }
constexpr bool constexpr bool
operator<=(const uint128_t& b) const operator<=(const uint128_t& b) const
{ {
return upper < b.upper || (upper == b.upper && lower <= b.lower); return std::tie(upper, lower) <= std::tie(b.upper, b.lower);
} }
constexpr bool constexpr bool
operator>(const uint128_t& b) const operator>(const uint128_t& b) const
{ {
return upper > b.upper || (upper == b.upper && lower > b.lower); return std::tie(upper, lower) > std::tie(b.upper, b.lower);
} }
constexpr bool constexpr bool
operator>=(const uint128_t& b) const operator>=(const uint128_t& b) const
{ {
return upper > b.upper || (upper == b.upper && lower >= b.lower); return std::tie(upper, lower) >= std::tie(b.upper, b.lower);
} }
constexpr uint128_t& constexpr uint128_t&

@ -412,7 +412,8 @@ namespace llarp
return nullptr; return nullptr;
} }
void PathContext::RemovePathSet(PathSet_ptr) void
PathContext::RemovePathSet(PathSet_ptr)
{} {}
} // namespace path } // namespace path
} // namespace llarp } // namespace llarp

@ -335,7 +335,8 @@ namespace llarp
Build(*maybe, roles); Build(*maybe, roles);
} }
bool Builder::UrgentBuild(llarp_time_t) const bool
Builder::UrgentBuild(llarp_time_t) const
{ {
return buildIntervalLimit > MIN_PATH_BUILD_INTERVAL * 4; return buildIntervalLimit > MIN_PATH_BUILD_INTERVAL * 4;
} }

@ -73,7 +73,8 @@ namespace llarp
} }
} }
void PathSet::Tick(llarp_time_t) void
PathSet::Tick(llarp_time_t)
{ {
std::unordered_set<RouterID> endpoints; std::unordered_set<RouterID> endpoints;
for (auto& item : m_Paths) for (auto& item : m_Paths)

@ -210,19 +210,22 @@ namespace llarp
BlacklistSNode(const RouterID) = 0; BlacklistSNode(const RouterID) = 0;
/// override me in subtype /// override me in subtype
virtual bool HandleGotIntroMessage(std::shared_ptr<const dht::GotIntroMessage>) virtual bool
HandleGotIntroMessage(std::shared_ptr<const dht::GotIntroMessage>)
{ {
return false; return false;
} }
/// override me in subtype /// override me in subtype
virtual bool HandleGotRouterMessage(std::shared_ptr<const dht::GotRouterMessage>) virtual bool
HandleGotRouterMessage(std::shared_ptr<const dht::GotRouterMessage>)
{ {
return false; return false;
} }
/// override me in subtype /// override me in subtype
virtual bool HandleGotNameMessage(std::shared_ptr<const dht::GotNameMessage>) virtual bool
HandleGotNameMessage(std::shared_ptr<const dht::GotNameMessage>)
{ {
return false; return false;
} }

@ -308,7 +308,8 @@ namespace llarp
throw std::logic_error{"Peer stats backend not enabled!"}; throw std::logic_error{"Peer stats backend not enabled!"};
} }
void PeerDb::loadDatabase(std::optional<fs::path>) void
PeerDb::loadDatabase(std::optional<fs::path>)
{} {}
void void
@ -349,7 +350,8 @@ namespace llarp
PeerDb::configure(const RouterConfig&) PeerDb::configure(const RouterConfig&)
{} {}
bool PeerDb::shouldFlush(llarp_time_t) bool
PeerDb::shouldFlush(llarp_time_t)
{ {
return false; return false;
} }

@ -199,14 +199,12 @@ namespace llarp
virtual bool virtual bool
IsServiceNode() const = 0; IsServiceNode() const = 0;
virtual bool /// Called to determine if we're in a bad state (which gets reported to our oxend) that should
IsActiveServiceNode() const = 0; /// prevent uptime proofs from going out to the network (so that the error state gets noticed).
/// Currently this means we require a decent number of peers whenever we are fully staked
/// If we are running as a service node and appear active, i.e. registered and not /// (active or decommed).
/// decommissioned, we should *not* ping core if we know of too few peers, to indicate to core virtual std::optional<std::string>
/// we are not in a good state. OxendErrorState() const = 0;
virtual bool
ShouldPingOxen() const = 0;
virtual bool virtual bool
StartRpcServer() = 0; StartRpcServer() = 0;
@ -315,7 +313,9 @@ namespace llarp
/// set router's service node whitelist /// set router's service node whitelist
virtual void virtual void
SetRouterWhitelist( SetRouterWhitelist(
const std::vector<RouterID>& whitelist, const std::vector<RouterID>& greylist) = 0; const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& unfundedlist) = 0;
virtual std::unordered_set<RouterID> virtual std::unordered_set<RouterID>
GetRouterWhitelist() const = 0; GetRouterWhitelist() const = 0;

@ -34,7 +34,9 @@ namespace llarp
virtual void virtual void
SetRouterWhitelist( SetRouterWhitelist(
const std::vector<RouterID>& whitelist, const std::vector<RouterID>& greylist) = 0; const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& greenlist) = 0;
virtual void virtual void
GetRC(const RouterID& router, RCRequestCallback callback, bool forceLookup = false) = 0; GetRC(const RouterID& router, RCRequestCallback callback, bool forceLookup = false) = 0;
@ -48,6 +50,12 @@ namespace llarp
virtual bool virtual bool
IsGreylisted(const RouterID& remote) const = 0; IsGreylisted(const RouterID& remote) const = 0;
virtual bool
IsGreenlisted(const RouterID& remote) const = 0;
virtual bool
IsRegistered(const RouterID& remote) const = 0;
virtual bool virtual bool
CheckRC(const RouterContact& rc) const = 0; CheckRC(const RouterContact& rc) const = 0;

@ -32,26 +32,28 @@ namespace llarp
whitelistRouters.erase(router); whitelistRouters.erase(router);
} }
static void
loadColourList(std::unordered_set<RouterID>& beigelist, const std::vector<RouterID>& new_beige)
{
beigelist.clear();
beigelist.insert(new_beige.begin(), new_beige.end());
}
void void
RCLookupHandler::SetRouterWhitelist( RCLookupHandler::SetRouterWhitelist(
const std::vector<RouterID>& whitelist, const std::vector<RouterID>& greylist) const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& greenlist)
{ {
if (whitelist.empty()) if (whitelist.empty())
return; return;
util::Lock l(_mutex); util::Lock l(_mutex);
whitelistRouters.clear(); loadColourList(whitelistRouters, whitelist);
greylistRouters.clear(); loadColourList(greylistRouters, greylist);
for (auto& router : whitelist) loadColourList(greenlistRouters, greenlist);
{
whitelistRouters.emplace(router);
}
for (auto& router : greylist)
{
greylistRouters.emplace(router);
}
LogInfo("lokinet service node list now has ", whitelistRouters.size(), " routers"); LogInfo("lokinet service node list now has ", whitelistRouters.size(), " active routers");
} }
bool bool
@ -140,6 +142,21 @@ namespace llarp
return greylistRouters.count(remote); return greylistRouters.count(remote);
} }
bool
RCLookupHandler::IsGreenlisted(const RouterID& remote) const
{
util::Lock lock{_mutex};
return greenlistRouters.count(remote);
}
bool
RCLookupHandler::IsRegistered(const RouterID& remote) const
{
util::Lock lock{_mutex};
return whitelistRouters.count(remote) || greylistRouters.count(remote)
|| greenlistRouters.count(remote);
}
bool bool
RCLookupHandler::PathIsAllowed(const RouterID& remote) const RCLookupHandler::PathIsAllowed(const RouterID& remote) const
{ {

@ -42,8 +42,11 @@ namespace llarp
void void
SetRouterWhitelist( SetRouterWhitelist(
const std::vector<RouterID>& whitelist, const std::vector<RouterID>& greylist) override const std::vector<RouterID>& whitelist,
EXCLUDES(_mutex); const std::vector<RouterID>& greylist,
const std::vector<RouterID>& greenlist
) override EXCLUDES(_mutex);
bool bool
HaveReceivedWhitelist() const override; HaveReceivedWhitelist() const override;
@ -61,6 +64,16 @@ namespace llarp
bool bool
IsGreylisted(const RouterID& remote) const override EXCLUDES(_mutex); IsGreylisted(const RouterID& remote) const override EXCLUDES(_mutex);
// "greenlist" = new routers (i.e. "green") that aren't fully funded yet
bool
IsGreenlisted(const RouterID& remote) const override EXCLUDES(_mutex);
// registered just means that there is at least an operator stake, but doesn't require the node
// be fully funded, active, or not decommed. (In other words: it is any of the white, grey, or
// green list).
bool
IsRegistered(const RouterID& remote) const override EXCLUDES(_mutex);
bool bool
CheckRC(const RouterContact& rc) const override; CheckRC(const RouterContact& rc) const override;
@ -134,8 +147,12 @@ namespace llarp
bool useWhitelist = false; bool useWhitelist = false;
bool isServiceNode = false; bool isServiceNode = false;
// whitelist = active routers
std::unordered_set<RouterID> whitelistRouters GUARDED_BY(_mutex); std::unordered_set<RouterID> whitelistRouters GUARDED_BY(_mutex);
// greylist = fully funded, but decommissioned routers
std::unordered_set<RouterID> greylistRouters GUARDED_BY(_mutex); std::unordered_set<RouterID> greylistRouters GUARDED_BY(_mutex);
// greenlist = registered but not fully-staked routers
std::unordered_set<RouterID> greenlistRouters GUARDED_BY(_mutex);
using TimePoint = std::chrono::steady_clock::time_point; using TimePoint = std::chrono::steady_clock::time_point;
std::unordered_map<RouterID, TimePoint> _routerLookupTimes; std::unordered_map<RouterID, TimePoint> _routerLookupTimes;

@ -147,13 +147,16 @@ namespace llarp
auto& route = platform->RouteManager(); auto& route = platform->RouteManager();
// find current gateways // get current gateways, assume sorted by lowest metric first
auto gateways = route.GetGatewaysNotOnInterface(*vpn); auto gateways = route.GetGatewaysNotOnInterface(*vpn);
std::optional<net::ipv4addr_t> next_gw; std::optional<net::ipv4addr_t> next_gw;
for (auto& gateway : gateways) for (auto& gateway : gateways)
{ {
if (auto* gw_ptr = std::get_if<net::ipv4addr_t>(&gateway)) if (auto* gw_ptr = std::get_if<net::ipv4addr_t>(&gateway))
{
next_gw = *gw_ptr; next_gw = *gw_ptr;
break;
}
} }
// update current gateway and apply state changes as needed // update current gateway and apply state changes as needed

@ -395,6 +395,31 @@ namespace llarp
{ {
m_Config = std::move(c); m_Config = std::move(c);
auto& conf = *m_Config; auto& conf = *m_Config;
// Do logging config as early as possible to get the configured log level applied
// Backwards compat: before 0.9.10 we used `type=file` with `file=|-|stdout` for print mode
auto log_type = conf.logging.m_logType;
if (log_type == log::Type::File
&& (conf.logging.m_logFile == "stdout" || conf.logging.m_logFile == "-"
|| conf.logging.m_logFile.empty()))
log_type = log::Type::Print;
if (log::get_level_default() != log::Level::off)
log::reset_level(conf.logging.m_logLevel);
log::clear_sinks();
log::add_sink(log_type, conf.logging.m_logFile);
enableRPCServer = conf.api.m_enableRPCServer;
// re-add rpc log sink if rpc enabled, else free it
if (enableRPCServer and llarp::logRingBuffer)
log::add_sink(llarp::logRingBuffer, llarp::log::DEFAULT_PATTERN_MONO);
else
llarp::logRingBuffer = nullptr;
log::debug(logcat, "Configuring router");
whitelistRouters = conf.lokid.whitelistRouters; whitelistRouters = conf.lokid.whitelistRouters;
if (whitelistRouters) if (whitelistRouters)
{ {
@ -402,33 +427,39 @@ namespace llarp
m_lokidRpcClient = std::make_shared<rpc::LokidRpcClient>(m_lmq, weak_from_this()); m_lokidRpcClient = std::make_shared<rpc::LokidRpcClient>(m_lmq, weak_from_this());
} }
enableRPCServer = conf.api.m_enableRPCServer;
if (enableRPCServer) if (enableRPCServer)
rpcBindAddr = oxenmq::address(conf.api.m_rpcBindAddr); rpcBindAddr = oxenmq::address(conf.api.m_rpcBindAddr);
log::debug(logcat, "Starting RPC server");
if (not StartRpcServer()) if (not StartRpcServer())
throw std::runtime_error("Failed to start rpc server"); throw std::runtime_error("Failed to start rpc server");
if (conf.router.m_workerThreads > 0) if (conf.router.m_workerThreads > 0)
m_lmq->set_general_threads(conf.router.m_workerThreads); m_lmq->set_general_threads(conf.router.m_workerThreads);
log::debug(logcat, "Starting OMQ server");
m_lmq->start(); m_lmq->start();
_nodedb = std::move(nodedb); _nodedb = std::move(nodedb);
m_isServiceNode = conf.router.m_isRelay; m_isServiceNode = conf.router.m_isRelay;
log::debug(
logcat, m_isServiceNode ? "Running as a relay (service node)" : "Running as a client");
if (whitelistRouters) if (whitelistRouters)
{ {
m_lokidRpcClient->ConnectAsync(lokidRPCAddr); m_lokidRpcClient->ConnectAsync(lokidRPCAddr);
} }
// fetch keys log::debug(logcat, "Initializing key manager");
if (not m_keyManager->initialize(conf, true, isSNode)) if (not m_keyManager->initialize(conf, true, isSNode))
throw std::runtime_error("KeyManager failed to initialize"); throw std::runtime_error("KeyManager failed to initialize");
log::debug(logcat, "Initializing from configuration");
if (!FromConfig(conf)) if (!FromConfig(conf))
throw std::runtime_error("FromConfig() failed"); throw std::runtime_error("FromConfig() failed");
log::debug(logcat, "Initializing identity");
if (not EnsureIdentity()) if (not EnsureIdentity())
throw std::runtime_error("EnsureIdentity() failed"); throw std::runtime_error("EnsureIdentity() failed");
return true; return true;
@ -471,16 +502,14 @@ namespace llarp
return nodedb()->NumLoaded() < KnownPeerWarningThreshold; return nodedb()->NumLoaded() < KnownPeerWarningThreshold;
} }
bool std::optional<std::string>
Router::IsActiveServiceNode() const Router::OxendErrorState() const
{
return IsServiceNode() and not(LooksDeregistered() or LooksDecommissioned());
}
bool
Router::ShouldPingOxen() const
{ {
return IsActiveServiceNode() and not TooFewPeers(); // If we're in the white or gray list then we *should* be establishing connections to other
// routers, so if we have almost no peers then something is almost certainly wrong.
if (LooksFunded() and TooFewPeers())
return "too few peer connections; lokinet is not adequately connected to the network";
return std::nullopt;
} }
void void
@ -508,10 +537,17 @@ namespace llarp
} }
bool bool
Router::LooksDeregistered() const Router::LooksFunded() const
{
return IsServiceNode() and whitelistRouters and _rcLookupHandler.HaveReceivedWhitelist()
and _rcLookupHandler.SessionIsAllowed(pubkey());
}
bool
Router::LooksRegistered() const
{ {
return IsServiceNode() and whitelistRouters and _rcLookupHandler.HaveReceivedWhitelist() return IsServiceNode() and whitelistRouters and _rcLookupHandler.HaveReceivedWhitelist()
and not _rcLookupHandler.SessionIsAllowed(pubkey()); and _rcLookupHandler.IsRegistered(pubkey());
} }
bool bool
@ -596,6 +632,7 @@ namespace llarp
Router::FromConfig(const Config& conf) Router::FromConfig(const Config& conf)
{ {
// Set netid before anything else // Set netid before anything else
log::debug(logcat, "Network ID set to {}", conf.router.m_netId);
if (!conf.router.m_netId.empty() && strcmp(conf.router.m_netId.c_str(), llarp::DEFAULT_NETID)) if (!conf.router.m_netId.empty() && strcmp(conf.router.m_netId.c_str(), llarp::DEFAULT_NETID))
{ {
const auto& netid = conf.router.m_netId; const auto& netid = conf.router.m_netId;
@ -635,28 +672,27 @@ namespace llarp
_ourAddress->setPort(*maybe_port); _ourAddress->setPort(*maybe_port);
else else
throw std::runtime_error{"public ip provided without public port"}; throw std::runtime_error{"public ip provided without public port"};
log::debug(logcat, "Using {} for our public address", *_ourAddress);
} }
else
log::debug(logcat, "No explicit public address given; will auto-detect during link setup");
RouterContact::BlockBogons = conf.router.m_blockBogons; RouterContact::BlockBogons = conf.router.m_blockBogons;
// Lokid Config
whitelistRouters = conf.lokid.whitelistRouters;
lokidRPCAddr = oxenmq::address(conf.lokid.lokidRPCAddr);
m_isServiceNode = conf.router.m_isRelay;
auto& networkConfig = conf.network; auto& networkConfig = conf.network;
/// build a set of strictConnectPubkeys ( /// build a set of strictConnectPubkeys (
/// TODO: make this consistent with config -- do we support multiple strict connections
// or not?
std::unordered_set<RouterID> strictConnectPubkeys; std::unordered_set<RouterID> strictConnectPubkeys;
if (not networkConfig.m_strictConnect.empty()) if (not networkConfig.m_strictConnect.empty())
{ {
const auto& val = networkConfig.m_strictConnect; const auto& val = networkConfig.m_strictConnect;
if (IsServiceNode()) if (IsServiceNode())
throw std::runtime_error("cannot use strict-connect option as service node"); throw std::runtime_error("cannot use strict-connect option as service node");
if (val.size() < 2)
throw std::runtime_error(
"Must specify more than one strict-connect router if using strict-connect");
strictConnectPubkeys.insert(val.begin(), val.end()); strictConnectPubkeys.insert(val.begin(), val.end());
log::debug(logcat, "{} strict-connect routers configured", val.size());
} }
std::vector<fs::path> configRouters = conf.connect.routers; std::vector<fs::path> configRouters = conf.connect.routers;
@ -675,58 +711,51 @@ namespace llarp
} }
} }
BootstrapList b_list; bootstrapRCList.clear();
for (const auto& router : configRouters) for (const auto& router : configRouters)
{ {
b_list.AddFromFile(router); log::debug(logcat, "Loading bootstrap router list from {}", defaultBootstrapFile);
bootstrapRCList.AddFromFile(router);
} }
for (const auto& rc : conf.bootstrap.routers) for (const auto& rc : conf.bootstrap.routers)
{ {
b_list.emplace(rc); bootstrapRCList.emplace(rc);
} }
// in case someone has an old bootstrap file and is trying to use a bootstrap // in case someone has an old bootstrap file and is trying to use a bootstrap
// that no longer exists // that no longer exists
for (auto rc_itr = b_list.begin(); rc_itr != b_list.end();) auto clearBadRCs = [this]() {
{ for (auto it = bootstrapRCList.begin(); it != bootstrapRCList.end();)
if (rc_itr->IsObsoleteBootstrap())
b_list.erase(rc_itr);
else
rc_itr++;
}
auto verifyRCs = [&]() {
for (auto& rc : b_list)
{ {
if (rc.IsObsoleteBootstrap()) if (it->IsObsoleteBootstrap())
{ log::warning(logcat, "ignoring obsolete boostrap RC: {}", RouterID{it->pubkey});
log::warning(logcat, "ignoring obsolete boostrap RC: {}", RouterID(rc.pubkey)); else if (not it->Verify(Now()))
continue; log::warning(logcat, "ignoring invalid bootstrap RC: {}", RouterID{it->pubkey});
} else
if (not rc.Verify(Now()))
{ {
log::warning(logcat, "ignoring invalid RC: {}", RouterID(rc.pubkey)); ++it;
continue; continue;
} }
bootstrapRCList.emplace(std::move(rc)); // we are in one of the above error cases that we warned about:
it = bootstrapRCList.erase(it);
} }
}; };
verifyRCs(); clearBadRCs();
if (bootstrapRCList.empty() and not conf.bootstrap.seednode) if (bootstrapRCList.empty() and not conf.bootstrap.seednode)
{ {
auto fallbacks = llarp::load_bootstrap_fallbacks(); auto fallbacks = llarp::load_bootstrap_fallbacks();
if (auto itr = fallbacks.find(_rc.netID.ToString()); itr != fallbacks.end()) if (auto itr = fallbacks.find(_rc.netID.ToString()); itr != fallbacks.end())
{ {
b_list = itr->second; bootstrapRCList = itr->second;
log::debug(logcat, "loaded {} default fallback bootstrap routers", bootstrapRCList.size());
verifyRCs(); clearBadRCs();
} }
if (bootstrapRCList.empty() if (bootstrapRCList.empty() and not conf.bootstrap.seednode)
and not conf.bootstrap.seednode) // empty after trying fallback, if set
{ {
// empty after trying fallback, if set
log::error( log::error(
logcat, logcat,
"No bootstrap routers were loaded. The default bootstrap file {} does not exist, and " "No bootstrap routers were loaded. The default bootstrap file {} does not exist, and "
@ -797,26 +826,6 @@ namespace llarp
hiddenServiceContext().AddEndpoint(conf); hiddenServiceContext().AddEndpoint(conf);
} }
// Logging config
// Backwards compat: before 0.9.10 we used `type=file` with `file=|-|stdout` for print mode
auto log_type = conf.logging.m_logType;
if (log_type == log::Type::File
&& (conf.logging.m_logFile == "stdout" || conf.logging.m_logFile == "-"
|| conf.logging.m_logFile.empty()))
log_type = log::Type::Print;
if (log::get_level_default() != log::Level::off)
log::reset_level(conf.logging.m_logLevel);
log::clear_sinks();
log::add_sink(log_type, conf.logging.m_logFile);
// re-add rpc log sink if rpc enabled, else free it
if (enableRPCServer and llarp::logRingBuffer)
log::add_sink(llarp::logRingBuffer, llarp::log::DEFAULT_PATTERN_MONO);
else
llarp::logRingBuffer = nullptr;
return true; return true;
} }
@ -973,7 +982,7 @@ namespace llarp
// don't purge bootstrap nodes from nodedb // don't purge bootstrap nodes from nodedb
if (IsBootstrapNode(rc.pubkey)) if (IsBootstrapNode(rc.pubkey))
{ {
log::debug(logcat, "Not removing {}: is bootstrap node", rc.pubkey); log::trace(logcat, "Not removing {}: is bootstrap node", rc.pubkey);
return false; return false;
} }
// if for some reason we stored an RC that isn't a valid router // if for some reason we stored an RC that isn't a valid router
@ -1058,18 +1067,22 @@ namespace llarp
connectToNum = strictConnect; connectToNum = strictConnect;
} }
if (now >= m_NextDecommissionWarn) if (isSvcNode and now >= m_NextDecommissionWarn)
{ {
constexpr auto DecommissionWarnInterval = 5min; constexpr auto DecommissionWarnInterval = 5min;
if (auto dereg = LooksDeregistered(); dereg or decom) if (auto registered = LooksRegistered(), funded = LooksFunded();
not(registered and funded and not decom))
{ {
// complain about being deregistered // complain about being deregistered/decommed/unfunded
LogError( log::error(
"We are running as a service node but we seem to be ", logcat,
dereg ? "deregistered" : "decommissioned"); "We are running as a service node but we seem to be {}",
not registered ? "deregistered"
: decom ? "decommissioned"
: "not fully staked");
m_NextDecommissionWarn = now + DecommissionWarnInterval; m_NextDecommissionWarn = now + DecommissionWarnInterval;
} }
else if (isSvcNode and TooFewPeers()) else if (TooFewPeers())
{ {
log::error( log::error(
logcat, logcat,
@ -1079,9 +1092,9 @@ namespace llarp
} }
} }
// if we need more sessions to routers and we are not a service node kicked from the network // if we need more sessions to routers and we are not a service node kicked from the network or
// we shall connect out to others // we are a client we shall connect out to others
if (connected < connectToNum and not LooksDeregistered()) if (connected < connectToNum and (LooksFunded() or not isSvcNode))
{ {
size_t dlt = connectToNum - connected; size_t dlt = connectToNum - connected;
LogDebug("connecting to ", dlt, " random routers to keep alive"); LogDebug("connecting to ", dlt, " random routers to keep alive");
@ -1233,9 +1246,11 @@ namespace llarp
void void
Router::SetRouterWhitelist( Router::SetRouterWhitelist(
const std::vector<RouterID>& whitelist, const std::vector<RouterID>& greylist) const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& unfundedlist)
{ {
_rcLookupHandler.SetRouterWhitelist(whitelist, greylist); _rcLookupHandler.SetRouterWhitelist(whitelist, greylist, unfundedlist);
} }
bool bool

@ -143,7 +143,9 @@ namespace llarp
void void
SetRouterWhitelist( SetRouterWhitelist(
const std::vector<RouterID>& whitelist, const std::vector<RouterID>& greylist) override; const std::vector<RouterID>& whitelist,
const std::vector<RouterID>& greylist,
const std::vector<RouterID>& unfunded) override;
std::unordered_set<RouterID> std::unordered_set<RouterID>
GetRouterWhitelist() const override GetRouterWhitelist() const override
@ -203,9 +205,16 @@ namespace llarp
bool bool
LooksDecommissioned() const; LooksDecommissioned() const;
/// return true if we look like we are a deregistered service node /// return true if we look like we are a registered, fully-staked service node (either active or
/// decommissioned). This condition determines when we are allowed to (and attempt to) connect
/// to other peers when running as a service node.
bool bool
LooksDeregistered() const; LooksFunded() const;
/// return true if we a registered service node; not that this only requires a partial stake,
/// and does not imply that this service node is *active* or fully funded.
bool
LooksRegistered() const;
/// return true if we look like we are allowed and able to test other routers /// return true if we look like we are allowed and able to test other routers
bool bool
@ -378,12 +387,8 @@ namespace llarp
bool bool
IsServiceNode() const override; IsServiceNode() const override;
/// return true if service node *and* not deregistered or decommissioned std::optional<std::string>
bool OxendErrorState() const override;
IsActiveServiceNode() const override;
bool
ShouldPingOxen() const override;
void void
Close(); Close();
@ -556,8 +561,11 @@ namespace llarp
bool m_isServiceNode = false; bool m_isServiceNode = false;
// Delay warning about being decommed/dereged until we've had enough time to sync up with oxend
static constexpr auto DECOMM_WARNING_STARTUP_DELAY = 15s;
llarp_time_t m_LastStatsReport = 0s; llarp_time_t m_LastStatsReport = 0s;
llarp_time_t m_NextDecommissionWarn = 0s; llarp_time_t m_NextDecommissionWarn = time_now_ms() + DECOMM_WARNING_STARTUP_DELAY;
std::shared_ptr<llarp::KeyManager> m_keyManager; std::shared_ptr<llarp::KeyManager> m_keyManager;
std::shared_ptr<PeerDb> m_peerDb; std::shared_ptr<PeerDb> m_peerDb;

@ -41,7 +41,7 @@ namespace llarp
bool bool
operator<(const RouterVersion& other) const operator<(const RouterVersion& other) const
{ {
return m_ProtoVersion < other.m_ProtoVersion || m_Version < other.m_Version; return std::tie(m_ProtoVersion, m_Version) < std::tie(other.m_ProtoVersion, other.m_Version);
} }
bool bool

@ -112,35 +112,57 @@ namespace llarp
void void
LokidRpcClient::UpdateServiceNodeList() LokidRpcClient::UpdateServiceNodeList()
{ {
nlohmann::json request, fields; if (m_UpdatingList.exchange(true))
fields["pubkey_ed25519"] = true; return; // update already in progress
fields["service_node_pubkey"] = true;
fields["funded"] = true; nlohmann::json request{
fields["active"] = true; {"fields",
request["fields"] = fields; {
m_UpdatingList = true; {"pubkey_ed25519", true},
{"service_node_pubkey", true},
{"funded", true},
{"active", true},
{"block_hash", true},
}},
};
if (!m_LastUpdateHash.empty())
request["fields"]["poll_block_hash"] = m_LastUpdateHash;
Request( Request(
"rpc.get_service_nodes", "rpc.get_service_nodes",
[self = shared_from_this()](bool success, std::vector<std::string> data) { [self = shared_from_this()](bool success, std::vector<std::string> data) {
self->m_UpdatingList = false;
if (not success) if (not success)
{
LogWarn("failed to update service node list"); LogWarn("failed to update service node list");
return; else if (data.size() < 2)
} LogWarn("oxend gave empty reply for service node list");
if (data.size() < 2) else
{
LogWarn("lokid gave empty reply for service node list");
return;
}
try
{ {
self->HandleGotServiceNodeList(std::move(data[1])); try
} {
catch (std::exception& ex) auto json = nlohmann::json::parse(std::move(data[1]));
{ if (json.at("status") != "OK")
LogError("failed to process service node list: ", ex.what()); throw std::runtime_error{"get_service_nodes did not return 'OK' status"};
if (auto it = json.find("unchanged");
it != json.end() and it->is_boolean() and it->get<bool>())
LogDebug("service node list unchanged");
else
{
self->HandleNewServiceNodeList(json.at("service_node_states"));
if (auto it = json.find("block_hash"); it != json.end() and it->is_string())
self->m_LastUpdateHash = it->get<std::string>();
else
self->m_LastUpdateHash.clear();
}
}
catch (const std::exception& ex)
{
LogError("failed to process service node list: ", ex.what());
}
} }
// set down here so that the 1) we don't start updating until we're completely finished
// with the previous update; and 2) so that m_UpdatingList also guards m_LastUpdateHash
self->m_UpdatingList = false;
}, },
request.dump()); request.dump());
} }
@ -152,25 +174,27 @@ namespace llarp
auto makePingRequest = [self = shared_from_this()]() { auto makePingRequest = [self = shared_from_this()]() {
// send a ping // send a ping
PubKey pk{}; PubKey pk{};
bool should_ping = false; auto r = self->m_Router.lock();
if (auto r = self->m_Router.lock()) if (not r)
{ return; // router has gone away, maybe shutting down?
pk = r->pubkey();
should_ping = r->ShouldPingOxen(); pk = r->pubkey();
}
if (should_ping) nlohmann::json payload = {
{ {"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())},
nlohmann::json payload = { {"version", {VERSION[0], VERSION[1], VERSION[2]}}};
{"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())},
{"version", {VERSION[0], VERSION[1], VERSION[2]}}}; if (auto err = r->OxendErrorState())
self->Request( payload["error"] = *err;
"admin.lokinet_ping",
[](bool success, std::vector<std::string> data) { self->Request(
(void)data; "admin.lokinet_ping",
LogDebug("Received response for ping. Successful: ", success); [](bool success, std::vector<std::string> data) {
}, (void)data;
payload.dump()); LogDebug("Received response for ping. Successful: ", success);
} },
payload.dump());
// subscribe to block updates // subscribe to block updates
self->Request("sub.block", [](bool success, std::vector<std::string> data) { self->Request("sub.block", [](bool success, std::vector<std::string> data) {
if (data.empty() or not success) if (data.empty() or not success)
@ -180,52 +204,53 @@ namespace llarp
} }
LogDebug("subscribed to new blocks: ", data[0]); LogDebug("subscribed to new blocks: ", data[0]);
}); });
// Trigger an update on a regular timer as well in case we missed a block notify for some
// reason (e.g. oxend restarts and loses the subscription); we poll using the last known
// hash so that the poll is very cheap (basically empty) if the block hasn't advanced.
self->UpdateServiceNodeList();
}; };
// Fire one ping off right away to get things going.
makePingRequest();
m_lokiMQ->add_timer(makePingRequest, PingInterval); m_lokiMQ->add_timer(makePingRequest, PingInterval);
// initial fetch of service node list
UpdateServiceNodeList();
} }
void void
LokidRpcClient::HandleGotServiceNodeList(std::string data) LokidRpcClient::HandleNewServiceNodeList(const nlohmann::json& j)
{ {
auto j = nlohmann::json::parse(std::move(data));
if (const auto itr = j.find("unchanged"); itr != j.end() and itr->get<bool>())
{
LogDebug("service node list unchanged");
return;
}
std::unordered_map<RouterID, PubKey> keymap; std::unordered_map<RouterID, PubKey> keymap;
std::vector<RouterID> activeNodeList, nonActiveNodeList; std::vector<RouterID> activeNodeList, decommNodeList, unfundedNodeList;
if (const auto itr = j.find("service_node_states"); itr != j.end() and itr->is_array()) if (not j.is_array())
throw std::runtime_error{
"Invalid service node list: expected array of service node states"};
for (auto& snode : j)
{ {
for (auto& snode : *itr) const auto ed_itr = snode.find("pubkey_ed25519");
{ if (ed_itr == snode.end() or not ed_itr->is_string())
// Skip unstaked snodes: continue;
if (const auto funded_itr = snode.find("funded"); funded_itr == snode.end() const auto svc_itr = snode.find("service_node_pubkey");
or not funded_itr->is_boolean() or not funded_itr->get<bool>()) if (svc_itr == snode.end() or not svc_itr->is_string())
continue; continue;
const auto active_itr = snode.find("active");
const auto ed_itr = snode.find("pubkey_ed25519"); if (active_itr == snode.end() or not active_itr->is_boolean())
if (ed_itr == snode.end() or not ed_itr->is_string()) continue;
continue; const bool active = active_itr->get<bool>();
const auto svc_itr = snode.find("service_node_pubkey"); const auto funded_itr = snode.find("funded");
if (svc_itr == snode.end() or not svc_itr->is_string()) if (funded_itr == snode.end() or not funded_itr->is_boolean())
continue; continue;
const auto active_itr = snode.find("active"); const bool funded = funded_itr->get<bool>();
if (active_itr == snode.end() or not active_itr->is_boolean())
continue; RouterID rid;
const bool active = active_itr->get<bool>(); PubKey pk;
if (not rid.FromHex(ed_itr->get<std::string_view>())
RouterID rid; or not pk.FromHex(svc_itr->get<std::string_view>()))
PubKey pk; continue;
if (not rid.FromHex(ed_itr->get<std::string_view>())
or not pk.FromHex(svc_itr->get<std::string_view>())) keymap[rid] = pk;
continue; (active ? activeNodeList
: funded ? decommNodeList
keymap[rid] = pk; : unfundedNodeList)
(active ? activeNodeList : nonActiveNodeList).push_back(std::move(rid)); .push_back(std::move(rid));
}
} }
if (activeNodeList.empty()) if (activeNodeList.empty())
@ -233,17 +258,19 @@ namespace llarp
LogWarn("got empty service node list, ignoring."); LogWarn("got empty service node list, ignoring.");
return; return;
} }
// inform router about the new list // inform router about the new list
if (auto router = m_Router.lock()) if (auto router = m_Router.lock())
{ {
auto& loop = router->loop(); auto& loop = router->loop();
loop->call([this, loop->call([this,
active = std::move(activeNodeList), active = std::move(activeNodeList),
inactive = std::move(nonActiveNodeList), decomm = std::move(decommNodeList),
unfunded = std::move(unfundedNodeList),
keymap = std::move(keymap), keymap = std::move(keymap),
router = std::move(router)]() mutable { router = std::move(router)]() mutable {
m_KeyMap = std::move(keymap); m_KeyMap = std::move(keymap);
router->SetRouterWhitelist(active, inactive); router->SetRouterWhitelist(active, decomm, unfunded);
}); });
} }
else else

@ -55,6 +55,8 @@ namespace llarp
void void
Command(std::string_view cmd); Command(std::string_view cmd);
/// triggers a service node list refresh from oxend; thread-safe and will do nothing if an
/// update is already in progress.
void void
UpdateServiceNodeList(); UpdateServiceNodeList();
@ -72,8 +74,10 @@ namespace llarp
m_lokiMQ->request(*m_Connection, std::move(cmd), std::move(func)); m_lokiMQ->request(*m_Connection, std::move(cmd), std::move(func));
} }
// Handles a service node list update; takes the "service_node_states" object of an oxend
// "get_service_nodes" rpc request.
void void
HandleGotServiceNodeList(std::string json); HandleNewServiceNodeList(const nlohmann::json& json);
// Handles request from lokid for peer stats on a specific peer // Handles request from lokid for peer stats on a specific peer
void void
@ -88,6 +92,7 @@ namespace llarp
std::weak_ptr<AbstractRouter> m_Router; std::weak_ptr<AbstractRouter> m_Router;
std::atomic<bool> m_UpdatingList; std::atomic<bool> m_UpdatingList;
std::string m_LastUpdateHash;
std::unordered_map<RouterID, PubKey> m_KeyMap; std::unordered_map<RouterID, PubKey> m_KeyMap;

@ -40,6 +40,11 @@
#include <uvw.hpp> #include <uvw.hpp>
#include <variant> #include <variant>
namespace
{
constexpr size_t MIN_ENDPOINTS_FOR_LNS_LOOKUP = 2;
} // namespace
namespace llarp namespace llarp
{ {
namespace service namespace service
@ -309,6 +314,7 @@ namespace llarp
auto obj = path::Builder::ExtractStatus(); auto obj = path::Builder::ExtractStatus();
obj["exitMap"] = m_ExitMap.ExtractStatus(); obj["exitMap"] = m_ExitMap.ExtractStatus();
obj["identity"] = m_Identity.pub.Addr().ToString(); obj["identity"] = m_Identity.pub.Addr().ToString();
obj["networkReady"] = ReadyToDoLookup();
util::StatusObject authCodes; util::StatusObject authCodes;
for (const auto& [service, info] : m_RemoteAuthInfos) for (const auto& [service, info] : m_RemoteAuthInfos)
@ -320,7 +326,8 @@ namespace llarp
return m_state->ExtractStatus(obj); return m_state->ExtractStatus(obj);
} }
void Endpoint::Tick(llarp_time_t) void
Endpoint::Tick(llarp_time_t)
{ {
const auto now = llarp::time_now_ms(); const auto now = llarp::time_now_ms();
path::Builder::Tick(now); path::Builder::Tick(now);
@ -945,6 +952,22 @@ namespace llarp
return not m_ExitMap.Empty(); return not m_ExitMap.Empty();
} }
bool
Endpoint::ReadyToDoLookup(std::optional<uint64_t> numPaths) const
{
if (not numPaths)
{
path::Path::UniqueEndpointSet_t paths;
ForEachPath([&paths](auto path) {
if (path and path->IsReady())
paths.insert(path);
});
numPaths = paths.size();
}
return numPaths >= MIN_ENDPOINTS_FOR_LNS_LOOKUP;
}
void void
Endpoint::LookupNameAsync( Endpoint::LookupNameAsync(
std::string name, std::string name,
@ -964,23 +987,20 @@ namespace llarp
} }
LogInfo(Name(), " looking up LNS name: ", name); LogInfo(Name(), " looking up LNS name: ", name);
path::Path::UniqueEndpointSet_t paths; path::Path::UniqueEndpointSet_t paths;
ForEachPath([&](auto path) { ForEachPath([&paths](auto path) {
if (path and path->IsReady()) if (path and path->IsReady())
paths.insert(path); paths.insert(path);
}); });
constexpr size_t min_unique_lns_endpoints = 2;
constexpr size_t max_unique_lns_endpoints = 7;
// not enough paths // not enough paths
if (paths.size() < min_unique_lns_endpoints) if (not ReadyToDoLookup(paths.size()))
{ {
LogWarn( LogWarn(
Name(), Name(),
" not enough paths for lns lookup, have ", " not enough paths for lns lookup, have ",
paths.size(), paths.size(),
" need ", " need ",
min_unique_lns_endpoints); MIN_ENDPOINTS_FOR_LNS_LOOKUP);
handler(std::nullopt); handler(std::nullopt);
return; return;
} }
@ -1005,11 +1025,12 @@ namespace llarp
handler(result); handler(result);
}; };
constexpr size_t max_lns_lookup_endpoints = 7;
// pick up to max_unique_lns_endpoints random paths to do lookups from // pick up to max_unique_lns_endpoints random paths to do lookups from
std::vector<path::Path_ptr> chosenpaths; std::vector<path::Path_ptr> chosenpaths;
chosenpaths.insert(chosenpaths.begin(), paths.begin(), paths.end()); chosenpaths.insert(chosenpaths.begin(), paths.begin(), paths.end());
std::shuffle(chosenpaths.begin(), chosenpaths.end(), CSRNG{}); std::shuffle(chosenpaths.begin(), chosenpaths.end(), CSRNG{});
chosenpaths.resize(std::min(paths.size(), max_unique_lns_endpoints)); chosenpaths.resize(std::min(paths.size(), max_lns_lookup_endpoints));
auto resultHandler = auto resultHandler =
m_state->lnsTracker.MakeResultHandler(name, chosenpaths.size(), maybeInvalidateCache); m_state->lnsTracker.MakeResultHandler(name, chosenpaths.size(), maybeInvalidateCache);
@ -1165,7 +1186,8 @@ namespace llarp
return m_Identity.pub.Addr(); return m_Identity.pub.Addr();
} }
std::optional<EndpointBase::SendStat> Endpoint::GetStatFor(AddressVariant_t) const std::optional<EndpointBase::SendStat>
Endpoint::GetStatFor(AddressVariant_t) const
{ {
// TODO: implement me // TODO: implement me
return std::nullopt; return std::nullopt;

@ -521,6 +521,9 @@ namespace llarp
return false; return false;
} }
bool
ReadyToDoLookup(std::optional<uint64_t> numPaths = std::nullopt) const;
protected: protected:
IDataHandler* m_DataHandler = nullptr; IDataHandler* m_DataHandler = nullptr;
Identity m_Identity; Identity m_Identity;

@ -80,7 +80,6 @@ namespace llarp
Clear(); Clear();
std::array<byte_t, 4096> tmp; std::array<byte_t, 4096> tmp;
llarp_buffer_t buf(tmp);
// this can throw // this can throw
bool exists = fs::exists(fname); bool exists = fs::exists(fname);
@ -94,6 +93,7 @@ namespace llarp
// check for file // check for file
if (!exists) if (!exists)
{ {
llarp_buffer_t buf{tmp};
// regen and encode // regen and encode
RegenerateKeys(); RegenerateKeys();
if (!BEncode(&buf)) if (!BEncode(&buf))
@ -108,6 +108,7 @@ namespace llarp
{ {
throw std::runtime_error{fmt::format("failed to write {}: {}", fname, e.what())}; throw std::runtime_error{fmt::format("failed to write {}: {}", fname, e.what())};
} }
return;
} }
if (not fs::is_regular_file(fname)) if (not fs::is_regular_file(fname))
@ -125,10 +126,11 @@ namespace llarp
throw std::length_error{"service identity too big"}; throw std::length_error{"service identity too big"};
} }
// (don't catch io error exceptions) // (don't catch io error exceptions)
{
if (!bencode_decode_dict(*this, &buf)) llarp_buffer_t buf{tmp};
throw std::length_error{"could not decode service identity"}; if (!bencode_decode_dict(*this, &buf))
throw std::length_error{"could not decode service identity"};
}
auto crypto = CryptoManager::instance(); auto crypto = CryptoManager::instance();
// ensure that the encryption key is set // ensure that the encryption key is set

@ -55,8 +55,8 @@ namespace llarp
bool bool
operator<(const Introduction& other) const operator<(const Introduction& other) const
{ {
return expiresAt < other.expiresAt || pathID < other.pathID || router < other.router return std::tie(expiresAt, pathID, router, version, latency)
|| version < other.version || latency < other.latency; < std::tie(other.expiresAt, other.pathID, other.router, other.version, other.latency);
} }
bool bool

@ -35,7 +35,8 @@ namespace llarp
} }
/// handle lookup result for introsets /// handle lookup result for introsets
virtual bool HandleNameResponse(std::optional<Address>) virtual bool
HandleNameResponse(std::optional<Address>)
{ {
return false; return false;
} }
@ -76,7 +77,8 @@ namespace llarp
RouterID endpoint; RouterID endpoint;
/// return true if this lookup is for a remote address /// return true if this lookup is for a remote address
virtual bool IsFor(EndpointBase::AddressVariant_t) const virtual bool
IsFor(EndpointBase::AddressVariant_t) const
{ {
return false; return false;
} }

@ -25,7 +25,7 @@ namespace llarp::vpn
bool bool
operator<(const InterfaceAddress& other) const operator<(const InterfaceAddress& other) const
{ {
return range < other.range or fam < other.fam; return std::tie(range, fam) < std::tie(other.range, other.fam);
} }
}; };

@ -125,7 +125,8 @@ namespace llarp::win32
return -1; return -1;
} }
virtual bool WritePacket(net::IPPacket) override virtual bool
WritePacket(net::IPPacket) override
{ {
return false; return false;
} }

@ -66,13 +66,14 @@ namespace llarp
return false; return false;
} }
llarp::huint128_t ObtainIPForAddr(std::variant<service::Address, RouterID>) override llarp::huint128_t
ObtainIPForAddr(std::variant<service::Address, RouterID>) override
{ {
return {0}; return {0};
} }
std::optional<std::variant<service::Address, RouterID>> ObtainAddrForIP( std::optional<std::variant<service::Address, RouterID>>
huint128_t) const override ObtainAddrForIP(huint128_t) const override
{ {
return std::nullopt; return std::nullopt;
} }

Loading…
Cancel
Save