Compare commits

...

31 Commits

Author SHA1 Message Date
dr7ana 42337388f9
Merge pull request #2213 from dr7ana/quic-wip
Outbound/inbound message handling; compilation fixes
7 months ago
Jason Rhinelander f7c18de0d4
Give up for now 7 months ago
Jason Rhinelander 4f364f5e59
Bump libquic to latest for static build fixes 7 months ago
Jason Rhinelander a7a18868c7
Turn off terrible new cmake 3.24+ default 7 months ago
Jason Rhinelander 6ebc812cda
Remove unused file 7 months ago
Jason Rhinelander 1ca81713ab
Bump armhf static build to bullseye
Use backports for cmake because ngtcp2 needs 3.20+.
7 months ago
Jason Rhinelander e237d5ad6e
Don't export CC
This was causing cmake to double-invoke ccache for compilation units,
and broke oxen-mq's local zmq build for the same reason.
7 months ago
dr7ana 8cbae70369 Weird clang unused variable CI fix 7 months ago
Jason Rhinelander b4a1ed9b85
Bump oxen-mq for libzmq llvm static build fix 7 months ago
dr7ana 7d713323f0 Windows CI fixes
- some weird function call business
- string formatting
- etc
7 months ago
dr7ana aae677814d Bump libzmq static; remove patches 7 months ago
Jason Rhinelander 6f2825c922
Bump WinDivert to latest
There are some bugfix releases, but also the upstream hash was wrong for
the current release anyway (upstream changed it?).
7 months ago
Jason Rhinelander 16506b6d8b
Default libcrypt to whether or not we find it
Also deliberately don't provide the function at all if we aren't
compiled with libcrypt so that we can't link if we try to call it when
not available.
7 months ago
Jason Rhinelander d2667cfb89
Disable Router Hive & DEB builds
They aren't useful right now.
7 months ago
dr7ana 7ac88616f7 squash 7 months ago
dr7ana b7e21becf0 windows fixes 7 months ago
dr7ana 7314c2a22a CI Fixes, squash 7 months ago
Jason Rhinelander c18ad4c618
Temporarily disable building/running test suite 7 months ago
dr7ana 2abe2d9363 Review fixes
- cleaned up include-what-you-use errors (mostly quoted includes)
- misc fixes
7 months ago
Jason Rhinelander 5c3467ecb0 Fix systemd linkage 7 months ago
Jason Rhinelander 18effaa76f Bring oxen-encoding back in as a submodule
As long as it's loaded before oxen-mq or libquic, this should end up
being the one that gets used in oxen-mq/libquic, and so we don't have to
update those when we want something in a newer oxen-encoding.
7 months ago
Jason Rhinelander c3242e4092 Add format.sh detection of include problems 7 months ago
dr7ana 46ad8d4058 Clang format include sorting + CMake
- includes are now sorted in consistent, logical order; first step in an attempt to fix the tomfoolery (no relation to Tom) brought in by include-what-you-use
- shuffled around some cmake linking to simplify dependency graph
- superfluous files removed
7 months ago
dr7ana bda8b211dd Cmake restructuring 7 months ago
Jason Rhinelander f4f5ab0109 "Refactor" aka delete Crypto/CryptoManager
- Get rid of CryptoManager.
- Get rid of Crypto.
- Move all the Crypto instance methods to llarp::crypto functions.
  (None of them needed to be methods at all, so this is simple).
- Move sodium/ntru initialization into static initialization.
- Add llarp::csrng, which is an available llarp::CSRNG instance which is
  a bit easier than needing to construct a `CSRNG rng{};` in various
  places.
- Various related small simplifications/cleanups.
7 months ago
dr7ana e710cfea47 Review commit 7 months ago
dr7ana 0e451db77f Compilation fixes
- almost all errors have been commented out for refactor or already refactored
- committing this prior to sorting out the cmake structure
- upcoming include-what-you-use application
7 months ago
dr7ana 3ae8fce77d Outbound context absorbed sendcontex
- message transmission routed through refactored handling
- still work to be done, but now to make it compile at least
7 months ago
dr7ana 41312abab0 introset and message transmission underway
- message handling through classes that inherit from PathSet
- cleanups around link_manager
- etc etc
7 months ago
dr7ana 6955f3fae0 initial commit for next PR 7 months ago
Thomas Winget 4755269458 implement sending "path control" (onioned control) message
TODO: handle at transit hop, handle at terminal hop, create and handle responses
7 months ago

@ -33,10 +33,12 @@ BraceWrapping:
SplitEmptyNamespace: false
BreakBeforeTernaryOperators: 'true'
BreakConstructorInitializersBeforeComma: 'true'
ColumnLimit: 100
Cpp11BracedListStyle: 'true'
KeepEmptyLinesAtTheStartOfBlocks: 'false'
NamespaceIndentation: All
PenaltyBreakString: '3'
SortIncludes: CaseInsensitive
SpaceBeforeParens: ControlStatements
SpacesInAngles: 'false'
SpacesInContainerLiterals: 'false'
@ -44,8 +46,6 @@ SpacesInParentheses: 'false'
SpacesInSquareBrackets: 'false'
Standard: Cpp11
UseTab: Never
SortIncludes: false
ColumnLimit: 100
# treat pointers and reference declarations as if part of the type
DerivePointerAlignment: false
@ -55,7 +55,23 @@ PointerAlignment: Left
BinPackParameters: 'false'
BinPackArguments: 'false'
# TODO: uncomment me when we are reading to rearrange the header includes
# IncludeBlocks: Regroup
# IncludeCategories: 'llarp/'
# Include block sorting in the following order:
# - Main header for source file (clang-format default prioritizes this first)
# - Relative path includes in quotation marks
# - Absolute path includes in angle brackets
# - External dependencies
# - System dependencies
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '".+\.h'
Priority: 2
- Regex: '^<llarp'
Priority: 3
- Regex: '<winsock2\.h>'
Priority: 4
- Regex: '<windows\.h>'
Priority: 5
- Regex: '^<.*\.h(pp)?>$'
Priority: 6
- Regex: '(<)(.)+(>)'
Priority: 7

