Review commit

pull/2232/head
dr7ana 9 months ago
parent 66ec886480
commit c0b19de963

1
.gitignore vendored

@ -67,3 +67,4 @@ regdbhelper.dll
# xcode # xcode
xcuserdata/ 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.h>
#include "libntrup/ntru_api.h"
#ifdef __x86_64__ #ifdef __x86_64__
#include <cpuid.h> #include <cpuid.h>
#include <array> #include <array>

@ -1,13 +1,10 @@
#include <cpr/cpr.h> #include <cpr/cpr.h>
#include <llarp/constants/files.hpp> #include <llarp/constants/files.hpp>
#include <llarp/constants/version.hpp> #include <llarp/constants/version.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/util/fs.hpp> #include <llarp/util/fs.hpp>
#include <fstream>
#include <sstream>
#include <iostream> #include <iostream>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
@ -15,12 +12,6 @@
#include <openssl/x509.h> #include <openssl/x509.h>
#endif #endif
#include <sstream>
#ifndef _WIN32
#include <openssl/x509.h>
#endif
namespace namespace
{ {
int int

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

@ -3,8 +3,7 @@
#include <llarp.hpp> #include <llarp.hpp>
#include <llarp/util/lokinet_init.h> #include <llarp/util/lokinet_init.h>
#include <llarp/util/exceptions.hpp> #include <llarp/util/exceptions.hpp>
#include <llarp/util/fs.hpp> #include <bits/chrono.h>
#include <llarp/util/str.hpp>
#ifdef _WIN32 #ifdef _WIN32
#include <llarp/win32/service_manager.hpp> #include <llarp/win32/service_manager.hpp>
@ -13,16 +12,38 @@
#include <llarp/util/service_manager.hpp> #include <llarp/util/service_manager.hpp>
#endif #endif
#include <csignal> #include <CLI/CLI.hpp>
#include <csignal>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <thread> #include <thread>
#include <future> #include <future>
#include <cstdlib>
#include <CLI/App.hpp> #include <exception>
#include <CLI/Formatter.hpp> #include <filesystem>
#include <CLI/Config.hpp> #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 namespace
{ {
@ -350,8 +371,8 @@ namespace
int int
lokinet_main(int argc, char** argv) lokinet_main(int argc, char** argv)
{ {
if (auto result = Lokinet_INIT()) // if (auto result = Lokinet_INIT())
return result; // return result;
llarp::RuntimeOptions opts; llarp::RuntimeOptions opts;
opts.showBanner = false; opts.showBanner = false;

@ -7,38 +7,128 @@ add_library(lokinet-cryptography
crypto/types.cpp 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 STATIC
${CMAKE_CURRENT_BINARY_DIR}/constants/version.cpp ${CMAKE_CURRENT_BINARY_DIR}/constants/version.cpp
util/bencode.cpp util/bencode.cpp
util/buffer.cpp util/buffer.cpp
util/file.cpp util/file.cpp
util/json.cpp
util/logging/buffer.cpp
util/easter_eggs.cpp
util/mem.cpp util/mem.cpp
util/str.cpp util/str.cpp
util/thread/queue_manager.cpp
util/thread/threading.cpp util/thread/threading.cpp
util/time.cpp) util/time.cpp
util/logging/buffer.cpp
)
add_dependencies(lokinet-util genversion) add_dependencies(lokinet-utils genversion)
# lokinet-platform holds all platform specific code # Addressing and event loop files used by lokinet-core and other libraries
add_library(lokinet-platform # needed by rpc/ link/ service/ config/ path/ dht/
add_library(lokinet-time-place
STATIC 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/ev.cpp
ev/libuv.cpp ev/libuv.cpp
net/interface_info.cpp net/exit_info.cpp # only router_contact
net/ip.cpp net/ip.cpp
net/ip_address.cpp net/ip_address.cpp
net/ip_packet.cpp net/ip_packet.cpp
net/ip_range.cpp net/ip_range.cpp
net/net_int.cpp net/net_int.cpp
net/sock_addr.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/packet_router.cpp
vpn/egres_packet_router.cpp
vpn/platform.cpp vpn/platform.cpp
) )
@ -80,16 +170,21 @@ endif()
# parse modify and reconstitute dns wire proto, dns queries and RR # parse modify and reconstitute dns wire proto, dns queries and RR
# should have no concept of dns caching, this is left as an implementation # should have no concept of dns caching, this is left as an implementation
# detail of dns resolvers (LATER: make separate lib for dns resolvers) # detail of dns resolvers (LATER: make separate lib for dns resolvers)
add_library(lokinet-dns add_library(lokinet-dns-internal
STATIC STATIC
dns/message.cpp dns/name.cpp # srv_data, question, rr
dns/name.cpp
dns/platform.cpp dns/platform.cpp
dns/question.cpp dns/question.cpp # message
dns/rr.cpp dns/rr.cpp
dns/serialize.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 # platform specific bits and bobs for setting dns
add_library(lokinet-dns-platform INTERFACE) add_library(lokinet-dns-platform INTERFACE)
@ -102,15 +197,10 @@ endif()
# nodedb data published to the network and versions of it stored locally # nodedb data published to the network and versions of it stored locally
add_library(lokinet-nodedb add_library(lokinet-nodedb
STATIC STATIC
bootstrap.cpp bootstrap.cpp # config, router.hpp
net/exit_info.cpp
net/traffic_policy.cpp
nodedb.cpp nodedb.cpp
pow.cpp profiling.cpp # path, router, service::endpoint
profiling.cpp net/traffic_policy.cpp # config, intro_set
router_contact.cpp
router_id.cpp
router_version.cpp
) )
set(BOOTSTRAP_FALLBACKS) set(BOOTSTRAP_FALLBACKS)
@ -141,15 +231,8 @@ add_library(lokinet-config
config/key_manager.cpp config/key_manager.cpp
) )
# lokinet-consensus is for deriving and tracking network consensus state for both service nodes and clients # All path objects; link directly to lokinet-core
add_library(lokinet-consensus add_library(lokinet-path
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 STATIC
path/abstracthophandler.cpp path/abstracthophandler.cpp
path/path_context.cpp path/path_context.cpp
@ -160,262 +243,140 @@ add_library(lokinet-layer-onion
messages/relay.cpp messages/relay.cpp
) )
# lokinet-layer-link is for our layer 2 analog which splits up layer 2 frames into add_library(lokinet-amalgum INTERFACE)
# 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. # interface library for setting common includes, linkage and flags.
add_library(lokinet-base INTERFACE) add_library(lokinet-base INTERFACE)
target_include_directories(lokinet-base target_include_directories(lokinet-base
INTERFACE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include INTERFACE ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/include
) )
target_link_libraries(lokinet-base INTERFACE quic) target_link_libraries(lokinet-base INTERFACE quic)
if(WITH_PEERSTATS) # Link libraries to their internals
target_compile_definitions(lokinet-base INTERFACE -DLOKINET_PEERSTATS_BACKEND) target_link_libraries(lokinet-core-internal PUBLIC lokinet-utils lokinet-core-utils)
target_link_libraries(lokinet-base INTERFACE sqlite_orm) target_link_libraries(lokinet-core PRIVATE lokinet-core-internal)
endif() # target_link_libraries(lokinet-rpc PRIVATE lokinet-rpc-internal)
target_link_libraries(lokinet-wire PRIVATE lokinet-wire-internal)
# interface libraries for internal linkage # target_link_libraries(lokinet-time-place PRIVATE lokinet-time-place-internal)
add_library(lokinet-layers INTERFACE) target_link_libraries(lokinet-dns PRIVATE lokinet-dns-internal)
add_library(lokinet-amalgum INTERFACE) target_link_libraries(lokinet-utils PRIVATE lokinet-utils-internal)
# helper function to link a library to lokinet-base, enable lto, add to lokinet-amalgum and then link to other libs # Link lokinet-dns to alternate libraries
function(lokinet_link_lib libname) target_link_libraries(lokinet-dns PUBLIC lokinet-dns-platform)
# Absolutely fuck this line, it doesn't "create" the target, as the target already exists if (TARGET lokinet-dns-systemd)
# message(DEBUG "created target: ${libname}") target_link_libraries(lokinet-dns PUBLIC lokinet-dns-systemd)
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() endif()
lokinet_link_lib(lokinet-platform lokinet-util) # Link relevant to lokinet-base
target_link_libraries(lokinet-core PUBLIC lokinet-base)
lokinet_link_lib(lokinet-config target_link_libraries(lokinet-rpc PUBLIC lokinet-base)
lokinet-util 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-nodedb
lokinet-wire
lokinet-time-place
lokinet-dns lokinet-dns
lokinet-platform lokinet-platform
lokinet-utils
lokinet-cryptography
lokinet-path
) )
#or just do this??
lokinet_link_lib(lokinet-context # target_link_libraries(lokinet-amalgum INTERFACE lokinet-base)
lokinet-config target_link_libraries(lokinet-wire-internal PUBLIC lokinet-time-place)
lokinet-platform target_link_libraries(lokinet-dns-internal PUBLIC lokinet-utils lokinet-config)
lokinet-peerstats target_link_libraries(lokinet-dns PUBLIC lokinet-cryptography)
lokinet-layers target_link_libraries(lokinet-nodedb PUBLIC lokinet-cryptography)
lokinet-consensus target_link_libraries(lokinet-platform PUBLIC lokinet-cryptography)
lokinet-rpc 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-platform
lokinet-config
) )
lokinet_link_lib(lokinet-dns target_link_libraries(lokinet-cryptography
lokinet-platform PUBLIC
lokinet-dns-platform lokinet-libcrypt
lokinet-config lokinet-libntrup
) )
lokinet_link_lib(lokinet-nodedb target_link_libraries(lokinet-utils
lokinet-util PUBLIC
lokinet-platform lokinet-cryptography
) )
lokinet_link_lib(lokinet-util # cross linkage
target_link_libraries(lokinet-core
PUBLIC
lokinet-rpc
lokinet-wire
lokinet-nodedb lokinet-nodedb
lokinet-platform lokinet-config
) lokinet-cryptography
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 # 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-config PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq) target_link_libraries(lokinet-nodedb PUBLIC oxenmq::oxenmq uvw)
target_link_libraries(lokinet-dns PUBLIC libunbound) target_link_libraries(lokinet-path PUBLIC oxenmq::oxenmq)
target_link_libraries(lokinet-time-place PUBLIC uvw oxenc::oxenc)
target_link_libraries(lokinet-cryptography PUBLIC target_link_libraries(lokinet-platform PUBLIC oxenmq::oxenmq Threads::Threads base_libs uvw)
oxenc::oxenc target_link_libraries(lokinet-cryptography PUBLIC oxenc::oxenc sodium)
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)
target_link_libraries(lokinet-context PUBLIC
CLI11 # if(WITH_EMBEDDED_LOKINET)
oxenmq::oxenmq # include(GNUInstallDirs)
uvw # add_library(lokinet-shared SHARED lokinet_shared.cpp)
) # target_link_libraries(lokinet-shared PUBLIC lokinet-amalgum)
# if(WIN32)
target_link_libraries(lokinet-platform PUBLIC # set(CMAKE_SHARED_LIBRARY_PREFIX_CXX "")
Threads::Threads # endif()
base_libs # set_target_properties(lokinet-shared PROPERTIES OUTPUT_NAME lokinet)
uvw # if(WIN32)
) # target_link_libraries(lokinet-shared PUBLIC ws2_32 iphlpapi -fstack-protector)
# install(TARGETS lokinet-shared DESTINATION bin COMPONENT liblokinet)
target_link_libraries(lokinet-util PUBLIC # elseif(NOT APPLE)
nlohmann_json::nlohmann_json # install(TARGETS lokinet-shared LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT liblokinet)
# filesystem # endif()
oxenc::oxenc # endif()
)
# file(GLOB_RECURSE docs_SRC */*.hpp *.hpp)
target_link_libraries(lokinet-layer-link PUBLIC # set(DOCS_SRC ${docs_SRC} PARENT_SCOPE)
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 "bootstrap.hpp"
#include "util/bencode.hpp" #include "util/bencode.hpp"
#include "util/logging.hpp" #include "util/logging.hpp"
#include "util/logging/buffer.hpp" #include "util/logging/buffer.hpp"
#include "util/fs.hpp"
namespace llarp namespace llarp
{ {

@ -1,8 +1,9 @@
#pragma once #pragma once
#include "router_contact.hpp"
#include <set> #include <set>
#include <unordered_map> #include <unordered_map>
#include "router_contact.hpp"
#include "llarp/util/fs.hpp" #include "llarp/util/fs.hpp"
namespace llarp 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 "config.hpp"
#include "definition.hpp"
#include "ini.hpp"
#include <llarp/constants/files.hpp> #include <llarp/constants/files.hpp>
#include <llarp/constants/platform.hpp> #include <llarp/constants/platform.hpp>
@ -8,19 +6,14 @@
#include <llarp/net/net.hpp> #include <llarp/net/net.hpp>
#include <llarp/net/ip.hpp> #include <llarp/net/ip.hpp>
#include <llarp/router_contact.hpp> #include <llarp/router_contact.hpp>
#include <stdexcept>
#include <llarp/util/file.hpp> #include <llarp/util/file.hpp>
#include <llarp/util/formattable.hpp>
#include <llarp/util/logging.hpp> #include <llarp/util/logging.hpp>
#include <llarp/util/mem.hpp>
#include <llarp/util/str.hpp> #include <llarp/util/str.hpp>
#include <llarp/service/name.hpp> #include <llarp/service/name.hpp>
#include <stdexcept>
#include <chrono> #include "definition.hpp"
#include <cstdlib> #include "ini.hpp"
#include <ios>
#include <iostream>
namespace llarp namespace llarp
{ {

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

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

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

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

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

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

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

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

@ -3,7 +3,6 @@
#include <sodium/core.h> #include <sodium/core.h>
#include <sodium/crypto_generichash.h> #include <sodium/crypto_generichash.h>
#include <sodium/crypto_sign.h> #include <sodium/crypto_sign.h>
#include <sodium/crypto_scalarmult.h>
#include <sodium/crypto_scalarmult_ed25519.h> #include <sodium/crypto_scalarmult_ed25519.h>
#include <sodium/crypto_stream_xchacha20.h> #include <sodium/crypto_stream_xchacha20.h>
#include <sodium/crypto_core_ed25519.h> #include <sodium/crypto_core_ed25519.h>
@ -11,16 +10,12 @@
#include <sodium/randombytes.h> #include <sodium/randombytes.h>
#include <sodium/utils.h> #include <sodium/utils.h>
#include <oxenc/endian.h> #include <oxenc/endian.h>
#include <llarp/util/mem.hpp>
#include <llarp/util/str.hpp>
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#ifdef HAVE_CRYPT #ifdef HAVE_CRYPT
#include <crypt.h> #include <crypt.h>
#endif #endif
#include <llarp/util/str.hpp>
namespace llarp namespace llarp
{ {
static bool static bool

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

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

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

@ -2,14 +2,10 @@
#include <llarp/util/buffer.hpp> #include <llarp/util/buffer.hpp>
#include <llarp/util/file.hpp> #include <llarp/util/file.hpp>
#include <iterator>
#include <oxenc/hex.h> #include <oxenc/hex.h>
#include <sodium/crypto_sign.h> // #include <sodium/crypto_hash_sha512.h>
#include <sodium/crypto_sign_ed25519.h> // #include <sodium/crypto_scalarmult_ed25519.h>
#include <sodium/crypto_scalarmult_ed25519.h>
namespace llarp namespace llarp
{ {

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

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

@ -1,434 +1,430 @@
#include "message.hpp" #include "message.hpp"
#include <oxenc/endian.h>
#include "dns.hpp" #include <oxenc/endian.h>
#include "srv_data.hpp"
#include <llarp/util/buffer.hpp> #include <llarp/util/buffer.hpp>
#include <llarp/util/logging.hpp>
#include <llarp/net/ip.hpp> #include <llarp/net/ip.hpp>
#include <array> #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 Message::Message(const Question& question) : hdr_id{0}, hdr_fields{}
MessageHeader::Encode(llarp_buffer_t* buf) const {
{ questions.emplace_back(question);
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 bool
MessageHeader::Decode(llarp_buffer_t* buf) Message::Encode(llarp_buffer_t* buf) const
{ {
if (!buf->read_uint16(id)) MessageHeader hdr;
return false; hdr.id = hdr_id;
if (!buf->read_uint16(fields)) hdr.fields = hdr_fields;
return false; hdr.qd_count = questions.size();
if (!buf->read_uint16(qd_count)) hdr.an_count = answers.size();
return false; hdr.ns_count = 0;
if (!buf->read_uint16(an_count)) hdr.ar_count = 0;
return false;
if (!buf->read_uint16(ns_count)) if (!hdr.Encode(buf))
return false; return false;
if (!buf->read_uint16(ar_count))
for (const auto& question : questions)
if (!question.Encode(buf))
return false; 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 for (const auto& answer : answers)
Message::Encode(llarp_buffer_t* buf) const if (!answer.Encode(buf))
{
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; return false;
for (const auto& question : questions) return true;
if (!question.Encode(buf)) }
return false;
for (const auto& answer : answers)
if (!answer.Encode(buf))
return false;
return true;
}
bool bool
Message::Decode(llarp_buffer_t* buf) Message::Decode(llarp_buffer_t* buf)
{
for (auto& qd : questions)
{ {
for (auto& qd : questions) if (!qd.Decode(buf))
{
if (!qd.Decode(buf))
{
log::error(logcat, "failed to decode question");
return false;
}
log::debug(logcat, "question: {}", qd);
}
for (auto& an : answers)
{ {
if (not an.Decode(buf)) log::error(logcat, "failed to decode question");
{ return false;
log::debug(logcat, "failed to decode answer");
return false;
}
} }
return true; log::debug(logcat, "question: {}", qd);
} }
for (auto& an : answers)
util::StatusObject
Message::ToJSON() const
{ {
std::vector<util::StatusObject> ques; if (not an.Decode(buf))
std::vector<util::StatusObject> ans;
for (const auto& q : questions)
{
ques.push_back(q.ToJSON());
}
for (const auto& a : answers)
{ {
ans.push_back(a.ToJSON()); log::debug(logcat, "failed to decode answer");
return false;
} }
return util::StatusObject{{"questions", ques}, {"answers", ans}};
} }
return true;
}
OwnedBuffer util::StatusObject
Message::ToBuffer() const Message::ToJSON() const
{
std::vector<util::StatusObject> ques;
std::vector<util::StatusObject> ans;
for (const auto& q : questions)
{ {
std::array<byte_t, 1500> tmp; ques.push_back(q.ToJSON());
llarp_buffer_t buf{tmp};
if (not Encode(&buf))
throw std::runtime_error("cannot encode dns message");
return OwnedBuffer::copy_used(buf);
} }
for (const auto& a : answers)
void
Message::AddServFail(RR_TTL_t)
{ {
if (questions.size()) ans.push_back(a.ToJSON());
{
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;
}
} }
return util::StatusObject{{"questions", ques}, {"answers", ans}};
}
static constexpr uint16_t OwnedBuffer
reply_flags(uint16_t setbits) 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 void
Message::AddINReply(llarp::huint128_t ip, bool isV6, RR_TTL_t ttl) 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); rec.rr_type = qTypeAAAA;
ResourceRecord rec; ip.ToV6(rec.rData);
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));
} }
} else
void
Message::AddAReply(std::string name, RR_TTL_t ttl)
{
if (questions.size())
{ {
hdr_fields = reply_flags(hdr_fields); const auto addr = net::TruncateV6(ip);
rec.rr_type = qTypeA;
const auto& question = questions[0]; rec.rData.resize(4);
answers.emplace_back(); oxenc::write_host_as_big(addr.h, rec.rData.data());
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);
}
} }
answers.emplace_back(std::move(rec));
} }
}
void void
Message::AddNSReply(std::string name, RR_TTL_t ttl) 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); buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
const auto& question = questions[0]; memcpy(rec.rData.data(), buf.base, buf.sz);
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);
}
} }
} }
}
void void
Message::AddCNAMEReply(std::string name, RR_TTL_t ttl) 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); buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
const auto& question = questions[0]; memcpy(rec.rData.data(), buf.base, buf.sz);
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);
}
} }
} }
}
void void
Message::AddMXReply(std::string name, uint16_t priority, RR_TTL_t ttl) 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); buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
const auto& question = questions[0]; memcpy(rec.rData.data(), buf.base, buf.sz);
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);
}
} }
} }
}
void void
Message::AddSRVReply(std::vector<SRVData> records, RR_TTL_t ttl) Message::AddMXReply(std::string name, uint16_t priority, RR_TTL_t ttl)
{
if (questions.size())
{ {
hdr_fields = reply_flags(hdr_fields); hdr_fields = reply_flags(hdr_fields);
const auto& question = questions[0]; const auto& question = questions[0];
answers.emplace_back();
for (const auto& srv : records) 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; buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz); rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, 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 for (const auto& srv : records)
Message::AddTXTReply(std::string str, RR_TTL_t ttl)
{ {
auto& rec = answers.emplace_back(); if (not srv.IsValid())
rec.rr_name = questions[0].qname; {
AddNXReply();
return;
}
answers.emplace_back();
auto& rec = answers.back();
rec.rr_name = question.qname;
rec.rr_type = qTypeSRV;
rec.rr_class = qClassIN; rec.rr_class = qClassIN;
rec.rr_type = qTypeTXT;
rec.ttl = ttl; rec.ttl = ttl;
std::array<byte_t, 1024> tmp{};
std::array<byte_t, 512> tmp = {{0}};
llarp_buffer_t buf(tmp); 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}); target = srv.target;
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());
}
void if (not EncodeNameTo(&buf, target))
Message::AddNXReply(RR_TTL_t)
{
if (questions.size())
{ {
answers.clear(); AddNXReply();
authorities.clear(); return;
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;
} }
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
memcpy(rec.rData.data(), buf.base, buf.sz);
} }
}
std::string void
Message::ToString() const 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( const auto left = std::min(str.size(), size_t{256});
"[DNSMessage id={:x} fields={:x} questions={{{}}} answers={{{}}} authorities={{{}}} " const auto sub = str.substr(0, left);
"additional={{{}}}]", uint8_t byte = left;
hdr_id, *buf.cur = byte;
hdr_fields, buf.cur++;
fmt::format("{}", fmt::join(questions, ",")), if (not buf.write(sub.begin(), sub.end()))
fmt::format("{}", fmt::join(answers, ",")), throw std::length_error("text record too big");
fmt::format("{}", fmt::join(authorities, ",")), str = str.substr(left);
fmt::format("{}", fmt::join(additional, ",")));
} }
buf.sz = buf.cur - buf.base;
rec.rData.resize(buf.sz);
std::copy_n(buf.base, buf.sz, rec.rData.data());
}
std::optional<Message> void
MaybeParseDNSMessage(llarp_buffer_t buf) Message::AddNXReply(RR_TTL_t)
{
if (questions.size())
{ {
MessageHeader hdr{}; answers.clear();
if (not hdr.Decode(&buf)) authorities.clear();
return std::nullopt; additional.clear();
Message msg{hdr}; // authorative response with recursion available
if (not msg.Decode(&buf)) hdr_fields = reply_flags(hdr_fields);
return std::nullopt; // don't allow recursion on this request
return msg; 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 "name.hpp"
#include <llarp/net/net.hpp>
#include <llarp/net/ip.hpp> #include <llarp/net/ip.hpp>
#include <llarp/util/str.hpp> #include <llarp/util/str.hpp>
#include <llarp/net/net_bits.hpp>
#include <oxenc/hex.h> #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> if (buf->size_left() < 1)
DecodeName(llarp_buffer_t* buf, bool trimTrailingDot) return std::nullopt;
auto result = std::make_optional<std::string>();
auto& name = *result;
size_t l;
do
{ {
if (buf->size_left() < 1) l = *buf->cur;
return std::nullopt; buf->cur++;
auto result = std::make_optional<std::string>(); if (l)
auto& name = *result;
size_t l;
do
{ {
l = *buf->cur; if (buf->size_left() < l)
buf->cur++; return std::nullopt;
if (l)
{
if (buf->size_left() < l)
return std::nullopt;
name.append((const char*)buf->cur, l); name.append((const char*)buf->cur, l);
name += '.'; name += '.';
} }
buf->cur = buf->cur + l; buf->cur = buf->cur + l;
} while (l); } while (l);
/// trim off last dot /// trim off last dot
if (trimTrailingDot) if (trimTrailingDot)
name.pop_back(); name.pop_back();
return result; return result;
} }
bool bool
EncodeNameTo(llarp_buffer_t* buf, std::string_view name) EncodeNameTo(llarp_buffer_t* buf, std::string_view name)
{ {
if (name.size() && name.back() == '.') if (name.size() && name.back() == '.')
name.remove_suffix(1); 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(); std::memcpy(buf->cur, part.data(), l);
if (l > 63) buf->cur += l;
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;
} }
*buf->cur = 0; else
buf->cur++; break;
return true;
} }
*buf->cur = 0;
buf->cur++;
return true;
}
std::optional<huint128_t> std::optional<huint128_t>
DecodePTR(std::string_view name) DecodePTR(std::string_view name)
{
bool isV6 = false;
auto pos = name.find(".in-addr.arpa");
if (pos == std::string::npos)
{ {
bool isV6 = false; pos = name.find(".ip6.arpa");
auto pos = name.find(".in-addr.arpa"); isV6 = true;
if (pos == std::string::npos) }
{ if (pos == std::string::npos)
pos = name.find(".ip6.arpa"); return std::nullopt;
isV6 = true; name = name.substr(0, pos + 1);
} const auto numdots = std::count(name.begin(), name.end(), '.');
if (pos == std::string::npos) if (numdots == 4 && !isV6)
return std::nullopt; {
name = name.substr(0, pos + 1); std::array<uint8_t, 4> q;
const auto numdots = std::count(name.begin(), name.end(), '.'); for (int i = 3; i >= 0; i--)
if (numdots == 4 && !isV6)
{ {
std::array<uint8_t, 4> q; pos = name.find('.');
for (int i = 3; i >= 0; i--) if (!llarp::parse_int(name.substr(0, pos), q[i]))
{ return std::nullopt;
pos = name.find('.'); name.remove_prefix(pos + 1);
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]));
} }
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 if (not(oxenc::is_hex_digit(name[i]) and name[i + 1] == '.'
// "badcfe1032...", then decode the hex string to bytes. and oxenc::is_hex_digit(name[i + 2]) and name[i + 3] == '.'))
std::array<char, 32> in; return std::nullopt;
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;
// Flip the nybbles because the smallest one is first // Flip the nybbles because the smallest one is first
*in_pos++ = name[i + 2]; *in_pos++ = name[i + 2];
*in_pos++ = name[i]; *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;
} }
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 bool
NameIsReserved(std::string_view name) 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 = { if (ends_with(name, reserved)) // subdomain foo.loki.loki
".snode.loki"sv, ".loki.loki"sv, ".snode.loki."sv, ".loki.loki."sv}; return true;
for (const auto& reserved : reserved_names) if (name == reserved.substr(1)) // loki.loki itself
{ return true;
if (ends_with(name, reserved)) // subdomain foo.loki.loki
return true;
if (name == reserved.substr(1)) // loki.loki itself
return true;
}
return false;
} }
} // namespace dns return false;
} // namespace llarp }
} // namespace llarp::dns

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

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

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

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

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

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

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

