Review commit

pull/2213/head
dr7ana 8 months ago
parent 0e451db77f
commit e710cfea47

1
.gitignore vendored

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

@ -0,0 +1,5 @@
set(GRAPHVIZ_MODULE_LIBS OFF CACHE BOOL "")
set(GRAPHVIZ_EXTERNAL_LIBS OFF CACHE BOOL "")
set(GRAPHVIZ_GENERATE_PER_TARGET OFF CACHE BOOL "")
set(GRAPHVIZ_GENERATE_DEPENDERS OFF CACHE BOOL "")
set(GRAPHVIZ_OBJECT_LIBS OFF CACHE BOOL "")

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

@ -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 <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

@ -1,16 +1,11 @@
#include <oxenmq/oxenmq.h>
#include <nlohmann/json.hpp>
#include <fmt/core.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 <fmt/core.h>
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <oxenmq/oxenmq.h>
#ifdef _WIN32
// add the unholy windows headers for iphlpapi
@ -19,7 +14,6 @@
#include <iphlpapi.h>
#include <strsafe.h>
#else
#include <sys/wait.h>
#endif
/// do a oxenmq request on an omq instance blocking style

@ -3,8 +3,7 @@
#include <llarp.hpp>
#include <llarp/util/lokinet_init.h>
#include <llarp/util/exceptions.hpp>
#include <llarp/util/fs.hpp>
#include <llarp/util/str.hpp>
#include <bits/chrono.h>
#ifdef _WIN32
#include <llarp/win32/service_manager.hpp>
@ -13,16 +12,38 @@
#include <llarp/util/service_manager.hpp>
#endif
#include <csignal>
#include <CLI/CLI.hpp>
#include <csignal>
#include <string>
#include <iostream>
#include <thread>
#include <future>
#include <CLI/App.hpp>
#include <CLI/Formatter.hpp>
#include <CLI/Config.hpp>
#include <cstdlib>
#include <exception>
#include <filesystem>
#include <initializer_list>
#include <memory>
#include <optional>
#include <stdexcept>
#include <utility>
#include "CLI/Error.hpp"
#include "CLI/Option.hpp"
#include "CLI/impl/App_inl.hpp"
#include "CLI/impl/Option_inl.hpp"
#include "fmt/core.h"
#include "llarp/constants/files.hpp"
#include "llarp/constants/platform.hpp"
#include "llarp/ev/ev.hpp"
#include "llarp/util/logging.hpp"
#include "llarp/util/thread/threading.hpp"
#include "oxen/log.hpp"
#include "oxen/log/catlogger.hpp"
#include "oxen/log/level.hpp"
#include "oxen/log/ring_buffer_sink.hpp"
#include "oxen/log/type.hpp"
#include "spdlog/common.h"
namespace
{
@ -350,8 +371,8 @@ namespace
int
lokinet_main(int argc, char** argv)
{
if (auto result = Lokinet_INIT())
return result;
// if (auto result = Lokinet_INIT())
// return result;
llarp::RuntimeOptions opts;
opts.showBanner = false;

@ -7,38 +7,128 @@ add_library(lokinet-cryptography
crypto/types.cpp
)
add_library(lokinet-util
# files only included by lokinet-core
add_library(lokinet-core-internal
STATIC
router/rc_gossiper.cpp
service/info.cpp
service/lns_tracker.cpp
service/session.cpp
)
# Functional objects use by lokinet-core and other libraries
# needed by vpn/ router/ rpc/ handlers/ net/ link/
add_library(lokinet-core-utils
STATIC
endpoint_base.cpp
exit/context.cpp
exit/endpoint.cpp # handlers/exit.hpp
exit/policy.cpp # net/
service/auth.cpp # config/
service/context.cpp
service/identity.cpp
service/intro.cpp # path
service/name.cpp
service/tag.cpp
)
add_library(lokinet-core
STATIC
context.cpp
consensus/reachability_testing.cpp
exit/session.cpp
handlers/exit.cpp # link/ exit/
handlers/tun.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
vpn/egres_packet_router.cpp
)
# Files only included by lokinet-rpc
# add_library(lokinet-rpc-internal
# STATIC
# )
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
)
# Files only included by lokinet-wire
add_library(lokinet-wire-internal
STATIC
link/connection.cpp
)
add_library(lokinet-wire
STATIC
link/contacts.cpp
link/link_manager.cpp
# link/tunnel.cpp
)
add_library(lokinet-utils-internal
STATIC
util/thread/queue_manager.cpp
)
# config, crypto, timeplace, nodedb, bootstrap.cpp, net, router
add_library(lokinet-utils
STATIC
${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)
add_dependencies(lokinet-util genversion)
util/time.cpp
util/logging/buffer.cpp
)
add_dependencies(lokinet-utils genversion)
# lokinet-platform holds all platform specific code
add_library(lokinet-platform
# Addressing and event loop files used by lokinet-core and other libraries
# needed by rpc/ link/ service/ config/ path/ dht/
add_library(lokinet-time-place
STATIC
# for networking
pow.cpp # only intro_set
router_contact.cpp
router_id.cpp
router_version.cpp # to be deleted shortly
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
service/address.cpp
service/convotag.cpp
service/intro_set.cpp
)
# lokinet-platform holds all platform specific code
add_library(lokinet-platform
STATIC
router/rc_lookup_handler.cpp
net/interface_info.cpp
vpn/packet_router.cpp
vpn/egres_packet_router.cpp
vpn/platform.cpp
)
@ -80,16 +170,21 @@ endif()
# 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
add_library(lokinet-dns-internal
STATIC
dns/message.cpp
dns/name.cpp
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)
)
add_library(lokinet-dns
STATIC
dns/message.cpp # dns/server
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)
@ -102,15 +197,10 @@ endif()
# 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
bootstrap.cpp # config, router.hpp
nodedb.cpp
pow.cpp
profiling.cpp
router_contact.cpp
router_id.cpp
router_version.cpp
profiling.cpp # path, router, service::endpoint
net/traffic_policy.cpp # config, intro_set
)
set(BOOTSTRAP_FALLBACKS)
@ -141,15 +231,8 @@ add_library(lokinet-config
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
# All path objects; link directly to lokinet-core
add_library(lokinet-path
STATIC
path/abstracthophandler.cpp
path/path_context.cpp
@ -160,262 +243,140 @@ add_library(lokinet-layer-onion
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
)
# 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
)
# 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/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/session.cpp
service/tag.cpp
)
add_library(lokinet-amalgum INTERFACE)
# interface library for setting commone includes, linkage and flags.
# interface library for setting common 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)
# Absolutely fuck this line, it doesn't "create" the target, as the target already exists
# 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-cryptography lokinet-peerstats)
if(TARGET lokinet-dns-systemd)
lokinet_link_lib(lokinet-dns-systemd
lokinet-dns
lokinet-platform
)
# Link libraries to their internals
target_link_libraries(lokinet-core-internal PUBLIC lokinet-utils lokinet-core-utils)
target_link_libraries(lokinet-core PRIVATE lokinet-core-internal)
# target_link_libraries(lokinet-rpc PRIVATE lokinet-rpc-internal)
target_link_libraries(lokinet-wire PRIVATE lokinet-wire-internal)
# target_link_libraries(lokinet-time-place PRIVATE lokinet-time-place-internal)
target_link_libraries(lokinet-dns PRIVATE lokinet-dns-internal)
target_link_libraries(lokinet-utils PRIVATE lokinet-utils-internal)
# Link lokinet-dns to alternate libraries
target_link_libraries(lokinet-dns PUBLIC lokinet-dns-platform)
if (TARGET lokinet-dns-systemd)
target_link_libraries(lokinet-dns PUBLIC lokinet-dns-systemd)
endif()
lokinet_link_lib(lokinet-platform lokinet-util)
lokinet_link_lib(lokinet-config
lokinet-util
# Link relevant to lokinet-base
target_link_libraries(lokinet-core PUBLIC lokinet-base)
target_link_libraries(lokinet-rpc PUBLIC lokinet-base)
target_link_libraries(lokinet-nodedb PUBLIC lokinet-base)
target_link_libraries(lokinet-wire PUBLIC lokinet-base)
target_link_libraries(lokinet-time-place PUBLIC lokinet-base)
target_link_libraries(lokinet-dns PUBLIC lokinet-base)
target_link_libraries(lokinet-platform PUBLIC lokinet-base)
target_link_libraries(lokinet-utils PUBLIC lokinet-base)
target_link_libraries(lokinet-libntrup PUBLIC lokinet-base)
# Link relevant to amalgum
target_link_libraries(lokinet-amalgum
INTERFACE
lokinet-core
lokinet-rpc
lokinet-nodedb
lokinet-wire
lokinet-time-place
lokinet-dns
lokinet-platform
lokinet-utils
lokinet-cryptography
lokinet-path
)
lokinet_link_lib(lokinet-context
lokinet-config
lokinet-platform
lokinet-peerstats
lokinet-layers
lokinet-consensus
lokinet-rpc
#or just do this??
# target_link_libraries(lokinet-amalgum INTERFACE lokinet-base)
target_link_libraries(lokinet-wire-internal PUBLIC lokinet-time-place)
target_link_libraries(lokinet-dns-internal PUBLIC lokinet-utils lokinet-config)
target_link_libraries(lokinet-dns PUBLIC lokinet-cryptography)
target_link_libraries(lokinet-nodedb PUBLIC 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-path
PUBLIC
lokinet-time-place
)
lokinet_link_lib(
target_link_libraries(lokinet-core-utils
PUBLIC
lokinet-core
lokinet-wire
lokinet-rpc
lokinet-platform
lokinet-config
)
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
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
)
# 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
# cross linkage
target_link_libraries(lokinet-core
PUBLIC
lokinet-rpc
lokinet-wire
lokinet-nodedb
lokinet-config
lokinet-cryptography
)
# per component external deps
# target_link_libraries(oxenmq::oxenmq
# PUBLIC
# lokinet-time-place
# lokinet-core
# lokinet-config
# lokinet-platform
# lokinet-dns
# lokinet-rpc
# )
target_link_libraries(lokinet-rpc PUBLIC oxenmq::oxenmq oxenc::oxenc)
target_link_libraries(lokinet-core PUBLIC oxenmq::oxenmq CLI11 uvw)
target_link_libraries(lokinet-config PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq)
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
)
if(WITH_EMBEDDED_LOKINET)
include(GNUInstallDirs)
add_library(lokinet-shared SHARED lokinet_shared.cpp)
target_link_libraries(lokinet-shared PUBLIC lokinet-amalgum)
if(WIN32)
set(CMAKE_SHARED_LIBRARY_PREFIX_CXX "")
endif()
set_target_properties(lokinet-shared PROPERTIES OUTPUT_NAME lokinet)
if(WIN32)
target_link_libraries(lokinet-shared PUBLIC ws2_32 iphlpapi -fstack-protector)
install(TARGETS lokinet-shared DESTINATION bin COMPONENT liblokinet)
elseif(NOT APPLE)
install(TARGETS lokinet-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT liblokinet)
endif()
endif()
file(GLOB_RECURSE docs_SRC */*.hpp *.hpp)
set(DOCS_SRC ${docs_SRC} PARENT_SCOPE)
target_link_libraries(lokinet-nodedb PUBLIC oxenmq::oxenmq uvw)
target_link_libraries(lokinet-path PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-time-place PUBLIC uvw oxenc::oxenc)
target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq Threads::Threads base_libs uvw)
target_link_libraries(lokinet-cryptography PUBLIC oxenc::oxenc sodium)
target_link_libraries(lokinet-dns PUBLIC libunbound uvw)
target_link_libraries(lokinet-utils PUBLIC nlohmann_json::nlohmann_json oxenc::oxenc)
target_link_libraries(lokinet-wire PUBLIC oxenmq::oxenmq quic uvw)
# if(WITH_EMBEDDED_LOKINET)
# include(GNUInstallDirs)
# add_library(lokinet-shared SHARED lokinet_shared.cpp)
# target_link_libraries(lokinet-shared PUBLIC lokinet-amalgum)
# if(WIN32)
# set(CMAKE_SHARED_LIBRARY_PREFIX_CXX "")
# endif()
# set_target_properties(lokinet-shared PROPERTIES OUTPUT_NAME lokinet)
# if(WIN32)
# target_link_libraries(lokinet-shared PUBLIC ws2_32 iphlpapi -fstack-protector)
# install(TARGETS lokinet-shared DESTINATION bin COMPONENT liblokinet)
# elseif(NOT APPLE)
# install(TARGETS lokinet-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT liblokinet)
# endif()
# endif()
# file(GLOB_RECURSE docs_SRC */*.hpp *.hpp)
# set(DOCS_SRC ${docs_SRC} PARENT_SCOPE)

@ -0,0 +1,421 @@
include(Version)
add_library(lokinet-cryptography
STATIC
crypto/crypto.cpp
crypto/encrypted_frame.cpp
crypto/types.cpp
)
add_library(lokinet-util
STATIC
${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)
add_dependencies(lokinet-util genversion)
# lokinet-platform holds all platform specific code
add_library(lokinet-platform
STATIC
# for networking
ev/ev.cpp
ev/libuv.cpp
net/interface_info.cpp
net/ip.cpp
net/ip_address.cpp
net/ip_packet.cpp
net/ip_range.cpp
net/net_int.cpp
net/sock_addr.cpp
vpn/packet_router.cpp
vpn/egres_packet_router.cpp
vpn/platform.cpp
)
if (ANDROID)
target_sources(lokinet-platform PRIVATE android/ifaddrs.c util/nop_service_manager.cpp)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
target_sources(lokinet-platform PRIVATE linux/dbus.cpp)
if(WITH_SYSTEMD)
target_sources(lokinet-platform PRIVATE linux/sd_service_manager.cpp)
else()
target_sources(lokinet-platform PRIVATE util/nop_service_manager.cpp)
endif()
endif()
if (WIN32)
target_sources(lokinet-platform PRIVATE
net/win32.cpp
vpn/win32.cpp
win32/service_manager.cpp
win32/exec.cpp
win32/dll.cpp
win32/exception.cpp
win32/wintun.cpp
win32/windivert.cpp)
target_include_directories(lokinet-platform PRIVATE ${CMAKE_BINARY_DIR}/wintun/include/ ${CMAKE_BINARY_DIR}/WinDivert-${WINDIVERT_VERSION}/include/)
else()
target_sources(lokinet-platform PRIVATE
net/posix.cpp)
endif()
if(APPLE)
add_subdirectory(apple)
target_sources(lokinet-platform PRIVATE util/nop_service_manager.cpp)
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
dns/platform.cpp
dns/question.cpp
dns/rr.cpp
dns/serialize.cpp
dns/server.cpp
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)
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
nodedb.cpp
pow.cpp
profiling.cpp
router_contact.cpp
router_id.cpp
router_version.cpp
)
set(BOOTSTRAP_FALLBACKS)
foreach(bs IN ITEMS MAINNET TESTNET)
if(BOOTSTRAP_FALLBACK_${bs})
message(STATUS "Building with ${bs} fallback boostrap path \"${BOOTSTRAP_FALLBACK_${bs}}\"")
file(READ "${BOOTSTRAP_FALLBACK_${bs}}" bs_data HEX)
if(bs STREQUAL TESTNET)
set(network "gamma")
elseif(bs STREQUAL MAINNET)
set(network "lokinet")
else()
string(TOLOWER "${bs}" network)
endif()
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "\\\\x\\1" bs_data "${bs_data}")
set(BOOTSTRAP_FALLBACKS "${BOOTSTRAP_FALLBACKS}{\"${network}\"s, \"${bs_data}\"sv},\n")
endif()
endforeach()
configure_file("bootstrap-fallbacks.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/bootstrap-fallbacks.cpp" @ONLY)
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
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
path/abstracthophandler.cpp
path/path_context.cpp
path/path.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
)
# 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
)
# 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/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/session.cpp
service/tag.cpp
)
# 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)
# Absolutely fuck this line, it doesn't "create" the target, as the target already exists
# 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-cryptography lokinet-peerstats)
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
lokinet-config
lokinet-platform
lokinet-peerstats
lokinet-layers
lokinet-consensus
lokinet-rpc
)
lokinet_link_lib(
lokinet-platform
lokinet-config
)
lokinet_link_lib(lokinet-dns
lokinet-platform
lokinet-dns-platform
lokinet-config
)
lokinet_link_lib(lokinet-nodedb
lokinet-util
lokinet-platform
)
lokinet_link_lib(lokinet-util
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
)
# 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-config PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq)
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
)
if(WITH_EMBEDDED_LOKINET)
include(GNUInstallDirs)
add_library(lokinet-shared SHARED lokinet_shared.cpp)
target_link_libraries(lokinet-shared PUBLIC lokinet-amalgum)
if(WIN32)
set(CMAKE_SHARED_LIBRARY_PREFIX_CXX "")
endif()
set_target_properties(lokinet-shared PROPERTIES OUTPUT_NAME lokinet)
if(WIN32)
target_link_libraries(lokinet-shared PUBLIC ws2_32 iphlpapi -fstack-protector)
install(TARGETS lokinet-shared DESTINATION bin COMPONENT liblokinet)
elseif(NOT APPLE)
install(TARGETS lokinet-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT liblokinet)
endif()
endif()
file(GLOB_RECURSE docs_SRC */*.hpp *.hpp)
set(DOCS_SRC ${docs_SRC} PARENT_SCOPE)

@ -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,8 +1,9 @@
#pragma once
#include "router_contact.hpp"
#include <set>
#include <unordered_map>
#include "router_contact.hpp"
#include "llarp/util/fs.hpp"
namespace llarp

@ -0,0 +1,25 @@
#include <initializer_list>
#include "llarp/bootstrap.hpp"
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,6 +1,4 @@
#include "config.hpp"
#include "definition.hpp"
#include "ini.hpp"
#include <llarp/constants/files.hpp>
#include <llarp/constants/platform.hpp>
@ -8,19 +6,14 @@
#include <llarp/net/net.hpp>
#include <llarp/net/ip.hpp>
#include <llarp/router_contact.hpp>
#include <stdexcept>
#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 <stdexcept>
#include <chrono>
#include <cstdlib>
#include <ios>
#include <iostream>
#include "definition.hpp"
#include "ini.hpp"
namespace llarp
{

@ -1,11 +1,6 @@
#pragma once
#include "ini.hpp"
#include "definition.hpp"
#include <llarp/net/traffic_policy.hpp>
#include <llarp/net/net.hpp>
#include <chrono>
#include <llarp/bootstrap.hpp>
#include <llarp/crypto/types.hpp>
#include <llarp/router_contact.hpp>
@ -20,7 +15,8 @@
#include <llarp/service/auth.hpp>
#include <llarp/dns/srv_data.hpp>
#include <llarp/router_contact.hpp>
#include <oxenmq/address.h>
#include <chrono>
#include <cstdlib>
#include <functional>
#include <optional>
@ -29,7 +25,8 @@
#include <vector>
#include <unordered_set>
#include <oxenmq/address.h>
#include "ini.hpp"
#include "definition.hpp"
namespace llarp
{

@ -1,11 +1,10 @@
#pragma once
#include <fmt/core.h>
#include <initializer_list>
#include <type_traits>
#include <llarp/util/str.hpp>
#include <llarp/util/fs.hpp>
#include <initializer_list>
#include <type_traits>
#include <iostream>
#include <memory>
#include <set>

@ -2,13 +2,10 @@
#include <llarp/util/logging.hpp>
#include <llarp/util/formattable.hpp>
#include <llarp/util/str.hpp>
#include <cctype>
#include <fstream>
#include <list>
#include <iostream>
#include <cassert>
#include <stdexcept>
namespace llarp

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

@ -1,9 +1,10 @@
#pragma once
#include <atomic>
#include "config.hpp"
#include <llarp/crypto/types.hpp>
#include <llarp/router_contact.hpp>
#include <atomic>
#include "config.hpp"
namespace llarp
{

@ -1,6 +1,6 @@
#include "reachability_testing.hpp"
#include <chrono>
#include <llarp/router/router.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/crypto/crypto.hpp>

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

@ -1,5 +1,3 @@
#include "nodedb.hpp"
#include <llarp.hpp>
#include <llarp/constants/version.hpp>
#include <llarp/constants/evloop.hpp>
@ -7,18 +5,14 @@
#include <llarp/crypto/crypto.hpp>
#include <llarp/ev/ev.hpp>
#include <llarp/router/router.hpp>
#include <llarp/service/context.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 <memory>
#include <csignal>
#include <stdexcept>
#include "nodedb.hpp"
#if (__FreeBSD__) || (__OpenBSD__) || (__NetBSD__)
#include <pthread_np.h>
#endif

@ -3,7 +3,6 @@
#include <sodium/core.h>
#include <sodium/crypto_generichash.h>
#include <sodium/crypto_sign.h>
#include <sodium/crypto_scalarmult.h>
#include <sodium/crypto_scalarmult_ed25519.h>
#include <sodium/crypto_stream_xchacha20.h>
#include <sodium/crypto_core_ed25519.h>
@ -11,16 +10,12 @@
#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

@ -1,14 +1,12 @@
#pragma once
#include "constants.hpp"
#include "types.hpp"
#include <llarp/util/buffer.hpp>
#include <functional>
#include <cstdint>
#include "constants.hpp"
#include "types.hpp"
namespace llarp
{
/*

@ -1,8 +1,8 @@
#include "encrypted_frame.hpp"
#include "crypto.hpp"
#include <llarp/util/logging.hpp>
#include <llarp/util/mem.hpp>
#include "crypto.hpp"
namespace llarp
{

@ -1,10 +1,11 @@
#pragma once
#include "encrypted.hpp"
#include "types.hpp"
#include <llarp/util/buffer.hpp>
#include <utility>
#include <llarp/util/mem.h>
#include <utility>
#include "encrypted.hpp"
#include "types.hpp"
namespace llarp
{

@ -2,14 +2,10 @@
#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_scalarmult_ed25519.h>
// #include <sodium/crypto_hash_sha512.h>
// #include <sodium/crypto_scalarmult_ed25519.h>
namespace llarp
{

@ -1,14 +1,16 @@
#pragma once
#include "constants.hpp"
#include <sodium.h>
#include <llarp/router_id.hpp>
#include <llarp/util/aligned.hpp>
#include <llarp/util/types.hpp>
#include <llarp/util/fs.hpp>
#include <algorithm>
#include <iostream>
#include "constants.hpp"
namespace llarp
{
using SharedSecret = AlignedBuffer<SHAREDKEYSIZE>;

@ -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,430 @@
#include "message.hpp"
#include <oxenc/endian.h>
#include "dns.hpp"
#include "srv_data.hpp"
#include <oxenc/endian.h>
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/net/ip.hpp>
#include <array>
namespace llarp
#include "dns.hpp"
#include "srv_data.hpp"
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)
{
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)
{
static auto logcat = log::Cat("dns");
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;
for (const auto& answer : answers)
if (!answer.Encode(buf))
return false;
return true;
}
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))
{
log::error(logcat, "failed to decode question");
return false;
}
log::debug(logcat, "question: {}", qd);
}
for (auto& an : answers)
if (!qd.Decode(buf))
{
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)
{
ques.push_back(q.ToJSON());
}
for (const auto& a : answers)
if (not an.Decode(buf))
{
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::AddSRVReply(std::vector<SRVData> records, RR_TTL_t ttl)
{
hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0];
void
Message::AddTXTReply(std::string str, RR_TTL_t ttl)
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 == "")
{
// 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
{
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);
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,139 +1,137 @@
#include "name.hpp"
#include <llarp/net/net.hpp>
#include <llarp/net/ip.hpp>
#include <llarp/util/str.hpp>
#include <llarp/net/net_bits.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

@ -2,27 +2,23 @@
#include <llarp/net/net_int.hpp>
#include <llarp/util/buffer.hpp>
#include <string>
#include <optional>
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

@ -1,8 +1,8 @@
#pragma once
#include <string>
#include <memory>
#include <llarp/net/sock_addr.hpp>
#include <llarp/util/logging.hpp>
#include <string>
#include <memory>
#include <stdexcept>
#ifndef _WIN32

@ -1 +0,0 @@
#pragma once

@ -1,129 +1,126 @@
#include "question.hpp"
#include <llarp/util/logging.hpp>
#include <llarp/util/str.hpp>
#include "dns.hpp"
namespace llarp
namespace llarp::dns
{
namespace dns
static auto logcat = log::Cat("dns");
Question::Question(Question&& other)
: qname(std::move(other.qname))
, qtype(std::move(other.qtype))
, qclass(std::move(other.qclass))
{}
Question::Question(const Question& other)
: qname(other.qname), qtype(other.qtype), qclass(other.qclass)
{}
Question::Question(std::string name, QType_t type)
: qname{std::move(name)}, qtype{type}, qclass{qClassIN}
{
static auto logcat = log::Cat("dns");
Question::Question(Question&& other)
: qname(std::move(other.qname))
, qtype(std::move(other.qtype))
, qclass(std::move(other.qclass))
{}
Question::Question(const Question& other)
: qname(other.qname), qtype(other.qtype), qclass(other.qclass)
{}
Question::Question(std::string name, QType_t type)
: qname{std::move(name)}, qtype{type}, qclass{qClassIN}
{
if (qname.empty())
throw std::invalid_argument{"qname cannot be empty"};
}
if (qname.empty())
throw std::invalid_argument{"qname cannot be empty"};
}
bool
Question::Encode(llarp_buffer_t* buf) const
bool
Question::Encode(llarp_buffer_t* buf) const
{
if (!EncodeNameTo(buf, qname))
return false;
if (!buf->put_uint16(qtype))
return false;
return buf->put_uint16(qclass);
}
bool
Question::Decode(llarp_buffer_t* buf)
{
if (auto name = DecodeName(buf))
qname = *std::move(name);
else
{
if (!EncodeNameTo(buf, qname))
return false;
if (!buf->put_uint16(qtype))
return false;
return buf->put_uint16(qclass);
log::error(logcat, "failed to decode name");
return false;
}
bool
Question::Decode(llarp_buffer_t* buf)
if (!buf->read_uint16(qtype))
{
if (auto name = DecodeName(buf))
qname = *std::move(name);
else
{
log::error(logcat, "failed to decode name");
return false;
}
if (!buf->read_uint16(qtype))
{
log::error(logcat, "failed to decode type");
return false;
}
if (!buf->read_uint16(qclass))
{
log::error(logcat, "failed to decode class");
return false;
}
return true;
log::error(logcat, "failed to decode type");
return false;
}
util::StatusObject
Question::ToJSON() const
if (!buf->read_uint16(qclass))
{
return util::StatusObject{{"qname", qname}, {"qtype", qtype}, {"qclass", qclass}};
log::error(logcat, "failed to decode class");
return false;
}
return true;
}
bool
Question::IsName(const std::string& other) const
{
// does other have a . at the end?
if (other.find_last_of('.') == (other.size() - 1))
return other == qname;
// no, add it and retry
return IsName(other + ".");
}
util::StatusObject
Question::ToJSON() const
{
return util::StatusObject{{"qname", qname}, {"qtype", qtype}, {"qclass", qclass}};
}
bool
Question::IsLocalhost() const
{
return (qname == "localhost.loki." or llarp::ends_with(qname, ".localhost.loki."));
}
bool
Question::IsName(const std::string& other) const
{
// does other have a . at the end?
if (other.find_last_of('.') == (other.size() - 1))
return other == qname;
// no, add it and retry
return IsName(other + ".");
}
bool
Question::IsLocalhost() const
{
return (qname == "localhost.loki." or llarp::ends_with(qname, ".localhost.loki."));
}
bool
Question::HasSubdomains() const
{
const auto parts = split(qname, ".", true);
return parts.size() >= 3;
}
bool
Question::HasSubdomains() const
{
const auto parts = split(qname, ".", true);
return parts.size() >= 3;
}
std::string
Question::Subdomains() const
{
if (qname.size() < 2)
return "";
std::string
Question::Subdomains() const
{
if (qname.size() < 2)
return "";
size_t pos;
size_t pos;
pos = qname.rfind('.', qname.size() - 2);
if (pos == std::string::npos or pos == 0)
return "";
pos = qname.rfind('.', qname.size() - 2);
if (pos == std::string::npos or pos == 0)
return "";
pos = qname.rfind('.', pos - 1);
if (pos == std::string::npos or pos == 0)
return "";
pos = qname.rfind('.', pos - 1);
if (pos == std::string::npos or pos == 0)
return "";
return qname.substr(0, pos);
}
return qname.substr(0, pos);
}
std::string
Question::Name() const
{
return qname.substr(0, qname.find_last_of('.'));
}
std::string
Question::Name() const
{
return qname.substr(0, qname.find_last_of('.'));
}
bool
Question::HasTLD(const std::string& tld) const
{
return qname.find(tld) != std::string::npos
&& qname.rfind(tld) == (qname.size() - tld.size()) - 1;
}
bool
Question::HasTLD(const std::string& tld) const
{
return qname.find(tld) != std::string::npos
&& qname.rfind(tld) == (qname.size() - tld.size()) - 1;
}
std::string
Question::ToString() const
{
return fmt::format("[DNSQuestion qname={} qtype={:x} qclass={:x}]", qname, qtype, qclass);
}
} // namespace dns
} // namespace llarp
std::string
Question::ToString() const
{
return fmt::format("[DNSQuestion qname={} qtype={:x} qclass={:x}]", qname, qtype, qclass);
}
} // namespace llarp::dns

@ -2,71 +2,69 @@
#include "serialize.hpp"
#include "name.hpp"
#include <llarp/net/net_int.hpp>
namespace llarp
namespace llarp::dns
{
namespace dns
{
using QType_t = uint16_t;
using QClass_t = uint16_t;
using QType_t = uint16_t;
using QClass_t = uint16_t;
struct Question : public Serialize
{
Question() = default;
struct Question : public Serialize
{
Question() = default;
explicit Question(std::string name, QType_t type);
explicit Question(std::string name, QType_t type);
Question(Question&& other);
Question(const Question& other);
bool
Encode(llarp_buffer_t* buf) const override;
Question(Question&& other);
Question(const Question& other);
bool
Encode(llarp_buffer_t* buf) const override;
bool
Decode(llarp_buffer_t* buf) override;
bool
Decode(llarp_buffer_t* buf) override;
std::string
ToString() const;
std::string
ToString() const;
bool
operator==(const Question& other) const
{
return qname == other.qname && qtype == other.qtype && qclass == other.qclass;
}
bool
operator==(const Question& other) const
{
return qname == other.qname && qtype == other.qtype && qclass == other.qclass;
}
std::string qname;
QType_t qtype;
QClass_t qclass;
std::string qname;
QType_t qtype;
QClass_t qclass;
/// determine if we match a name
bool
IsName(const std::string& other) const;
/// determine if we match a name
bool
IsName(const std::string& other) const;
/// is the name [something.]localhost.loki. ?
bool
IsLocalhost() const;
/// is the name [something.]localhost.loki. ?
bool
IsLocalhost() const;
/// return true if we have subdomains in ths question
bool
HasSubdomains() const;
/// return true if we have subdomains in ths question
bool
HasSubdomains() const;
/// get subdomain(s), if any, from qname
std::string
Subdomains() const;
/// get subdomain(s), if any, from qname
std::string
Subdomains() const;
/// return qname with no trailing .
std::string
Name() const;
/// return qname with no trailing .
std::string
Name() const;
/// determine if we are using this TLD
bool
HasTLD(const std::string& tld) const;
/// determine if we are using this TLD
bool
HasTLD(const std::string& tld) const;
util::StatusObject
ToJSON() const override;
};
} // namespace dns
} // namespace llarp
util::StatusObject
ToJSON() const override;
};
} // namespace llarp::dns
template <>
constexpr inline bool llarp::IsToStringFormattable<llarp::dns::Question> = true;

@ -1,125 +1,116 @@
#include "rr.hpp"
#include "dns.hpp"
#include <llarp/util/formattable.hpp>
#include <llarp/util/mem.hpp>
#include <llarp/util/logging.hpp>
namespace llarp
namespace llarp::dns
{
namespace dns
{
static auto logcat = log::Cat("dns");
static auto logcat = log::Cat("dns");
ResourceRecord::ResourceRecord(const ResourceRecord& other)
: rr_name(other.rr_name)
, rr_type(other.rr_type)
, rr_class(other.rr_class)
, ttl(other.ttl)
, rData(other.rData)
{}
ResourceRecord::ResourceRecord(const ResourceRecord& other)
: rr_name(other.rr_name)
, rr_type(other.rr_type)
, rr_class(other.rr_class)
, ttl(other.ttl)
, rData(other.rData)
{}
ResourceRecord::ResourceRecord(ResourceRecord&& other)
: rr_name(std::move(other.rr_name))
, rr_type(std::move(other.rr_type))
, rr_class(std::move(other.rr_class))
, ttl(std::move(other.ttl))
, rData(std::move(other.rData))
{}
ResourceRecord::ResourceRecord(ResourceRecord&& other)
: rr_name(std::move(other.rr_name))
, rr_type(std::move(other.rr_type))
, rr_class(std::move(other.rr_class))
, ttl(std::move(other.ttl))
, rData(std::move(other.rData))
{}
ResourceRecord::ResourceRecord(std::string name, RRType_t type, RR_RData_t data)
: rr_name{std::move(name)}
, rr_type{type}
, rr_class{qClassIN}
, ttl{1}
, rData{std::move(data)}
{}
ResourceRecord::ResourceRecord(std::string name, RRType_t type, RR_RData_t data)
: rr_name{std::move(name)}, rr_type{type}, rr_class{qClassIN}, ttl{1}, rData{std::move(data)}
{}
bool
ResourceRecord::Encode(llarp_buffer_t* buf) const
bool
ResourceRecord::Encode(llarp_buffer_t* buf) const
{
if (not EncodeNameTo(buf, rr_name))
return false;
if (!buf->put_uint16(rr_type))
{
if (not EncodeNameTo(buf, rr_name))
return false;
if (!buf->put_uint16(rr_type))
{
return false;
}
if (!buf->put_uint16(rr_class))
{
return false;
}
if (!buf->put_uint32(ttl))
{
return false;
}
if (!EncodeRData(buf, rData))
{
return false;
}
return true;
return false;
}
bool
ResourceRecord::Decode(llarp_buffer_t* buf)
if (!buf->put_uint16(rr_class))
{
uint16_t discard;
if (!buf->read_uint16(discard))
return false;
if (!buf->read_uint16(rr_type))
{
log::debug(logcat, "failed to decode rr type");
return false;
}
if (!buf->read_uint16(rr_class))
{
log::debug(logcat, "failed to decode rr class");
return false;
}
if (!buf->read_uint32(ttl))
{
log::debug(logcat, "failed to decode ttl");
return false;
}
if (!DecodeRData(buf, rData))
{
log::debug(logcat, "failed to decode rr rdata {}", *this);
return false;
}
return true;
return false;
}
util::StatusObject
ResourceRecord::ToJSON() const
if (!buf->put_uint32(ttl))
{
return util::StatusObject{
{"name", rr_name},
{"type", rr_type},
{"class", rr_class},
{"ttl", ttl},
{"rdata", std::string{reinterpret_cast<const char*>(rData.data()), rData.size()}}};
return false;
}
std::string
ResourceRecord::ToString() const
if (!EncodeRData(buf, rData))
{
return fmt::format(
"[RR name={} type={} class={} ttl={} rdata-size={}]",
rr_name,
rr_type,
rr_class,
ttl,
rData.size());
return false;
}
return true;
}
bool
ResourceRecord::HasCNameForTLD(const std::string& tld) const
bool
ResourceRecord::Decode(llarp_buffer_t* buf)
{
uint16_t discard;
if (!buf->read_uint16(discard))
return false;
if (!buf->read_uint16(rr_type))
{
if (rr_type != qTypeCNAME)
return false;
llarp_buffer_t buf(rData);
if (auto name = DecodeName(&buf))
return name->rfind(tld) == name->size() - tld.size() - 1;
log::debug(logcat, "failed to decode rr type");
return false;
}
if (!buf->read_uint16(rr_class))
{
log::debug(logcat, "failed to decode rr class");
return false;
}
if (!buf->read_uint32(ttl))
{
log::debug(logcat, "failed to decode ttl");
return false;
}
if (!DecodeRData(buf, rData))
{
log::debug(logcat, "failed to decode rr rdata {}", *this);
return false;
}
return true;
}
util::StatusObject
ResourceRecord::ToJSON() const
{
return util::StatusObject{
{"name", rr_name},
{"type", rr_type},
{"class", rr_class},
{"ttl", ttl},
{"rdata", std::string{reinterpret_cast<const char*>(rData.data()), rData.size()}}};
}
std::string
ResourceRecord::ToString() const
{
return fmt::format(
"[RR name={} type={} class={} ttl={} rdata-size={}]",
rr_name,
rr_type,
rr_class,
ttl,
rData.size());
}
bool
ResourceRecord::HasCNameForTLD(const std::string& tld) const
{
if (rr_type != qTypeCNAME)
return false;
llarp_buffer_t buf(rData);
if (auto name = DecodeName(&buf))
return name->rfind(tld) == name->size() - tld.size() - 1;
return false;
}
} // namespace dns
} // namespace llarp
} // namespace llarp::dns

@ -1,52 +1,49 @@
#pragma once
#include "name.hpp"
#include "serialize.hpp"
#include <llarp/net/net_int.hpp>
#include <memory>
#include <vector>
namespace llarp
#include "name.hpp"
#include "serialize.hpp"
namespace llarp::dns
{
namespace dns
using RRClass_t = uint16_t;
using RRType_t = uint16_t;
using RR_RData_t = std::vector<byte_t>;
using RR_TTL_t = uint32_t;
struct ResourceRecord : public Serialize
{
using RRClass_t = uint16_t;
using RRType_t = uint16_t;
using RR_RData_t = std::vector<byte_t>;
using RR_TTL_t = uint32_t;
struct ResourceRecord : public Serialize
{
ResourceRecord() = default;
ResourceRecord(const ResourceRecord& other);
ResourceRecord(ResourceRecord&& other);
explicit ResourceRecord(std::string name, RRType_t type, RR_RData_t rdata);
bool
Encode(llarp_buffer_t* buf) const override;
bool
Decode(llarp_buffer_t* buf) override;
util::StatusObject
ToJSON() const override;
std::string
ToString() const;
bool
HasCNameForTLD(const std::string& tld) const;
std::string rr_name;
RRType_t rr_type;
RRClass_t rr_class;
RR_TTL_t ttl;
RR_RData_t rData;
};
} // namespace dns
} // namespace llarp
ResourceRecord() = default;
ResourceRecord(const ResourceRecord& other);
ResourceRecord(ResourceRecord&& other);
explicit ResourceRecord(std::string name, RRType_t type, RR_RData_t rdata);
bool
Encode(llarp_buffer_t* buf) const override;
bool
Decode(llarp_buffer_t* buf) override;
util::StatusObject
ToJSON() const override;
std::string
ToString() const;
bool
HasCNameForTLD(const std::string& tld) const;
std::string rr_name;
RRType_t rr_type;
RRClass_t rr_class;
RR_TTL_t ttl;
RR_RData_t rData;
};
} // namespace llarp::dns
template <>
constexpr inline bool llarp::IsToStringFormattable<llarp::dns::ResourceRecord> = true;

@ -1,44 +1,40 @@
#include "serialize.hpp"
#include <llarp/net/net_int.hpp>
namespace llarp
namespace llarp::dns
{
namespace dns
Serialize::~Serialize() = default;
bool
EncodeRData(llarp_buffer_t* buf, const std::vector<byte_t>& v)
{
Serialize::~Serialize() = default;
if (v.size() > 65536)
return false;
uint16_t len = v.size();
if (!buf->put_uint16(len))
return false;
if (buf->size_left() < len)
return false;
memcpy(buf->cur, v.data(), len);
buf->cur += len;
return true;
}
bool
EncodeRData(llarp_buffer_t* buf, const std::vector<byte_t>& v)
bool
DecodeRData(llarp_buffer_t* buf, std::vector<byte_t>& v)
{
uint16_t len;
if (!buf->read_uint16(len))
return false;
size_t left = buf->size_left();
if (left < len)
return false;
v.resize(size_t(len));
if (len)
{
if (v.size() > 65536)
return false;
uint16_t len = v.size();
if (!buf->put_uint16(len))
return false;
if (buf->size_left() < len)
return false;
memcpy(buf->cur, v.data(), len);
memcpy(v.data(), buf->cur, len);
buf->cur += len;
return true;
}
bool
DecodeRData(llarp_buffer_t* buf, std::vector<byte_t>& v)
{
uint16_t len;
if (!buf->read_uint16(len))
return false;
size_t left = buf->size_left();
if (left < len)
return false;
v.resize(size_t(len));
if (len)
{
memcpy(v.data(), buf->cur, len);
buf->cur += len;
}
return true;
}
return true;
}
} // namespace dns
} // namespace llarp
} // namespace llarp::dns

@ -4,33 +4,30 @@
#include <llarp/util/status.hpp>
#include <vector>
namespace llarp
namespace llarp::dns
{
namespace dns
/// base type for serializable dns entities
struct Serialize
{
/// base type for serializable dns entities
struct Serialize
{
virtual ~Serialize() = 0;
virtual ~Serialize() = 0;
/// encode entity to buffer
virtual bool
Encode(llarp_buffer_t* buf) const = 0;
/// encode entity to buffer
virtual bool
Encode(llarp_buffer_t* buf) const = 0;
/// decode entity from buffer
virtual bool
Decode(llarp_buffer_t* buf) = 0;
/// decode entity from buffer
virtual bool
Decode(llarp_buffer_t* buf) = 0;
/// convert this whatever into json
virtual util::StatusObject
ToJSON() const = 0;
};
/// convert this whatever into json
virtual util::StatusObject
ToJSON() const = 0;
};
bool
EncodeRData(llarp_buffer_t* buf, const std::vector<byte_t>& rdata);
bool
EncodeRData(llarp_buffer_t* buf, const std::vector<byte_t>& rdata);
bool
DecodeRData(llarp_buffer_t* buf, std::vector<byte_t>& rdata);
bool
DecodeRData(llarp_buffer_t* buf, std::vector<byte_t>& rdata);
} // namespace dns
} // namespace llarp
} // namespace llarp::dns

@ -1,22 +1,20 @@
#include "server.hpp"
#include <llarp/constants/platform.hpp>
#include <llarp/constants/apple.hpp>
#include "dns.hpp"
#include <iterator>
#include <llarp/crypto/crypto.hpp>
#include <array>
#include <llarp/ev/udp_handle.hpp>
#include <unbound.h>
#include <stdexcept>
#include <utility>
#include <llarp/ev/udp_handle.hpp>
#include <optional>
#include <memory>
#include <unbound.h>
#include <uvw.hpp>
#include "oxen/log.hpp"
#include "sd_platform.hpp"
#include "nm_platform.hpp"
#include <uvw.hpp>
namespace llarp::dns
{
static auto logcat = log::Cat("dns");

@ -1,7 +1,5 @@
#pragma once
#include "message.hpp"
#include "platform.hpp"
#include <llarp/config/config.hpp>
#include <llarp/ev/ev.hpp>
#include <llarp/net/net.hpp>
@ -9,6 +7,9 @@
#include <llarp/util/compare_ptr.hpp>
#include <set>
#include "message.hpp"
#include "platform.hpp"
namespace llarp::dns
{
/// a job handling 1 dns query

@ -1,12 +1,10 @@
#include "srv_data.hpp"
#include <llarp/util/str.hpp>
#include <llarp/util/logging.hpp>
#include <limits>
#include <oxenc/bt_serialize.h>
#include "llarp/util/bencode.h"
#include "llarp/util/types.hpp"
#include <llarp/util/bencode.h>
#include <llarp/util/types.hpp>
#include <llarp/util/str.hpp>
namespace llarp::dns
{

@ -1,11 +1,11 @@
#pragma once
#include "name.hpp"
#include "serialize.hpp"
#include <tuple>
#include <string_view>
#include "dns.hpp"
#include "name.hpp"
#include "serialize.hpp"
#include "llarp/util/status.hpp"
namespace llarp::dns

@ -4,19 +4,16 @@
struct llarp_buffer_t;
namespace llarp
namespace llarp::dns
{
namespace dns
{
using name_t = std::string;
using name_t = std::string;
/// decode name from buffer
bool
decode_name(llarp_buffer_t* buf, name_t& name);
/// decode name from buffer
bool
decode_name(llarp_buffer_t* buf, name_t& name);
/// encode name to buffer
bool
encode_name(llarp_buffer_t* buf, const name_t& name);
/// encode name to buffer
bool
encode_name(llarp_buffer_t* buf, const name_t& name);
} // namespace dns
} // namespace llarp
} // namespace llarp::dns

@ -1,14 +1,7 @@
#pragma once
#include "llarp/service/address.hpp"
#include "llarp/service/convotag.hpp"
#include "llarp/service/protocol_type.hpp"
#include "router_id.hpp"
#include "llarp/ev/ev.hpp"
#include "llarp/dns/srv_data.hpp"
#include <llarp/link/tunnel.hpp>
#include <quic.hpp>
#include <functional>
#include <memory>
#include <string>
@ -16,8 +9,14 @@
#include <optional>
#include <unordered_set>
#include <set>
#include "llarp/service/address.hpp"
#include "llarp/service/convotag.hpp"
#include "llarp/service/protocol_type.hpp"
#include "router_id.hpp"
#include "llarp/ev/ev.hpp"
#include "llarp/dns/srv_data.hpp"
#include "oxenc/variant.h"
#include <quic.hpp>
namespace llarp
{

@ -1,13 +1,9 @@
#include "ev.hpp"
#include <llarp/util/mem.hpp>
#include <llarp/util/str.hpp>
#include <llarp/net/net.hpp>
#include <cstddef>
#include <cstring>
#include <string_view>
#include "libuv.hpp"
#include <llarp/net/net.hpp>
namespace llarp
{

@ -1,13 +1,13 @@
#include "libuv.hpp"
#include <llarp/util/exceptions.hpp>
#include <llarp/vpn/platform.hpp>
#include <memory>
#include <thread>
#include <type_traits>
#include <cstring>
#include <llarp/util/exceptions.hpp>
#include <llarp/util/thread/queue.hpp>
#include <llarp/vpn/platform.hpp>
#include <uvw.hpp>
namespace llarp::uv

@ -1,18 +1,17 @@
#pragma once
#include "ev.hpp"
#include "udp_handle.hpp"
#include <llarp/util/thread/queue.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <uvw/loop.h>
#include <uvw/async.h>
#include <uvw/poll.h>
#include <uvw/udp.h>
#include <functional>
#include <map>
#include <vector>
#include "ev.hpp"
#include "udp_handle.hpp"
namespace llarp::uv
{
class UVWakeup;

@ -1,10 +1,10 @@
#pragma once
#include "policy.hpp"
#include <llarp/handlers/exit.hpp>
#include <string>
#include <unordered_map>
#include "policy.hpp"
namespace llarp::exit
{
/// owner of all the exit endpoints

@ -5,7 +5,6 @@
#include <llarp/path/abstracthophandler.hpp>
#include <llarp/service/protocol_type.hpp>
#include <llarp/util/time.hpp>
#include <queue>
namespace llarp

@ -5,7 +5,6 @@
#include <llarp/path/path_context.hpp>
#include <llarp/path/path.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <utility>
namespace llarp::exit

@ -4,7 +4,6 @@
#include <llarp/net/ip_packet.hpp>
#include <llarp/path/pathbuilder.hpp>
#include <llarp/constants/path.hpp>
#include <deque>
#include <queue>

@ -4,20 +4,16 @@
#include <llarp/net/net.hpp>
#include <llarp/path/path_context.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/bits.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <cassert>
#include <llarp/service/protocol_type.hpp>
#include <cassert>
namespace llarp::handlers
{
ExitEndpoint::ExitEndpoint(std::string name, Router* r)
: router(r)
, name(std::move(name))
, tunnel_manager{std::make_shared<link::TunnelManager>(*this)}
// , tunnel_manager{std::make_shared<link::TunnelManager>(*this)}
{
should_init_tun = true;
}
@ -784,7 +780,8 @@ namespace llarp::handlers
link::TunnelManager*
ExitEndpoint::GetQUICTunnel()
{
return tunnel_manager.get();
return nullptr;
// return tunnel_manager.get();
}
bool

@ -1,10 +1,11 @@
#pragma once
#include <llarp/exit/endpoint.hpp>
#include "tun.hpp"
#include <llarp/dns/server.hpp>
#include <unordered_map>
#include "tun.hpp"
namespace llarp
{
struct Router;
@ -226,7 +227,7 @@ namespace llarp
SockAddr resolver_addr;
std::vector<SockAddr> upstream_resolvers;
std::shared_ptr<link::TunnelManager> tunnel_manager;
// std::shared_ptr<link::TunnelManager> tunnel_manager;
using PacketQueue_t = std::
priority_queue<net::IPPacket, std::vector<net::IPPacket>, net::IPPacket::CompareOrder>;

@ -1,11 +1,10 @@
#include <algorithm>
#include <iterator>
#include <variant>
#include "tun.hpp"
#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <netdb.h>
#endif
#include <llarp/dns/dns.hpp>
@ -16,20 +15,13 @@
#include <llarp/service/context.hpp>
#include <llarp/service/outbound_context.hpp>
#include <llarp/service/endpoint_state.hpp>
#include <llarp/service/outbound_context.hpp>
#include <llarp/service/name.hpp>
#include <llarp/service/protocol_type.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/rpc/endpoint_rpc.hpp>
#include <llarp/util/str.hpp>
#include <llarp/util/logging/buffer.hpp>
#include <llarp/dns/srv_data.hpp>
#include <llarp/constants/net.hpp>
#include <llarp/constants/platform.hpp>
#include <oxenc/bt.h>
namespace llarp::handlers
{
static auto logcat = log::Cat("tun");

@ -11,7 +11,6 @@
#include <llarp/util/thread/threading.hpp>
#include <llarp/vpn/packet_router.hpp>
#include <llarp/vpn/platform.hpp>
#include <future>
#include <type_traits>
#include <variant>

@ -2,7 +2,6 @@
#include <llarp/router_id.hpp>
#include <llarp/router_contact.hpp>
#include <quic.hpp>
namespace llarp::link

@ -463,11 +463,6 @@ namespace llarp
return;
}
// TODO: do we still need this concept?
void
LinkManager::update_peer_db(std::shared_ptr<PeerDb>)
{}
// TODO: this
util::StatusObject
LinkManager::extract_status() const

@ -1,23 +1,19 @@
#pragma once
#include "connection.hpp"
#include <llarp/constants/path.hpp>
#include <llarp/util/decaying_hashset.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/peerstats/peer_db.hpp>
#include <llarp/crypto/crypto.hpp>
#include <llarp/util/compare_ptr.hpp>
#include <quic.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/priority_queue.hpp>
#include <unordered_map>
#include <set>
#include <atomic>
#include <llarp/util/logging.hpp>
#include <llarp/util/priority_queue.hpp>
#include "connection.hpp"
namespace
{
@ -264,9 +260,6 @@ namespace llarp
void
check_persisting_conns(llarp_time_t now);
void
update_peer_db(std::shared_ptr<PeerDb> peerDb);
util::StatusObject
extract_status() const;

@ -20,7 +20,7 @@ namespace llarp
namespace llarp::link
{
struct Endpoint;
// struct Endpoint;
using namespace std::chrono_literals;
@ -153,7 +153,7 @@ namespace llarp::link
struct ClientTunnel
{
// quic endpoint
std::unique_ptr<Endpoint> client;
// std::unique_ptr<Endpoint> client;
// Callback to invoke on quic connection established (true argument) or failed (false arg)
OpenCallback open_cb;
// TCP listening socket
@ -164,7 +164,28 @@ namespace llarp::link
// because we are still handshaking, or we reached the stream limit).
std::queue<std::weak_ptr<uvw::TCPHandle>> pending_incoming;
~ClientTunnel();
~ClientTunnel()
{
// if (tcp)
// {
// tcp->close();
// tcp->data(nullptr);
// tcp.reset();
// }
// for (auto& conn : conns)
// conn->close();
// conns.clear();
// while (not pending_incoming.empty())
// {
// if (auto tcp = pending_incoming.front().lock())
// {
// tcp->clear();
// tcp->close();
// }
// pending_incoming.pop();
// }
}
};
// pseudo-port -> Client instance (the "port" is used to route incoming quic packets to the

@ -1,162 +0,0 @@
#include <llarp/crypto/crypto.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/bencode.h>
#include <llarp/util/logging.hpp>
#include <oxenc/bt_producer.h>
namespace llarp
{
bool
LinkIntroMessage::decode_key(const llarp_buffer_t& key, llarp_buffer_t* buf)
{
if (key.startswith("a"))
{
llarp_buffer_t strbuf;
if (!bencode_read_string(buf, &strbuf))
return false;
if (strbuf.sz != 1)
return false;
return *strbuf.cur == 'i';
}
if (key.startswith("n"))
{
if (nonce.BDecode(buf))
return true;
llarp::LogWarn("failed to decode nonce in LIM");
return false;
}
if (key.startswith("p"))
{
return bencode_read_integer(buf, &session_period);
}
if (key.startswith("r"))
{
if (rc.BDecode(buf))
return true;
llarp::LogWarn("failed to decode RC in LIM");
llarp::DumpBuffer(*buf);
return false;
}
if (key.startswith("v"))
{
if (!bencode_read_integer(buf, &version))
return false;
if (version != llarp::constants::proto_version)
{
llarp::LogWarn(
"llarp protocol version mismatch ", version, " != ", llarp::constants::proto_version);
return false;
}
llarp::LogDebug("LIM version ", version);
return true;
}
if (key.startswith("z"))
{
return sig.BDecode(buf);
}
llarp::LogWarn("invalid LIM key: ", *key.cur);
return false;
}
std::string
LinkIntroMessage::bt_encode() const
{
oxenc::bt_dict_producer btdp;
try
{
btdp.append("a", "i");
btdp.append("n", nonce.ToView());
btdp.append("p", session_period);
{
auto subdict = btdp.append_list("r");
rc.bt_encode_subdict(subdict);
}
btdp.append("v", llarp::constants::proto_version);
btdp.append("z", sig.ToView());
}
catch (...)
{
log::critical(link_cat, "Error: LinkIntroMessage failed to bt encode contents!");
}
return std::move(btdp).str();
}
bool
LinkIntroMessage::handle_message(Router* /*router*/) const
{
if (!verify())
return false;
return true;
// return conn->GotLIM(this);
}
void
LinkIntroMessage::clear()
{
session_period = 0;
nonce.Zero();
rc.Clear();
sig.Zero();
version = 0;
}
bool
LinkIntroMessage::sign(std::function<bool(Signature&, const llarp_buffer_t&)> signer)
{
sig.Zero();
// need to keep this as a llarp_buffer_t for now, as all the crypto code expects
// byte_t types -- fix this later
std::array<byte_t, MAX_MSG_SIZE> tmp;
llarp_buffer_t buf(tmp);
auto bte = bt_encode();
buf.write(bte.begin(), bte.end());
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
return signer(sig, buf);
}
bool
LinkIntroMessage::verify() const
{
LinkIntroMessage copy;
copy = *this;
copy.sig.Zero();
// need to keep this as a llarp_buffer_t for now, as all the crypto code expects
// byte_t types -- fix this later
std::array<byte_t, MAX_MSG_SIZE> tmp;
llarp_buffer_t buf(tmp);
auto bte = copy.bt_encode();
buf.write(bte.begin(), bte.end());
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// outer signature
if (!CryptoManager::instance()->verify(
rc.pubkey, reinterpret_cast<uint8_t*>(bte.data()), bte.size(), sig))
{
log::error(link_cat, "Error: outer signature failed!");
return false;
}
// verify RC
if (!rc.Verify(llarp::time_now_ms()))
{
log::error(link_cat, "Error: invalid RC in link intro!");
return false;
}
return true;
}
} // namespace llarp