@ -38,6 +38,12 @@ local kitware_repo(distro) = [
'eatmydata ' + apt_get_quiet + ' update',
];
local debian_backports(distro, pkgs) = [
'echo "deb http://deb.debian.org/debian ' + distro + '-backports main" >/etc/apt/sources.list.d/' + distro + '-backports.list',
'eatmydata ' + apt_get_quiet + ' update',
'eatmydata ' + apt_get_quiet + ' install -y ' + std.join(' ', std.map(function(x) x + '/' + distro + '-backports', pkgs)),
];
// Regular build on a debian-like system:
local debian_pipeline(name,
image,
@ -51,7 +57,7 @@ local debian_pipeline(name,
local_mirror=true,
extra_cmds=[],
jobs=6,
tests=true,
tests=false, // FIXME TODO: temporary until test suite is fixed
oxen_repo=false,
allow_fail=false) = {
kind: 'pipeline',
@ -104,16 +110,15 @@ local local_gnutls(jobs=6, prefix='/usr/local') = [
apt_get_quiet + ' install -y curl ca-certificates',
'curl -sSL https://ftp.gnu.org/gnu/nettle/nettle-3.9.1.tar.gz | tar xfz -',
'curl -sSL https://www.gnupg.org/ftp/gcrypt/gnutls/v3.8/gnutls-3.8.0.tar.xz | tar xfJ -',
'export CC="ccache gcc"',
'export PKG_CONFIG_PATH=' + prefix + '/lib/pkgconfig:' + prefix + '/lib64/pkgconfig',
'export LD_LIBRARY_PATH=' + prefix + '/lib:' + prefix + '/lib64',
'cd nettle-3.9.1',
'./configure --prefix=' + prefix,
'./configure --prefix=' + prefix + ' CC="ccache gcc"',
'make -j' + jobs,
'make install',
'cd ..',
'cd gnutls-3.8.0',
'./configure --prefix=' + prefix + ' --with-included-libtasn1 --with-included-unistring --without-p11-kit --disable-libdane --disable-cxx --without-tpm --without-tpm2',
'./configure --prefix=' + prefix + ' --with-included-libtasn1 --with-included-unistring --without-p11-kit --disable-libdane --disable-cxx --without-tpm --without-tpm2 CC="ccache gcc"',
'make -j' + jobs,
'make install',
'cd ..',
@ -446,11 +451,11 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = {
'./contrib/ci/drone-static-upload.sh',
]),
// Static armhf build (gets uploaded)
debian_pipeline('Static (buster armhf)',
docker_base + 'debian-buster/arm32v7',
debian_pipeline('Static [FIXME] (bullseye armhf)',
docker_base + 'debian-bullseye/arm32v7',
arch='arm64',
deps=['g++', 'python3-dev', 'automake', 'libtool'],
extra_setup=kitware_repo('bionic'),
extra_setup=debian_backports('bullseye', ['cmake']),
cmake_extra='-DBUILD_STATIC_DEPS=ON -DBUILD_SHARED_LIBS=OFF -DSTATIC_LINK=ON ' +
'-DCMAKE_CXX_FLAGS="-march=armv7-a+fp -Wno-psabi" -DCMAKE_C_FLAGS="-march=armv7-a+fp" ' +
'-DNATIVE_BUILD=OFF -DWITH_SYSTEMD=OFF -DWITH_BOOTSTRAP=OFF',
@ -458,8 +463,10 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = {
'./contrib/ci/drone-check-static-libs.sh',
'UPLOAD_OS=linux-armhf ./contrib/ci/drone-static-upload.sh',
],
allow_fail=true, // XXX FIXME: build currently fails!
jobs=4),
/*
// integration tests
debian_pipeline('Router Hive',
docker_base + 'ubuntu-lts',
@ -471,6 +478,7 @@ local docs_pipeline(name, image, extra_cmds=[], allow_fail=false) = {
deb_builder(docker_base + 'debian-bullseye-builder', 'bullseye', 'debian/bullseye'),
deb_builder(docker_base + 'ubuntu-jammy-builder', 'jammy', 'ubuntu/jammy'),
deb_builder(docker_base + 'debian-sid-builder', 'sid', 'debian/sid', arch='arm64'),
*/
// Macos builds:
mac_builder('macOS (Release)', extra_cmds=[

1
.gitignore vendored

@ -67,3 +67,4 @@ regdbhelper.dll
# xcode
xcuserdata/
scc.py

3
.gitmodules vendored

@ -35,3 +35,6 @@
[submodule "external/span-lite"]
path = external/span-lite
url = https://github.com/martinmoene/span-lite.git
[submodule "external/oxen-encoding"]
path = external/oxen-encoding
url = https://github.com/oxen-io/oxen-encoding.git

@ -1,12 +1,18 @@
cmake_minimum_required(VERSION 3.13...3.24) # 3.13 is buster's version
# Cmake 3.24+ breaks extraction timestamps by default, hurray, but the option to not break
# timestamps fails in cmake <3.24, extra hurray!
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
cmake_policy(SET CMP0135 OLD)
endif()
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Has to be set before `project()`, and ignored on non-macos:
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15 CACHE STRING "macOS deployment target (Apple clang only)")
option(BUILD_DAEMON "build lokinet daemon and associated utils" ON)
option(GRAPH_DEPENDENCIES "Produce graphviz representation of cmake dependencies" OFF)
set(LANGS C CXX)
if(APPLE AND BUILD_DAEMON)
@ -257,23 +263,26 @@ pkg_check_modules(SD libsystemd IMPORTED_TARGET)
# Default WITH_SYSTEMD to true if we found it
option(WITH_SYSTEMD "enable systemd integration for sd_notify" ${SD_FOUND})
# Base interface target where we set up global link libraries, definitions, includes, etc.
add_library(base_libs INTERFACE)
add_subdirectory(external)
# interface library for setting common includes, linkage and flags
add_library(lokinet-base INTERFACE)
target_include_directories(lokinet-base INTERFACE . include)
target_link_libraries(lokinet-base INTERFACE quic nlohmann_json::nlohmann_json)
if(WITH_SYSTEMD AND (NOT ANDROID))
if(NOT SD_FOUND)
message(FATAL_ERROR "libsystemd not found")
endif()
target_link_libraries(base_libs INTERFACE PkgConfig::SD)
target_compile_definitions(base_libs INTERFACE WITH_SYSTEMD)
target_link_libraries(lokinet-base INTERFACE PkgConfig::SD)
target_compile_definitions(lokinet-base INTERFACE WITH_SYSTEMD)
endif()
add_subdirectory(external)
if(USE_JEMALLOC AND NOT STATIC_LINK)
pkg_check_modules(JEMALLOC jemalloc IMPORTED_TARGET)
if(JEMALLOC_FOUND)
target_link_libraries(base_libs INTERFACE PkgConfig::JEMALLOC)
target_link_libraries(lokinet-base INTERFACE PkgConfig::JEMALLOC)
else()
message(STATUS "jemalloc not found, not linking to jemalloc")
endif()
@ -283,8 +292,8 @@ endif()
if(ANDROID)
target_link_libraries(base_libs INTERFACE log)
target_compile_definitions(base_libs INTERFACE ANDROID)
target_link_libraries(lokinet-base INTERFACE log)
target_compile_definitions(lokinet-base INTERFACE ANDROID)
set(ANDROID_PLATFORM_SRC android/ifaddrs.c)
endif()

@ -0,0 +1,4 @@
set(GRAPHVIZ_GRAPH_NAME "graph.dot" CACHE STRING "")
set(GRAPHVIZ_GENERATE_PER_TARGET FALSE CACHE BOOL "")
set(GRAPHVIZ_GENERATE_DEPENDERS FALSE CACHE BOOL "")
set(GRAPHVIZ_OBJECT_LIBS OFF CACHE BOOL "")

@ -41,11 +41,11 @@ set(SODIUM_SOURCE libsodium-${SODIUM_VERSION}.tar.gz)
set(SODIUM_HASH SHA512=17e8638e46d8f6f7d024fe5559eccf2b8baf23e143fadd472a7d29d228b186d86686a5e6920385fe2020729119a5f12f989c3a782afbd05a8db4819bb18666ef
CACHE STRING "libsodium source hash")
set(ZMQ_VERSION 4.3.4 CACHE STRING "libzmq version")
set(ZMQ_VERSION 4.3.5 CACHE STRING "libzmq version")
set(ZMQ_MIRROR ${LOCAL_MIRROR} https://github.com/zeromq/libzmq/releases/download/v${ZMQ_VERSION}
CACHE STRING "libzmq mirror(s)")
set(ZMQ_SOURCE zeromq-${ZMQ_VERSION}.tar.gz)
set(ZMQ_HASH SHA512=e198ef9f82d392754caadd547537666d4fba0afd7d027749b3adae450516bcf284d241d4616cad3cb4ad9af8c10373d456de92dc6d115b037941659f141e7c0e
set(ZMQ_HASH SHA512=a71d48aa977ad8941c1609947d8db2679fc7a951e4cd0c3a1127ae026d883c11bd4203cf315de87f95f5031aec459a731aec34e5ce5b667b8d0559b157952541
CACHE STRING "libzmq source hash")
set(LIBUV_VERSION 1.44.2 CACHE STRING "libuv version")
@ -352,16 +352,9 @@ if(ARCH_TRIPLET MATCHES mingw)
endif()
endif()
if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
set(zmq_patch
PATCH_COMMAND ${PROJECT_SOURCE_DIR}/contrib/apply-patches.sh
${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-wepoll.patch
${PROJECT_SOURCE_DIR}/contrib/patches/libzmq-mingw-unistd.patch)
endif()
build_external(zmq
DEPENDS sodium_external
${zmq_patch}
CONFIGURE_COMMAND ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --enable-static --disable-shared
--disable-curve-keygen --enable-curve --disable-drafts --disable-libunwind --with-libsodium
--without-pgm --without-norm --without-vmci --without-docs --with-pic --disable-Werror --disable-libbsd ${zmq_extra}
@ -370,6 +363,7 @@ build_external(zmq
)
add_static_target(libzmq zmq_external libzmq.a)
set(libzmq_link_libs "sodium")
if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
list(APPEND libzmq_link_libs iphlpapi)

@ -1,7 +0,0 @@
if(STATIC_LINK)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
link_libraries( -static-libstdc++ )
else()
link_libraries( -static-libstdc++ -static-libgcc )
endif()
endif()

@ -25,11 +25,11 @@ set(WINTUN_SOURCE wintun-${WINTUN_VERSION}.zip)
set(WINTUN_HASH SHA256=07c256185d6ee3652e09fa55c0b673e2624b565e02c4b9091c79ca7d2f24ef51
CACHE STRING "wintun source hash")
set(WINDIVERT_VERSION 2.2.0-A CACHE STRING "windivert version")
set(WINDIVERT_VERSION 2.2.2-A CACHE STRING "windivert version")
set(WINDIVERT_MIRROR https://reqrypt.org/download
CACHE STRING "windivert mirror(s)")
set(WINDIVERT_SOURCE WinDivert-${WINDIVERT_VERSION}.zip)
set(WINDIVERT_HASH SHA256=2a7630aac0914746fbc565ac862fa096e3e54233883ac52d17c83107496b7a7f
set(WINDIVERT_HASH SHA512=92eb2ef98ced175d44de1cdb7c52f2ebc534b6a997926baeb83bfe94cba9287b438f796aff11f6163918bcdbc25bcd4e3383715f139f690d207ce219f846a345
CACHE STRING "windivert source hash")
set(WINTUN_URL ${WINTUN_MIRROR}/${WINTUN_SOURCE}

@ -4,12 +4,28 @@
cd "$(dirname $0)/../"
sources=($(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#'))
incl_pat='^(#include +)"(llarp|libntrup|oxen|oxenc|oxenmq|quic|CLI|cpr|nlohmann|ghc|fmt|spdlog|uvw?)([/.][^"]*)"'
if [ "$1" = "verify" ] ; 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
if [ $($CLANG_FORMAT --output-replacements-xml "${sources[@]}" | grep '</replacement>' | wc -l) -ne 0 ] ; then
exit 2
fi
if grep --color -E "$incl_pat" "${sources[@]}"; then
exit 5
fi
else
$CLANG_FORMAT -i $(find jni daemon llarp include pybind | grep -E '\.([hc](pp)?|m(m)?)$' | grep -v '#') &> /dev/null
$CLANG_FORMAT -i "${sources[@]}" &> /dev/null
perl -pi -e "s{$incl_pat}"'{$1<$2$3>}' "${sources[@]}" &> /dev/null
fi
# Some includes just shouldn't exist anywhere, but need to be fixed manually:
if grep --color -E '^#include ([<"]external/|<bits/|<.*/impl)' "${sources[@]}"; then
echo "Format failed: bad includes detected that can't be auto-corrected"
exit 5
fi
swift_format=$(command -v swiftformat 2>/dev/null)

@ -1,4 +1,5 @@
#include <libntrup/ntru.h>
#include <libntrup/ntru_api.h>
#ifdef __x86_64__
#include <cpuid.h>

@ -59,7 +59,8 @@ foreach(exe ${exetargets})
elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
target_link_directories(${exe} PRIVATE /usr/local/lib)
endif()
target_link_libraries(${exe} PUBLIC lokinet-amalgum hax_and_shims_for_cmake)
# target_link_libraries(${exe} PUBLIC lokinet-amalgum hax_and_shims_for_cmake)
target_link_libraries(${exe} PUBLIC lokinet-core hax_and_shims_for_cmake)
if(STRIP_SYMBOLS)
add_custom_command(TARGET ${exe}
POST_BUILD
@ -79,6 +80,9 @@ foreach(exe ${exetargets})
endif()
endforeach()
target_link_libraries(lokinet PRIVATE CLI11)
target_link_libraries(lokinet-vpn PRIVATE CLI11)
if(SETCAP)
install(CODE "execute_process(COMMAND ${SETCAP} cap_net_admin,cap_net_bind_service=+eip ${CMAKE_INSTALL_PREFIX}/bin/lokinet)")
endif()

@ -1,13 +1,10 @@
#include <cpr/cpr.h>
#include <llarp/constants/files.hpp>
#include <llarp/constants/version.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/fs.hpp>
#include <fstream>
#include <sstream>
#include <iostream>
#include <cpr/cpr.h>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
@ -15,12 +12,6 @@
#include <openssl/x509.h>
#endif
#include <sstream>
#ifndef _WIN32
#include <openssl/x509.h>
#endif
namespace
{
int
@ -102,9 +93,9 @@ main(int argc, char* argv[])
{
return fail("failed to fetch '" + bootstrap_url + "' HTTP " + std::to_string(resp.status_code));
}
std::stringstream ss;
ss << resp.text;
std::string data{ss.str()};
const auto& data = resp.text;
if (data[0] == 'l' or data[0] == 'd')
{
try

@ -1,25 +1,20 @@
#include <oxenmq/oxenmq.h>
#include <nlohmann/json.hpp>
#include <CLI/CLI.hpp>
#include <fmt/core.h>
#include <nlohmann/json.hpp>
#include <oxenmq/oxenmq.h>
#include <future>
#include <vector>
#include <array>
#include <llarp/net/net.hpp>
#include <string_view>
#include <CLI/App.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/Config.hpp>
#include "oxenmq/address.h"
#include <vector>
#ifdef _WIN32
// add the unholy windows headers for iphlpapi
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <strsafe.h>
#include <ws2tcpip.h>
#else
#include <sys/wait.h>
#endif
/// do a oxenmq request on an omq instance blocking style

@ -1,28 +1,33 @@
#include <llarp.hpp>
#include <llarp/config/config.hpp> // for ensure_config
#include <llarp/constants/files.hpp>
#include <llarp/constants/platform.hpp>
#include <llarp/constants/version.hpp>
#include <llarp.hpp>
#include <llarp/util/lokinet_init.h>
#include <llarp/ev/ev.hpp>
#include <llarp/util/exceptions.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/lokinet_init.h>
#include <llarp/util/thread/threading.hpp>
#ifdef _WIN32
#include <llarp/win32/service_manager.hpp>
#include <dbghelp.h>
#else
#include <llarp/util/service_manager.hpp>
#endif
#include <CLI/CLI.hpp>
#include <fmt/core.h>
#include <oxen/log.hpp>
#include <csignal>
#include <string>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <thread>
#include <future>
#include <utility>
#include <CLI/App.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/Config.hpp>
#ifdef _WIN32
#include <llarp/win32/service_manager.hpp>
#else
#include <llarp/util/service_manager.hpp>
#endif
namespace
{
@ -269,9 +274,9 @@ namespace
const auto flags =
(MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithFullMemoryInfo | MiniDumpWithHandleData | MiniDumpWithUnloadedModules | MiniDumpWithThreadInfo);
std::stringstream ss;
ss << "C:\\ProgramData\\lokinet\\crash-" << llarp::time_now_ms().count() << ".dmp";
const std::string fname = ss.str();
const std::string fname =
fmt::format("C:\\ProgramData\\lokinet\\crash-{}.dump", llarp::time_now_ms().count());
HANDLE hDumpFile;
SYSTEMTIME stLocalTime;
GetLocalTime(&stLocalTime);
@ -350,9 +355,6 @@ namespace
int
lokinet_main(int argc, char** argv)
{
if (auto result = Lokinet_INIT())
return result;
llarp::RuntimeOptions opts;
opts.showBanner = false;
@ -507,30 +509,8 @@ namespace
if (ctx and ctx->IsUp() and not ctx->LooksAlive())
{
auto deadlock_cat = llarp::log::Cat("deadlock");
for (const auto& wtf :
{"you have been visited by the mascot of the deadlocked router.",
"⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⣀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⢀⣀⣀⡀⠄⠄⠄⡠⢲⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡀⠄⠄",
"⠄⠄⠄⠔⣈⣀⠄⢔⡒⠳⡴⠊⠄⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣧⠄⠄",
"⠄⢜⡴⢑⠖⠊⢐⣤⠞⣩⡇⠄⠄⠄⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣆⠄⠝⠛⠋⠐",
"⢸⠏⣷⠈⠄⣱⠃⠄⢠⠃⠐⡀⠄⠄⠄⠄⠙⠻⢿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠸⠄⠄⠄⠄",
"⠈⣅⠞⢁⣿⢸⠘⡄⡆⠄⠄⠈⠢⡀⠄⠄⠄⠄⠄⠄⠉⠙⠛⠛⠛⠉⠉⡀⠄⠡⢀⠄⣀",
"⠄⠙⡎⣹⢸⠄⠆⢘⠁⠄⠄⠄⢸⠈⠢⢄⡀⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠃⠄⠄⠄⠄⠄",
"⠄⠄⠑⢿⠈⢆⠘⢼⠄⠄⠄⠄⠸⢐⢾⠄⡘⡏⠲⠆⠠⣤⢤⢤⡤⠄⣖⡇⠄⠄⠄⠄⠄",
"⣴⣶⣿⣿⣣⣈⣢⣸⠄⠄⠄⠄⡾⣷⣾⣮⣤⡏⠁⠘⠊⢠⣷⣾⡛⡟⠈⠄⠄⠄⠄⠄⠄",
"⣿⣿⣿⣿⣿⠉⠒⢽⠄⠄⠄⠄⡇⣿⣟⣿⡇⠄⠄⠄⠄⢸⣻⡿⡇⡇⠄⠄⠄⠄⠄⠄⠄",
"⠻⣿⣿⣿⣿⣄⠰⢼⠄⠄⠄⡄⠁⢻⣍⣯⠃⠄⠄⠄⠄⠈⢿⣻⠃⠈⡆⡄⠄⠄⠄⠄⠄",
"⠄⠙⠿⠿⠛⣿⣶⣤⡇⠄⠄⢣⠄⠄⠈⠄⢠⠂⠄⠁⠄⡀⠄⠄⣀⠔⢁⠃⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⣿⣿⣿⣿⣾⠢⣖⣶⣦⣤⣤⣬⣤⣤⣤⣴⣶⣶⡏⠠⢃⠌⠄⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⠿⠿⠟⠛⡹⠉⠛⠛⠿⠿⣿⣿⣿⣿⣿⡿⠂⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄",
"⠠⠤⠤⠄⠄⣀⠄⠄⠄⠑⠠⣤⣀⣀⣀⡘⣿⠿⠙⠻⡍⢀⡈⠂⠄⠄⠄⠄⠄⠄⠄⠄⠄",
"⠄⠄⠄⠄⠄⠄⠑⠠⣠⣴⣾⣿⣿⣿⣿⣿⣿⣇⠉⠄⠻⣿⣷⣄⡀⠄⠄⠄⠄⠄⠄⠄⠄",
"file a bug report now or be cursed with this "
"annoying image in your syslog for all time."})
{
llarp::log::critical(deadlock_cat, wtf);
llarp::log::flush();
}
llarp::log::critical(deadlock_cat, "Router is deadlocked!");
llarp::log::flush();
llarp::sys::service_manager->failed();
std::abort();
}
@ -651,6 +631,17 @@ main(int argc, char* argv[])
#ifndef _WIN32
return lokinet_main(argc, argv);
#else
if (auto hntdll = GetModuleHandle("ntdll.dll"))
{
if (GetProcAddress(hntdll, "wine_get_version"))
{
static const char* text = "Don't run lokinet in wine, aborting startup";
static const char* title = "Lokinet Wine Error";
MessageBoxA(NULL, text, title, MB_ICONHAND);
std::abort();
}
}
SERVICE_TABLE_ENTRY DispatchTable[] = {
{strdup("lokinet"), (LPSERVICE_MAIN_FUNCTION)win32_daemon_entry}, {NULL, NULL}};

@ -26,7 +26,9 @@ if(SUBMODULE_CHECK)
message(STATUS "Checking submodules")
check_submodule(CLI11)
check_submodule(cpr)
check_submodule(ghc-filesystem)
check_submodule(nlohmann)
check_submodule(oxen-encoding)
check_submodule(oxen-libquic)
check_submodule(oxen-mq)
check_submodule(pybind11)
@ -58,6 +60,7 @@ macro(system_or_submodule BIGNAME smallname pkgconf subdir)
endif()
endmacro()
system_or_submodule(OXENC oxenc liboxenc>=1.0.10 oxen-encoding)
system_or_submodule(OXENMQ oxenmq liboxenmq>=1.2.14 oxen-mq)
set(JSON_BuildTests OFF CACHE INTERNAL "")
@ -136,7 +139,10 @@ endif()
set(default_libcrypt OFF)
if(LINUX AND NOT STATIC_LINK)
set(default_libcrypt ON)
pkg_check_modules(LIBCRYPT libcrypt IMPORTED_TARGET)
if(LIBCRYPTO_FOUND)
set(default_libcrypt ON)
endif()
endif()
if(MACOS)
set(default_libcrypt ON)
@ -147,7 +153,7 @@ option(WITH_LIBCRYPT "enable fast password hash with libcrypt" ${default_libcryp
add_library(lokinet-libcrypt INTERFACE)
if(WITH_LIBCRYPT)
pkg_check_modules(LIBCRYPT libcrypt IMPORTED_TARGET REQUIRED)
add_definitions(-DHAVE_CRYPT)
target_compile_definitions(lokinet-libcrypt INTERFACE -DHAVE_CRYPT)
target_link_libraries(lokinet-libcrypt INTERFACE PkgConfig::LIBCRYPT)
message(STATUS "using libcrypt ${LIBCRYPT_VERSION}")
else()

@ -0,0 +1 @@
Subproject commit a7de63756dcc5c31cb899a4b810e6434b1a7c01c

@ -1 +1 @@
Subproject commit 33982d24a380268933ebea33976ad806e5c4e4bb
Subproject commit 6ee6ed398d00043d862466a56279b5c502513bff

2
external/oxen-mq vendored

@ -1 +1 @@
Subproject commit 68b3420bad5f0384f06d378b89ccdc06aba07465
Subproject commit a27961d787c9065f2bf6da9d60d01dca2e125739

@ -19,8 +19,6 @@ namespace llarp
struct Config;
struct RouterContact;
struct Config;
struct Crypto;
struct CryptoManager;
struct Router;
class NodeDB;
@ -38,8 +36,6 @@ namespace llarp
struct Context
{
std::shared_ptr<Crypto> crypto = nullptr;
std::shared_ptr<CryptoManager> cryptoManager = nullptr;
std::shared_ptr<Router> router = nullptr;
std::shared_ptr<EventLoop> loop = nullptr;
std::shared_ptr<NodeDB> nodedb = nullptr;

@ -1,8 +1,8 @@
#pragma once
#include "lokinet/lokinet_addr.h"
#include "lokinet/lokinet_context.h"
#include "lokinet/lokinet_srv.h"
#include "lokinet/lokinet_misc.h"
#include "lokinet/lokinet_addr.h"
#include "lokinet/lokinet_srv.h"
#include "lokinet/lokinet_stream.h"
#include "lokinet/lokinet_udp.h"

@ -1,7 +1,8 @@
#include "lokinet_jni_common.hpp"
#include "network_loki_lokinet_LokinetConfig.h"
#include <llarp.hpp>
#include <llarp/config/config.hpp>
#include "lokinet_jni_common.hpp"
extern "C"
{

@ -1,5 +1,6 @@
#include "network_loki_lokinet_LokinetDaemon.h"
#include "lokinet_jni_common.hpp"
#include "network_loki_lokinet_LokinetDaemon.h"
#include <llarp.hpp>
#include <llarp/config/config.hpp>
#include <llarp/router/router.hpp>

@ -1,8 +1,9 @@
#pragma once
#include <jni.h>
#include <string_view>
#include <functional>
#include <string_view>
/// visit string as native bytes
/// jvm uses some unholy encoding internally so we convert it to utf-8

@ -1,44 +1,116 @@
include(Version)
add_library(lokinet-cryptography
STATIC
# Add an internal lokinet static library target, enables LTO (if enabled) on the target,
# and links it to the common lokinet-base interface.
# Invoke with the target/library name (e.g. "lokinet-foo") and list of source files, e.g.
# lokinet_add_library(lokinet-foo foo/source1.cpp foo/source2.cpp)
function(lokinet_add_library libname)
add_library(${libname} STATIC ${ARGN})
target_link_libraries(${libname} PUBLIC lokinet-base)
enable_lto(${libname})
endfunction()
lokinet_add_library(lokinet-cryptography
crypto/crypto.cpp
crypto/encrypted_frame.cpp
crypto/types.cpp
)
add_library(lokinet-util
STATIC
# Functional objects use by lokinet-core and other libraries
# needed by vpn/ router/ rpc/ handlers/ net/ link/
lokinet_add_library(lokinet-core-utils
endpoint_base.cpp
exit/context.cpp
exit/endpoint.cpp # handlers/exit.hpp
exit/policy.cpp # net/
handlers/exit.cpp # link/ exit/
handlers/tun.cpp
router/rc_gossiper.cpp
service/auth.cpp # config/
service/context.cpp
service/identity.cpp
service/info.cpp
service/intro.cpp # path
service/lns_tracker.cpp
service/name.cpp
service/session.cpp
service/tag.cpp
vpn/egres_packet_router.cpp
)
lokinet_add_library(lokinet-core
context.cpp
consensus/reachability_testing.cpp
exit/session.cpp
link/link_manager.cpp
router/router.cpp
router/route_poker.cpp
service/async_key_exchange.cpp
service/endpoint_util.cpp
service/endpoint.cpp
service/endpoint_state.cpp
service/name.cpp
service/outbound_context.cpp
service/protocol.cpp
)
lokinet_add_library(lokinet-rpc
rpc/endpoint_rpc.cpp
rpc/json_binary_proxy.cpp
rpc/json_conversions.cpp
rpc/lokid_rpc_client.cpp
rpc/rpc_request_parser.cpp
rpc/rpc_server.cpp
)
lokinet_add_library(lokinet-wire
link/connection.cpp
link/contacts.cpp
link/link_manager.cpp
# link/tunnel.cpp
)
# config, crypto, timeplace, nodedb, bootstrap.cpp, net, router
lokinet_add_library(lokinet-utils
${CMAKE_CURRENT_BINARY_DIR}/constants/version.cpp
util/bencode.cpp
util/buffer.cpp
util/file.cpp
util/json.cpp
util/logging/buffer.cpp
util/easter_eggs.cpp
util/mem.cpp
util/str.cpp
util/thread/queue_manager.cpp
util/thread/threading.cpp
util/time.cpp)
util/thread/queue_manager.cpp
util/time.cpp
)
add_dependencies(lokinet-util genversion)
add_dependencies(lokinet-utils genversion)
# lokinet-platform holds all platform specific code
add_library(lokinet-platform
STATIC
# for networking
# Addressing and event loop files used by lokinet-core and other libraries
# needed by rpc/ link/ service/ config/ path/ dht/
lokinet_add_library(lokinet-time-place
ev/ev.cpp
ev/libuv.cpp
net/interface_info.cpp
net/exit_info.cpp # only router_contact
net/ip.cpp
net/ip_address.cpp
net/ip_packet.cpp
net/ip_range.cpp
net/net_int.cpp
net/sock_addr.cpp
router_contact.cpp
router_id.cpp
router_version.cpp # to be deleted shortly
service/address.cpp
service/convotag.cpp
service/intro_set.cpp
)
# lokinet-platform holds all platform specific code
lokinet_add_library(lokinet-platform
net/interface_info.cpp
router/rc_lookup_handler.cpp
vpn/packet_router.cpp
vpn/egres_packet_router.cpp
vpn/platform.cpp
)
@ -78,39 +150,31 @@ endif()
# lokinet-dns is the dns parsing and hooking library that we use to
# parse modify and reconstitute dns wire proto, dns queries and RR
# should have no concept of dns caching, this is left as an implementation
# detail of dns resolvers (LATER: make separate lib for dns resolvers)
add_library(lokinet-dns
STATIC
dns/message.cpp
dns/name.cpp
lokinet_add_library(lokinet-dns
dns/message.cpp # dns/server
dns/name.cpp # srv_data, question, rr
dns/platform.cpp
dns/question.cpp
dns/question.cpp # message
dns/rr.cpp
dns/serialize.cpp
dns/server.cpp
dns/srv_data.cpp)
dns/server.cpp # handlers/exit+tun and service/endpoint
dns/srv_data.cpp
)
# platform specific bits and bobs for setting dns
add_library(lokinet-dns-platform INTERFACE)
if(WITH_SYSTEMD)
add_library(lokinet-dns-systemd STATIC dns/nm_platform.cpp dns/sd_platform.cpp)
lokinet_add_library(lokinet-dns-systemd dns/nm_platform.cpp dns/sd_platform.cpp)
target_link_libraries(lokinet-dns-platform INTERFACE lokinet-dns-systemd)
endif()
# lokinet-nodedb holds all types and logic for storing parsing and constructing
# nodedb data published to the network and versions of it stored locally
add_library(lokinet-nodedb
STATIC
bootstrap.cpp
net/exit_info.cpp
net/traffic_policy.cpp
lokinet_add_library(lokinet-nodedb
bootstrap.cpp # config, router.hpp
net/traffic_policy.cpp # config, intro_set
nodedb.cpp
pow.cpp
profiling.cpp
router_contact.cpp
router_id.cpp
router_version.cpp
profiling.cpp # path, router, service::endpoint
)
set(BOOTSTRAP_FALLBACKS)
@ -133,296 +197,98 @@ configure_file("bootstrap-fallbacks.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/bootstr
target_sources(lokinet-nodedb PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/bootstrap-fallbacks.cpp")
# lokinet-config is for all configuration types and parsers
add_library(lokinet-config
STATIC
lokinet_add_library(lokinet-config
config/config.cpp
config/definition.cpp
config/ini.cpp
config/key_manager.cpp
)
# lokinet-consensus is for deriving and tracking network consensus state for both service nodes and clients
add_library(lokinet-consensus
STATIC
consensus/reachability_testing.cpp
)
# lokinet-layer-onion is the "dumb" onion routing layer with builds manages and does i/o
# with onion paths. onion paths anonymize routing layer pdu.
add_library(lokinet-layer-onion
STATIC
# All path objects; link directly to lokinet-core
lokinet_add_library(lokinet-path
messages/relay.cpp
path/abstracthophandler.cpp
path/path_context.cpp
path/path.cpp
path/path_context.cpp
path/pathbuilder.cpp
path/pathset.cpp
path/transit_hop.cpp
messages/relay.cpp
)
# lokinet-layer-link is for our layer 2 analog which splits up layer 2 frames into
# a series of layer 1 symbols which are then transmitted between lokinet instances
add_library(lokinet-layer-link
STATIC
link/connection.cpp
link/contacts.cpp
link/link_manager.cpp
# link/tunnel.cpp
# Link libraries to their internals
target_link_libraries(lokinet-core-utils PUBLIC lokinet-dns)
target_link_libraries(lokinet-core PUBLIC lokinet-core-utils)
# Link lokinet-dns to alternate libraries
target_link_libraries(lokinet-dns PUBLIC lokinet-dns-platform)
target_link_libraries(lokinet-wire PUBLIC lokinet-time-place)
target_link_libraries(lokinet-dns PUBLIC lokinet-utils lokinet-cryptography lokinet-config)
target_link_libraries(lokinet-nodedb PUBLIC lokinet-time-place lokinet-cryptography)
target_link_libraries(lokinet-platform PUBLIC lokinet-cryptography)
target_link_libraries(lokinet-rpc PUBLIC lokinet-wire)
target_link_libraries(lokinet-time-place PUBLIC lokinet-utils lokinet-cryptography)
target_link_libraries(lokinet-wire PUBLIC lokinet-cryptography)
target_link_libraries(lokinet-config PUBLIC lokinet-cryptography)
target_link_libraries(lokinet-dns
PUBLIC
lokinet-time-place
)
# lokinet-context holds the contextualized god objects for a lokinet instance
# it is what any main function would link to in practice but it is hidden behind an interface library (lokinet-amalgum)
add_library(lokinet-context
STATIC
context.cpp
link/link_manager.cpp
router/rc_lookup_handler.cpp
router/rc_gossiper.cpp
router/router.cpp
router/route_poker.cpp
target_link_libraries(lokinet-path
PUBLIC
lokinet-time-place
)
# lokinet-rpc holds all rpc related compilation units
add_library(lokinet-rpc
STATIC
rpc/json_binary_proxy.cpp
rpc/json_conversions.cpp
rpc/lokid_rpc_client.cpp
rpc/rpc_request_parser.cpp
rpc/rpc_server.cpp
rpc/endpoint_rpc.cpp
)
# optional peer stats library
add_library(lokinet-peerstats
STATIC
peerstats/peer_db.cpp
peerstats/types.cpp
)
# kitchen sink to be removed after refactor
add_library(lokinet-service-deprecated-kitchensink
STATIC
endpoint_base.cpp
exit/context.cpp
exit/endpoint.cpp
exit/exit_messages.cpp
exit/policy.cpp
exit/session.cpp
handlers/exit.cpp
handlers/tun.cpp
service/name.cpp
service/address.cpp
service/async_key_exchange.cpp
service/auth.cpp
service/convotag.cpp
service/context.cpp
service/endpoint_state.cpp
service/endpoint_util.cpp
service/endpoint.cpp
service/identity.cpp
service/info.cpp
service/intro_set.cpp
service/intro.cpp
service/lns_tracker.cpp
service/name.cpp
service/outbound_context.cpp
service/protocol.cpp
service/sendcontext.cpp
service/session.cpp
service/tag.cpp
)
# interal tooling for pybind
add_library(lokinet-tooling INTERFACE)
if(WITH_HIVE)
add_library(lokinet-hive-tooling
STATIC
tooling/router_hive.cpp
tooling/hive_router.cpp
tooling/hive_context.cpp
)
target_link_libraries(lokinet-tooling INTERFACE lokinet-hive-tooling)
endif()
# interface library for setting commone includes, linkage and flags.
add_library(lokinet-base INTERFACE)
target_include_directories(lokinet-base
INTERFACE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include
)
target_link_libraries(lokinet-base INTERFACE quic)
if(WITH_PEERSTATS)
target_compile_definitions(lokinet-base INTERFACE -DLOKINET_PEERSTATS_BACKEND)
target_link_libraries(lokinet-base INTERFACE sqlite_orm)
endif()
# interface libraries for internal linkage
add_library(lokinet-layers INTERFACE)
add_library(lokinet-amalgum INTERFACE)
# helper function to link a library to lokinet-base, enable lto, add to lokinet-amalgum and then link to other libs
function(lokinet_link_lib libname)
message(DEBUG "created target: ${libname}")
enable_lto(${libname})
target_link_libraries(${libname} PUBLIC lokinet-base ${ARGN})
target_link_libraries(lokinet-amalgum INTERFACE ${libname})
endfunction()
# internal public linkages of components
lokinet_link_lib(lokinet-util lokinet-libntrup)
lokinet_link_lib(lokinet-cryptography lokinet-libcrypt lokinet-util)
lokinet_link_lib(lokinet-peerstats lokinet-context)
lokinet_link_lib(lokinet-consensus lokinet-context)
lokinet_link_lib(lokinet-layer-link lokinet-peerstats)
if(TARGET lokinet-hive-tooling)
lokinet_link_lib(lokinet-hive-tooling lokinet-context)
endif()
if(TARGET lokinet-dns-systemd)
lokinet_link_lib(lokinet-dns-systemd
lokinet-dns
lokinet-platform
)
endif()
lokinet_link_lib(lokinet-platform lokinet-util)
lokinet_link_lib(lokinet-config
lokinet-util
lokinet-nodedb
lokinet-dns
lokinet-platform
)
lokinet_link_lib(lokinet-context
target_link_libraries(lokinet-core-utils
PUBLIC
lokinet-config
lokinet-platform
lokinet-peerstats
lokinet-layers
lokinet-consensus
lokinet-rpc
)
lokinet_link_lib(
lokinet-platform
lokinet-config
lokinet-rpc
lokinet-wire
)
lokinet_link_lib(lokinet-dns
lokinet-platform
lokinet-dns-platform
lokinet-config
target_link_libraries(lokinet-cryptography
PUBLIC
lokinet-libcrypt
lokinet-libntrup
)
lokinet_link_lib(lokinet-nodedb
lokinet-util
lokinet-platform
target_link_libraries(lokinet-utils
PUBLIC
lokinet-cryptography
)
lokinet_link_lib(lokinet-util
# cross linkage
target_link_libraries(lokinet-core
PUBLIC
lokinet-cryptography
lokinet-nodedb
lokinet-platform
)
lokinet_link_lib(lokinet-rpc
lokinet-context
lokinet-peerstats
lokinet-util
)
# inter lokinet-layer public/private linkage.
# when linking each layer, we consider the layer directly below private linkage and the layer above public linkage.
# this lets us hide functionality of layers below us when depended on by another component.
#
# from highest to lowest layer, the above layers are stacked as follows:
#
# platform (what lokinet snapps interact with, be it l3 os interaction or embedded lokinet)
# flow (how we want to route and stripe over our onion routing)
# routing (what we are onion routing)
# onion (how the onion routing happens)
# link (what we want to send over the wire and to where)
# wire (what is actually sent over the wire)
#
function(link_lokinet_layers)
set(lib ${ARGV0})
if(${ARGC} GREATER 1)
lokinet_link_lib(${ARGV1} ${lib})
list(REMOVE_AT ARGV 1)
target_link_libraries(${lib} PRIVATE ${ARGV1})
# recursion :D
link_lokinet_layers(${ARGV})
else()
lokinet_link_lib(${lib})
endif()
endfunction()
link_lokinet_layers(
lokinet-layer-onion
lokinet-layer-link
lokinet-path
lokinet-rpc
lokinet-wire
)
# set me to OFF to disable old codepath
set(use_old_impl ON)
if(use_old_impl)
# flow layer deprecated-kitchensink (remove me after refactor)
lokinet_link_lib(lokinet-service-deprecated-kitchensink
lokinet-dns
lokinet-nodedb
lokinet-context
lokinet-layer-onion
lokinet-platform
lokinet-rpc
)
target_link_libraries(lokinet-layers INTERFACE lokinet-service-deprecated-kitchensink)
endif()
target_link_libraries(lokinet-layers INTERFACE
lokinet-layer-onion
lokinet-layer-link
)
# per component external deps
target_link_libraries(lokinet-base INTERFACE oxenc::oxenc oxen::logging)
target_link_libraries(lokinet-rpc PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-core PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-config PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-nodedb PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-path PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-time-place PUBLIC uvw)
target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq Threads::Threads uvw)
target_link_libraries(lokinet-cryptography PUBLIC sodium)
target_link_libraries(lokinet-dns PUBLIC libunbound)
target_link_libraries(lokinet-cryptography PUBLIC
oxenc::oxenc
sodium
)
target_link_libraries(lokinet-context PUBLIC
CLI11
oxenmq::oxenmq
uvw
)
target_link_libraries(lokinet-platform PUBLIC
Threads::Threads
base_libs
uvw
)
target_link_libraries(lokinet-util PUBLIC
nlohmann_json::nlohmann_json
# filesystem
oxenc::oxenc
)
target_link_libraries(lokinet-layer-link PUBLIC
quic
uvw
)
target_link_libraries(lokinet-utils PUBLIC nlohmann_json::nlohmann_json)
target_link_libraries(lokinet-wire PUBLIC oxenmq::oxenmq quic)
if(WITH_EMBEDDED_LOKINET)
include(GNUInstallDirs)
add_library(lokinet-shared SHARED lokinet_shared.cpp)
target_link_libraries(lokinet-shared PUBLIC lokinet-amalgum)
# target_link_libraries(lokinet-shared PUBLIC lokinet-amalgum)
target_link_libraries(lokinet-shared PUBLIC lokinet-core)
if(WIN32)
set(CMAKE_SHARED_LIBRARY_PREFIX_CXX "")
endif()

@ -24,17 +24,17 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ifaddrs.h"
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netpacket/packet.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
typedef struct NetlinkList
{

@ -23,8 +23,7 @@
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
*/
#ifndef _IFADDRS_H_
#define _IFADDRS_H_
#pragma once
struct ifaddrs
{
@ -53,5 +52,3 @@ getifaddrs(struct ifaddrs** ifap);
extern void
freeifaddrs(struct ifaddrs* ifa);
__END_DECLS
#endif

@ -11,7 +11,7 @@ find_library(FOUNDATION Foundation REQUIRED)
find_library(NETEXT NetworkExtension REQUIRED)
find_library(COREFOUNDATION CoreFoundation REQUIRED)
target_link_libraries(lokinet-util PUBLIC ${FOUNDATION})
target_link_libraries(lokinet-base INTERFACE ${FOUNDATION})
target_sources(lokinet-platform PRIVATE vpn_platform.cpp vpn_interface.cpp route_manager.cpp context_wrapper.cpp)
@ -27,7 +27,7 @@ enable_lto(lokinet-extension)
target_compile_options(lokinet-extension PRIVATE -fobjc-arc)
if(MACOS_SYSTEM_EXTENSION)
target_compile_definitions(lokinet-extension PRIVATE MACOS_SYSTEM_EXTENSION)
target_compile_definitions(lokinet-util PUBLIC MACOS_SYSTEM_EXTENSION)
target_compile_definitions(lokinet-base INTERFACE MACOS_SYSTEM_EXTENSION)
else()
target_link_options(lokinet-extension PRIVATE -e _NSExtensionMain)
endif()
@ -41,7 +41,7 @@ else()
endif()
target_link_libraries(lokinet-extension PRIVATE
lokinet-amalgum
lokinet-core
${COREFOUNDATION}
${NETEXT})

@ -1,6 +1,6 @@
#pragma once
#include <uv.h>
#include <NetworkExtension/NetworkExtension.h>
#include <uv.h>
extern NSString* error_domain;

@ -1,4 +1,5 @@
#include "DNSTrampoline.h"
#include <uv.h>
NSString* error_domain = @"org.lokinet";

@ -1,8 +1,9 @@
#include <Foundation/Foundation.h>
#include <NetworkExtension/NetworkExtension.h>
#include "context_wrapper.h"
#include "DNSTrampoline.h"
#include <Foundation/Foundation.h>
#include <NetworkExtension/NetworkExtension.h>
#define LLARP_APPLE_PACKET_BUF_SIZE 64
@interface LLARPPacketTunnel : NEPacketTunnelProvider

@ -1,8 +1,9 @@
#pragma once
#include <llarp.hpp>
#include "vpn_platform.hpp"
#include "route_manager.hpp"
#include "vpn_platform.hpp"
#include <llarp.hpp>
namespace llarp::apple
{

@ -1,17 +1,22 @@
#include <cstdint>
#include <cstring>
#include <cassert>
#include <llarp/net/ip_packet.hpp>
#include "context_wrapper.h"
#include "context.hpp"
#include "vpn_interface.hpp"
#include <llarp/config/config.hpp>
#include <llarp/constants/apple.hpp>
#include <llarp/ev/libuv.hpp>
#include <llarp/net/ip_packet.hpp>
#include <llarp/util/fs.hpp>
#include <uvw/loop.h>
#include <llarp/util/logging.hpp>
#include <llarp/util/logging/buffer.hpp>
#include <llarp/util/logging/callback_sink.hpp>
#include "vpn_interface.hpp"
#include "context_wrapper.h"
#include "context.hpp"
// #include <uvw/loop.h>
#include <cassert>
#include <cstdint>
#include <cstring>
namespace
{

@ -8,8 +8,8 @@ extern "C"
{
#endif
#include <unistd.h>
#include <sys/socket.h>
#include <unistd.h>
#include <uv.h>
// Port (on localhost) for our DNS trampoline for bouncing DNS requests through the exit route

@ -1,7 +1,9 @@
#include "route_manager.hpp"
#include <llarp.hpp>
#include <llarp/handlers/tun.hpp>
#include <llarp/service/context.hpp>
#include <llarp.hpp>
#include <memory>
namespace llarp::apple

@ -1,8 +1,9 @@
#pragma once
#include "context_wrapper.h"
#include <llarp/router/router.hpp>
#include <llarp/vpn/platform.hpp>
#include "context_wrapper.h"
namespace llarp::apple
{

@ -1,6 +1,8 @@
#include "vpn_interface.hpp"
#include "context.hpp"
#include <llarp/router/router.hpp>
namespace llarp::apple

@ -1,8 +1,9 @@
#pragma once
#include <llarp.hpp>
#include <llarp/vpn/platform.hpp>
#include <llarp/util/thread/queue.hpp>
#include <llarp/vpn/platform.hpp>
#include <memory>
namespace llarp::apple

@ -1,4 +1,5 @@
#include "vpn_platform.hpp"
#include "context.hpp"
namespace llarp::apple

@ -1,8 +1,9 @@
#pragma once
#include <llarp/vpn/platform.hpp>
#include "vpn_interface.hpp"
#include "route_manager.hpp"
#include "vpn_interface.hpp"
#include <llarp/vpn/platform.hpp>
namespace llarp::apple
{

@ -1,5 +1,5 @@
#include <initializer_list>
#include "llarp/bootstrap.hpp"
#include <llarp/bootstrap.hpp>
namespace llarp
{

@ -1,8 +1,8 @@
#include "bootstrap.hpp"
#include "util/bencode.hpp"
#include "util/logging.hpp"
#include "util/logging/buffer.hpp"
#include "util/fs.hpp"
namespace llarp
{

@ -1,9 +1,11 @@
#pragma once
#include "router_contact.hpp"
#include <llarp/util/fs.hpp>
#include <set>
#include <unordered_map>
#include "llarp/util/fs.hpp"
namespace llarp
{

@ -0,0 +1,26 @@
#include <llarp/bootstrap.hpp>
#include <initializer_list>
namespace llarp
{
using namespace std::literals;
std::unordered_map<std::string, BootstrapList>
load_bootstrap_fallbacks()
{
std::unordered_map<std::string, BootstrapList> fallbacks;
using init_list = std::initializer_list<std::pair<std::string, std::string_view>>;
// clang-format off
for (const auto& [network, bootstrap] : init_list{
//
})
// clang-format on
{
llarp_buffer_t buf{bootstrap.data(), bootstrap.size()};
auto& bsl = fallbacks[network];
bsl.BDecode(&buf);
}
return fallbacks;
}
} // namespace llarp

@ -1,26 +1,20 @@
#include "config.hpp"
#include "definition.hpp"
#include "ini.hpp"
#include <llarp/constants/files.hpp>
#include <llarp/constants/platform.hpp>
#include <llarp/constants/version.hpp>
#include <llarp/net/net.hpp>
#include <llarp/net/ip.hpp>
#include <llarp/net/net.hpp>
#include <llarp/router_contact.hpp>
#include <stdexcept>
#include <llarp/service/name.hpp>
#include <llarp/util/file.hpp>
#include <llarp/util/formattable.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/mem.hpp>
#include <llarp/util/str.hpp>
#include <llarp/service/name.hpp>
#include <chrono>
#include <cstdlib>
#include <ios>
#include <iostream>
#include <stdexcept>
namespace llarp
{

@ -1,35 +1,33 @@
#pragma once
#include "ini.hpp"
#include "definition.hpp"
#include <llarp/net/traffic_policy.hpp>
#include <llarp/net/net.hpp>
#include <chrono>
#include "ini.hpp"
#include <llarp/bootstrap.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/constants/files.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/dns/srv_data.hpp>
#include <llarp/net/ip_address.hpp>
#include <llarp/net/net_int.hpp>
#include <llarp/net/ip_range_map.hpp>
#include <llarp/net/net.hpp>
#include <llarp/net/net_int.hpp>
#include <llarp/net/traffic_policy.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/service/address.hpp>
#include <llarp/service/auth.hpp>
#include <llarp/dns/srv_data.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/str.hpp>
#include <oxenmq/address.h>
#include <chrono>
#include <cstdlib>
#include <functional>
#include <optional>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <unordered_set>
#include <oxenmq/address.h>
namespace llarp
{
@ -187,6 +185,7 @@ namespace llarp
defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params);
};
// TODO: remove oxenmq from this header
struct ApiConfig
{
bool m_enableRPCServer = false;

@ -1,9 +1,10 @@
#include "definition.hpp"
#include <llarp/util/logging.hpp>
#include <cassert>
#include <iterator>
#include <stdexcept>
#include <cassert>
namespace llarp
{

@ -1,21 +1,22 @@
#pragma once
#include <fmt/core.h>
#include <initializer_list>
#include <type_traits>
#include <llarp/util/str.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/str.hpp>
#include <fmt/core.h>
#include <cassert>
#include <functional>
#include <initializer_list>
#include <iostream>
#include <memory>
#include <optional>
#include <set>
#include <sstream>
#include <stdexcept>
#include <type_traits>
#include <unordered_map>
#include <vector>
#include <functional>
#include <optional>
#include <cassert>
namespace llarp
{

@ -1,14 +1,11 @@
#include "ini.hpp"
#include <llarp/util/logging.hpp>
#include <llarp/util/formattable.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/logging.hpp>
#include <cctype>
#include <fstream>
#include <list>
#include <iostream>
#include <cassert>
#include <stdexcept>
namespace llarp

@ -1,12 +1,13 @@
#pragma once
#include <string_view>
#include <string>
#include <llarp/util/file.hpp>
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
#include <llarp/util/file.hpp>
namespace llarp
{

@ -1,10 +1,12 @@
#include "key_manager.hpp"
#include <system_error>
#include <llarp/util/logging.hpp>
#include "config.hpp"
#include <llarp/crypto/crypto.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/util/logging.hpp>
#include <system_error>
namespace llarp
{
@ -19,9 +21,9 @@ namespace llarp
if (not isSNode)
{
CryptoManager::instance()->identity_keygen(identityKey);
CryptoManager::instance()->encryption_keygen(encryptionKey);
CryptoManager::instance()->encryption_keygen(transportKey);
crypto::identity_keygen(identityKey);
crypto::encryption_keygen(encryptionKey);
crypto::encryption_keygen(transportKey);
return true;
}
@ -93,23 +95,21 @@ namespace llarp
// load identity key or create if needed
auto identityKeygen = [](llarp::SecretKey& key) {
// TODO: handle generating from service node seed
llarp::CryptoManager::instance()->identity_keygen(key);
llarp::crypto::identity_keygen(key);
};
if (not loadOrCreateKey(m_idKeyPath, identityKey, identityKeygen))
return false;
}
// load encryption key
auto encryptionKeygen = [](llarp::SecretKey& key) {
llarp::CryptoManager::instance()->encryption_keygen(key);
};
auto encryptionKeygen = [](llarp::SecretKey& key) { llarp::crypto::encryption_keygen(key); };
if (not loadOrCreateKey(m_encKeyPath, encryptionKey, encryptionKeygen))
return false;
// TODO: transport key (currently done in LinkLayer)
auto transportKeygen = [](llarp::SecretKey& key) {
key.Zero();
CryptoManager::instance()->encryption_keygen(key);
crypto::encryption_keygen(key);
};
if (not loadOrCreateKey(m_transportKeyPath, transportKey, transportKeygen))
return false;

@ -1,10 +1,12 @@
#pragma once
#include <atomic>
#include "config.hpp"
#include <llarp/crypto/types.hpp>
#include <llarp/router_contact.hpp>
#include <atomic>
namespace llarp
{
/// KeyManager manages the cryptographic keys stored on disk for the local

@ -1,9 +1,9 @@
#include "reachability_testing.hpp"
#include <chrono>
#include <llarp/crypto/crypto.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/crypto/crypto.hpp>
using std::chrono::steady_clock;
@ -76,9 +76,9 @@ namespace llarp::consensus
{
if (next_general_test > now)
return std::nullopt;
CSRNG rng;
next_general_test =
now + std::chrono::duration_cast<time_point_t::duration>(fseconds(TESTING_INTERVAL(rng)));
next_general_test = now
+ std::chrono::duration_cast<time_point_t::duration>(
fseconds(TESTING_INTERVAL(llarp::csrng)));
// Pull the next element off the queue, but skip ourself, any that are no longer registered, and
// any that are currently known to be failing (those are queued for testing separately).
@ -107,7 +107,7 @@ namespace llarp::consensus
const auto all = router->router_whitelist();
testing_queue.insert(testing_queue.begin(), all.begin(), all.end());
std::shuffle(testing_queue.begin(), testing_queue.end(), rng);
std::shuffle(testing_queue.begin(), testing_queue.end(), llarp::csrng);
// Recurse with the rebuilt list, but don't let it try rebuilding again
return next_random(router, now, false);
@ -138,9 +138,8 @@ namespace llarp::consensus
if (previous_failures < 0)
previous_failures = 0;
CSRNG rng;
auto next_test_in = duration_cast<time_point_t::duration>(
previous_failures * TESTING_BACKOFF + fseconds{TESTING_INTERVAL(rng)});
previous_failures * TESTING_BACKOFF + fseconds{TESTING_INTERVAL(llarp::csrng)});
if (next_test_in > TESTING_BACKOFF_MAX)
next_test_in = TESTING_BACKOFF_MAX;

@ -1,5 +1,8 @@
#pragma once
#include <llarp/router_id.hpp>
#include <llarp/util/time.hpp>
#include <chrono>
#include <queue>
#include <random>
@ -7,9 +10,6 @@
#include <unordered_set>
#include <vector>
#include <llarp/util/time.hpp>
#include <llarp/router_id.hpp>
namespace llarp
{
struct Router;

@ -1,7 +0,0 @@
#pragma once
namespace llarp
{
/// default queue length for logic jobs
constexpr std::size_t event_loop_queue_size = 1024;
} // namespace llarp

@ -6,8 +6,8 @@
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#include <pwd.h>
#include <unistd.h>
#endif
namespace llarp

@ -1,6 +1,6 @@
#pragma once
#include <llarp/util/types.hpp>
#include <llarp/util/time.hpp>
#include <llarp/util/types.hpp>
#include <cstdlib>

@ -1,11 +1,11 @@
#pragma once
#include <llarp/util/time.hpp>
#include <llarp/util/types.hpp>
#include <chrono>
#include <cstddef>
#include <llarp/util/types.hpp>
#include <llarp/util/time.hpp>
namespace llarp::path
{
/// maximum path length

@ -1,7 +1,7 @@
#pragma once
#include <cstdint>
#include <array>
#include <cstdint>
namespace llarp
{

@ -1,23 +1,16 @@
#include <llarp.hpp>
#include "constants/version.hpp"
#include "constants/evloop.hpp"
#include "config/config.hpp"
#include "crypto/crypto.hpp"
#include "ev/ev.hpp"
#include <memory>
#include "nodedb.hpp"
#include "router/router.hpp"
#include "service/context.hpp"
#include "util/logging.hpp"
#include <llarp.hpp>
#include <llarp/config/config.hpp>
#include <llarp/constants/version.hpp>
#include <llarp/crypto/crypto.hpp>
#include <llarp/ev/ev.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/service_manager.hpp>
#include <CLI/App.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/Config.hpp>
#include <csignal>
#include <memory>
#include <stdexcept>
#if (__FreeBSD__) || (__OpenBSD__) || (__NetBSD__)
@ -74,9 +67,6 @@ namespace llarp
loop = EventLoop::create(jobQueueSize);
}
crypto = std::make_shared<Crypto>();
cryptoManager = std::make_shared<CryptoManager>(crypto.get());
router = makeRouter(loop);
nodedb = makeNodeDB();
@ -89,7 +79,9 @@ namespace llarp
Context::makeNodeDB()
{
return std::make_shared<NodeDB>(
nodedb_dirname, [r = router.get()](auto call) { r->queue_disk_io(std::move(call)); });
nodedb_dirname,
[r = router.get()](auto call) { r->queue_disk_io(std::move(call)); },
router.get());
}
std::shared_ptr<Router>

@ -1,9 +1,9 @@
#pragma once
#include <cstdint>
#include <libntrup/ntru.h>
#include <cstdint>
static constexpr uint32_t PUBKEYSIZE = 32;
static constexpr uint32_t SECKEYSIZE = 64;
static constexpr uint32_t NONCESIZE = 24;

@ -1,26 +1,22 @@
#include "crypto.hpp"
#include <oxenc/endian.h>
#include <sodium/core.h>
#include <sodium/crypto_aead_xchacha20poly1305.h>
#include <sodium/crypto_core_ed25519.h>
#include <sodium/crypto_generichash.h>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_scalarmult.h>
#include <sodium/crypto_scalarmult_curve25519.h>
#include <sodium/crypto_scalarmult_ed25519.h>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_stream_xchacha20.h>
#include <sodium/crypto_core_ed25519.h>
#include <sodium/crypto_aead_xchacha20poly1305.h>
#include <sodium/randombytes.h>
#include <sodium/utils.h>
#include <oxenc/endian.h>
#include <llarp/util/mem.hpp>
#include <llarp/util/str.hpp>
#include <cassert>
#include <cstring>
#ifdef HAVE_CRYPT
#include <crypt.h>
#endif
#include <llarp/util/str.hpp>
namespace llarp
{
static bool
@ -113,28 +109,8 @@ namespace llarp
return false;
}
Crypto::Crypto()
{
if (sodium_init() == -1)
{
throw std::runtime_error("sodium_init() returned -1");
}
char* avx2 = std::getenv("AVX2_FORCE_DISABLE");
if (avx2 && std::string(avx2) == "1")
{
ntru_init(1);
}
else
{
ntru_init(0);
}
int seed = 0;
randombytes(reinterpret_cast<unsigned char*>(&seed), sizeof(seed));
srand(seed);
}
std::optional<AlignedBuffer<32>>
Crypto::maybe_decrypt_name(std::string_view ciphertext, SymmNonce nounce, std::string_view name)
crypto::maybe_decrypt_name(std::string_view ciphertext, SymmNonce nonce, std::string_view name)
{
const auto payloadsize = ciphertext.size() - crypto_aead_xchacha20poly1305_ietf_ABYTES;
if (payloadsize != 32)
@ -157,7 +133,7 @@ namespace llarp
ciphertext.size(),
nullptr,
0,
nounce.data(),
nonce.data(),
derivedKey.data())
== -1)
{
@ -167,32 +143,33 @@ namespace llarp
}
bool
Crypto::xchacha20(uint8_t* buf, size_t size, const SharedSecret& k, const TunnelNonce& n)
crypto::xchacha20(uint8_t* buf, size_t size, const SharedSecret& k, const TunnelNonce& n)
{
return crypto_stream_xchacha20_xor(buf, buf, size, n.data(), k.data()) == 0;
return xchacha20(buf, size, n.data(), k.data());
}
bool
Crypto::xchacha20(uint8_t* buf, size_t size, const uint8_t* secret, const uint8_t* nonce)
crypto::xchacha20(uint8_t* buf, size_t size, const uint8_t* secret, const uint8_t* nonce)
{
return crypto_stream_xchacha20_xor(buf, buf, size, nonce, secret) == 0;
}
bool
Crypto::dh_client(
crypto::dh_client(
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
{
return dh_client_priv(shared, pk, sk, n);
}
/// path dh relay side
bool
Crypto::dh_server(
crypto::dh_server(
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
{
return dh_server_priv(shared, pk, sk, n);
}
bool
Crypto::dh_server(
crypto::dh_server(
uint8_t* shared_secret,
const uint8_t* other_pk,
const uint8_t* local_pk,
@ -202,27 +179,27 @@ namespace llarp
}
/// transport dh client side
bool
Crypto::transport_dh_client(
crypto::transport_dh_client(
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
{
return dh_client_priv(shared, pk, sk, n);
}
/// transport dh server side
bool
Crypto::transport_dh_server(
crypto::transport_dh_server(
llarp::SharedSecret& shared, const PubKey& pk, const SecretKey& sk, const TunnelNonce& n)
{
return dh_server_priv(shared, pk, sk, n);
}
bool
Crypto::shorthash(ShortHash& result, uint8_t* buf, size_t size)
crypto::shorthash(ShortHash& result, uint8_t* buf, size_t size)
{
return crypto_generichash_blake2b(result.data(), ShortHash::SIZE, buf, size, nullptr, 0) != -1;
}
bool
Crypto::hmac(uint8_t* result, uint8_t* buf, size_t size, const SharedSecret& secret)
crypto::hmac(uint8_t* result, uint8_t* buf, size_t size, const SharedSecret& secret)
{
return crypto_generichash_blake2b(result, HMACSIZE, buf, size, secret.data(), HMACSECSIZE)
!= -1;
@ -235,25 +212,25 @@ namespace llarp
}
bool
Crypto::sign(Signature& sig, const SecretKey& secret, uint8_t* buf, size_t size)
crypto::sign(Signature& sig, const SecretKey& secret, uint8_t* buf, size_t size)
{
return crypto_sign_detached(sig.data(), nullptr, buf, size, secret.data()) != -1;
}
bool
Crypto::sign(uint8_t* sig, uint8_t* sk, uint8_t* buf, size_t size)
crypto::sign(uint8_t* sig, uint8_t* sk, uint8_t* buf, size_t size)
{
return crypto_sign_detached(sig, nullptr, buf, size, sk) != -1;
}
bool
Crypto::sign(uint8_t* sig, const SecretKey& sk, ustring_view buf)
crypto::sign(uint8_t* sig, const SecretKey& sk, ustring_view buf)
{
return crypto_sign_detached(sig, nullptr, buf.data(), buf.size(), sk.data()) != -1;
}
bool
Crypto::sign(Signature& sig, const PrivateKey& privkey, uint8_t* buf, size_t size)
crypto::sign(Signature& sig, const PrivateKey& privkey, uint8_t* buf, size_t size)
{
PubKey pubkey;
@ -297,13 +274,13 @@ namespace llarp
}
bool
Crypto::verify(const PubKey& pub, uint8_t* buf, size_t size, const Signature& sig)
crypto::verify(const PubKey& pub, uint8_t* buf, size_t size, const Signature& sig)
{
return crypto_sign_verify_detached(sig.data(), buf, size, pub.data()) != -1;
}
bool
Crypto::verify(ustring_view pub, ustring_view buf, ustring_view sig)
crypto::verify(ustring_view pub, ustring_view buf, ustring_view sig)
{
return (pub.size() == 32 && sig.size() == 64)
? crypto_sign_verify_detached(sig.data(), buf.data(), buf.size(), pub.data()) != -1
@ -311,7 +288,7 @@ namespace llarp
}
bool
Crypto::verify(uint8_t* pub, uint8_t* buf, size_t size, uint8_t* sig)
crypto::verify(uint8_t* pub, uint8_t* buf, size_t size, uint8_t* sig)
{
return crypto_sign_verify_detached(sig, buf, size, pub) != -1;
}
@ -368,7 +345,7 @@ namespace llarp
static AlignedBuffer<32> zero;
bool
Crypto::derive_subkey(
crypto::derive_subkey(
PubKey& out_pubkey, const PubKey& root_pubkey, uint64_t key_n, const AlignedBuffer<32>* hash)
{
// scalar h = H( BLIND-STRING || root_pubkey || key_n )
@ -385,7 +362,7 @@ namespace llarp
}
bool
Crypto::derive_subkey_private(
crypto::derive_subkey_private(
PrivateKey& out_key, const SecretKey& root_key, uint64_t key_n, const AlignedBuffer<32>* hash)
{
// Derives a private subkey from a root key.
@ -452,24 +429,24 @@ namespace llarp
}
bool
Crypto::seed_to_secretkey(llarp::SecretKey& secret, const llarp::IdentitySecret& seed)
crypto::seed_to_secretkey(llarp::SecretKey& secret, const llarp::IdentitySecret& seed)
{
return crypto_sign_ed25519_seed_keypair(secret.data() + 32, secret.data(), seed.data()) != -1;
}
void
Crypto::randomize(const llarp_buffer_t& buff)
crypto::randomize(uint8_t* buf, size_t len)
{
randombytes((unsigned char*)buff.base, buff.sz);
randombytes(buf, len);
}
void
Crypto::randbytes(byte_t* ptr, size_t sz)
crypto::randbytes(byte_t* ptr, size_t sz)
{
randombytes((unsigned char*)ptr, sz);
}
void
Crypto::identity_keygen(llarp::SecretKey& keys)
crypto::identity_keygen(llarp::SecretKey& keys)
{
PubKey pk;
int result = crypto_sign_keypair(pk.data(), keys.data());
@ -483,7 +460,7 @@ namespace llarp
}
bool
Crypto::check_identity_privkey(const llarp::SecretKey& keys)
crypto::check_identity_privkey(const llarp::SecretKey& keys)
{
AlignedBuffer<crypto_sign_SEEDBYTES> seed;
llarp::PubKey pk;
@ -496,7 +473,7 @@ namespace llarp
}
void
Crypto::encryption_keygen(llarp::SecretKey& keys)
crypto::encryption_keygen(llarp::SecretKey& keys)
{
auto d = keys.data();
randbytes(d, 32);
@ -504,31 +481,29 @@ namespace llarp
}
bool
Crypto::pqe_encrypt(PQCipherBlock& ciphertext, SharedSecret& sharedkey, const PQPubKey& pubkey)
crypto::pqe_encrypt(PQCipherBlock& ciphertext, SharedSecret& sharedkey, const PQPubKey& pubkey)
{
return crypto_kem_enc(ciphertext.data(), sharedkey.data(), pubkey.data()) != -1;
}
bool
Crypto::pqe_decrypt(
crypto::pqe_decrypt(
const PQCipherBlock& ciphertext, SharedSecret& sharedkey, const byte_t* secretkey)
{
return crypto_kem_dec(sharedkey.data(), ciphertext.data(), secretkey) != -1;
}
void
Crypto::pqe_keygen(PQKeyPair& keypair)
crypto::pqe_keygen(PQKeyPair& keypair)
{
auto d = keypair.data();
crypto_kem_keypair(d + PQ_SECRETKEYSIZE, d);
}
#ifdef HAVE_CRYPT
bool
Crypto::check_passwd_hash(std::string pwhash, std::string challenge)
crypto::check_passwd_hash(std::string pwhash, std::string challenge)
{
(void)pwhash;
(void)challenge;
bool ret = false;
#ifdef HAVE_CRYPT
auto pos = pwhash.find_last_of('$');
auto settings = pwhash.substr(0, pos);
crypt_data data{};
@ -537,9 +512,9 @@ namespace llarp
ret = ptr == pwhash;
}
sodium_memzero(&data, sizeof(data));
#endif
return ret;
}
#endif
const byte_t*
seckey_topublic(const SecretKey& sec)
@ -566,4 +541,23 @@ namespace llarp
randombytes((byte_t*)&i, sizeof(i));
return i;
}
// Called during static initialization to initialize libsodium and ntru. (The CSRNG return is not
// useful, but just here to get this called during static initialization of `llarp::csrng`).
static CSRNG
_initialize_crypto()
{
if (sodium_init() == -1)
{
log::critical(log::Cat("initialization"), "sodium_init() failed, unable to continue!");
std::abort();
}
char* avx2 = std::getenv("AVX2_FORCE_DISABLE");
ntru_init(avx2 && avx2 == "1"sv);
return CSRNG{};
}
CSRNG csrng = _initialize_crypto();
} // namespace llarp

@ -5,27 +5,21 @@
#include <llarp/util/buffer.hpp>
#include <functional>
#include <cstdint>
#include <functional>
namespace llarp
{
/*
TODO:
- make uint8_t pointers const where needed
-
*/
struct Crypto
namespace crypto
{
Crypto();
~Crypto() = default;
/// decrypt cipherText given the key generated from name
std::optional<AlignedBuffer<32>>
maybe_decrypt_name(std::string_view ciphertext, SymmNonce nounce, std::string_view name);
maybe_decrypt_name(std::string_view ciphertext, SymmNonce nonce, std::string_view name);
/// xchacha symmetric cipher
bool
@ -98,7 +92,7 @@ namespace llarp
seed_to_secretkey(llarp::SecretKey&, const llarp::IdentitySecret&);
/// randomize buffer
void
randomize(const llarp_buffer_t&);
randomize(uint8_t* buf, size_t len);
/// randomizer memory
void
randbytes(byte_t*, size_t);
@ -123,7 +117,7 @@ namespace llarp
bool
check_passwd_hash(std::string pwhash, std::string challenge);
};
}; // namespace crypto
/// return random 64bit unsigned interger
uint64_t
@ -138,39 +132,6 @@ namespace llarp
const byte_t*
pq_keypair_to_secret(const PQKeyPair& keypair);
struct CryptoManager
{
private:
static Crypto* m_crypto;
Crypto* m_prevCrypto;
public:
explicit CryptoManager(Crypto* crypto) : m_prevCrypto(m_crypto)
{
m_crypto = crypto;
}
~CryptoManager()
{
m_crypto = m_prevCrypto;
}
static Crypto*
instance()
{
#ifdef NDEBUG
return m_crypto;
#else
if (m_crypto)
return m_crypto;
assert(false && "Cryptomanager::instance() was undefined");
abort();
#endif
}
};
/// rng type that uses llarp::randint(), which is cryptographically secure
struct CSRNG
{
@ -180,19 +141,21 @@ namespace llarp
min()
{
return std::numeric_limits<uint64_t>::min();
};
}
static constexpr uint64_t
max()
{
return std::numeric_limits<uint64_t>::max();
};
}
uint64_t
operator()()
{
return llarp::randint();
};
}
};
extern CSRNG csrng;
} // namespace llarp

@ -6,8 +6,8 @@
#include <llarp/util/buffer.hpp>
#include <llarp/util/mem.hpp>
#include <vector>
#include <stdexcept>
#include <vector>
namespace llarp
{

@ -1,16 +1,14 @@
#include "encrypted_frame.hpp"
#include "crypto.hpp"
#include <llarp/util/logging.hpp>
#include <llarp/util/mem.hpp>
namespace llarp
{
bool
EncryptedFrame::DoEncrypt(const SharedSecret& shared, bool noDH)
{
auto crypto = CryptoManager::instance();
uint8_t* hash_ptr = data();
uint8_t* nonce_ptr = hash_ptr + SHORTHASHSIZE;
uint8_t* pubkey_ptr = nonce_ptr + TUNNONCESIZE;
@ -18,20 +16,20 @@ namespace llarp
if (noDH)
{
crypto->randbytes(nonce_ptr, TUNNONCESIZE);
crypto->randbytes(pubkey_ptr, PUBKEYSIZE);
crypto::randbytes(nonce_ptr, TUNNONCESIZE);
crypto::randbytes(pubkey_ptr, PUBKEYSIZE);
}
TunnelNonce nonce(nonce_ptr);
// encrypt body
if (!crypto->xchacha20(body_ptr, size() - EncryptedFrameOverheadSize, shared, nonce))
if (!crypto::xchacha20(body_ptr, size() - EncryptedFrameOverheadSize, shared, nonce))
{
llarp::LogError("encrypt failed");
return false;
}
if (!crypto->hmac(hash_ptr, nonce_ptr, size() - SHORTHASHSIZE, shared))
if (!crypto::hmac(hash_ptr, nonce_ptr, size() - SHORTHASHSIZE, shared))
{
llarp::LogError("Failed to generate message auth");
return false;
@ -55,16 +53,14 @@ namespace llarp
SharedSecret shared;
auto crypto = CryptoManager::instance();
// set our pubkey
memcpy(pubkey, ourSecretKey.toPublic().data(), PUBKEYSIZE);
// randomize nonce
crypto->randbytes(noncePtr, TUNNONCESIZE);
crypto::randbytes(noncePtr, TUNNONCESIZE);
TunnelNonce nonce(noncePtr);
// derive shared key
if (!crypto->dh_client(shared, otherPubkey, ourSecretKey, nonce))
if (!crypto::dh_client(shared, otherPubkey, ourSecretKey, nonce))
{
llarp::LogError("DH failed");
return false;
@ -76,8 +72,6 @@ namespace llarp
bool
EncryptedFrame::DoDecrypt(const SharedSecret& shared)
{
auto crypto = CryptoManager::instance();
uint8_t* hash_ptr = data();
uint8_t* nonce_ptr = hash_ptr + SHORTHASHSIZE;
uint8_t* body_ptr = hash_ptr + EncryptedFrameOverheadSize;
@ -85,7 +79,7 @@ namespace llarp
TunnelNonce nonce(nonce_ptr);
ShortHash digest;
if (!crypto->hmac(digest.data(), nonce_ptr, size() - SHORTHASHSIZE, shared))
if (!crypto::hmac(digest.data(), nonce_ptr, size() - SHORTHASHSIZE, shared))
{
llarp::LogError("Digest failed");
return false;
@ -97,7 +91,7 @@ namespace llarp
return false;
}
if (!crypto->xchacha20(body_ptr, size() - EncryptedFrameOverheadSize, shared, nonce))
if (!crypto::xchacha20(body_ptr, size() - EncryptedFrameOverheadSize, shared, nonce))
{
llarp::LogError("decrypt failed");
return false;
@ -121,10 +115,8 @@ namespace llarp
SharedSecret shared;
auto crypto = CryptoManager::instance();
// use dh_server because we are not the creator of this message
if (!crypto->dh_server(shared, otherPubkey, ourSecretKey, nonce))
if (!crypto::dh_server(shared, otherPubkey, ourSecretKey, nonce))
{
llarp::LogError("DH failed");
return false;

@ -2,10 +2,12 @@
#include "encrypted.hpp"
#include "types.hpp"
#include <llarp/util/buffer.hpp>
#include <utility>
#include <llarp/util/mem.h>
#include <utility>
namespace llarp
{
static constexpr size_t EncryptedFrameOverheadSize = PUBKEYSIZE + TUNNONCESIZE + SHORTHASHSIZE;

@ -3,12 +3,8 @@
#include <llarp/util/buffer.hpp>
#include <llarp/util/file.hpp>
#include <iterator>
#include <oxenc/hex.h>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_sign_ed25519.h>
#include <sodium/crypto_hash_sha512.h>
#include <sodium/crypto_scalarmult_ed25519.h>
namespace llarp

@ -1,10 +1,11 @@
#pragma once
#include "constants.hpp"
#include <llarp/router_id.hpp>
#include <llarp/util/aligned.hpp>
#include <llarp/util/types.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/types.hpp>
#include <algorithm>
#include <iostream>
@ -218,15 +219,14 @@ namespace llarp
using PQKeyPair = AlignedBuffer<PQ_KEYPAIRSIZE>;
/// PKE(result, publickey, secretkey, nonce)
using path_dh_func =
std::function<bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&)>;
using path_dh_func = bool (*)(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&);
/// TKE(result, publickey, secretkey, nonce)
using transport_dh_func =
std::function<bool(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&)>;
bool (*)(SharedSecret&, const PubKey&, const SecretKey&, const TunnelNonce&);
/// SH(result, body)
using shorthash_func = std::function<bool(ShortHash&, const llarp_buffer_t&)>;
using shorthash_func = bool (*)(ShortHash&, const llarp_buffer_t&);
} // namespace llarp
namespace std

@ -2,6 +2,7 @@
#include "kademlia.hpp"
#include "key.hpp"
#include <llarp/util/status.hpp>
#include <map>

@ -1,669 +0,0 @@
#include "context.hpp"
#include "explorenetworkjob.hpp"
#include "localrouterlookup.hpp"
#include "localserviceaddresslookup.hpp"
#include "localtaglookup.hpp"
#include <llarp/dht/messages/findrouter.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/dht/messages/pubintro.hpp>
#include "node.hpp"
#include "publishservicejob.hpp"
#include "recursiverouterlookup.hpp"
#include "serviceaddresslookup.hpp"
#include "taglookup.hpp"
#include <llarp/messages/dht_immediate.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/profiling.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/util/decaying_hashset.hpp>
#include <vector>
namespace llarp::dht
{
AbstractDHTMessageHandler::~AbstractDHTMessageHandler() = default;
struct DHTMessageHandler final : public AbstractDHTMessageHandler
{
DHTMessageHandler();
~DHTMessageHandler() override = default;
util::StatusObject
ExtractStatus() const override;
void
StoreRC(const RouterContact rc) const override
{
GetRouter()->rc_lookup_handler().check_rc(rc);
}
// void
// LookupIntroSetRelayed(
// const Key_t& target,
// const Key_t& whoasked,
// uint64_t whoaskedTX,
// const Key_t& askpeer,
// uint64_t relayOrder,
// service::EncryptedIntroSetLookupHandler result = nullptr) override;
// void
// LookupIntroSetDirect(
// const Key_t& target,
// const Key_t& whoasked,
// uint64_t whoaskedTX,
// const Key_t& askpeer,
// service::EncryptedIntroSetLookupHandler result = nullptr) override;
/// on behalf of whoasked request router with public key target from dht
/// router with key askpeer
void
LookupRouterRecursive(
const RouterID& target,
const Key_t& whoasked,
uint64_t whoaskedTX,
const Key_t& askpeer,
RouterLookupHandler result = nullptr) override;
bool
LookupRouter(const RouterID& target, RouterLookupHandler result) override
{
Key_t askpeer;
if (!_nodes->FindClosest(Key_t(target), askpeer))
{
return false;
}
LookupRouterRecursive(target, OurKey(), 0, askpeer, result);
return true;
}
bool
HasRouterLookup(const RouterID& target) const override
{
return pendingRouterLookups().HasLookupFor(target);
}
/// issue dht lookup for router via askpeer and send reply to local path
void
LookupRouterForPath(
const RouterID& target, uint64_t txid, const PathID_t& path, const Key_t& askpeer) override;
/// issue dht lookup for introset for addr via askpeer and send reply to
/// local path
void
LookupIntroSetForPath(
const Key_t& addr,
uint64_t txid,
const llarp::PathID_t& path,
const Key_t& askpeer,
uint64_t relayOrder) override;
/// send a dht message to peer, if keepalive is true then keep the session
/// with that peer alive for 10 seconds
void
DHTSendTo(const RouterID& peer, AbstractDHTMessage* msg, bool keepalive = true) override;
/// get routers closest to target excluding requester
bool
HandleExploritoryRouterLookup(
const Key_t& requester,
uint64_t txid,
const RouterID& target,
std::vector<std::unique_ptr<AbstractDHTMessage>>& reply) override;
/// handle rc lookup from requester for target
void
LookupRouterRelayed(
const Key_t& requester,
uint64_t txid,
const Key_t& target,
bool recursive,
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies) override;
/// relay a dht message from a local path to the main network
bool
RelayRequestForPath(const llarp::PathID_t& localPath, const AbstractDHTMessage& msg) override;
/// send introset to peer as R/S
void
PropagateLocalIntroSet(
const PathID_t& from,
uint64_t txid,
const service::EncryptedIntroSet& introset,
const Key_t& tellpeer,
uint64_t relayOrder) override;
/// send introset to peer from source with S counter and excluding peers
void
PropagateIntroSetTo(
const Key_t& from,
uint64_t txid,
const service::EncryptedIntroSet& introset,
const Key_t& tellpeer,
uint64_t relayOrder) override;
/// initialize dht context and explore every exploreInterval milliseconds
void
Init(const Key_t& us, Router* router) override;
/// get localally stored introset by service address
std::optional<llarp::service::EncryptedIntroSet>
GetIntroSetByLocation(const Key_t& location) const override;
void
handle_cleaner_timer();
/// explore dht for new routers
void
Explore(size_t N = 3);
llarp::Router* router{nullptr};
// for router contacts
std::unique_ptr<Bucket<RCNode>> _nodes;
// for introduction sets
std::unique_ptr<Bucket<ISNode>> _services;
Bucket<ISNode>*
services() override
{
return _services.get();
}
bool allowTransit{false};
bool&
AllowTransit() override
{
return allowTransit;
}
const bool&
AllowTransit() const override
{
return allowTransit;
}
Bucket<RCNode>*
Nodes() const override
{
return _nodes.get();
}
void
PutRCNodeAsync(const RCNode& val) override
{
router->loop()->call([nodes = Nodes(), val] { nodes->PutNode(val); });
}
void
DelRCNodeAsync(const Key_t& val) override
{
router->loop()->call([nodes = Nodes(), val] { nodes->DelNode(val); });
}
const Key_t&
OurKey() const override
{
return ourKey;
}
llarp::Router*
GetRouter() const override
{
return router;
}
bool
GetRCFromNodeDB(const Key_t& k, llarp::RouterContact& rc) const override
{
if (const auto maybe = router->node_db()->Get(k.as_array()); maybe.has_value())
{
rc = *maybe;
return true;
}
return false;
}
PendingIntrosetLookups _pendingIntrosetLookups;
PendingRouterLookups _pendingRouterLookups;
PendingExploreLookups _pendingExploreLookups;
PendingIntrosetLookups&
pendingIntrosetLookups() override
{
return _pendingIntrosetLookups;
}
const PendingIntrosetLookups&
pendingIntrosetLookups() const override
{
return _pendingIntrosetLookups;
}
PendingRouterLookups&
pendingRouterLookups() override
{
return _pendingRouterLookups;
}
const PendingRouterLookups&
pendingRouterLookups() const override
{
return _pendingRouterLookups;
}
PendingExploreLookups&
pendingExploreLookups() override
{
return _pendingExploreLookups;
}
const PendingExploreLookups&
pendingExploreLookups() const override
{
return _pendingExploreLookups;
}
uint64_t
NextID()
{
return ++ids;
}
llarp_time_t
Now() const override;
void
ExploreNetworkVia(const Key_t& peer) override;
bool
handle_message(
const AbstractDHTMessage&, std::vector<std::unique_ptr<dht::AbstractDHTMessage>>&) override;
private:
std::shared_ptr<int> _timer_keepalive;
void
CleanupTX();
uint64_t ids;
Key_t ourKey;
};
DHTMessageHandler::DHTMessageHandler()
{
randombytes((byte_t*)&ids, sizeof(uint64_t));
}
void
DHTMessageHandler::Explore(size_t N)
{
// ask N random peers for new routers
llarp::LogDebug("Exploring network via ", N, " peers");
std::set<Key_t> peers;
if (_nodes->GetManyRandom(peers, N))
{
for (const auto& peer : peers)
ExploreNetworkVia(peer);
}
else
llarp::LogError("failed to select ", N, " random nodes for exploration");
}
void
DHTMessageHandler::ExploreNetworkVia(const Key_t& askpeer)
{
uint64_t txid = ++ids;
const TXOwner peer(askpeer, txid);
const TXOwner whoasked(OurKey(), txid);
const RouterID K(askpeer.as_array());
pendingExploreLookups().NewTX(
peer, whoasked, K, new ExploreNetworkJob(askpeer.as_array(), this));
}
void
DHTMessageHandler::handle_cleaner_timer()
{
// clean up transactions
CleanupTX();
const llarp_time_t now = Now();
if (_nodes)
{
// expire router contacts in memory
auto& nodes = _nodes->nodes;
auto itr = nodes.begin();
while (itr != nodes.end())
{
if (itr->second.rc.IsExpired(now))
{
itr = nodes.erase(itr);
}
else
++itr;
}
}
if (_services)
{
// expire intro sets
auto& nodes = _services->nodes;
auto itr = nodes.begin();
while (itr != nodes.end())
{
if (itr->second.introset.IsExpired(now))
{
itr = nodes.erase(itr);
}
else
++itr;
}
}
}
void
DHTMessageHandler::LookupRouterRelayed(
const Key_t& requester,
uint64_t txid,
const Key_t& target,
bool recursive,
std::vector<std::unique_ptr<AbstractDHTMessage>>& replies)
{
if (target == ourKey)
{
// we are the target, give them our RC
replies.emplace_back(new GotRouterMessage(requester, txid, {router->rc()}, false));
return;
}
if (not GetRouter()->SessionToRouterAllowed(target.as_array()))
{
// explicitly not allowed
replies.emplace_back(new GotRouterMessage(requester, txid, {}, false));
return;
}
const auto rc = GetRouter()->node_db()->FindClosestTo(target);
const Key_t next(rc.pubkey);
{
if (next == target)
{
// we know the target
if (rc.ExpiresSoon(llarp::time_now_ms()))
{
// ask target for their rc to keep it updated
LookupRouterRecursive(target.as_array(), requester, txid, next);
}
else
{
// send reply with rc we know of
replies.emplace_back(new GotRouterMessage(requester, txid, {rc}, false));
}
}
else if (recursive) // are we doing a recursive lookup?
{
// is the next peer we ask closer to the target than us?
if ((next ^ target) < (ourKey ^ target))
{
// yes it is closer, ask neighbour recursively
LookupRouterRecursive(target.as_array(), requester, txid, next);
}
else
{
// no we are closer to the target so tell requester it's not there
// so they switch to iterative lookup
replies.emplace_back(new GotRouterMessage(requester, txid, {}, false));
}
}
else
{
// iterative lookup and we don't have it tell them who is closer
replies.emplace_back(new GotRouterMessage(requester, next, txid, false));
}
}
}
std::optional<llarp::service::EncryptedIntroSet>
DHTMessageHandler::GetIntroSetByLocation(const Key_t& key) const
{
auto itr = _services->nodes.find(key);
if (itr == _services->nodes.end())
return {};
return itr->second.introset;
}
void
DHTMessageHandler::CleanupTX()
{
auto now = Now();
llarp::LogTrace("DHT tick");
pendingRouterLookups().Expire(now);
_pendingIntrosetLookups.Expire(now);
pendingExploreLookups().Expire(now);
}
util::StatusObject
DHTMessageHandler::ExtractStatus() const
{
util::StatusObject obj{
{"pendingRouterLookups", pendingRouterLookups().ExtractStatus()},
{"pendingIntrosetLookups", _pendingIntrosetLookups.ExtractStatus()},
{"pendingExploreLookups", pendingExploreLookups().ExtractStatus()},
{"nodes", _nodes->ExtractStatus()},
{"services", _services->ExtractStatus()},
{"ourKey", ourKey.ToHex()}};
return obj;
}
bool
DHTMessageHandler::handle_message(
const AbstractDHTMessage& msg, std::vector<std::unique_ptr<dht::AbstractDHTMessage>>& replies)
{
return msg.handle_message(*this, replies);
}
void
DHTMessageHandler::Init(const Key_t& us, Router* r)
{
router = r;
ourKey = us;
_nodes = std::make_unique<Bucket<RCNode>>(ourKey, llarp::randint);
_services = std::make_unique<Bucket<ISNode>>(ourKey, llarp::randint);
llarp::LogDebug("initialize dht with key ", ourKey);
// start cleanup timer
_timer_keepalive = std::make_shared<int>(0);
router->loop()->call_every(1s, _timer_keepalive, [this] { handle_cleaner_timer(); });
}
void
DHTMessageHandler::DHTSendTo(const RouterID& peer, AbstractDHTMessage* msg, bool)
{
router->SendToOrQueue(peer, msg);
auto now = Now();
router->PersistSessionUntil(peer, now + 1min);
}
// this function handles incoming DHT messages sent down a path by a client
// note that IMessage here is different than that found in the routing
// namespace. by the time this is called, we are inside
// llarp::routing::DHTMessage::HandleMessage()
bool
DHTMessageHandler::RelayRequestForPath(const llarp::PathID_t& id, const AbstractDHTMessage& msg)
{
routing::PathDHTMessage reply;
if (not handle_message(msg, reply.dht_msgs))
return false;
if (not reply.dht_msgs.empty())
{
auto path = router->path_context().GetByUpstream(router->pubkey(), id);
return path && path->SendRoutingMessage(reply, router);
}
return true;
}
void
DHTMessageHandler::LookupIntroSetForPath(
const Key_t& addr,
uint64_t txid,
const llarp::PathID_t& path,
const Key_t& askpeer,
uint64_t relayOrder)
{
const TXOwner asker(OurKey(), txid);
const TXOwner peer(askpeer, ++ids);
_pendingIntrosetLookups.NewTX(
peer,
asker,
asker,
new LocalServiceAddressLookup(path, txid, relayOrder, addr, this, askpeer));
}
void
DHTMessageHandler::PropagateIntroSetTo(
const Key_t& from,
uint64_t txid,
const service::EncryptedIntroSet& introset,
const Key_t& tellpeer,
uint64_t relayOrder)
{
const TXOwner asker(from, txid);
const TXOwner peer(tellpeer, ++ids);
_pendingIntrosetLookups.NewTX(
peer, asker, asker, new PublishServiceJob(asker, introset, this, relayOrder));
}
void
DHTMessageHandler::PropagateLocalIntroSet(
const PathID_t& from,
uint64_t txid,
const service::EncryptedIntroSet& introset,
const Key_t& tellpeer,
uint64_t relayOrder)
{
const TXOwner asker(OurKey(), txid);
const TXOwner peer(tellpeer, ++ids);
_pendingIntrosetLookups.NewTX(
peer,
asker,
peer,
new LocalPublishServiceJob(peer, from, txid, introset, this, relayOrder));
}
void
DHTMessageHandler::LookupIntroSetRelayed(
const Key_t& addr,
const Key_t& whoasked,
uint64_t txid,
const Key_t& askpeer,
uint64_t relayOrder,
service::EncryptedIntroSetLookupHandler handler)
{
const TXOwner asker(whoasked, txid);
const TXOwner peer(askpeer, ++ids);
_pendingIntrosetLookups.NewTX(
peer, asker, asker, new ServiceAddressLookup(asker, addr, this, relayOrder, handler));
}
void
DHTMessageHandler::LookupIntroSetDirect(
const Key_t& addr,
const Key_t& whoasked,
uint64_t txid,
const Key_t& askpeer,
service::EncryptedIntroSetLookupHandler handler)
{
const TXOwner asker(whoasked, txid);
const TXOwner peer(askpeer, ++ids);
_pendingIntrosetLookups.NewTX(
peer, asker, asker, new ServiceAddressLookup(asker, addr, this, 0, handler), 1s);
}
bool
DHTMessageHandler::HandleExploritoryRouterLookup(
const Key_t& requester,
uint64_t txid,
const RouterID& target,
std::vector<std::unique_ptr<AbstractDHTMessage>>& reply)
{
std::vector<RouterID> closer;
const Key_t t(target.as_array());
std::set<Key_t> foundRouters;
if (!_nodes)
return false;
const size_t nodeCount = _nodes->size();
if (nodeCount == 0)
{
llarp::LogError("cannot handle exploritory router lookup, no dht peers");
return false;
}
llarp::LogDebug("We have ", _nodes->size(), " connected nodes into the DHT");
// ourKey should never be in the connected list
// requester is likely in the connected list
// 4 or connection nodes (minus a potential requestor), whatever is less
if (!_nodes->GetManyNearExcluding(
t, foundRouters, std::min(nodeCount, size_t{4}), std::set<Key_t>{ourKey, requester}))
{
llarp::LogError(
"not enough dht nodes to handle exploritory router lookup, "
"have ",
nodeCount,
" dht peers");
return false;
}
for (const auto& f : foundRouters)
{
const RouterID id = f.as_array();
// discard shit routers
if (router->router_profiling().IsBadForConnect(id))
continue;
closer.emplace_back(id);
}
llarp::LogDebug("Gave ", closer.size(), " routers for exploration");
reply.emplace_back(new GotRouterMessage(txid, closer, false));
return true;
}
void
DHTMessageHandler::LookupRouterForPath(
const RouterID& target, uint64_t txid, const llarp::PathID_t& path, const Key_t& askpeer)
{
const TXOwner peer(askpeer, ++ids);
const TXOwner whoasked(OurKey(), txid);
_pendingRouterLookups.NewTX(
peer, whoasked, target, new LocalRouterLookup(path, txid, target, this));
}
void
DHTMessageHandler::LookupRouterRecursive(
const RouterID& target,
const Key_t& whoasked,
uint64_t txid,
const Key_t& askpeer,
RouterLookupHandler handler)
{
const TXOwner asker(whoasked, txid);
const TXOwner peer(askpeer, ++ids);
_pendingRouterLookups.NewTX(
peer, asker, target, new RecursiveRouterLookup(asker, target, this, handler));
}
llarp_time_t
DHTMessageHandler::Now() const
{
return router->now();
}
std::unique_ptr<AbstractDHTMessageHandler>
make_handler()
{
return std::make_unique<DHTMessageHandler>();
}
} // namespace llarp::dht

@ -1,53 +0,0 @@
#include "context.hpp"
#include "dht.h"
#include <llarp/router_contact.hpp>
llarp_dht_context::llarp_dht_context(llarp::Router* router)
{
parent = router;
impl = llarp::dht::make_handler();
}
struct llarp_dht_context*
llarp_dht_context_new(llarp::Router* router)
{
return new llarp_dht_context(router);
}
void
llarp_dht_context_free(struct llarp_dht_context* ctx)
{
delete ctx;
}
void
__llarp_dht_remove_peer(struct llarp_dht_context* ctx, const byte_t* id)
{
ctx->impl->Nodes()->DelNode(llarp::dht::Key_t(id));
}
void
llarp_dht_allow_transit(llarp_dht_context* ctx)
{
ctx->impl->AllowTransit() = true;
}
void
llarp_dht_context_start(struct llarp_dht_context* ctx, const byte_t* key)
{
ctx->impl->Init(llarp::dht::Key_t(key), ctx->parent);
}
void
llarp_dht_lookup_router(struct llarp_dht_context* ctx, struct llarp_router_lookup_job* job)
{
job->dht = ctx;
job->found = false;
job->result.Clear();
// llarp_rc_clear(&job->result);
llarp::LogError("implement me llarp_dht_lookup_router");
/*
ctx->parent->logic->queue_job(
{job, &llarp::dht::Context::queue_router_lookup});
*/
}

@ -1,61 +0,0 @@
#pragma once
#include <llarp/crypto/crypto.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/util/buffer.hpp>
/**
* dht.h
*
* DHT functions
*/
struct llarp_dht_context;
namespace llarp
{
struct Router;
}
/// allocator
struct llarp_dht_context*
llarp_dht_context_new(llarp::Router* parent);
/// deallocator
void
llarp_dht_context_free(struct llarp_dht_context* dht);
/// start dht context with our location in keyspace
void
llarp_dht_context_start(struct llarp_dht_context* ctx, const byte_t* key);
// remove this? dns needs it atm
struct llarp_router_lookup_job;
using llarp_router_lookup_handler = void (*)(struct llarp_router_lookup_job*);
struct llarp_router_lookup_job
{
/// can be anything but usually a class context for hook
void* user;
llarp_router_lookup_handler hook;
struct llarp_dht_context* dht;
llarp::PubKey target;
bool found;
// make sure you initialize addr and exits
llarp::RouterContact result;
bool iterative;
};
// end dns requirement
/// start allowing dht participation on a context
void
llarp_dht_allow_transit(struct llarp_dht_context* ctx);
/// remove router from tracked dht peer list
/// internal function do not use
void
__llarp_dht_remove_peer(struct llarp_dht_context* ctx, const byte_t* id);
void
llarp_dht_lookup_router(struct llarp_dht_context* ctx, struct llarp_router_lookup_job* job);

@ -1,39 +0,0 @@
#include "explorenetworkjob.hpp"
#include <llarp/dht/messages/findrouter.hpp>
#include <llarp/router/router.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/tooling/dht_event.hpp>
namespace llarp::dht
{
void
ExploreNetworkJob::Start(const TXOwner& peer)
{
auto msg = new FindRouterMessage(peer.txid);
auto router = parent->GetRouter();
if (router)
{
router->notify_router_event<tooling::FindRouterSentEvent>(router->pubkey(), *msg);
}
parent->DHTSendTo(peer.node.as_array(), msg);
}
void
ExploreNetworkJob::SendReply()
{
llarp::LogDebug("got ", valuesFound.size(), " routers from exploration");
auto router = parent->GetRouter();
for (const auto& pk : valuesFound)
{
// lookup router
if (router and router->node_db()->Has(pk))
continue;
parent->LookupRouter(
pk, [router, pk](const auto& res) { router->HandleDHTLookupForExplore(pk, res); });
}
}
} // namespace llarp::dht

@ -1,30 +0,0 @@
#ifndef LLARP_DHT_EXPLORENETWORKJOB
#define LLARP_DHT_EXPLORENETWORKJOB
#include "tx.hpp"
#include <llarp/router_id.hpp>
namespace llarp::dht
{
struct ExploreNetworkJob : public TX<RouterID, RouterID>
{
ExploreNetworkJob(const RouterID& peer, AbstractDHTMessageHandler* ctx)
: TX<RouterID, RouterID>(TXOwner{}, peer, ctx)
{}
bool
Validate(const RouterID&) const override
{
// TODO: check with lokid
return true;
}
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,6 +1,7 @@
#pragma once
#include "key.hpp"
#include <llarp/router_contact.hpp>
namespace llarp::dht

@ -1,7 +1,7 @@
#pragma once
#include <llarp/util/aligned.hpp>
#include <llarp/router_id.hpp>
#include <llarp/util/aligned.hpp>
#include <llarp/util/formattable.hpp>
#include <array>

@ -1,61 +0,0 @@
#include "localrouterlookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/util/logging.hpp>
namespace llarp::dht
{
LocalRouterLookup::LocalRouterLookup(
const PathID_t& path, uint64_t txid, const RouterID& _target, AbstractDHTMessageHandler* ctx)
: RecursiveRouterLookup(TXOwner{ctx->OurKey(), txid}, _target, ctx, nullptr), localPath(path)
{}
void
LocalRouterLookup::SendReply()
{
auto path =
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
if (!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
if (valuesFound.size())
{
RouterContact found;
for (const auto& rc : valuesFound)
{
if (rc.OtherIsNewer(found))
found = rc;
}
valuesFound.clear();
if (not found.pubkey.IsZero())
{
valuesFound.resize(1);
valuesFound[0] = found;
}
else
{
llarp::LogWarn("We found a null RC for dht request, dropping it");
}
}
routing::PathDHTMessage msg;
msg.dht_msgs.emplace_back(
new GotRouterMessage(parent->OurKey(), whoasked.txid, valuesFound, true));
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace llarp::dht

@ -1,27 +0,0 @@
#ifndef LLARP_DHT_LOCALROUTERLOOKUP
#define LLARP_DHT_LOCALROUTERLOOKUP
#include "recursiverouterlookup.hpp"
#include <llarp/path/path_types.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/router_id.hpp>
namespace llarp::dht
{
struct LocalRouterLookup : public RecursiveRouterLookup
{
PathID_t localPath;
LocalRouterLookup(
const PathID_t& path,
uint64_t txid,
const RouterID& target,
AbstractDHTMessageHandler* ctx);
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,58 +0,0 @@
#include "localserviceaddresslookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/util/logging.hpp>
namespace llarp::dht
{
LocalServiceAddressLookup::LocalServiceAddressLookup(
const PathID_t& pathid,
uint64_t txid,
uint64_t relayOrder,
const Key_t& addr,
AbstractDHTMessageHandler* ctx,
[[maybe_unused]] const Key_t& askpeer)
: ServiceAddressLookup(TXOwner{ctx->OurKey(), txid}, addr, ctx, relayOrder, nullptr)
, localPath(pathid)
{}
void
LocalServiceAddressLookup::SendReply()
{
auto path =
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
if (!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
// pick newest if we have more than 1 result
if (valuesFound.size())
{
service::EncryptedIntroSet found;
for (const auto& introset : valuesFound)
{
if (found.OtherIsNewer(introset))
found = introset;
}
valuesFound.clear();
valuesFound.emplace_back(found);
}
routing::PathDHTMessage msg;
msg.dht_msgs.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace llarp::dht

@ -1,28 +0,0 @@
#ifndef LLARP_DHT_LOCALSERVICEADDRESSLOOKUP
#define LLARP_DHT_LOCALSERVICEADDRESSLOOKUP
#include "serviceaddresslookup.hpp"
#include <llarp/path/path_types.hpp>
namespace llarp::dht
{
struct LocalServiceAddressLookup : public ServiceAddressLookup
{
PathID_t localPath;
LocalServiceAddressLookup(
const PathID_t& pathid,
uint64_t txid,
uint64_t relayOrder,
const Key_t& addr,
AbstractDHTMessageHandler* ctx,
[[maybe_unused]] const Key_t& askpeer);
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,42 +0,0 @@
#include "localtaglookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/routing/path_dht_message.hpp>
namespace llarp::dht
{
LocalTagLookup::LocalTagLookup(
const PathID_t& path,
uint64_t txid,
const service::Tag& _target,
AbstractDHTMessageHandler* ctx)
: TagLookup(TXOwner{ctx->OurKey(), txid}, _target, ctx, 0), localPath(path)
{}
void
LocalTagLookup::SendReply()
{
auto path =
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
if (!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::PathDHTMessage msg;
msg.dht_msgs.emplace_back(new GotIntroMessage(valuesFound, whoasked.txid));
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace llarp::dht

@ -1,23 +0,0 @@
#ifndef LLARP_DHT_LOOKUPTAGLOOKUP
#define LLARP_DHT_LOOKUPTAGLOOKUP
#include "taglookup.hpp"
namespace llarp::dht
{
struct LocalTagLookup : public TagLookup
{
PathID_t localPath;
LocalTagLookup(
const PathID_t& path,
uint64_t txid,
const service::Tag& target,
AbstractDHTMessageHandler* ctx);
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,138 +0,0 @@
#include "context.hpp"
#include "oxenc/bt_serialize.h"
#include <memory>
#include <llarp/util/bencode.hpp>
#include <llarp/dht/messages/findintro.hpp>
#include <llarp/dht/messages/findrouter.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/dht/messages/pubintro.hpp>
#include <llarp/dht/messages/findname.hpp>
#include <llarp/dht/messages/gotname.hpp>
namespace llarp::dht
{
struct MessageDecoder
{
const Key_t& From;
std::unique_ptr<AbstractDHTMessage> msg;
bool firstKey = true;
bool relayed = false;
MessageDecoder(const Key_t& from, bool wasRelayed) : From(from), relayed(wasRelayed)
{}
bool
operator()(llarp_buffer_t* buffer, llarp_buffer_t* key)
{
llarp_buffer_t strbuf;
// check for empty dict
if (!key)
return !firstKey;
// first key
if (firstKey)
{
if (!(key->startswith("A")))
return false;
if (!bencode_read_string(buffer, &strbuf))
return false;
// bad msg size?
if (strbuf.sz != 1)
return false;
llarp::LogDebug("Handle DHT message ", *strbuf.base, " relayed=", relayed);
switch (*strbuf.base)
{
case 'N':
msg = std::make_unique<FindNameMessage>(From, Key_t{}, 0);
break;
case 'M':
msg = std::make_unique<GotNameMessage>(From, 0, service::EncryptedName{});
break;
case 'F':
msg = std::make_unique<FindIntroMessage>(From, relayed, 0);
break;
case 'R':
if (relayed)
msg = std::make_unique<RelayedFindRouterMessage>(From);
else
msg = std::make_unique<FindRouterMessage>(From);
break;
case 'S':
msg = std::make_unique<GotRouterMessage>(From, relayed);
break;
case 'I':
msg = std::make_unique<PublishIntroMessage>(From, relayed);
break;
case 'G':
if (relayed)
{
msg = std::make_unique<RelayedGotIntroMessage>();
break;
}
else
{
msg = std::make_unique<GotIntroMessage>(From);
break;
}
default:
llarp::LogWarn("unknown dht message type: ", (char)*strbuf.base);
// bad msg type
return false;
}
firstKey = false;
return msg != nullptr;
}
return msg->decode_key(*key, buffer);
}
};
std::unique_ptr<AbstractDHTMessage>
DecodeMessage(const Key_t& from, llarp_buffer_t* buf, bool relayed)
{
MessageDecoder dec(from, relayed);
if (!bencode_read_dict(dec, buf))
return nullptr;
return std::move(dec.msg);
}
struct ListDecoder
{
ListDecoder(
bool hasRelayed, const Key_t& from, std::vector<std::unique_ptr<AbstractDHTMessage>>& list)
: relayed(hasRelayed), From(from), l(list)
{}
bool relayed;
const Key_t& From;
std::vector<std::unique_ptr<AbstractDHTMessage>>& l;
bool
operator()(llarp_buffer_t* buffer, bool has)
{
if (!has)
return true;
auto msg = DecodeMessage(From, buffer, relayed);
if (msg)
{
l.emplace_back(std::move(msg));
return true;
}
return false;
}
};
bool
DecodeMessageList(
Key_t from,
llarp_buffer_t* buf,
std::vector<std::unique_ptr<AbstractDHTMessage>>& list,
bool relayed)
{
ListDecoder dec(relayed, from, list);
return bencode_read_list(dec, buf);
}
} // namespace llarp::dht

@ -1,8 +1,10 @@
#pragma once
#include "key.hpp"
#include <llarp/router_contact.hpp>
#include <llarp/service/intro_set.hpp>
#include <utility>
namespace llarp::dht

@ -1,81 +0,0 @@
#include "publishservicejob.hpp"
#include "context.hpp"
#include <llarp/dht/messages/pubintro.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/router/router.hpp>
#include <utility>
namespace llarp::dht
{
PublishServiceJob::PublishServiceJob(
const TXOwner& asker,
const service::EncryptedIntroSet& introset_,
AbstractDHTMessageHandler* ctx,
uint64_t relayOrder_)
: TX<TXOwner, service::EncryptedIntroSet>(asker, asker, ctx)
, relayOrder(relayOrder_)
, introset(introset_)
{}
bool
PublishServiceJob::Validate(const service::EncryptedIntroSet& value) const
{
if (value.derivedSigningKey != introset.derivedSigningKey)
{
llarp::LogWarn("publish introset acknowledgement acked a different service");
return false;
}
const llarp_time_t now = llarp::time_now_ms();
return value.verify(now);
}
void
PublishServiceJob::Start(const TXOwner& peer)
{
parent->DHTSendTo(
peer.node.as_array(), new PublishIntroMessage(introset, peer.txid, false, relayOrder));
}
void
PublishServiceJob::SendReply()
{
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage({introset}, whoasked.txid));
}
LocalPublishServiceJob::LocalPublishServiceJob(
const TXOwner& peer,
const PathID_t& fromID,
uint64_t _txid,
const service::EncryptedIntroSet& introset,
AbstractDHTMessageHandler* ctx,
uint64_t relayOrder)
: PublishServiceJob(peer, introset, ctx, relayOrder), localPath(fromID), txid(_txid)
{}
void
LocalPublishServiceJob::SendReply()
{
auto path =
parent->GetRouter()->path_context().GetByUpstream(parent->OurKey().as_array(), localPath);
if (!path)
{
llarp::LogWarn(
"did not send reply for relayed dht request, no such local path "
"for pathid=",
localPath);
return;
}
routing::PathDHTMessage msg;
msg.dht_msgs.emplace_back(new GotIntroMessage({introset}, txid));
if (!path->SendRoutingMessage(msg, parent->GetRouter()))
{
llarp::LogWarn(
"failed to send routing message when informing result of dht "
"request, pathid=",
localPath);
}
}
} // namespace llarp::dht

@ -1,51 +0,0 @@
#ifndef LLARP_DHT_PUBLISHSERVICEJOB
#define LLARP_DHT_PUBLISHSERVICEJOB
#include "tx.hpp"
#include "txowner.hpp"
#include <llarp/service/address.hpp>
#include <llarp/service/intro_set.hpp>
#include <set>
namespace llarp::dht
{
struct PublishServiceJob : public TX<TXOwner, service::EncryptedIntroSet>
{
uint64_t relayOrder;
service::EncryptedIntroSet introset;
PublishServiceJob(
const TXOwner& asker,
const service::EncryptedIntroSet& introset,
AbstractDHTMessageHandler* ctx,
uint64_t relayOrder);
bool
Validate(const service::EncryptedIntroSet& introset) const override;
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
struct LocalPublishServiceJob : public PublishServiceJob
{
PathID_t localPath;
uint64_t txid;
LocalPublishServiceJob(
const TXOwner& peer,
const PathID_t& fromID,
uint64_t txid,
const service::EncryptedIntroSet& introset,
AbstractDHTMessageHandler* ctx,
uint64_t relayOrder);
void
SendReply() override;
};
} // namespace llarp::dht
#endif

@ -1,71 +0,0 @@
#include "recursiverouterlookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/findrouter.hpp>
#include <llarp/dht/messages/gotrouter.hpp>
#include <llarp/router/router.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <utility>
namespace llarp
{
namespace dht
{
RecursiveRouterLookup::RecursiveRouterLookup(
const TXOwner& _whoasked,
const RouterID& _target,
AbstractDHTMessageHandler* ctx,
RouterLookupHandler result)
: TX<RouterID, RouterContact>(_whoasked, _target, ctx), resultHandler(std::move(result))
{
peersAsked.insert(ctx->OurKey());
}
bool
RecursiveRouterLookup::Validate(const RouterContact& rc) const
{
if (!rc.Verify(parent->Now()))
{
llarp::LogWarn("rc from lookup result is invalid");
return false;
}
return true;
}
void
RecursiveRouterLookup::Start(const TXOwner& peer)
{
parent->DHTSendTo(peer.node.as_array(), new FindRouterMessage(peer.txid, target));
}
void
RecursiveRouterLookup::SendReply()
{
if (valuesFound.size())
{
RouterContact found;
for (const auto& rc : valuesFound)
{
if (found.OtherIsNewer(rc) && parent->GetRouter()->rc_lookup_handler().check_rc(rc))
found = rc;
}
valuesFound.clear();
valuesFound.emplace_back(found);
}
if (resultHandler)
{
resultHandler(valuesFound);
}
if (whoasked.node != parent->OurKey())
{
parent->DHTSendTo(
whoasked.node.as_array(),
new GotRouterMessage({}, whoasked.txid, valuesFound, false),
false);
}
}
} // namespace dht
} // namespace llarp

@ -1,34 +0,0 @@
#ifndef LLARP_DHT_RECURSIVEROUTERLOOKUP
#define LLARP_DHT_RECURSIVEROUTERLOOKUP
#include "tx.hpp"
#include <llarp/router_contact.hpp>
#include <llarp/router_id.hpp>
namespace llarp
{
namespace dht
{
struct RecursiveRouterLookup : public TX<RouterID, RouterContact>
{
RouterLookupHandler resultHandler;
RecursiveRouterLookup(
const TXOwner& whoasked,
const RouterID& target,
AbstractDHTMessageHandler* ctx,
RouterLookupHandler result);
bool
Validate(const RouterContact& rc) const override;
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

@ -1,70 +0,0 @@
#include "serviceaddresslookup.hpp"
#include <llarp/dht/messages/findintro.hpp>
#include <llarp/dht/messages/gotintro.hpp>
#include <utility>
namespace llarp
{
namespace dht
{
ServiceAddressLookup::ServiceAddressLookup(
const TXOwner& asker,
const Key_t& addr,
AbstractDHTMessageHandler* ctx,
uint32_t order,
service::EncryptedIntroSetLookupHandler handler)
: TX<TXOwner, service::EncryptedIntroSet>(asker, asker, ctx)
, location(addr)
, handleResult(std::move(handler))
, relayOrder(order)
{
peersAsked.insert(ctx->OurKey());
}
bool
ServiceAddressLookup::Validate(const service::EncryptedIntroSet& value) const
{
if (!value.verify(parent->Now()))
{
llarp::LogWarn("Got invalid introset from service lookup");
return false;
}
if (value.derivedSigningKey != location)
{
llarp::LogWarn("got introset with wrong target from service lookup");
return false;
}
return true;
}
void
ServiceAddressLookup::Start(const TXOwner& peer)
{
parent->DHTSendTo(
peer.node.as_array(), new FindIntroMessage(peer.txid, location, relayOrder));
}
void
ServiceAddressLookup::SendReply()
{
// get newest introset
if (valuesFound.size())
{
llarp::service::EncryptedIntroSet found;
for (const auto& introset : valuesFound)
{
if (found.OtherIsNewer(introset))
found = introset;
}
valuesFound.clear();
valuesFound.emplace_back(found);
}
if (handleResult)
{
handleResult(valuesFound);
}
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage(valuesFound, whoasked.txid));
}
} // namespace dht
} // namespace llarp

@ -1,41 +0,0 @@
#ifndef LLARP_DHT_SERVICEADDRESSLOOKUP
#define LLARP_DHT_SERVICEADDRESSLOOKUP
#include "key.hpp"
#include "tx.hpp"
#include <llarp/service/address.hpp>
#include <llarp/service/intro_set.hpp>
namespace llarp
{
namespace dht
{
struct TXOwner;
struct ServiceAddressLookup : public TX<TXOwner, service::EncryptedIntroSet>
{
Key_t location;
service::EncryptedIntroSetLookupHandler handleResult;
uint32_t relayOrder;
ServiceAddressLookup(
const TXOwner& asker,
const Key_t& addr,
AbstractDHTMessageHandler* ctx,
uint32_t relayOrder,
service::EncryptedIntroSetLookupHandler handler);
bool
Validate(const service::EncryptedIntroSet& value) const override;
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

@ -1,40 +0,0 @@
#include "taglookup.hpp"
#include "context.hpp"
#include <llarp/dht/messages/gotintro.hpp>
namespace llarp
{
namespace dht
{
bool
TagLookup::Validate(const service::EncryptedIntroSet& introset) const
{
if (!introset.verify(parent->Now()))
{
llarp::LogWarn("got invalid introset from tag lookup");
return false;
}
if (not introset.topic)
return false;
if (*introset.topic != target)
{
llarp::LogWarn("got introset with mismatched topic in tag lookup");
return false;
}
return true;
}
void
TagLookup::Start(const TXOwner& peer)
{
parent->DHTSendTo(peer.node.as_array(), new FindIntroMessage(target, peer.txid));
}
void
TagLookup::SendReply()
{
parent->DHTSendTo(whoasked.node.as_array(), new GotIntroMessage({}, whoasked.txid));
}
} // namespace dht
} // namespace llarp

@ -1,35 +0,0 @@
#ifndef LLARP_DHT_TAGLOOKUP
#define LLARP_DHT_TAGLOOKUP
#include "tx.hpp"
#include <llarp/service/intro_set.hpp>
#include <llarp/service/tag.hpp>
namespace llarp
{
namespace dht
{
struct TagLookup : public TX<service::Tag, service::EncryptedIntroSet>
{
uint64_t recursionDepth;
TagLookup(
const TXOwner& asker,
const service::Tag& tag,
AbstractDHTMessageHandler* ctx,
uint64_t recursion)
: TX<service::Tag, service::EncryptedIntroSet>(asker, tag, ctx), recursionDepth(recursion)
{}
bool
Validate(const service::EncryptedIntroSet& introset) const override;
void
Start(const TXOwner& peer) override;
void
SendReply() override;
};
} // namespace dht
} // namespace llarp
#endif

@ -1,79 +0,0 @@
#ifndef LLARP_DHT_TX
#define LLARP_DHT_TX
#include "key.hpp"
#include "txowner.hpp"
#include <llarp/util/logging.hpp>
#include <llarp/util/status.hpp>
#include <set>
#include <vector>
namespace llarp::dht
{
struct AbstractDHTMessageHandler;
template <typename K, typename V>
struct TX
{
K target;
AbstractDHTMessageHandler* parent;
std::set<Key_t> peersAsked;
std::vector<V> valuesFound;
TXOwner whoasked;
TX(const TXOwner& asker, const K& k, AbstractDHTMessageHandler* p)
: target(k), parent(p), whoasked(asker)
{}
virtual ~TX() = default;
void
OnFound(const Key_t& askedPeer, const V& value);
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{
{"whoasked", whoasked.ExtractStatus()}, {"target", target.ExtractStatus()}};
std::vector<util::StatusObject> foundObjs;
std::transform(
valuesFound.begin(),
valuesFound.end(),
std::back_inserter(foundObjs),
[](const auto& item) -> util::StatusObject { return item.ExtractStatus(); });
obj["found"] = foundObjs;
std::vector<std::string> asked;
std::transform(
peersAsked.begin(),
peersAsked.end(),
std::back_inserter(asked),
[](const auto& item) -> std::string { return item.ToString(); });
obj["asked"] = asked;
return obj;
}
virtual bool
Validate(const V& value) const = 0;
virtual void
Start(const TXOwner& peer) = 0;
virtual void
SendReply() = 0;
};
template <typename K, typename V>
inline void
TX<K, V>::OnFound(const Key_t& askedPeer, const V& value)
{
peersAsked.insert(askedPeer);
if (Validate(value))
{
valuesFound.push_back(value);
}
}
} // namespace llarp::dht
#endif

@ -1,216 +0,0 @@
#ifndef LLARP_DHT_TXHOLDER
#define LLARP_DHT_TXHOLDER
#include "tx.hpp"
#include "txowner.hpp"
#include <llarp/util/time.hpp>
#include <llarp/util/status.hpp>
#include <memory>
#include <unordered_map>
namespace llarp
{
namespace dht
{
template <typename K, typename V>
struct TXHolder
{
using TXPtr = std::unique_ptr<TX<K, V>>;
// tx who are waiting for a reply for each key
std::unordered_multimap<K, TXOwner> waiting;
// tx timesouts by key
std::unordered_map<K, llarp_time_t> timeouts;
// maps remote peer with tx to handle reply from them
std::unordered_map<TXOwner, TXPtr> tx;
const TX<K, V>*
GetPendingLookupFrom(const TXOwner& owner) const;
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{};
std::vector<util::StatusObject> txObjs, timeoutsObjs, waitingObjs;
std::transform(
tx.begin(),
tx.end(),
std::back_inserter(txObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"owner", item.first.ExtractStatus()}, {"tx", item.second->ExtractStatus()}};
});
obj["tx"] = txObjs;
std::transform(
timeouts.begin(),
timeouts.end(),
std::back_inserter(timeoutsObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"time", to_json(item.second)}, {"target", item.first.ExtractStatus()}};
});
obj["timeouts"] = timeoutsObjs;
std::transform(
waiting.begin(),
waiting.end(),
std::back_inserter(waitingObjs),
[](const auto& item) -> util::StatusObject {
return util::StatusObject{
{"target", item.first.ExtractStatus()},
{"whoasked", item.second.ExtractStatus()}};
});
obj["waiting"] = waitingObjs;
return obj;
}
bool
HasLookupFor(const K& target) const
{
return timeouts.find(target) != timeouts.end();
}
bool
HasPendingLookupFrom(const TXOwner& owner) const
{
return GetPendingLookupFrom(owner) != nullptr;
}
void
NewTX(
const TXOwner& askpeer,
const TXOwner& whoasked,
const K& k,
TX<K, V>* t,
llarp_time_t requestTimeoutMS = 15s);
/// mark tx as not fond
void
NotFound(const TXOwner& from, const std::unique_ptr<Key_t>& next);
void
Found(const TXOwner& from, const K& k, const std::vector<V>& values)
{
Inform(from, k, values, true);
}
/// inform all watches for key of values found
void
Inform(
TXOwner from,
K key,
std::vector<V> values,
bool sendreply = false,
bool removeTimeouts = true);
void
Expire(llarp_time_t now);
};
template <typename K, typename V>
const TX<K, V>*
TXHolder<K, V>::GetPendingLookupFrom(const TXOwner& owner) const
{
auto itr = tx.find(owner);
if (itr == tx.end())
{
return nullptr;
}
return itr->second.get();
}
template <typename K, typename V>
void
TXHolder<K, V>::NewTX(
const TXOwner& askpeer,
const TXOwner& whoasked,
const K& k,
TX<K, V>* t,
llarp_time_t requestTimeoutMS)
{
(void)whoasked;
tx.emplace(askpeer, std::unique_ptr<TX<K, V>>(t));
auto count = waiting.count(k);
waiting.emplace(k, askpeer);
auto itr = timeouts.find(k);
if (itr == timeouts.end())
{
timeouts.emplace(k, time_now_ms() + requestTimeoutMS);
}
if (count == 0)
{
t->Start(askpeer);
}
}
template <typename K, typename V>
void
TXHolder<K, V>::NotFound(const TXOwner& from, const std::unique_ptr<Key_t>&)
{
auto txitr = tx.find(from);
if (txitr == tx.end())
{
return;
}
Inform(from, txitr->second->target, {}, true, true);
}
template <typename K, typename V>
void
TXHolder<K, V>::Inform(
TXOwner from, K key, std::vector<V> values, bool sendreply, bool removeTimeouts)
{
auto range = waiting.equal_range(key);
auto itr = range.first;
while (itr != range.second)
{
auto txitr = tx.find(itr->second);
if (txitr != tx.end())
{
for (const auto& value : values)
{
txitr->second->OnFound(from.node, value);
}
if (sendreply)
{
txitr->second->SendReply();
tx.erase(txitr);
}
}
++itr;
}
if (sendreply)
{
waiting.erase(key);
}
if (removeTimeouts)
{
timeouts.erase(key);
}
}
template <typename K, typename V>
void
TXHolder<K, V>::Expire(llarp_time_t now)
{
auto itr = timeouts.begin();
while (itr != timeouts.end())
{
if (now >= itr->second)
{
Inform(TXOwner{}, itr->first, {}, true, false);
itr = timeouts.erase(itr);
}
else
{
++itr;
}
}
}
} // namespace dht
} // namespace llarp
#endif

@ -1,64 +0,0 @@
#pragma once
#include "key.hpp"
#include <llarp/util/status.hpp>
#include <cstdint>
namespace llarp
{
namespace dht
{
struct TXOwner
{
Key_t node;
uint64_t txid = 0;
TXOwner() = default;
TXOwner(const TXOwner&) = default;
TXOwner(TXOwner&&) = default;
TXOwner&
operator=(const TXOwner&) = default;
TXOwner(const Key_t& k, uint64_t id) : node(k), txid(id)
{}
util::StatusObject
ExtractStatus() const
{
util::StatusObject obj{
{"txid", txid},
{"node", node.ToHex()},
};
return obj;
}
bool
operator==(const TXOwner& other) const
{
return std::tie(txid, node) == std::tie(other.txid, other.node);
}
bool
operator<(const TXOwner& other) const
{
return std::tie(txid, node) < std::tie(other.txid, other.node);
}
};
} // namespace dht
} // namespace llarp
namespace std
{
template <>
struct hash<llarp::dht::TXOwner>
{
std::size_t
operator()(const llarp::dht::TXOwner& o) const noexcept
{
std::size_t sz2;
memcpy(&sz2, o.node.data(), sizeof(std::size_t));
return o.txid ^ (sz2 << 1);
}
};
} // namespace std

@ -1,30 +1,29 @@
#pragma once
#include <llarp/util/logging.hpp>
#include <cstdint>
namespace llarp
namespace llarp::dns
{
namespace dns
{
constexpr uint16_t qTypeSRV = 33;
constexpr uint16_t qTypeAAAA = 28;
constexpr uint16_t qTypeTXT = 16;
constexpr uint16_t qTypeMX = 15;
constexpr uint16_t qTypePTR = 12;
constexpr uint16_t qTypeCNAME = 5;
constexpr uint16_t qTypeNS = 2;
constexpr uint16_t qTypeA = 1;
constexpr uint16_t qTypeSRV = 33;
constexpr uint16_t qTypeAAAA = 28;
constexpr uint16_t qTypeTXT = 16;
constexpr uint16_t qTypeMX = 15;
constexpr uint16_t qTypePTR = 12;
constexpr uint16_t qTypeCNAME = 5;
constexpr uint16_t qTypeNS = 2;
constexpr uint16_t qTypeA = 1;
constexpr uint16_t qClassIN = 1;
constexpr uint16_t qClassIN = 1;
constexpr uint16_t flags_QR = (1 << 15);
constexpr uint16_t flags_AA = (1 << 10);
constexpr uint16_t flags_TC = (1 << 9);
constexpr uint16_t flags_RD = (1 << 8);
constexpr uint16_t flags_RA = (1 << 7);
constexpr uint16_t flags_RCODENameError = (3);
constexpr uint16_t flags_RCODEServFail = (2);
constexpr uint16_t flags_RCODENoError = (0);
constexpr uint16_t flags_QR = (1 << 15);
constexpr uint16_t flags_AA = (1 << 10);
constexpr uint16_t flags_TC = (1 << 9);
constexpr uint16_t flags_RD = (1 << 8);
constexpr uint16_t flags_RA = (1 << 7);
constexpr uint16_t flags_RCODENameError = (3);
constexpr uint16_t flags_RCODEServFail = (2);
constexpr uint16_t flags_RCODENoError = (0);
} // namespace dns
} // namespace llarp
} // namespace llarp::dns

@ -1,434 +1,432 @@
#include "message.hpp"
#include <oxenc/endian.h>
#include "dns.hpp"
#include "srv_data.hpp"
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/net/ip.hpp>
#include <llarp/util/buffer.hpp>
#include <oxenc/endian.h>
#include <array>
namespace llarp
namespace llarp::dns
{
namespace dns
static auto logcat = log::Cat("dns");
bool
MessageHeader::Encode(llarp_buffer_t* buf) const
{
if (!buf->put_uint16(id))
return false;
if (!buf->put_uint16(fields))
return false;
if (!buf->put_uint16(qd_count))
return false;
if (!buf->put_uint16(an_count))
return false;
if (!buf->put_uint16(ns_count))
return false;
return buf->put_uint16(ar_count);
}
bool
MessageHeader::Decode(llarp_buffer_t* buf)
{
static auto logcat = log::Cat("dns");
if (!buf->read_uint16(id))
return false;
if (!buf->read_uint16(fields))
return false;
if (!buf->read_uint16(qd_count))
return false;
if (!buf->read_uint16(an_count))
return false;
if (!buf->read_uint16(ns_count))
return false;
if (!buf->read_uint16(ar_count))
return false;
return true;
}
util::StatusObject
MessageHeader::ToJSON() const
{
return util::StatusObject{};
}
Message::Message(Message&& other)
: hdr_id(std::move(other.hdr_id))
, hdr_fields(std::move(other.hdr_fields))
, questions(std::move(other.questions))
, answers(std::move(other.answers))
, authorities(std::move(other.authorities))
, additional(std::move(other.additional))
{}
Message::Message(const Message& other)
: hdr_id(other.hdr_id)
, hdr_fields(other.hdr_fields)
, questions(other.questions)
, answers(other.answers)
, authorities(other.authorities)
, additional(other.additional)
{}
Message::Message(const MessageHeader& hdr) : hdr_id(hdr.id), hdr_fields(hdr.fields)
{
questions.resize(size_t(hdr.qd_count));
answers.resize(size_t(hdr.an_count));
authorities.resize(size_t(hdr.ns_count));
additional.resize(size_t(hdr.ar_count));
}
bool
MessageHeader::Encode(llarp_buffer_t* buf) const
{
if (!buf->put_uint16(id))
return false;
if (!buf->put_uint16(fields))
return false;
if (!buf->put_uint16(qd_count))
return false;
if (!buf->put_uint16(an_count))
return false;
if (!buf->put_uint16(ns_count))
return false;
return buf->put_uint16(ar_count);
}
Message::Message(const Question& question) : hdr_id{0}, hdr_fields{}
{
questions.emplace_back(question);
}
bool
MessageHeader::Decode(llarp_buffer_t* buf)
{
if (!buf->read_uint16(id))
return false;
if (!buf->read_uint16(fields))
return false;
if (!buf->read_uint16(qd_count))
return false;
if (!buf->read_uint16(an_count))
return false;
if (!buf->read_uint16(ns_count))
return false;
if (!buf->read_uint16(ar_count))
bool
Message::Encode(llarp_buffer_t* buf) const
{
MessageHeader hdr;
hdr.id = hdr_id;
hdr.fields = hdr_fields;
hdr.qd_count = questions.size();
hdr.an_count = answers.size();
hdr.ns_count = 0;
hdr.ar_count = 0;
if (!hdr.Encode(buf))
return false;
for (const auto& question : questions)
if (!question.Encode(buf))
return false;
return true;
}
util::StatusObject
MessageHeader::ToJSON() const
{
return util::StatusObject{};
}
Message::Message(Message&& other)
: hdr_id(std::move(other.hdr_id))
, hdr_fields(std::move(other.hdr_fields))
, questions(std::move(other.questions))
, answers(std::move(other.answers))
, authorities(std::move(other.authorities))
, additional(std::move(other.additional))
{}
Message::Message(const Message& other)
: hdr_id(other.hdr_id)
, hdr_fields(other.hdr_fields)
, questions(other.questions)
, answers(other.answers)
, authorities(other.authorities)
, additional(other.additional)
{}
Message::Message(const MessageHeader& hdr) : hdr_id(hdr.id), hdr_fields(hdr.fields)
{
questions.resize(size_t(hdr.qd_count));
answers.resize(size_t(hdr.an_count));
authorities.resize(size_t(hdr.ns_count));
additional.resize(size_t(hdr.ar_count));
}
Message::Message(const Question& question) : hdr_id{0}, hdr_fields{}
{
questions.emplace_back(question);
}
bool
Message::Encode(llarp_buffer_t* buf) const
{
MessageHeader hdr;
hdr.id = hdr_id;
hdr.fields = hdr_fields;
hdr.qd_count = questions.size();
hdr.an_count = answers.size();
hdr.ns_count = 0;
hdr.ar_count = 0;
if (!hdr.Encode(buf))
for (const auto& answer : answers)
if (!answer.Encode(buf))
return false;
for (const auto& question : questions)
if (!question.Encode(buf))
return false;
return true;
}
for (const auto& answer : answers)
if (!answer.Encode(buf))
return false;
return true;
}
bool
Message::Decode(llarp_buffer_t* buf)
bool
Message::Decode(llarp_buffer_t* buf)
{
for (auto& qd : questions)
{
for (auto& qd : questions)
if (!qd.Decode(buf))
{
if (!qd.Decode(buf))
{
log::error(logcat, "failed to decode question");
return false;
}
log::debug(logcat, "question: {}", qd);
}
for (auto& an : answers)
{
if (not an.Decode(buf))
{
log::debug(logcat, "failed to decode answer");
return false;
}
log::error(logcat, "failed to decode question");
return false;
}
return true;
log::debug(logcat, "question: {}", qd);
}
util::StatusObject
Message::ToJSON() const
for (auto& an : answers)
{
std::vector<util::StatusObject> ques;
std::vector<util::StatusObject> ans;
for (const auto& q : questions)
if (not an.Decode(buf))
{
ques.push_back(q.ToJSON());
}
for (const auto& a : answers)
{
ans.push_back(a.ToJSON());
log::debug(logcat, "failed to decode answer");
return false;
}
return util::StatusObject{{"questions", ques}, {"answers", ans}};
}
return true;
}
OwnedBuffer
Message::ToBuffer() const
util::StatusObject
Message::ToJSON() const
{
std::vector<util::StatusObject> ques;
std::vector<util::StatusObject> ans;
for (const auto& q : questions)
{
std::array<byte_t, 1500> tmp;
llarp_buffer_t buf{tmp};
if (not Encode(&buf))
throw std::runtime_error("cannot encode dns message");
return OwnedBuffer::copy_used(buf);
ques.push_back(q.ToJSON());
}
void
Message::AddServFail(RR_TTL_t)
for (const auto& a : answers)
{
if (questions.size())
{
hdr_fields |= flags_RCODEServFail;
// authorative response with recursion available
hdr_fields |= flags_QR | flags_AA | flags_RA;
// don't allow recursion on this request
hdr_fields &= ~flags_RD;
}
ans.push_back(a.ToJSON());
}
return util::StatusObject{{"questions", ques}, {"answers", ans}};
}
static constexpr uint16_t
reply_flags(uint16_t setbits)
OwnedBuffer
Message::ToBuffer() const
{
std::array<byte_t, 1500> tmp;
llarp_buffer_t buf{tmp};
if (not Encode(&buf))
throw std::runtime_error("cannot encode dns message");
return OwnedBuffer::copy_used(buf);
}
void
Message::AddServFail(RR_TTL_t)
{
if (questions.size())
{
return setbits | flags_QR | flags_AA | flags_RA;
hdr_fields |= flags_RCODEServFail;
// authorative response with recursion available
hdr_fields |= flags_QR | flags_AA | flags_RA;
// don't allow recursion on this request
hdr_fields &= ~flags_RD;
}
}
static constexpr uint16_t
reply_flags(uint16_t setbits)
{
return setbits | flags_QR | flags_AA | flags_RA;
}
void
Message::AddINReply(llarp::huint128_t ip, bool isV6, RR_TTL_t ttl)
void
Message::AddINReply(llarp::huint128_t ip, bool isV6, RR_TTL_t ttl)
{
if (questions.size())
{
if (questions.size())
hdr_fields = reply_flags(hdr_fields);
ResourceRecord rec;
rec.rr_name = questions[0].qname;
rec.rr_class = qClassIN;
rec.ttl = ttl;
if (isV6)
{
hdr_fields = reply_flags(hdr_fields);
ResourceRecord rec;
rec.rr_name = questions[0].qname;
rec.rr_class = qClassIN;
rec.ttl = ttl;
if (isV6)
{
rec.rr_type = qTypeAAAA;
ip.ToV6(rec.rData);
}
else
{
const auto addr = net::TruncateV6(ip);
rec.rr_type = qTypeA;
rec.rData.resize(4);
oxenc::write_host_as_big(addr.h, rec.rData.data());
}
answers.emplace_back(std::move(rec));
rec.rr_type = qTypeAAAA;
ip.ToV6(rec.rData);
}
}
void
Message::AddAReply(std::string name, RR_TTL_t ttl)
{
if (questions.size())
else
{
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = question.qtype;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
if (EncodeNameTo(&buf, name))
{
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
const auto addr = net::TruncateV6(ip);
rec.rr_type = qTypeA;
rec.rData.resize(4);
oxenc::write_host_as_big(addr.h, rec.rData.data());
}
answers.emplace_back(std::move(rec));
}
}
void
Message::AddNSReply(std::string name, RR_TTL_t ttl)
void
Message::AddAReply(std::string name, RR_TTL_t ttl)
{
if (questions.size())
{
if (not questions.empty())
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = question.qtype;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
if (EncodeNameTo(&buf, name))
{
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeNS;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
if (EncodeNameTo(&buf, name))
{
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
}
}
void
Message::AddCNAMEReply(std::string name, RR_TTL_t ttl)
void
Message::AddNSReply(std::string name, RR_TTL_t ttl)
{
if (not questions.empty())
{
if (questions.size())
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeNS;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
if (EncodeNameTo(&buf, name))
{
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeCNAME;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
if (EncodeNameTo(&buf, name))
{
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
}
}
void
Message::AddMXReply(std::string name, uint16_t priority, RR_TTL_t ttl)
void
Message::AddCNAMEReply(std::string name, RR_TTL_t ttl)
{
if (questions.size())
{
if (questions.size())
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeCNAME;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
if (EncodeNameTo(&buf, name))
{
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeMX;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
buf.put_uint16(priority);
if (EncodeNameTo(&buf, name))
{
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
}
}
void
Message::AddSRVReply(std::vector<SRVData> records, RR_TTL_t ttl)
void
Message::AddMXReply(std::string name, uint16_t priority, RR_TTL_t ttl)
{
if (questions.size())
{
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
for (const auto& srv : records)
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeMX;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
buf.put_uint16(priority);
if (EncodeNameTo(&buf, name))
{
if (not srv.IsValid())
{
AddNXReply();
return;
}
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeSRV;
rec.rr_class = qClassIN;
rec.ttl = ttl;
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
buf.put_uint16(srv.priority);
buf.put_uint16(srv.weight);
buf.put_uint16(srv.port);
std::string target;
if (srv.target == "")
{
// get location of second dot (after service.proto) in qname
size_t pos = question.qname.find(".");
pos = question.qname.find(".", pos + 1);
target = question.qname.substr(pos + 1);
}
else
{
target = srv.target;
}
if (not EncodeNameTo(&buf, target))
{
AddNXReply();
return;
}
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
}
}
void
Message::AddTXTReply(std::string str, RR_TTL_t ttl)
void
Message::AddSRVReply(std::vector<SRVData> records, RR_TTL_t ttl)
{
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
for (const auto& srv : records)
{
auto& rec = answers.emplace_back();
rec.rr_name = questions[0].qname;
if (not srv.IsValid())
{
AddNXReply();
return;
}
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeSRV;
rec.rr_class = qClassIN;
rec.rr_type = qTypeTXT;
rec.ttl = ttl;
std::array<byte_t, 1024> tmp{};
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp);
while (not str.empty())
buf.put_uint16(srv.priority);
buf.put_uint16(srv.weight);
buf.put_uint16(srv.port);
std::string target;
if (srv.target == "")
{
const auto left = std::min(str.size(), size_t{256});
const auto sub = str.substr(0, left);
uint8_t byte = left;
*buf.cur = byte;
buf.cur++;
if (not buf.write(sub.begin(), sub.end()))
throw std::length_error("text record too big");
str = str.substr(left);
// get location of second dot (after service.proto) in qname
size_t pos = question.qname.find(".");
pos = question.qname.find(".", pos + 1);
target = question.qname.substr(pos + 1);
}
else
{
target = srv.target;
}
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
std::copy_n(buf.base, buf.sz, rec.rData.data());
}
void
Message::AddNXReply(RR_TTL_t)
{
if (questions.size())
if (not EncodeNameTo(&buf, target))
{
answers.clear();
authorities.clear();
additional.clear();
// authorative response with recursion available
hdr_fields = reply_flags(hdr_fields);
// don't allow recursion on this request
hdr_fields &= ~flags_RD;
hdr_fields |= flags_RCODENameError;
AddNXReply();
return;
}
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
}
}
std::string
Message::ToString() const
void
Message::AddTXTReply(std::string str, RR_TTL_t ttl)
{
auto& rec = answers.emplace_back();
rec.rr_name = questions[0].qname;
rec.rr_class = qClassIN;
rec.rr_type = qTypeTXT;
rec.ttl = ttl;
std::array<byte_t, 1024> tmp{};
llarp_buffer_t buf(tmp);
while (not str.empty())
{
return fmt::format(
"[DNSMessage id={:x} fields={:x} questions={{{}}} answers={{{}}} authorities={{{}}} "
"additional={{{}}}]",
hdr_id,
hdr_fields,
fmt::format("{}", fmt::join(questions, ",")),
fmt::format("{}", fmt::join(answers, ",")),
fmt::format("{}", fmt::join(authorities, ",")),
fmt::format("{}", fmt::join(additional, ",")));
const auto left = std::min(str.size(), size_t{256});
const auto sub = str.substr(0, left);
uint8_t byte = left;
*buf.cur = byte;
buf.cur++;
if (not buf.write(sub.begin(), sub.end()))
throw std::length_error("text record too big");
str = str.substr(left);
}
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
std::copy_n(buf.base, buf.sz, rec.rData.data());
}
std::optional<Message>
MaybeParseDNSMessage(llarp_buffer_t buf)
void
Message::AddNXReply(RR_TTL_t)
{
if (questions.size())
{
MessageHeader hdr{};
if (not hdr.Decode(&buf))
return std::nullopt;
Message msg{hdr};
if (not msg.Decode(&buf))
return std::nullopt;
return msg;
answers.clear();
authorities.clear();
additional.clear();
// authorative response with recursion available
hdr_fields = reply_flags(hdr_fields);
// don't allow recursion on this request
hdr_fields &= ~flags_RD;
hdr_fields |= flags_RCODENameError;
}
} // namespace dns
} // namespace llarp
}
std::string
Message::ToString() const
{
return fmt::format(
"[DNSMessage id={:x} fields={:x} questions={{{}}} answers={{{}}} authorities={{{}}} "
"additional={{{}}}]",
hdr_id,
hdr_fields,
fmt::format("{}", fmt::join(questions, ",")),
fmt::format("{}", fmt::join(answers, ",")),
fmt::format("{}", fmt::join(authorities, ",")),
fmt::format("{}", fmt::join(additional, ",")));
}
std::optional<Message>
MaybeParseDNSMessage(llarp_buffer_t buf)
{
MessageHeader hdr{};
if (not hdr.Decode(&buf))
return std::nullopt;
Message msg{hdr};
if (not msg.Decode(&buf))
return std::nullopt;
return msg;
}
} // namespace llarp::dns

@ -1,8 +1,8 @@
#pragma once
#include "serialize.hpp"
#include "rr.hpp"
#include "question.hpp"
#include "rr.hpp"
#include "serialize.hpp"
namespace llarp
{

@ -1,139 +1,138 @@
#include "name.hpp"
#include <llarp/net/net.hpp>
#include <llarp/net/ip.hpp>
#include <llarp/net/net_bits.hpp>
#include <llarp/util/str.hpp>
#include <oxenc/hex.h>
namespace llarp
namespace llarp::dns
{
namespace dns
std::optional<std::string>
DecodeName(llarp_buffer_t* buf, bool trimTrailingDot)
{
std::optional<std::string>
DecodeName(llarp_buffer_t* buf, bool trimTrailingDot)
if (buf->size_left() < 1)
return std::nullopt;
auto result = std::make_optional<std::string>();
auto& name = *result;
size_t l;
do
{
if (buf->size_left() < 1)
return std::nullopt;
auto result = std::make_optional<std::string>();
auto& name = *result;
size_t l;
do
l = *buf->cur;
buf->cur++;
if (l)
{
l = *buf->cur;
buf->cur++;
if (l)
{
if (buf->size_left() < l)
return std::nullopt;
if (buf->size_left() < l)
return std::nullopt;
name.append((const char*)buf->cur, l);
name += '.';
}
buf->cur = buf->cur + l;
} while (l);
/// trim off last dot
if (trimTrailingDot)
name.pop_back();
return result;
}
name.append((const char*)buf->cur, l);
name += '.';
}
buf->cur = buf->cur + l;
} while (l);
/// trim off last dot
if (trimTrailingDot)
name.pop_back();
return result;
}
bool
EncodeNameTo(llarp_buffer_t* buf, std::string_view name)
{
if (name.size() && name.back() == '.')
name.remove_suffix(1);
bool
EncodeNameTo(llarp_buffer_t* buf, std::string_view name)
{
if (name.size() && name.back() == '.')
name.remove_suffix(1);
for (auto part : llarp::split(name, "."))
for (auto part : llarp::split(name, "."))
{
size_t l = part.length();
if (l > 63)
return false;
*(buf->cur) = l;
buf->cur++;
if (buf->size_left() < l)
return false;
if (l)
{
size_t l = part.length();
if (l > 63)
return false;
*(buf->cur) = l;
buf->cur++;
if (buf->size_left() < l)
return false;
if (l)
{
std::memcpy(buf->cur, part.data(), l);
buf->cur += l;
}
else
break;
std::memcpy(buf->cur, part.data(), l);
buf->cur += l;
}
*buf->cur = 0;
buf->cur++;
return true;
else
break;
}
*buf->cur = 0;
buf->cur++;
return true;
}
std::optional<huint128_t>
DecodePTR(std::string_view name)
std::optional<huint128_t>
DecodePTR(std::string_view name)
{
bool isV6 = false;
auto pos = name.find(".in-addr.arpa");
if (pos == std::string::npos)
{
bool isV6 = false;
auto pos = name.find(".in-addr.arpa");
if (pos == std::string::npos)
{
pos = name.find(".ip6.arpa");
isV6 = true;
}
if (pos == std::string::npos)
return std::nullopt;
name = name.substr(0, pos + 1);
const auto numdots = std::count(name.begin(), name.end(), '.');
if (numdots == 4 && !isV6)
pos = name.find(".ip6.arpa");
isV6 = true;
}
if (pos == std::string::npos)
return std::nullopt;
name = name.substr(0, pos + 1);
const auto numdots = std::count(name.begin(), name.end(), '.');
if (numdots == 4 && !isV6)
{
std::array<uint8_t, 4> q;
for (int i = 3; i >= 0; i--)
{
std::array<uint8_t, 4> q;
for (int i = 3; i >= 0; i--)
{
pos = name.find('.');
if (!llarp::parse_int(name.substr(0, pos), q[i]))
return std::nullopt;
name.remove_prefix(pos + 1);
}
return net::ExpandV4(llarp::ipaddr_ipv4_bits(q[0], q[1], q[2], q[3]));
pos = name.find('.');
if (!llarp::parse_int(name.substr(0, pos), q[i]))
return std::nullopt;
name.remove_prefix(pos + 1);
}
if (numdots == 32 && name.size() == 64 && isV6)
return net::ExpandV4(llarp::ipaddr_ipv4_bits(q[0], q[1], q[2], q[3]));
}
if (numdots == 32 && name.size() == 64 && isV6)
{
// We're going to convert from nybbles a.b.c.d.e.f.0.1.2.3.[...] into hex string
// "badcfe1032...", then decode the hex string to bytes.
std::array<char, 32> in;
auto in_pos = in.data();
for (size_t i = 0; i < 64; i += 4)
{
// We're going to convert from nybbles a.b.c.d.e.f.0.1.2.3.[...] into hex string
// "badcfe1032...", then decode the hex string to bytes.
std::array<char, 32> in;
auto in_pos = in.data();
for (size_t i = 0; i < 64; i += 4)
{
if (not(oxenc::is_hex_digit(name[i]) and name[i + 1] == '.'
and oxenc::is_hex_digit(name[i + 2]) and name[i + 3] == '.'))
return std::nullopt;
if (not(oxenc::is_hex_digit(name[i]) and name[i + 1] == '.'
and oxenc::is_hex_digit(name[i + 2]) and name[i + 3] == '.'))
return std::nullopt;
// Flip the nybbles because the smallest one is first
*in_pos++ = name[i + 2];
*in_pos++ = name[i];
}
assert(in_pos == in.data() + in.size());
huint128_t ip;
static_assert(in.size() == 2 * sizeof(ip.h));
// our string right now is the little endian representation, so load it as such on little
// endian, or in reverse on big endian.
if constexpr (oxenc::little_endian)
oxenc::from_hex(in.begin(), in.end(), reinterpret_cast<uint8_t*>(&ip.h));
else
oxenc::from_hex(in.rbegin(), in.rend(), reinterpret_cast<uint8_t*>(&ip.h));
return ip;
// Flip the nybbles because the smallest one is first
*in_pos++ = name[i + 2];
*in_pos++ = name[i];
}
return std::nullopt;
assert(in_pos == in.data() + in.size());
huint128_t ip;
static_assert(in.size() == 2 * sizeof(ip.h));
// our string right now is the little endian representation, so load it as such on little
// endian, or in reverse on big endian.
if constexpr (oxenc::little_endian)
oxenc::from_hex(in.begin(), in.end(), reinterpret_cast<uint8_t*>(&ip.h));
else
oxenc::from_hex(in.rbegin(), in.rend(), reinterpret_cast<uint8_t*>(&ip.h));
return ip;
}
return std::nullopt;
}
bool
NameIsReserved(std::string_view name)
bool
NameIsReserved(std::string_view name)
{
const std::vector<std::string_view> reserved_names = {
".snode.loki"sv, ".loki.loki"sv, ".snode.loki."sv, ".loki.loki."sv};
for (const auto& reserved : reserved_names)
{
const std::vector<std::string_view> reserved_names = {
".snode.loki"sv, ".loki.loki"sv, ".snode.loki."sv, ".loki.loki."sv};
for (const auto& reserved : reserved_names)
{
if (ends_with(name, reserved)) // subdomain foo.loki.loki
return true;
if (name == reserved.substr(1)) // loki.loki itself
return true;
}
return false;
if (ends_with(name, reserved)) // subdomain foo.loki.loki
return true;
if (name == reserved.substr(1)) // loki.loki itself
return true;
}
} // namespace dns
} // namespace llarp
return false;
}
} // namespace llarp::dns

@ -3,26 +3,23 @@
#include <llarp/net/net_int.hpp>
#include <llarp/util/buffer.hpp>
#include <string>
#include <optional>
#include <string>
namespace llarp
namespace llarp::dns
{
namespace dns
{
/// decode name from buffer; return nullopt on failure
std::optional<std::string>
DecodeName(llarp_buffer_t* buf, bool trimTrailingDot = false);
/// decode name from buffer; return nullopt on failure
std::optional<std::string>
DecodeName(llarp_buffer_t* buf, bool trimTrailingDot = false);
/// encode name to buffer
bool
EncodeNameTo(llarp_buffer_t* buf, std::string_view name);
/// encode name to buffer
bool
EncodeNameTo(llarp_buffer_t* buf, std::string_view name);
std::optional<huint128_t>
DecodePTR(std::string_view name);
std::optional<huint128_t>
DecodePTR(std::string_view name);
bool
NameIsReserved(std::string_view name);
bool
NameIsReserved(std::string_view name);
} // namespace dns
} // namespace llarp
} // namespace llarp::dns

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save