From 5f49d3a49fbe8ff34dc72230e8375f7fbe0b21d2 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sun, 19 Sep 2021 16:41:03 -0400 Subject: [PATCH 01/43] update header with notes --- include/lokinet/lokinet_udp.h | 50 +++++++++++++++-------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 27b00c3e7..25b240dba 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -59,46 +59,40 @@ extern "C" /// inbound listen udp socket /// expose udp port exposePort to the void - /// if srv is not NULL add an srv record for this port, the format being "thingservice" in which - /// will add a srv record "_udp.thingservice.ouraddress.tld" that advertises this port provide - /// localAddr to forward inbound udp packets to "ip:port" if localAddr is NULL then the resulting - /// socket MUST be drained by lokinet_udp_recvmmsg - /// + /// localAddr to forward inbound udp packets to "ip:port" /// returns 0 on success /// returns nonzero on error in which it is an errno value int EXPORT lokinet_udp_bind( int exposedPort, - char* srv, char* localAddr, struct lokinet_udp_listen_result* result, struct lokinet_context* ctx); - /// poll many udp sockets for activity - /// returns 0 on sucess - /// - /// returns non zero errno on error + /// get remote peer information about a local udp flow coming from localaddr + /// returns 0 on success + /// returns nonzero on error in which it is an errno value int EXPORT - lokinet_udp_poll( - const int* socket_ids, - size_t numsockets, - const struct timespec* timeout, - struct lokinet_context* ctx); + lokinet_udp_peername(char* localAddr, struct lokinet_udp_flow* flow, struct lokinet_context* ctx); - struct lokinet_udp_pkt - { - char remote_addr[256]; - int remote_port; - struct iovec pkt; - }; + /* - /// analog to recvmmsg - ssize_t EXPORT - lokinet_udp_recvmmsg( - int socket_id, - struct lokinet_udp_pkt* events, - size_t max_events, - struct lokient_context* ctx); + Packet arrives for new flow: + - call "new_flow" callback, which can return: + - drop + - accept, returns (context pointer, flow timeout). + + If accepted then this packet and subsequent packets on the flow: + - call "new_packet" callback, given it the context pointer from accept. + + If no packets for (timeout) we call + - "flow_timeout" with the context pointer + + int new_flow(const struct remote_details* remote, void** user_ctx, int* flow_timeout); + void new_packet(const struct remote_details* remote, char* data, size_t len, void* user_ctx); + void flow_timeout(const struct remote_details* remote, void* user_ctx); + + */ #ifdef __cplusplus } From 433febe5c636f9fcb20961b73179cd47dfc24436 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 10:04:41 -0400 Subject: [PATCH 02/43] update liblokinet udp api header --- include/lokinet/lokinet_udp.h | 66 +++++++++++------------------------ 1 file changed, 21 insertions(+), 45 deletions(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 25b240dba..b68e685fb 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -21,7 +21,7 @@ extern "C" #endif /// information about a udp flow - struct lokinet_udp_flow + struct lokinet_udp_flowinfo { /// the socket id for this flow used for i/o purposes and closing this socket int socket_id; @@ -35,21 +35,6 @@ extern "C" int local_port; }; - /// establish an outbound udp flow - /// remoteHost is the remote .loki or .snode address conneting to - /// remotePort is either a string integer or an srv record name to lookup, e.g. thingservice in - /// which we do a srv lookup for _udp.thingservice.remotehost.tld and use the "best" port provided - /// localAddr is the local ip:port to bind our socket to, if localAddr is NULL then - /// lokinet_udp_sendmmsg MUST be used to send packets return 0 on success return nonzero on fail, - /// containing an errno value - int EXPORT - lokinet_udp_establish( - char* remoteHost, - char* remotePort, - char* localAddr, - struct lokinet_udp_flow* flow, - struct lokinet_context* ctx); - /// a result from a lokinet_udp_bind call struct lokinet_udp_bind_result { @@ -57,43 +42,34 @@ extern "C" int socket_id; }; + /// flow acceptor hook, return 0 success, return nonzero with errno on failure + typedef int (*lokinet_udp_flow_filter)(void*, const struct lokinet_udp_flowinfo*, void**, int*); + + /// hook function for handling packets + typedef void (*lokinet_udp_flow_recv_func)( + const struct lokinet_udp_flowinfo*, char*, size_t, void*); + + /// hook function for flow timeout + typedef void (*lokinet_udp_flow_timeout_func)(const lokinet_udp_flowinfo*, void*); + /// inbound listen udp socket /// expose udp port exposePort to the void - /// localAddr to forward inbound udp packets to "ip:port" - /// returns 0 on success - /// returns nonzero on error in which it is an errno value + /// filter MUST be non null, pointing to a flow filter for accepting new udp flows, called with + /// user data recv MUST be non null, pointing to a packet handler function for each flow, called + /// with per flow user data provided by filter function if accepted timeout MUST be non null, + /// pointing to a cleanup function to clean up a stale flow, staleness determined by the value + /// given by the filter function returns 0 on success returns nonzero on error in which it is an + /// errno value int EXPORT lokinet_udp_bind( int exposedPort, - char* localAddr, + lokinet_udp_flow_filter filter, + lokinet_udp_flow_recv_func recv, + lokinet_udp_flow_timeout_func timeout, + void* user, struct lokinet_udp_listen_result* result, struct lokinet_context* ctx); - /// get remote peer information about a local udp flow coming from localaddr - /// returns 0 on success - /// returns nonzero on error in which it is an errno value - int EXPORT - lokinet_udp_peername(char* localAddr, struct lokinet_udp_flow* flow, struct lokinet_context* ctx); - - /* - - Packet arrives for new flow: - - call "new_flow" callback, which can return: - - drop - - accept, returns (context pointer, flow timeout). - - If accepted then this packet and subsequent packets on the flow: - - call "new_packet" callback, given it the context pointer from accept. - - If no packets for (timeout) we call - - "flow_timeout" with the context pointer - - int new_flow(const struct remote_details* remote, void** user_ctx, int* flow_timeout); - void new_packet(const struct remote_details* remote, char* data, size_t len, void* user_ctx); - void flow_timeout(const struct remote_details* remote, void* user_ctx); - - */ - #ifdef __cplusplus } #endif From 50001da9a10e7a53c73979cfc150492721e30a01 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 10:21:57 -0400 Subject: [PATCH 03/43] remove dead shit from header --- include/lokinet/lokinet_udp.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index b68e685fb..8f21cb565 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -2,19 +2,6 @@ #include "lokinet_context.h" -#ifdef _WIN32 -extern "C" -{ - struct iovec - { - void* iov_base; - size_t iov_len; - }; -} -#else -#include -#endif - #ifdef __cplusplus extern "C" { From db7050cd2d580feac3fbe88da2ad32ec74523117 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 10:50:58 -0400 Subject: [PATCH 04/43] update liblokinet udp header --- include/lokinet/lokinet_udp.h | 62 ++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 8f21cb565..82ffd0a3a 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -14,12 +14,8 @@ extern "C" int socket_id; /// remote endpoint's .loki or .snode address char remote_addr[256]; - /// local endpoint's ip address - char local_addr[64]; /// remote endpont's port int remote_port; - /// local endpoint's port - int local_port; }; /// a result from a lokinet_udp_bind call @@ -30,23 +26,37 @@ extern "C" }; /// flow acceptor hook, return 0 success, return nonzero with errno on failure - typedef int (*lokinet_udp_flow_filter)(void*, const struct lokinet_udp_flowinfo*, void**, int*); + typedef int (*lokinet_udp_flow_filter)( + void* /*user*/, + const struct lokinet_udp_flowinfo* /* remote address */, + void** /* flow-userdata */, + int* /* timeout */); /// hook function for handling packets typedef void (*lokinet_udp_flow_recv_func)( - const struct lokinet_udp_flowinfo*, char*, size_t, void*); + const struct lokinet_udp_flowinfo* /* remote address */, + char* /* data pointer */, + size_t /* data length */, + void* /* flow-userdata */); /// hook function for flow timeout - typedef void (*lokinet_udp_flow_timeout_func)(const lokinet_udp_flowinfo*, void*); + typedef void (*lokinet_udp_flow_timeout_func)( + const lokinet_udp_flowinfo* /* remote address */, void* /* flow-userdata */); /// inbound listen udp socket /// expose udp port exposePort to the void - /// filter MUST be non null, pointing to a flow filter for accepting new udp flows, called with - /// user data recv MUST be non null, pointing to a packet handler function for each flow, called - /// with per flow user data provided by filter function if accepted timeout MUST be non null, + //// + /// @param filter MUST be non null, pointing to a flow filter for accepting new udp flows, called + /// with user data + /// + /// @param recv MUST be non null, pointing to a packet handler function for each flow, called + /// with per flow user data provided by filter function if accepted + /// + /// @param timeout MUST be non null, /// pointing to a cleanup function to clean up a stale flow, staleness determined by the value - /// given by the filter function returns 0 on success returns nonzero on error in which it is an - /// errno value + /// given by the filter function returns 0 on success + /// + /// @returns nonzero on error in which it is an errno value int EXPORT lokinet_udp_bind( int exposedPort, @@ -57,6 +67,34 @@ extern "C" struct lokinet_udp_listen_result* result, struct lokinet_context* ctx); + /// @brief establish a udp flow to remote endpoint + /// + /// @param remote the remote address to establish to + /// + /// @param ctx the lokinet context to use + /// + /// @return 0 on success, non zero errno on fail + int EXPORT + lokinet_udp_establish(const struct lokinet_udp_flowinfo* remote, struct lokinet_context* ctx); + + /// @brief send on an established flow to remote endpoint + /// + /// @param flowinfo populated after call on success + /// + /// @param ptr pointer to data to send + /// + /// @param len the length of the data + /// + /// @param ctx the lokinet context to use + /// + /// @returns 0 on success and non zero errno on fail + int EXPORT + lokinet_udp_flow_send( + const struct lokinet_udp_flowinfo* remote, + const void* ptr, + size_t len, + struct lokinet_ctx* ctx); + #ifdef __cplusplus } #endif From 5b8ebb269c8e4045e5d447aa04dd05ed7cb931fb Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 16:16:46 -0400 Subject: [PATCH 05/43] changes for liblokinet-ffi * cmake option BUILD_DAEMON for toggling building of daemon directory * when WITH_BOOTSTRAP is OFF dont build curl or cpr --- CMakeLists.txt | 8 +++++--- cmake/StaticBuild.cmake | 2 ++ external/CMakeLists.txt | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 526fbb368..1c41c6e28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ option(TRACY_ROOT "include tracy profiler source" OFF) option(WITH_TESTS "build unit tests" OFF) option(WITH_HIVE "build simulation stubs" OFF) option(BUILD_PACKAGE "builds extra components for making an installer (with 'make package')" OFF) +option(BUILD_DAEMON "build lokinet daemon and associated utils" ON) include(cmake/enable_lto.cmake) @@ -182,7 +183,7 @@ if(OXENMQ_FOUND) message(STATUS "Found system liboxenmq ${OXENMQ_VERSION}") else() message(STATUS "using oxenmq submodule") - add_subdirectory(${CMAKE_SOURCE_DIR}/external/oxen-mq) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/external/oxen-mq) endif() @@ -327,8 +328,9 @@ endif() add_subdirectory(crypto) add_subdirectory(llarp) -add_subdirectory(daemon) - +if(BUILD_DAEMON) + add_subdirectory(daemon) +endif() if(WITH_HIVE) add_subdirectory(pybind) diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index 87ba00a81..d7546fd02 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -335,6 +335,7 @@ set_target_properties(libzmq PROPERTIES INTERFACE_LINK_LIBRARIES "${libzmq_link_libs}" INTERFACE_COMPILE_DEFINITIONS "ZMQ_STATIC") +if(WITH_BOOTSTRAP) set(curl_extra) if(WIN32) set(curl_ssl_opts --without-ssl --with-schannel) @@ -423,3 +424,4 @@ endif() set_target_properties(CURL::libcurl PROPERTIES INTERFACE_LINK_LIBRARIES "${libcurl_link_libs}" INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB") +endif() diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 2ddd0e96f..47ea0b8ab 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -56,7 +56,7 @@ add_ngtcp2_lib() # cpr configuration. Ideally we'd just do this via add_subdirectory, but cpr's cmake requires # 3.15+, and we target lower than that (and this is fairly simple to build). - +if(WITH_BOOTSTRAP) if(NOT BUILD_STATIC_DEPS) find_package(CURL REQUIRED COMPONENTS HTTP HTTPS SSL) @@ -79,3 +79,4 @@ target_link_libraries(cpr PUBLIC CURL::libcurl) target_include_directories(cpr PUBLIC cpr/include) target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL) add_library(cpr::cpr ALIAS cpr) +endif() From 00075f541bceb44484d0d378c82d4eb6b1992a89 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 16:24:41 -0400 Subject: [PATCH 06/43] fix compile error --- include/lokinet/lokinet_udp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 82ffd0a3a..b1909c4c3 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -41,7 +41,7 @@ extern "C" /// hook function for flow timeout typedef void (*lokinet_udp_flow_timeout_func)( - const lokinet_udp_flowinfo* /* remote address */, void* /* flow-userdata */); + const struct lokinet_udp_flowinfo* /* remote address */, void* /* flow-userdata */); /// inbound listen udp socket /// expose udp port exposePort to the void From c4b1a9c074da63798111742b90c45b73fd2636ad Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 17:47:06 -0400 Subject: [PATCH 07/43] lokinet_add_bootstrap_rc * allow bootstrap lists to be passed in --- llarp/lokinet_shared.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 7a4891032..86b7d3aa6 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -237,11 +238,26 @@ extern "C" auto lock = ctx->acquire(); // add a temp cryptography implementation here so rc.Verify works llarp::CryptoManager instance{new llarp::sodium::CryptoLibSodium{}}; - if (not rc.BDecode(&buf)) - return -1; - if (not rc.Verify(llarp::time_now_ms())) - return -2; - ctx->config->bootstrap.routers.insert(std::move(rc)); + if (data[0] == 'l') + { + llarp::BootstrapList routers{}; + if (not routers.BDecode(&buf)) + return -1; + for (const auto& rc : routers) + { + if (not rc.Verify(llarp::time_now_ms())) + return -2; + } + ctx->config->bootstrap.routers = std::move(routers); + } + else + { + if (not rc.BDecode(&buf)) + return -1; + if (not rc.Verify(llarp::time_now_ms())) + return -2; + ctx->config->bootstrap.routers.insert(std::move(rc)); + } return 0; } From 2428cc189e725252f783c15f41574b1b68da6f96 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 17:55:07 -0400 Subject: [PATCH 08/43] llarp::BootstrapConfig update * make routers member a llarp::BootstrapList --- llarp/config/config.hpp | 3 ++- llarp/lokinet_shared.cpp | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/llarp/config/config.hpp b/llarp/config/config.hpp index 4b518fc04..ff7ca2e71 100644 --- a/llarp/config/config.hpp +++ b/llarp/config/config.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -196,7 +197,7 @@ namespace llarp struct BootstrapConfig { std::vector files; - std::set routers; + BootstrapList routers; bool seednode; void defineConfigOptions(ConfigDefinition& conf, const ConfigGenParameters& params); diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 86b7d3aa6..16e66f718 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -240,15 +240,13 @@ extern "C" llarp::CryptoManager instance{new llarp::sodium::CryptoLibSodium{}}; if (data[0] == 'l') { - llarp::BootstrapList routers{}; - if (not routers.BDecode(&buf)) + if (not ctx->config->bootstrap.routers.BDecode(&buf)) return -1; - for (const auto& rc : routers) + for (const auto& rc : ctx->config.bootstrap.routers) { if (not rc.Verify(llarp::time_now_ms())) return -2; } - ctx->config->bootstrap.routers = std::move(routers); } else { From c5b5ff7810370ff71efc9736eee9d35cde27e0b9 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 17:57:55 -0400 Subject: [PATCH 09/43] typo fix --- llarp/lokinet_shared.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 16e66f718..145af9f03 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -242,7 +242,7 @@ extern "C" { if (not ctx->config->bootstrap.routers.BDecode(&buf)) return -1; - for (const auto& rc : ctx->config.bootstrap.routers) + for (const auto& rc : ctx->config->bootstrap.routers) { if (not rc.Verify(llarp::time_now_ms())) return -2; From 38d4cec7d1a7b2fbf2346f62b257bcca7a7d079c Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 18:07:47 -0400 Subject: [PATCH 10/43] log errors on decoding --- llarp/lokinet_shared.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 145af9f03..f893d00e6 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -8,9 +8,10 @@ #include #include #include -#include #include +#include + #include #ifdef _WIN32 @@ -241,7 +242,10 @@ extern "C" if (data[0] == 'l') { if (not ctx->config->bootstrap.routers.BDecode(&buf)) + { + LogError("Cannot decode bootstrap list: ", llarp::buffer_printer{buf}); return -1; + } for (const auto& rc : ctx->config->bootstrap.routers) { if (not rc.Verify(llarp::time_now_ms())) From 8c8f97adda0452871c49fabfb34e32f28cb90d60 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 18:12:08 -0400 Subject: [PATCH 11/43] more logging --- llarp/lokinet_shared.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index f893d00e6..1b0bf0653 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -233,7 +233,6 @@ extern "C" lokinet_add_bootstrap_rc(const char* data, size_t datalen, struct lokinet_context* ctx) { llarp_buffer_t buf{data, datalen}; - llarp::RouterContact rc{}; if (ctx == nullptr) return -3; auto lock = ctx->acquire(); @@ -243,7 +242,7 @@ extern "C" { if (not ctx->config->bootstrap.routers.BDecode(&buf)) { - LogError("Cannot decode bootstrap list: ", llarp::buffer_printer{buf}); + llarp::LogError("Cannot decode bootstrap list: ", llarp::buffer_printer{buf}); return -1; } for (const auto& rc : ctx->config->bootstrap.routers) @@ -254,8 +253,12 @@ extern "C" } else { + llarp::RouterContact rc{}; if (not rc.BDecode(&buf)) + { + llarp::LogError("failed to decode signle RC: ", llarp::buffer_printer{buf}); return -1; + } if (not rc.Verify(llarp::time_now_ms())) return -2; ctx->config->bootstrap.routers.insert(std::move(rc)); From 66de6808843beadc20d5ebcce8841987dc51705e Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 18:22:15 -0400 Subject: [PATCH 12/43] sanity check --- llarp/lokinet_shared.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 1b0bf0653..0766be0f4 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -232,6 +232,8 @@ extern "C" int EXPORT lokinet_add_bootstrap_rc(const char* data, size_t datalen, struct lokinet_context* ctx) { + if (data == nullptr or datalen == 0) + return -3; llarp_buffer_t buf{data, datalen}; if (ctx == nullptr) return -3; From bbb082931abce87ef33ef04414db63470fc56b8b Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 18:40:29 -0400 Subject: [PATCH 13/43] more logging --- llarp/bootstrap.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/llarp/bootstrap.cpp b/llarp/bootstrap.cpp index f21f3a025..32f273de4 100644 --- a/llarp/bootstrap.cpp +++ b/llarp/bootstrap.cpp @@ -1,5 +1,7 @@ #include "bootstrap.hpp" #include "util/bencode.hpp" +#include "util/logging/logger.hpp" +#include "util/logging/buffer.hpp" namespace llarp { @@ -16,9 +18,12 @@ namespace llarp [&](llarp_buffer_t* b, bool more) -> bool { if (more) { - RouterContact rc; + RouterContact rc{}; if (not rc.BDecode(b)) + { + LogError("invalid rc in bootstrap list: ", llarp::buffer_printer{*b}); return false; + } emplace(std::move(rc)); } return true; From 13c3786067da0cd6c7a18615d424d60b0d6c446d Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 20 Sep 2021 20:03:05 -0400 Subject: [PATCH 14/43] correct function names --- include/lokinet/lokinet_stream.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/lokinet/lokinet_stream.h b/include/lokinet/lokinet_stream.h index d5d97754b..77be691f5 100644 --- a/include/lokinet/lokinet_stream.h +++ b/include/lokinet/lokinet_stream.h @@ -53,6 +53,9 @@ extern "C" int EXPORT lokinet_inbound_stream(uint16_t port, struct lokinet_context* context); + void EXPORT + lokinet_close_stream(int stream_id, struct lokinet_context* context); + #ifdef __cplusplus } #endif From 9d069983b4cac45a3adacbad75101f4af29f4cd6 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 21 Sep 2021 09:07:28 -0400 Subject: [PATCH 15/43] add WITH_BOOTSTRAP option for toggling building lokinet-bootstrap --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c41c6e28..ff0a9f12d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ option(WITH_TESTS "build unit tests" OFF) option(WITH_HIVE "build simulation stubs" OFF) option(BUILD_PACKAGE "builds extra components for making an installer (with 'make package')" OFF) option(BUILD_DAEMON "build lokinet daemon and associated utils" ON) +option(WITH_BOOTSTRAP "build lokinet-bootstrap tool" ON) include(cmake/enable_lto.cmake) From 9fb11bf3da54c5de92b66c8838258419b575a4df Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 21 Sep 2021 10:32:50 -0400 Subject: [PATCH 16/43] typo fixes and clarify docs --- include/lokinet/lokinet_udp.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index b1909c4c3..6142192df 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -10,12 +10,12 @@ extern "C" /// information about a udp flow struct lokinet_udp_flowinfo { - /// the socket id for this flow used for i/o purposes and closing this socket - int socket_id; /// remote endpoint's .loki or .snode address char remote_addr[256]; /// remote endpont's port int remote_port; + /// the socket id for this flow used for i/o purposes and closing this socket + int socket_id; }; /// a result from a lokinet_udp_bind call @@ -30,7 +30,7 @@ extern "C" void* /*user*/, const struct lokinet_udp_flowinfo* /* remote address */, void** /* flow-userdata */, - int* /* timeout */); + int* /* timeout seconds */); /// hook function for handling packets typedef void (*lokinet_udp_flow_recv_func)( @@ -64,7 +64,7 @@ extern "C" lokinet_udp_flow_recv_func recv, lokinet_udp_flow_timeout_func timeout, void* user, - struct lokinet_udp_listen_result* result, + struct lokinet_udp_bind_result* result, struct lokinet_context* ctx); /// @brief establish a udp flow to remote endpoint From 71364da9f4082be55d1c6159a7612512432dbe59 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 21 Sep 2021 10:58:02 -0400 Subject: [PATCH 17/43] fix typos add lokinet_udp_close --- include/lokinet/lokinet_udp.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 6142192df..54d7f0ed7 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -93,7 +93,16 @@ extern "C" const struct lokinet_udp_flowinfo* remote, const void* ptr, size_t len, - struct lokinet_ctx* ctx); + struct lokinet_context* ctx); + + /// @brief close a bound udp socket + /// closes all flows immediately + /// + /// @param socket_id the bound udp socket's id + /// + /// @param ctx lokinet context + void EXPORT + lokinet_udp_close(int socket_id, struct lokinet_context* ctx); #ifdef __cplusplus } From e11e736ea5e414549d29d788f2caea051be22cf2 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 21 Sep 2021 11:12:28 -0400 Subject: [PATCH 18/43] typofix --- include/lokinet/lokinet_udp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 54d7f0ed7..1d4de8cd2 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -11,7 +11,7 @@ extern "C" struct lokinet_udp_flowinfo { /// remote endpoint's .loki or .snode address - char remote_addr[256]; + char remote_host[[256]; /// remote endpont's port int remote_port; /// the socket id for this flow used for i/o purposes and closing this socket From d3d07fe53e6abd1f3d0132e132fd0bdd2d170617 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 21 Sep 2021 11:12:59 -0400 Subject: [PATCH 19/43] typofix --- include/lokinet/lokinet_udp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 1d4de8cd2..99d7cc83a 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -11,7 +11,7 @@ extern "C" struct lokinet_udp_flowinfo { /// remote endpoint's .loki or .snode address - char remote_host[[256]; + char remote_host[256]; /// remote endpont's port int remote_port; /// the socket id for this flow used for i/o purposes and closing this socket From 1c70b0f42f1ce95ffcfc6e7d669f415a91845fb7 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 21 Sep 2021 16:04:05 -0400 Subject: [PATCH 20/43] add lokinet_hex_to_base32z --- include/lokinet/lokinet_misc.h | 5 +++++ llarp/lokinet_shared.cpp | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/include/lokinet/lokinet_misc.h b/include/lokinet/lokinet_misc.h index dea41f9ba..fa20911e4 100644 --- a/include/lokinet/lokinet_misc.h +++ b/include/lokinet/lokinet_misc.h @@ -21,6 +21,11 @@ extern "C" int EXPORT lokinet_log_level(const char*); + /// @brief take in hex and turn it into base32z + /// @return value must be free()'d later + char* EXPORT + lokinet_hex_to_base32z(const char* hex); + #ifdef __cplusplus } #endif diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 0766be0f4..3020889e2 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -12,6 +12,8 @@ #include +#include + #include #ifdef _WIN32 @@ -546,6 +548,13 @@ extern "C" return id; } + char* EXPORT + lokinet_hex_to_base32z(const char* hex) + { + const auto base32z = oxenmq::to_base32z(oxenmq::from_hex(std::string{hex})); + return strdup(base32z.c_str()); + } + void EXPORT lokinet_close_stream(int stream_id, struct lokinet_context* ctx) { From ba57ab04aa47c64b289ad48f799fa5d5f7dfd113 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 23 Sep 2021 14:01:04 -0400 Subject: [PATCH 21/43] wire up liblokient_udp_* --- include/lokinet/lokinet_udp.h | 20 +- llarp/CMakeLists.txt | 1 + llarp/handlers/null.hpp | 161 +++++++----- llarp/handlers/tun.hpp | 2 +- llarp/lokinet_shared.cpp | 392 +++++++++++++++++++++++++++++- llarp/net/ip_packet.cpp | 33 +++ llarp/net/ip_packet.hpp | 8 + llarp/service/endpoint.hpp | 8 + llarp/vpn/egres_packet_router.cpp | 101 ++++++++ llarp/vpn/egres_packet_router.hpp | 49 ++++ llarp/vpn/packet_router.hpp | 5 +- 11 files changed, 695 insertions(+), 85 deletions(-) create mode 100644 llarp/vpn/egres_packet_router.cpp create mode 100644 llarp/vpn/egres_packet_router.hpp diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 99d7cc83a..7e5b6ca2b 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -13,7 +13,7 @@ extern "C" /// remote endpoint's .loki or .snode address char remote_host[256]; /// remote endpont's port - int remote_port; + uint16_t remote_port; /// the socket id for this flow used for i/o purposes and closing this socket int socket_id; }; @@ -32,10 +32,14 @@ extern "C" void** /* flow-userdata */, int* /* timeout seconds */); + /// callback to make a new outbound flow + typedef void(lokinet_udp_create_flow_func)( + void* /*userdata*/, void** /*flow userdata*/, int* /* flowtimeout */); + /// hook function for handling packets typedef void (*lokinet_udp_flow_recv_func)( const struct lokinet_udp_flowinfo* /* remote address */, - char* /* data pointer */, + const char* /* data pointer */, size_t /* data length */, void* /* flow-userdata */); @@ -59,7 +63,7 @@ extern "C" /// @returns nonzero on error in which it is an errno value int EXPORT lokinet_udp_bind( - int exposedPort, + uint16_t exposedPort, lokinet_udp_flow_filter filter, lokinet_udp_flow_recv_func recv, lokinet_udp_flow_timeout_func timeout, @@ -69,13 +73,21 @@ extern "C" /// @brief establish a udp flow to remote endpoint /// + /// @param create_flow the callback to create the new flow if we establish one + /// + /// @param user passed to new_flow as user data + /// /// @param remote the remote address to establish to /// /// @param ctx the lokinet context to use /// /// @return 0 on success, non zero errno on fail int EXPORT - lokinet_udp_establish(const struct lokinet_udp_flowinfo* remote, struct lokinet_context* ctx); + lokinet_udp_establish( + lokinet_udp_create_flow_func create_flow, + void* user, + const struct lokinet_udp_flowinfo* remote, + struct lokinet_context* ctx); /// @brief send on an established flow to remote endpoint /// diff --git a/llarp/CMakeLists.txt b/llarp/CMakeLists.txt index 05a60bbc3..2ccc1712c 100644 --- a/llarp/CMakeLists.txt +++ b/llarp/CMakeLists.txt @@ -54,6 +54,7 @@ add_library(lokinet-platform net/net_int.cpp net/sock_addr.cpp vpn/packet_router.cpp + vpn/egres_packet_router.cpp vpn/platform.cpp ) diff --git a/llarp/handlers/null.hpp b/llarp/handlers/null.hpp index e8f209dc6..174afb60d 100644 --- a/llarp/handlers/null.hpp +++ b/llarp/handlers/null.hpp @@ -5,87 +5,114 @@ #include #include #include +#include -namespace llarp +namespace llarp::handlers { - namespace handlers + struct NullEndpoint final : public llarp::service::Endpoint, + public std::enable_shared_from_this { - struct NullEndpoint final : public llarp::service::Endpoint, - public std::enable_shared_from_this + NullEndpoint(AbstractRouter* r, llarp::service::Context* parent) + : llarp::service::Endpoint{r, parent} + , m_PacketRouter{new vpn::EgresPacketRouter{[](auto, auto) {}}} { - NullEndpoint(AbstractRouter* r, llarp::service::Context* parent) - : llarp::service::Endpoint(r, parent) - { - r->loop()->add_ticker([this] { Pump(Now()); }); - } + r->loop()->add_ticker([this] { Pump(Now()); }); + } - virtual bool - HandleInboundPacket( - const service::ConvoTag tag, - const llarp_buffer_t& buf, - service::ProtocolType t, - uint64_t) override + virtual bool + HandleInboundPacket( + const service::ConvoTag tag, + const llarp_buffer_t& buf, + service::ProtocolType t, + uint64_t) override + { + LogTrace("Inbound ", t, " packet (", buf.sz, "B) on convo ", tag); + if (t == service::ProtocolType::Control) { - LogTrace("Inbound ", t, " packet (", buf.sz, "B) on convo ", tag); - if (t == service::ProtocolType::Control) - { - return true; - } - if (t != service::ProtocolType::QUIC) - return false; - - auto* quic = GetQUICTunnel(); - if (!quic) - { - LogWarn("incoming quic packet but this endpoint is not quic capable; dropping"); - return false; - } - if (buf.sz < 4) - { - LogWarn("invalid incoming quic packet, dropping"); - return false; - } - quic->receive_packet(tag, buf); return true; } - - std::string - GetIfName() const override + if (t == service::ProtocolType::TrafficV4 or t == service::ProtocolType::TrafficV6) { - return ""; + if (auto from = GetEndpointWithConvoTag(tag)) + { + net::IPPacket pkt{}; + if (not pkt.Load(buf)) + { + LogWarn("invalid ip packet from remote T=", tag); + return false; + } + m_PacketRouter->HandleIPPacketFrom(std::move(*from), std::move(pkt)); + return true; + } + else + { + LogWarn("did not handle packet, no endpoint with convotag T=", tag); + return false; + } } + if (t != service::ProtocolType::QUIC) + return false; - path::PathSet_ptr - GetSelf() override - { - return shared_from_this(); - } - - std::weak_ptr - GetWeak() override - { - return weak_from_this(); - } - - bool - SupportsV6() const override + auto* quic = GetQUICTunnel(); + if (!quic) { + LogWarn("incoming quic packet but this endpoint is not quic capable; dropping"); return false; } - - void - SendPacketToRemote(const llarp_buffer_t&, service::ProtocolType) override{}; - - huint128_t ObtainIPForAddr(std::variant) override + if (buf.sz < 4) { - return {0}; + LogWarn("invalid incoming quic packet, dropping"); + return false; } + quic->receive_packet(tag, buf); + return true; + } - std::optional> ObtainAddrForIP( - huint128_t) const override - { - return std::nullopt; - } - }; - } // namespace handlers -} // namespace llarp + std::string + GetIfName() const override + { + return ""; + } + + path::PathSet_ptr + GetSelf() override + { + return shared_from_this(); + } + + std::weak_ptr + GetWeak() override + { + return weak_from_this(); + } + + bool + SupportsV6() const override + { + return false; + } + + void + SendPacketToRemote(const llarp_buffer_t&, service::ProtocolType) override{}; + + huint128_t ObtainIPForAddr(std::variant) override + { + return {0}; + } + + std::optional> ObtainAddrForIP( + huint128_t) const override + { + return std::nullopt; + } + + vpn::EgresPacketRouter* + EgresPacketRouter() override + { + return m_PacketRouter.get(); + } + + private: + std::unique_ptr m_PacketRouter; + }; +} // namespace llarp::handlers diff --git a/llarp/handlers/tun.hpp b/llarp/handlers/tun.hpp index ee7a64b5f..37fe9f37d 100644 --- a/llarp/handlers/tun.hpp +++ b/llarp/handlers/tun.hpp @@ -15,7 +15,7 @@ #include #include #include -#include "service/protocol_type.hpp" +#include namespace llarp { diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 3020889e2..982b1eef9 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -1,7 +1,5 @@ - - -#include "lokinet.h" -#include "llarp.hpp" +#include +#include #include #include @@ -15,6 +13,8 @@ #include #include +#include +#include #ifdef _WIN32 #define EHOSTDOWN ENETDOWN @@ -32,6 +32,165 @@ namespace return std::make_shared(); } }; + + struct UDPFlow + { + using Clock_t = std::chrono::steady_clock; + void* m_FlowUserData; + std::chrono::seconds m_FlowTimeout; + std::chrono::time_point m_ExpiresAt; + lokinet_udp_flowinfo m_FlowInfo; + lokinet_udp_flow_recv_func m_Recv; + + /// call timeout hook for this flow + void + TimedOut(lokinet_udp_flow_timeout_func timeout) + { + timeout(&m_FlowInfo, m_FlowUserData); + } + + /// mark this flow as active + /// updates the expires at timestamp + void + MarkActive() + { + m_ExpiresAt = Clock_t::now() + m_FlowTimeout; + } + + /// returns true if we think this flow is expired + bool + IsExpired() const + { + return Clock_t::now() >= m_ExpiresAt; + } + + void + HandlePacket(const llarp::net::IPPacket& pkt) + { + if (auto maybe = pkt.L4Data()) + { + MarkActive(); + m_Recv(&m_FlowInfo, maybe->first, maybe->second, m_FlowUserData); + } + } + }; + + struct UDPHandler + { + using AddressVariant_t = llarp::vpn::AddressVariant_t; + int m_SocketID; + llarp::nuint16_t m_LocalPort; + lokinet_udp_flow_filter m_Filter; + lokinet_udp_flow_recv_func m_Recv; + lokinet_udp_flow_timeout_func m_Timeout; + void* m_User; + std::weak_ptr m_Endpoint; + + std::unordered_map m_Flows; + + std::mutex m_Access; + + explicit UDPHandler( + int socketid, + llarp::nuint16_t localport, + lokinet_udp_flow_filter filter, + lokinet_udp_flow_recv_func recv, + lokinet_udp_flow_timeout_func timeout, + void* user, + std::weak_ptr ep) + : m_SocketID{socketid} + , m_LocalPort{localport} + , m_Filter{filter} + , m_Recv{recv} + , m_Timeout{timeout} + , m_User{user} + , m_Endpoint{ep} + {} + + void + KillAllFlows() + { + std::unique_lock lock{m_Access}; + for (auto& item : m_Flows) + { + item.second.TimedOut(m_Timeout); + } + m_Flows.clear(); + } + + void + AddFlow( + const AddressVariant_t& from, + const lokinet_udp_flowinfo& flow_addr, + void* flow_userdata, + int flow_timeoutseconds) + { + std::unique_lock lock{m_Access}; + auto& flow = m_Flows[from]; + flow.m_FlowInfo = flow_addr; + flow.m_FlowTimeout = std::chrono::seconds{flow_timeoutseconds}; + flow.m_FlowUserData = flow_userdata; + } + + void + ExpireOldFlows() + { + std::unique_lock lock{m_Access}; + for (auto itr = m_Flows.begin(); itr != m_Flows.end();) + { + if (itr->second.IsExpired()) + { + itr->second.TimedOut(m_Timeout); + itr = m_Flows.erase(itr); + } + else + ++itr; + } + } + + void + HandlePacketFrom(AddressVariant_t from, llarp::net::IPPacket pkt) + { + bool isNewFlow{false}; + { + std::unique_lock lock{m_Access}; + isNewFlow = m_Flows.count(from) == 0; + } + if (isNewFlow) + { + lokinet_udp_flowinfo flow_addr{}; + // set flow remote address + var::visit( + [&flow_addr](auto&& from) { + const auto addr = from.ToString(); + std::copy_n( + addr.data(), + std::min(addr.size(), sizeof(flow_addr.remote_host)), + flow_addr.remote_host); + }, + from); + // set socket id + flow_addr.socket_id = m_SocketID; + // get source port + if (auto srcport = pkt.SrcPort()) + { + flow_addr.remote_port = ToHost(*srcport).h; + } + else + return; // invalid data so we bail + void* flow_userdata = nullptr; + int flow_timeoutseconds{}; + // got a new flow, let's check if we want it + if (m_Filter(m_User, &flow_addr, &flow_userdata, &flow_timeoutseconds)) + return; + AddFlow(from, flow_addr, flow_userdata, flow_timeoutseconds); + } + { + std::unique_lock lock{m_Access}; + m_Flows[from].HandlePacket(pkt); + } + } + }; } // namespace struct lokinet_context @@ -43,7 +202,10 @@ struct lokinet_context std::unique_ptr runner; - lokinet_context() : impl{std::make_shared()}, config{llarp::Config::EmbeddedConfig()} + int _socket_id; + + lokinet_context() + : impl{std::make_shared()}, config{llarp::Config::EmbeddedConfig()}, _socket_id{0} {} ~lokinet_context() @@ -52,6 +214,69 @@ struct lokinet_context runner->join(); } + int + next_socket_id() + { + int id = ++_socket_id; + // handle overflow + if (id < 0) + { + _socket_id = 0; + id = ++_socket_id; + } + return id; + } + + /// make a udp handler and hold onto it + /// return its id + [[nodiscard]] int + make_udp_handler( + const std::shared_ptr& ep, + llarp::huint16_t exposePort, + lokinet_udp_flow_filter filter, + lokinet_udp_flow_recv_func recv, + lokinet_udp_flow_timeout_func timeout, + void* user) + { + if (udp_sockets.empty()) + { + // start udp flow expiration timer + impl->router->loop()->call_every(1s, std::make_shared(0), [this]() { + std::unique_lock lock{m_access}; + for (auto& item : udp_sockets) + { + item.second->ExpireOldFlows(); + } + }); + } + + auto udp = std::make_unique( + next_socket_id(), llarp::ToNet(exposePort), filter, recv, timeout, user, std::weak_ptr{ep}); + auto id = udp->m_SocketID; + auto pkt = ep->EgresPacketRouter(); + pkt->AddUDPHandler(exposePort, [udp = udp.get(), this](auto from, auto pkt) { + udp->HandlePacketFrom(std::move(from), std::move(pkt)); + }); + udp_sockets[udp->m_SocketID] = std::move(udp); + return id; + } + + void + remove_udp_handler(int socket_id) + { + std::unique_ptr udp; + { + std::unique_lock lock{m_access}; + if (auto itr = udp_sockets.find(socket_id); itr != udp_sockets.end()) + { + udp = std::move(itr->second); + udp_sockets.erase(itr); + } + } + if (udp) + udp->KillAllFlows(); + } + /// acquire mutex for accessing this context [[nodiscard]] auto acquire() @@ -66,6 +291,7 @@ struct lokinet_context } std::unordered_map streams; + std::unordered_map> udp_sockets; void inbound_stream(int id) @@ -82,8 +308,6 @@ struct lokinet_context namespace { - std::unique_ptr g_context; - void stream_error(lokinet_stream_result* result, int err) { @@ -359,11 +583,11 @@ extern "C" return; auto lock = ctx->acquire(); - if (not ctx->impl->IsStopping()) - { - ctx->impl->CloseAsync(); - ctx->impl->Wait(); - } + if (ctx->impl->IsStopping()) + return; + + ctx->impl->CloseAsync(); + ctx->impl->Wait(); if (ctx->runner) ctx->runner->join(); @@ -626,4 +850,148 @@ extern "C" delete result->internal; result->internal = nullptr; } + + int EXPORT + lokinet_udp_bind( + uint16_t exposedPort, + lokinet_udp_flow_filter filter, + lokinet_udp_flow_recv_func recv, + lokinet_udp_flow_timeout_func timeout, + void* user, + struct lokinet_udp_bind_result* result, + struct lokinet_context* ctx) + { + if (filter == nullptr or recv == nullptr or timeout == nullptr or result == nullptr + or ctx == nullptr) + return EINVAL; + + auto lock = ctx->acquire(); + if (auto ep = ctx->endpoint()) + { + result->socket_id = + ctx->make_udp_handler(ep, llarp::huint16_t{exposedPort}, filter, recv, timeout, user); + return 0; + } + else + return EINVAL; + } + + void EXPORT + lokinet_udp_close(int socket_id, struct lokinet_context* ctx) + { + if (ctx) + ctx->remove_udp_handler(socket_id); + } + + int EXPORT + lokinet_udp_flow_send( + const struct lokinet_udp_flowinfo* remote, + const void* ptr, + size_t len, + struct lokinet_context* ctx) + { + if (remote == nullptr or remote->remote_port == 0 or ptr == nullptr or len == 0 + or ctx == nullptr) + return EINVAL; + std::shared_ptr ep; + llarp::nuint16_t srcport{0}; + llarp::nuint16_t dstport{llarp::ToNet(llarp::huint16_t{remote->remote_port})}; + { + auto lock = ctx->acquire(); + if (auto itr = ctx->udp_sockets.find(remote->socket_id); itr != ctx->udp_sockets.end()) + { + ep = itr->second->m_Endpoint.lock(); + srcport = itr->second->m_LocalPort; + } + else + return EHOSTUNREACH; + } + if (auto maybe = llarp::service::ParseAddress(std::string{remote->remote_host})) + { + llarp::net::IPPacket pkt = llarp::net::IPPacket::UDP( + llarp::nuint32_t{0}, + srcport, + llarp::nuint32_t{0}, + dstport, + llarp_buffer_t{reinterpret_cast(ptr), len}); + + if (pkt.sz == 0) + return EINVAL; + std::promise ret; + ctx->impl->router->loop()->call_soon([addr = *maybe, pkt = std::move(pkt), ep, &ret]() { + if (auto tag = ep->GetBestConvoTagFor(addr)) + { + if (ep->SendToOrQueue(*tag, pkt.ConstBuffer(), llarp::service::ProtocolType::TrafficV4)) + { + ret.set_value(0); + return; + } + } + ret.set_value(ENETUNREACH); + }); + return ret.get_future().get(); + } + return EINVAL; + } + + int EXPORT + lokinet_udp_establish( + lokinet_udp_create_flow_func create_flow, + void* user, + const struct lokinet_udp_flowinfo* remote, + struct lokinet_context* ctx) + { + if (create_flow == nullptr or remote == nullptr or ctx == nullptr) + return EINVAL; + std::shared_ptr ep; + { + auto lock = ctx->acquire(); + if (auto itr = ctx->udp_sockets.find(remote->socket_id); itr != ctx->udp_sockets.end()) + { + ep = itr->second->m_Endpoint.lock(); + } + else + return EHOSTUNREACH; + } + if (auto maybe = llarp::service::ParseAddress(std::string{remote->remote_host})) + { + { + // check for pre existing flow + auto lock = ctx->acquire(); + if (auto itr = ctx->udp_sockets.find(remote->socket_id); itr != ctx->udp_sockets.end()) + { + auto& udp = itr->second; + if (udp->m_Flows.count(*maybe)) + { + // we already have a flow. + return EADDRINUSE; + } + } + } + std::promise gotten; + ctx->impl->router->loop()->call_soon([addr = *maybe, ep, &gotten]() { + ep->EnsurePathTo( + addr, [&gotten](auto result) { gotten.set_value(result.has_value()); }, 5s); + }); + if (gotten.get_future().get()) + { + void* flow_data{nullptr}; + int flow_timeoutseconds{}; + create_flow(user, &flow_data, &flow_timeoutseconds); + { + auto lock = ctx->acquire(); + if (auto itr = ctx->udp_sockets.find(remote->socket_id); itr != ctx->udp_sockets.end()) + { + itr->second->AddFlow(*maybe, *remote, flow_data, flow_timeoutseconds); + return 0; + } + else + return EADDRINUSE; + } + } + else + return ETIMEDOUT; + } + return EINVAL; + } } diff --git a/llarp/net/ip_packet.cpp b/llarp/net/ip_packet.cpp index c31c2332d..b1deaaeea 100644 --- a/llarp/net/ip_packet.cpp +++ b/llarp/net/ip_packet.cpp @@ -128,6 +128,19 @@ namespace llarp } } + std::optional + IPPacket::SrctPort() const + { + switch (IPProtocol{Header()->protocol}) + { + case IPProtocol::TCP: + case IPProtocol::UDP: + return nuint16_t{*reinterpret_cast(buf + (Header()->ihl * 4))}; + default: + return std::nullopt; + } + } + huint32_t IPPacket::srcv4() const { @@ -571,6 +584,26 @@ namespace llarp return std::nullopt; } + std::optional> + IPPacket::L4Data() const + { + const auto* hdr = Header(); + size_t l4_HeaderSize = 0; + if (hdr->protocol == 0x11) + { + l4_HeaderSize = 8; + } + else + return std::nullopt; + + // check for invalid size + if (sz < (hdr->ihl * 4) + l4_HeaderSize) + return std::nullopt; + + const uint8_t* ptr = buf + ((hdr->ihl * 4) + l4_HeaderSize); + return std::make_pair(reinterpret_cast(ptr), std::distance(ptr, buf + sz)); + } + IPPacket IPPacket::UDP( nuint32_t srcaddr, diff --git a/llarp/net/ip_packet.hpp b/llarp/net/ip_packet.hpp index 9f4b91fb6..0987633aa 100644 --- a/llarp/net/ip_packet.hpp +++ b/llarp/net/ip_packet.hpp @@ -293,6 +293,14 @@ namespace llarp std::optional DstPort() const; + /// get source port if applicable + std::optional + SrcPort() const; + + /// get pointer and size of layer 4 data + std::optional> + L4Data() const; + void UpdateIPv4Address(nuint32_t src, nuint32_t dst); diff --git a/llarp/service/endpoint.hpp b/llarp/service/endpoint.hpp index b15add487..48308a525 100644 --- a/llarp/service/endpoint.hpp +++ b/llarp/service/endpoint.hpp @@ -28,6 +28,8 @@ #include +#include + // minimum time between introset shifts #ifndef MIN_SHIFT_INTERVAL #define MIN_SHIFT_INTERVAL 5s @@ -168,6 +170,12 @@ namespace llarp void HandlePathDied(path::Path_ptr p) override; + virtual vpn::EgresPacketRouter* + EgresPacketRouter() + { + return nullptr; + }; + bool PublishIntroSet(const EncryptedIntroSet& i, AbstractRouter* r) override; diff --git a/llarp/vpn/egres_packet_router.cpp b/llarp/vpn/egres_packet_router.cpp new file mode 100644 index 000000000..f892f0832 --- /dev/null +++ b/llarp/vpn/egres_packet_router.cpp @@ -0,0 +1,101 @@ +#include "egres_packet_router.hpp" + +namespace llarp::vpn +{ + struct EgresUDPPacketHandler : public EgresLayer4Handler + { + EgresPacketHandlerFunc m_BaseHandler; + std::unordered_map m_LocalPorts; + + explicit EgresUDPPacketHandler(EgresPacketHandlerFunc baseHandler) + : m_BaseHandler{std::move(baseHandler)} + {} + + void + AddSubHandler(nuint16_t localport, EgresPacketHandlerFunc handler) override + { + m_LocalPorts.emplace(localport, std::move(handler)); + } + + void + RemoveSubHandler(nuint16_t localport) override + { + m_LocalPorts.erase(localport); + } + + void + HandleIPPacketFrom(AddressVariant_t from, net::IPPacket pkt) override + { + const uint8_t* ptr = pkt.buf + (pkt.Header()->ihl * 4) + 2; + const nuint16_t dstPort{*reinterpret_cast(ptr)}; + if (auto itr = m_LocalPorts.find(dstPort); itr != m_LocalPorts.end()) + { + itr->second(std::move(from), std::move(pkt)); + } + else + m_BaseHandler(std::move(from), std::move(pkt)); + } + }; + + struct EgresGenericLayer4Handler : public EgresLayer4Handler + { + EgresPacketHandlerFunc m_BaseHandler; + + explicit EgresGenericLayer4Handler(EgresPacketHandlerFunc baseHandler) + : m_BaseHandler{std::move(baseHandler)} + {} + + void + HandleIPPacketFrom(AddressVariant_t from, net::IPPacket pkt) override + { + m_BaseHandler(std::move(from), std::move(pkt)); + } + }; + + EgresPacketRouter::EgresPacketRouter(EgresPacketHandlerFunc baseHandler) + : m_BaseHandler{std::move(baseHandler)} + {} + + void + EgresPacketRouter::HandleIPPacketFrom(AddressVariant_t from, net::IPPacket pkt) + { + const auto proto = pkt.Header()->protocol; + if (const auto itr = m_IPProtoHandler.find(proto); itr != m_IPProtoHandler.end()) + { + itr->second->HandleIPPacketFrom(std::move(from), std::move(pkt)); + } + else + m_BaseHandler(std::move(from), std::move(pkt)); + } + + namespace + { + constexpr byte_t udp_proto = 0x11; + } + + void + EgresPacketRouter::AddUDPHandler(huint16_t localport, EgresPacketHandlerFunc func) + { + if (m_IPProtoHandler.find(udp_proto) == m_IPProtoHandler.end()) + { + m_IPProtoHandler.emplace(udp_proto, std::make_unique(m_BaseHandler)); + } + m_IPProtoHandler[udp_proto]->AddSubHandler(ToNet(localport), func); + } + + void + EgresPacketRouter::AddIProtoHandler(uint8_t proto, EgresPacketHandlerFunc func) + { + m_IPProtoHandler[proto] = std::make_unique(std::move(func)); + } + + void + EgresPacketRouter::RemoveUDPHandler(huint16_t localport) + { + if (auto itr = m_IPProtoHandler.find(udp_proto); itr != m_IPProtoHandler.end()) + { + itr->second->RemoveSubHandler(ToNet(localport)); + } + } + +} // namespace llarp::vpn diff --git a/llarp/vpn/egres_packet_router.hpp b/llarp/vpn/egres_packet_router.hpp new file mode 100644 index 000000000..8b074267d --- /dev/null +++ b/llarp/vpn/egres_packet_router.hpp @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace llarp::vpn +{ + using AddressVariant_t = llarp::EndpointBase::AddressVariant_t; + using EgresPacketHandlerFunc = std::function; + + struct EgresLayer4Handler + { + virtual ~EgresLayer4Handler() = default; + + virtual void + HandleIPPacketFrom(AddressVariant_t from, net::IPPacket pkt) = 0; + + virtual void AddSubHandler(nuint16_t, EgresPacketHandlerFunc){}; + virtual void RemoveSubHandler(nuint16_t){}; + }; + + class EgresPacketRouter + { + EgresPacketHandlerFunc m_BaseHandler; + std::unordered_map> m_IPProtoHandler; + + public: + /// baseHandler will be called if no other handlers matches a packet + explicit EgresPacketRouter(EgresPacketHandlerFunc baseHandler); + + /// feed in an ip packet for handling + void + HandleIPPacketFrom(AddressVariant_t, net::IPPacket pkt); + + /// add a non udp packet handler using ip protocol proto + void + AddIProtoHandler(uint8_t proto, EgresPacketHandlerFunc func); + + /// helper that adds a udp packet handler for UDP destinted for localport + void + AddUDPHandler(huint16_t localport, EgresPacketHandlerFunc func); + + /// remove a udp handler that is already set up by bound port + void + RemoveUDPHandler(huint16_t localport); + }; +} // namespace llarp::vpn diff --git a/llarp/vpn/packet_router.hpp b/llarp/vpn/packet_router.hpp index e84454eae..ee0721a05 100644 --- a/llarp/vpn/packet_router.hpp +++ b/llarp/vpn/packet_router.hpp @@ -17,7 +17,6 @@ namespace llarp::vpn virtual void AddSubHandler(nuint16_t, PacketHandlerFunc){}; }; - class PacketRouter { PacketHandlerFunc m_BaseHandler; @@ -38,5 +37,9 @@ namespace llarp::vpn /// helper that adds a udp packet handler for UDP destinted for localport void AddUDPHandler(huint16_t localport, PacketHandlerFunc func); + + /// remove a udp handler that is already set up by bound port + void + RemoveUDPHandler(huint16_t localport); }; } // namespace llarp::vpn From b225ec1043f2926edfac5e9d2600a3509035a5c3 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 23 Sep 2021 14:31:47 -0400 Subject: [PATCH 22/43] thread safety stuff --- llarp/lokinet_shared.cpp | 65 ++++++++++++++++++++++++++++++---------- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 982b1eef9..f97b04dad 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -229,7 +229,7 @@ struct lokinet_context /// make a udp handler and hold onto it /// return its id - [[nodiscard]] int + [[nodiscard]] std::optional make_udp_handler( const std::shared_ptr& ep, llarp::huint16_t exposePort, @@ -250,21 +250,38 @@ struct lokinet_context }); } - auto udp = std::make_unique( + auto udp = std::make_shared( next_socket_id(), llarp::ToNet(exposePort), filter, recv, timeout, user, std::weak_ptr{ep}); auto id = udp->m_SocketID; - auto pkt = ep->EgresPacketRouter(); - pkt->AddUDPHandler(exposePort, [udp = udp.get(), this](auto from, auto pkt) { - udp->HandlePacketFrom(std::move(from), std::move(pkt)); + std::promise result; + + impl->router->loop()->call([ep, &result, udp]() { + if (auto pkt = ep->GetEgresPacketRouter()) + { + pkt->AddUDPHandler(exposePort, [udp = std::weak_ptr{udp}](auto from, auto pkt) { + if (auto ptr = udp.lock()) + { + ptr->HandlePacketFrom(std::move(from), std::move(pkt)); + } + }); + result.set_value(true); + } + else + result.set_value(false); }); - udp_sockets[udp->m_SocketID] = std::move(udp); - return id; + + if (result.get_future().get()) + { + udp_sockets[udp->m_SocketID] = std::move(udp); + return id; + } + return std::nullopt; } void remove_udp_handler(int socket_id) { - std::unique_ptr udp; + std::shared_ptr udp; { std::unique_lock lock{m_access}; if (auto itr = udp_sockets.find(socket_id); itr != udp_sockets.end()) @@ -274,7 +291,14 @@ struct lokinet_context } } if (udp) + { udp->KillAllFlows(); + // remove packet handler + impl->router->loop()->call([ep = udp->m_Endpoint.lock(), locaport = udp->m_LocalPort]() { + if (auto pkt = ep->EgresPacketRouter()) + pkt->RemoveUDPHandler(localport); + }); + } } /// acquire mutex for accessing this context @@ -291,7 +315,7 @@ struct lokinet_context } std::unordered_map streams; - std::unordered_map> udp_sockets; + std::unordered_map> udp_sockets; void inbound_stream(int id) @@ -868,19 +892,23 @@ extern "C" auto lock = ctx->acquire(); if (auto ep = ctx->endpoint()) { - result->socket_id = - ctx->make_udp_handler(ep, llarp::huint16_t{exposedPort}, filter, recv, timeout, user); - return 0; + if (auto maybe = + ctx->make_udp_handler(ep, llarp::huint16_t{exposedPort}, filter, recv, timeout, user)) + { + result->socket_id = *maybe; + return 0; + } } - else - return EINVAL; + return EINVAL; } void EXPORT lokinet_udp_close(int socket_id, struct lokinet_context* ctx) { if (ctx) + { ctx->remove_udp_handler(socket_id); + } } int EXPORT @@ -918,7 +946,7 @@ extern "C" if (pkt.sz == 0) return EINVAL; std::promise ret; - ctx->impl->router->loop()->call_soon([addr = *maybe, pkt = std::move(pkt), ep, &ret]() { + ctx->impl->router->loop()->call([addr = *maybe, pkt = std::move(pkt), ep, &ret]() { if (auto tag = ep->GetBestConvoTagFor(addr)) { if (ep->SendToOrQueue(*tag, pkt.ConstBuffer(), llarp::service::ProtocolType::TrafficV4)) @@ -946,6 +974,11 @@ extern "C" std::shared_ptr ep; { auto lock = ctx->acquire(); + if (ctx->impl->router->loop()->inEventLoop()) + { + LogError("cannot call udp_establish from internal event loop"); + return EINVAL; + } if (auto itr = ctx->udp_sockets.find(remote->socket_id); itr != ctx->udp_sockets.end()) { ep = itr->second->m_Endpoint.lock(); @@ -969,7 +1002,7 @@ extern "C" } } std::promise gotten; - ctx->impl->router->loop()->call_soon([addr = *maybe, ep, &gotten]() { + ctx->impl->router->loop()->call([addr = *maybe, ep, &gotten]() { ep->EnsurePathTo( addr, [&gotten](auto result) { gotten.set_value(result.has_value()); }, 5s); }); From f5157c31da59d012da6b0357e930752ba8856fa7 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 24 Sep 2021 09:35:33 -0400 Subject: [PATCH 23/43] make it compile --- llarp/lokinet_shared.cpp | 13 +++++++------ llarp/net/ip_packet.cpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index f97b04dad..592b7e967 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -255,8 +255,8 @@ struct lokinet_context auto id = udp->m_SocketID; std::promise result; - impl->router->loop()->call([ep, &result, udp]() { - if (auto pkt = ep->GetEgresPacketRouter()) + impl->router->loop()->call([ep, &result, udp, exposePort]() { + if (auto pkt = ep->EgresPacketRouter()) { pkt->AddUDPHandler(exposePort, [udp = std::weak_ptr{udp}](auto from, auto pkt) { if (auto ptr = udp.lock()) @@ -294,10 +294,11 @@ struct lokinet_context { udp->KillAllFlows(); // remove packet handler - impl->router->loop()->call([ep = udp->m_Endpoint.lock(), locaport = udp->m_LocalPort]() { - if (auto pkt = ep->EgresPacketRouter()) - pkt->RemoveUDPHandler(localport); - }); + impl->router->loop()->call( + [ep = udp->m_Endpoint.lock(), localport = llarp::ToHost(udp->m_LocalPort)]() { + if (auto pkt = ep->EgresPacketRouter()) + pkt->RemoveUDPHandler(localport); + }); } } diff --git a/llarp/net/ip_packet.cpp b/llarp/net/ip_packet.cpp index b1deaaeea..deef93102 100644 --- a/llarp/net/ip_packet.cpp +++ b/llarp/net/ip_packet.cpp @@ -129,7 +129,7 @@ namespace llarp } std::optional - IPPacket::SrctPort() const + IPPacket::SrcPort() const { switch (IPProtocol{Header()->protocol}) { From f38bf2770dc9631f3b07e4b2dcd852d0bb001f8e Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 24 Sep 2021 10:10:08 -0400 Subject: [PATCH 24/43] move WITH_BOOTSTRAP option to root project CMakeLists.txt --- CMakeLists.txt | 8 +++++++- daemon/CMakeLists.txt | 14 ++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff0a9f12d..97407324c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,12 @@ endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +set(DEFAULT_WITH_BOOTSTRAP ON) +if(APPLE) + set(DEFAULT_WITH_BOOTSTRAP OFF) +endif() + + # Core options option(USE_AVX2 "enable avx2 code" OFF) option(USE_NETNS "enable networking namespace support. Linux only" OFF) @@ -61,7 +67,7 @@ option(WITH_TESTS "build unit tests" OFF) option(WITH_HIVE "build simulation stubs" OFF) option(BUILD_PACKAGE "builds extra components for making an installer (with 'make package')" OFF) option(BUILD_DAEMON "build lokinet daemon and associated utils" ON) -option(WITH_BOOTSTRAP "build lokinet-bootstrap tool" ON) +option(WITH_BOOTSTRAP "build lokinet-bootstrap tool" ${DEFAULT_WITH_BOOTSTRAP}) include(cmake/enable_lto.cmake) diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index bc7be3a1f..a565bf96f 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -1,8 +1,3 @@ -set(DEFAULT_WITH_BOOTSTRAP ON) -if(APPLE) - set(DEFAULT_WITH_BOOTSTRAP OFF) -endif() -option(WITH_BOOTSTRAP "build lokinet-bootstrap tool" ${DEFAULT_WITH_BOOTSTRAP}) add_executable(lokinet-vpn lokinet-vpn.cpp) if(APPLE) @@ -11,11 +6,10 @@ if(APPLE) else() add_executable(lokinet lokinet.cpp) enable_lto(lokinet lokinet-vpn) - - if(WITH_BOOTSTRAP) - add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) - enable_lto(lokinet-bootstrap) - endif() +endif() +if(WITH_BOOTSTRAP) + add_executable(lokinet-bootstrap lokinet-bootstrap.cpp) + enable_lto(lokinet-bootstrap) endif() From 50b80564914f45daad44b69ecdf9b36c6d2c9f4e Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 24 Sep 2021 10:43:53 -0400 Subject: [PATCH 25/43] enable liblokinet on macos --- contrib/mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/mac.sh b/contrib/mac.sh index 0ddcbe3ff..0d338e579 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -21,7 +21,7 @@ cmake \ -DBUILD_PACKAGE=ON \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_TESTING=OFF \ - -DBUILD_LIBLOKINET=OFF \ + -DBUILD_LIBLOKINET=ON \ -DWITH_TESTS=OFF \ -DNATIVE_BUILD=OFF \ -DSTATIC_LINK=ON \ From 1feaec1169e8ce38fbc7e9f3a5cf7257f7fb0b26 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 24 Sep 2021 10:54:43 -0400 Subject: [PATCH 26/43] build liblokinet on macos --- daemon/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index a565bf96f..c6780820a 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -110,7 +110,7 @@ if(APPLE) @ONLY) add_custom_target( sign - DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension + DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension lokinet-shared COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() From 51b1d41b12162a38ced5da8706ce77abc06bc2dc Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sat, 25 Sep 2021 10:43:51 -0400 Subject: [PATCH 27/43] disable gost in static build --- cmake/StaticBuild.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index d7546fd02..73618ebdb 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -282,6 +282,7 @@ build_external(unbound DEPENDS openssl_external expat_external CONFIGURE_COMMAND ./configure ${cross_host} ${cross_rc} --prefix=${DEPS_DESTDIR} --disable-shared --enable-static --with-libunbound-only --with-pic + --disable-gost --$,enable,disable>-flto --with-ssl=${DEPS_DESTDIR} --with-libexpat=${DEPS_DESTDIR} "CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}" From b31cac4b714113d2d734ac8e6cbb2ea6209e0a0c Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sat, 25 Sep 2021 11:22:48 -0400 Subject: [PATCH 28/43] nodejs dipshittery --- cmake/StaticBuild.cmake | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index 73618ebdb..8344d4315 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -277,12 +277,15 @@ build_external(expat ) add_static_target(expat expat_external libexpat.a) - +if(WIN32) + # fickleness from cross compile and some nodejs dipshittery causes this to be required + set(unbound_extra_opts --disable-gost --disable-ecdsa) +endif() build_external(unbound DEPENDS openssl_external expat_external CONFIGURE_COMMAND ./configure ${cross_host} ${cross_rc} --prefix=${DEPS_DESTDIR} --disable-shared --enable-static --with-libunbound-only --with-pic - --disable-gost + ${unbound_extra_opts} --$,enable,disable>-flto --with-ssl=${DEPS_DESTDIR} --with-libexpat=${DEPS_DESTDIR} "CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}" From 65b29a1b703de95405f83cccb1e3be2ea414be03 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sat, 25 Sep 2021 12:54:43 -0400 Subject: [PATCH 29/43] add liblokinet custom logger --- include/lokinet/lokinet_misc.h | 6 ++++++ llarp/lokinet_shared.cpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/include/lokinet/lokinet_misc.h b/include/lokinet/lokinet_misc.h index fa20911e4..b09b20e2c 100644 --- a/include/lokinet/lokinet_misc.h +++ b/include/lokinet/lokinet_misc.h @@ -21,6 +21,12 @@ extern "C" int EXPORT lokinet_log_level(const char*); + typedef void (*lokinet_logger_func)(const char*, void*); + + /// set a custom logger function + void EXPORT + lokinet_set_logger(lokinet_logger_func func, void* user); + /// @brief take in hex and turn it into base32z /// @return value must be free()'d later char* EXPORT diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 592b7e967..6e793b915 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -22,6 +22,33 @@ namespace { + struct Logger : public llarp::ILogStream + { + lokinet_logger_func func; + void* user; + + explicit Logger(lokinet_logger_func _func, void* _user) : func{_func}, user{_user} + {} + + void + PreLog(std::stringstream&, llarp::LogLevel, const char*, int, const std::string&) const override + {} + + void + Print(llarp::LogLevel, const char*, const std::string& msg) override + { + func(msg.c_str(), user); + } + + void + PostLog(std::stringstream&) const override{}; + + void + ImmediateFlush() override{}; + + void Tick(llarp_time_t) override{}; + }; + struct Context : public llarp::Context { using llarp::Context::Context; @@ -1028,4 +1055,10 @@ extern "C" } return EINVAL; } + + void EXPORT + lokinet_set_logger(lokinet_logger_func func, void* user) + { + llarp::LogContext::Instance().logStream.reset(new Logger{func, user}); + } } From 8153edbf433b24e124eaa90d6c961aba06a71adc Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Sat, 25 Sep 2021 13:07:52 -0400 Subject: [PATCH 30/43] dont enable apple languages when not building daemon --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97407324c..4c6bc125b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,11 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Has to be set before `project()`, and ignored on non-macos: set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12 CACHE STRING "macOS deployment target (Apple clang only)") +option(BUILD_DAEMON "build lokinet daemon and associated utils" ON) + + set(LANGS C CXX) -if(APPLE) +if(APPLE AND BUILD_DAEMON) set(LANGS ${LANGS} OBJC Swift) endif() @@ -66,7 +69,6 @@ option(TRACY_ROOT "include tracy profiler source" OFF) option(WITH_TESTS "build unit tests" OFF) option(WITH_HIVE "build simulation stubs" OFF) option(BUILD_PACKAGE "builds extra components for making an installer (with 'make package')" OFF) -option(BUILD_DAEMON "build lokinet daemon and associated utils" ON) option(WITH_BOOTSTRAP "build lokinet-bootstrap tool" ${DEFAULT_WITH_BOOTSTRAP}) include(cmake/enable_lto.cmake) From 82ffa2f02c6a11b8d81cf05ed858783e0f47c3b1 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 30 Sep 2021 10:26:27 -0400 Subject: [PATCH 31/43] Update mac.sh disable liblokinet on mac by default in mac.sh --- contrib/mac.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/mac.sh b/contrib/mac.sh index 0d338e579..0ddcbe3ff 100755 --- a/contrib/mac.sh +++ b/contrib/mac.sh @@ -21,7 +21,7 @@ cmake \ -DBUILD_PACKAGE=ON \ -DBUILD_SHARED_LIBS=OFF \ -DBUILD_TESTING=OFF \ - -DBUILD_LIBLOKINET=ON \ + -DBUILD_LIBLOKINET=OFF \ -DWITH_TESTS=OFF \ -DNATIVE_BUILD=OFF \ -DSTATIC_LINK=ON \ From 97966976d09d08a27066c6896ea068435404f071 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 30 Sep 2021 10:27:24 -0400 Subject: [PATCH 32/43] Update CMakeLists.txt dont depend on lokinet-shared target for sign target as we disabled it by default. --- daemon/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/CMakeLists.txt b/daemon/CMakeLists.txt index c6780820a..a565bf96f 100644 --- a/daemon/CMakeLists.txt +++ b/daemon/CMakeLists.txt @@ -110,7 +110,7 @@ if(APPLE) @ONLY) add_custom_target( sign - DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension lokinet-shared + DEPENDS "${PROJECT_BINARY_DIR}/sign.sh" lokinet lokinet-extension COMMAND "${PROJECT_BINARY_DIR}/sign.sh" ) else() From ef19111f885fd490066616b199d122e54aac245d Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 30 Sep 2021 10:32:38 -0400 Subject: [PATCH 33/43] dont pack struct becuase alignment --- include/lokinet/lokinet_stream.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/lokinet/lokinet_stream.h b/include/lokinet/lokinet_stream.h index 77be691f5..545049c9b 100644 --- a/include/lokinet/lokinet_stream.h +++ b/include/lokinet/lokinet_stream.h @@ -8,7 +8,6 @@ extern "C" #endif /// the result of a lokinet stream mapping attempt -#pragma pack(1) struct lokinet_stream_result { /// set to zero on success otherwise the error that happened @@ -23,7 +22,6 @@ extern "C" /// the id of the stream we created int stream_id; }; -#pragma pack() /// connect out to a remote endpoint /// remoteAddr is in the form of "name:port" From 94ce7a9af734912b28e96f25e7cb1db0fe87fda6 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 30 Sep 2021 10:36:20 -0400 Subject: [PATCH 34/43] make function pointer arguments named --- include/lokinet/lokinet_stream.h | 2 +- include/lokinet/lokinet_udp.h | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/lokinet/lokinet_stream.h b/include/lokinet/lokinet_stream.h index 545049c9b..385a67fc8 100644 --- a/include/lokinet/lokinet_stream.h +++ b/include/lokinet/lokinet_stream.h @@ -37,7 +37,7 @@ extern "C" /// return 0 to accept /// return -1 to explicitly reject /// return -2 to silently drop - typedef int (*lokinet_stream_filter)(const char* remote, uint16_t port, void*); + typedef int (*lokinet_stream_filter)(const char* remote, uint16_t port, void* userdata); /// set stream accepter filter /// passes user parameter into stream filter as void * diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 7e5b6ca2b..15b503809 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -27,25 +27,25 @@ extern "C" /// flow acceptor hook, return 0 success, return nonzero with errno on failure typedef int (*lokinet_udp_flow_filter)( - void* /*user*/, - const struct lokinet_udp_flowinfo* /* remote address */, - void** /* flow-userdata */, - int* /* timeout seconds */); + void* userdata, + const struct lokinet_udp_flowinfo* remote_address, + void** flow_userdata, + int* timeout_seconds); /// callback to make a new outbound flow typedef void(lokinet_udp_create_flow_func)( - void* /*userdata*/, void** /*flow userdata*/, int* /* flowtimeout */); + void* userdata, void** flow_userdata, int* timeout_seconds); /// hook function for handling packets typedef void (*lokinet_udp_flow_recv_func)( - const struct lokinet_udp_flowinfo* /* remote address */, - const char* /* data pointer */, - size_t /* data length */, - void* /* flow-userdata */); + const struct lokinet_udp_flowinfo* remote_address, + const char* pkt_data, + size_t pkt_length, + void* flow_userdata); /// hook function for flow timeout typedef void (*lokinet_udp_flow_timeout_func)( - const struct lokinet_udp_flowinfo* /* remote address */, void* /* flow-userdata */); + const struct lokinet_udp_flowinfo* remote_address, void* flow_userdata); /// inbound listen udp socket /// expose udp port exposePort to the void From e2cd4d66ccdc8dd2ea9d274c449741f6a18b7b64 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 30 Sep 2021 10:40:54 -0400 Subject: [PATCH 35/43] docstring update --- include/lokinet/lokinet_udp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/lokinet/lokinet_udp.h b/include/lokinet/lokinet_udp.h index 15b503809..9e520dcd3 100644 --- a/include/lokinet/lokinet_udp.h +++ b/include/lokinet/lokinet_udp.h @@ -90,8 +90,9 @@ extern "C" struct lokinet_context* ctx); /// @brief send on an established flow to remote endpoint + /// blocks until we have sent the packet /// - /// @param flowinfo populated after call on success + /// @param flowinfo remote flow to use for sending /// /// @param ptr pointer to data to send /// From b20e7bedf87f154fef8fcef3959f5bc6f0666563 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 30 Sep 2021 10:43:06 -0400 Subject: [PATCH 36/43] identify --- external/CMakeLists.txt | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 47ea0b8ab..8f7c49d84 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -57,26 +57,26 @@ add_ngtcp2_lib() # cpr configuration. Ideally we'd just do this via add_subdirectory, but cpr's cmake requires # 3.15+, and we target lower than that (and this is fairly simple to build). if(WITH_BOOTSTRAP) -if(NOT BUILD_STATIC_DEPS) - find_package(CURL REQUIRED COMPONENTS HTTP HTTPS SSL) + if(NOT BUILD_STATIC_DEPS) + find_package(CURL REQUIRED COMPONENTS HTTP HTTPS SSL) - # CURL::libcurl wasn't added to FindCURL until cmake 3.12, so add it if necessary - if (CMAKE_VERSION VERSION_LESS 3.12 AND NOT TARGET CURL::libcurl) - add_library(libcurl UNKNOWN IMPORTED GLOBAL) - set_target_properties(libcurl PROPERTIES - IMPORTED_LOCATION ${CURL_LIBRARIES} - INTERFACE_INCLUDE_DIRECTORIES "${CURL_INCLUDE_DIRS}") - add_library(CURL_libcurl INTERFACE) - target_link_libraries(CURL_libcurl INTERFACE libcurl) - add_library(CURL::libcurl ALIAS CURL_libcurl) + # CURL::libcurl wasn't added to FindCURL until cmake 3.12, so add it if necessary + if (CMAKE_VERSION VERSION_LESS 3.12 AND NOT TARGET CURL::libcurl) + add_library(libcurl UNKNOWN IMPORTED GLOBAL) + set_target_properties(libcurl PROPERTIES + IMPORTED_LOCATION ${CURL_LIBRARIES} + INTERFACE_INCLUDE_DIRECTORIES "${CURL_INCLUDE_DIRS}") + add_library(CURL_libcurl INTERFACE) + target_link_libraries(CURL_libcurl INTERFACE libcurl) + add_library(CURL::libcurl ALIAS CURL_libcurl) + endif() endif() -endif() -file(GLOB cpr_sources ${conf_depends} cpr/cpr/*.cpp) + file(GLOB cpr_sources ${conf_depends} cpr/cpr/*.cpp) -add_library(cpr STATIC EXCLUDE_FROM_ALL ${cpr_sources}) -target_link_libraries(cpr PUBLIC CURL::libcurl) -target_include_directories(cpr PUBLIC cpr/include) -target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL) -add_library(cpr::cpr ALIAS cpr) + add_library(cpr STATIC EXCLUDE_FROM_ALL ${cpr_sources}) + target_link_libraries(cpr PUBLIC CURL::libcurl) + target_include_directories(cpr PUBLIC cpr/include) + target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL) + add_library(cpr::cpr ALIAS cpr) endif() From 5286d442fb7dd411be25709ad1c0981eaf71d029 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Thu, 30 Sep 2021 13:17:06 -0400 Subject: [PATCH 37/43] updates: * add udptest example * fix up udp codepath in liblokinet --- contrib/liblokinet/CMakeLists.txt | 10 ++ contrib/liblokinet/readme.md | 13 ++ contrib/liblokinet/udptest.cpp | 239 ++++++++++++++++++++++++++++++ llarp/handlers/null.hpp | 8 +- llarp/lokinet_shared.cpp | 15 +- llarp/vpn/egres_packet_router.cpp | 17 ++- 6 files changed, 287 insertions(+), 15 deletions(-) create mode 100644 contrib/liblokinet/CMakeLists.txt create mode 100644 contrib/liblokinet/readme.md create mode 100644 contrib/liblokinet/udptest.cpp diff --git a/contrib/liblokinet/CMakeLists.txt b/contrib/liblokinet/CMakeLists.txt new file mode 100644 index 000000000..6985f741b --- /dev/null +++ b/contrib/liblokinet/CMakeLists.txt @@ -0,0 +1,10 @@ + +cmake_minimum_required(VERSION 3.10) + +project(udptest LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +add_executable(udptest udptest.cpp) +include_directories(../../include) +target_link_libraries(udptest PUBLIC lokinet) + diff --git a/contrib/liblokinet/readme.md b/contrib/liblokinet/readme.md new file mode 100644 index 000000000..e0f63d135 --- /dev/null +++ b/contrib/liblokinet/readme.md @@ -0,0 +1,13 @@ +# liblokinet examples + +building: + + $ mkdir -p build + $ cd build + $ cp /path/to/liblokinet.so . + $ cmake .. -DCMAKE_EXE_LINKER_FLAGS='-L.' + $ make + +running: + + $ ./udptest /path/to/bootstrap.signed diff --git a/contrib/liblokinet/udptest.cpp b/contrib/liblokinet/udptest.cpp new file mode 100644 index 000000000..9db9c399e --- /dev/null +++ b/contrib/liblokinet/udptest.cpp @@ -0,0 +1,239 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool _run{true}; + +using Lokinet_ptr = std::shared_ptr; + +[[nodiscard]] auto +MakeLokinet(const std::vector& bootstrap) +{ + auto ctx = std::shared_ptr(lokinet_context_new(), lokinet_context_free); + if (auto err = lokinet_add_bootstrap_rc(bootstrap.data(), bootstrap.size(), ctx.get())) + throw std::runtime_error{strerror(err)}; + if (lokinet_context_start(ctx.get())) + throw std::runtime_error{"could not start context"}; + return ctx; +} + +void +WaitForReady(const Lokinet_ptr& ctx) +{ + while (_run and lokinet_wait_for_ready(1000, ctx.get())) + { + std::cout << "waiting for context..." << std::endl; + } +} + +class Flow +{ + lokinet_udp_flowinfo const _info; + lokinet_context* const _ctx; + + public: + explicit Flow(const lokinet_udp_flowinfo* info, lokinet_context* ctx) : _info{*info}, _ctx{ctx} + {} + + lokinet_context* + Context() const + { + return _ctx; + } + + std::string + String() const + { + std::stringstream ss; + ss << std::string{_info.remote_host} << ":" << std::to_string(_info.remote_port) + << " on socket " << _info.socket_id; + return ss.str(); + } +}; + +struct ConnectJob +{ + lokinet_udp_flowinfo remote; + lokinet_context* ctx; +}; + +void +CreateOutboundFlow(void* user, void** flowdata, int* timeout) +{ + auto* job = static_cast(user); + Flow* flow = new Flow{&job->remote, job->ctx}; + *flowdata = flow; + *timeout = 30; + std::cout << "made outbound flow: " << flow->String() << std::endl; + ; +} + +int +ProcessNewInboundFlow(void* user, const lokinet_udp_flowinfo* remote, void** flowdata, int* timeout) +{ + auto* ctx = static_cast(user); + Flow* flow = new Flow{remote, ctx}; + std::cout << "new udp flow: " << flow->String() << std::endl; + *flowdata = flow; + *timeout = 30; + + return 0; +} + +void +DeleteFlow(const lokinet_udp_flowinfo* remote, void* flowdata) +{ + auto* flow = static_cast(flowdata); + std::cout << "udp flow from " << flow->String() << " timed out" << std::endl; + delete flow; +} + +void +HandleUDPPacket(const lokinet_udp_flowinfo* remote, const char* pkt, size_t len, void* flowdata) +{ + auto* flow = static_cast(flowdata); + std::cout << "we got " << len << " bytes of udp from " << flow->String() << std::endl; +} + +void +BounceUDPPacket(const lokinet_udp_flowinfo* remote, const char* pkt, size_t len, void* flowdata) +{ + auto* flow = static_cast(flowdata); + std::cout << "bounce " << len << " bytes of udp from " << flow->String() << std::endl; + if (auto err = lokinet_udp_flow_send(remote, pkt, len, flow->Context())) + { + std::cout << "bounce failed: " << strerror(err) << std::endl; + } +} + +Lokinet_ptr sender, recip; + +void +signal_handler(int) +{ + _run = false; +} + +int +main(int argc, char* argv[]) +{ + if (argc == 1) + { + std::cout << "usage: " << argv[0] << " bootstrap.signed" << std::endl; + return 1; + } + + /* + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + */ + + std::vector bootstrap; + + // load bootstrap.signed + { + std::ifstream inf{argv[1], std::ifstream::ate | std::ifstream::binary}; + size_t len = inf.tellg(); + inf.seekg(0); + bootstrap.resize(len); + inf.read(bootstrap.data(), bootstrap.size()); + } + + if (auto* loglevel = getenv("LOKINET_LOG")) + lokinet_log_level(loglevel); + else + lokinet_log_level("none"); + + std::cout << "starting up" << std::endl; + + recip = MakeLokinet(bootstrap); + WaitForReady(recip); + + lokinet_udp_bind_result recipBindResult{}; + + const auto port = 10000; + + if (auto err = lokinet_udp_bind( + port, + ProcessNewInboundFlow, + BounceUDPPacket, + DeleteFlow, + recip.get(), + &recipBindResult, + recip.get())) + { + std::cout << "failed to bind recip udp socket " << strerror(err) << std::endl; + return 0; + } + + std::cout << "bound recip udp" << std::endl; + + sender = MakeLokinet(bootstrap); + WaitForReady(sender); + + std::string recipaddr{lokinet_address(recip.get())}; + + std::cout << "recip ready at " << recipaddr << std::endl; + + lokinet_udp_bind_result senderBindResult{}; + + if (auto err = lokinet_udp_bind( + port, + ProcessNewInboundFlow, + HandleUDPPacket, + DeleteFlow, + sender.get(), + &senderBindResult, + sender.get())) + { + std::cout << "failed to bind sender udp socket " << strerror(err) << std::endl; + return 0; + } + + ConnectJob connect{}; + connect.remote.socket_id = senderBindResult.socket_id; + connect.remote.remote_port = port; + std::copy_n(recipaddr.c_str(), recipaddr.size(), connect.remote.remote_host); + connect.ctx = sender.get(); + + std::cout << "bound sender udp" << std::endl; + + do + { + std::cout << "try establish to " << connect.remote.remote_host << std::endl; + if (auto err = + lokinet_udp_establish(CreateOutboundFlow, &connect, &connect.remote, sender.get())) + { + std::cout << "failed to establish to recip: " << strerror(err) << std::endl; + usleep(100000); + } + else + break; + } while (true); + std::cout << "sender established" << std::endl; + + const std::string buf{"liblokinet"}; + + const std::string senderAddr{lokinet_address(sender.get())}; + + do + { + std::cout << senderAddr << " send to remote: " << buf << std::endl; + if (auto err = lokinet_udp_flow_send(&connect.remote, buf.data(), buf.size(), sender.get())) + { + std::cout << "send failed: " << strerror(err) << std::endl; + } + usleep(100000); + } while (_run); + return 0; +} diff --git a/llarp/handlers/null.hpp b/llarp/handlers/null.hpp index 174afb60d..e0464b041 100644 --- a/llarp/handlers/null.hpp +++ b/llarp/handlers/null.hpp @@ -14,7 +14,13 @@ namespace llarp::handlers { NullEndpoint(AbstractRouter* r, llarp::service::Context* parent) : llarp::service::Endpoint{r, parent} - , m_PacketRouter{new vpn::EgresPacketRouter{[](auto, auto) {}}} + , m_PacketRouter{new vpn::EgresPacketRouter{[](auto from, auto pkt) { + var::visit( + [&pkt](auto&& from) { + LogError("unhandled traffic from: ", from, " of ", pkt.sz, " bytes"); + }, + from); + }}} { r->loop()->add_ticker([this] { Pump(Now()); }); } diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index 6e793b915..a1f73b3a9 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -157,6 +157,7 @@ namespace flow.m_FlowInfo = flow_addr; flow.m_FlowTimeout = std::chrono::seconds{flow_timeoutseconds}; flow.m_FlowUserData = flow_userdata; + flow.m_Recv = m_Recv; } void @@ -285,11 +286,8 @@ struct lokinet_context impl->router->loop()->call([ep, &result, udp, exposePort]() { if (auto pkt = ep->EgresPacketRouter()) { - pkt->AddUDPHandler(exposePort, [udp = std::weak_ptr{udp}](auto from, auto pkt) { - if (auto ptr = udp.lock()) - { - ptr->HandlePacketFrom(std::move(from), std::move(pkt)); - } + pkt->AddUDPHandler(exposePort, [udp](auto from, auto pkt) { + udp->HandlePacketFrom(std::move(from), std::move(pkt)); }); result.set_value(true); } @@ -1031,8 +1029,13 @@ extern "C" } std::promise gotten; ctx->impl->router->loop()->call([addr = *maybe, ep, &gotten]() { - ep->EnsurePathTo( + ep->MarkAddressOutbound(addr); + auto res = ep->EnsurePathTo( addr, [&gotten](auto result) { gotten.set_value(result.has_value()); }, 5s); + if (not res) + { + gotten.set_value(false); + } }); if (gotten.get_future().get()) { diff --git a/llarp/vpn/egres_packet_router.cpp b/llarp/vpn/egres_packet_router.cpp index f892f0832..655aaeb49 100644 --- a/llarp/vpn/egres_packet_router.cpp +++ b/llarp/vpn/egres_packet_router.cpp @@ -14,7 +14,7 @@ namespace llarp::vpn void AddSubHandler(nuint16_t localport, EgresPacketHandlerFunc handler) override { - m_LocalPorts.emplace(localport, std::move(handler)); + m_LocalPorts.emplace(std::move(localport), std::move(handler)); } void @@ -26,14 +26,15 @@ namespace llarp::vpn void HandleIPPacketFrom(AddressVariant_t from, net::IPPacket pkt) override { - const uint8_t* ptr = pkt.buf + (pkt.Header()->ihl * 4) + 2; - const nuint16_t dstPort{*reinterpret_cast(ptr)}; - if (auto itr = m_LocalPorts.find(dstPort); itr != m_LocalPorts.end()) + if (auto dstPort = pkt.DstPort()) { - itr->second(std::move(from), std::move(pkt)); + if (auto itr = m_LocalPorts.find(*dstPort); itr != m_LocalPorts.end()) + { + itr->second(std::move(from), std::move(pkt)); + return; + } } - else - m_BaseHandler(std::move(from), std::move(pkt)); + m_BaseHandler(std::move(from), std::move(pkt)); } }; @@ -80,7 +81,7 @@ namespace llarp::vpn { m_IPProtoHandler.emplace(udp_proto, std::make_unique(m_BaseHandler)); } - m_IPProtoHandler[udp_proto]->AddSubHandler(ToNet(localport), func); + m_IPProtoHandler[udp_proto]->AddSubHandler(ToNet(localport), std::move(func)); } void From bf6dfaaef837b353fc65a6d7b13b5d369e43f3d5 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 4 Oct 2021 10:32:26 -0400 Subject: [PATCH 38/43] cmake fixups --- cmake/StaticBuild.cmake | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/cmake/StaticBuild.cmake b/cmake/StaticBuild.cmake index 8344d4315..b266d68ee 100644 --- a/cmake/StaticBuild.cmake +++ b/cmake/StaticBuild.cmake @@ -277,15 +277,10 @@ build_external(expat ) add_static_target(expat expat_external libexpat.a) -if(WIN32) - # fickleness from cross compile and some nodejs dipshittery causes this to be required - set(unbound_extra_opts --disable-gost --disable-ecdsa) -endif() build_external(unbound DEPENDS openssl_external expat_external CONFIGURE_COMMAND ./configure ${cross_host} ${cross_rc} --prefix=${DEPS_DESTDIR} --disable-shared --enable-static --with-libunbound-only --with-pic - ${unbound_extra_opts} --$,enable,disable>-flto --with-ssl=${DEPS_DESTDIR} --with-libexpat=${DEPS_DESTDIR} "CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}" @@ -339,7 +334,10 @@ set_target_properties(libzmq PROPERTIES INTERFACE_LINK_LIBRARIES "${libzmq_link_libs}" INTERFACE_COMPILE_DEFINITIONS "ZMQ_STATIC") -if(WITH_BOOTSTRAP) +if(NOT WITH_BOOTSTRAP) + return() +endif() + set(curl_extra) if(WIN32) set(curl_ssl_opts --without-ssl --with-schannel) @@ -428,4 +426,3 @@ endif() set_target_properties(CURL::libcurl PROPERTIES INTERFACE_LINK_LIBRARIES "${libcurl_link_libs}" INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB") -endif() From f8768488ed8dba10c2aac48d4fed6325b4f5efac Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 4 Oct 2021 10:38:38 -0400 Subject: [PATCH 39/43] make pybind compile --- pybind/llarp/config.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pybind/llarp/config.cpp b/pybind/llarp/config.cpp index c0d15cdfe..42a46f2ac 100644 --- a/pybind/llarp/config.cpp +++ b/pybind/llarp/config.cpp @@ -75,18 +75,18 @@ namespace llarp .def(py::init<>()) .def( "setOutboundLink", - [](LinksConfig& self, std::string interface, int family, uint16_t port) { + [](LinksConfig& self, std::string _interface, int family, uint16_t port) { LinksConfig::LinkInfo info; - info.m_interface = std::move(interface); + info.m_interface = std::move(_interface); info.addressFamily = family; info.port = port; self.m_OutboundLink = std::move(info); }) .def( "addInboundLink", - [](LinksConfig& self, std::string interface, int family, uint16_t port) { + [](LinksConfig& self, std::string _interface, int family, uint16_t port) { LinksConfig::LinkInfo info; - info.m_interface = std::move(interface); + info.minterface = std::move(_interface); info.addressFamily = family; info.port = port; self.m_InboundLinks.push_back(info); From c655a21d68874ae0163ef86d9b308870d692d1f5 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Mon, 4 Oct 2021 10:53:54 -0400 Subject: [PATCH 40/43] typofix --- pybind/llarp/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pybind/llarp/config.cpp b/pybind/llarp/config.cpp index 42a46f2ac..0675f98e5 100644 --- a/pybind/llarp/config.cpp +++ b/pybind/llarp/config.cpp @@ -86,7 +86,7 @@ namespace llarp "addInboundLink", [](LinksConfig& self, std::string _interface, int family, uint16_t port) { LinksConfig::LinkInfo info; - info.minterface = std::move(_interface); + info.m_interface = std::move(_interface); info.addressFamily = family; info.port = port; self.m_InboundLinks.push_back(info); From 635f4bcd8c082b5e86ad59b3540df9fe07390094 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 13 Oct 2021 07:37:25 -0400 Subject: [PATCH 41/43] make it compile --- llarp/lokinet_shared.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index a1f73b3a9..e85df7389 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -31,11 +31,12 @@ namespace {} void - PreLog(std::stringstream&, llarp::LogLevel, const char*, int, const std::string&) const override + PreLog(std::stringstream&, llarp::LogLevel, std::string_view, int, const std::string&) + const override {} void - Print(llarp::LogLevel, const char*, const std::string& msg) override + Print(llarp::LogLevel, std::string_view, const std::string& msg) override { func(msg.c_str(), user); } @@ -1002,7 +1003,7 @@ extern "C" auto lock = ctx->acquire(); if (ctx->impl->router->loop()->inEventLoop()) { - LogError("cannot call udp_establish from internal event loop"); + llarp::LogError("cannot call udp_establish from internal event loop"); return EINVAL; } if (auto itr = ctx->udp_sockets.find(remote->socket_id); itr != ctx->udp_sockets.end()) From 743bc2433ae21be699d152d79846b18f8836fcce Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 13 Oct 2021 08:54:19 -0400 Subject: [PATCH 42/43] resolve race condition in udp flow and packet handling --- llarp/lokinet_shared.cpp | 60 +++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index e85df7389..a900b801e 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -151,7 +151,8 @@ namespace const AddressVariant_t& from, const lokinet_udp_flowinfo& flow_addr, void* flow_userdata, - int flow_timeoutseconds) + int flow_timeoutseconds, + std::optional firstPacket = std::nullopt) { std::unique_lock lock{m_Access}; auto& flow = m_Flows[from]; @@ -159,6 +160,8 @@ namespace flow.m_FlowTimeout = std::chrono::seconds{flow_timeoutseconds}; flow.m_FlowUserData = flow_userdata; flow.m_Recv = m_Recv; + if (firstPacket) + flow.HandlePacket(*firstPacket); } void @@ -180,44 +183,37 @@ namespace void HandlePacketFrom(AddressVariant_t from, llarp::net::IPPacket pkt) { - bool isNewFlow{false}; { std::unique_lock lock{m_Access}; - isNewFlow = m_Flows.count(from) == 0; - } - if (isNewFlow) - { - lokinet_udp_flowinfo flow_addr{}; - // set flow remote address - var::visit( - [&flow_addr](auto&& from) { - const auto addr = from.ToString(); - std::copy_n( - addr.data(), - std::min(addr.size(), sizeof(flow_addr.remote_host)), - flow_addr.remote_host); - }, - from); - // set socket id - flow_addr.socket_id = m_SocketID; - // get source port - if (auto srcport = pkt.SrcPort()) + if (m_Flows.count(from)) { - flow_addr.remote_port = ToHost(*srcport).h; - } - else - return; // invalid data so we bail - void* flow_userdata = nullptr; - int flow_timeoutseconds{}; - // got a new flow, let's check if we want it - if (m_Filter(m_User, &flow_addr, &flow_userdata, &flow_timeoutseconds)) + m_Flows[from].HandlePacket(pkt); return; - AddFlow(from, flow_addr, flow_userdata, flow_timeoutseconds); + } } + lokinet_udp_flowinfo flow_addr{}; + // set flow remote address + std::string addrstr = var::visit([&flow_addr](auto&& from) { return from.ToString(); }, from); + + std::copy_n( + addrstr.data(), + std::min(addrstr.size(), sizeof(flow_addr.remote_host)), + flow_addr.remote_host); + // set socket id + flow_addr.socket_id = m_SocketID; + // get source port + if (const auto srcport = pkt.SrcPort()) { - std::unique_lock lock{m_Access}; - m_Flows[from].HandlePacket(pkt); + flow_addr.remote_port = ToHost(*srcport).h; } + else + return; // invalid data so we bail + void* flow_userdata = nullptr; + int flow_timeoutseconds{}; + // got a new flow, let's check if we want it + if (m_Filter(m_User, &flow_addr, &flow_userdata, &flow_timeoutseconds)) + return; + AddFlow(from, flow_addr, flow_userdata, flow_timeoutseconds, pkt); } }; } // namespace From 04b23416ed1a2aadb0789eeb019b4f6cf372d5d3 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Wed, 13 Oct 2021 08:54:45 -0400 Subject: [PATCH 43/43] do less allocations in lokinet_hex_tobase32z --- llarp/lokinet_shared.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/llarp/lokinet_shared.cpp b/llarp/lokinet_shared.cpp index a900b801e..ac4652729 100644 --- a/llarp/lokinet_shared.cpp +++ b/llarp/lokinet_shared.cpp @@ -822,8 +822,22 @@ extern "C" char* EXPORT lokinet_hex_to_base32z(const char* hex) { - const auto base32z = oxenmq::to_base32z(oxenmq::from_hex(std::string{hex})); - return strdup(base32z.c_str()); + std::string_view hexview{hex}; + if (not oxenmq::is_hex(hexview)) + return nullptr; + + const size_t byte_len = hexview.size() / 2; + const size_t b32z_len = (byte_len * 8 + 4) / 5; // = ⌈N×8÷5⌉ because 5 bits per 32z char + auto buf = std::make_unique(b32z_len + 1); + char* end = buf.get() + b32z_len; + *end = 0; // null terminate + // Write the bytes into the *end* of the buffer so that when we rewrite the final b32z chars + // into the buffer we won't overwrite any byte values until after we've consumed them. + char* bytepos = end - byte_len; + oxenmq::from_hex(hexview.begin(), hexview.end(), bytepos); + // In-place conversion into the buffer + oxenmq::to_base32z(bytepos, end, buf.get()); + return buf.release(); // leak the buffer to the caller } void EXPORT