diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index 62277eaa3..d0b9f7b29 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -11,25 +11,25 @@ set(OPENSSL_SOURCE openssl-${OPENSSL_VERSION}.tar.gz) set(OPENSSL_HASH SHA256=aa7d8d9bef71ad6525c55ba11e5f4397889ce49c2c9349dcea6d3e4f0b024a7a 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}") set(EXPAT_MIRROR ${LOCAL_MIRROR} https://github.com/libexpat/libexpat/releases/download/${EXPAT_TAG} CACHE STRING "expat download mirror(s)") set(EXPAT_SOURCE expat-${EXPAT_VERSION}.tar.xz) -set(EXPAT_HASH SHA256=f79b8f904b749e3e0d20afeadecf8249c55b2e32d4ebb089ae378df479dcaf25 +set(EXPAT_HASH SHA512=8508379b4915d84d50f3638678a90792179c98247d1cb5e6e6387d117af4dc148ac7031c1debea8b96e7b710ef436cf0dd5da91f3d22b8186a00cfafe1201169 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_SOURCE unbound-${UNBOUND_VERSION}.tar.gz) -set(UNBOUND_HASH SHA512=0ea65ea63265be677441bd2a28df12098ec5e86c3372240c2874f9bd13752b8b818da81ae6076cf02cbeba3d36e397698a4c2b50570be1a6a8e47f57a0251572 +set(UNBOUND_HASH SHA512=f6b9f279330fb19b5feca09524959940aad8c4e064528aa82b369c726d77e9e8e5ca23f366f6e9edcf2c061b96f482ed7a2c26ac70fc15ae5762b3d7e36a5284 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 CACHE STRING "sqlite3 download mirror(s)") 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") 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 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} CACHE STRING "libuv mirror(s)") set(LIBUV_SOURCE libuv-v${LIBUV_VERSION}.tar.gz) -set(LIBUV_HASH SHA512=b4f8944e2c79e3a6a31ded6cccbe4c0eeada50db6bc8a448d7015642795012a4b80ffeef7ca455bb093c59a8950d0e1430566c3c2fa87b73f82699098162d834 +set(LIBUV_HASH SHA512=91197ff9303112567bbb915bbb88058050e2ad1c048815a3b57c054635d5dc7df458b956089d785475290132236cb0edcfae830f5d749de29a9a3213eeaf0b20 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 CACHE STRING "zlib mirror(s)") -set(ZLIB_SOURCE zlib-${ZLIB_VERSION}.tar.gz) -set(ZLIB_HASH SHA256=91844808532e5ce316b3c010929493c0244f3d37593afd6de04f71821d5136d9 +set(ZLIB_SOURCE zlib-${ZLIB_VERSION}.tar.xz) +set(ZLIB_HASH SHA256=d14c38e313afc35a9a8760dadf26042f51ea0f5d154b0630a31da0540107fb98 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 CACHE STRING "curl mirror(s)") set(CURL_SOURCE curl-${CURL_VERSION}.tar.xz) -set(CURL_HASH SHA256=2cb9c2356e7263a1272fd1435ef7cdebf2cd21400ec287b068396deb705c22c4 +set(CURL_HASH SHA512=b57cc31649a4f47cc4b482f56a85c86c8e8aaeaf01bc1b51b065fdb9145a9092bc52535e52a85a66432eb163605b2edbf5bc5c33ea6e40e50f26a69ad1365cbd CACHE STRING "curl source hash") include(ExternalProject) @@ -167,6 +167,11 @@ if(APPLE) set(deps_CXXFLAGS "${deps_CXXFLAGS} -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET}") 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") set(_make $(MAKE)) diff --git a/cmake/win32.cmake b/cmake/win32.cmake index ae3bdb6d2..a8f977c28 100644 --- a/cmake/win32.cmake +++ b/cmake/win32.cmake @@ -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 # to .r[o]data section one after the other! 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) link_libatomic() diff --git a/contrib/ci/drone-check-static-libs.sh b/contrib/ci/drone-check-static-libs.sh index 0d919c7ca..b4d8b0b2a 100755 --- a/contrib/ci/drone-check-static-libs.sh +++ b/contrib/ci/drone-check-static-libs.sh @@ -8,7 +8,7 @@ set -o errexit bad= if [ "$DRONE_STAGE_OS" == "darwin" ]; then 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 fi elif [ "$DRONE_STAGE_OS" == "linux" ]; then diff --git a/contrib/ci/drone-format-verify.sh b/contrib/ci/drone-format-verify.sh index 387340018..197b2e2a9 100755 --- a/contrib/ci/drone-format-verify.sh +++ b/contrib/ci/drone-format-verify.sh @@ -1,6 +1,9 @@ #!/usr/bin/env bash test "x$IGNORE" != "x" && exit 0 + +. $(dirname $0)/../format-version.sh + 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 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) diff --git a/contrib/ci/drone-static-upload.sh b/contrib/ci/drone-static-upload.sh index 460d001c2..2f2f7f2ef 100755 --- a/contrib/ci/drone-static-upload.sh +++ b/contrib/ci/drone-static-upload.sh @@ -19,9 +19,15 @@ set -o xtrace # Don't start tracing until *after* we write the ssh key chmod 600 ssh_key -os="${UPLOAD_OS:-$DRONE_STAGE_OS-$DRONE_STAGE_ARCH}" -if [ -n "$WINDOWS_BUILD_NAME" ]; then - os="windows-$WINDOWS_BUILD_NAME" +os="$UPLOAD_OS" +if [ -z "$os" ]; then + 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 if [ -n "$DRONE_TAG" ]; then @@ -55,8 +61,8 @@ elif [ -e build-mac ]; then mv build-mac/Lokinet*/ "$base" tar cJvf "$archive" "$base" else - cp -av daemon/lokinet daemon/lokinet-vpn "$base" - cp -av ../contrib/bootstrap/mainnet.signed "$base/bootstrap.signed" + cp -av build/daemon/lokinet{,-vpn} "$base" + cp -av contrib/bootstrap/mainnet.signed "$base/bootstrap.signed" # tar dat shiz up yo archive="$base.tar.xz" tar cJvf "$archive" "$base" diff --git a/contrib/cross/mingw_core.cmake b/contrib/cross/mingw_core.cmake index a42673eda..8086ab7f3 100644 --- a/contrib/cross/mingw_core.cmake +++ b/contrib/cross/mingw_core.cmake @@ -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 # second one is for non-root installs diff --git a/contrib/format-version.sh b/contrib/format-version.sh new file mode 100644 index 000000000..d8fe6e855 --- /dev/null +++ b/contrib/format-version.sh @@ -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 diff --git a/contrib/format.sh b/contrib/format.sh index a51fbaa9a..d757554e0 100755 --- a/contrib/format.sh +++ b/contrib/format.sh @@ -1,31 +1,15 @@ #!/usr/bin/env bash -CLANG_FORMAT_DESIRED_VERSION=11 - -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 +. $(dirname $0)/format-version.sh cd "$(dirname $0)/../" + if [ "$1" = "verify" ] ; then - if [ $($binary --output-replacements-xml $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') | grep '' | 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 '' | wc -l) -ne 0 ] ; then exit 2 fi 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 swift_format=$(command -v swiftformat 2>/dev/null) diff --git a/daemon/lokinet.cpp b/daemon/lokinet.cpp index 70c9648f2..af71310a5 100644 --- a/daemon/lokinet.cpp +++ b/daemon/lokinet.cpp @@ -329,9 +329,8 @@ class WindowsServiceStopped LONG GenerateDump(EXCEPTION_POINTERS* pExceptionPointers) { - const auto flags = (MINIDUMP_TYPE)( - MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | MiniDumpWithHandleData - | MiniDumpWithUnloadedModules | MiniDumpWithThreadInfo); + const auto flags = + (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithThreadInfo); std::stringstream ss; ss << "C:\\ProgramData\\lokinet\\crash-" << llarp::time_now_ms().count() << ".dmp"; diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 0e43855c0..d235c1ec2 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -124,4 +124,19 @@ if(WITH_BOOTSTRAP) target_include_directories(cpr PUBLIC cpr/include) target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL) 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() diff --git a/external/cpr b/external/cpr index aac5058a1..f88fd7737 160000 --- a/external/cpr +++ b/external/cpr @@ -1 +1 @@ -Subproject commit aac5058a15e9ad5ad393973dc6fe44d7614a7f55 +Subproject commit f88fd7737de3e640c61703eb57a0fa0ce00c60cd diff --git a/external/cxxopts b/external/cxxopts index 6fa46a748..c74846a89 160000 --- a/external/cxxopts +++ b/external/cxxopts @@ -1 +1 @@ -Subproject commit 6fa46a748838d5544ff8e9ab058906ba2c4bc0f3 +Subproject commit c74846a891b3cc3bfa992d588b1295f528d43039 diff --git a/external/ghc-filesystem b/external/ghc-filesystem index 2a8b380f8..cd6805e94 160000 --- a/external/ghc-filesystem +++ b/external/ghc-filesystem @@ -1 +1 @@ -Subproject commit 2a8b380f8d4e77b389c42a194ab9c70d8e3a0f1e +Subproject commit cd6805e94dd5d6346be1b75a54cdc27787319dd2 diff --git a/external/nlohmann b/external/nlohmann index db78ac1d7..bc889afb4 160000 --- a/external/nlohmann +++ b/external/nlohmann @@ -1 +1 @@ -Subproject commit db78ac1d7716f56fc9f1b030b715f872f93964e4 +Subproject commit bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d diff --git a/external/pybind11 b/external/pybind11 index 8de7772cc..aa304c9c7 160000 --- a/external/pybind11 +++ b/external/pybind11 @@ -1 +1 @@ -Subproject commit 8de7772cc72daca8e947b79b83fea46214931604 +Subproject commit aa304c9c7d725ffb9d10af08a3b34cb372307020 diff --git a/external/sqlite_orm b/external/sqlite_orm index 4c6a46bd4..fdcc1da46 160000 --- a/external/sqlite_orm +++ b/external/sqlite_orm @@ -1 +1 @@ -Subproject commit 4c6a46bd4dcfba14a650e0fafb86331526878587 +Subproject commit fdcc1da46fbd90feb886c0588462a62d29eb5a06 diff --git a/llarp/apple/route_manager.hpp b/llarp/apple/route_manager.hpp index b69904276..69403c04d 100644 --- a/llarp/apple/route_manager.hpp +++ b/llarp/apple/route_manager.hpp @@ -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 /// 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 diff --git a/llarp/config/config.cpp b/llarp/config/config.cpp index d0f9f567e..aa02da5c2 100644 --- a/llarp/config/config.cpp +++ b/llarp/config/config.cpp @@ -300,9 +300,9 @@ namespace llarp throw std::invalid_argument{"duplicate strict connect snode: " + value}; }, 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", - "first hop).", + "first hop). This REQUIRES two or more nodes to be specified.", }); conf.defineOption( @@ -459,9 +459,8 @@ namespace llarp "owned-range", MultiValue, Comment{ - "When in exit mode announce we allow a private range in our introset" - "exmaple:", - "owned-range=10.0.0.0/24", + "When in exit mode announce we allow a private range in our introset. For example:", + " owned-range=10.0.0.0/24", }, [this](std::string arg) { IPRange range; @@ -475,12 +474,17 @@ namespace llarp "traffic-whitelist", MultiValue, Comment{ - "List of ip traffic whitelist, anything not specified will be dropped by us." - "examples:", - "tcp for all tcp traffic regardless of port", - "0x69 for all packets using ip protocol 0x69" - "udp/53 for udp port 53", - "tcp/smtp for smtp port", + "Adds an IP traffic type whitelist; can be specified multiple times. If any are", + "specified then only matched traffic will be allowed and all other traffic will be", + "dropped. Examples:", + " traffic-whitelist=tcp", + "would allow all TCP/IP packets (regardless of 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) { if (not m_TrafficPolicy) @@ -497,9 +501,12 @@ namespace llarp MultiValue, Comment{ "Specify a `.loki` address and an optional ip range to use as an exit broker.", - "Example:", - "exit-node=whatever.loki # maps all exit traffic to whatever.loki", - "exit-node=stuff.loki:100.0.0.0/24 # maps 100.0.0.0/24 to stuff.loki", + "Examples:", + " exit-node=whatever.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) { if (arg.empty()) @@ -580,10 +587,10 @@ namespace llarp Default{true}, Comment{ "Enable / disable automatic route configuration.", - "When this is enabled and an exit is used Lokinet will automatically configure " - "operating system routes to route traffic through the exit node.", - "This is enabled by default, but can be disabled to perform advanced exit routing " - "configuration manually."}, + "When this is enabled and an exit is used Lokinet will automatically configure the", + "operating system routes to route public internet traffic through the exit node.", + "This is enabled by default, but can be disabled if advanced/manual exit routing", + "configuration is desired."}, AssignmentAcceptor(m_EnableRoutePoker)); conf.defineOption( @@ -593,8 +600,8 @@ namespace llarp Default{true}, Comment{ "Enable / disable route configuration blackholes.", - "When enabled lokinet will drop ip4 and ip6 not included in exit config.", - "Enabled by default."}, + "When enabled lokinet will drop IPv4 and IPv6 traffic (when in exit mode) that is not", + "handled in the exit configuration. Enabled by default."}, AssignmentAcceptor(m_BlackholeRoutes)); conf.defineOption( @@ -602,7 +609,7 @@ namespace llarp "ifname", Comment{ "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)); @@ -626,10 +633,10 @@ namespace llarp "ip6-range", ClientOnly, 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.", "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.", }, IP6RangeDefault, @@ -720,9 +727,13 @@ namespace llarp ClientOnly, MultiValue, Comment{ - "Specify SRV Records for services hosted on the SNApp", - "for more info see https://docs.loki.network/Lokinet/Guides/HostingSNApps/", - "srv=_service._protocol priority weight port target.loki", + "Specify SRV Records for services hosted on the SNApp for protocols that use SRV", + "records for service discovery. Each line specifies a single SRV record as:", + " 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) { llarp::dns::SRVData newSRV; @@ -737,8 +748,8 @@ namespace llarp "path-alignment-timeout", ClientOnly, Comment{ - "time in seconds how long to wait for a path to align to pivot routers", - "if not provided a sensible default will be used", + "How long to wait (in seconds) for a path to align to a pivot router when establishing", + "a path through the network to a remote .loki address.", }, [this](int val) { if (val <= 0) @@ -753,9 +764,10 @@ namespace llarp ClientOnly, Default{fs::path{params.defaultDataDir / "addrmap.dat"}}, Comment{ - "persist mapped ephemeral addresses to a file", - "on restart the mappings will be loaded so that ip addresses will not be mapped to a " - "different address", + "If given this specifies a file in which to record mapped local tunnel addresses so", + "the same local address will be used for the same lokinet address on reboot. If this", + "is not specified then the local IP of remote lokinet targets will not persist across", + "restarts of lokinet.", }, [this](fs::path arg) { if (arg.empty()) @@ -879,7 +891,7 @@ namespace llarp "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) { m_ExtraOpts.emplace(key, val); }); @@ -1150,7 +1162,7 @@ namespace llarp RelayOnly, Default{true}, 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)); @@ -1159,8 +1171,8 @@ namespace llarp return; throw std::invalid_argument( "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 " - "rpc=ipc:///var/lib/loki/lokid.sock or rpc=ipc:///home/snode/.loki/lokid.sock"); + "option instead with oxend's lmq-local-control address -- typically a value such as " + "rpc=ipc:///var/lib/oxen/oxend.sock or rpc=ipc:///home/snode/.oxen/oxend.sock"); }); conf.defineOption( @@ -1168,12 +1180,12 @@ namespace llarp "rpc", RelayOnly, 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", - "ipc://LOKID-DATA-DIRECTORY/lokid.sock, such as:", - " rpc=ipc:///var/lib/loki/lokid.sock", - " rpc=ipc:///home/USER/.loki/lokid.sock", - "but can use (non-default) TCP if lokid is configured that way:", + "ipc://OXEND-DATA-DIRECTORY/oxend.sock, such as:", + " rpc=ipc:///var/lib/oxen/oxend.sock", + " rpc=ipc:///home/USER/.oxen/oxend.sock", + "but can use (non-default) TCP if oxend is configured that way:", " rpc=tcp://127.0.0.1:5678", }, [this](std::string arg) { lokidRPCAddr = oxenmq::address(arg); }); @@ -1202,7 +1214,7 @@ namespace llarp "add-node", MultiValue, 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.", }, [this](std::string arg) { @@ -1292,9 +1304,9 @@ namespace llarp m_UniqueHopsNetmaskSize = arg; }, 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.", - "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 conf.defineOption( @@ -1306,9 +1318,11 @@ namespace llarp m_ExcludeCountries.emplace(lowercase_ascii_string(std::move(arg))); }, Comment{ - "exclude a country given its 2 letter country code from being used in path builds", - "e.g. exclude-country=DE", - "can be listed multiple times to exclude multiple countries"}); + "Exclude a country given its 2 letter country code from being used in path builds.", + "For example:", + " 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 } @@ -1399,6 +1413,7 @@ namespace llarp params->isRelay = isRelay; params->defaultDataDir = m_DataDir; ConfigDefinition conf{isRelay}; + addBackwardsCompatibleConfigOptions(conf); initializeConfig(conf, *params); for (const auto& item : m_Additional) @@ -1616,11 +1631,11 @@ namespace llarp initializeConfig(def, *params); generateCommonConfigComments(def); - // lokid + // oxend def.addSectionComments( "lokid", { - "Settings for communicating with lokid", + "Settings for communicating with oxend", }); return def.generateINIConfig(true); diff --git a/llarp/dht/context.cpp b/llarp/dht/context.cpp index d2b0e7129..06c67953d 100644 --- a/llarp/dht/context.cpp +++ b/llarp/dht/context.cpp @@ -441,7 +441,7 @@ namespace llarp Context::CleanupTX() { auto now = Now(); - llarp::LogDebug("DHT tick"); + llarp::LogTrace("DHT tick"); pendingRouterLookups().Expire(now); _pendingIntrosetLookups.Expire(now); diff --git a/llarp/dns/message.cpp b/llarp/dns/message.cpp index f4d70763f..48d84f703 100644 --- a/llarp/dns/message.cpp +++ b/llarp/dns/message.cpp @@ -160,7 +160,8 @@ namespace llarp return OwnedBuffer::copy_used(buf); } - void Message::AddServFail(RR_TTL_t) + void + Message::AddServFail(RR_TTL_t) { if (questions.size()) { @@ -386,7 +387,8 @@ namespace llarp 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()) { diff --git a/llarp/dns/server.cpp b/llarp/dns/server.cpp index aa9e83da7..49e4fef14 100644 --- a/llarp/dns/server.cpp +++ b/llarp/dns/server.cpp @@ -89,7 +89,6 @@ namespace llarp::dns class Query : public QueryJob_Base { - std::weak_ptr parent; std::shared_ptr src; SockAddr resolverAddr; SockAddr askerAddr; @@ -102,11 +101,13 @@ namespace llarp::dns SockAddr toaddr, SockAddr fromaddr) : QueryJob_Base{std::move(query)} - , parent{parent_} , src{std::move(pktsrc)} , resolverAddr{std::move(toaddr)} , askerAddr{std::move(fromaddr)} + , parent{parent_} {} + std::weak_ptr parent; + int id{}; virtual void SendReply(llarp::OwnedBuffer replyBuf) const override; @@ -126,6 +127,7 @@ namespace llarp::dns #endif std::optional m_LocalAddr; + std::set m_Pending; struct ub_result_deleter { @@ -166,7 +168,9 @@ namespace llarp::dns hdr.id = query->Underlying().hdr_id; buf.cur = buf.base; 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 query->SendReply(std::move(pkt)); } @@ -407,6 +411,13 @@ namespace llarp::dns #endif 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); m_ctx = nullptr; } @@ -478,6 +489,12 @@ namespace llarp::dns return true; } } + if (not m_ctx) + { + // we are down + tmp->Cancel(); + return true; + } const auto& q = query.questions[0]; if (auto err = ub_resolve_async( m_ctx, @@ -486,7 +503,7 @@ namespace llarp::dns q.qclass, tmp.get(), &Resolver::Callback, - nullptr)) + &tmp->id)) { log::warning( logcat, "failed to send upstream query with libunbound: {}", ub_strerror(err)); @@ -494,6 +511,7 @@ namespace llarp::dns } else { + m_Pending.insert(tmp->id); // Leak the bare pointer we gave to unbound; we'll recapture it in Callback (void)tmp.release(); } diff --git a/llarp/dns/srv_data.hpp b/llarp/dns/srv_data.hpp index f61606322..58281ab8d 100644 --- a/llarp/dns/srv_data.hpp +++ b/llarp/dns/srv_data.hpp @@ -10,7 +10,7 @@ namespace llarp::dns { - typedef std::tuple SRVTuple; + using SRVTuple = std::tuple; struct SRVData { @@ -38,19 +38,23 @@ namespace llarp::dns SRVTuple toTuple() const; + auto + toTupleRef() const + { + return std::tie(service_proto, priority, weight, port, target); + } + /// so we can put SRVData in a std::set bool operator<(const SRVData& other) const { - return service_proto < other.service_proto or priority < other.priority - or weight < other.weight or port < other.port or target < other.target; + return toTupleRef() < other.toTupleRef(); } bool operator==(const SRVData& other) const { - return service_proto == other.service_proto and priority == other.priority - and weight == other.weight and port == other.port and target == other.target; + return toTupleRef() == other.toTupleRef(); } bool diff --git a/llarp/handlers/exit.cpp b/llarp/handlers/exit.cpp index 11c9d35c2..64e002e3a 100644 --- a/llarp/handlers/exit.cpp +++ b/llarp/handlers/exit.cpp @@ -613,7 +613,8 @@ namespace llarp }); } - std::optional ExitEndpoint::GetStatFor(AddressVariant_t) const + std::optional + ExitEndpoint::GetStatFor(AddressVariant_t) const { /// TODO: implement me return std::nullopt; diff --git a/llarp/handlers/null.hpp b/llarp/handlers/null.hpp index cd97fa82d..bfa0525e8 100644 --- a/llarp/handlers/null.hpp +++ b/llarp/handlers/null.hpp @@ -101,13 +101,14 @@ namespace llarp::handlers void SendPacketToRemote(const llarp_buffer_t&, service::ProtocolType) override{}; - huint128_t ObtainIPForAddr(std::variant) override + huint128_t + ObtainIPForAddr(std::variant) override { return {0}; } - std::optional> ObtainAddrForIP( - huint128_t) const override + std::optional> + ObtainAddrForIP(huint128_t) const override { return std::nullopt; } diff --git a/llarp/iwp/linklayer.cpp b/llarp/iwp/linklayer.cpp index 03e2259eb..6fb807058 100644 --- a/llarp/iwp/linklayer.cpp +++ b/llarp/iwp/linklayer.cpp @@ -26,7 +26,7 @@ namespace llarp::iwp , m_Inbound{allowInbound} {} - const char* + std::string_view LinkLayer::Name() const { return "iwp"; diff --git a/llarp/iwp/linklayer.hpp b/llarp/iwp/linklayer.hpp index 6d58b046c..82504edc7 100644 --- a/llarp/iwp/linklayer.hpp +++ b/llarp/iwp/linklayer.hpp @@ -35,7 +35,7 @@ namespace llarp::iwp std::shared_ptr NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) override; - const char* + std::string_view Name() const override; uint16_t diff --git a/llarp/iwp/message_buffer.hpp b/llarp/iwp/message_buffer.hpp index 3ea352064..f0dae604c 100644 --- a/llarp/iwp/message_buffer.hpp +++ b/llarp/iwp/message_buffer.hpp @@ -53,11 +53,12 @@ namespace llarp uint16_t m_ResendPriority; bool - operator<(const OutboundMessage& msg) const + operator<(const OutboundMessage& other) const { // yes, the first order is reversed as higher means more important // 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 diff --git a/llarp/iwp/session.cpp b/llarp/iwp/session.cpp index 382e75c64..b2109c479 100644 --- a/llarp/iwp/session.cpp +++ b/llarp/iwp/session.cpp @@ -924,13 +924,15 @@ namespace llarp } } - void Session::HandleCLOS(Packet_t) + void + Session::HandleCLOS(Packet_t) { LogInfo("remote closed by ", m_RemoteAddr); Close(); } - void Session::HandlePING(Packet_t) + void + Session::HandlePING(Packet_t) { m_LastRX = m_Parent->Now(); } diff --git a/llarp/link/server.cpp b/llarp/link/server.cpp index 58924e4ad..72eaa7ff9 100644 --- a/llarp/link/server.cpp +++ b/llarp/link/server.cpp @@ -249,7 +249,7 @@ namespace llarp bool ILinkLayer::PickAddress(const RouterContact& rc, llarp::AddressInfo& picked) const { - std::string OurDialect = Name(); + auto OurDialect = Name(); for (const auto& addr : rc.addrs) { if (addr.dialect == OurDialect) diff --git a/llarp/link/server.hpp b/llarp/link/server.hpp index 0e7c86c89..f9aca894b 100644 --- a/llarp/link/server.hpp +++ b/llarp/link/server.hpp @@ -135,7 +135,7 @@ namespace llarp virtual void Stop(); - virtual const char* + virtual std::string_view Name() const = 0; util::StatusObject @@ -179,7 +179,7 @@ namespace llarp bool IsCompatable(const llarp::RouterContact& other) const { - const std::string us = Name(); + const auto us = Name(); for (const auto& ai : other.addrs) if (ai.dialect == us) return true; @@ -207,7 +207,9 @@ namespace llarp bool 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 diff --git a/llarp/link/session.hpp b/llarp/link/session.hpp index fc8df2414..0c54756fa 100644 --- a/llarp/link/session.hpp +++ b/llarp/link/session.hpp @@ -68,7 +68,8 @@ namespace llarp /// recv packet on low layer /// not used by utp - virtual bool Recv_LL(Packet_t) + virtual bool + Recv_LL(Packet_t) { return true; } diff --git a/llarp/net/address_info.cpp b/llarp/net/address_info.cpp index fd5424632..f39b1d4c9 100644 --- a/llarp/net/address_info.cpp +++ b/llarp/net/address_info.cpp @@ -23,7 +23,7 @@ namespace llarp bool 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 diff --git a/llarp/net/ip_range.hpp b/llarp/net/ip_range.hpp index 9772793aa..a4e9b0be3 100644 --- a/llarp/net/ip_range.hpp +++ b/llarp/net/ip_range.hpp @@ -117,8 +117,8 @@ namespace llarp bool operator<(const IPRange& other) const { - return (this->addr & this->netmask_bits) < (other.addr & other.netmask_bits) - || this->netmask_bits < other.netmask_bits; + auto maskedA = addr & netmask_bits, maskedB = other.addr & other.netmask_bits; + return std::tie(maskedA, netmask_bits) < std::tie(maskedB, other.netmask_bits); } bool diff --git a/llarp/net/net.hpp b/llarp/net/net.hpp index e54a7ee8e..b3a7af8e4 100644 --- a/llarp/net/net.hpp +++ b/llarp/net/net.hpp @@ -34,62 +34,16 @@ namespace llarp { - inline bool - operator==(const in_addr& a, const in_addr& b) + inline int + 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 - operator==(const in6_addr& a, const in6_addr& b) + inline int + cmp(const in6_addr& a, const in6_addr& b) { - return memcmp(&a, &b, sizeof(in6_addr)) == 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(a) == reinterpret_cast(b); - case AF_INET6: - return reinterpret_cast(a) == reinterpret_cast(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; + return memcmp(&a, &b, sizeof(in6_addr)); } namespace net @@ -261,3 +215,61 @@ namespace llarp } // namespace net } // 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(a) == reinterpret_cast(b); + case AF_INET6: + return reinterpret_cast(a) == reinterpret_cast(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); +} diff --git a/llarp/net/posix.cpp b/llarp/net/posix.cpp index b04398c0c..6bc764a0b 100644 --- a/llarp/net/posix.cpp +++ b/llarp/net/posix.cpp @@ -93,7 +93,8 @@ namespace llarp::net return IPRange::FindPrivateRange(currentRanges); } - std::optional GetInterfaceIndex(ipaddr_t) const override + std::optional + GetInterfaceIndex(ipaddr_t) const override { // todo: implement me return std::nullopt; diff --git a/llarp/net/sock_addr.cpp b/llarp/net/sock_addr.cpp index f42feb928..8fdf457f1 100644 --- a/llarp/net/sock_addr.cpp +++ b/llarp/net/sock_addr.cpp @@ -206,15 +206,13 @@ namespace llarp bool SockAddr::operator<(const SockAddr& other) const { - return (m_addr.sin6_addr < other.m_addr.sin6_addr) - or (m_addr.sin6_port < other.m_addr.sin6_port); + return m_addr < other.m_addr; } bool SockAddr::operator==(const SockAddr& other) const { - return m_addr.sin6_addr == other.m_addr.sin6_addr - and m_addr.sin6_port == other.m_addr.sin6_port; + return m_addr == other.m_addr; } huint128_t diff --git a/llarp/net/traffic_policy.hpp b/llarp/net/traffic_policy.hpp index 1368d05d4..a34456535 100644 --- a/llarp/net/traffic_policy.hpp +++ b/llarp/net/traffic_policy.hpp @@ -33,11 +33,7 @@ namespace llarp::net bool operator<(const ProtocolInfo& other) const { - if (port and other.port) - { - return protocol < other.protocol or *port < *other.port; - } - return protocol < other.protocol; + return std::tie(protocol, port) < std::tie(other.protocol, other.port); } ProtocolInfo() = default; diff --git a/llarp/net/uint128.hpp b/llarp/net/uint128.hpp index 4bc39f53c..dde7c83af 100644 --- a/llarp/net/uint128.hpp +++ b/llarp/net/uint128.hpp @@ -141,25 +141,25 @@ namespace llarp constexpr bool 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 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 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 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& diff --git a/llarp/path/path_context.cpp b/llarp/path/path_context.cpp index f856ec3e8..7bb5223b0 100644 --- a/llarp/path/path_context.cpp +++ b/llarp/path/path_context.cpp @@ -412,7 +412,8 @@ namespace llarp return nullptr; } - void PathContext::RemovePathSet(PathSet_ptr) + void + PathContext::RemovePathSet(PathSet_ptr) {} } // namespace path } // namespace llarp diff --git a/llarp/path/pathbuilder.cpp b/llarp/path/pathbuilder.cpp index eaefcf40c..478060005 100644 --- a/llarp/path/pathbuilder.cpp +++ b/llarp/path/pathbuilder.cpp @@ -335,7 +335,8 @@ namespace llarp Build(*maybe, roles); } - bool Builder::UrgentBuild(llarp_time_t) const + bool + Builder::UrgentBuild(llarp_time_t) const { return buildIntervalLimit > MIN_PATH_BUILD_INTERVAL * 4; } diff --git a/llarp/path/pathset.cpp b/llarp/path/pathset.cpp index c3ba852d6..0474544d2 100644 --- a/llarp/path/pathset.cpp +++ b/llarp/path/pathset.cpp @@ -73,7 +73,8 @@ namespace llarp } } - void PathSet::Tick(llarp_time_t) + void + PathSet::Tick(llarp_time_t) { std::unordered_set endpoints; for (auto& item : m_Paths) diff --git a/llarp/path/pathset.hpp b/llarp/path/pathset.hpp index 734b5b26b..3e431bf41 100644 --- a/llarp/path/pathset.hpp +++ b/llarp/path/pathset.hpp @@ -210,19 +210,22 @@ namespace llarp BlacklistSNode(const RouterID) = 0; /// override me in subtype - virtual bool HandleGotIntroMessage(std::shared_ptr) + virtual bool + HandleGotIntroMessage(std::shared_ptr) { return false; } /// override me in subtype - virtual bool HandleGotRouterMessage(std::shared_ptr) + virtual bool + HandleGotRouterMessage(std::shared_ptr) { return false; } /// override me in subtype - virtual bool HandleGotNameMessage(std::shared_ptr) + virtual bool + HandleGotNameMessage(std::shared_ptr) { return false; } diff --git a/llarp/peerstats/peer_db.cpp b/llarp/peerstats/peer_db.cpp index 8226dafc8..d3b93b75b 100644 --- a/llarp/peerstats/peer_db.cpp +++ b/llarp/peerstats/peer_db.cpp @@ -308,7 +308,8 @@ namespace llarp throw std::logic_error{"Peer stats backend not enabled!"}; } - void PeerDb::loadDatabase(std::optional) + void + PeerDb::loadDatabase(std::optional) {} void @@ -349,7 +350,8 @@ namespace llarp PeerDb::configure(const RouterConfig&) {} - bool PeerDb::shouldFlush(llarp_time_t) + bool + PeerDb::shouldFlush(llarp_time_t) { return false; } diff --git a/llarp/router/abstractrouter.hpp b/llarp/router/abstractrouter.hpp index 022e6767a..7f6a368a7 100644 --- a/llarp/router/abstractrouter.hpp +++ b/llarp/router/abstractrouter.hpp @@ -199,14 +199,12 @@ namespace llarp virtual bool IsServiceNode() const = 0; - virtual bool - IsActiveServiceNode() const = 0; - - /// If we are running as a service node and appear active, i.e. registered and not - /// decommissioned, we should *not* ping core if we know of too few peers, to indicate to core - /// we are not in a good state. - virtual bool - ShouldPingOxen() const = 0; + /// Called to determine if we're in a bad state (which gets reported to our oxend) that should + /// 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 + /// (active or decommed). + virtual std::optional + OxendErrorState() const = 0; virtual bool StartRpcServer() = 0; @@ -315,7 +313,9 @@ namespace llarp /// set router's service node whitelist virtual void SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) = 0; + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& unfundedlist) = 0; virtual std::unordered_set GetRouterWhitelist() const = 0; diff --git a/llarp/router/i_rc_lookup_handler.hpp b/llarp/router/i_rc_lookup_handler.hpp index ffc5a3a4b..4efee04c6 100644 --- a/llarp/router/i_rc_lookup_handler.hpp +++ b/llarp/router/i_rc_lookup_handler.hpp @@ -34,7 +34,9 @@ namespace llarp virtual void SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) = 0; + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist) = 0; virtual void GetRC(const RouterID& router, RCRequestCallback callback, bool forceLookup = false) = 0; @@ -48,6 +50,12 @@ namespace llarp virtual bool IsGreylisted(const RouterID& remote) const = 0; + virtual bool + IsGreenlisted(const RouterID& remote) const = 0; + + virtual bool + IsRegistered(const RouterID& remote) const = 0; + virtual bool CheckRC(const RouterContact& rc) const = 0; diff --git a/llarp/router/rc_lookup_handler.cpp b/llarp/router/rc_lookup_handler.cpp index 48150090f..ca9169e65 100644 --- a/llarp/router/rc_lookup_handler.cpp +++ b/llarp/router/rc_lookup_handler.cpp @@ -32,26 +32,28 @@ namespace llarp whitelistRouters.erase(router); } + static void + loadColourList(std::unordered_set& beigelist, const std::vector& new_beige) + { + beigelist.clear(); + beigelist.insert(new_beige.begin(), new_beige.end()); + } + void RCLookupHandler::SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist) { if (whitelist.empty()) return; util::Lock l(_mutex); - whitelistRouters.clear(); - greylistRouters.clear(); - for (auto& router : whitelist) - { - whitelistRouters.emplace(router); - } - for (auto& router : greylist) - { - greylistRouters.emplace(router); - } + loadColourList(whitelistRouters, whitelist); + loadColourList(greylistRouters, greylist); + loadColourList(greenlistRouters, greenlist); - LogInfo("lokinet service node list now has ", whitelistRouters.size(), " routers"); + LogInfo("lokinet service node list now has ", whitelistRouters.size(), " active routers"); } bool @@ -140,6 +142,21 @@ namespace llarp 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 RCLookupHandler::PathIsAllowed(const RouterID& remote) const { diff --git a/llarp/router/rc_lookup_handler.hpp b/llarp/router/rc_lookup_handler.hpp index 8beee74b7..184b8d102 100644 --- a/llarp/router/rc_lookup_handler.hpp +++ b/llarp/router/rc_lookup_handler.hpp @@ -42,8 +42,11 @@ namespace llarp void SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) override - EXCLUDES(_mutex); + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& greenlist + + ) override EXCLUDES(_mutex); bool HaveReceivedWhitelist() const override; @@ -61,6 +64,16 @@ namespace llarp bool 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 CheckRC(const RouterContact& rc) const override; @@ -134,8 +147,12 @@ namespace llarp bool useWhitelist = false; bool isServiceNode = false; + // whitelist = active routers std::unordered_set whitelistRouters GUARDED_BY(_mutex); + // greylist = fully funded, but decommissioned routers std::unordered_set greylistRouters GUARDED_BY(_mutex); + // greenlist = registered but not fully-staked routers + std::unordered_set greenlistRouters GUARDED_BY(_mutex); using TimePoint = std::chrono::steady_clock::time_point; std::unordered_map _routerLookupTimes; diff --git a/llarp/router/route_poker.cpp b/llarp/router/route_poker.cpp index 8b38b133a..3fdc0e4bb 100644 --- a/llarp/router/route_poker.cpp +++ b/llarp/router/route_poker.cpp @@ -147,13 +147,16 @@ namespace llarp auto& route = platform->RouteManager(); - // find current gateways + // get current gateways, assume sorted by lowest metric first auto gateways = route.GetGatewaysNotOnInterface(*vpn); std::optional next_gw; for (auto& gateway : gateways) { if (auto* gw_ptr = std::get_if(&gateway)) + { next_gw = *gw_ptr; + break; + } } // update current gateway and apply state changes as needed diff --git a/llarp/router/router.cpp b/llarp/router/router.cpp index 975c6074b..73e52bf4d 100644 --- a/llarp/router/router.cpp +++ b/llarp/router/router.cpp @@ -395,6 +395,31 @@ namespace llarp { m_Config = std::move(c); 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; if (whitelistRouters) { @@ -402,33 +427,39 @@ namespace llarp m_lokidRpcClient = std::make_shared(m_lmq, weak_from_this()); } - enableRPCServer = conf.api.m_enableRPCServer; if (enableRPCServer) rpcBindAddr = oxenmq::address(conf.api.m_rpcBindAddr); + log::debug(logcat, "Starting RPC server"); if (not StartRpcServer()) throw std::runtime_error("Failed to start rpc server"); if (conf.router.m_workerThreads > 0) m_lmq->set_general_threads(conf.router.m_workerThreads); + log::debug(logcat, "Starting OMQ server"); m_lmq->start(); _nodedb = std::move(nodedb); m_isServiceNode = conf.router.m_isRelay; + log::debug( + logcat, m_isServiceNode ? "Running as a relay (service node)" : "Running as a client"); if (whitelistRouters) { m_lokidRpcClient->ConnectAsync(lokidRPCAddr); } - // fetch keys + log::debug(logcat, "Initializing key manager"); if (not m_keyManager->initialize(conf, true, isSNode)) throw std::runtime_error("KeyManager failed to initialize"); + + log::debug(logcat, "Initializing from configuration"); if (!FromConfig(conf)) throw std::runtime_error("FromConfig() failed"); + log::debug(logcat, "Initializing identity"); if (not EnsureIdentity()) throw std::runtime_error("EnsureIdentity() failed"); return true; @@ -471,16 +502,14 @@ namespace llarp return nodedb()->NumLoaded() < KnownPeerWarningThreshold; } - bool - Router::IsActiveServiceNode() const + std::optional + 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 @@ -508,10 +537,17 @@ namespace llarp } bool - Router::LooksDeregistered() const + Router::LooksFunded() const { return IsServiceNode() and whitelistRouters and _rcLookupHandler.HaveReceivedWhitelist() - and not _rcLookupHandler.SessionIsAllowed(pubkey()); + and _rcLookupHandler.SessionIsAllowed(pubkey()); + } + + bool + Router::LooksRegistered() const + { + return IsServiceNode() and whitelistRouters and _rcLookupHandler.HaveReceivedWhitelist() + and _rcLookupHandler.IsRegistered(pubkey()); } bool @@ -596,6 +632,7 @@ namespace llarp Router::FromConfig(const Config& conf) { // 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)) { const auto& netid = conf.router.m_netId; @@ -635,28 +672,27 @@ namespace llarp _ourAddress->setPort(*maybe_port); else 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; - // Lokid Config - whitelistRouters = conf.lokid.whitelistRouters; - lokidRPCAddr = oxenmq::address(conf.lokid.lokidRPCAddr); - - m_isServiceNode = conf.router.m_isRelay; - auto& networkConfig = conf.network; /// build a set of strictConnectPubkeys ( - /// TODO: make this consistent with config -- do we support multiple strict connections - // or not? std::unordered_set strictConnectPubkeys; if (not networkConfig.m_strictConnect.empty()) { const auto& val = networkConfig.m_strictConnect; if (IsServiceNode()) 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()); + log::debug(logcat, "{} strict-connect routers configured", val.size()); } std::vector configRouters = conf.connect.routers; @@ -675,58 +711,51 @@ namespace llarp } } - BootstrapList b_list; + bootstrapRCList.clear(); 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) { - b_list.emplace(rc); + bootstrapRCList.emplace(rc); } // in case someone has an old bootstrap file and is trying to use a bootstrap // that no longer exists - for (auto rc_itr = b_list.begin(); rc_itr != b_list.end();) - { - if (rc_itr->IsObsoleteBootstrap()) - b_list.erase(rc_itr); - else - rc_itr++; - } - - auto verifyRCs = [&]() { - for (auto& rc : b_list) + auto clearBadRCs = [this]() { + for (auto it = bootstrapRCList.begin(); it != bootstrapRCList.end();) { - if (rc.IsObsoleteBootstrap()) + if (it->IsObsoleteBootstrap()) + log::warning(logcat, "ignoring obsolete boostrap RC: {}", RouterID{it->pubkey}); + else if (not it->Verify(Now())) + log::warning(logcat, "ignoring invalid bootstrap RC: {}", RouterID{it->pubkey}); + else { - log::warning(logcat, "ignoring obsolete boostrap RC: {}", RouterID(rc.pubkey)); + ++it; continue; } - if (not rc.Verify(Now())) - { - log::warning(logcat, "ignoring invalid RC: {}", RouterID(rc.pubkey)); - 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) { auto fallbacks = llarp::load_bootstrap_fallbacks(); if (auto itr = fallbacks.find(_rc.netID.ToString()); itr != fallbacks.end()) { - b_list = itr->second; - - verifyRCs(); + bootstrapRCList = itr->second; + log::debug(logcat, "loaded {} default fallback bootstrap routers", bootstrapRCList.size()); + clearBadRCs(); } - if (bootstrapRCList.empty() - and not conf.bootstrap.seednode) // empty after trying fallback, if set + if (bootstrapRCList.empty() and not conf.bootstrap.seednode) { + // empty after trying fallback, if set log::error( logcat, "No bootstrap routers were loaded. The default bootstrap file {} does not exist, and " @@ -797,26 +826,6 @@ namespace llarp 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; } @@ -973,7 +982,7 @@ namespace llarp // don't purge bootstrap nodes from nodedb 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; } // if for some reason we stored an RC that isn't a valid router @@ -1058,18 +1067,22 @@ namespace llarp connectToNum = strictConnect; } - if (now >= m_NextDecommissionWarn) + if (isSvcNode and now >= m_NextDecommissionWarn) { 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 - LogError( - "We are running as a service node but we seem to be ", - dereg ? "deregistered" : "decommissioned"); + // complain about being deregistered/decommed/unfunded + log::error( + logcat, + "We are running as a service node but we seem to be {}", + not registered ? "deregistered" + : decom ? "decommissioned" + : "not fully staked"); m_NextDecommissionWarn = now + DecommissionWarnInterval; } - else if (isSvcNode and TooFewPeers()) + else if (TooFewPeers()) { log::error( 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 - // we shall connect out to others - if (connected < connectToNum and not LooksDeregistered()) + // if we need more sessions to routers and we are not a service node kicked from the network or + // we are a client we shall connect out to others + if (connected < connectToNum and (LooksFunded() or not isSvcNode)) { size_t dlt = connectToNum - connected; LogDebug("connecting to ", dlt, " random routers to keep alive"); @@ -1233,9 +1246,11 @@ namespace llarp void Router::SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& unfundedlist) { - _rcLookupHandler.SetRouterWhitelist(whitelist, greylist); + _rcLookupHandler.SetRouterWhitelist(whitelist, greylist, unfundedlist); } bool diff --git a/llarp/router/router.hpp b/llarp/router/router.hpp index 8eb751410..53b24e4aa 100644 --- a/llarp/router/router.hpp +++ b/llarp/router/router.hpp @@ -143,7 +143,9 @@ namespace llarp void SetRouterWhitelist( - const std::vector& whitelist, const std::vector& greylist) override; + const std::vector& whitelist, + const std::vector& greylist, + const std::vector& unfunded) override; std::unordered_set GetRouterWhitelist() const override @@ -203,9 +205,16 @@ namespace llarp bool 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 - 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 bool @@ -378,12 +387,8 @@ namespace llarp bool IsServiceNode() const override; - /// return true if service node *and* not deregistered or decommissioned - bool - IsActiveServiceNode() const override; - - bool - ShouldPingOxen() const override; + std::optional + OxendErrorState() const override; void Close(); @@ -556,8 +561,11 @@ namespace llarp 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_NextDecommissionWarn = 0s; + llarp_time_t m_NextDecommissionWarn = time_now_ms() + DECOMM_WARNING_STARTUP_DELAY; std::shared_ptr m_keyManager; std::shared_ptr m_peerDb; diff --git a/llarp/router_version.hpp b/llarp/router_version.hpp index 30429483b..a03cc02fc 100644 --- a/llarp/router_version.hpp +++ b/llarp/router_version.hpp @@ -41,7 +41,7 @@ namespace llarp bool 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 diff --git a/llarp/rpc/lokid_rpc_client.cpp b/llarp/rpc/lokid_rpc_client.cpp index 7048188fd..a40c33383 100644 --- a/llarp/rpc/lokid_rpc_client.cpp +++ b/llarp/rpc/lokid_rpc_client.cpp @@ -112,35 +112,57 @@ namespace llarp void LokidRpcClient::UpdateServiceNodeList() { - nlohmann::json request, fields; - fields["pubkey_ed25519"] = true; - fields["service_node_pubkey"] = true; - fields["funded"] = true; - fields["active"] = true; - request["fields"] = fields; - m_UpdatingList = true; + if (m_UpdatingList.exchange(true)) + return; // update already in progress + + nlohmann::json request{ + {"fields", + { + {"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( "rpc.get_service_nodes", [self = shared_from_this()](bool success, std::vector data) { - self->m_UpdatingList = false; if (not success) - { LogWarn("failed to update service node list"); - return; - } - if (data.size() < 2) + else if (data.size() < 2) + LogWarn("oxend gave empty reply for service node list"); + else { - LogWarn("lokid gave empty reply for service node list"); - return; - } - try - { - self->HandleGotServiceNodeList(std::move(data[1])); - } - catch (std::exception& ex) - { - LogError("failed to process service node list: ", ex.what()); + try + { + auto json = nlohmann::json::parse(std::move(data[1])); + if (json.at("status") != "OK") + 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()) + 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(); + 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()); } @@ -152,25 +174,27 @@ namespace llarp auto makePingRequest = [self = shared_from_this()]() { // send a ping PubKey pk{}; - bool should_ping = false; - if (auto r = self->m_Router.lock()) - { - pk = r->pubkey(); - should_ping = r->ShouldPingOxen(); - } - if (should_ping) - { - nlohmann::json payload = { - {"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())}, - {"version", {VERSION[0], VERSION[1], VERSION[2]}}}; - self->Request( - "admin.lokinet_ping", - [](bool success, std::vector data) { - (void)data; - LogDebug("Received response for ping. Successful: ", success); - }, - payload.dump()); - } + auto r = self->m_Router.lock(); + if (not r) + return; // router has gone away, maybe shutting down? + + pk = r->pubkey(); + + nlohmann::json payload = { + {"pubkey_ed25519", oxenc::to_hex(pk.begin(), pk.end())}, + {"version", {VERSION[0], VERSION[1], VERSION[2]}}}; + + if (auto err = r->OxendErrorState()) + payload["error"] = *err; + + self->Request( + "admin.lokinet_ping", + [](bool success, std::vector data) { + (void)data; + LogDebug("Received response for ping. Successful: ", success); + }, + payload.dump()); + // subscribe to block updates self->Request("sub.block", [](bool success, std::vector data) { if (data.empty() or not success) @@ -180,52 +204,53 @@ namespace llarp } 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); - // initial fetch of service node list - UpdateServiceNodeList(); } 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()) - { - LogDebug("service node list unchanged"); - return; - } std::unordered_map keymap; - std::vector activeNodeList, nonActiveNodeList; - if (const auto itr = j.find("service_node_states"); itr != j.end() and itr->is_array()) + std::vector activeNodeList, decommNodeList, unfundedNodeList; + 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) - { - // Skip unstaked snodes: - if (const auto funded_itr = snode.find("funded"); funded_itr == snode.end() - or not funded_itr->is_boolean() or not funded_itr->get()) - continue; + const auto ed_itr = snode.find("pubkey_ed25519"); + if (ed_itr == snode.end() or not ed_itr->is_string()) + continue; + const auto svc_itr = snode.find("service_node_pubkey"); + if (svc_itr == snode.end() or not svc_itr->is_string()) + continue; + const auto active_itr = snode.find("active"); + if (active_itr == snode.end() or not active_itr->is_boolean()) + continue; + const bool active = active_itr->get(); + const auto funded_itr = snode.find("funded"); + if (funded_itr == snode.end() or not funded_itr->is_boolean()) + continue; + const bool funded = funded_itr->get(); - const auto ed_itr = snode.find("pubkey_ed25519"); - if (ed_itr == snode.end() or not ed_itr->is_string()) - continue; - const auto svc_itr = snode.find("service_node_pubkey"); - if (svc_itr == snode.end() or not svc_itr->is_string()) - continue; - const auto active_itr = snode.find("active"); - if (active_itr == snode.end() or not active_itr->is_boolean()) - continue; - const bool active = active_itr->get(); + RouterID rid; + PubKey pk; + if (not rid.FromHex(ed_itr->get()) + or not pk.FromHex(svc_itr->get())) + continue; - RouterID rid; - PubKey pk; - if (not rid.FromHex(ed_itr->get()) - or not pk.FromHex(svc_itr->get())) - continue; - - keymap[rid] = pk; - (active ? activeNodeList : nonActiveNodeList).push_back(std::move(rid)); - } + keymap[rid] = pk; + (active ? activeNodeList + : funded ? decommNodeList + : unfundedNodeList) + .push_back(std::move(rid)); } if (activeNodeList.empty()) @@ -233,17 +258,19 @@ namespace llarp LogWarn("got empty service node list, ignoring."); return; } + // inform router about the new list if (auto router = m_Router.lock()) { auto& loop = router->loop(); loop->call([this, active = std::move(activeNodeList), - inactive = std::move(nonActiveNodeList), + decomm = std::move(decommNodeList), + unfunded = std::move(unfundedNodeList), keymap = std::move(keymap), router = std::move(router)]() mutable { m_KeyMap = std::move(keymap); - router->SetRouterWhitelist(active, inactive); + router->SetRouterWhitelist(active, decomm, unfunded); }); } else diff --git a/llarp/rpc/lokid_rpc_client.hpp b/llarp/rpc/lokid_rpc_client.hpp index b2614bd10..bfc267480 100644 --- a/llarp/rpc/lokid_rpc_client.hpp +++ b/llarp/rpc/lokid_rpc_client.hpp @@ -55,6 +55,8 @@ namespace llarp void 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 UpdateServiceNodeList(); @@ -72,8 +74,10 @@ namespace llarp 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 - HandleGotServiceNodeList(std::string json); + HandleNewServiceNodeList(const nlohmann::json& json); // Handles request from lokid for peer stats on a specific peer void @@ -88,6 +92,7 @@ namespace llarp std::weak_ptr m_Router; std::atomic m_UpdatingList; + std::string m_LastUpdateHash; std::unordered_map m_KeyMap; diff --git a/llarp/service/endpoint.cpp b/llarp/service/endpoint.cpp index 1395dadd1..48c33543a 100644 --- a/llarp/service/endpoint.cpp +++ b/llarp/service/endpoint.cpp @@ -40,6 +40,11 @@ #include #include +namespace +{ + constexpr size_t MIN_ENDPOINTS_FOR_LNS_LOOKUP = 2; +} // namespace + namespace llarp { namespace service @@ -309,6 +314,7 @@ namespace llarp auto obj = path::Builder::ExtractStatus(); obj["exitMap"] = m_ExitMap.ExtractStatus(); obj["identity"] = m_Identity.pub.Addr().ToString(); + obj["networkReady"] = ReadyToDoLookup(); util::StatusObject authCodes; for (const auto& [service, info] : m_RemoteAuthInfos) @@ -320,7 +326,8 @@ namespace llarp return m_state->ExtractStatus(obj); } - void Endpoint::Tick(llarp_time_t) + void + Endpoint::Tick(llarp_time_t) { const auto now = llarp::time_now_ms(); path::Builder::Tick(now); @@ -945,6 +952,22 @@ namespace llarp return not m_ExitMap.Empty(); } + bool + Endpoint::ReadyToDoLookup(std::optional 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 Endpoint::LookupNameAsync( std::string name, @@ -964,23 +987,20 @@ namespace llarp } LogInfo(Name(), " looking up LNS name: ", name); path::Path::UniqueEndpointSet_t paths; - ForEachPath([&](auto path) { + ForEachPath([&paths](auto path) { if (path and path->IsReady()) paths.insert(path); }); - constexpr size_t min_unique_lns_endpoints = 2; - constexpr size_t max_unique_lns_endpoints = 7; - // not enough paths - if (paths.size() < min_unique_lns_endpoints) + if (not ReadyToDoLookup(paths.size())) { LogWarn( Name(), " not enough paths for lns lookup, have ", paths.size(), " need ", - min_unique_lns_endpoints); + MIN_ENDPOINTS_FOR_LNS_LOOKUP); handler(std::nullopt); return; } @@ -1005,11 +1025,12 @@ namespace llarp handler(result); }; + constexpr size_t max_lns_lookup_endpoints = 7; // pick up to max_unique_lns_endpoints random paths to do lookups from std::vector chosenpaths; chosenpaths.insert(chosenpaths.begin(), paths.begin(), paths.end()); 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 = m_state->lnsTracker.MakeResultHandler(name, chosenpaths.size(), maybeInvalidateCache); @@ -1165,7 +1186,8 @@ namespace llarp return m_Identity.pub.Addr(); } - std::optional Endpoint::GetStatFor(AddressVariant_t) const + std::optional + Endpoint::GetStatFor(AddressVariant_t) const { // TODO: implement me return std::nullopt; diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index 00a2a3c68..09b960957 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -521,6 +521,9 @@ namespace llarp return false; } + bool + ReadyToDoLookup(std::optional numPaths = std::nullopt) const; + protected: IDataHandler* m_DataHandler = nullptr; Identity m_Identity; diff --git a/llarp/service/identity.cpp b/llarp/service/identity.cpp index f54a025a5..a28bb2204 100644 --- a/llarp/service/identity.cpp +++ b/llarp/service/identity.cpp @@ -80,7 +80,6 @@ namespace llarp Clear(); std::array tmp; - llarp_buffer_t buf(tmp); // this can throw bool exists = fs::exists(fname); @@ -94,6 +93,7 @@ namespace llarp // check for file if (!exists) { + llarp_buffer_t buf{tmp}; // regen and encode RegenerateKeys(); if (!BEncode(&buf)) @@ -108,6 +108,7 @@ namespace llarp { throw std::runtime_error{fmt::format("failed to write {}: {}", fname, e.what())}; } + return; } if (not fs::is_regular_file(fname)) @@ -125,10 +126,11 @@ namespace llarp throw std::length_error{"service identity too big"}; } // (don't catch io error exceptions) - - if (!bencode_decode_dict(*this, &buf)) - throw std::length_error{"could not decode service identity"}; - + { + llarp_buffer_t buf{tmp}; + if (!bencode_decode_dict(*this, &buf)) + throw std::length_error{"could not decode service identity"}; + } auto crypto = CryptoManager::instance(); // ensure that the encryption key is set diff --git a/llarp/service/intro.hpp b/llarp/service/intro.hpp index c1c431eb0..bb659a4d4 100644 --- a/llarp/service/intro.hpp +++ b/llarp/service/intro.hpp @@ -55,8 +55,8 @@ namespace llarp bool operator<(const Introduction& other) const { - return expiresAt < other.expiresAt || pathID < other.pathID || router < other.router - || version < other.version || latency < other.latency; + return std::tie(expiresAt, pathID, router, version, latency) + < std::tie(other.expiresAt, other.pathID, other.router, other.version, other.latency); } bool diff --git a/llarp/service/lookup.hpp b/llarp/service/lookup.hpp index 1507f68dc..9f20cc127 100644 --- a/llarp/service/lookup.hpp +++ b/llarp/service/lookup.hpp @@ -35,7 +35,8 @@ namespace llarp } /// handle lookup result for introsets - virtual bool HandleNameResponse(std::optional
) + virtual bool + HandleNameResponse(std::optional
) { return false; } @@ -76,7 +77,8 @@ namespace llarp RouterID endpoint; /// 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; } diff --git a/llarp/vpn/platform.hpp b/llarp/vpn/platform.hpp index 6d0b18063..ebba6dee8 100644 --- a/llarp/vpn/platform.hpp +++ b/llarp/vpn/platform.hpp @@ -25,7 +25,7 @@ namespace llarp::vpn bool operator<(const InterfaceAddress& other) const { - return range < other.range or fam < other.fam; + return std::tie(range, fam) < std::tie(other.range, other.fam); } }; diff --git a/llarp/win32/windivert.cpp b/llarp/win32/windivert.cpp index b359e1927..7dc181e91 100644 --- a/llarp/win32/windivert.cpp +++ b/llarp/win32/windivert.cpp @@ -125,7 +125,8 @@ namespace llarp::win32 return -1; } - virtual bool WritePacket(net::IPPacket) override + virtual bool + WritePacket(net::IPPacket) override { return false; } diff --git a/pybind/llarp/handlers/pyhandler.hpp b/pybind/llarp/handlers/pyhandler.hpp index 97fdc9572..3f712dcc6 100644 --- a/pybind/llarp/handlers/pyhandler.hpp +++ b/pybind/llarp/handlers/pyhandler.hpp @@ -66,13 +66,14 @@ namespace llarp return false; } - llarp::huint128_t ObtainIPForAddr(std::variant) override + llarp::huint128_t + ObtainIPForAddr(std::variant) override { return {0}; } - std::optional> ObtainAddrForIP( - huint128_t) const override + std::optional> + ObtainAddrForIP(huint128_t) const override { return std::nullopt; }