@ -2,11 +2,11 @@
#include <llarp/crypto/encrypted.hpp>
#include <llarp/crypto/types.hpp>
#include "link_message.hpp"
#include <llarp/path/path_types.hpp>
#include <vector>
#include "link_message.hpp"
namespace llarp
{
/*

@ -2,15 +2,11 @@
#include <arpa/inet.h>
#endif
#include "exit_info.hpp"
#include "net.hpp"
#include <llarp/util/bencode.h>
#include <llarp/util/bits.hpp>
#include <llarp/util/mem.h>
#include <list>
#include <cstring>
#include "exit_info.hpp"
namespace llarp
{
bool

@ -1,11 +1,11 @@
#pragma once
#include <llarp/crypto/types.hpp>
#include "ip_address.hpp"
#include <llarp/util/bencode.hpp>
#include <iosfwd>
#include "ip_address.hpp"
/**
* exit_info.h
*

@ -1,9 +1,10 @@
#pragma once
#include <llarp/util/formattable.hpp>
#include <optional>
#include <string>
#include <vector>
#include <llarp/util/formattable.hpp>
#include "ip_range.hpp"
namespace llarp::net

@ -1,5 +1,7 @@
#pragma once
#include "net_int.hpp"
#include <cstdint>
namespace llarp::net

@ -1,6 +1,5 @@
#include "ip_address.hpp"
#include "net.hpp"
#include "ip_range.hpp"
namespace llarp
{

@ -1,15 +1,13 @@
#pragma once
#include "sock_addr.hpp"
#include <llarp/util/formattable.hpp>
#include <optional>
#include <string_view>
#include <string>
#include "sock_addr.hpp"
#include "net_int.hpp"
#include <llarp/util/formattable.hpp>
namespace llarp
{
/// A struct that can represent either an IPv4 or IPv6 address. It is meant for representation

@ -1,17 +1,16 @@
#include "ip_packet.hpp"
#include "ip.hpp"
#include <llarp/constants/net.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/mem.hpp>
#include <llarp/util/str.hpp>
#include "ip.hpp"
#ifndef _WIN32
#include <netinet/in.h>
#endif
#include <oxenc/endian.h>
#include <algorithm>
#include <map>
namespace llarp::net
{

@ -2,13 +2,14 @@
#include <oxenc/endian.h>
#include <llarp/ev/ev.hpp>
#include "net.hpp"
#include <llarp/util/buffer.hpp>
#include <llarp/util/time.hpp>
#include <memory>
#include <llarp/service/protocol_type.hpp>
#include <memory>
#include <utility>
#include "net.hpp"
namespace llarp::net
{
struct ip_header_le

@ -1,19 +1,19 @@
#pragma once
#include "ip.hpp"
#include "net_bits.hpp"
#include <oxen/log/catlogger.hpp>
#include <llarp/util/bits.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/types.hpp>
#include <llarp/util/logging.hpp>
#include <oxenc/bt.h>
#include <list>
#include <optional>
#include <stdexcept>
#include <string>
#include "ip.hpp"
#include "net_bits.hpp"
namespace
{
static auto net_cat = llarp::log::Cat("lokinet.net");

@ -1,4 +1,6 @@
#pragma once
#include "ip.hpp"
#include "net_int.hpp"
namespace llarp

@ -14,6 +14,8 @@ if_nametoindex(const char* __ifname) __THROW;
#endif
#endif
#include <string>
namespace llarp::net
{
/// get the name of the loopback interface

@ -8,18 +8,17 @@
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif
#include "net.h"
#include <llarp/util/formattable.hpp>
#include <oxenc/variant.h>
#include <cstdlib> // for itoa
#include <iostream>
#include <vector>
#include <llarp/util/formattable.hpp>
#include <oxenc/variant.h>
#include "net.h"
#include "uint128.hpp"
namespace llarp

@ -1,14 +1,8 @@
#include "net.hpp"
#include "net_if.hpp"
#include <stdexcept>
#include <llarp/constants/platform.hpp>
#include <arpa/inet.h>
#include "ip.hpp"
#include "net.hpp"
#include "net_if.hpp"
#include "ip_range.hpp"
#include <llarp/util/logging.hpp>
#include <llarp/util/str.hpp>
#ifdef ANDROID
#include <llarp/android/ifaddrs.h>
@ -16,9 +10,7 @@
#include <ifaddrs.h>
#endif
#include <cstdio>
#include <list>
#include <type_traits>
namespace llarp::net
{

@ -1,14 +1,13 @@
#include "sock_addr.hpp"
#include <llarp/util/str.hpp>
#include <llarp/util/mem.hpp>
#include <stdexcept>
#include "ip_range.hpp"
#include "ip.hpp"
#include "net_bits.hpp"
#include "net.hpp"
#include <llarp/util/str.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/util/mem.hpp>
#include <charconv>
#include <stdexcept>
namespace llarp
{

@ -9,11 +9,12 @@
#include <wspiapi.h>
#endif
#include <oxenc/variant.h>
#include <llarp/util/formattable.hpp>
#include <string_view>
#include <string>
#include "net_int.hpp"
#include <oxenc/variant.h>
#include <llarp/util/formattable.hpp>
namespace llarp
{

@ -1,13 +1,12 @@
#pragma once
#include <oxenc/bt.h>
#include <set>
#include "ip_range.hpp"
#include "ip_packet.hpp"
#include "llarp/util/status.hpp"
#include <oxenc/bt.h>
#include <set>
namespace llarp::net
{
/// information about an IP protocol

@ -1,20 +1,14 @@
#include "nodedb.hpp"
#include <algorithm>
#include <unordered_map>
#include <utility>
#include "router_contact.hpp"
#include "crypto/crypto.hpp"
#include "crypto/types.hpp"
#include "util/buffer.hpp"
#include "util/fs.hpp"
#include "util/logging.hpp"
#include "util/time.hpp"
#include "util/mem.hpp"
#include "util/str.hpp"
#include "dht/kademlia.hpp"
#include <algorithm>
#include <unordered_map>
#include <utility>
static const char skiplist_subdirs[] = "0123456789abcdef";
static const std::string RC_FILE_EXT = ".signed";

@ -1,16 +1,6 @@
#pragma once
#include "router_contact.hpp"
#include "router_id.hpp"
#include "util/common.hpp"
#include "util/fs.hpp"
#include "dht/key.hpp"
#include "crypto/crypto.hpp"
#include "util/thread/threading.hpp"
#include "util/thread/annotations.hpp"
#include <llarp/router/router.hpp>
#include <set>
#include <optional>
#include <unordered_set>
@ -19,6 +9,15 @@
#include <atomic>
#include <algorithm>
#include "router_contact.hpp"
#include "router_id.hpp"
#include "util/common.hpp"
#include "util/fs.hpp"
#include "dht/key.hpp"
#include "crypto/crypto.hpp"
#include "util/thread/threading.hpp"
#include "util/thread/annotations.hpp"
namespace llarp
{
struct Router;

@ -6,7 +6,6 @@
#include <llarp/util/decaying_hashset.hpp>
#include <llarp/messages/relay.hpp>
#include <vector>
#include <memory>
struct llarp_buffer_t;

@ -1,20 +1,11 @@
#include "path.hpp"
#include "pathbuilder.hpp"
#include "transit_hop.hpp"
#include <llarp/link/link_manager.hpp>
#include <llarp/messages/dht.hpp>
#include <llarp/messages/exit.hpp>
#include <llarp/nodedb.hpp>
#include <llarp/profiling.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/buffer.hpp>
#include <oxenc/endian.h>
#include <deque>
#include <queue>
namespace llarp::path
{
Path::Path(

@ -1,9 +1,5 @@
#pragma once
#include "abstracthophandler.hpp"
#include "path_types.hpp"
#include "pathset.hpp"
#include <llarp/constants/path.hpp>
#include <llarp/crypto/encrypted_frame.hpp>
#include <llarp/crypto/types.hpp>
@ -14,7 +10,6 @@
#include <llarp/util/compare_ptr.hpp>
#include <llarp/util/thread/threading.hpp>
#include <llarp/util/time.hpp>
#include <algorithm>
#include <functional>
#include <list>
@ -23,6 +18,10 @@
#include <unordered_set>
#include <vector>
#include "abstracthophandler.hpp"
#include "path_types.hpp"
#include "pathset.hpp"
namespace llarp
{
struct Router;
@ -36,6 +35,7 @@ namespace llarp
using TransitHop_ptr = std::shared_ptr<TransitHop>;
struct Ptr_hash;
struct Endpoint_Hash;
struct endpoint_comparator;

@ -1,19 +1,18 @@
#pragma once
#include "abstracthophandler.hpp"
#include "path_types.hpp"
#include "pathset.hpp"
#include "transit_hop.hpp"
#include <llarp/crypto/encrypted_frame.hpp>
#include <llarp/net/ip_address.hpp>
#include <llarp/util/compare_ptr.hpp>
#include <llarp/util/decaying_hashset.hpp>
#include <llarp/util/types.hpp>
#include <memory>
#include <unordered_map>
#include "abstracthophandler.hpp"
#include "path_types.hpp"
#include "pathset.hpp"
#include "transit_hop.hpp"
namespace llarp
{
struct Router;

@ -1,6 +1,4 @@
#include "pathbuilder.hpp"
#include "path.hpp"
#include "path_context.hpp"
#include <llarp/crypto/crypto.hpp>
#include <llarp/link/link_manager.hpp>
@ -9,10 +7,10 @@
#include <llarp/profiling.hpp>
#include <llarp/router/router.hpp>
#include <llarp/router/rc_lookup_handler.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <functional>
#include "path.hpp"
#include "path_context.hpp"
namespace llarp
{

@ -1,10 +1,6 @@
#include "path.hpp"
#include "pathset.hpp"
#include <llarp/router/router.hpp>
#include <random>
namespace llarp::path
{
PathSet::PathSet(size_t num) : numDesiredPaths(num)

@ -1,6 +1,5 @@
#pragma once
#include "path_types.hpp"
#include <llarp/router_contact.hpp>
#include <llarp/service/protocol_type.hpp>
#include <llarp/router_id.hpp>
@ -8,13 +7,14 @@
#include <llarp/util/status.hpp>
#include <llarp/util/thread/threading.hpp>
#include <llarp/util/time.hpp>
#include <functional>
#include <list>
#include <map>
#include <tuple>
#include <unordered_set>
#include "path_types.hpp"
namespace std
{
template <>

@ -1,13 +1,7 @@
#include "path.hpp"
#include "path_context.hpp"
#include "transit_hop.hpp"
#include <llarp/exit/context.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/router/router.hpp>
#include <llarp/util/buffer.hpp>
#include <oxenc/endian.h>
#include "transit_hop.hpp"
namespace llarp::path
{
@ -29,6 +23,15 @@ namespace llarp::path
m_DownstreamWorkCounter = 0;
}
bool
TransitHop::send_path_control_message(
std::string,
std::string,
std::function<void(oxen::quic::message m)>)
{
return true;
}
bool
TransitHop::Expired(llarp_time_t now) const
{

@ -1,133 +0,0 @@
#pragma once
#include <sqlite_orm/sqlite_orm.h>
#include "types.hpp"
/// Contains some code to help deal with sqlite_orm in hopes of keeping other headers clean
namespace llarp
{
inline auto
initStorage(const std::string& file)
{
using namespace sqlite_orm;
return make_storage(
file,
make_table(
"peerstats",
make_column("routerId", &PeerStats::routerId, primary_key(), unique()),
make_column("numConnectionAttempts", &PeerStats::numConnectionAttempts),
make_column("numConnectionSuccesses", &PeerStats::numConnectionSuccesses),
make_column("numConnectionRejections", &PeerStats::numConnectionRejections),
make_column("numConnectionTimeouts", &PeerStats::numConnectionTimeouts),
make_column("numPathBuilds", &PeerStats::numPathBuilds),
make_column("numPacketsAttempted", &PeerStats::numPacketsAttempted),
make_column("numPacketsSent", &PeerStats::numPacketsSent),
make_column("numPacketsDropped", &PeerStats::numPacketsDropped),
make_column("numPacketsResent", &PeerStats::numPacketsResent),
make_column("numDistinctRCsReceived", &PeerStats::numDistinctRCsReceived),
make_column("numLateRCs", &PeerStats::numLateRCs),
make_column("peakBandwidthBytesPerSec", &PeerStats::peakBandwidthBytesPerSec),
make_column("longestRCReceiveInterval", &PeerStats::longestRCReceiveInterval),
make_column("leastRCRemainingLifetime", &PeerStats::leastRCRemainingLifetime)));
}
using PeerDbStorage = decltype(initStorage(""));
} // namespace llarp
/// "custom" types for sqlite_orm
/// reference: https://github.com/fnc12/sqlite_orm/blob/master/examples/enum_binding.cpp
namespace sqlite_orm
{
/// llarp_time_t serialization
template <>
struct type_printer<llarp_time_t> : public integer_printer
{};
template <>
struct statement_binder<llarp_time_t>
{
int
bind(sqlite3_stmt* stmt, int index, const llarp_time_t& value)
{
return statement_binder<int64_t>().bind(stmt, index, value.count());
}
};
template <>
struct field_printer<llarp_time_t>
{
std::string
operator()(const llarp_time_t& value) const
{
return fmt::format("{}", value.count());
}
};
template <>
struct row_extractor<llarp_time_t>
{
llarp_time_t
extract(const char* row_value)
{
int64_t raw = static_cast<int64_t>(atoi(row_value));
return llarp_time_t(raw);
}
llarp_time_t
extract(sqlite3_stmt* stmt, int columnIndex)
{
auto str = sqlite3_column_text(stmt, columnIndex);
return this->extract((const char*)str);
}
};
/// RouterID serialization
template <>
struct type_printer<llarp::RouterID> : public text_printer
{};
template <>
struct statement_binder<llarp::RouterID>
{
int
bind(sqlite3_stmt* stmt, int index, const llarp::RouterID& value)
{
return statement_binder<std::string>().bind(stmt, index, value.ToString());
}
};
template <>
struct field_printer<llarp::RouterID>
{
std::string
operator()(const llarp::RouterID& value) const
{
return value.ToString();
}
};
template <>
struct row_extractor<llarp::RouterID>
{
llarp::RouterID
extract(const char* row_value)
{
llarp::RouterID id;
if (not id.FromString(row_value))
throw std::runtime_error("Invalid RouterID in sqlite3 database");
return id;
}
llarp::RouterID
extract(sqlite3_stmt* stmt, int columnIndex)
{
auto str = sqlite3_column_text(stmt, columnIndex);
return this->extract((const char*)str);
}
};
} // namespace sqlite_orm

@ -1,380 +0,0 @@
#include "peer_db.hpp"
#include <llarp/util/logging.hpp>
#include <llarp/util/status.hpp>
#include <llarp/util/str.hpp>
namespace llarp
{
#ifdef LOKINET_PEERSTATS_BACKEND
PeerDb::PeerDb()
{
m_lastFlush.store({});
}
void
PeerDb::loadDatabase(std::optional<fs::path> file)
{
std::lock_guard guard(m_statsLock);
if (m_storage)
throw std::runtime_error("Reloading database not supported"); // TODO
m_peerStats.clear();
// sqlite_orm treats empty-string as an indicator to load a memory-backed database, which we'll
// use if file is an empty-optional
std::string fileString;
if (file.has_value())
{
fileString = file->string();
LogInfo("Loading PeerDb from file ", fileString);
}
else
{
LogInfo("Loading memory-backed PeerDb");
}
m_storage = std::make_unique<PeerDbStorage>(initStorage(fileString));
m_storage->sync_schema(true); // true for "preserve" as in "don't nuke" (how cute!)
auto allStats = m_storage->get_all<PeerStats>();
LogInfo("Loading ", allStats.size(), " PeerStats from table peerstats...");
for (PeerStats& stats : allStats)
{
// we cleared m_peerStats, and the database should enforce that routerId is unique...
assert(m_peerStats.find(stats.routerId) == m_peerStats.end());
stats.stale = false;
m_peerStats[stats.routerId] = stats;
}
}
void
PeerDb::flushDatabase()
{
LogDebug("flushing PeerDb...");
auto start = time_now_ms();
if (not shouldFlush(start))
{
LogWarn("Call to flushDatabase() while already in progress, ignoring");
return;
}
if (not m_storage)
throw std::runtime_error("Cannot flush database before it has been loaded");
std::vector<PeerStats> staleStats;
{
std::lock_guard guard(m_statsLock);
// copy all stale entries
for (auto& entry : m_peerStats)
{
if (entry.second.stale)
{
staleStats.push_back(entry.second);
entry.second.stale = false;
}
}
}
LogDebug("Updating ", staleStats.size(), " stats");
{
auto guard = m_storage->transaction_guard();
for (const auto& stats : staleStats)
{
m_storage->replace(stats);
}
guard.commit();
}
auto end = time_now_ms();
auto elapsed = end - start;
LogDebug("PeerDb flush took about ", elapsed, " seconds");
m_lastFlush.store(end);
}
void
PeerDb::accumulatePeerStats(const RouterID& routerId, const PeerStats& delta)
{
if (routerId != delta.routerId)
throw std::invalid_argument{
fmt::format("routerId {} doesn't match {}", routerId, delta.routerId)};
std::lock_guard guard(m_statsLock);
auto itr = m_peerStats.find(routerId);
if (itr == m_peerStats.end())
itr = m_peerStats.insert({routerId, delta}).first;
else
itr->second += delta;
itr->second.stale = true;
}
void
PeerDb::modifyPeerStats(const RouterID& routerId, std::function<void(PeerStats&)> callback)
{
std::lock_guard guard(m_statsLock);
PeerStats& stats = m_peerStats[routerId];
stats.routerId = routerId;
stats.stale = true;
callback(stats);
}
std::optional<PeerStats>
PeerDb::getCurrentPeerStats(const RouterID& routerId) const
{
std::lock_guard guard(m_statsLock);
auto itr = m_peerStats.find(routerId);
if (itr == m_peerStats.end())
return std::nullopt;
else
return itr->second;
}
std::vector<PeerStats>
PeerDb::listAllPeerStats() const
{
std::lock_guard guard(m_statsLock);
std::vector<PeerStats> statsList;
statsList.reserve(m_peerStats.size());
for (const auto& [routerId, stats] : m_peerStats)
{
statsList.push_back(stats);
}
return statsList;
}
std::vector<PeerStats>
PeerDb::listPeerStats(const std::vector<RouterID>& ids) const
{
std::lock_guard guard(m_statsLock);
std::vector<PeerStats> statsList;
statsList.reserve(ids.size());
for (const auto& id : ids)
{
const auto itr = m_peerStats.find(id);
if (itr != m_peerStats.end())
statsList.push_back(itr->second);
}
return statsList;
}
/// Assume we receive an RC at some point `R` in time which was signed at some point `S` in time
/// and expires at some point `E` in time, as depicted below:
///
/// +-----------------------------+
/// | signed rc | <- useful lifetime of RC
/// +-----------------------------+
/// ^ [ . . . . . . . . ] <----------- window in which we receive this RC gossiped to us
/// | ^ ^
/// | | |
/// S R E
///
/// One useful metric from this is the difference between (E - R), the useful contact time of this
/// RC. As we track this metric over time, the high and low watermarks serve to tell us how
/// quickly we receive signed RCs from a given router and how close to expiration they are when
/// we receive them. The latter is particularly useful, and should always be a positive number for
/// a healthy router. A negative number indicates that we are receiving an expired RC.
///
/// TODO: we actually discard expired RCs, so we currently would not detect a negative value for
/// (E - R)
///
/// Another related metric is the distance between a newly received RC and the previous RC's
/// expiration, which represents how close we came to having no useful RC to work with. This
/// should be a high (positive) number for a healthy router, and if negative indicates that we
/// had no way to contact this router for a period of time.
///
/// E1 E2 E3
/// | | |
/// v | |
/// +-----------------------------+ | |
/// | signed rc 1 | | |
/// +-----------------------------+ | |
/// [ . . . . . ] v |
/// ^ +-----------------------------+ |
/// | | signed rc 2 | |
/// | +-----------------------------+ |
/// | [ . . . . . . . . . . ] v
/// | ^ +-----------------------------+
/// | | | signed rc 3 |
/// | | +-----------------------------+
/// | | [ . . ]
/// | | ^
/// | | |
/// R1 R2 R3
///
/// Example: the delta between (E1 - R2) is healthy, but the delta between (E2 - R3) is indicates
/// that we had a brief period of time where we had no valid (non-expired) RC for this router
/// (because it is negative).
void
PeerDb::handleGossipedRC(const RouterContact& rc, llarp_time_t now)
{
std::lock_guard guard(m_statsLock);
RouterID id(rc.pubkey);
auto& stats = m_peerStats[id];
stats.routerId = id;
const bool isNewRC = (stats.lastRCUpdated < rc.last_updated);
if (isNewRC)
{
stats.numDistinctRCsReceived++;
if (stats.numDistinctRCsReceived > 1)
{
auto prevRCExpiration = (stats.lastRCUpdated + RouterContact::Lifetime);
// we track max expiry as the delta between (last expiration time - time received),
// and this value will be negative for an unhealthy router
// TODO: handle case where new RC is also expired? just ignore?
auto expiry = prevRCExpiration - now;
if (stats.numDistinctRCsReceived == 2)
stats.leastRCRemainingLifetime = expiry;
else
stats.leastRCRemainingLifetime = std::min(stats.leastRCRemainingLifetime, expiry);
}
stats.lastRCUpdated = rc.last_updated;
stats.stale = true;
}
}
void
PeerDb::configure(const RouterConfig& routerConfig)
{
fs::path dbPath = routerConfig.m_dataDir / "peerstats.sqlite";
loadDatabase(dbPath);
}
bool
PeerDb::shouldFlush(llarp_time_t now)
{
constexpr llarp_time_t TargetFlushInterval = 30s;
return (now - m_lastFlush.load() >= TargetFlushInterval);
}
util::StatusObject
PeerDb::ExtractStatus() const
{
std::lock_guard guard(m_statsLock);
bool loaded = (m_storage.get() != nullptr);
util::StatusObject dbFile = nullptr;
if (loaded)
dbFile = m_storage->filename();
std::vector<util::StatusObject> statsObjs;
statsObjs.reserve(m_peerStats.size());
for (const auto& pair : m_peerStats)
{
statsObjs.push_back(pair.second.toJson());
}
util::StatusObject obj{
{"dbLoaded", loaded},
{"dbFile", dbFile},
{"lastFlushMs", m_lastFlush.load().count()},
{"stats", statsObjs},
};
return obj;
}
#else // !LOKINET_PEERSTATS
// Empty stubs
PeerDb::PeerDb()
{
throw std::logic_error{"Peer stats backend not enabled!"};
}
void
PeerDb::loadDatabase(std::optional<fs::path>)
{}
void
PeerDb::flushDatabase()
{}
void
PeerDb::accumulatePeerStats(const RouterID&, const PeerStats&)
{}
void
PeerDb::modifyPeerStats(const RouterID&, std::function<void(PeerStats&)>)
{}
std::optional<PeerStats>
PeerDb::getCurrentPeerStats(const RouterID&) const
{
return std::nullopt;
}
std::vector<PeerStats>
PeerDb::listAllPeerStats() const
{
return {};
}
std::vector<PeerStats>
PeerDb::listPeerStats(const std::vector<RouterID>&) const
{
return {};
}
void
PeerDb::handleGossipedRC(const RouterContact&, llarp_time_t)
{}
void
PeerDb::configure(const RouterConfig&)
{}
bool
PeerDb::shouldFlush(llarp_time_t)
{
return false;
}
util::StatusObject
PeerDb::ExtractStatus() const
{
return {};
}
#endif
}; // namespace llarp
/*
- How does a SN/quorum of SN determine if an operator is acting in good faith on the network
- w/o the other operator knowing
- Observing and gathering data in a meaningful way
- What type of stats could you even collect off lokinet?
- Collecting network-wide data can't be automatically actioned unless the SN is collecting
- Redundancy model
- Don't rely on an individual, but a collection of them
*/

@ -1,141 +0,0 @@
#pragma once
#include <filesystem>
#include <functional>
#include <unordered_map>
#include <llarp/util/fs.hpp>
#include <llarp/config/config.hpp>
#include <llarp/router_id.hpp>
#include <llarp/util/time.hpp>
#include <llarp/util/status.hpp>
#include "types.hpp"
#ifdef LOKINET_PEERSTATS_BACKEND
#include "orm.hpp"
#endif
namespace llarp
{
/// Maintains a database of stats collected about the connections with our Service Node peers.
/// This uses a sqlite3 database behind the scenes as persistance, but this database is
/// periodically flushed to, meaning that it will become stale as PeerDb accumulates stats without
/// a flush.
struct PeerDb
{
/// Constructor
PeerDb();
/// Loads the database from disk using the provided filepath. If the file is equal to
/// `std::nullopt`, the database will be loaded into memory (useful for testing).
///
/// This must be called prior to calling flushDatabase(), and will truncate any existing data.
///
/// This is a blocking call, both in the sense that it blocks on disk/database I/O and that it
/// will sit on a mutex while the database is loaded.
///
/// @param file is an optional file which doesn't have to exist but must be writable, if a value
/// is provided. If no value is provided, the database will be memory-backed.
/// @throws if sqlite_orm/sqlite3 is unable to open or create a database at the given file
void
loadDatabase(std::optional<fs::path> file);
/// Flushes the database. Must be called after loadDatabase(). This call will block during I/O
/// and should be called in an appropriate threading context. However, it will make a temporary
/// copy of the peer stats so as to avoid sitting on a mutex lock during disk I/O.
///
/// @throws if the database could not be written to (esp. if loadDatabase() has not been called)
void
flushDatabase();
/// Add the given stats to the cummulative stats for the given peer. For cummulative stats, the
/// stats are added together; for watermark stats, the max is kept.
///
/// This is intended to be used in the following pattern:
///
/// 1) Initialize an empty PeerStats
/// 2) Collect relevant stats
/// 3) Call accumulatePeerStats() with the stats
/// 4) Reset the stats to 0
/// 5) <Repeat 2-4 periodically>
///
/// @param routerId is the id of the router whose stats should be modified.
/// @param delta is the stats to add to the existing stats
void
accumulatePeerStats(const RouterID& routerId, const PeerStats& delta);
/// Allows write-access to the stats for a given peer while appropriate mutex lock is held. This
/// is an alternative means of incrementing peer stats that is suitable for one-off
/// modifications.
///
/// Note that this holds m_statsLock during the callback invocation, so the callback should
/// return as quickly as possible.
///
/// @param routerId is the id of the router whose stats should be modified.
/// @param callback is a function which will be called immediately with mutex held
void
modifyPeerStats(const RouterID& routerId, std::function<void(PeerStats&)> callback);
/// Provides a snapshot of the most recent PeerStats we have for the given peer. If we don't
/// have any stats for the peer, std::nullopt
///
/// @param routerId is the RouterID of the requested peer
/// @return a copy of the most recent peer stats or an empty one if no such peer is known
std::optional<PeerStats>
getCurrentPeerStats(const RouterID& routerId) const;
/// Lists all peer stats. This essentially dumps the database into a list of PeerStats objects.
///
/// Note that this avoids disk I/O by copying from our cached map of peers.
///
/// @return a list of all PeerStats we have maintained
std::vector<PeerStats>
listAllPeerStats() const;
/// Lists specific peer stats.
///
/// @param peers is list of RouterIDs which are desired
/// @return a list of the requested peers. Peers not found will be omitted.
std::vector<PeerStats>
listPeerStats(const std::vector<RouterID>& ids) const;
/// Handles a new gossiped RC, updating stats as needed. The database tracks the last
/// advertised update time, so it knows whether this is a new RC or not.
///
/// The given RC is assumed to be valid.
///
/// @param rc is the RouterContact to handle
/// @param now is an optional time representing the current time
void
handleGossipedRC(const RouterContact& rc, llarp_time_t now = time_now_ms());
/// Configures the PeerDb based on RouterConfig
///
/// @param routerConfig
void
configure(const RouterConfig& routerConfig);
/// Returns whether or not we should flush, as determined by the last time we flushed and the
/// configured flush interval.
///
/// @param now is the current[-ish] time
bool
shouldFlush(llarp_time_t now);
/// Get JSON status for API
///
/// @return JSON object representing our current status
util::StatusObject
ExtractStatus() const;
#ifdef LOKINET_PEERSTATS_BACKEND
private:
std::unordered_map<RouterID, PeerStats> m_peerStats;
mutable std::mutex m_statsLock;
std::unique_ptr<PeerDbStorage> m_storage;
std::atomic<llarp_time_t> m_lastFlush;
#endif
};
} // namespace llarp

@ -1,146 +0,0 @@
#include "types.hpp"
#include <llarp/util/str.hpp>
#include <oxenc/bt_serialize.h>
#include <stdexcept>
namespace llarp
{
constexpr auto RouterIdKey = "routerId";
constexpr auto NumConnectionAttemptsKey = "numConnectionAttempts";
constexpr auto NumConnectionSuccessesKey = "numConnectionSuccesses";
constexpr auto NumConnectionRejectionsKey = "numConnectionRejections";
constexpr auto NumConnectionTimeoutsKey = "numConnectionTimeouts";
constexpr auto NumPathBuildsKey = "numPathBuilds";
constexpr auto NumPacketsAttemptedKey = "numPacketsAttempted";
constexpr auto NumPacketsSentKey = "numPacketsSent";
constexpr auto NumPacketsDroppedKey = "numPacketsDropped";
constexpr auto NumPacketsResentKey = "numPacketsResent";
constexpr auto NumDistinctRCsReceivedKey = "numDistinctRCsReceived";
constexpr auto NumLateRCsKey = "numLateRCs";
constexpr auto PeakBandwidthBytesPerSecKey = "peakBandwidthBytesPerSec";
constexpr auto LongestRCReceiveIntervalKey = "longestRCReceiveInterval";
constexpr auto LeastRCRemainingLifetimeKey = "leastRCRemainingLifetime";
constexpr auto LastRCUpdatedKey = "lastRCUpdated";
PeerStats::PeerStats() = default;
PeerStats::PeerStats(const RouterID& routerId_) : routerId(routerId_)
{}
PeerStats&
PeerStats::operator+=(const PeerStats& other)
{
numConnectionAttempts += other.numConnectionAttempts;
numConnectionSuccesses += other.numConnectionSuccesses;
numConnectionRejections += other.numConnectionRejections;
numConnectionTimeouts += other.numConnectionTimeouts;
numPathBuilds += other.numPathBuilds;
numPacketsAttempted += other.numPacketsAttempted;
numPacketsSent += other.numPacketsSent;
numPacketsDropped += other.numPacketsDropped;
numPacketsResent += other.numPacketsResent;
numDistinctRCsReceived += other.numDistinctRCsReceived;
numLateRCs += other.numLateRCs;
peakBandwidthBytesPerSec = std::max(peakBandwidthBytesPerSec, other.peakBandwidthBytesPerSec);
longestRCReceiveInterval = std::max(longestRCReceiveInterval, other.longestRCReceiveInterval);
leastRCRemainingLifetime = std::max(leastRCRemainingLifetime, other.leastRCRemainingLifetime);
lastRCUpdated = std::max(lastRCUpdated, other.lastRCUpdated);
return *this;
}
bool
PeerStats::operator==(const PeerStats& other) const
{
return routerId == other.routerId and numConnectionAttempts == other.numConnectionAttempts
and numConnectionSuccesses == other.numConnectionSuccesses
and numConnectionRejections == other.numConnectionRejections
and numConnectionTimeouts == other.numConnectionTimeouts
and numPathBuilds == other.numPathBuilds
and numPacketsAttempted == other.numPacketsAttempted
and numPacketsSent == other.numPacketsSent and numPacketsDropped == other.numPacketsDropped
and numPacketsResent == other.numPacketsResent
and numDistinctRCsReceived == other.numDistinctRCsReceived
and numLateRCs == other.numLateRCs
and peakBandwidthBytesPerSec == other.peakBandwidthBytesPerSec
and longestRCReceiveInterval == other.longestRCReceiveInterval
and leastRCRemainingLifetime == other.leastRCRemainingLifetime
and lastRCUpdated == other.lastRCUpdated;
}
util::StatusObject
PeerStats::toJson() const
{
return {
{RouterIdKey, routerId.ToString()},
{NumConnectionAttemptsKey, numConnectionAttempts},
{NumConnectionSuccessesKey, numConnectionSuccesses},
{NumConnectionRejectionsKey, numConnectionRejections},
{NumConnectionTimeoutsKey, numConnectionTimeouts},
{NumPathBuildsKey, numPathBuilds},
{NumPacketsAttemptedKey, numPacketsAttempted},
{NumPacketsSentKey, numPacketsSent},
{NumPacketsDroppedKey, numPacketsDropped},
{NumPacketsResentKey, numPacketsResent},
{NumDistinctRCsReceivedKey, numDistinctRCsReceived},
{NumLateRCsKey, numLateRCs},
{PeakBandwidthBytesPerSecKey, peakBandwidthBytesPerSec},
{LongestRCReceiveIntervalKey, longestRCReceiveInterval.count()},
{LeastRCRemainingLifetimeKey, leastRCRemainingLifetime.count()},
{LastRCUpdatedKey, lastRCUpdated.count()},
};
}
void
PeerStats::BEncode(llarp_buffer_t* buf) const
{
if (not buf)
throw std::runtime_error("PeerStats: Can't use null buf");
const oxenc::bt_dict data = {
{NumConnectionAttemptsKey, numConnectionAttempts},
{NumConnectionSuccessesKey, numConnectionSuccesses},
{NumConnectionRejectionsKey, numConnectionRejections},
{NumConnectionTimeoutsKey, numConnectionTimeouts},
{NumPathBuildsKey, numPathBuilds},
{NumPacketsAttemptedKey, numPacketsAttempted},
{NumPacketsSentKey, numPacketsSent},
{NumPacketsDroppedKey, numPacketsDropped},
{NumPacketsResentKey, numPacketsResent},
{NumDistinctRCsReceivedKey, numDistinctRCsReceived},
{NumLateRCsKey, numLateRCs},
{PeakBandwidthBytesPerSecKey, (uint64_t)peakBandwidthBytesPerSec},
{LongestRCReceiveIntervalKey, longestRCReceiveInterval.count()},
{LeastRCRemainingLifetimeKey, leastRCRemainingLifetime.count()},
{LastRCUpdatedKey, lastRCUpdated.count()},
};
const auto serialized = oxenc::bt_serialize(data);
if (not buf->write(serialized.begin(), serialized.end()))
throw std::runtime_error("PeerStats: buffer too small");
}
void
PeerStats::BEncodeList(const std::vector<PeerStats>& statsList, llarp_buffer_t* buf)
{
if (not buf)
throw std::runtime_error("PeerStats: Can't use null buf");
if (not bencode_start_list(buf))
throw std::runtime_error("PeerStats: Could not create bencode dict");
for (const auto& stats : statsList)
{
stats.BEncode(buf);
}
if (not bencode_end(buf))
throw std::runtime_error("PeerStats: Could not end bencode dict");
}
}; // namespace llarp

@ -1,59 +0,0 @@
#pragma once
#include <chrono>
#include <unordered_map>
#include <llarp/router_id.hpp>
#include <llarp/util/status.hpp>
#include <llarp/util/time.hpp>
/// Types stored in our peerstats database are declared here
namespace llarp
{
// Struct containing stats we know about a peer
struct PeerStats
{
RouterID routerId;
int32_t numConnectionAttempts = 0;
int32_t numConnectionSuccesses = 0;
int32_t numConnectionRejections = 0;
int32_t numConnectionTimeouts = 0;
int32_t numPathBuilds = 0;
int64_t numPacketsAttempted = 0;
int64_t numPacketsSent = 0;
int64_t numPacketsDropped = 0;
int64_t numPacketsResent = 0;
int32_t numDistinctRCsReceived = 0;
int32_t numLateRCs = 0;
double peakBandwidthBytesPerSec = 0;
llarp_time_t longestRCReceiveInterval = 0ms;
llarp_time_t leastRCRemainingLifetime = 0ms;
llarp_time_t lastRCUpdated = 0ms;
// not serialized
bool stale = true;
PeerStats();
PeerStats(const RouterID& routerId);
PeerStats&
operator+=(const PeerStats& other);
bool
operator==(const PeerStats& other) const;
util::StatusObject
toJson() const;
void
BEncode(llarp_buffer_t* buf) const;
static void
BEncodeList(const std::vector<PeerStats>& statsList, llarp_buffer_t* buf);
};
} // namespace llarp

@ -1,10 +1,9 @@
#include "pow.hpp"
#include "crypto/crypto.hpp"
#include "util/buffer.hpp"
#include <cmath>
#include "crypto/crypto.hpp"
namespace llarp
{
PoW::~PoW() = default;

@ -1,9 +1,9 @@
#include "profiling.hpp"
#include <oxenc/bt_producer.h>
#include <oxenc/bt_serialize.h>
#include "util/file.hpp"
#include "util/logging.hpp"
using oxenc::bt_dict_consumer;
using oxenc::bt_dict_producer;

@ -1,12 +1,12 @@
#pragma once
#include <map>
#include "path/path.hpp"
#include "router_id.hpp"
#include "util/bencode.hpp"
#include "util/thread/threading.hpp"
#include "util/thread/annotations.hpp"
#include <map>
namespace oxenc
{

@ -1,389 +0,0 @@
#include <llarp/messages/link_message.hpp>
#include "router.hpp"
#include <llarp/constants/link_layer.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <llarp/util/status.hpp>
#include <algorithm>
#include <cstdlib>
namespace llarp
{
const PathID_t OutboundMessageHandler::zeroID;
using namespace std::chrono_literals;
OutboundMessageHandler::OutboundMessageHandler(size_t maxQueueSize)
: outboundQueue(maxQueueSize), recentlyRemovedPaths(5s), removedSomePaths(false)
{}
bool
OutboundMessageHandler::QueueMessage(
const RouterID& remote, const AbstractLinkMessage& msg, SendStatusHandler callback)
{
// if the destination is invalid, callback with failure and return
if (not _router->link_manager().have_client_connection_to(remote)
and not _router->rc_lookup_handler().is_session_allowed(remote))
{
DoCallback(callback, SendStatus::InvalidRouter);
return true;
}
MessageQueueEntry ent;
ent.router = remote;
ent.inform = std::move(callback);
ent.pathid = msg.pathid;
ent.priority = msg.priority();
std::string _buf;
_buf.reserve(MAX_LINK_MSG_SIZE);
if (!EncodeBuffer(msg, _buf))
return false;
ent.message.resize(_buf.size());
std::copy_n(_buf.data(), _buf.size(), ent.message.data());
// if we have a session to the destination, queue the message and return
if (_router->link_manager().have_connection_to(remote))
{
QueueOutboundMessage(std::move(ent));
return true;
}
// if we don't have a session to the destination, queue the message onto
// a special pending session queue for that destination, and then create
// that pending session if there is not already a session establish attempt
// in progress.
bool shouldCreateSession = false;
{
util::Lock l{_mutex};
// create queue for <remote> if it doesn't exist, and get iterator
auto [queue_itr, is_new] = pendingSessionMessageQueues.emplace(remote, MessageQueue());
queue_itr->second.push(std::move(ent));
shouldCreateSession = is_new;
}
if (shouldCreateSession)
{
QueueSessionCreation(remote);
}
return true;
}
void
OutboundMessageHandler::Pump()
{
m_Killer.TryAccess([this]() {
recentlyRemovedPaths.Decay();
ProcessOutboundQueue();
// TODO: this probably shouldn't be pumping, as it defeats the purpose
// of having a limit on sends per tick, but chaning it is potentially bad
// and requires testing so it should be changed later.
if (/*bool more = */ SendRoundRobin())
_router->TriggerPump();
});
}
void
OutboundMessageHandler::RemovePath(const PathID_t& pathid)
{
m_Killer.TryAccess([this, pathid]() {
/* add the path id to a list of recently removed paths to act as a filter
* for messages that are queued but haven't been sorted into path queues yet.
*
* otherwise these messages would re-create the path queue we just removed, and
* those path queues would be leaked / never removed.
*/
recentlyRemovedPaths.Insert(pathid);
auto itr = outboundMessageQueues.find(pathid);
if (itr != outboundMessageQueues.end())
{
outboundMessageQueues.erase(itr);
}
removedSomePaths = true;
});
}
util::StatusObject
OutboundMessageHandler::ExtractStatus() const
{
util::StatusObject status{
"queueStats",
{{"queued", m_queueStats.queued},
{"dropped", m_queueStats.dropped},
{"sent", m_queueStats.sent},
{"queueWatermark", m_queueStats.queueWatermark},
{"perTickMax", m_queueStats.perTickMax},
{"numTicks", m_queueStats.numTicks}}};
return status;
}
void
OutboundMessageHandler::Init(Router* router)
{
_router = router;
outboundMessageQueues.emplace(zeroID, MessageQueue());
}
static inline SendStatus
ToSendStatus(const SessionResult result)
{
switch (result)
{
case SessionResult::Establish:
return SendStatus::Success;
case SessionResult::Timeout:
case SessionResult::EstablishFail:
return SendStatus::Timeout;
case SessionResult::RouterNotFound:
return SendStatus::RouterNotFound;
case SessionResult::InvalidRouter:
return SendStatus::InvalidRouter;
case SessionResult::NoLink:
return SendStatus::NoLink;
}
throw std::invalid_argument{
fmt::format("SessionResult {} has no corresponding SendStatus when transforming", result)};
}
void
OutboundMessageHandler::OnSessionResult(const RouterID& router, const SessionResult result)
{
FinalizeSessionRequest(router, ToSendStatus(result));
}
void
OutboundMessageHandler::DoCallback(SendStatusHandler callback, SendStatus status)
{
if (callback)
_router->loop()->call([f = std::move(callback), status] { f(status); });
}
// TODO: still necessary/desired?
void
OutboundMessageHandler::QueueSessionCreation(const RouterID& remote)
{
_router->link_manager().Connect(remote);
}
/** Note: This is where AbstractLinkMessage::bt_encode() is called. Contextually, this is
different than how the other Abstract message types invoke ::bt_encode(), namely that
there is no bt_dict_producer already being appended to. As a result, this use case
likely requires a span backport and/or re-designed llarp_buffer. Until then, the
::bt_encode() override that returns an std::string upon destruction of its bt_dict_producer
will be used
*/
bool
OutboundMessageHandler::EncodeBuffer(const AbstractLinkMessage& msg, std::string& buf)
{
if (buf = msg.bt_encode(); not buf.empty())
return true;
log::error(link_cat, "Error: OutboundMessageHandler failed to encode outbound message!");
return false;
}
bool
OutboundMessageHandler::Send(const MessageQueueEntry& ent)
{
const llarp_buffer_t buf{ent.message};
m_queueStats.sent++;
SendStatusHandler callback = ent.inform;
return _router->link_manager().send_to(
ent.router,
buf,
[this, callback](AbstractLinkSession::DeliveryStatus status) {
if (status == AbstractLinkSession::DeliveryStatus::eDeliverySuccess)
DoCallback(callback, SendStatus::Success);
else
{
DoCallback(callback, SendStatus::Congestion);
}
},
ent.priority);
}
bool
OutboundMessageHandler::SendIfSession(const MessageQueueEntry& ent)
{
if (_router->link_manager().have_connection_to(ent.router))
{
return Send(ent);
}
return false;
}
bool
OutboundMessageHandler::QueueOutboundMessage(MessageQueueEntry entry)
{
// copy callback in case we need to call it, so we can std::move(entry)
auto callback = entry.inform;
if (outboundQueue.tryPushBack(std::move(entry)) != llarp::thread::QueueReturn::Success)
{
m_queueStats.dropped++;
DoCallback(callback, SendStatus::Congestion);
}
else
{
m_queueStats.queued++;
uint32_t queueSize = outboundQueue.size();
m_queueStats.queueWatermark = std::max(queueSize, m_queueStats.queueWatermark);
}
return true;
}
void
OutboundMessageHandler::ProcessOutboundQueue()
{
while (not outboundQueue.empty())
{
MessageQueueEntry entry = outboundQueue.popFront();
// messages may still be queued for processing when a pathid is removed,
// so check here if the pathid was recently removed.
if (recentlyRemovedPaths.Contains(entry.pathid))
{
continue;
}
auto [queue_itr, is_new] = outboundMessageQueues.emplace(entry.pathid, MessageQueue());
if (is_new && !entry.pathid.IsZero())
{
roundRobinOrder.push(entry.pathid);
}
MessageQueue& path_queue = queue_itr->second;
if (path_queue.size() < MAX_PATH_QUEUE_SIZE || entry.pathid.IsZero())
{
path_queue.push(std::move(entry));
}
else
{
DoCallback(entry.inform, SendStatus::Congestion);
m_queueStats.dropped++;
}
}
}
bool
OutboundMessageHandler::SendRoundRobin()
{
m_queueStats.numTicks++;
// send routing messages first priority
auto& routing_mq = outboundMessageQueues[zeroID];
while (not routing_mq.empty())
{
const MessageQueueEntry& entry = routing_mq.top();
Send(entry);
routing_mq.pop();
}
size_t num_queues = roundRobinOrder.size();
// if any paths have been removed since last tick, remove any stale
// entries from the round-robin ordering
if (removedSomePaths)
{
for (size_t i = 0; i < num_queues; i++)
{
PathID_t pathid = std::move(roundRobinOrder.front());
roundRobinOrder.pop();
if (outboundMessageQueues.find(pathid) != outboundMessageQueues.end())
{
roundRobinOrder.push(std::move(pathid));
}
}
}
removedSomePaths = false;
num_queues = roundRobinOrder.size();
if (num_queues == 0)
{
return false;
}
// send messages for each pathid in roundRobinOrder, stopping when
// either every path's queue is empty or a set maximum amount of
// messages have been sent.
size_t consecutive_empty = 0;
for (size_t sent_count = 0; sent_count < MAX_OUTBOUND_MESSAGES_PER_TICK;)
{
PathID_t pathid = std::move(roundRobinOrder.front());
roundRobinOrder.pop();
auto& message_queue = outboundMessageQueues[pathid];
if (message_queue.size() > 0)
{
const MessageQueueEntry& entry = message_queue.top();
Send(entry);
message_queue.pop();
consecutive_empty = 0;
consecutive_empty++;
}
else
{
consecutive_empty++;
}
roundRobinOrder.push(std::move(pathid));
// if num_queues empty queues in a row, all queues empty.
if (consecutive_empty == num_queues)
{
break;
}
}
m_queueStats.perTickMax = std::max((uint32_t)consecutive_empty, m_queueStats.perTickMax);
return consecutive_empty != num_queues;
}
void
OutboundMessageHandler::FinalizeSessionRequest(const RouterID& router, SendStatus status)
{
MessageQueue movedMessages;
{
util::Lock l(_mutex);
auto itr = pendingSessionMessageQueues.find(router);
if (itr == pendingSessionMessageQueues.end())
{
return;
}
movedMessages.swap(itr->second);
pendingSessionMessageQueues.erase(itr);
}
while (!movedMessages.empty())
{
const MessageQueueEntry& entry = movedMessages.top();
if (status == SendStatus::Success)
{
Send(entry);
}
else
{
DoCallback(entry.inform, status);
}
movedMessages.pop();
}
}
} // namespace llarp

@ -1,319 +0,0 @@
#include "outbound_session_maker.hpp"
#include "router.hpp"
#include <llarp/tooling/peer_stats_event.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/nodedb.hpp>
#include "rc_lookup_handler.hpp"
#include <llarp/link/link_manager.hpp>
#include <llarp/util/meta/memfn.hpp>
#include <llarp/util/thread/threading.hpp>
#include <llarp/util/status.hpp>
#include <llarp/crypto/crypto.hpp>
#include <utility>
#include <llarp/rpc/lokid_rpc_client.hpp>
namespace llarp
{
bool
OutboundSessionMaker::OnSessionEstablished(AbstractLinkSession* session)
{
// TODO: do we want to keep it
const RouterContact rc = session->GetRemoteRC();
const auto router = RouterID(session->GetPubKey());
const bool isOutbound = not session->IsInbound();
const std::string remoteType = rc.IsPublicRouter() ? "router" : "client";
LogInfo(
"session with ", remoteType, " [", router, "] ", isOutbound ? "established" : "received");
if (not _rcLookup->SessionIsAllowed(router))
{
FinalizeRequest(router, SessionResult::InvalidRouter);
return false;
}
if (isOutbound)
{
work([this, rc] { VerifyRC(rc); });
return true;
}
return _rcLookup->CheckRC(rc);
}
void
OutboundSessionMaker::OnConnectTimeout(AbstractLinkSession* session)
{
const auto router = RouterID(session->GetPubKey());
LogWarn("Session establish attempt to ", router, " timed out.", session->GetRemoteEndpoint());
FinalizeRequest(router, SessionResult::Timeout);
}
void
OutboundSessionMaker::CreateSessionTo(const RouterID& router, RouterCallback on_result)
{
{
util::Lock l(_mutex);
auto itr_pair = pendingCallbacks.emplace(router, CallbacksQueue{});
if (on_result)
itr_pair.first->second.push_back(on_result);
}
if (HavePendingSessionTo(router))
{
LogDebug("has pending session to", router);
return;
}
CreatePendingSession(router);
// short-circuit to success callback if we already have an outbound session
// to the remote
if (_linkManager->HasConnection(router))
{
FinalizeRequest(router, SessionResult::Establish);
return;
}
LogDebug("Creating session establish attempt to ", router, " .");
auto fn = util::memFn(&OutboundSessionMaker::OnRouterContactResult, this);
_rcLookup->GetRC(router, fn);
}
void
OutboundSessionMaker::CreateSessionTo(const RouterContact& rc, RouterCallback on_result)
{
const RouterID router{rc.pubkey};
{
util::Lock l(_mutex);
auto itr_pair = pendingCallbacks.emplace(router, CallbacksQueue{});
if (on_result)
itr_pair.first->second.push_back(on_result);
}
if (not HavePendingSessionTo(router))
{
LogDebug("Creating session establish attempt to ", router);
CreatePendingSession(router);
}
GotRouterContact(router, rc);
}
bool
OutboundSessionMaker::HavePendingSessionTo(const RouterID& router) const
{
util::Lock l(_mutex);
return pendingCallbacks.find(router) != pendingCallbacks.end();
}
void
OutboundSessionMaker::ConnectToRandomRouters(int numDesired)
{
int remainingDesired = numDesired;
std::set<RouterID> exclude;
do
{
auto filter = [exclude](const auto& rc) -> bool { return exclude.count(rc.pubkey) == 0; };
RouterContact other;
if (const auto maybe = _nodedb->GetRandom(filter))
{
other = *maybe;
}
else
break;
exclude.insert(other.pubkey);
if (not _rcLookup->SessionIsAllowed(other.pubkey))
{
continue;
}
if (not(_linkManager->HasSessionTo(other.pubkey) || HavePendingSessionTo(other.pubkey)))
{
CreateSessionTo(other, nullptr);
--remainingDesired;
}
} while (remainingDesired > 0);
LogDebug(
"connecting to ", numDesired - remainingDesired, " out of ", numDesired, " random routers");
}
// TODO: this
util::StatusObject
OutboundSessionMaker::ExtractStatus() const
{
util::StatusObject status{};
return status;
}
void
OutboundSessionMaker::Init(
Router* router,
LinkManager* linkManager,
RCLookupHandler* rcLookup,
Profiling* profiler,
EventLoop_ptr loop,
WorkerFunc_t dowork)
{
_router = router;
_linkManager = linkManager;
_rcLookup = rcLookup;
_loop = std::move(loop);
_nodedb = router->nodedb();
_profiler = profiler;
work = std::move(dowork);
}
void
OutboundSessionMaker::GotRouterContact(const RouterID& router, const RouterContact& rc)
{
if (not _rcLookup->CheckRC(rc))
{
FinalizeRequest(rc.pubkey, SessionResult::InvalidRouter);
return;
}
if (not ShouldConnectTo(router))
{
FinalizeRequest(router, SessionResult::NoLink);
return;
}
auto result = _linkManager->Connect(rc);
if (result)
FinalizeRequest(router, SessionResult::Establish);
else
FinalizeRequest(router, SessionResult::EstablishFail);
}
bool
OutboundSessionMaker::ShouldConnectTo(const RouterID& router) const
{
if (router == us or not _rcLookup->SessionIsAllowed(router))
return false;
if (_router->IsServiceNode())
return true;
size_t numPending = 0;
{
util::Lock lock(_mutex);
if (pendingCallbacks.find(router) == pendingCallbacks.end())
numPending += pendingCallbacks.size();
}
return _linkManager->get_num_connected() + numPending < maxConnectedRouters;
}
void
OutboundSessionMaker::InvalidRouter(const RouterID& router)
{
FinalizeRequest(router, SessionResult::InvalidRouter);
}
void
OutboundSessionMaker::RouterNotFound(const RouterID& router)
{
FinalizeRequest(router, SessionResult::RouterNotFound);
}
void
OutboundSessionMaker::OnRouterContactResult(
const RouterID& router, const RouterContact* const rc, const RCRequestResult result)
{
if (not HavePendingSessionTo(router))
{
LogError("no pending session to ", router);
return;
}
switch (result)
{
case RCRequestResult::Success:
if (rc)
{
GotRouterContact(router, *rc);
}
else
{
LogError("RCRequestResult::Success but null rc pointer given");
InvalidRouter(router);
}
break;
case RCRequestResult::InvalidRouter:
InvalidRouter(router);
break;
case RCRequestResult::RouterNotFound:
RouterNotFound(router);
break;
default:
RouterNotFound(router);
break;
}
}
void
OutboundSessionMaker::VerifyRC(const RouterContact rc)
{
if (not _rcLookup->CheckRC(rc))
{
FinalizeRequest(rc.pubkey, SessionResult::InvalidRouter);
return;
}
FinalizeRequest(rc.pubkey, SessionResult::Establish);
}
// TODO: rename this, if we even want to keep it
void
OutboundSessionMaker::CreatePendingSession(const RouterID& router)
{
auto peerDb = _router->peerDb();
if (peerDb)
{
peerDb->modifyPeerStats(router, [](PeerStats& stats) { stats.numConnectionAttempts++; });
}
_router->NotifyRouterEvent<tooling::ConnectionAttemptEvent>(_router->pubkey(), router);
}
void
OutboundSessionMaker::FinalizeRequest(const RouterID& router, const SessionResult type)
{
CallbacksQueue movedCallbacks;
{
util::Lock l(_mutex);
if (type == SessionResult::Establish)
{
_profiler->MarkConnectSuccess(router);
}
else
{
// TODO: add non timeout related fail case
_profiler->MarkConnectTimeout(router);
}
auto itr = pendingCallbacks.find(router);
if (itr != pendingCallbacks.end())
{
movedCallbacks.splice(movedCallbacks.begin(), itr->second);
pendingCallbacks.erase(itr);
}
}
for (const auto& callback : movedCallbacks)
{
_loop->call([callback, router, type] { return callback(router, type); });
}
}
} // namespace llarp

@ -1,8 +1,7 @@
#include "rc_gossiper.hpp"
#include <llarp/router_contact.hpp>
#include <llarp/util/time.hpp>
#include <llarp/constants/link_layer.hpp>
#include <llarp/link/link_manager.hpp>
namespace llarp
{

@ -1,19 +1,15 @@
#include <chrono>
#include "rc_lookup_handler.hpp"
#include <llarp/link/contacts.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/crypto/crypto.hpp>
#include <llarp/service/context.hpp>
#include <llarp/router_contact.hpp>
#include <llarp/util/types.hpp>
#include <llarp/util/thread/threading.hpp>
#include <llarp/nodedb.hpp>
#include "router.hpp"
#include <iterator>
#include <functional>
#include <random>
#include "rc_lookup_handler.hpp"
#include "router.hpp"
namespace llarp
{

@ -2,7 +2,6 @@
#include <llarp/router_id.hpp>
#include <llarp/util/thread/threading.hpp>
#include <chrono>
#include <unordered_map>
#include <set>

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

Loading…
Cancel
Save