@ -1,44 +1,40 @@
#include "serialize.hpp" #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 bool
EncodeRData(llarp_buffer_t* buf, const std::vector<byte_t>& v) 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) memcpy(v.data(), buf->cur, len);
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; 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::dns
} // namespace llarp

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

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

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

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

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

@ -4,19 +4,16 @@
struct llarp_buffer_t; 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 /// decode name from buffer
bool bool
decode_name(llarp_buffer_t* buf, name_t& name); decode_name(llarp_buffer_t* buf, name_t& name);
/// encode name to buffer /// encode name to buffer
bool bool
encode_name(llarp_buffer_t* buf, const name_t& name); encode_name(llarp_buffer_t* buf, const name_t& name);
} // namespace dns } // namespace llarp::dns
} // namespace llarp

@ -1,14 +1,7 @@
#pragma once #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 <llarp/link/tunnel.hpp>
#include <quic.hpp>
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <string> #include <string>
@ -16,8 +9,14 @@
#include <optional> #include <optional>
#include <unordered_set> #include <unordered_set>
#include <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 "oxenc/variant.h"
#include <quic.hpp>
namespace llarp namespace llarp
{ {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -20,7 +20,7 @@ namespace llarp
namespace llarp::link namespace llarp::link
{ {
struct Endpoint; // struct Endpoint;
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -153,7 +153,7 @@ namespace llarp::link
struct ClientTunnel struct ClientTunnel
{ {
// quic endpoint // 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) // Callback to invoke on quic connection established (true argument) or failed (false arg)
OpenCallback open_cb; OpenCallback open_cb;
// TCP listening socket // TCP listening socket
@ -164,7 +164,28 @@ namespace llarp::link
// because we are still handshaking, or we reached the stream limit). // because we are still handshaking, or we reached the stream limit).
std::queue<std::weak_ptr<uvw::TCPHandle>> pending_incoming; 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 // 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/encrypted.hpp>
#include <llarp/crypto/types.hpp> #include <llarp/crypto/types.hpp>
#include "link_message.hpp"
#include <llarp/path/path_types.hpp> #include <llarp/path/path_types.hpp>
#include <vector> #include <vector>
#include "link_message.hpp"
namespace llarp namespace llarp
{ {
/* /*

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

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

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

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

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

@ -1,15 +1,13 @@
#pragma once #pragma once
#include "sock_addr.hpp" #include <llarp/util/formattable.hpp>
#include <optional> #include <optional>
#include <string_view> #include <string_view>
#include <string> #include <string>
#include "sock_addr.hpp"
#include "net_int.hpp" #include "net_int.hpp"
#include <llarp/util/formattable.hpp>
namespace llarp namespace llarp
{ {
/// A struct that can represent either an IPv4 or IPv6 address. It is meant for representation /// 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_packet.hpp"
#include "ip.hpp"
#include <llarp/constants/net.hpp> #include <llarp/constants/net.hpp>
#include <llarp/util/buffer.hpp> #include <llarp/util/buffer.hpp>
#include <llarp/util/mem.hpp>
#include <llarp/util/str.hpp> #include <llarp/util/str.hpp>
#include "ip.hpp"
#ifndef _WIN32 #ifndef _WIN32
#include <netinet/in.h> #include <netinet/in.h>
#endif #endif
#include <oxenc/endian.h> #include <oxenc/endian.h>
#include <algorithm> #include <algorithm>
#include <map>
namespace llarp::net namespace llarp::net
{ {

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

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

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

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

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

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

@ -1,14 +1,13 @@
#include "sock_addr.hpp" #include "sock_addr.hpp"
#include <llarp/util/str.hpp>
#include <llarp/util/mem.hpp>
#include <stdexcept>
#include "ip_range.hpp" #include "ip_range.hpp"
#include "ip.hpp" #include "ip.hpp"
#include "net_bits.hpp" #include "net_bits.hpp"
#include "net.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 namespace llarp
{ {

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

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

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

@ -1,16 +1,6 @@
#pragma once #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 <llarp/router/router.hpp>
#include <set> #include <set>
#include <optional> #include <optional>
#include <unordered_set> #include <unordered_set>
@ -19,6 +9,15 @@
#include <atomic> #include <atomic>
#include <algorithm> #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 namespace llarp
{ {
struct Router; struct Router;

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

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

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

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

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

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

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "path_types.hpp"
#include <llarp/router_contact.hpp> #include <llarp/router_contact.hpp>
#include <llarp/service/protocol_type.hpp> #include <llarp/service/protocol_type.hpp>
#include <llarp/router_id.hpp> #include <llarp/router_id.hpp>
@ -8,13 +7,14 @@
#include <llarp/util/status.hpp> #include <llarp/util/status.hpp>
#include <llarp/util/thread/threading.hpp> #include <llarp/util/thread/threading.hpp>
#include <llarp/util/time.hpp> #include <llarp/util/time.hpp>
#include <functional> #include <functional>
#include <list> #include <list>
#include <map> #include <map>
#include <tuple> #include <tuple>
#include <unordered_set> #include <unordered_set>
#include "path_types.hpp"
namespace std namespace std
{ {
template <> 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/router/router.hpp>
#include <llarp/util/buffer.hpp> #include <llarp/util/buffer.hpp>
#include <oxenc/endian.h> #include "transit_hop.hpp"
namespace llarp::path namespace llarp::path
{ {
@ -29,6 +23,15 @@ namespace llarp::path
m_DownstreamWorkCounter = 0; m_DownstreamWorkCounter = 0;
} }
bool
TransitHop::send_path_control_message(
std::string,
std::string,
std::function<void(oxen::quic::message m)>)
{
return true;
}
bool bool
TransitHop::Expired(llarp_time_t now) const 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 "pow.hpp"
#include "crypto/crypto.hpp"
#include "util/buffer.hpp"
#include <cmath> #include <cmath>
#include "crypto/crypto.hpp"
namespace llarp namespace llarp
{ {
PoW::~PoW() = default; PoW::~PoW() = default;

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

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <map>
#include "path/path.hpp" #include "path/path.hpp"
#include "router_id.hpp" #include "router_id.hpp"
#include "util/bencode.hpp" #include "util/bencode.hpp"
#include "util/thread/threading.hpp" #include "util/thread/threading.hpp"
#include "util/thread/annotations.hpp" #include "util/thread/annotations.hpp"
#include <map>
namespace oxenc 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 "rc_gossiper.hpp"
#include <llarp/router_contact.hpp>
#include <llarp/util/time.hpp> #include <llarp/util/time.hpp>
#include <llarp/constants/link_layer.hpp>
#include <llarp/link/link_manager.hpp>
namespace llarp namespace llarp
{ {

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

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

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

Loading…
Cancel
Save