Merge pull request #67 from majestrate/dev

various fixes to make the network stop spamming itself
pull/68/head
Jeff 6 years ago committed by GitHub
commit 3ef2b5c8ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,76 +1,76 @@
{
"editor.formatOnSave": true,
"files.associations": {
"array": "cpp",
"limits": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"exception": "cpp",
"filesystem": "cpp",
"string_view": "cpp",
"fstream": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"memory": "cpp",
"mutex": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"system_error": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"type_traits": "cpp",
"tuple": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"utility": "cpp",
"__config": "cpp",
"__nullptr": "cpp",
"algorithm": "cpp",
"io": "cpp",
"strstream": "cpp",
"numeric": "cpp",
"valarray": "cpp",
"*.ipp": "cpp",
"csignal": "cpp",
"future": "cpp",
"map": "cpp",
"vector": "cpp",
"new": "cpp",
"shared_mutex": "cpp",
"complex": "cpp",
"variant": "cpp",
"any": "cpp",
"tuntap.h": "c",
"hashtable": "cpp",
"__mutex_base": "cpp",
"iterator": "cpp"
}
"editor.formatOnSave": true,
"files.associations": {
"array": "cpp",
"limits": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"exception": "cpp",
"filesystem": "cpp",
"string_view": "cpp",
"fstream": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"memory": "cpp",
"mutex": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"system_error": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"type_traits": "cpp",
"tuple": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"utility": "cpp",
"__config": "cpp",
"__nullptr": "cpp",
"algorithm": "cpp",
"io": "cpp",
"strstream": "cpp",
"numeric": "cpp",
"valarray": "cpp",
"*.ipp": "cpp",
"csignal": "cpp",
"future": "cpp",
"map": "cpp",
"vector": "cpp",
"new": "cpp",
"shared_mutex": "cpp",
"complex": "cpp",
"variant": "cpp",
"any": "cpp",
"tuntap.h": "c",
"hashtable": "cpp",
"__mutex_base": "cpp",
"iterator": "cpp"
}
}

@ -6,7 +6,7 @@
{
"label": "build",
"type": "shell",
"command": "make -j8 JSONRPC=ON",
"command": "make -j8 JSONRPC=ON test",
"group": "build",
"problemMatcher": [
"$gcc"

@ -6,9 +6,10 @@ project(${PROJECT_NAME} C CXX ASM)
option(USE_LIBABYSS "enable libabyss" )
option(USE_AVX2 "enable avx2 code" )
option(USE_NETNS "enable networking namespace support" )
# Require C++17
set(CMAKE_CXX_STANDARD 17)
# Require C++11
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
@ -21,19 +22,29 @@ add_compile_options(-Wvla)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fpermissive>)
add_compile_options(-Wno-unused-function -Wno-deprecated-declarations -Wno-unknown-pragmas)
# gah, can't recall which -Wno flag is exclusive to clang
# -Wno-cast-function-type is GNU exclusive..i think
if (WOW64_CROSS_COMPILE OR WIN64_CROSS_COMPILE)
# dynamic linking does this all the time
if(CMAKE_HOST_WIN32)
add_compile_options(-Wno-cast-function-type)
endif()
if (USING_CLANG)
add_compile_options(-Wno-unused-command-line-argument -Wno-c++11-narrowing)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-bad-function-cast>)
# because clang is insane enough to inline whole sections of the C++ library!
# May have been fixed in llvm-7.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--allow-multiple-definition --rtlib=libgcc")
endif(USING_CLANG)
endif()
if(WIN32)
add_compile_options($<$<COMPILE_LANGUAGE:C>:-Wno-bad-function-cast>)
add_compile_options(-Wno-cast-function-type)
set(FS_LIB stdc++fs)
endif(WIN32)
if(DEBIAN)
add_definitions(-DDEBIAN)
endif()
@ -44,13 +55,19 @@ find_package(Threads REQUIRED)
if(STATIC_LINK)
add_compile_options(-static)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc -static" )
if(USING_CLANG)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static -Wl,--whole-archive -Wl,--no-whole-archive")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc -static -Wl,--whole-archive -lpthread -Wl,--no-whole-archive" )
endif()
endif()
# This is now configurable in ini
#if(DNS_PORT)
# add_definitions(-DDNS_PORT=${DNS_PORT})
#endif()
if(USE_NETNS)
add_definitions(-DNETNS=1)
else()
add_definitions(-DNETNS=0)
endif()
if(SHADOW)
set(WITH_STATIC OFF)
@ -62,8 +79,10 @@ if(TESTNET)
add_definitions(-DTESTNET=1)
endif()
if(NOT DEBIAN)
set(OPTIMIZE_FLAGS -O3)
set(DEBUG_FLAGS -O0 -g3)
endif()
if(ASAN)
set(DEBUG_FLAGS "${DEBUG_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
@ -93,17 +112,18 @@ if(CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
add_compile_options( ${DEBUG_FLAGS} )
endif()
if(NOT DEBIAN)
if(NOT ANDROID)
if (USE_AVX2)
set(CRYPTO_FLAGS -march=native)
set(CMAKE_ASM_FLAGS "-march=native ${CMAKE_ASM_FLAGS} $ENV{ASFLAGS}")
if (NOT USE_AVX2)
set(CRYPTO_FLAGS -march=core2 -mtune=native)
set(CMAKE_ASM_FLAGS "-march=core2")
else()
if(WIN32)
set(CRYPTO_FLAGS -march=core2)
set(CMAKE_ASM_FLAGS "-march=core2 ${CMAKE_ASM_FLAGS} $ENV{ASFLAGS}")
set(CRYPTO_FLAGS -march=haswell -mtune=native)
set(CMAKE_ASM_FLAGS "-march=haswell -mtune=native ${CMAKE_ASM_FLAGS} $ENV{ASFLAGS}")
endif()
endif()
endif()
if(RPI)
add_definitions(-DRPI)
set(WITH_STATIC ON)
@ -136,18 +156,18 @@ if(JEMALLOC)
set(MALLOC_LIB jemalloc)
endif()
if (WIN32)
set(FS_LIB stdc++fs)
endif(WIN32)
# FS_LIB should resolve to nothing on all other platforms
# it is only required on win32 -rick
set(LIBS Threads::Threads ${MALLOC_LIB} ${FS_LIB})
set(LIBS ${LIBS} ${MALLOC_LIB} ${FS_LIB})
if(ANDROID)
set(LIBS ${LIBS} log)
endif()
if(NOT USING_CLANG)
set(LIBS ${LIBS} Threads::Threads)
endif()
set(LIB lokinet)
set(SHARED_LIB ${LIB})
set(STATIC_LIB ${LIB}-static)
@ -262,9 +282,6 @@ set(LIB_PLATFORM_SRC
${ISOLATE_PROC_SRC}
# tun
${LIBTUNTAP_SRC}
# win32 inline code
llarp/win32_inet.c
llarp/win32_intrnl.c
# c++17 compat code
${CXX_COMPAT_SRC}
)
@ -490,9 +507,11 @@ set(DNS_SRC
set(TEST_SRC
test/main.cpp
test/alignedbuffer_unittest.cpp
test/base32_unittest.cpp
test/dht_unittest.cpp
test/encrypted_frame_unittest.cpp
test/exit_unittest.cpp
test/hiddenservice_unittest.cpp
test/traffic_transfer_unittest.cpp
test/obtain_exit_unittest.cpp

@ -5,7 +5,7 @@ SIGN = gpg --sign --detach
REPO := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
PREFIX ?= /usr/local
prefix = $(DESTDIR)/usr/local
CC ?= cc
CXX ?= c++
@ -49,12 +49,13 @@ JSONRPC ?= OFF
AVX2 ?= ON
RPI ?= OFF
STATIC_LINK ?= OFF
NETNS ?= OFF
CLANG ?= OFF
CMAKE_GEN ?= Unix Makefiles
BUILD_ROOT = $(REPO)/build
CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DSTATIC_LINK=$(STATIC_LINK) -DUSE_AVX2=$(AVX2) -DUSE_LIBABYSS=$(JSONRPC) -DRPI=$(RPI) '$(REPO)'")
CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "cmake -G'$(CMAKE_GEN)' -DUSING_CLANG=$(CLANG) -DSTATIC_LINK=$(STATIC_LINK) -DUSE_NETNS=$(NETNS) -DUSE_AVX2=$(AVX2) -DUSE_LIBABYSS=$(JSONRPC) -DRPI=$(RPI) '$(REPO)'")
SCAN_BUILD ?= scan-build
ANALYZE_CONFIG_CMD = $(shell /bin/echo -n "cd '$(BUILD_ROOT)' && " ; /bin/echo -n "$(SCAN_BUILD) cmake -DUSE_LIBABYSS=$(JSONRPC) '$(REPO)'")
@ -73,6 +74,7 @@ LINT_FILES = $(wildcard llarp/*.cpp)
LINT_CHECK = $(LINT_FILES:.cpp=.cpp-check)
clean:
rm -f $(TARGETS)
rm -rf $(BUILD_ROOT)
rm -f $(SHADOW_PLUGIN) $(SHADOW_CONFIG)
rm -f *.sig
@ -141,7 +143,9 @@ testnet:
python3 contrib/testnet/genconf.py --bin=$(TESTNET_EXE) --svc=$(TESTNET_SERVERS) --clients=$(TESTNET_CLIENTS) --dir=$(TESTNET_ROOT) --out $(TESTNET_CONF) --connect=4
LLARP_DEBUG=$(TESTNET_DEBUG) supervisord -n -d $(TESTNET_ROOT) -l $(TESTNET_LOG) -c $(TESTNET_CONF)
test: debug
$(TEST_EXE): debug
test: $(TEST_EXE)
$(TEST_EXE)
android-gradle-prepare:
@ -192,14 +196,26 @@ docker-debian:
docker-fedora:
docker build -f docker/fedora.Dockerfile .
install:
rm -f $(PREFIX)/bin/lokinet
cp $(EXE) $(PREFIX)/bin/lokinet
chmod 755 $(PREFIX)/bin/lokinet
$(SETCAP) $(PREFIX)/bin/lokinet || true
rm -f $(PREFIX)/bin/lokinet-bootstrap
cp $(REPO)/lokinet-bootstrap $(PREFIX)/bin/lokinet-bootstrap
chmod 755 $(PREFIX)/bin/lokinet-bootstrap
debian-configure:
mkdir -p '$(BUILD_ROOT)'
$(CONFIG_CMD) -DDEBIAN=ON -DRELEASE_MOTTO="$(shell cat $(REPO)/motto.txt)" -DCMAKE_BUILD_TYPE=Release
debian: debian-configure
$(MAKE) -C '$(BUILD_ROOT)'
cp $(EXE) lokinet
cp $(BUILD_ROOT)/rcutil lokinet-rcutil
debian-test:
$(TEST_EXE)
install-bins:
install -T $(EXE) $(prefix)/bin/lokinet
install -T $(REPO)/lokinet-bootstrap $(prefix)/bin/lokinet-bootstrap
install-setcap: install-bins
$(SETCAP) $(prefix)/bin/lokinet || true
install: install-setcap
fuzz-configure: clean
cmake -GNinja -DCMAKE_BUILD_TYPE=Fuzz -DCMAKE_C_COMPILER=afl-gcc -DCMAKE_CXX_COMPILER=afl-g++
@ -209,3 +225,5 @@ fuzz-build: fuzz-configure
fuzz: fuzz-build
$(EXE)
.PHONY: debian-install

@ -15,8 +15,13 @@ def jsonrpc(method, **args):
def main():
if len(sys.argv) == 2 and sys.argv[1] == 'config':
print("graph_title lokinet peers")
print("lokinet.peers.outbound Number of outbound lokinet peers")
print("lokinet.peers.inbound Number of inbound lokinet peers")
print("graph_vlabel peers")
print("graph_category network")
print("graph_info This graph shows the number of node to node sessions of this lokinet router")
print("lokinet.peers.outbound.info Number of outbound lokinet peers")
print("lokinet.peers.inbound.info Number of inbound lokinet peers")
print("lokinet.peers.outbound.label outbound peers")
print("lokinet.peers.inbound.label inbound peers")
else:
inbound = 0
outbound = 0
@ -30,8 +35,8 @@ def main():
except:
pass
print("lokinet.peers.outboud {}".format(outbound))
print("lokinet.peers.inboud {}".format(inbound))
print("lokinet.peers.outbound {}".format(outbound))
print("lokinet.peers.inbound {}".format(inbound))
if __name__ == '__main__':

@ -23,7 +23,12 @@
#include <tmmintrin.h>
#ifndef __amd64__
#ifdef __clang__
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("sse2")))
#else
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __target__("sse2")))
#endif
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtsi64_si128(long long __a)
{

@ -48,7 +48,7 @@ sodium_init(void)
{
return -1; /* LCOV_EXCL_LINE */
}
return 0;
return initialized ? 0 : -1;
}
#ifdef _WIN32

@ -9,7 +9,7 @@
#include "xmm6int/salsa20_xmm6int-sse2.h"
#include "xmm6int/salsa20_xmm6int-avx2.h"
static const crypto_stream_salsa20_implementation *implementation;
static crypto_stream_salsa20_implementation *implementation = NULL;
size_t
crypto_stream_salsa20_keybytes(void)
@ -33,6 +33,7 @@ int
crypto_stream_salsa20(unsigned char *c, unsigned long long clen,
const unsigned char *n, const unsigned char *k)
{
_crypto_stream_salsa20_pick_best_implementation();
return implementation->stream(c, clen, n, k);
}
@ -41,6 +42,7 @@ crypto_stream_salsa20_xor_ic(unsigned char *c, const unsigned char *m,
unsigned long long mlen, const unsigned char *n,
uint64_t ic, const unsigned char *k)
{
_crypto_stream_salsa20_pick_best_implementation();
return implementation->stream_xor_ic(c, m, mlen, n, ic, k);
}
@ -49,6 +51,7 @@ crypto_stream_salsa20_xor(unsigned char *c, const unsigned char *m,
unsigned long long mlen, const unsigned char *n,
const unsigned char *k)
{
_crypto_stream_salsa20_pick_best_implementation();
return implementation->stream_xor_ic(c, m, mlen, n, 0U, k);
}
@ -61,12 +64,8 @@ crypto_stream_salsa20_keygen(unsigned char k[crypto_stream_salsa20_KEYBYTES])
int
_crypto_stream_salsa20_pick_best_implementation(void)
{
#if __AVX2__ && __amd64__
implementation = &crypto_stream_salsa20_xmm6_implementation;
#else
implementation = &crypto_stream_salsa20_ref_implementation;
#endif
if(implementation)
return 0;
#if __AVX2__
if(sodium_runtime_has_avx2())
{
@ -81,5 +80,7 @@ _crypto_stream_salsa20_pick_best_implementation(void)
return 0;
}
#endif
if(implementation == NULL)
implementation = &crypto_stream_salsa20_ref_implementation;
return 0; /* LCOV_EXCL_LINE */
}

@ -8,7 +8,7 @@
#include <sodium/private/sse2_64_32.h>
#include <sodium/utils.h>
#if __AVX2__
#if __AVX2__ && __amd64__
#ifdef __GNUC__
#pragma GCC target("sse2")
@ -23,11 +23,18 @@
#include <tmmintrin.h>
#ifndef __amd64__
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("sse2")))
#ifdef __clang__
#define __DEFAULT_FN_ATTRS \
__attribute__((__always_inline__, __nodebug__, __target__("sse2")))
#else
#define __DEFAULT_FN_ATTRS \
__attribute__((__always_inline__, __target__("sse2")))
#endif
static __inline__ __m128i __DEFAULT_FN_ATTRS
_mm_cvtsi64_si128(long long __a)
{
return (__m128i){ __a, 0 };
return (__m128i){__a, 0};
}
#endif

@ -221,7 +221,12 @@ main(int argc, char *argv[])
struct sockaddr_in m_address;
int m_sockfd;
m_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
#ifndef _WIN32
m_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
#else
m_sockfd =
WSASocket(AF_INET, SOCK_DGRAM, 0, nullptr, 0, WSA_FLAG_OVERLAPPED);
#endif
m_address.sin_family = AF_INET;
m_address.sin_addr.s_addr = INADDR_ANY;
m_address.sin_port = htons(server_port);

@ -489,7 +489,7 @@ main(int argc, char *argv[])
// llarp::LogInfo("Looking for string: ", rcfname);
llarp::PubKey binaryPK;
llarp::HexDecode(rcfname, binaryPK.data());
llarp::HexDecode(rcfname, binaryPK.data(), binaryPK.size());
llarp::LogInfo("Looking for binary: ", binaryPK);
llarp::RouterContact *rc = llarp_main_getDatabase(ctx, binaryPK.data());
@ -510,7 +510,7 @@ main(int argc, char *argv[])
llarp_main_setup(ctx);
llarp::PubKey binaryPK;
llarp::HexDecode(rcfname, binaryPK.data());
llarp::HexDecode(rcfname, binaryPK.data(), binaryPK.size());
llarp::LogInfo("Queueing job");
llarp_router_lookup_job *job = new llarp_router_lookup_job;
@ -581,7 +581,7 @@ main(int argc, char *argv[])
llarp::PubKey binaryPK;
// llarp::service::Address::FromString
llarp::HexDecode(rcfname, binaryPK.data());
llarp::HexDecode(rcfname, binaryPK.data(), binaryPK.size());
char tmp[(1 + 32) * 2] = {0};
std::string b32 = llarp::Base32Encode(binaryPK, tmp);
llarp::LogInfo("to base32 ", b32);

6
debian/rules vendored

@ -19,3 +19,9 @@ endif
override_dh_auto_build:
$(MAKE) debian
override_dh_auto_test:
$(MAKE) debian-test
override_dh_auto_install:
$(MAKE) debian-install

@ -553,8 +553,9 @@ ip address used for exit traffic.
A: "G",
S: uint64_sequence_number,
T: transaction_id_uint64,
Y: "<16 byte nonce>",
V: 0,
Z: "<64 bytes signature using router identity signing key>"
Z: "<64 bytes signature>"
}
any TITM recieved on the same path will be forwarded out to the internet if
@ -573,14 +574,15 @@ was denied.
S: uint64_sequence_number,
T: transaction_id_uint64,
V: 0,
Z: "<64 bytes signature signed by router's signing key>"
Y: "<16 byte nonce>",
Z: "<64 bytes signature>"
}
discarded data fragment message (DDFM)
sent in reply to TDFM when we don't have a path locally or are doing network
congestion control. indcates a TDFM was discarded.
congestion control from a TITM.
{
A: "D",
@ -734,24 +736,25 @@ transfer data on a session previously made
transfer ip traffic message (TITM)
transfer ip traffic for exit
transfer ip traffic
{
A: "I",
S: uint64_sequence_number,
V: 0,
X: "<N bytes ip packet>",
Y: "<16 bytes nonce>",
Z: "<64 bytes signature using previously provided signing key>"
}
X is parsed as an IP packet and the source addresss is extracted.
Next we find the corrisponding signing key for a previously granted exit address
Next we find the corrisponding signing key for a previously granted address
and use it to validate the siganture of the entire message. If the signing key
cannot be found or the signature is invalid this message is dropped, otherwise
the X value is sent on the appropriate exit network interface.
the X value is sent on the appropriate network interface.
When we recieve an ip packet from the internet to an exit address, we put it
into a TITM, signed with the exit info's signing key and send it downstream the
into a TITM, signed with the router's signing key and send it downstream the
corrisponding path in an LRDM.
update exit path message (UXPM)
@ -761,37 +764,42 @@ should use the new path that this message came from.
{
A: "U",
R: "<16 bytes previous rx path id>",
P: "<16 bytes previous tx path id>",
S: uint64_sequence_number,
T: "<16 bytes previous tx path id>",
U: uint64_unique_id,
T: uint64_txid,
V: 0,
Y: "<16 bytes nonce>",
Z: "<64 bytes signature using previously provided signing key>"
}
update exit verify message (EXVM)
close exit path message (CXPM)
sent in reply to a UXPM to verify that the path handover was accepted
client sends a CXPM when the exit is no longer needed or by the exit if the
exit wants to close prematurely.
also sent by exit in reply to a CXPM to confirm close.
{
A: "V",
U: uint64_unique_id,
A: "C",
S: uint64_sequence_number,
V: 0,
Z: "<64 bytes signature from router's signing key>"
Y: "<16 bytes nonce>",
Z: "<64 bytes signature>"
}
close exit path message (CXPM)
update exit verify message (EXVM)
client sends a CXPM when the exit is no longer needed.
sent in reply to a UXPM to verify that the path handover was accepted
{
A: "C",
A: "V",
S: uint64_sequence_number,
T: transaction_id_uint64,
T: uint64_txid,
V: 0,
Z: "<64 bytes signagure using previously provided signing key>"
Y: "<16 bytes nonce>",
Z: "<64 bytes signature>"
}
DHT message holder message:
wrapper message for sending many dht messages down a path.

@ -69,7 +69,7 @@ namespace llarp
bool
operator==(const AlignedBuffer& other) const
{
return memcmp(data(), other.data(), sz) == 0;
return memcmp(b, other.b, sz) == 0;
}
bool
@ -159,35 +159,35 @@ namespace llarp
byte_t*
data()
{
return &b[0];
return b;
}
const byte_t*
data() const
{
return &b[0];
return b;
}
Long_t*
data_l()
{
return &l[0];
return l;
}
const Long_t*
data_l() const
{
return &l[0];
return l;
}
operator const byte_t*() const
{
return &b[0];
return b;
}
operator byte_t*()
{
return &b[0];
return b;
}
bool
@ -221,9 +221,9 @@ namespace llarp
struct Hash
{
size_t
operator()(const AlignedBuffer& buf) const
operator()(const AlignedBuffer< sz, randomize, Long_t >& buf) const
{
return *buf.data_l();
return buf.l[0];
}
};

@ -29,14 +29,23 @@ namespace llarp
}
};
struct GetNowSyscall
{
llarp_time_t
operator()() const
{
return llarp::time_now_ms();
}
};
template < typename T, typename GetTime, typename PutTime, typename Compare,
typename Mutex_t = util::Mutex, typename Lock_t = util::Lock,
llarp_time_t dropMs = 5, llarp_time_t initialIntervalMs = 100,
size_t MaxSize = 1024 >
typename GetNow = GetNowSyscall, typename Mutex_t = util::Mutex,
typename Lock_t = util::Lock, llarp_time_t dropMs = 5,
llarp_time_t initialIntervalMs = 100, size_t MaxSize = 1024 >
struct CoDelQueue
{
CoDelQueue(const std::string& name, const PutTime& put)
: m_name(name), _putTime(put)
CoDelQueue(const std::string& name, const PutTime& put, const GetNow& now)
: m_name(name), _putTime(put), _getNow(now)
{
}
@ -96,11 +105,13 @@ namespace llarp
void
Process(Visit visitor, Filter f)
{
llarp_time_t lowest = 0xFFFFFFFFFFFFFFFFUL;
// auto start = time_now_ms();
llarp_time_t lowest = std::numeric_limits< llarp_time_t >::max();
if(_getNow() < nextTickAt)
return;
// llarp::LogInfo("CoDelQueue::Process - start at ", start);
Lock_t lock(m_QueueMutex);
auto start = firstPut;
if(m_QueueIdx == 1)
{
visitor(m_Queue[0]);
@ -129,7 +140,8 @@ namespace llarp
{
item->~T();
nextTickInterval += initialIntervalMs / std::sqrt(++dropNum);
firstPut = 0;
firstPut = 0;
nextTickAt = start + nextTickInterval;
return;
}
else
@ -141,18 +153,21 @@ namespace llarp
visitor(*item);
item->~T();
}
firstPut = 0;
firstPut = 0;
nextTickAt = start + nextTickInterval;
}
llarp_time_t firstPut = 0;
size_t dropNum = 0;
llarp_time_t nextTickInterval = initialIntervalMs;
llarp_time_t nextTickAt = 0;
Mutex_t m_QueueMutex;
size_t m_QueueIdx = 0;
T m_Queue[MaxSize];
std::string m_name;
GetTime _getTime;
PutTime _putTime;
GetNow _getNow;
}; // namespace util
} // namespace util
} // namespace llarp

@ -133,8 +133,8 @@ namespace llarp
int
char2int(char input);
void
HexDecode(const char* src, uint8_t* target);
bool
HexDecode(const char* src, uint8_t* target, size_t sz);
} // namespace llarp
#endif

@ -3,7 +3,6 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#ifndef ssize_t
#define ssize_t long
#endif

@ -21,9 +21,27 @@ namespace llarp
void
Tick(llarp_time_t now);
void
ClearAllEndpoints();
bool
AddExitEndpoint(const std::string &name, const Config_t &config);
bool
ObtainNewExit(const llarp::PubKey &remote, const llarp::PathID_t &path,
bool permitInternet);
llarp::exit::Endpoint *
FindEndpointForPath(const llarp::PathID_t &path) const;
/// calculate (pk, tx, rx) for all exit traffic
using TrafficStats =
std::unordered_map< PubKey, std::pair< uint64_t, uint64_t >,
PubKey::Hash >;
void
CalculateExitTraffic(TrafficStats &stats);
private:
llarp_router *m_Router;
std::unordered_map< std::string,

@ -19,34 +19,80 @@ namespace llarp
struct Endpoint
{
Endpoint(const llarp::PubKey& remoteIdent,
const llarp::PathID_t& beginPath,
const llarp::PathID_t& beginPath, bool rewriteDst, huint32_t ip,
llarp::handlers::ExitEndpoint* parent);
~Endpoint();
/// close ourselves
void
Close();
/// return true if we are expired right now
bool
IsExpired(llarp_time_t now) const;
bool
ExpiresSoon(llarp_time_t now, llarp_time_t dlt = 5000) const;
/// tick ourself, reset tx/rx rates
void
Tick(llarp_time_t now);
/// handle traffic from service node / internet
bool
SendInboundTraffic(llarp_buffer_t buff);
/// send traffic to service node / internet
/// does ip rewrite
/// does ip rewrite here
bool
SendOutboundTraffic(llarp_buffer_t buf);
void
/// update local path id and cascade information to parent
/// return true if success
bool
UpdateLocalPath(const llarp::PathID_t& nextPath);
llarp::path::IHopHandler*
GetCurrentPath() const;
const llarp::PubKey&
PubKey() const
{
return m_remoteSignKey;
}
const llarp::PathID_t&
LocalPath() const
{
return m_CurrentPath;
}
uint64_t
TxRate() const
{
return m_TxRate;
}
uint64_t
RxRate() const
{
return m_RxRate;
}
huint32_t
LocalIP() const
{
return m_IP;
}
private:
llarp::handlers::ExitEndpoint* m_Parent;
llarp::PubKey m_remoteSignKey;
llarp::PathID_t m_CurrentPath;
llarp::huint32_t m_IP;
uint64_t m_TxRate, m_RxRate;
bool m_RewriteSource;
};
} // namespace exit
} // namespace llarp

@ -1,6 +1,7 @@
#ifndef LLARP_EXIT_SESSION_HPP
#define LLARP_EXIT_SESSION_HPP
#include <llarp/pathbuilder.hpp>
#include <llarp/ip.hpp>
namespace llarp
{
@ -9,27 +10,41 @@ namespace llarp
/// a persisiting exit session with an exit router
struct BaseSession : public llarp::path::Builder
{
BaseSession(const llarp::RouterID& exitRouter, llarp_router* r,
size_t numpaths, size_t hoplen);
BaseSession(const llarp::RouterID& exitRouter,
std::function< bool(llarp_buffer_t) > writepkt,
llarp_router* r, size_t numpaths, size_t hoplen);
~BaseSession();
bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop) override;
size_t hop, llarp::path::PathRole roles) override;
bool
ShouldBuildMore(llarp_time_t now) const override;
void
HandlePathBuilt(llarp::path::Path* p) override;
bool
SendUpstreamTraffic(llarp::net::IPv4Packet pkt);
protected:
llarp::RouterID m_ExitRouter;
};
std::function< bool(llarp_buffer_t) > m_WritePacket;
/// a N-hop exit sesssion form a client
struct ClientSesssion final : public BaseSession
{
};
bool
HandleTrafficDrop(llarp::path::Path* p, const llarp::PathID_t& path,
uint64_t s);
/// a "direct" session between service nodes
struct DirectSession final : public BaseSession
{
bool
HandleGotExit(llarp::path::Path* p, llarp_time_t b);
bool
HandleTraffic(llarp::path::Path* p, llarp_buffer_t buf);
private:
llarp::SecretKey m_ExitIdentity;
};
} // namespace exit

@ -2,7 +2,7 @@
#define LLARP_XI_HPP
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <llarp/net.h>
#include <llarp/net.hpp>
#include <iostream>
#include <llarp/bits.hpp>
@ -21,6 +21,16 @@ namespace llarp
struct in6_addr netmask;
PubKey pubkey;
ExitInfo(const PubKey &pk, const nuint32_t &ipv4_exit) : IBEncodeMessage()
{
pubkey = pk;
memset(address.s6_addr, 0, 16);
address.s6_addr[11] = 0xff;
address.s6_addr[10] = 0xff;
memcpy(address.s6_addr + 12, &ipv4_exit, 4);
memset(netmask.s6_addr, 0xff, 16);
}
ExitInfo() : IBEncodeMessage()
{
}

@ -9,35 +9,134 @@ namespace llarp
{
namespace handlers
{
struct ExitEndpoint final : public TunEndpoint
struct ExitEndpoint
{
ExitEndpoint(const std::string& name, llarp_router* r);
~ExitEndpoint();
void
Tick(llarp_time_t now) override;
Tick(llarp_time_t now);
bool
SetOption(const std::string& k, const std::string& v) override;
SetOption(const std::string& k, const std::string& v);
virtual std::string
Name() const override;
std::string
Name() const;
bool
AllocateNewExit(const llarp::PubKey pk, const llarp::PathID_t& path,
bool permitInternet);
llarp::exit::Endpoint*
FindEndpointByPath(const llarp::PathID_t& path);
llarp::exit::Endpoint*
FindEndpointByIP(huint32_t ip);
bool
UpdateEndpointPath(const llarp::PubKey& remote,
const llarp::PathID_t& next);
/// handle ip packet from outside
void
OnInetPacket(llarp_buffer_t buf);
llarp_router*
Router();
llarp_crypto*
Crypto();
template < typename Stats >
void
CalculateTrafficStats(Stats& stats)
{
auto itr = m_ActiveExits.begin();
while(itr != m_ActiveExits.end())
{
stats[itr->first].first += itr->second->TxRate();
stats[itr->first].second += itr->second->RxRate();
++itr;
}
}
/// DO NOT CALL ME
void
DelEndpointInfo(const llarp::PathID_t& path);
/// DO NOT CALL ME
void
RemoveExit(const llarp::exit::Endpoint* ep);
bool
QueueOutboundTraffic(llarp_buffer_t buf);
/// sets up networking and starts traffic
bool
Start();
bool
HasLocalMappedAddrFor(const llarp::PubKey& pk) const;
huint32_t
GetIfAddr() const;
protected:
void
FlushSend() override;
FlushInbound();
private:
std::string m_Name;
huint32_t
GetIPForIdent(const llarp::PubKey pk);
huint32_t
AllocateNewAddress();
void
MarkIPActive(llarp::huint32_t ip);
void
KickIdentOffExit(const llarp::PubKey& pk);
std::unordered_multimap< llarp::PubKey, llarp::exit::Endpoint,
llarp_router* m_Router;
bool m_ShouldInitTun;
std::string m_Name;
bool m_PermitExit;
std::unordered_map< llarp::PathID_t, llarp::PubKey,
llarp::PathID_t::Hash >
m_Paths;
std::unordered_multimap< llarp::PubKey,
std::unique_ptr< llarp::exit::Endpoint >,
llarp::PubKey::Hash >
m_ActiveExits;
using KeyMap_t = std::unordered_map< llarp::PubKey, llarp::huint32_t,
llarp::PubKey::Hash >;
KeyMap_t m_KeyToIP;
std::unordered_map< llarp::huint32_t, llarp::PubKey,
llarp::huint32_t::Hash >
m_AddrsToPubKey;
m_IPToKey;
huint32_t m_IfAddr;
huint32_t m_HigestAddr;
huint32_t m_NextAddr;
std::unordered_map< llarp::huint32_t, llarp_time_t,
llarp::huint32_t::Hash >
m_IPActivity;
llarp_tun_io m_Tun;
using Pkt_t = llarp::net::IPv4Packet;
using PacketQueue_t =
llarp::util::CoDelQueue< Pkt_t, Pkt_t::GetTime, Pkt_t::PutTime,
Pkt_t::CompareOrder, Pkt_t::GetNow,
llarp::util::DummyMutex,
llarp::util::DummyLock, 5, 100, 1024 >;
/// internet to llarp packet queue
PacketQueue_t m_InetToNetwork;
};
} // namespace handlers
} // namespace llarp

@ -51,6 +51,17 @@ namespace llarp
bool
ProcessDataMessage(service::ProtocolMessage* msg);
/// queue outbound packet to the world
bool
QueueOutboundTraffic(llarp::net::IPv4Packet&& pkt);
/// get the local interface's address
huint32_t
GetIfAddr() const;
bool
HasLocalIP(const huint32_t& ip) const;
#ifndef WIN32
/// overrides Endpoint
bool
@ -80,24 +91,37 @@ namespace llarp
static void
handleTickTun(void* u);
/// get a service address for ip address
service::Address
ObtainAddrForIP(huint32_t ip);
/// get a key for ip address
template < typename Addr >
Addr
ObtainAddrForIP(huint32_t ip)
{
auto itr = m_IPToAddr.find(ip);
if(itr == m_IPToAddr.end())
{
// not found
Addr addr;
addr.Zero();
return addr;
}
// found
return itr->second.data();
}
bool
HasAddress(const service::Address& remote) const
HasAddress(const byte_t* addr) const
{
return m_AddrToIP.find(remote) != m_AddrToIP.end();
return m_AddrToIP.find(addr) != m_AddrToIP.end();
}
/// get ip address for service address unconditionally
/// get ip address for key unconditionally
huint32_t
ObtainIPForAddr(const service::Address& addr);
ObtainIPForAddr(const byte_t* addr);
protected:
typedef llarp::util::CoDelQueue<
net::IPv4Packet, net::IPv4Packet::GetTime, net::IPv4Packet::PutTime,
net::IPv4Packet::CompareOrder >
net::IPv4Packet::CompareOrder, net::IPv4Packet::GetNow >
PacketQueue_t;
/// queue for sending packets over the network from us
PacketQueue_t m_UserToNetworkPktQueue;
@ -119,7 +143,27 @@ namespace llarp
virtual void
FlushSend();
/// maps ip to key (host byte order)
std::unordered_map< huint32_t, AlignedBuffer< 32 >, huint32_t::Hash >
m_IPToAddr;
/// maps key to ip (host byte order)
std::unordered_map< AlignedBuffer< 32 >, huint32_t,
AlignedBuffer< 32 >::Hash >
m_AddrToIP;
private:
bool
QueueInboundPacketForExit(llarp_buffer_t buf)
{
return m_NetworkToUserPktQueue.EmplaceIf(
[&](llarp::net::IPv4Packet& pkt) -> bool {
if(!pkt.Load(buf))
return false;
pkt.UpdateIPv4PacketOnDst(pkt.src(), m_OurIP);
return true;
});
}
#ifndef WIN32
/// handles setup, given value true on success and false on failure to set
/// up interface
@ -131,12 +175,6 @@ namespace llarp
/// for netns)
struct dotLokiLookup dll;
/// maps ip to service address (host byte order)
std::unordered_map< huint32_t, service::Address, huint32_t::Hash >
m_IPToAddr;
/// maps service address to ip (host byte order)
std::unordered_map< service::Address, huint32_t, service::Address::Hash >
m_AddrToIP;
/// maps ip address to timestamp last active
std::unordered_map< huint32_t, llarp_time_t, huint32_t::Hash >
m_IPActivity;

@ -113,6 +113,19 @@ namespace llarp
}
};
struct GetNow
{
llarp_ev_loop* loop;
GetNow(llarp_ev_loop* evloop) : loop(evloop)
{
}
llarp_time_t
operator()() const
{
return llarp_ev_loop_time_now_ms(loop);
}
};
struct CompareOrder
{
bool

@ -49,6 +49,10 @@ namespace llarp
struct GrantExitMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
uint64_t T;
Nonce_t Y;
llarp::Signature Z;
GrantExitMessage() : IMessage()
{
}
@ -57,9 +61,18 @@ namespace llarp
{
}
GrantExitMessage&
operator=(const GrantExitMessage& other);
bool
BEncode(llarp_buffer_t* buf) const override;
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf) override;
@ -69,6 +82,13 @@ namespace llarp
struct RejectExitMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
uint64_t B;
std::vector< llarp::exit::Policy > R;
uint64_t T;
Nonce_t Y;
llarp::Signature Z;
RejectExitMessage() : IMessage()
{
}
@ -77,6 +97,49 @@ namespace llarp
{
}
RejectExitMessage&
operator=(const RejectExitMessage& other);
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
bool
BEncode(llarp_buffer_t* buf) const override;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf) override;
bool
HandleMessage(IMessageHandler* h, llarp_router* r) const override;
};
struct UpdateExitVerifyMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
uint64_t T;
Nonce_t Y;
llarp::Signature Z;
UpdateExitVerifyMessage() : IMessage()
{
}
~UpdateExitVerifyMessage()
{
}
UpdateExitVerifyMessage&
operator=(const UpdateExitVerifyMessage& other);
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
bool
BEncode(llarp_buffer_t* buf) const override;
@ -89,6 +152,12 @@ namespace llarp
struct UpdateExitMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
llarp::PathID_t P;
uint64_t T;
Nonce_t Y;
llarp::Signature Z;
UpdateExitMessage() : IMessage()
{
}
@ -97,6 +166,15 @@ namespace llarp
{
}
UpdateExitMessage&
operator=(const UpdateExitMessage& other);
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
bool
BEncode(llarp_buffer_t* buf) const override;
@ -109,6 +187,11 @@ namespace llarp
struct CloseExitMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
Nonce_t Y;
llarp::Signature Z;
CloseExitMessage() : IMessage()
{
}
@ -117,6 +200,9 @@ namespace llarp
{
}
CloseExitMessage&
operator=(const CloseExitMessage& other);
bool
BEncode(llarp_buffer_t* buf) const override;
@ -125,6 +211,12 @@ namespace llarp
bool
HandleMessage(IMessageHandler* h, llarp_router* r) const override;
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
};
} // namespace routing

@ -11,7 +11,10 @@ namespace llarp
constexpr size_t MaxExitMTU = 1500;
struct TransferTrafficMessage final : public IMessage
{
using Nonce_t = AlignedBuffer< 16 >;
std::vector< byte_t > X;
Nonce_t Y;
llarp::Signature Z;
TransferTrafficMessage&

@ -3,21 +3,6 @@
#if defined(_WIN32) || defined(__MINGW32__)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
// because this shit is not defined for Windows NT reeeee
#ifdef __cplusplus
extern "C"
{
#endif
#if _WIN32_WINNT < 0x600
const char*
inet_ntop(int af, const void* src, char* dst, size_t size);
int
inet_pton(int af, const char* src, void* dst);
#endif
#ifdef __cplusplus
}
#endif
typedef unsigned short in_port_t;
typedef unsigned int in_addr_t;
#else

@ -19,7 +19,6 @@
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif

@ -144,6 +144,10 @@ struct llarp_async_load_rc
void
llarp_nodedb_async_load_rc(struct llarp_async_load_rc *job);
bool
llarp_nodedb_select_random_exit(struct llarp_nodedb *n,
llarp::RouterContact &rc);
bool
llarp_nodedb_select_random_hop(struct llarp_nodedb *n,
const llarp::RouterContact &prev,

@ -104,6 +104,9 @@ namespace llarp
virtual bool
Expired(llarp_time_t now) const = 0;
virtual bool
ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const = 0;
/// send routing message and increment sequence number
virtual bool
SendRoutingMessage(const llarp::routing::IMessage* msg,
@ -162,11 +165,18 @@ namespace llarp
}
bool
Expired(llarp_time_t now) const;
Expired(llarp_time_t now) const override;
bool
ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const override
{
return now >= ExpireTime() - dlt;
}
// send routing message when end of path
bool
SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r);
SendRoutingMessage(const llarp::routing::IMessage* msg,
llarp_router* r) override;
// handle routing message when end of path
bool
@ -175,44 +185,50 @@ namespace llarp
bool
HandleDataDiscardMessage(const llarp::routing::DataDiscardMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandlePathConfirmMessage(const llarp::routing::PathConfirmMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandlePathTransferMessage(const llarp::routing::PathTransferMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandlePathLatencyMessage(const llarp::routing::PathLatencyMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleObtainExitMessage(const llarp::routing::ObtainExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleUpdateExitVerifyMessage(
const llarp::routing::UpdateExitVerifyMessage* msg,
llarp_router* r) override;
bool
HandleTransferTrafficMessage(
const llarp::routing::TransferTrafficMessage* msg, llarp_router* r);
const llarp::routing::TransferTrafficMessage* msg,
llarp_router* r) override;
bool
HandleUpdateExitMessage(const llarp::routing::UpdateExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleGrantExitMessage(const llarp::routing::GrantExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleRejectExitMessage(const llarp::routing::RejectExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleCloseExitMessage(const llarp::routing::CloseExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleHiddenServiceFrame(__attribute__((unused))
const llarp::service::ProtocolFrame* frame)
HandleHiddenServiceFrame(__attribute__((
unused)) const llarp::service::ProtocolFrame* frame) override
{
/// TODO: implement me
llarp::LogWarn("Got hidden service data on transit hop");
@ -223,15 +239,18 @@ namespace llarp
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
bool
HandleDHTMessage(const llarp::dht::IMessage* msg, llarp_router* r);
HandleDHTMessage(const llarp::dht::IMessage* msg,
llarp_router* r) override;
// handle data in upstream direction
bool
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y,
llarp_router* r) override;
// handle data in downstream direction
bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y,
llarp_router* r) override;
};
/// configuration for a single hop when building a path
@ -268,6 +287,12 @@ namespace llarp
typedef std::vector< PathHopConfig > HopList;
typedef std::function< bool(Path*, const service::ProtocolFrame*) >
DataHandlerFunc;
typedef std::function< bool(Path*) > ExitUpdatedFunc;
typedef std::function< bool(Path*) > ExitClosedFunc;
typedef std::function< bool(Path*, llarp_buffer_t) >
ExitTrafficHandlerFunc;
/// (path, backoff) backoff is 0 on success
typedef std::function< bool(Path*, llarp_time_t) > ObtainedExitHandler;
HopList hops;
@ -276,13 +301,55 @@ namespace llarp
llarp::service::Introduction intro;
llarp_time_t buildStarted;
PathStatus _status;
Path(const std::vector< RouterContact >& routers, PathSet* parent);
Path(const std::vector< RouterContact >& routers, PathSet* parent,
PathRole startingRoles);
PathRole
Role() const
{
return _role;
}
void
MarkActive(llarp_time_t now)
{
m_LastRecvMessage = now;
}
bool
SupportsRoles(PathRole roles) const
{
return (_role & roles) == roles;
}
PathStatus
Status() const
{
return _status;
}
void
SetBuildResultHook(BuildResultHookFunc func);
void
SetExitTrafficHandler(ExitTrafficHandlerFunc handler)
{
m_ExitTrafficHandler = handler;
}
void
SetCloseExitFunc(ExitClosedFunc handler)
{
m_ExitClosed = handler;
}
void
SetUpdateExitFunc(ExitUpdatedFunc handler)
{
m_ExitUpdated = handler;
}
void
SetDataHandler(DataHandlerFunc func)
{
@ -311,75 +378,88 @@ namespace llarp
}
bool
Expired(llarp_time_t now) const;
ExpiresSoon(llarp_time_t now, llarp_time_t dlt = 5000) const override
{
return now >= (ExpireTime() - dlt);
}
bool
Expired(llarp_time_t now) const override;
void
Tick(llarp_time_t now, llarp_router* r);
bool
SendRoutingMessage(const llarp::routing::IMessage* msg, llarp_router* r);
SendRoutingMessage(const llarp::routing::IMessage* msg,
llarp_router* r) override;
bool
HandleObtainExitMessage(const llarp::routing::ObtainExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleUpdateExitVerifyMessage(
const llarp::routing::UpdateExitVerifyMessage* msg,
llarp_router* r) override;
bool
HandleTransferTrafficMessage(
const llarp::routing::TransferTrafficMessage* msg, llarp_router* r);
const llarp::routing::TransferTrafficMessage* msg,
llarp_router* r) override;
bool
HandleUpdateExitMessage(const llarp::routing::UpdateExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleCloseExitMessage(const llarp::routing::CloseExitMessage* msg,
llarp_router* r);
bool
HandleRejectExitMessagge(const llarp::routing::RejectExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleGrantExitMessage(const llarp::routing::GrantExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleRejectExitMessage(const llarp::routing::RejectExitMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleDataDiscardMessage(const llarp::routing::DataDiscardMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandlePathConfirmMessage(const llarp::routing::PathConfirmMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandlePathLatencyMessage(const llarp::routing::PathLatencyMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandlePathTransferMessage(const llarp::routing::PathTransferMessage* msg,
llarp_router* r);
llarp_router* r) override;
bool
HandleHiddenServiceFrame(const llarp::service::ProtocolFrame* frame);
HandleHiddenServiceFrame(
const llarp::service::ProtocolFrame* frame) override;
bool
HandleGotIntroMessage(const llarp::dht::GotIntroMessage* msg);
bool
HandleDHTMessage(const llarp::dht::IMessage* msg, llarp_router* r);
HandleDHTMessage(const llarp::dht::IMessage* msg,
llarp_router* r) override;
bool
HandleRoutingMessage(llarp_buffer_t buf, llarp_router* r);
// handle data in upstream direction
bool
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
HandleUpstream(llarp_buffer_t X, const TunnelNonce& Y,
llarp_router* r) override;
// handle data in downstream direction
bool
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y, llarp_router* r);
HandleDownstream(llarp_buffer_t X, const TunnelNonce& Y,
llarp_router* r) override;
bool
IsReady() const;
@ -404,17 +484,40 @@ namespace llarp
std::string
Name() const;
void
AddObtainExitHandler(ObtainedExitHandler handler)
{
m_ObtainedExitHooks.push_back(handler);
}
bool
SendExitRequest(const llarp::routing::ObtainExitMessage* msg,
llarp_router* r);
protected:
llarp::routing::InboundMessageParser m_InboundMessageParser;
private:
/// call obtained exit hooks
bool
InformExitResult(llarp_time_t b);
BuildResultHookFunc m_BuiltHook;
DataHandlerFunc m_DataHandler;
DropHandlerFunc m_DropHandler;
CheckForDeadFunc m_CheckForDead;
ExitUpdatedFunc m_ExitUpdated;
ExitClosedFunc m_ExitClosed;
ExitTrafficHandlerFunc m_ExitTrafficHandler;
std::vector< ObtainedExitHandler > m_ObtainedExitHooks;
llarp_time_t m_LastRecvMessage = 0;
llarp_time_t m_LastLatencyTestTime = 0;
uint64_t m_LastLatencyTestID = 0;
uint64_t m_UpdateExitTX = 0;
uint64_t m_CloseExitTX = 0;
uint64_t m_ExitObtainTX = 0;
PathStatus _status;
PathRole _role;
};
enum PathBuildStatus

@ -26,7 +26,7 @@ namespace llarp
virtual bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop);
size_t hop, PathRole roles);
virtual bool
ShouldBuildMore(llarp_time_t now) const;
@ -35,16 +35,18 @@ namespace llarp
Now() const;
void
BuildOne();
BuildOne(PathRole roles = ePathRoleAny);
void
Build(const std::vector< RouterContact >& hops);
Build(const std::vector< RouterContact >& hops,
PathRole roles = ePathRoleAny);
bool
SelectHops(llarp_nodedb* db, std::vector< RouterContact >& hops);
SelectHops(llarp_nodedb* db, std::vector< RouterContact >& hops,
PathRole roles = ePathRoleAny);
void
ManualRebuild(size_t N);
ManualRebuild(size_t N, PathRole roles = ePathRoleAny);
virtual const byte_t*
GetTunnelEncryptionSecretKey() const;

@ -21,6 +21,7 @@ namespace llarp
namespace path
{
/// status of a path
enum PathStatus
{
ePathBuilding,
@ -28,6 +29,21 @@ namespace llarp
ePathTimeout,
ePathExpired
};
/// the role of this path can fuffill
using PathRole = int;
/// capable of any role
constexpr PathRole ePathRoleAny = 0;
/// outbound hs traffic capabale
constexpr PathRole ePathRoleOutboundHS = (1 << 0);
/// inbound hs traffic capable
constexpr PathRole ePathRoleInboundHS = (1 << 1);
/// exit traffic capable
constexpr PathRole ePathRoleExit = (1 << 2);
/// dht message capable
constexpr PathRole ePathRoleDHT = (1 << 3);
// forward declare
struct Path;
@ -63,9 +79,14 @@ namespace llarp
void
ExpirePaths(llarp_time_t now);
/// get the number of paths in this status
size_t
NumInStatus(PathStatus st) const;
/// get the number of paths that match the role that are available
size_t
AvailablePaths(PathRole role) const;
/// get time from event loop
virtual llarp_time_t
Now() const = 0;
@ -74,6 +95,14 @@ namespace llarp
virtual bool
ShouldBuildMore(llarp_time_t now) const;
/// return true if we need another path with the given path roles
virtual bool
ShouldBuildMoreForRoles(llarp_time_t now, PathRole roles) const;
/// return the minimum number of paths we want for given roles
virtual size_t
MinRequiredForRoles(PathRole roles) const;
/// return true if we should publish a new hidden service descriptor
virtual bool
ShouldPublishDescriptors(__attribute__((unused)) llarp_time_t now) const
@ -104,16 +133,19 @@ namespace llarp
}
Path*
GetEstablishedPathClosestTo(const RouterID& router) const;
GetEstablishedPathClosestTo(const RouterID& router,
PathRole roles = ePathRoleAny) const;
Path*
PickRandomEstablishedPath() const;
PickRandomEstablishedPath(PathRole roles = ePathRoleAny) const;
Path*
GetPathByRouter(const RouterID& router) const;
GetPathByRouter(const RouterID& router,
PathRole roles = ePathRoleAny) const;
Path*
GetNewestPathByRouter(const RouterID& router) const;
GetNewestPathByRouter(const RouterID& router,
PathRole roles = ePathRoleAny) const;
Path*
GetPathByID(const PathID_t& id) const;
@ -136,7 +168,7 @@ namespace llarp
virtual bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop) = 0;
size_t hop, PathRole roles) = 0;
protected:
size_t m_NumPaths;

@ -53,6 +53,12 @@ namespace llarp
void
Clear();
bool
IsExit() const
{
return exits.size() > 0;
}
bool
BDecode(llarp_buffer_t *buf) override
{

@ -39,6 +39,10 @@ namespace llarp
HandleUpdateExitMessage(const UpdateExitMessage *msg,
llarp_router *r) = 0;
virtual bool
HandleUpdateExitVerifyMessage(const UpdateExitVerifyMessage *msg,
llarp_router *r) = 0;
virtual bool
HandleCloseExitMessage(const CloseExitMessage *msg, llarp_router *r) = 0;

@ -40,10 +40,10 @@ namespace llarp
bool
Start(const std::string& remote);
/// async test if a router is valid via jsonrpc
/// test if a router is valid
void
AsyncVerifyRouter(llarp::PubKey pkey,
std::function< void(llarp::PubKey, bool) > handler);
VerifyRouter(llarp::PubKey pkey,
std::function< void(llarp::PubKey, bool) > handler);
private:
CallerImpl* m_Impl;

@ -22,6 +22,11 @@ namespace llarp
Zero();
}
Address(const byte_t* buf)
{
memcpy(b, buf, 32);
}
Address(const Address& other)
{
memcpy(b, other.b, 32);

@ -7,6 +7,8 @@
#include <llarp/service/protocol.hpp>
#include <llarp/path.hpp>
#include <llarp/ev.h>
#include <llarp/net.hpp>
#include <llarp/exit/session.hpp>
// minimum time between interoset shifts
#ifndef MIN_SHIFT_INTERVAL
@ -108,15 +110,16 @@ namespace llarp
HasPathToService(const Address& remote) const;
virtual huint32_t
ObtainIPForAddr(__attribute__((unused))
const llarp::service::Address& remote)
ObtainIPForAddr(const byte_t * addr)
{
(void) addr;
return {0};
}
virtual bool
HasAddress(__attribute__((unused)) const Address& remote) const
HasAddress(const byte_t* addr) const
{
(void)addr;
return false;
}
@ -159,8 +162,7 @@ namespace llarp
HandlePathBuilt(path::Path* path);
bool
SendToOrQueue(const Address& remote, llarp_buffer_t payload,
ProtocolType t);
SendToOrQueue(const byte_t* addr, llarp_buffer_t payload, ProtocolType t);
struct PendingBuffer
{
@ -253,18 +255,18 @@ namespace llarp
/// update the current selected intro to be a new best introduction
/// return true if we have changed intros
bool
ShiftIntroduction();
ShiftIntroduction() override;
/// mark the current remote intro as bad
bool
MarkCurrentIntroBad(llarp_time_t now);
MarkCurrentIntroBad(llarp_time_t now) override;
/// return true if we are ready to send
bool
ReadyToSend() const;
bool
ShouldBuildMore(llarp_time_t now) const;
ShouldBuildMore(llarp_time_t now) const override;
/// tick internal state
/// return true to mark as dead
@ -279,21 +281,22 @@ namespace llarp
CheckPathIsDead(path::Path* p, llarp_time_t dlt);
void
AsyncGenIntro(llarp_buffer_t payload, ProtocolType t);
AsyncGenIntro(llarp_buffer_t payload, ProtocolType t) override;
/// issues a lookup to find the current intro set of the remote service
void
UpdateIntroSet(bool randomizePath);
UpdateIntroSet(bool randomizePath) override;
bool
BuildOneAlignedTo(const RouterID& remote);
void
HandlePathBuilt(path::Path* path);
HandlePathBuilt(path::Path* path) override;
bool
SelectHop(llarp_nodedb* db, const RouterContact& prev,
RouterContact& cur, size_t hop);
RouterContact& cur, size_t hop,
llarp::path::PathRole roles) override;
bool
HandleHiddenServiceFrame(path::Path* p, const ProtocolFrame* frame);
@ -331,14 +334,6 @@ namespace llarp
EnsurePathToService(const Address& remote, PathEnsureHook h,
uint64_t timeoutMS, bool lookupOnRandomPath = false);
virtual bool
HandleAuthenticatedDataFrom(__attribute__((unused)) const Address& remote,
__attribute__((unused)) llarp_buffer_t data)
{
/// TODO: imlement me
return true;
}
void
PutSenderFor(const ConvoTag& tag, const ServiceInfo& info);
@ -423,6 +418,7 @@ namespace llarp
protected:
IDataHandler* m_DataHandler = nullptr;
Identity m_Identity;
std::unique_ptr< llarp::exit::BaseSession > m_Exit;
private:
llarp_router* m_Router;

@ -48,6 +48,8 @@ llarp_threadpool_tick(struct llarp_threadpool *tp);
void
llarp_threadpool_queue_job(struct llarp_threadpool *tp,
struct llarp_thread_job j);
void
llarp_threadpool_start(struct llarp_threadpool *tp);
void
llarp_threadpool_stop(struct llarp_threadpool *tp);

File diff suppressed because it is too large Load Diff

@ -25,23 +25,8 @@
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#include "libutp_inet_ntop.h"
// we already have our own definition of these
// -despair
#ifndef inet_ntop
namespace
{
extern "C"
{
const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
int
inet_pton(int af, const char *src, void *dst);
}
} // namespace
#endif
//######################################################################
const char *
libutp::inet_ntop(int af, const void *src, char *dest, size_t length)

@ -679,6 +679,8 @@ namespace llarp
Key_t t(target.data());
std::set< Key_t > found;
// TODO: also load from nodedb
if(!nodes)
return false;
size_t nodeCount = nodes->Size();
if(nodeCount == 0)
{

@ -255,7 +255,8 @@ ReverseHandlerIter(struct llarp::service::Context::endpoint_iter *endpointCfg)
if(inRange)
{
llarp::service::Address addr =
tunEndpoint->ObtainAddrForIP(searchIPv4_fixed);
tunEndpoint->ObtainAddrForIP< llarp::service::Address >(
searchIPv4_fixed);
if(addr.IsZero())
{
write404_dnss_response(context->from,

@ -299,7 +299,7 @@ generic_handle_dnsc_recvfrom(dnsc_answer_request *request,
llarp::LogDebug("Read an authority for ",
request->question.name, " at ", std::to_string(pos));
// castBuf += answer->name.length() + 4 + 4 + 4 + answer->rdLen;
if(pos > sz)
if((ssize_t)pos > sz)
{
llarp::LogWarn("Would read past end of dns packet. for ",
request->question.name);
@ -603,7 +603,7 @@ llarp_handle_dnsc_recvfrom(struct llarp_udp_io *const udp,
llarp::LogDebug("Header got client responses for id: ", hdr->id);
// if we sent this out, then there's an id
struct dns_tracker *tracker = (struct dns_tracker *)udp->user;
struct dns_tracker *tracker = (struct dns_tracker *)udp->user;
struct dnsc_answer_request *request = tracker->client_request[hdr->id].get();
// sometimes we'll get double responses
@ -694,7 +694,7 @@ void
llarp_host_resolved(dnsc_answer_request *const request)
{
dns_tracker *tracker = (dns_tracker *)request->context->tracker;
auto val = std::find_if(
auto val = std::find_if(
tracker->client_request.begin(), tracker->client_request.end(),
[request](
std::pair< const uint32_t, std::unique_ptr< dnsc_answer_request > >
@ -735,7 +735,7 @@ llarp_dnsc_init(struct dnsc_context *const dnsc,
llarp::LogInfo("DNSc adding relay ", dnsc_sockaddr);
dnsc->resolvers.push_back(dnsc_sockaddr);
dnsc->tracker = &dns_udp_tracker;
dnsc->logic = logic;
dnsc->logic = logic;
return true;
}

@ -15,13 +15,15 @@ namespace llarp
return 0;
}
void
HexDecode(const char* src, uint8_t* target)
bool
HexDecode(const char* src, uint8_t* target, size_t sz)
{
while(*src && src[1])
while(*src && src[1] && sz)
{
*(target++) = char2int(*src) * 16 + char2int(src[1]);
src += 2;
--sz;
}
return sz == 0;
}
} // namespace llarp

@ -95,7 +95,9 @@ llarp_ev_close_udp(struct llarp_udp_io *udp)
llarp_time_t
llarp_ev_loop_time_now_ms(struct llarp_ev_loop *loop)
{
return loop->_now;
if(loop)
return loop->_now;
return llarp::time_now_ms();
}
void

@ -141,20 +141,13 @@ namespace llarp
virtual ssize_t
do_write(void* data, size_t sz)
{
DWORD w;
// DWORD w;
if(std::holds_alternative< HANDLE >(fd))
{
WriteFile(std::get< HANDLE >(fd), data, sz, nullptr, &portfd[1]);
GetOverlappedResult(std::get< HANDLE >(fd), &portfd[1], &w, TRUE);
}
else
{
WriteFile((HANDLE)std::get< SOCKET >(fd), data, sz, nullptr,
&portfd[1]);
GetOverlappedResult((HANDLE)std::get< SOCKET >(fd), &portfd[1], &w,
TRUE);
}
return w;
return sz;
}
bool
@ -246,6 +239,7 @@ namespace llarp
}
/// reset errno
errno = 0;
SetLastError(0);
}
std::unique_ptr< LossyWriteQueue_t > m_LossyWriteQueue;
@ -288,6 +282,20 @@ namespace llarp
}
};
struct GetNow
{
llarp_ev_loop* loop;
GetNow(llarp_ev_loop* l) : loop(l)
{
}
llarp_time_t
operator()() const
{
return llarp_ev_loop_time_now_ms(loop);
}
};
struct PutTime
{
llarp_ev_loop* loop;
@ -311,10 +319,10 @@ namespace llarp
};
};
typedef llarp::util::CoDelQueue< WriteBuffer, WriteBuffer::GetTime,
WriteBuffer::PutTime, WriteBuffer::Compare,
llarp::util::NullMutex,
llarp::util::NullLock, 5, 100, 128 >
typedef llarp::util::CoDelQueue<
WriteBuffer, WriteBuffer::GetTime, WriteBuffer::PutTime,
WriteBuffer::Compare, WriteBuffer::GetNow, llarp::util::NullMutex,
llarp::util::NullLock, 5, 100, 1024 >
LossyWriteQueue_t;
typedef std::deque< WriteBuffer > LosslessWriteQueue_t;

@ -177,7 +177,7 @@ namespace llarp
llarp_tun_io* t;
device* tunif;
tun(llarp_tun_io* tio, llarp_ev_loop* l)
: ev_io(-1, new LossyWriteQueue_t("tun_write_queue", l))
: ev_io(-1, new LossyWriteQueue_t("tun_write_queue", l, l))
, t(tio)
, tunif(tuntap_init())

@ -8,6 +8,10 @@
#include "ev.hpp"
#include "logger.hpp"
#ifdef sizeof
#undef sizeof
#endif
// TODO: convert all socket errno calls to WSAGetLastError(3),
// don't think winsock sets regular errno to this day
namespace llarp
@ -62,7 +66,7 @@ namespace llarp
{
socklen_t slen = sizeof(sockaddr_in);
if(_addr.ss_family == AF_UNIX)
slen = sizeof(sockaddr_un);
slen = 115;
else if(_addr.ss_family == AF_INET6)
slen = sizeof(sockaddr_in6);
int result =
@ -132,13 +136,14 @@ namespace llarp
virtual int
read(void* buf, size_t sz)
{
printf("read\n");
sockaddr_in6 src;
socklen_t slen = sizeof(src);
sockaddr* addr = (sockaddr*)&src;
unsigned long flags = 0;
WSABUF wbuf = {(u_long)sz, static_cast< char* >(buf)};
// WSARecvFrom
llarp::LogDebug("read ", sz, " bytes into socket");
llarp::LogDebug("read ", sz, " bytes from socket");
int ret = ::WSARecvFrom(std::get< SOCKET >(fd), &wbuf, 1, nullptr, &flags,
addr, &slen, &portfd[0], nullptr);
// 997 is the error code for queued ops
@ -155,6 +160,7 @@ namespace llarp
virtual int
sendto(const sockaddr* to, const void* data, size_t sz)
{
printf("sendto\n");
socklen_t slen;
WSABUF wbuf = {(u_long)sz, (char*)data};
switch(to->sa_family)
@ -242,7 +248,6 @@ namespace llarp
setup()
{
llarp::LogDebug("set ifname to ", t->ifname);
strncpy(tunif->if_name, t->ifname, IFNAMSIZ);
if(tuntap_start(tunif, TUNTAP_MODE_TUNNEL, 0) == -1)
{
@ -289,16 +294,10 @@ struct llarp_win32_loop : public llarp_ev_loop
tcp_connect(struct llarp_tcp_connecter* tcp, const sockaddr* remoteaddr)
{
// create socket
DWORD on = 1;
SOCKET fd = ::socket(remoteaddr->sa_family, SOCK_STREAM, 0);
SOCKET fd = WSASocket(remoteaddr->sa_family, SOCK_STREAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
return false;
// set non blocking
if(ioctlsocket(fd, FIONBIO, &on) == SOCKET_ERROR)
{
::closesocket(fd);
return false;
}
llarp::tcp_conn* conn = new llarp::tcp_conn(this, fd, remoteaddr, tcp);
add_ev(conn, true);
conn->connect();
@ -315,8 +314,8 @@ struct llarp_win32_loop : public llarp_ev_loop
llarp::ev_io*
bind_tcp(llarp_tcp_acceptor* tcp, const sockaddr* bindaddr)
{
DWORD on = 1;
SOCKET fd = ::socket(bindaddr->sa_family, SOCK_STREAM, 0);
SOCKET fd = WSASocket(bindaddr->sa_family, SOCK_STREAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
return nullptr;
socklen_t sz = sizeof(sockaddr_in);
@ -345,7 +344,6 @@ struct llarp_win32_loop : public llarp_ev_loop
llarp::ev_io* serv = new llarp::tcp_serv(this, fd, tcp);
tcp->impl = serv;
ioctlsocket(fd, FIONBIO, &on);
return serv;
}
@ -366,27 +364,31 @@ struct llarp_win32_loop : public llarp_ev_loop
tick(int ms)
{
OVERLAPPED_ENTRY events[1024];
ULONG numEvents = 0;
if(::GetQueuedCompletionStatusEx(iocpfd, events, 1024, &numEvents, ms,
false))
{
for(ULONG idx = 0; idx < numEvents; ++idx)
memset(&events, 0, sizeof(OVERLAPPED_ENTRY) * 1024);
ULONG result = 0;
::GetQueuedCompletionStatusEx(iocpfd, events, 1024, &result, ms, false);
ULONG idx = 0;
while(idx < result)
{
llarp::ev_io* ev =
reinterpret_cast< llarp::ev_io* >(events[idx].lpCompletionKey);
if(ev && events[idx].lpOverlapped)
{
llarp::ev_io* ev =
reinterpret_cast< llarp::ev_io* >(events[idx].lpCompletionKey);
if(ev)
auto amount =
std::min(EV_READ_BUF_SZ, events[idx].dwNumberOfBytesTransferred);
if(ev->write)
ev->flush_write_buffers(amount);
else
{
if(ev->write)
ev->flush_write();
auto amount =
std::min(EV_READ_BUF_SZ, events[idx].dwNumberOfBytesTransferred);
memcpy(readbuf, events[idx].lpOverlapped->Pointer, amount);
ev->read(readbuf, amount);
}
}
++idx;
}
tick_listeners();
return 0;
return result;
}
// ok apparently this isn't being used yet...
@ -444,8 +446,8 @@ struct llarp_win32_loop : public llarp_ev_loop
default:
return INVALID_SOCKET;
}
DWORD on = 1;
SOCKET fd = ::socket(addr->sa_family, SOCK_DGRAM, 0);
SOCKET fd = WSASocket(addr->sa_family, SOCK_DGRAM, 0, nullptr, 0,
WSA_FLAG_OVERLAPPED);
if(fd == INVALID_SOCKET)
{
perror("WSASocket()");
@ -475,7 +477,6 @@ struct llarp_win32_loop : public llarp_ev_loop
return INVALID_SOCKET;
}
llarp::LogDebug("socket fd is ", fd);
ioctlsocket(fd, FIONBIO, &on);
return fd;
}
@ -630,4 +631,4 @@ struct llarp_win32_loop : public llarp_ev_loop
}
};
#endif
#endif

@ -8,18 +8,71 @@ namespace llarp
bool
CloseExitMessage::BEncode(llarp_buffer_t* buf) const
{
(void)buf;
// TODO: implement me
return false;
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "C"))
return false;
if(!BEncodeWriteDictInt("S", S, buf))
return false;
if(!BEncodeWriteDictInt("V", version, buf))
return false;
if(!BEncodeWriteDictEntry("Y", Y, buf))
return false;
if(!BEncodeWriteDictEntry("Z", Z, buf))
return false;
return bencode_end(buf);
}
bool
CloseExitMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
{
(void)k;
(void)buf;
// TODO: implement me
return false;
bool read = false;
if(!BEncodeMaybeReadDictInt("S", S, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Y", Y, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, k, buf))
return false;
return read;
}
bool
CloseExitMessage::Verify(llarp_crypto* c, const llarp::PubKey& pk) const
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
CloseExitMessage copy;
copy = *this;
copy.Z.Zero();
if(!copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->verify(pk, buf, Z);
}
bool
CloseExitMessage::Sign(llarp_crypto* c, const llarp::SecretKey& sk)
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
Z.Zero();
Y.Randomize();
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->sign(Z, sk, buf);
}
CloseExitMessage&
CloseExitMessage::operator=(const CloseExitMessage& other)
{
S = other.S;
version = other.version;
Y = other.Y;
Z = other.Z;
return *this;
}
bool

@ -22,6 +22,45 @@ namespace llarp
}
}
void
Context::CalculateExitTraffic(TrafficStats& stats)
{
auto itr = m_Exits.begin();
while(itr != m_Exits.end())
{
itr->second->CalculateTrafficStats(stats);
++itr;
}
}
llarp::exit::Endpoint*
Context::FindEndpointForPath(const llarp::PathID_t& path) const
{
auto itr = m_Exits.begin();
while(itr != m_Exits.end())
{
auto ep = itr->second->FindEndpointByPath(path);
if(ep)
return ep;
++itr;
}
return nullptr;
}
bool
Context::ObtainNewExit(const llarp::PubKey& pk, const llarp::PathID_t& path,
bool permitInternet)
{
auto itr = m_Exits.begin();
while(itr != m_Exits.end())
{
if(itr->second->AllocateNewExit(pk, path, permitInternet))
return true;
++itr;
}
return false;
}
bool
Context::AddExitEndpoint(const std::string& name, const Config_t& conf)
{
@ -48,6 +87,8 @@ namespace llarp
}
}
// add endpoint
if(!endpoint->Start())
return false;
m_Exits.emplace(name, std::move(endpoint));
return true;
}

@ -5,8 +5,43 @@ namespace llarp
{
namespace exit
{
Endpoint::Endpoint(const llarp::PubKey& remoteIdent,
const llarp::PathID_t& beginPath, bool rewriteIP,
huint32_t ip, llarp::handlers::ExitEndpoint* parent)
: m_Parent(parent)
, m_remoteSignKey(remoteIdent)
, m_CurrentPath(beginPath)
, m_IP(ip)
, m_RewriteSource(rewriteIP)
{
}
Endpoint::~Endpoint()
{
m_Parent->DelEndpointInfo(m_CurrentPath);
}
void
Endpoint::Close()
{
m_Parent->RemoveExit(this);
}
bool
Endpoint::UpdateLocalPath(const llarp::PathID_t& nextPath)
{
if(!m_Parent->UpdateEndpointPath(m_remoteSignKey, nextPath))
return false;
m_CurrentPath = nextPath;
return true;
}
void
Endpoint::Tick(llarp_time_t now)
{
(void)now;
m_RxRate = 0;
m_TxRate = 0;
}
bool
@ -21,19 +56,63 @@ namespace llarp
return true;
}
bool
Endpoint::ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const
{
auto path = GetCurrentPath();
if(path)
return path->ExpiresSoon(now, dlt);
return true;
}
bool
Endpoint::SendOutboundTraffic(llarp_buffer_t buf)
{
llarp::net::IPv4Packet pkt;
if(!pkt.Load(buf))
return false;
huint32_t dst;
if(m_RewriteSource)
dst = m_Parent->GetIfAddr();
else
dst = pkt.dst();
pkt.UpdateIPv4PacketOnDst(m_IP, dst);
if(!m_Parent->QueueOutboundTraffic(pkt.Buffer()))
{
llarp::LogError("failed to queue outbound traffic");
return false;
}
m_TxRate += buf.sz;
return true;
}
bool
Endpoint::SendInboundTraffic(llarp_buffer_t buf)
{
auto path = GetCurrentPath();
if(path)
{
llarp::net::IPv4Packet pkt;
if(!pkt.Load(buf))
return false;
huint32_t src;
if(m_RewriteSource)
src = m_Parent->GetIfAddr();
else
src = pkt.src();
pkt.UpdateIPv4PacketOnDst(src, m_IP);
llarp::routing::TransferTrafficMessage msg;
if(!msg.PutBuffer(buf))
if(!msg.PutBuffer(pkt.Buffer()))
return false;
msg.S = path->NextSeqNo();
if(!msg.Sign(m_Parent->Crypto(), m_Parent->Router()->identity))
return false;
return path->SendRoutingMessage(&msg, m_Parent->Router());
if(!path->SendRoutingMessage(&msg, m_Parent->Router()))
return false;
m_RxRate += buf.sz;
return true;
}
return false;
}

@ -8,18 +8,76 @@ namespace llarp
bool
GrantExitMessage::BEncode(llarp_buffer_t* buf) const
{
(void)buf;
// TODO: implement me
return false;
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "G"))
return false;
if(!BEncodeWriteDictInt("S", S, buf))
return false;
if(!BEncodeWriteDictInt("T", T, buf))
return false;
if(!BEncodeWriteDictInt("V", version, buf))
return false;
if(!BEncodeWriteDictEntry("Y", Y, buf))
return false;
if(!BEncodeWriteDictEntry("Z", Z, buf))
return false;
return bencode_end(buf);
}
bool
GrantExitMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
{
(void)k;
(void)buf;
// TODO: implement me
return false;
bool read = false;
if(!BEncodeMaybeReadDictInt("S", S, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("T", T, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Y", Y, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, k, buf))
return false;
return read;
}
bool
GrantExitMessage::Verify(llarp_crypto* c, const llarp::PubKey& pk) const
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
GrantExitMessage copy;
copy = *this;
copy.Z.Zero();
if(!copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->verify(pk, buf, Z);
}
bool
GrantExitMessage::Sign(llarp_crypto* c, const llarp::SecretKey& sk)
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
Z.Zero();
Y.Randomize();
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->sign(Z, sk, buf);
}
GrantExitMessage&
GrantExitMessage::operator=(const GrantExitMessage& other)
{
S = other.S;
T = other.T;
version = other.version;
Y = other.Y;
Z = other.Z;
return *this;
}
bool

@ -24,9 +24,9 @@ namespace llarp
bool
ObtainExitMessage::Sign(llarp_crypto* c, const llarp::SecretKey& sk)
{
byte_t tmp[MAX_LINK_MSG_SIZE - 128] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
I = llarp::seckey_topublic(sk);
byte_t tmp[1024] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
I = llarp::seckey_topublic(sk);
Z.Zero();
if(!BEncode(&buf))
return false;
@ -37,8 +37,8 @@ namespace llarp
bool
ObtainExitMessage::Verify(llarp_crypto* c) const
{
byte_t tmp[MAX_LINK_MSG_SIZE - 128] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
byte_t tmp[1024] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
ObtainExitMessage copy;
copy = *this;
copy.Z.Zero();
@ -54,7 +54,7 @@ namespace llarp
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "X"))
if(!BEncodeWriteDictMsgType(buf, "A", "O"))
return false;
if(!BEncodeWriteDictArray("B", B, buf))
return false;

@ -8,19 +8,86 @@ namespace llarp
bool
RejectExitMessage::BEncode(llarp_buffer_t* buf) const
{
(void)buf;
// TODO: implement me
return false;
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "J"))
return false;
if(!BEncodeWriteDictInt("B", B, buf))
return false;
if(!BEncodeWriteDictList("R", R, buf))
return false;
if(!BEncodeWriteDictInt("S", S, buf))
return false;
if(!BEncodeWriteDictInt("T", T, buf))
return false;
if(!BEncodeWriteDictInt("V", version, buf))
return false;
if(!BEncodeWriteDictEntry("Y", Y, buf))
return false;
if(!BEncodeWriteDictEntry("Z", Z, buf))
return false;
return bencode_end(buf);
}
bool
RejectExitMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
{
(void)k;
(void)buf;
// TODO: implement me
return false;
bool read = false;
if(!BEncodeMaybeReadDictInt("B", B, read, k, buf))
return false;
if(!BEncodeMaybeReadDictList("R", R, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("S", S, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("T", T, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Y", Y, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, k, buf))
return false;
return read;
}
RejectExitMessage&
RejectExitMessage::operator=(const RejectExitMessage& other)
{
B = other.B;
R = other.R;
S = other.S;
T = other.T;
version = other.version;
Y = other.Y;
Z = other.Z;
return *this;
}
bool
RejectExitMessage::Sign(llarp_crypto* c, const llarp::SecretKey& sk)
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
Z.Zero();
Y.Randomize();
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->sign(Z, sk, buf);
}
bool
RejectExitMessage::Verify(llarp_crypto* c, const llarp::PubKey& pk) const
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
RejectExitMessage copy;
copy = *this;
copy.Z.Zero();
if(!copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->verify(pk, buf, Z);
}
bool

@ -1,8 +1,113 @@
#include <llarp/exit/session.hpp>
#include "router.hpp"
namespace llarp
{
namespace exit
{
}
BaseSession::BaseSession(const llarp::RouterID& router,
std::function< bool(llarp_buffer_t) > writepkt,
llarp_router* r, size_t numpaths, size_t hoplen)
: llarp::path::Builder(r, r->dht, numpaths, hoplen)
, m_ExitRouter(router)
, m_WritePacket(writepkt)
{
r->crypto.identity_keygen(m_ExitIdentity);
}
BaseSession::~BaseSession()
{
}
bool
BaseSession::ShouldBuildMore(llarp_time_t now) const
{
return AvailablePaths(llarp::path::ePathRoleExit) == 0
|| path::Builder::ShouldBuildMore(now);
}
bool
BaseSession::SelectHop(llarp_nodedb* db, const RouterContact& prev,
RouterContact& cur, size_t hop,
llarp::path::PathRole roles)
{
if(hop == numHops - 1)
return llarp_nodedb_get_rc(db, m_ExitRouter, cur);
else
return path::Builder::SelectHop(db, prev, cur, hop, roles);
}
void
BaseSession::HandlePathBuilt(llarp::path::Path* p)
{
p->SetDropHandler(std::bind(&BaseSession::HandleTrafficDrop, this,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3));
p->SetExitTrafficHandler(std::bind(&BaseSession::HandleTraffic, this,
std::placeholders::_1,
std::placeholders::_2));
p->AddObtainExitHandler(std::bind(&BaseSession::HandleGotExit, this,
std::placeholders::_1,
std::placeholders::_2));
llarp::routing::ObtainExitMessage obtain;
obtain.S = p->NextSeqNo();
obtain.T = llarp_randint();
obtain.X = 0;
obtain.E = 1;
if(!obtain.Sign(&router->crypto, m_ExitIdentity))
{
llarp::LogError("Failed to sign exit request");
return;
}
if(p->SendExitRequest(&obtain, router))
llarp::LogInfo("asking ", m_ExitRouter, " for exit");
else
llarp::LogError("faild to send exit request");
}
bool
BaseSession::HandleGotExit(llarp::path::Path* p, llarp_time_t b)
{
if(b == 0)
{
llarp::LogInfo("obtained an exit via ", p->Endpoint());
}
return true;
}
bool
BaseSession::HandleTraffic(llarp::path::Path* p, llarp_buffer_t pkt)
{
(void)p;
if(m_WritePacket)
return m_WritePacket(pkt);
return false;
}
bool
BaseSession::HandleTrafficDrop(llarp::path::Path* p, const PathID_t& path,
uint64_t s)
{
(void)p;
llarp::LogError("dropped traffic on exit ", m_ExitRouter, " S=", s,
" P=", path);
return true;
}
bool
BaseSession::SendUpstreamTraffic(llarp::net::IPv4Packet pkt)
{
auto path = PickRandomEstablishedPath(llarp::path::ePathRoleExit);
if(!path)
return false;
llarp::routing::TransferTrafficMessage transfer;
transfer.S = path->NextSeqNo();
transfer.X.resize(pkt.sz);
memcpy(transfer.X.data(), pkt.buf, pkt.sz);
if(!transfer.Sign(&router->crypto, m_ExitIdentity))
return false;
return path->SendRoutingMessage(&transfer, router);
}
} // namespace exit
} // namespace llarp

@ -10,23 +10,22 @@ namespace llarp
{
byte_t tmp[MaxExitMTU + 512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
llarp::Signature sig;
// zero out sig
Z.Zero();
// randomize nonce
Y.Randomize();
if(!BEncode(&buf))
return false;
// rewind buffer
buf.sz = buf.cur - buf.base;
if(!c->sign(sig, k, buf))
return false;
Z = sig;
return true;
return c->sign(Z, k, buf);
}
TransferTrafficMessage&
TransferTrafficMessage::operator=(const TransferTrafficMessage& other)
{
Z = other.Z;
Y = other.Y;
S = other.S;
version = other.version;
X = other.X;
@ -39,7 +38,6 @@ namespace llarp
{
byte_t tmp[MaxExitMTU + 512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
llarp::Signature sig;
// make copy
TransferTrafficMessage copy;
copy = *this;
@ -80,7 +78,8 @@ namespace llarp
return false;
if(!bencode_write_bytestring(buf, X.data(), X.size()))
return false;
if(!BEncodeWriteDictEntry("Y", Y, buf))
return false;
if(!BEncodeWriteDictEntry("Z", Z, buf))
return false;
return bencode_end(buf);
@ -92,6 +91,8 @@ namespace llarp
bool read = false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, key, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Y", Y, read, key, buf))
return false;
if(!BEncodeMaybeReadDictInt("S", S, read, key, buf))
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, key, buf))

@ -8,18 +8,77 @@ namespace llarp
bool
UpdateExitMessage::BEncode(llarp_buffer_t* buf) const
{
(void)buf;
// TODO: implement me
return false;
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "V"))
return false;
if(!BEncodeWriteDictEntry("P", P, buf))
return false;
if(!BEncodeWriteDictInt("S", S, buf))
return false;
if(!BEncodeWriteDictInt("T", T, buf))
return false;
if(!BEncodeWriteDictInt("V", version, buf))
return false;
if(!BEncodeWriteDictEntry("Z", Z, buf))
return false;
return bencode_end(buf);
}
bool
UpdateExitMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
{
(void)k;
(void)buf;
// TODO: implement me
return false;
bool read = false;
if(!BEncodeMaybeReadDictInt("S", S, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("T", T, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("P", P, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, k, buf))
return false;
return read;
}
bool
UpdateExitMessage::Verify(llarp_crypto* c, const llarp::PubKey& pk) const
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
UpdateExitMessage copy;
copy = *this;
copy.Z.Zero();
if(!copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->verify(pk, buf, Z);
}
UpdateExitMessage&
UpdateExitMessage::operator=(const UpdateExitMessage& other)
{
P = other.P;
S = other.S;
T = other.T;
version = other.version;
Y = other.Y;
Z = other.Z;
return *this;
}
bool
UpdateExitMessage::Sign(llarp_crypto* c, const llarp::SecretKey& sk)
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
Y.Randomize();
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->sign(Z, sk, buf);
}
bool
@ -28,5 +87,41 @@ namespace llarp
return h->HandleUpdateExitMessage(this, r);
}
bool
UpdateExitVerifyMessage::BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "V"))
return false;
if(!BEncodeWriteDictInt("S", S, buf))
return false;
if(!BEncodeWriteDictInt("T", T, buf))
return false;
if(!BEncodeWriteDictInt("V", version, buf))
return false;
return bencode_end(buf);
}
bool
UpdateExitVerifyMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
{
bool read = false;
if(!BEncodeMaybeReadDictInt("S", S, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("T", T, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
return read;
}
bool
UpdateExitVerifyMessage::HandleMessage(IMessageHandler* h,
llarp_router* r) const
{
return h->HandleUpdateExitVerifyMessage(this, r);
}
} // namespace routing
} // namespace llarp

@ -1,26 +1,280 @@
#include <llarp/handlers/exit.hpp>
#include "../str.hpp"
#include "../router.hpp"
#include <llarp/net.hpp>
#include <cassert>
namespace llarp
{
namespace handlers
{
static void
ExitHandlerRecvPkt(llarp_tun_io *tun, const void *pkt, ssize_t sz)
{
static_cast< ExitEndpoint * >(tun->user)->OnInetPacket(
llarp::InitBuffer(pkt, sz));
}
static void
ExitHandlerFlushInbound(llarp_tun_io *tun)
{
static_cast< ExitEndpoint * >(tun->user)->FlushInbound();
}
ExitEndpoint::ExitEndpoint(const std::string &name, llarp_router *r)
: TunEndpoint(name, r), m_Name(name)
: m_Router(r)
, m_Name(name)
, m_Tun{{0}, 0, {0}, 0, 0, 0, 0, 0, 0}
, m_InetToNetwork(name + "_exit_rx", r->netloop, r->netloop)
{
m_Tun.user = this;
m_Tun.recvpkt = &ExitHandlerRecvPkt;
m_Tun.tick = &ExitHandlerFlushInbound;
m_ShouldInitTun = true;
}
ExitEndpoint::~ExitEndpoint()
{
}
void
ExitEndpoint::FlushInbound()
{
auto now = Router()->Now();
m_InetToNetwork.Process([&](Pkt_t &pkt) {
llarp::PubKey pk;
{
auto itr = m_IPToKey.find(pkt.dst());
if(itr == m_IPToKey.end())
{
// drop
llarp::LogWarn(Name(), " dropping packet, has no session at ",
pkt.dst());
return;
}
pk = itr->second;
}
llarp::exit::Endpoint *ep = nullptr;
auto range = m_ActiveExits.equal_range(pk);
auto itr = range.first;
uint64_t min = std::numeric_limits< uint64_t >::max();
/// pick path with lowest rx rate
while(itr != range.second)
{
if(ep == nullptr)
ep = itr->second.get();
else if(itr->second->RxRate() < min && !itr->second->ExpiresSoon(now))
{
min = ep->RxRate();
ep = itr->second.get();
}
++itr;
}
if(ep)
{
if(!ep->SendInboundTraffic(pkt.Buffer()))
{
llarp::LogWarn(Name(), " dropped inbound traffic for session ", pk);
}
}
});
}
bool
ExitEndpoint::Start()
{
if(m_ShouldInitTun)
return llarp_ev_add_tun(Router()->netloop, &m_Tun);
return true;
}
llarp_router *
ExitEndpoint::Router()
{
return m_Router;
}
llarp_crypto *
ExitEndpoint::Crypto()
{
return &m_Router->crypto;
}
huint32_t
ExitEndpoint::GetIfAddr() const
{
return m_IfAddr;
}
bool
ExitEndpoint::HasLocalMappedAddrFor(const llarp::PubKey &pk) const
{
return m_KeyToIP.find(pk) != m_KeyToIP.end();
}
huint32_t
ExitEndpoint::GetIPForIdent(const llarp::PubKey pk)
{
huint32_t found = {0};
if(!HasLocalMappedAddrFor(pk))
{
// allocate and map
found.h = AllocateNewAddress().h;
if(!m_KeyToIP.emplace(pk, found).second)
{
llarp::LogError(Name(), "failed to map ", pk, " to ", found);
return found;
}
if(!m_IPToKey.emplace(found, pk).second)
{
llarp::LogError(Name(), "failed to map ", found, " to ", pk);
return found;
}
if(HasLocalMappedAddrFor(pk))
llarp::LogInfo(Name(), " mapping ", pk, " to ", found);
else
llarp::LogError(Name(), "failed to map ", pk, " to ", found);
}
else
found.h = m_KeyToIP[pk].h;
MarkIPActive(found);
m_KeyToIP.rehash(0);
assert(HasLocalMappedAddrFor(pk));
return found;
}
huint32_t
ExitEndpoint::AllocateNewAddress()
{
if(m_NextAddr < m_HigestAddr)
return ++m_NextAddr;
// find oldest activity ip address
huint32_t found = {0};
llarp_time_t min = std::numeric_limits< llarp_time_t >::max();
auto itr = m_IPActivity.begin();
while(itr != m_IPActivity.end())
{
if(itr->second < min)
{
found.h = itr->first.h;
min = itr->second;
}
++itr;
}
// kick old ident off exit
// TODO: DoS
llarp::PubKey pk = m_IPToKey[found];
KickIdentOffExit(pk);
return found;
}
bool
ExitEndpoint::QueueOutboundTraffic(llarp_buffer_t buf)
{
return llarp_ev_tun_async_write(&m_Tun, buf.base, buf.sz);
}
void
ExitEndpoint::KickIdentOffExit(const llarp::PubKey &pk)
{
llarp::LogInfo(Name(), " kicking ", pk, " off exit");
huint32_t ip = m_KeyToIP[pk];
m_KeyToIP.erase(pk);
m_IPToKey.erase(ip);
auto range = m_ActiveExits.equal_range(pk);
auto exit_itr = range.first;
while(exit_itr != range.second)
exit_itr = m_ActiveExits.erase(exit_itr);
}
void
ExitEndpoint::MarkIPActive(llarp::huint32_t ip)
{
m_IPActivity[ip] = Router()->Now();
}
void
ExitEndpoint::OnInetPacket(llarp_buffer_t buf)
{
m_InetToNetwork.EmplaceIf(
[buf](Pkt_t &pkt) -> bool { return pkt.Load(buf); });
}
llarp::exit::Endpoint *
ExitEndpoint::FindEndpointByPath(const llarp::PathID_t &path)
{
llarp::exit::Endpoint *endpoint = nullptr;
llarp::PubKey pk;
{
auto itr = m_Paths.find(path);
if(itr == m_Paths.end())
return nullptr;
pk = itr->second;
}
{
auto itr = m_ActiveExits.find(pk);
if(itr != m_ActiveExits.end())
{
if(itr->second->PubKey() == pk)
endpoint = itr->second.get();
}
}
return endpoint;
}
bool
ExitEndpoint::UpdateEndpointPath(const llarp::PubKey &remote,
const llarp::PathID_t &next)
{
// check if already mapped
auto itr = m_Paths.find(next);
if(itr != m_Paths.end())
return false;
m_Paths.insert(std::make_pair(next, remote));
return true;
}
bool
ExitEndpoint::SetOption(const std::string &k, const std::string &v)
{
if(k == "type" && v == "null")
{
m_ShouldInitTun = false;
return true;
}
if(k == "exit")
{
// TODO: implement me
m_PermitExit = IsTrueValue(v.c_str());
return true;
}
if(k == "ifaddr")
{
auto pos = v.find("/");
if(pos == std::string::npos)
{
llarp::LogError(Name(), " ifaddr is not a cidr: ", v);
return false;
}
std::string nmask_str = v.substr(1 + pos);
std::string host_str = v.substr(0, pos);
strncpy(m_Tun.ifaddr, host_str.c_str(), sizeof(m_Tun.ifaddr));
m_Tun.netmask = std::atoi(nmask_str.c_str());
llarp::Addr ifaddr(host_str);
m_IfAddr = ifaddr.xtohl();
m_NextAddr = m_IfAddr;
m_HigestAddr = m_IfAddr ^ (~llarp::netmask_ipv4_bits(m_Tun.netmask));
llarp::LogInfo(Name(), " set ifaddr range to ", m_Tun.ifaddr, "/",
m_Tun.netmask, " lo=", m_IfAddr, " hi=", m_HigestAddr);
}
if(k == "ifname")
{
strncpy(m_Tun.ifname, v.c_str(), sizeof(m_Tun.ifname));
llarp::LogInfo(Name(), " set ifname to ", m_Tun.ifname);
}
if(k == "exit-whitelist")
{
// add exit policy whitelist rule
@ -33,33 +287,22 @@ namespace llarp
// TODO: implement me
return true;
}
return TunEndpoint::SetOption(k, v);
return true;
}
void
ExitEndpoint::FlushSend()
bool
ExitEndpoint::AllocateNewExit(const llarp::PubKey pk,
const llarp::PathID_t &path,
bool wantInternet)
{
m_UserToNetworkPktQueue.Process([&](net::IPv4Packet &pkt) {
// find pubkey for addr
auto itr = m_AddrsToPubKey.find(pkt.dst());
if(itr == m_AddrsToPubKey.end())
{
llarp::LogWarn(Name(), " has no endpoint for ", pkt.dst());
return true;
}
pkt.UpdateIPv4PacketOnSrc();
auto range = m_ActiveExits.equal_range(itr->second);
auto exit_itr = range.first;
while(exit_itr != range.second)
{
if(exit_itr->second.SendInboundTraffic(pkt.Buffer()))
return true;
++exit_itr;
}
// dropped
llarp::LogWarn(Name(), " dropped traffic to ", itr->second);
return true;
});
if(wantInternet && !m_PermitExit)
return false;
huint32_t ip = GetIPForIdent(pk);
m_ActiveExits.insert(std::make_pair(
pk, new llarp::exit::Endpoint(pk, path, !wantInternet, ip, this)));
m_Paths[path] = pk;
return HasLocalMappedAddrFor(pk);
}
std::string
@ -68,21 +311,45 @@ namespace llarp
return m_Name;
}
void
ExitEndpoint::DelEndpointInfo(const llarp::PathID_t &path)
{
m_Paths.erase(path);
}
void
ExitEndpoint::RemoveExit(const llarp::exit::Endpoint *ep)
{
auto range = m_ActiveExits.equal_range(ep->PubKey());
auto itr = range.first;
while(itr != range.second)
{
if(itr->second->LocalPath() == ep->LocalPath())
{
itr = m_ActiveExits.erase(itr);
// now ep is gone af
return;
}
++itr;
}
}
void
ExitEndpoint::Tick(llarp_time_t now)
{
auto itr = m_ActiveExits.begin();
while(itr != m_ActiveExits.end())
{
if(itr->second.IsExpired(now))
if(itr->second->IsExpired(now))
{
itr = m_ActiveExits.erase(itr);
}
else
{
itr->second->Tick(now);
++itr;
}
}
// call parent
TunEndpoint::Tick(now);
}
} // namespace handlers
} // namespace llarp

@ -15,8 +15,8 @@ namespace llarp
{
TunEndpoint::TunEndpoint(const std::string &nickname, llarp_router *r)
: service::Endpoint(nickname, r)
, m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop)
, m_NetworkToUserPktQueue(nickname + "_recvq", r->netloop)
, m_UserToNetworkPktQueue(nickname + "_sendq", r->netloop, r->netloop)
, m_NetworkToUserPktQueue(nickname + "_recvq", r->netloop, r->netloop)
{
tunif.user = this;
tunif.netmask = DefaultTunNetmask;
@ -33,6 +33,21 @@ namespace llarp
bool
TunEndpoint::SetOption(const std::string &k, const std::string &v)
{
if(k == "exit-node")
{
llarp::RouterID exitRouter;
if(!HexDecode(v.c_str(), exitRouter, exitRouter.size()))
{
llarp::LogError(Name(), " bad exit router key: ", v);
return false;
}
m_Exit.reset(new llarp::exit::BaseSession(
exitRouter,
std::bind(&TunEndpoint::QueueInboundPacketForExit, this,
std::placeholders::_1),
router, m_NumPaths, numHops));
llarp::LogInfo(Name(), " using exit at ", exitRouter);
}
if(k == "local-dns")
{
std::string resolverAddr = v;
@ -137,6 +152,20 @@ namespace llarp
return Endpoint::SetOption(k, v);
}
bool
TunEndpoint::HasLocalIP(const huint32_t &ip) const
{
return m_IPToAddr.find(ip) != m_IPToAddr.end();
}
bool
TunEndpoint::QueueOutboundTraffic(llarp::net::IPv4Packet &&pkt)
{
return m_NetworkToUserPktQueue.EmplaceIf(
[](llarp::net::IPv4Packet &) -> bool { return true; },
std::move(pkt));
}
bool
TunEndpoint::MapAddress(const service::Address &addr, huint32_t ip)
{
@ -144,13 +173,14 @@ namespace llarp
if(itr != m_IPToAddr.end())
{
// XXX is calling inet_ntoa safe in this context? it's MP-unsafe
llarp::LogWarn(ip, " already mapped to ", itr->second.ToString());
llarp::LogWarn(ip, " already mapped to ",
service::Address(itr->second).ToString());
return false;
}
llarp::LogInfo(Name() + " map ", addr.ToString(), " to ", ip);
m_IPToAddr.insert(std::make_pair(ip, addr));
m_AddrToIP.insert(std::make_pair(addr, ip));
m_IPToAddr.insert(std::make_pair(ip, addr.data()));
m_AddrToIP.insert(std::make_pair(addr.data(), ip));
MarkIPActiveForever(ip);
return true;
}
@ -257,9 +287,7 @@ namespace llarp
m_OurIP = lAddr.xtohl();
m_NextIP = m_OurIP;
auto xmask = netmask_ipv4_bits(tunif.netmask);
auto baseaddr = m_OurIP & xmask;
m_MaxIP = baseaddr | ~xmask;
m_MaxIP = m_OurIP ^ (~xmask);
llarp::LogInfo(Name(), " set ", tunif.ifname, " to have address ", lAddr);
llarp::LogInfo(Name(), " allocated up to ", m_MaxIP);
@ -319,7 +347,13 @@ namespace llarp
auto itr = m_IPToAddr.find(pkt.dst());
if(itr == m_IPToAddr.end())
{
llarp::LogWarn(Name(), " has no endpoint for ", pkt.dst());
if(m_Exit)
{
pkt.UpdateIPv4PacketOnDst({0}, pkt.dst());
m_Exit->SendUpstreamTraffic(std::move(pkt));
}
else
llarp::LogWarn(Name(), " has no endpoint for ", pkt.dst());
return true;
}
@ -327,7 +361,8 @@ namespace llarp
// this includes clearing IP addresses, recalculating checksums, etc
pkt.UpdateIPv4PacketOnSrc();
if(!SendToOrQueue(itr->second, pkt.Buffer(), service::eProtocolTraffic))
if(!SendToOrQueue(itr->second.data(), pkt.Buffer(),
service::eProtocolTraffic))
{
llarp::LogWarn(Name(), " did not flush packets");
}
@ -339,7 +374,7 @@ namespace llarp
TunEndpoint::ProcessDataMessage(service::ProtocolMessage *msg)
{
// llarp::LogInfo("got packet from ", msg->sender.Addr());
auto themIP = ObtainIPForAddr(msg->sender.Addr());
auto themIP = ObtainIPForAddr(msg->sender.Addr().data());
// llarp::LogInfo("themIP ", themIP);
auto usIP = m_OurIP;
auto buf = llarp::Buffer(msg->payload);
@ -372,30 +407,21 @@ namespace llarp
return true;
}
service::Address
TunEndpoint::ObtainAddrForIP(huint32_t ip)
huint32_t
TunEndpoint::GetIfAddr() const
{
auto itr = m_IPToAddr.find(ip);
if(itr == m_IPToAddr.end())
{
// not found
service::Address addr;
llarp::LogWarn(ip, " not found in tun map.");
return addr;
}
// found
return itr->second;
return m_OurIP;
}
huint32_t
TunEndpoint::ObtainIPForAddr(const service::Address &addr)
TunEndpoint::ObtainIPForAddr(const byte_t *a)
{
llarp_time_t now = Now();
huint32_t nextIP = {0};
AlignedBuffer< 32 > ident(a);
{
// previously allocated address
auto itr = m_AddrToIP.find(addr);
auto itr = m_AddrToIP.find(ident);
if(itr != m_AddrToIP.end())
{
// mark ip active
@ -413,9 +439,9 @@ namespace llarp
&& m_NextIP < m_MaxIP);
if(nextIP < m_MaxIP)
{
m_AddrToIP.insert(std::make_pair(addr, nextIP));
m_IPToAddr.insert(std::make_pair(nextIP, addr));
llarp::LogInfo(Name(), " mapped ", addr, " to ", nextIP);
m_AddrToIP[ident] = nextIP;
m_IPToAddr[nextIP] = ident;
llarp::LogInfo(Name(), " mapped ", ident, " to ", nextIP);
MarkIPActive(nextIP);
return nextIP;
}
@ -441,8 +467,8 @@ namespace llarp
++itr;
}
// remap address
m_IPToAddr[oldest.first] = addr;
m_AddrToIP[addr] = oldest.first;
m_IPToAddr[oldest.first] = ident;
m_AddrToIP[ident] = oldest.first;
nextIP = oldest.first;
// mark ip active

@ -60,7 +60,10 @@ namespace llarp
++itr;
}
else
{
llarp::LogInfo("session to ", itr->second->GetPubKey(), " timed out");
itr = m_AuthedLinks.erase(itr);
}
}
}
{
@ -121,6 +124,7 @@ namespace llarp
llarp::AddressInfo to;
if(!PickAddress(rc, to))
return;
llarp::LogInfo("Try establish to ", rc.pubkey);
llarp::Addr addr(to);
auto s = NewOutboundSession(rc, to);
s->Start();
@ -164,6 +168,7 @@ namespace llarp
ILinkLayer::CloseSessionTo(const PubKey& remote)
{
Lock l(m_AuthedLinksMutex);
llarp::LogInfo("Closing all to ", remote);
auto range = m_AuthedLinks.equal_range(remote);
auto itr = range.first;
while(itr != range.second)

@ -17,7 +17,6 @@
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#endif
namespace llarp
@ -565,7 +564,7 @@ namespace llarp
SendKeepAlive = [&]() -> bool {
auto now = parent->now();
if(sendq.size() == 0 && state == eSessionReady && now > lastActive
&& now - lastActive > (sessionTimeout / 4))
&& now - lastActive > 5000)
{
DiscardMessage msg;
byte_t tmp[128] = {0};

@ -1,4 +1,4 @@
#if defined(RPI) || defined(ANDROID)
#if defined(RPI) || defined(ANDROID) || NETNS == 0
#else
#include <asm/types.h>

@ -68,25 +68,8 @@ operator==(const sockaddr_in6& a, const sockaddr_in6& b)
#include <iphlpapi.h>
#include <strsafe.h>
// current strategy: mingw 32-bit builds call an inlined version of the function
// microsoft c++ and mingw 64-bit builds call the normal function
#define DEFAULT_BUFFER_SIZE 15000
// the inline monkey patch for downlevel platforms
#ifndef _MSC_VER
extern "C" DWORD FAR PASCAL
_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved,
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
PULONG pOutBufLen);
#endif
// in any case, we still need to implement some form of
// getifaddrs(3) with compatible semantics on NT...
// daemon.ini section [bind] will have something like
// [bind]
// Ethernet=1090
// inside, since that's what we use in windows to refer to
// network interfaces
struct llarp_nt_ifaddrs_t
{
struct llarp_nt_ifaddrs_t* ifa_next; /* Pointer to the next structure. */
@ -140,148 +123,6 @@ llarp_nt_sockaddr_pton(const char* src, struct sockaddr* dst)
return 0;
}
/* NB: IP_ADAPTER_INFO size varies size due to sizeof (time_t), the API assumes
* 4-byte datatype whilst compiler uses an 8-byte datatype. Size can be forced
* with -D_USE_32BIT_TIME_T with side effects to everything else.
*
* Only supports IPv4 addressing similar to SIOCGIFCONF socket option.
*
* Interfaces that are not "operationally up" will return the address 0.0.0.0,
* this includes adapters with static IP addresses but with disconnected cable.
* This is documented under the GetIpAddrTable API. Interface status can only
* be determined by the address, a separate flag is introduced with the
* GetAdapterAddresses API.
*
* The IPv4 loopback interface is not included.
*
* Available in Windows 2000 and Wine 1.0.
*/
static bool
_llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap)
{
DWORD dwRet;
ULONG ulOutBufLen = DEFAULT_BUFFER_SIZE;
PIP_ADAPTER_INFO pAdapterInfo = nullptr;
PIP_ADAPTER_INFO pAdapter = nullptr;
/* loop to handle interfaces coming online causing a buffer overflow
* between first call to list buffer length and second call to enumerate.
*/
for(unsigned i = 3; i; i--)
{
#ifdef DEBUG
fprintf(stderr, "IP_ADAPTER_INFO buffer length %lu bytes.\n", ulOutBufLen);
#endif
pAdapterInfo = (IP_ADAPTER_INFO*)_llarp_nt_heap_alloc(ulOutBufLen);
dwRet = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
if(ERROR_BUFFER_OVERFLOW == dwRet)
{
_llarp_nt_heap_free(pAdapterInfo);
pAdapterInfo = nullptr;
}
else
{
break;
}
}
switch(dwRet)
{
case ERROR_SUCCESS: /* NO_ERROR */
break;
case ERROR_BUFFER_OVERFLOW:
errno = ENOBUFS;
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
return false;
default:
errno = dwRet;
#ifdef DEBUG
fprintf(stderr, "system call failed: %lu\n", GetLastError());
#endif
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
return false;
}
/* count valid adapters */
int n = 0, k = 0;
for(pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next)
{
for(IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr;
pIPAddr = pIPAddr->Next)
{
/* skip null adapters */
if(strlen(pIPAddr->IpAddress.String) == 0)
continue;
++n;
}
}
#ifdef DEBUG
fprintf(stderr, "GetAdaptersInfo() discovered %d interfaces.\n", n);
#endif
/* contiguous block for adapter list */
struct _llarp_nt_ifaddrs_t* ifa =
llarp_nt_new0(struct _llarp_nt_ifaddrs_t, n);
struct _llarp_nt_ifaddrs_t* ift = ifa;
/* now populate list */
for(pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next)
{
for(IP_ADDR_STRING* pIPAddr = &pAdapter->IpAddressList; pIPAddr;
pIPAddr = pIPAddr->Next)
{
/* skip null adapters */
if(strlen(pIPAddr->IpAddress.String) == 0)
continue;
/* address */
ift->_ifa.ifa_addr = (struct sockaddr*)&ift->_addr;
assert(1
== llarp_nt_sockaddr_pton(pIPAddr->IpAddress.String,
ift->_ifa.ifa_addr));
/* name */
#ifdef DEBUG
fprintf(stderr, "name:%s IPv4 index:%lu\n", pAdapter->AdapterName,
pAdapter->Index);
#endif
ift->_ifa.ifa_name = ift->_name;
StringCchCopyN(ift->_ifa.ifa_name, 128, pAdapter->AdapterName, 128);
/* flags: assume up, broadcast and multicast */
ift->_ifa.ifa_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST;
if(pAdapter->Type == MIB_IF_TYPE_LOOPBACK)
ift->_ifa.ifa_flags |= IFF_LOOPBACK;
/* netmask */
ift->_ifa.ifa_netmask = (sockaddr*)&ift->_netmask;
assert(1
== llarp_nt_sockaddr_pton(pIPAddr->IpMask.String,
ift->_ifa.ifa_netmask));
/* next */
if(k++ < (n - 1))
{
ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1);
ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next);
}
else
{
ift->_ifa.ifa_next = nullptr;
}
}
}
if(pAdapterInfo)
_llarp_nt_heap_free(pAdapterInfo);
*ifap = (struct llarp_nt_ifaddrs_t*)ifa;
return true;
}
#if 0
/* Supports both IPv4 and IPv6 addressing. The size of IP_ADAPTER_ADDRESSES
* changes between Windows XP, XP SP1, and Vista with additional members.
*
@ -295,9 +136,6 @@ _llarp_nt_getadaptersinfo(struct llarp_nt_ifaddrs_t** ifap)
* and lower layer down.
*
* Available in Windows XP and Wine 1.3.
*
* NOTE(despair): an inline implementation is provided, much like
* getaddrinfo(3) for old hosts. See "win32_intrnl.*"
*/
static bool
_llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
@ -314,7 +152,7 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
fprintf(stderr, "IP_ADAPTER_ADDRESSES buffer length %lu bytes.\n", dwSize);
#endif
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize);
dwRet = _GetAdaptersAddresses(
dwRet = GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST
| GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME
@ -609,6 +447,10 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
ift->_ifa.ifa_next = (struct llarp_nt_ifaddrs_t*)(ift + 1);
ift = (struct _llarp_nt_ifaddrs_t*)(ift->_ifa.ifa_next);
}
else
{
ift->_ifa.ifa_next = nullptr;
}
}
}
@ -617,18 +459,13 @@ _llarp_nt_getadaptersaddresses(struct llarp_nt_ifaddrs_t** ifap)
*ifap = (struct llarp_nt_ifaddrs_t*)ifa;
return TRUE;
}
#endif
// an implementation of if_nametoindex(3) based on GetAdapterIndex(2)
// with a fallback to GetAdaptersAddresses(2) commented out for now
// unless it becomes evident that the first codepath fails in certain
// edge cases?
static unsigned
_llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
{
ULONG ifIndex;
DWORD /* dwSize = 4096,*/ dwRet;
// IP_ADAPTER_ADDRESSES *pAdapterAddresses = nullptr, *adapter;
DWORD dwSize = 4096, dwRet;
IP_ADAPTER_ADDRESSES *pAdapterAddresses = nullptr, *adapter;
char szAdapterName[256];
if(!ifname)
@ -642,7 +479,6 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
else
return 0;
#if 0
/* fallback to finding index via iterating adapter list */
/* loop to handle interfaces coming online causing a buffer overflow
@ -651,7 +487,7 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
for(unsigned i = 3; i; i--)
{
pAdapterAddresses = (IP_ADAPTER_ADDRESSES*)_llarp_nt_heap_alloc(dwSize);
dwRet = _GetAdaptersAddresses(
dwRet = GetAdaptersAddresses(
AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST,
@ -697,7 +533,6 @@ _llarp_nt_getadaptersaddresses_nametoindex(const char* ifname)
if(pAdapterAddresses)
_llarp_nt_heap_free(pAdapterAddresses);
return 0;
#endif
}
// the emulated getifaddrs(3) itself.
@ -709,7 +544,7 @@ llarp_nt_getifaddrs(struct llarp_nt_ifaddrs_t** ifap)
fprintf(stderr, "llarp_nt_getifaddrs (ifap:%p error:%p)\n", (void*)ifap,
(void*)errno);
#endif
return _llarp_nt_getadaptersinfo(ifap);
return _llarp_nt_getadaptersaddresses(ifap);
}
static void

@ -11,7 +11,6 @@
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#define inet_aton(x, y) inet_pton(AF_INET, x, y)
#endif

@ -411,6 +411,40 @@ llarp_nodedb_del_rc(struct llarp_nodedb *n, const llarp::RouterID &pk)
return n->Remove(pk);
}
bool
llarp_nodedb_select_random_exit(struct llarp_nodedb *n,
llarp::RouterContact &result)
{
const auto sz = n->entries.size();
auto itr = n->entries.begin();
if(sz < 3)
return false;
auto idx = llarp_randint() % sz;
if(idx)
std::advance(itr, idx - 1);
while(itr != n->entries.end())
{
if(itr->second.IsExit())
{
result = itr->second;
return true;
}
++itr;
}
// wrap arround
itr = n->entries.begin();
while(idx--)
{
if(itr->second.IsExit())
{
result = itr->second;
return true;
}
++itr;
}
return false;
}
bool
llarp_nodedb_select_random_hop(struct llarp_nodedb *n,
const llarp::RouterContact &prev,

@ -263,7 +263,11 @@ namespace llarp
{
if(builder->ShouldBuildMore(now))
{
builder->BuildOne();
builder->BuildOne(ePathRoleAny);
}
if(builder->ShouldBuildMoreForRoles(now, ePathRoleExit))
{
builder->BuildOne(ePathRoleExit);
}
}
}
@ -336,8 +340,9 @@ namespace llarp
{
}
Path::Path(const std::vector< RouterContact >& h, PathSet* parent)
: m_PathSet(parent)
Path::Path(const std::vector< RouterContact >& h, PathSet* parent,
PathRole startingRoles)
: m_PathSet(parent), _role(startingRoles)
{
hops.resize(h.size());
size_t hsz = h.size();
@ -442,6 +447,17 @@ namespace llarp
// check to see if this path is dead
if(_status == ePathEstablished)
{
if(SupportsRoles(ePathRoleExit))
{
if(m_LastRecvMessage && now > m_LastRecvMessage
&& now - m_LastRecvMessage > PATH_ALIVE_TIMEOUT)
{
// TODO: send close message
// r->routerProfiling.MarkPathFail(this);
// EnterState(ePathTimeout, now);
return;
}
}
if(m_LastRecvMessage && now > m_LastRecvMessage
&& now - m_LastRecvMessage > PATH_ALIVE_TIMEOUT)
{
@ -530,6 +546,24 @@ namespace llarp
return true;
}
bool
Path::HandleUpdateExitVerifyMessage(
const llarp::routing::UpdateExitVerifyMessage* msg, llarp_router* r)
{
(void)r;
if(m_UpdateExitTX && msg->T == m_UpdateExitTX)
{
if(m_ExitUpdated)
return m_ExitUpdated(this);
}
if(m_CloseExitTX && msg->T == m_CloseExitTX)
{
if(m_ExitClosed)
return m_ExitClosed(this);
}
return false;
}
bool
Path::SendRoutingMessage(const llarp::routing::IMessage* msg,
llarp_router* r)
@ -569,9 +603,9 @@ namespace llarp
bool
Path::HandleDataDiscardMessage(
const llarp::routing::DataDiscardMessage* msg,
__attribute__((unused)) llarp_router* r)
const llarp::routing::DataDiscardMessage* msg, llarp_router* r)
{
MarkActive(r->Now());
if(m_DropHandler)
return m_DropHandler(this, msg->P, msg->S);
return true;
@ -599,7 +633,7 @@ namespace llarp
// persist session with upstream router until the path is done
r->PersistSessionUntil(Upstream(), intro.expiresAt);
MarkActive(now);
// send path latency test
llarp::routing::PathLatencyMessage latency;
latency.T = llarp_randint();
@ -615,15 +649,8 @@ namespace llarp
bool
Path::HandleHiddenServiceFrame(const llarp::service::ProtocolFrame* frame)
{
if(m_DataHandler)
{
if(m_DataHandler(this, frame))
{
m_LastRecvMessage = m_PathSet->Now();
return true;
}
}
return false;
MarkActive(m_PathSet->Now());
return m_DataHandler && m_DataHandler(this, frame);
}
bool
@ -631,13 +658,15 @@ namespace llarp
const llarp::routing::PathLatencyMessage* msg, llarp_router* r)
{
auto now = r->Now();
// TODO: reanimate dead paths if they get this message
if(msg->L == m_LastLatencyTestID && _status == ePathEstablished)
MarkActive(now);
if(msg->L == m_LastLatencyTestID)
{
intro.latency = now - m_LastLatencyTestTime;
llarp::LogDebug("path latency is ", intro.latency,
" ms for tx=", TXID(), " rx=", RXID());
m_LastLatencyTestID = 0;
_status = ePathEstablished;
return true;
}
else
@ -653,6 +682,7 @@ namespace llarp
llarp::routing::DHTMessage reply;
if(!msg->HandleMessage(r->dht, reply.M))
return false;
MarkActive(r->Now());
if(reply.M.size())
return SendRoutingMessage(&reply, r);
return true;
@ -662,19 +692,39 @@ namespace llarp
Path::HandleCloseExitMessage(const llarp::routing::CloseExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
/// allows exits to close from their end
if(SupportsRoles(ePathRoleExit))
{
if(msg->Verify(&r->crypto, Endpoint()))
{
llarp::LogInfo(Name(), " had its exit closed");
_role &= ~ePathRoleExit;
return true;
}
else
llarp::LogError(Name(), " CXM from exit with bad signature");
}
else
llarp::LogError(Name(), " unwarrented CXM");
return false;
}
bool
Path::SendExitRequest(const llarp::routing::ObtainExitMessage* msg,
llarp_router* r)
{
llarp::LogInfo(Name(), " sending exit request to ", Endpoint());
m_ExitObtainTX = msg->T;
return SendRoutingMessage(msg, r);
}
bool
Path::HandleObtainExitMessage(const llarp::routing::ObtainExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
llarp::LogError(Name(), " got unwarrented OXM");
return false;
}
@ -682,9 +732,9 @@ namespace llarp
Path::HandleUpdateExitMessage(const llarp::routing::UpdateExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
llarp::LogError(Name(), " got unwarrented UXM");
return false;
}
@ -692,9 +742,18 @@ namespace llarp
Path::HandleRejectExitMessage(const llarp::routing::RejectExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
if(m_ExitObtainTX && msg->T == m_ExitObtainTX)
{
if(!msg->Verify(&r->crypto, Endpoint()))
{
llarp::LogError(Name(), "RXM invalid signature");
return false;
}
llarp::LogInfo(Name(), " ", Endpoint(), " Rejected exit");
MarkActive(r->Now());
return InformExitResult(msg->B);
}
llarp::LogError(Name(), " got unwarrented RXM");
return false;
}
@ -702,20 +761,50 @@ namespace llarp
Path::HandleGrantExitMessage(const llarp::routing::GrantExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
if(m_ExitObtainTX && msg->T == m_ExitObtainTX)
{
if(!msg->Verify(&r->crypto, Endpoint()))
{
llarp::LogError(Name(), " GXM signature failed");
return false;
}
// we now can send exit traffic
_role |= ePathRoleExit;
llarp::LogInfo(Name(), " ", Endpoint(), " Granted exit");
MarkActive(r->Now());
return InformExitResult(0);
}
llarp::LogError(Name(), " got unwarrented GXM");
return false;
}
bool
Path::InformExitResult(llarp_time_t B)
{
bool result = true;
for(const auto& hook : m_ObtainedExitHooks)
result &= hook(this, B);
m_ObtainedExitHooks.clear();
return result;
}
bool
Path::HandleTransferTrafficMessage(
const llarp::routing::TransferTrafficMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
return false;
// check if we can handle exit data
if(!SupportsRoles(ePathRoleExit))
return false;
// verify sig
if(!msg->Verify(&r->crypto, Endpoint()))
{
llarp::LogError(Name(), " bad signature on inbound traffic");
return false;
}
MarkActive(r->Now());
// handle traffic if we have a handler
return m_ExitTrafficHandler
&& m_ExitTrafficHandler(this, llarp::ConstBuffer(msg->X));
}
} // namespace path

@ -176,8 +176,9 @@ namespace llarp
bool
Builder::SelectHop(llarp_nodedb* db, const RouterContact& prev,
RouterContact& cur, size_t hop)
RouterContact& cur, size_t hop, PathRole roles)
{
(void)roles;
if(hop == 0 && router->NumberOfConnectedRouters())
return router->GetRandomConnectedRouter(cur);
@ -185,7 +186,8 @@ namespace llarp
do
{
--tries;
llarp_nodedb_select_random_hop(db, prev, cur, hop);
if(llarp_nodedb_select_random_hop(db, prev, cur, hop))
break;
} while(router->routerProfiling.IsBad(cur.pubkey) && tries > 0);
return !router->routerProfiling.IsBad(cur.pubkey);
}
@ -204,16 +206,16 @@ namespace llarp
}
void
Builder::BuildOne()
Builder::BuildOne(PathRole roles)
{
std::vector< RouterContact > hops;
if(SelectHops(router->nodedb, hops))
Build(hops);
if(SelectHops(router->nodedb, hops, roles))
Build(hops, roles);
}
bool
Builder::SelectHops(llarp_nodedb* nodedb,
std::vector< RouterContact >& hops)
std::vector< RouterContact >& hops, PathRole roles)
{
hops.resize(numHops);
size_t idx = 0;
@ -221,7 +223,7 @@ namespace llarp
{
if(idx == 0)
{
if(!SelectHop(nodedb, hops[0], hops[0], 0))
if(!SelectHop(nodedb, hops[0], hops[0], 0, roles))
{
llarp::LogError("failed to select first hop");
return false;
@ -229,7 +231,7 @@ namespace llarp
}
else
{
if(!SelectHop(nodedb, hops[idx - 1], hops[idx], idx))
if(!SelectHop(nodedb, hops[idx - 1], hops[idx], idx, roles))
{
/// TODO: handle this failure properly
llarp::LogWarn("Failed to select hop ", idx);
@ -248,14 +250,14 @@ namespace llarp
}
void
Builder::Build(const std::vector< RouterContact >& hops)
Builder::Build(const std::vector< RouterContact >& hops, PathRole roles)
{
lastBuild = Now();
// async generate keys
AsyncPathKeyExchangeContext< Builder >* ctx =
new AsyncPathKeyExchangeContext< Builder >(&router->crypto);
ctx->pathset = this;
auto path = new llarp::path::Path(hops, this);
auto path = new llarp::path::Path(hops, this, roles);
path->SetBuildResultHook(std::bind(&llarp::path::Builder::HandlePathBuilt,
this, std::placeholders::_1));
ctx->AsyncGenerateKeys(path, router->logic, router->tp, this,
@ -278,11 +280,11 @@ namespace llarp
}
void
Builder::ManualRebuild(size_t num)
Builder::ManualRebuild(size_t num, PathRole roles)
{
llarp::LogDebug("manual rebuild ", num);
while(num--)
BuildOne();
BuildOne(roles);
}
} // namespace path

@ -18,6 +18,29 @@ namespace llarp
return m_Paths.size() < m_NumPaths;
}
bool
PathSet::ShouldBuildMoreForRoles(llarp_time_t now, PathRole roles) const
{
const size_t required = MinRequiredForRoles(roles);
size_t has = 0;
for(const auto& item : m_Paths)
{
if(item.second->SupportsRoles(roles))
{
if(!item.second->ExpiresSoon(now))
++has;
}
}
return has < required;
}
size_t
PathSet::MinRequiredForRoles(PathRole roles) const
{
(void)roles;
return 0;
}
void
PathSet::Tick(llarp_time_t now, llarp_router* r)
{
@ -46,7 +69,8 @@ namespace llarp
}
Path*
PathSet::GetEstablishedPathClosestTo(const AlignedBuffer< 32 >& id) const
PathSet::GetEstablishedPathClosestTo(const AlignedBuffer< 32 >& id,
PathRole roles) const
{
Path* path = nullptr;
AlignedBuffer< 32 > dist;
@ -55,6 +79,8 @@ namespace llarp
{
if(!item.second->IsReady())
continue;
if(!item.second->SupportsRoles(roles))
continue;
AlignedBuffer< 32 > localDist = item.second->Endpoint() ^ id;
if(localDist < dist)
{
@ -66,13 +92,13 @@ namespace llarp
}
Path*
PathSet::GetNewestPathByRouter(const RouterID& id) const
PathSet::GetNewestPathByRouter(const RouterID& id, PathRole roles) const
{
Path* chosen = nullptr;
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->IsReady())
if(itr->second->IsReady() && itr->second->SupportsRoles(roles))
{
if(itr->second->Endpoint() == id)
{
@ -88,13 +114,13 @@ namespace llarp
}
Path*
PathSet::GetPathByRouter(const RouterID& id) const
PathSet::GetPathByRouter(const RouterID& id, PathRole roles) const
{
Path* chosen = nullptr;
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->IsReady())
if(itr->second->IsReady() && itr->second->SupportsRoles(roles))
{
if(itr->second->Endpoint() == id)
{
@ -122,6 +148,21 @@ namespace llarp
return nullptr;
}
size_t
PathSet::AvailablePaths(PathRole roles) const
{
size_t count = 0;
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->Status() == ePathEstablished
&& itr->second->SupportsRoles(roles))
++count;
++itr;
}
return count;
}
size_t
PathSet::NumInStatus(PathStatus st) const
{
@ -129,7 +170,7 @@ namespace llarp
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->_status == st)
if(itr->second->Status() == st)
++count;
++itr;
}
@ -232,13 +273,13 @@ namespace llarp
}
Path*
PathSet::PickRandomEstablishedPath() const
PathSet::PickRandomEstablishedPath(PathRole roles) const
{
std::vector< Path* > established;
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->IsReady())
if(itr->second->IsReady() && itr->second->SupportsRoles(roles))
established.push_back(itr->second);
++itr;
}

@ -5,7 +5,11 @@
#include <queue_manager.hpp>
#include <atomic>
#if __cplusplus >= 201703L
#include <optional>
#else
#include <tl/optional.hpp>
#endif
#include <tuple>
namespace llarp
@ -30,12 +34,12 @@ namespace llarp
QueueManager m_manager;
std::atomic<std::uint32_t> m_waitingPoppers;
std::atomic< std::uint32_t > m_waitingPoppers;
util::Semaphore m_popSemaphore;
const char
m_popSemaphorePadding[(2u * Alignment) - sizeof(util::Semaphore)];
std::atomic<std::uint32_t> m_waitingPushers;
std::atomic< std::uint32_t > m_waitingPushers;
util::Semaphore m_pushSemaphore;
const char
m_pushSemaphorePadding[(2u * Alignment) - sizeof(util::Semaphore)];
@ -72,8 +76,11 @@ namespace llarp
// Remove an element from the queue. Block until an element is available
Type
popFront();
#if __cplusplus >= 201703L
std::optional< Type >
#else
tl::optional< Type >
#endif
tryPopFront();
// Remove all elements from the queue. Note this is not atomic, and if
@ -260,7 +267,11 @@ namespace llarp
}
template < typename Type >
#if __cplusplus >= 201703L
std::optional< Type >
#else
tl::optional< Type >
#endif
Queue< Type >::tryPopFront()
{
uint32_t generation;
@ -284,9 +295,12 @@ namespace llarp
// - update the queue
// - notify any waiting pushers
QueuePopGuard popGuard(*this, generation, index);
QueuePopGuard< Type > popGuard(*this, generation, index);
#if __cplusplus >= 201703L
return std::optional< Type >(std::move(m_data[index]));
#else
return tl::optional< Type >(std::move(m_data[index]));
#endif
}
template < typename Type >
@ -382,8 +396,7 @@ namespace llarp
m_waitingPoppers.fetch_sub(1, std::memory_order_relaxed);
}
QueuePopGuard popGuard(*this, generation, index);
QueuePopGuard< Type > popGuard(*this, generation, index);
return Type(std::move(m_data[index]));
}

@ -6,6 +6,7 @@ namespace llarp
{
namespace thread
{
#if __cplusplus >= 201703L
// Turn an enum into its underlying value.
template < typename E >
constexpr auto
@ -13,7 +14,14 @@ namespace llarp
{
return static_cast< std::underlying_type_t< E > >(e);
}
#else
template < typename E >
constexpr uint32_t
to_underlying(E e) noexcept
{
return static_cast< uint32_t >(e);
}
#endif
static constexpr uint32_t GENERATION_COUNT_SHIFT = 0x2;
// Max number of generations which can be held in an uint32_t.
@ -159,7 +167,7 @@ namespace llarp
(void)m_pushPadding;
(void)m_popPadding;
m_states = new std::atomic<std::uint32_t>[capacity];
m_states = new std::atomic< std::uint32_t >[capacity];
for(size_t i = 0; i < capacity; ++i)
{
@ -435,7 +443,7 @@ namespace llarp
for(;;)
{
u_int32_t endCombinedIndex =
uint32_t endCombinedIndex =
(endGeneration * static_cast< uint32_t >(m_capacity)) + endIndex;
if(circularDifference(endCombinedIndex, loadedCombinedIndex,
@ -448,9 +456,9 @@ namespace llarp
assert(0 < circularDifference(endCombinedIndex, loadedCombinedIndex,
m_maxCombinedIndex + 1));
u_int32_t currIdx =
uint32_t currIdx =
static_cast< uint32_t >(loadedCombinedIndex % m_capacity);
u_int32_t currGen =
uint32_t currGen =
static_cast< uint32_t >(loadedCombinedIndex / m_capacity);
// Try to swap this cell from Full to Reading.

@ -46,12 +46,15 @@ struct TryConnectJob
void
Failed()
{
llarp::LogInfo("session to ", rc.pubkey, " closed");
link->CloseSessionTo(rc.pubkey);
}
void
Success()
{
llarp::LogInfo("established session with ", rc.pubkey);
router->FlushOutboundFor(rc.pubkey, link);
}
void
@ -169,25 +172,20 @@ bool
llarp_router::SendToOrQueue(const llarp::RouterID &remote,
const llarp::ILinkMessage *msg)
{
if(inboundLinks.size() == 0)
for(const auto &link : inboundLinks)
{
if(outboundLink->HasSessionTo(remote))
if(link->HasSessionTo(remote))
{
SendTo(remote, msg, outboundLink.get());
SendTo(remote, msg, link.get());
return true;
}
}
else
if(outboundLink && outboundLink->HasSessionTo(remote))
{
for(const auto &link : inboundLinks)
{
if(link->HasSessionTo(remote))
{
SendTo(remote, msg, link.get());
return true;
}
}
SendTo(remote, msg, outboundLink.get());
return true;
}
// no link available
// this will create an entry in the obmq if it's not already there
@ -331,14 +329,11 @@ llarp_router::SaveRC()
void
llarp_router::Close()
{
llarp::LogInfo("Closing ", inboundLinks.size(), " server bindings");
for(const auto &link : inboundLinks)
{
link->Stop();
}
inboundLinks.clear();
llarp::LogInfo("Closing LokiNetwork client");
if(outboundLink)
{
outboundLink->Stop();
@ -356,6 +351,7 @@ llarp_router::on_verify_client_rc(llarp_async_verify_rc *job)
llarp::PubKey pk(job->rc.pubkey);
router->FlushOutboundFor(pk, router->GetLinkWithSessionByPubkey(pk));
delete ctx;
delete job;
}
void
@ -373,6 +369,8 @@ llarp_router::on_verify_server_rc(llarp_async_verify_rc *job)
// was an outbound attempt
ctx->establish_job->Failed();
}
delete ctx;
delete job;
router->DiscardOutboundFor(pk);
return;
}
@ -400,7 +398,10 @@ llarp_router::on_verify_server_rc(llarp_async_verify_rc *job)
{
ctx->establish_job->Success();
}
router->FlushOutboundFor(pk, router->GetLinkWithSessionByPubkey(pk));
else
router->FlushOutboundFor(pk, router->GetLinkWithSessionByPubkey(pk));
delete ctx;
delete job;
}
void
@ -434,6 +435,10 @@ llarp_router::TryEstablishTo(const llarp::RouterID &remote)
std::bind(&llarp_router::HandleDHTLookupForTryEstablishTo, this, remote,
std::placeholders::_1));
}
else
{
llarp::LogWarn("not connecting to ", remote, " as it's unreliable");
}
}
void
@ -491,8 +496,13 @@ llarp_router::Tick()
llarp::LogDebug("establish to ", itr->first);
TryEstablishTo(itr->first);
}
++itr;
}
else
{
llarp::LogInfo("commit to ", itr->first, " expired");
itr = m_PersistingSessions.erase(itr);
}
++itr;
}
}
@ -536,9 +546,8 @@ llarp_router::SendTo(llarp::RouterID remote, const llarp::ILinkMessage *msg,
llarp::LogDebug("send ", buf.sz, " bytes to ", remote);
if(selected)
{
if(!selected->SendTo(remote, buf))
llarp::LogWarn("message to ", remote, " was dropped");
return;
if(selected->SendTo(remote, buf))
return;
}
bool sent = outboundLink->SendTo(remote, buf);
if(!sent)
@ -567,10 +576,8 @@ llarp_router::SessionClosed(const llarp::RouterID &remote)
{
__llarp_dht_remove_peer(dht, remote);
// remove from valid routers if it's a valid router
auto itr = validRouters.find(remote);
if(itr == validRouters.end())
return;
validRouters.erase(itr);
validRouters.erase(remote);
llarp::LogInfo("Session to ", remote, " fully closed");
}
llarp::ILinkLayer *
@ -656,12 +663,26 @@ llarp_router::async_verify_RC(const llarp::RouterContact &rc)
// job->crypto = &crypto; // we already have this
job->cryptoworker = tp;
job->diskworker = disk;
if(rc.IsPublicRouter())
job->hook = &llarp_router::on_verify_server_rc;
if(rpcCaller && rc.IsPublicRouter())
{
rpcCaller->VerifyRouter(rc.pubkey, [job, ctx](llarp::PubKey, bool valid) {
if(valid)
llarp_nodedb_async_verify(job);
else
{
delete job;
delete ctx;
}
});
}
else
job->hook = &llarp_router::on_verify_client_rc;
llarp_nodedb_async_verify(job);
{
if(rc.IsPublicRouter())
job->hook = &llarp_router::on_verify_server_rc;
else
job->hook = &llarp_router::on_verify_client_rc;
llarp_nodedb_async_verify(job);
}
}
void
@ -686,6 +707,8 @@ llarp_router::Run()
llarp::LogInfo("Bound RPC server to ", rpcBindAddr);
}
llarp_threadpool_start(tp);
routerProfiling.Load(routerProfilesFile.c_str());
llarp::Addr publicAddr(this->addrInfo);
@ -751,7 +774,16 @@ llarp_router::Run()
// set public signing key
_rc.pubkey = llarp::seckey_topublic(identity);
llarp::LogInfo("Your Identity pubkey ", rc().pubkey);
if(ExitEnabled())
{
llarp::nuint32_t a = publicAddr.xtonl();
// TODO: enable this once the network can serialize xi
//_rc.exits.emplace_back(_rc.pubkey, a);
llarp::LogInfo(
"Neato tehl33toh, You are a freaking exit relay. w00t!!!!! your exit "
"is advertised as exiting at ",
a);
}
llarp::LogInfo("Signing rc...");
if(!_rc.Sign(&crypto, identity))
{
@ -893,7 +925,8 @@ llarp_router::InitServiceNode()
llarp::LogInfo("accepting transit traffic");
paths.AllowTransit();
llarp_dht_allow_transit(dht);
return exitContext.AddExitEndpoint("default-connectivity", exitConf);
exitContext.AddExitEndpoint("default-connectivity", exitConf);
return true;
}
void
@ -1197,7 +1230,13 @@ namespace llarp
{
self->defaultIfName = val;
}
if(!StrEq(key, "profiles"))
if(StrEq(key, "profiles"))
{
self->routerProfilesFile = val;
self->routerProfiling.Load(val);
llarp::LogInfo("setting profiles to ", self->routerProfilesFile);
}
else
{
self->exitConf.insert(std::make_pair(key, val));
}
@ -1245,23 +1284,6 @@ namespace llarp
{
self->connect[key] = val;
}
else if(StrEq(section, "network"))
{
if(StrEq(key, "profiles"))
{
self->routerProfilesFile = val;
self->routerProfiling.Load(val);
llarp::LogInfo("setting profiles to ", self->routerProfilesFile);
}
if(StrEq(key, "min-connected"))
{
self->minConnectedRouters = std::max(atoi(val), 0);
}
if(StrEq(key, "max-connected"))
{
self->maxConnectedRouters = std::max(atoi(val), 1);
}
}
else if(StrEq(section, "router"))
{
if(StrEq(key, "nickname"))
@ -1313,5 +1335,5 @@ namespace llarp
self->publicOverride = true;
}
}
}
} // namespace llarp
} // namespace llarp

@ -25,6 +25,7 @@
#include "crypto.hpp"
#include "fs.hpp"
#include "mem.hpp"
#include "str.hpp"
bool
llarp_findOrCreateEncryption(llarp_crypto *crypto, const char *fpath,
@ -52,6 +53,9 @@ struct llarp_router
// our router contact
llarp::RouterContact _rc;
/// should we obey the service node whitelist?
bool whitelistRouters = false;
const llarp::RouterContact &
rc() const
{
@ -102,6 +106,15 @@ struct llarp_router
/// default exit config
llarp::exit::Context::Config_t exitConf;
bool
ExitEnabled() const
{
auto itr = exitConf.find("exit");
if(itr == exitConf.end())
return false;
return llarp::IsTrueValue(itr->second.c_str());
}
bool
CreateDefaultHiddenService();
@ -144,6 +157,11 @@ struct llarp_router
std::unordered_map< llarp::RouterID, llarp_time_t, llarp::RouterID::Hash >
m_PersistingSessions;
// lokinet routers from lokid, maps pubkey to when we think it will expire,
// set to max value right now
std::unordered_map< llarp::PubKey, llarp_time_t, llarp::PubKey::Hash >
lokinetRouters;
// TODO: change me if needed
const std::string defaultUpstreamResolver = "1.1.1.1:53";
std::list< std::string > upstreamResolvers;

@ -22,45 +22,52 @@ namespace llarp
}
void
PopulateReqHeaders(__attribute__((unused)) abyss::http::Headers_t& hdr)
PopulateReqHeaders(abyss::http::Headers_t& hdr)
{
(void)hdr;
// TODO: add http auth
}
};
struct VerifyRouterHandler : public CallerHandler
struct GetServiceNodeListHandler final : public CallerHandler
{
llarp::PubKey pk;
std::function< void(llarp::PubKey, bool) > handler;
using PubkeyList_t = std::vector< llarp::PubKey >;
using Callback_t = std::function< void(const PubkeyList_t&, bool) >;
~VerifyRouterHandler()
~GetServiceNodeListHandler()
{
}
Callback_t handler;
VerifyRouterHandler(::abyss::http::ConnImpl* impl, const llarp::PubKey& k,
std::function< void(llarp::PubKey, bool) > h)
: CallerHandler(impl), pk(k), handler(h)
GetServiceNodeListHandler(::abyss::http::ConnImpl* impl, Callback_t h)
: CallerHandler(impl), handler(h)
{
}
bool
HandleResponse(__attribute__((unused))
const ::abyss::http::RPC_Response& response)
HandleResponse(const ::abyss::http::RPC_Response& response)
{
handler(pk, true);
(void)response;
// TODO: get keys from response
PubkeyList_t keys;
handler(keys, true);
return true;
}
void
HandleError()
{
llarp::LogInfo("failed to verify router ", pk);
handler(pk, false);
handler({}, false);
}
};
struct CallerImpl : public ::abyss::http::JSONRPC
{
llarp_router* router;
llarp_time_t m_NextKeyUpdate;
const llarp_time_t KeyUpdateInterval = 1000 * 60 * 2;
using PubkeyList_t = GetServiceNodeListHandler::PubkeyList_t;
CallerImpl(llarp_router* r) : ::abyss::http::JSONRPC(), router(r)
{
}
@ -68,9 +75,26 @@ namespace llarp
void
Tick()
{
llarp_time_t now = router->Now();
if(now >= m_NextKeyUpdate)
{
AsyncUpdatePubkeyList();
m_NextKeyUpdate = now + KeyUpdateInterval;
}
Flush();
}
void
AsyncUpdatePubkeyList()
{
llarp::LogInfo("Updating service node list");
::abyss::json::Value params;
params.SetObject();
QueueRPC("get_all_service_node_keys", std::move(params),
std::bind(&CallerImpl::NewAsyncUpdatePubkeyListConn, this,
std::placeholders::_1));
}
bool
Start(const std::string& remote)
{
@ -78,21 +102,43 @@ namespace llarp
}
abyss::http::IRPCClientHandler*
NewConn(PubKey k, std::function< void(llarp::PubKey, bool) > handler,
abyss::http::ConnImpl* impl)
NewAsyncUpdatePubkeyListConn(abyss::http::ConnImpl* impl)
{
return new VerifyRouterHandler(impl, k, handler);
return new GetServiceNodeListHandler(
impl,
std::bind(&CallerImpl::HandleServiceNodeListUpdated, this,
std::placeholders::_1, std::placeholders::_2));
}
void
AsyncVerifyRouter(llarp::PubKey pk,
std::function< void(llarp::PubKey, bool) > handler)
VerifyRouter(llarp::PubKey pk,
std::function< void(llarp::PubKey, bool) > handler)
{
abyss::json::Value params;
params.SetObject();
QueueRPC("get_service_node", std::move(params),
std::bind(&CallerImpl::NewConn, this, pk, handler,
std::placeholders::_1));
if(router->whitelistRouters)
{
auto itr = router->lokinetRouters.find(pk);
handler(pk, itr != router->lokinetRouters.end());
}
else
{
handler(pk, true);
}
}
void
HandleServiceNodeListUpdated(const PubkeyList_t& list, bool updated)
{
if(updated)
{
router->lokinetRouters.clear();
for(const auto& pk : list)
router->lokinetRouters.emplace(
std::make_pair(pk, std::numeric_limits< llarp_time_t >::max()));
llarp::LogInfo("updated service node list, we have ",
router->lokinetRouters.size(), " authorized routers");
}
else
llarp::LogError("service node list not updated");
}
~CallerImpl()
@ -112,6 +158,30 @@ namespace llarp
{
}
bool
ListExitLevels(Response& resp) const
{
llarp::exit::Context::TrafficStats stats;
router->exitContext.CalculateExitTraffic(stats);
auto& alloc = resp.GetAllocator();
abyss::json::Value exits;
exits.SetArray();
auto itr = stats.begin();
while(itr != stats.end())
{
abyss::json::Value info, ident;
info.SetObject();
ident.SetString(itr->first.ToHex().c_str(), alloc);
info.AddMember("ident", ident, alloc);
info.AddMember("tx", abyss::json::Value(itr->second.first), alloc);
info.AddMember("rx", abyss::json::Value(itr->second.second), alloc);
exits.PushBack(info, alloc);
++itr;
}
resp.AddMember("result", exits, alloc);
return true;
}
bool
ListNeighboors(Response& resp) const
{
@ -148,6 +218,10 @@ namespace llarp
{
return ListNeighboors(response);
}
else if(method == "llarp.admin.exit.list")
{
return ListExitLevels(response);
}
return false;
}
};
@ -232,8 +306,8 @@ namespace llarp
}
void
AsyncVerifyRouter(llarp::PubKey pk,
std::function< void(llarp::PubKey, bool) > result)
VerifyRouter(llarp::PubKey pk,
std::function< void(llarp::PubKey, bool) > result)
{
// always allow routers when not using libabyss
result(pk, true);
@ -258,10 +332,10 @@ namespace llarp
}
void
Caller::AsyncVerifyRouter(
llarp::PubKey pk, std::function< void(llarp::PubKey, bool) > handler)
Caller::VerifyRouter(llarp::PubKey pk,
std::function< void(llarp::PubKey, bool) > handler)
{
m_Impl->AsyncVerifyRouter(pk, handler);
m_Impl->VerifyRouter(pk, handler);
}
Server::Server(llarp_router* r) : m_Impl(new ServerImpl(r))

@ -105,9 +105,9 @@ namespace llarp
auto itr = m_Endpoints.begin();
while(itr != m_Endpoints.end())
{
if(itr->second->HasAddress(addr))
if(itr->second->HasAddress(addr.data()))
{
ip = itr->second->ObtainIPForAddr(addr);
ip = itr->second->ObtainIPForAddr(addr.data());
return true;
}
++itr;
@ -115,7 +115,7 @@ namespace llarp
itr = m_Endpoints.find("default");
if(itr != m_Endpoints.end())
{
ip = itr->second->ObtainIPForAddr(addr);
ip = itr->second->ObtainIPForAddr(addr.data());
return true;
}
return false;
@ -151,7 +151,7 @@ namespace llarp
llarp::LogError("No tunnel endpoint found");
return zero;
}
return tunEndpoint->ObtainIPForAddr(addr);
return tunEndpoint->ObtainIPForAddr(addr.data());
}
bool

@ -38,11 +38,6 @@ namespace llarp
if(addr.FromString(v))
m_PrefetchAddrs.insert(addr);
}
if(k == "netns")
{
m_NetNS = v;
m_OnInit.push_back(std::bind(&Endpoint::IsolateNetwork, this));
}
if(k == "min-latency")
{
auto val = atoi(v.c_str());
@ -55,11 +50,7 @@ namespace llarp
bool
Endpoint::IsolateNetwork()
{
llarp::LogInfo("isolating network to namespace ", m_NetNS);
m_IsolatedWorker = llarp_init_isolated_net_threadpool(
m_NetNS.c_str(), &SetupIsolatedNetwork, &RunIsolatedMainLoop, this);
m_IsolatedLogic = llarp_init_single_process_logic(m_IsolatedWorker);
return true;
return false;
}
llarp_ev_loop*
@ -1040,11 +1031,14 @@ namespace llarp
}
bool
Endpoint::SendToOrQueue(const Address& remote, llarp_buffer_t data,
Endpoint::SendToOrQueue(const byte_t* addr, llarp_buffer_t data,
ProtocolType t)
{
service::Address remote(addr);
// inbound converstation
auto now = Now();
{
auto itr = m_AddressToService.find(remote);
if(itr != m_AddressToService.end())
@ -1512,7 +1506,8 @@ namespace llarp
bool
Endpoint::OutboundContext::SelectHop(llarp_nodedb* db,
const RouterContact& prev,
RouterContact& cur, size_t hop)
RouterContact& cur, size_t hop,
llarp::path::PathRole roles)
{
if(m_NextIntro.router.IsZero())
return false;
@ -1533,7 +1528,7 @@ namespace llarp
return false;
}
}
return path::Builder::SelectHop(db, prev, cur, hop);
return path::Builder::SelectHop(db, prev, cur, hop, roles);
}
uint64_t
@ -1550,7 +1545,8 @@ namespace llarp
{
if(markedBad)
return false;
bool should = path::Builder::ShouldBuildMore(now);
bool should = path::Builder::ShouldBuildMoreForRoles(
now, llarp::path::ePathRoleOutboundHS);
// determinte newest intro
Introduction intro;
if(!GetNewestIntro(intro))

@ -1,5 +1,4 @@
#include "threadpool.hpp"
#include <pthread.h>
#include <cstring>
#include <llarp/time.hpp>
@ -8,215 +7,21 @@
#include "logger.hpp"
#if(__FreeBSD__) || (__OpenBSD__) || (__NetBSD__)
#include <pthread_np.h>
#endif
#ifdef __linux__
#ifndef ANDROID
#include <llarp/linux/netns.hpp>
#endif
#endif
namespace llarp
{
namespace thread
{
void
Pool::Spawn(size_t workers, const char *name)
{
stop = false;
while(workers--)
{
threads.emplace_back([this, name] {
if(name)
{
#if(__APPLE__ && __MACH__)
pthread_setname_np(name);
#elif(__FreeBSD__) || (__OpenBSD__) || (__NetBSD__)
pthread_set_name_np(pthread_self(), name);
#elif(__linux__) || (__MINGW32__)
pthread_setname_np(pthread_self(), name);
#endif
}
for(;;)
{
Job_t job;
{
lock_t lock(this->queue_mutex);
this->condition.WaitUntil(
lock, [this] { return this->stop || !this->jobs.empty(); });
if(this->stop)
{
// discard pending jobs
while(this->jobs.size())
{
this->jobs.pop();
}
return;
}
job = std::move(this->jobs.top());
this->jobs.pop();
}
// do work
job();
}
});
}
}
void
Pool::Stop()
{
{
lock_t lock(queue_mutex);
stop = true;
}
condition.NotifyAll();
}
void
Pool::Join()
{
for(auto &t : threads)
t.join();
threads.clear();
done.NotifyAll();
}
void
Pool::QueueJob(const llarp_thread_job &job)
{
{
lock_t lock(queue_mutex);
// don't allow enqueueing after stopping the pool
if(stop)
return;
jobs.emplace(ids++, job);
}
condition.NotifyOne();
}
void
IsolatedPool::Spawn(size_t workers, const char *name)
{
IsolatedPool *self = this;
self->IsolatedName = name;
self->m_IsolatedWorkers = workers;
m_isolated = new std::thread([self] {
if(!self->IsolateCurrentProcess())
{
llarp::LogError("isolation failed: ", strerror(errno));
self->Fail();
return;
}
llarp::LogInfo("spawning isolated environment");
self->Pool::Spawn(self->m_IsolatedWorkers, self->IsolatedName);
if(self->Isolated())
{
self->MainLoop();
}
});
}
void
IsolatedPool::Join()
{
Pool::Join();
if(m_isolated)
{
m_isolated->join();
delete m_isolated;
m_isolated = nullptr;
}
}
_NetIsolatedPool::_NetIsolatedPool(
std::function< bool(void *, bool) > setupNet,
std::function< void(void *) > runMain, void *user)
: IsolatedPool(0)
{
m_NetSetup = setupNet;
m_RunMain = runMain;
m_user = user;
}
#ifdef __linux__
#if defined(ANDROID) || defined(RPI)
#else
struct LinuxNetNSIsolatedPool : public _NetIsolatedPool
{
LinuxNetNSIsolatedPool(std::function< bool(void *, bool) > setup,
std::function< void(void *) > run, void *user)
: _NetIsolatedPool(setup, run, user)
{
}
bool
IsolateNetwork()
{
return ::llarp::GNULinux::NetNSSwitch(IsolatedName);
}
};
typedef LinuxNetNSIsolatedPool NetIsolatedPool;
#define NET_ISOLATION_SUPPORTED
#endif
#endif
#if defined(__FreeBSD__)
struct FreeBSDJailedThreadPool : public _NetIsolatedPool
{
FreeBSDJailedThreadPool(std::function< bool(void *, bool) > setup,
std::function< void(void *) > run, void *user)
: _NetIsolatedPool(setup, run, user)
{
}
bool
IsolateNetwork()
{
// TODO: implement me
return false;
}
};
typedef FreeBSDJailedThreadPool NetIsolatedPool;
#define NET_ISOLATION_SUPPORTED
#endif
} // namespace thread
} // namespace llarp
struct llarp_threadpool
{
llarp::thread::Pool *impl;
std::unique_ptr< llarp::thread::Pool > impl;
llarp::util::Mutex m_access;
uint32_t ids = 0;
std::queue< llarp::thread::Pool::Job_t > jobs;
std::queue< std::function< void(void) > > jobs;
llarp_threadpool(int workers, const char *name, bool isolate,
__attribute__((unused)) setup_net_func setup = nullptr,
__attribute__((unused)) run_main_func runmain = nullptr,
__attribute__((unused)) void *user = nullptr)
llarp_threadpool(int workers, const char *name)
{
#ifdef NET_ISOLATION_SUPPORTED
if(isolate)
impl = new llarp::thread::NetIsolatedPool(setup, runmain, user);
else
#else
if(isolate)
{
llarp::LogError("network isolation not supported");
}
#endif
impl = new llarp::thread::Pool();
impl->Spawn(workers, name);
(void)name;
impl.reset(new llarp::thread::Pool(workers, workers * 128));
}
llarp_threadpool() : impl(nullptr)
llarp_threadpool()
{
}
};
@ -226,7 +31,7 @@ llarp_init_threadpool(int workers, const char *name)
{
if(workers <= 0)
workers = 1;
return new llarp_threadpool(workers, name, false);
return new llarp_threadpool(workers, name);
}
struct llarp_threadpool *
@ -235,24 +40,19 @@ llarp_init_same_process_threadpool()
return new llarp_threadpool();
}
struct llarp_threadpool *
llarp_init_isolated_net_threadpool(const char *name, setup_net_func setup,
run_main_func runmain, void *context)
{
return new llarp_threadpool(1, name, true, setup, runmain, context);
}
void
llarp_threadpool_join(struct llarp_threadpool *pool)
{
llarp::LogDebug("threadpool join");
if(pool->impl)
pool->impl->Join();
pool->impl->drain();
}
void
llarp_threadpool_start(__attribute__((unused)) struct llarp_threadpool *pool)
{ /** no op */
llarp_threadpool_start(struct llarp_threadpool *pool)
{
if(pool->impl)
pool->impl->start();
}
void
@ -260,18 +60,16 @@ llarp_threadpool_stop(struct llarp_threadpool *pool)
{
llarp::LogDebug("threadpool stop");
if(pool->impl)
pool->impl->Stop();
pool->impl->stop();
}
void
llarp_threadpool_wait(struct llarp_threadpool *pool)
{
llarp::util::Mutex mtx;
llarp::LogDebug("threadpool wait");
if(pool->impl)
{
llarp::util::Lock lock(mtx);
pool->impl->done.Wait(lock);
pool->impl->drain();
}
}
@ -280,12 +78,12 @@ llarp_threadpool_queue_job(struct llarp_threadpool *pool,
struct llarp_thread_job job)
{
if(pool->impl)
pool->impl->QueueJob(job);
pool->impl->addJob(std::bind(job.work, job.user));
else
{
// single threaded mode
llarp::util::Lock lock(pool->m_access);
pool->jobs.emplace(++pool->ids, job);
pool->jobs.emplace(std::bind(job.work, job.user));
}
}
@ -294,7 +92,7 @@ llarp_threadpool_tick(struct llarp_threadpool *pool)
{
while(pool->jobs.size())
{
llarp::thread::Pool::Job_t job;
std::function< void(void) > job;
{
llarp::util::Lock lock(pool->m_access);
job = std::move(pool->jobs.front());

@ -4,11 +4,7 @@
#include <llarp/threadpool.h>
#include <llarp/threading.hpp>
#include <functional>
#include <queue>
#include <thread>
#include <vector>
#include "thread_pool.hpp"
namespace llarp
{
@ -16,64 +12,16 @@ namespace llarp
{
typedef util::Mutex mtx_t;
typedef util::Lock lock_t;
struct Pool
{
virtual void
Spawn(size_t sz, const char* name);
void
QueueJob(const llarp_thread_job& job);
virtual void
Join();
void
Stop();
std::vector< std::thread > threads;
struct Job_t
{
uint32_t id;
void* user;
llarp_thread_work_func work;
Job_t() = default;
Job_t(uint32_t jobid, const llarp_thread_job& j)
: id(jobid), user(j.user), work(j.work)
{
}
bool
operator<(const Job_t& j) const
{
return id < j.id;
}
void
operator()() const
{
work(user);
}
};
std::priority_queue< Job_t > jobs;
uint32_t ids = 0;
mtx_t queue_mutex;
util::Condition condition;
util::Condition done;
bool stop;
};
using Pool = ThreadPool;
struct IsolatedPool : public Pool
{
IsolatedPool(int flags) : Pool(), m_flags(flags)
IsolatedPool(size_t workers, int flags)
: Pool(workers, workers * 128), m_flags(flags)
{
}
virtual void
Spawn(size_t workers, const char* name);
void
Join();

@ -15,7 +15,7 @@ namespace llarp
bool
TransitHop::Expired(llarp_time_t now) const
{
return now > ExpireTime();
return now >= ExpireTime();
}
llarp_time_t
@ -153,19 +153,57 @@ namespace llarp
TransitHop::HandleObtainExitMessage(
const llarp::routing::ObtainExitMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
return false;
if(msg->Verify(&r->crypto)
&& r->exitContext.ObtainNewExit(msg->I, info.rxID, msg->E != 0))
{
llarp::routing::GrantExitMessage grant;
grant.S = NextSeqNo();
grant.T = msg->T;
if(!grant.Sign(&r->crypto, r->identity))
{
llarp::LogError("Failed to sign grant exit message");
return false;
}
return SendRoutingMessage(&grant, r);
}
// TODO: exponential backoff
// TODO: rejected policies
llarp::routing::RejectExitMessage reject;
reject.S = NextSeqNo();
reject.T = msg->T;
if(!reject.Sign(&r->crypto, r->identity))
{
llarp::LogError("Failed to sign reject exit message");
return false;
}
return SendRoutingMessage(&reject, r);
}
bool
TransitHop::HandleCloseExitMessage(
const llarp::routing::CloseExitMessage* msg, llarp_router* r)
{
// TODO: implement me
llarp::routing::DataDiscardMessage discard(info.rxID, msg->S);
auto ep = r->exitContext.FindEndpointForPath(info.rxID);
if(ep && msg->Verify(&r->crypto, ep->PubKey()))
{
ep->Close();
// ep is now gone af
llarp::routing::CloseExitMessage reply;
reply.S = NextSeqNo();
if(reply.Sign(&r->crypto, r->identity))
return SendRoutingMessage(&reply, r);
}
return SendRoutingMessage(&discard, r);
}
bool
TransitHop::HandleUpdateExitVerifyMessage(
const llarp::routing::UpdateExitVerifyMessage* msg, llarp_router* r)
{
(void)msg;
(void)r;
llarp::LogError("unwarranted exit verify on ", info);
return false;
}
@ -173,19 +211,32 @@ namespace llarp
TransitHop::HandleUpdateExitMessage(
const llarp::routing::UpdateExitMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
return false;
auto ep = r->exitContext.FindEndpointForPath(msg->P);
if(ep)
{
if(!msg->Verify(&r->crypto, ep->PubKey()))
return false;
if(ep->UpdateLocalPath(info.rxID))
{
llarp::routing::UpdateExitVerifyMessage reply;
reply.T = msg->T;
reply.S = NextSeqNo();
return SendRoutingMessage(&reply, r);
}
}
// on fail tell message was discarded
llarp::routing::DataDiscardMessage discard(info.rxID, msg->S);
return SendRoutingMessage(&discard, r);
}
bool
TransitHop::HandleRejectExitMessage(
const llarp::routing::RejectExitMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
llarp::LogError(info, " got unwarrented RXM");
return false;
}
@ -193,9 +244,9 @@ namespace llarp
TransitHop::HandleGrantExitMessage(
const llarp::routing::GrantExitMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
llarp::LogError(info, " got unwarrented GXM");
return false;
}
@ -203,10 +254,27 @@ namespace llarp
TransitHop::HandleTransferTrafficMessage(
const llarp::routing::TransferTrafficMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
return false;
auto endpoint = r->exitContext.FindEndpointForPath(info.rxID);
if(endpoint)
{
if(msg->Verify(&r->crypto, endpoint->PubKey()))
{
if(endpoint->SendOutboundTraffic(llarp::ConstBuffer(msg->X)))
return true;
else
llarp::LogError("failed to send outbound traffic for exit on ",
info);
}
else
{
llarp::LogError("bad signature on exit traffic on ", info);
}
}
else
llarp::LogError("No exit endpoint on ", info);
// discarded
llarp::routing::DataDiscardMessage discard(info.rxID, msg->S);
return SendRoutingMessage(&discard, r);
}
bool
@ -214,25 +282,26 @@ namespace llarp
const llarp::routing::PathTransferMessage* msg, llarp_router* r)
{
auto path = r->paths.GetPathForTransfer(msg->P);
llarp::routing::DataDiscardMessage discarded(msg->P, msg->S);
if(!path)
{
llarp::routing::DataDiscardMessage discarded(msg->P, msg->S);
path = r->paths.GetPathForTransfer(msg->from);
return path && path->SendRoutingMessage(&discarded, r);
return SendRoutingMessage(&discarded, r);
}
byte_t tmp[service::MAX_PROTOCOL_MESSAGE_SIZE];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!msg->T.BEncode(&buf))
{
llarp::LogWarn("failed to transfer data message, encode failed");
return false;
llarp::LogWarn(info, " failed to transfer data message, encode failed");
return SendRoutingMessage(&discarded, r);
}
// rewind0
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// send
return path->HandleDownstream(buf, msg->Y, r);
if(path->HandleDownstream(buf, msg->Y, r))
return true;
return SendRoutingMessage(&discarded, r);
}
} // namespace path

@ -1,315 +0,0 @@
#if defined(__MINGW32__) && !defined(_WIN64)
/*
* Contains routines missing from WS2_32.DLL until 2006, if yer using
* Microsoft C/C++, then this code is irrelevant, as the official
* Platform SDK already links against these routines in the correct
* libraries.
*
* -despair86 30/07/18
*/
// these need to be in a specific order
#include <assert.h>
#include <llarp/net.h>
#include <windows.h>
#include <iphlpapi.h>
#if WINNT_CROSS_COMPILE && !NTSTATUS
typedef LONG NTSTATUS;
#endif
#include "win32_intrnl.h"
const char *
inet_ntop(int af, const void *src, char *dst, size_t size)
{
int address_length;
DWORD string_length = size;
struct sockaddr_storage sa;
struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
memset(&sa, 0, sizeof(sa));
switch(af)
{
case AF_INET:
address_length = sizeof(struct sockaddr_in);
sin->sin_family = af;
memcpy(&sin->sin_addr, src, sizeof(struct in_addr));
break;
case AF_INET6:
address_length = sizeof(struct sockaddr_in6);
sin6->sin6_family = af;
memcpy(&sin6->sin6_addr, src, sizeof(struct in6_addr));
break;
default:
return NULL;
}
if(WSAAddressToString((LPSOCKADDR)&sa, address_length, NULL, dst,
&string_length)
== 0)
{
return dst;
}
return NULL;
}
int
inet_pton(int af, const char *src, void *dst)
{
int address_length;
struct sockaddr_storage sa;
struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
switch(af)
{
case AF_INET:
address_length = sizeof(struct sockaddr_in);
break;
case AF_INET6:
address_length = sizeof(struct sockaddr_in6);
break;
default:
return -1;
}
if(WSAStringToAddress((LPTSTR)src, af, NULL, (LPSOCKADDR)&sa, &address_length)
== 0)
{
switch(af)
{
case AF_INET:
memcpy(dst, &sin->sin_addr, sizeof(struct in_addr));
break;
case AF_INET6:
memcpy(dst, &sin6->sin6_addr, sizeof(struct in6_addr));
break;
}
return 1;
}
return 0;
}
typedef struct _InterfaceIndexTable
{
DWORD numIndexes;
IF_INDEX indexes[1];
} InterfaceIndexTable;
// windows 2000
// todo(despair86): implement IPv6 detection using
// the ipv6 preview stack/adv net pack from 1999/2001
DWORD FAR PASCAL
_GetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved,
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
PULONG pOutBufLen)
{
InterfaceIndexTable *indexTable;
IFInfo ifInfo;
int i;
ULONG ret, requiredSize = 0;
PIP_ADAPTER_ADDRESSES currentAddress;
PUCHAR currentLocation;
HANDLE tcpFile;
(void)(Family);
if(!pOutBufLen)
return ERROR_INVALID_PARAMETER;
if(Reserved)
return ERROR_INVALID_PARAMETER;
indexTable = getInterfaceIndexTable();
if(!indexTable)
return ERROR_NOT_ENOUGH_MEMORY;
ret = openTcpFile(&tcpFile, FILE_READ_DATA);
if(!NT_SUCCESS(ret))
return ERROR_NO_DATA;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
/* The whole struct */
requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
/* Friendly name */
if(!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
requiredSize +=
strlen((char *)ifInfo.if_info.ent.if_descr) + 1; // FIXME
/* Adapter name */
requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
/* Unicast address */
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
/* FIXME: Implement multicast, anycast, and dns server stuff */
/* FIXME: Implement dns suffix and description */
requiredSize += 2 * sizeof(WCHAR);
/* We're only going to implement what's required for XP SP0 */
}
}
#ifdef DEBUG
fprintf(stderr, "size: %ld, requiredSize: %ld\n", *pOutBufLen, requiredSize);
#endif
if(!pAdapterAddresses || *pOutBufLen < requiredSize)
{
*pOutBufLen = requiredSize;
closeTcpFile(tcpFile);
free(indexTable);
return ERROR_BUFFER_OVERFLOW;
}
RtlZeroMemory(pAdapterAddresses, requiredSize);
/* Let's set up the pointers */
currentAddress = pAdapterAddresses;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
currentLocation =
(PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
/* FIXME: Friendly name */
if(!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
{
currentAddress->FriendlyName = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
}
/* Adapter name */
currentAddress->AdapterName = (PVOID)currentLocation;
currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
/* Unicast address */
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
{
currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
currentAddress->FirstUnicastAddress->Address.lpSockaddr =
(PVOID)currentLocation;
currentLocation += sizeof(struct sockaddr);
}
/* FIXME: Implement multicast, anycast, and dns server stuff */
/* FIXME: Implement dns suffix and description */
currentAddress->DnsSuffix = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
currentAddress->Description = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
currentAddress->Next = (PVOID)currentLocation;
/* Terminate the last address correctly */
if(i == 0)
currentAddress->Next = NULL;
/* We're only going to implement what's required for XP SP0 */
currentAddress = currentAddress->Next;
}
}
/* Now again, for real this time */
currentAddress = pAdapterAddresses;
for(i = indexTable->numIndexes; i >= 0; i--)
{
if(NT_SUCCESS(
getIPAddrEntryForIf(tcpFile, NULL, indexTable->indexes[i], &ifInfo)))
{
/* Make sure we're not looping more than we hoped for */
assert(currentAddress);
/* Alignment information */
currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
currentAddress->IfIndex = indexTable->indexes[i];
/* Adapter name */
strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
if(!(Flags & GAA_FLAG_SKIP_UNICAST))
{
currentAddress->FirstUnicastAddress->Length =
sizeof(IP_ADAPTER_UNICAST_ADDRESS);
currentAddress->FirstUnicastAddress->Flags = 0; // FIXME
currentAddress->FirstUnicastAddress->Next =
NULL; // FIXME: Support more than one address per adapter
currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family =
AF_INET;
memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
&ifInfo.ip_addr.iae_addr, sizeof(ifInfo.ip_addr.iae_addr));
currentAddress->FirstUnicastAddress->Address.iSockaddrLength =
sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
currentAddress->FirstUnicastAddress->PrefixOrigin =
IpPrefixOriginOther; // FIXME
currentAddress->FirstUnicastAddress->SuffixOrigin =
IpSuffixOriginOther; // FIXME
currentAddress->FirstUnicastAddress->DadState =
IpDadStatePreferred; // FIXME
currentAddress->FirstUnicastAddress->ValidLifetime =
0xFFFFFFFF; // FIXME
currentAddress->FirstUnicastAddress->PreferredLifetime =
0xFFFFFFFF; // FIXME
currentAddress->FirstUnicastAddress->LeaseLifetime =
0xFFFFFFFF; // FIXME
}
/* FIXME: Implement multicast, anycast, and dns server stuff */
currentAddress->FirstAnycastAddress = NULL;
currentAddress->FirstMulticastAddress = NULL;
currentAddress->FirstDnsServerAddress = NULL;
/* FIXME: Implement dns suffix, description, and friendly name */
currentAddress->DnsSuffix[0] = UNICODE_NULL;
currentAddress->Description[0] = UNICODE_NULL;
currentAddress->FriendlyName[0] = UNICODE_NULL;
/* Physical Address */
memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr,
ifInfo.if_info.ent.if_physaddrlen);
currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
/* Flags */
currentAddress->Flags = 0; // FIXME
/* MTU */
currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
/* Interface type */
currentAddress->IfType = ifInfo.if_info.ent.if_type;
/* Operational status */
if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
currentAddress->OperStatus = IfOperStatusUp;
else
currentAddress->OperStatus = IfOperStatusDown;
/* We're only going to implement what's required for XP SP0 */
/* Move to the next address */
currentAddress = currentAddress->Next;
}
}
closeTcpFile(tcpFile);
free(indexTable);
return NO_ERROR;
}
#endif

@ -1,572 +0,0 @@
#if defined(__MINGW32__) && !defined(_WIN64)
/*
* All the user-mode scaffolding necessary to backport GetAdaptersAddresses(2))
* to the NT 5.x series. See further comments for any limitations.
* NOTE: this is dead code, i haven't had time to debug it yet due to illness.
* For now, downlevel platforms use GetAdaptersInfo(2) which is inet4 only.
* -despair86 20/08/18
*/
#include <assert.h>
#include <stdio.h>
// apparently mingw-w64 loses its shit over this
// but only for 32-bit builds, naturally
#ifdef WIN32_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#endif
// these need to be in a specific order
#include <windows.h>
#include <winternl.h>
#include <tdi.h>
#include "win32_intrnl.h"
const PWCHAR TcpFileName = L"\\Device\\Tcp";
// from ntdll.dll
typedef void(FAR PASCAL *pRtlInitUString)(UNICODE_STRING *, const WCHAR *);
typedef NTSTATUS(FAR PASCAL *pNTOpenFile)(HANDLE *, ACCESS_MASK,
OBJECT_ATTRIBUTES *,
IO_STATUS_BLOCK *, ULONG, ULONG);
typedef NTSTATUS(FAR PASCAL *pNTClose)(HANDLE);
#define FSCTL_TCP_BASE FILE_DEVICE_NETWORK
#define _TCP_CTL_CODE(Function, Method, Access) \
CTL_CODE(FSCTL_TCP_BASE, Function, Method, Access)
#define IOCTL_TCP_QUERY_INFORMATION_EX \
_TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS)
typedef struct _InterfaceIndexTable
{
DWORD numIndexes;
DWORD numAllocated;
DWORD indexes[1];
} InterfaceIndexTable;
NTSTATUS
tdiGetMibForIfEntity(HANDLE tcpFile, TDIEntityID *ent,
IFEntrySafelySized *entry)
{
TCP_REQUEST_QUERY_INFORMATION_EX req;
NTSTATUS status = 0;
DWORD returnSize;
#ifdef DEBUG
fprintf(stderr, "TdiGetMibForIfEntity(tcpFile %x,entityId %x)\n",
(int)tcpFile, (int)ent->tei_instance);
#endif
memset(&req, 0, sizeof(req));
req.ID.toi_class = INFO_CLASS_PROTOCOL;
req.ID.toi_type = INFO_TYPE_PROVIDER;
req.ID.toi_id = 1;
req.ID.toi_entity = *ent;
status =
DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), entry, sizeof(*entry), &returnSize, NULL);
if(!status)
{
perror("IOCTL Failed\n");
return 0xc0000001;
}
fprintf(stderr,
"TdiGetMibForIfEntity() => {\n"
" if_index ....................... %lx\n"
" if_type ........................ %lx\n"
" if_mtu ......................... %ld\n"
" if_speed ....................... %lx\n"
" if_physaddrlen ................. %ld\n",
entry->ent.if_index, entry->ent.if_type, entry->ent.if_mtu,
entry->ent.if_speed, entry->ent.if_physaddrlen);
fprintf(stderr,
" if_physaddr .................... %02x:%02x:%02x:%02x:%02x:%02x\n"
" if_descr ....................... %s\n",
entry->ent.if_physaddr[0] & 0xff, entry->ent.if_physaddr[1] & 0xff,
entry->ent.if_physaddr[2] & 0xff, entry->ent.if_physaddr[3] & 0xff,
entry->ent.if_physaddr[4] & 0xff, entry->ent.if_physaddr[5] & 0xff,
entry->ent.if_descr);
fprintf(stderr, "} status %08lx\n", status);
return 0;
}
static NTSTATUS
tdiGetSetOfThings(HANDLE tcpFile, DWORD toiClass, DWORD toiType, DWORD toiId,
DWORD teiEntity, DWORD teiInstance, DWORD fixedPart,
DWORD entrySize, PVOID *tdiEntitySet, PDWORD numEntries)
{
TCP_REQUEST_QUERY_INFORMATION_EX req;
PVOID entitySet = 0;
NTSTATUS status = 0;
DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES,
arraySize = entrySize * MAX_TDI_ENTITIES;
memset(&req, 0, sizeof(req));
req.ID.toi_class = toiClass;
req.ID.toi_type = toiType;
req.ID.toi_id = toiId;
req.ID.toi_entity.tei_entity = teiEntity;
req.ID.toi_entity.tei_instance = teiInstance;
/* There's a subtle problem here...
* If an interface is added at this exact instant, (as if by a PCMCIA
* card insertion), the array will still not have enough entries after
* have allocated it after the first DeviceIoControl call.
*
* We'll get around this by repeating until the number of interfaces
* stabilizes.
*/
do
{
status =
DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), 0, 0, &allocationSizeForEntityArray, NULL);
if(!status)
return 0xc0000001;
arraySize = allocationSizeForEntityArray;
entitySet = HeapAlloc(GetProcessHeap(), 0, arraySize);
if(!entitySet)
{
status = ((NTSTATUS)0xC000009A);
return status;
}
status = DeviceIoControl(tcpFile, IOCTL_TCP_QUERY_INFORMATION_EX, &req,
sizeof(req), entitySet, arraySize,
&allocationSizeForEntityArray, NULL);
/* This is why we have the loop -- we might have added an adapter */
if(arraySize == allocationSizeForEntityArray)
break;
HeapFree(GetProcessHeap(), 0, entitySet);
entitySet = 0;
if(!status)
return 0xc0000001;
} while(TRUE); /* We break if the array we received was the size we
* expected. Therefore, we got here because it wasn't */
*numEntries = (arraySize - fixedPart) / entrySize;
*tdiEntitySet = entitySet;
return 0;
}
static NTSTATUS
tdiGetEntityIDSet(HANDLE tcpFile, TDIEntityID **entitySet, PDWORD numEntities)
{
NTSTATUS status =
tdiGetSetOfThings(tcpFile, INFO_CLASS_GENERIC, INFO_TYPE_PROVIDER,
ENTITY_LIST_ID, GENERIC_ENTITY, 0, 0,
sizeof(TDIEntityID), (PVOID *)entitySet, numEntities);
return status;
}
NTSTATUS
tdiGetIpAddrsForIpEntity(HANDLE tcpFile, TDIEntityID *ent, IPAddrEntry **addrs,
PDWORD numAddrs)
{
NTSTATUS status;
#ifdef DEBUG
fprintf(stderr, "TdiGetIpAddrsForIpEntity(tcpFile 0x%p, entityId 0x%lx)\n",
tcpFile, ent->tei_instance);
#endif
status = tdiGetSetOfThings(tcpFile, INFO_CLASS_PROTOCOL, INFO_TYPE_PROVIDER,
0x102, CL_NL_ENTITY, ent->tei_instance, 0,
sizeof(IPAddrEntry), (PVOID *)addrs, numAddrs);
return status;
}
static VOID
tdiFreeThingSet(PVOID things)
{
HeapFree(GetProcessHeap(), 0, things);
}
NTSTATUS
openTcpFile(PHANDLE tcpFile, ACCESS_MASK DesiredAccess)
{
UNICODE_STRING fileName;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
NTSTATUS status;
pRtlInitUString _RtlInitUnicodeString;
pNTOpenFile _NTOpenFile;
HANDLE ntdll;
ntdll = GetModuleHandle("ntdll.dll");
_RtlInitUnicodeString =
(pRtlInitUString)GetProcAddress(ntdll, "RtlInitUnicodeString");
_NTOpenFile = (pNTOpenFile)GetProcAddress(ntdll, "NtOpenFile");
_RtlInitUnicodeString(&fileName, TcpFileName);
InitializeObjectAttributes(&objectAttributes, &fileName, OBJ_CASE_INSENSITIVE,
NULL, NULL);
status = _NTOpenFile(tcpFile, DesiredAccess | SYNCHRONIZE, &objectAttributes,
&ioStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
/* String does not need to be freed: it points to the constant
* string we provided */
if(!NT_SUCCESS(status))
*tcpFile = INVALID_HANDLE_VALUE;
return status;
}
VOID
closeTcpFile(HANDLE h)
{
pNTClose _NTClose;
HANDLE ntdll = GetModuleHandle("ntdll.dll");
_NTClose = (pNTClose)GetProcAddress(ntdll, "NtClose");
assert(h != INVALID_HANDLE_VALUE);
_NTClose(h);
}
BOOL
isLoopback(HANDLE tcpFile, TDIEntityID *loop_maybe)
{
IFEntrySafelySized entryInfo;
NTSTATUS status;
status = tdiGetMibForIfEntity(tcpFile, loop_maybe, &entryInfo);
return NT_SUCCESS(status)
&& (entryInfo.ent.if_type == IFENT_SOFTWARE_LOOPBACK);
}
BOOL
isIpEntity(HANDLE tcpFile, TDIEntityID *ent)
{
UNREFERENCED_PARAMETER(tcpFile);
return (ent->tei_entity == CL_NL_ENTITY || ent->tei_entity == CO_NL_ENTITY);
}
NTSTATUS
getNthIpEntity(HANDLE tcpFile, DWORD index, TDIEntityID *ent)
{
DWORD numEntities = 0;
DWORD numRoutes = 0;
TDIEntityID *entitySet = 0;
NTSTATUS status = tdiGetEntityIDSet(tcpFile, &entitySet, &numEntities);
unsigned i;
if(!NT_SUCCESS(status))
return status;
for(i = 0; i < numEntities; i++)
{
if(isIpEntity(tcpFile, &entitySet[i]))
{
fprintf(stderr, "Entity %d is an IP Entity\n", i);
if(numRoutes == index)
break;
else
numRoutes++;
}
}
if(numRoutes == index && i < numEntities)
{
fprintf(stderr, "Index %lu is entity #%d - %04lx:%08lx\n", index, i,
entitySet[i].tei_entity, entitySet[i].tei_instance);
memcpy(ent, &entitySet[i], sizeof(*ent));
tdiFreeThingSet(entitySet);
return 0;
}
else
{
tdiFreeThingSet(entitySet);
return 0xc000001;
}
}
BOOL
isInterface(TDIEntityID *if_maybe)
{
return if_maybe->tei_entity == IF_ENTITY;
}
NTSTATUS
getInterfaceInfoSet(HANDLE tcpFile, IFInfo **infoSet, PDWORD numInterfaces)
{
DWORD numEntities;
TDIEntityID *entIDSet = NULL;
NTSTATUS status = tdiGetEntityIDSet(tcpFile, &entIDSet, &numEntities);
IFInfo *infoSetInt = 0;
int curInterf = 0;
unsigned i;
if(!NT_SUCCESS(status))
{
fprintf(stderr, "getInterfaceInfoSet: tdiGetEntityIDSet() failed: 0x%lx\n",
status);
return status;
}
infoSetInt = HeapAlloc(GetProcessHeap(), 0, sizeof(IFInfo) * numEntities);
if(infoSetInt)
{
for(i = 0; i < numEntities; i++)
{
if(isInterface(&entIDSet[i]))
{
infoSetInt[curInterf].entity_id = entIDSet[i];
status = tdiGetMibForIfEntity(tcpFile, &entIDSet[i],
&infoSetInt[curInterf].if_info);
fprintf(stderr, "tdiGetMibForIfEntity: %08lx\n", status);
if(NT_SUCCESS(status))
{
DWORD numAddrs;
IPAddrEntry *addrs;
TDIEntityID ip_ent;
unsigned j;
status = getNthIpEntity(tcpFile, curInterf, &ip_ent);
if(NT_SUCCESS(status))
status =
tdiGetIpAddrsForIpEntity(tcpFile, &ip_ent, &addrs, &numAddrs);
for(j = 0; NT_SUCCESS(status) && j < numAddrs; j++)
{
fprintf(stderr, "ADDR %d: index %ld (target %ld)\n", j,
addrs[j].iae_index,
infoSetInt[curInterf].if_info.ent.if_index);
if(addrs[j].iae_index == infoSetInt[curInterf].if_info.ent.if_index)
{
memcpy(&infoSetInt[curInterf].ip_addr, &addrs[j],
sizeof(addrs[j]));
curInterf++;
break;
}
}
if(NT_SUCCESS(status))
tdiFreeThingSet(addrs);
}
}
}
tdiFreeThingSet(entIDSet);
if(NT_SUCCESS(status))
{
*infoSet = infoSetInt;
*numInterfaces = curInterf;
}
else
{
HeapFree(GetProcessHeap(), 0, infoSetInt);
}
return status;
}
else
{
tdiFreeThingSet(entIDSet);
return ((NTSTATUS)0xC000009A);
}
}
NTSTATUS
getInterfaceInfoByName(HANDLE tcpFile, char *name, IFInfo *info)
{
IFInfo *ifInfo;
DWORD numInterfaces;
unsigned i;
NTSTATUS status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
if(NT_SUCCESS(status))
{
for(i = 0; i < numInterfaces; i++)
{
if(!strcmp((PCHAR)ifInfo[i].if_info.ent.if_descr, name))
{
memcpy(info, &ifInfo[i], sizeof(*info));
break;
}
}
HeapFree(GetProcessHeap(), 0, ifInfo);
return i < numInterfaces ? 0 : 0xc0000001;
}
return status;
}
NTSTATUS
getInterfaceInfoByIndex(HANDLE tcpFile, DWORD index, IFInfo *info)
{
IFInfo *ifInfo;
DWORD numInterfaces;
NTSTATUS status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
unsigned i;
if(NT_SUCCESS(status))
{
for(i = 0; i < numInterfaces; i++)
{
if(ifInfo[i].if_info.ent.if_index == index)
{
memcpy(info, &ifInfo[i], sizeof(*info));
break;
}
}
HeapFree(GetProcessHeap(), 0, ifInfo);
return i < numInterfaces ? 0 : 0xc0000001;
}
return status;
}
NTSTATUS
getIPAddrEntryForIf(HANDLE tcpFile, char *name, DWORD index, IFInfo *ifInfo)
{
NTSTATUS status = name ? getInterfaceInfoByName(tcpFile, name, ifInfo)
: getInterfaceInfoByIndex(tcpFile, index, ifInfo);
if(!NT_SUCCESS(status))
{
fprintf(stderr, "getIPAddrEntryForIf returning %lx\n", status);
}
return status;
}
InterfaceIndexTable *
getInterfaceIndexTableInt(BOOL nonLoopbackOnly)
{
DWORD numInterfaces, curInterface = 0;
unsigned i;
IFInfo *ifInfo;
InterfaceIndexTable *ret = 0;
HANDLE tcpFile;
NTSTATUS status = openTcpFile(&tcpFile, FILE_READ_DATA);
ifInfo = NULL;
if(NT_SUCCESS(status))
{
status = getInterfaceInfoSet(tcpFile, &ifInfo, &numInterfaces);
fprintf(stderr, "InterfaceInfoSet: %08lx, %04lx:%08lx\n", status,
ifInfo->entity_id.tei_entity, ifInfo->entity_id.tei_instance);
if(NT_SUCCESS(status))
{
ret = (InterfaceIndexTable *)calloc(
1, sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD));
if(ret)
{
ret->numAllocated = numInterfaces;
fprintf(stderr, "NumInterfaces = %ld\n", numInterfaces);
for(i = 0; i < numInterfaces; i++)
{
fprintf(stderr, "Examining interface %d\n", i);
if(!nonLoopbackOnly || !isLoopback(tcpFile, &ifInfo[i].entity_id))
{
fprintf(stderr, "Interface %d matches (%ld)\n", i, curInterface);
ret->indexes[curInterface++] = ifInfo[i].if_info.ent.if_index;
}
}
ret->numIndexes = curInterface;
}
tdiFreeThingSet(ifInfo);
}
closeTcpFile(tcpFile);
}
return ret;
}
InterfaceIndexTable *
getInterfaceIndexTable(void)
{
return getInterfaceIndexTableInt(FALSE);
}
#endif
// there's probably an use case for a _newer_ implementation
// of pthread_setname_np(3), in fact, I may just merge _this_
// upstream...
#if 0
#include <windows.h>
typedef HRESULT(FAR PASCAL *p_SetThreadDescription)(void *, const wchar_t *);
#define EXCEPTION_SET_THREAD_NAME ((DWORD)0x406D1388)
typedef struct _THREADNAME_INFO
{
DWORD dwType; /* must be 0x1000 */
LPCSTR szName; /* pointer to name (in user addr space) */
DWORD dwThreadID; /* thread ID (-1=caller thread) */
DWORD dwFlags; /* reserved for future use, must be zero */
} THREADNAME_INFO;
void
SetThreadName(DWORD dwThreadID, LPCSTR szThreadName)
{
THREADNAME_INFO info;
DWORD infosize;
HANDLE hThread;
/* because loonix is SHIT and limits thread names to 16 bytes */
wchar_t thr_name_w[16];
p_SetThreadDescription _SetThreadDescription;
/* current win10 flights now have a new named-thread API, let's try to use
* that first! */
/* first, dlsym(2) the new call from system library */
hThread = NULL;
_SetThreadDescription = (p_SetThreadDescription)GetProcAddress(
GetModuleHandle("kernel32"), "SetThreadDescription");
if(_SetThreadDescription)
{
/* grab another reference to the thread */
hThread = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, dwThreadID);
/* windows takes unicode, our input is utf-8 or plain ascii */
MultiByteToWideChar(CP_ACP, 0, szThreadName, -1, thr_name_w, 16);
if(hThread)
_SetThreadDescription(hThread, thr_name_w);
else
goto old; /* for whatever reason, we couldn't get a handle to the thread.
Just use the old method. */
}
else
{
old:
info.dwType = 0x1000;
info.szName = szThreadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
infosize = sizeof(info) / sizeof(DWORD);
__try
{
RaiseException(EXCEPTION_SET_THREAD_NAME, 0, infosize, (DWORD *)&info);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
/* clean up */
if(hThread)
CloseHandle(hThread);
}
#endif

@ -1,111 +0,0 @@
#ifndef WIN32_INTRNL_H
#define WIN32_INTRNL_H
/* if yer using Microsoft C++, then downlevel platforms are irrelevant to you */
#if defined(__MINGW32__) && !defined(_WIN64)
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
#include <tdiinfo.h>
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef unsigned int uint;
/* forward declare, each module has their own idea of what this is */
typedef struct _InterfaceIndexTable InterfaceIndexTable;
typedef struct IFEntry
{
ulong if_index;
ulong if_type;
ulong if_mtu;
ulong if_speed;
ulong if_physaddrlen;
uchar if_physaddr[8];
ulong if_adminstatus;
ulong if_operstatus;
ulong if_lastchange;
ulong if_inoctets;
ulong if_inucastpkts;
ulong if_innucastpkts;
ulong if_indiscards;
ulong if_inerrors;
ulong if_inunknownprotos;
ulong if_outoctets;
ulong if_outucastpkts;
ulong if_outnucastpkts;
ulong if_outdiscards;
ulong if_outerrors;
ulong if_outqlen;
ulong if_descrlen;
uchar if_descr[1];
} IFEntry;
typedef struct IPAddrEntry
{
ulong iae_addr;
ulong iae_index;
ulong iae_mask;
ulong iae_bcastaddr;
ulong iae_reasmsize;
ushort iae_context;
ushort iae_pad;
} IPAddrEntry;
typedef union _IFEntrySafelySized {
CHAR MaxSize[sizeof(DWORD) + sizeof(IFEntry) + 128 + 1];
IFEntry ent;
} IFEntrySafelySized;
#ifndef IFENT_SOFTWARE_LOOPBACK
#define IFENT_SOFTWARE_LOOPBACK 24 /* This is an SNMP constant from rfc1213 */
#endif /*IFENT_SOFTWARE_LOOPBACK*/
/* Encapsulates information about an interface */
typedef struct _IFInfo
{
TDIEntityID entity_id;
IFEntrySafelySized if_info;
IPAddrEntry ip_addr;
} IFInfo;
/* functions */
NTSTATUS
openTcpFile(PHANDLE tcpFile, ACCESS_MASK DesiredAccess);
VOID
closeTcpFile(HANDLE h);
BOOL
isLoopback(HANDLE tcpFile, TDIEntityID* loop_maybe);
BOOL
isIpEntity(HANDLE tcpFile, TDIEntityID* ent);
NTSTATUS
getNthIpEntity(HANDLE tcpFile, DWORD index, TDIEntityID* ent);
BOOL
isInterface(TDIEntityID* if_maybe);
NTSTATUS
getInterfaceInfoSet(HANDLE tcpFile, IFInfo** infoSet, PDWORD numInterfaces);
NTSTATUS
getInterfaceInfoByName(HANDLE tcpFile, char* name, IFInfo* info);
NTSTATUS
getInterfaceInfoByIndex(HANDLE tcpFile, DWORD index, IFInfo* info);
NTSTATUS
getIPAddrEntryForIf(HANDLE tcpFile, char* name, DWORD index, IFInfo* ifInfo);
InterfaceIndexTable*
getInterfaceIndexTableInt(BOOL nonLoopbackOnly);
InterfaceIndexTable*
getInterfaceIndexTable(void);
#endif
#endif

@ -1,8 +1,7 @@
#!/usr/bin/env sh
#
#!/usr/bin/env bash
# this shell script will be replaced by a proper program in the future (probably)
#
if [ "X$1" = "X" ] ; then url="https://i2p.rocks/i2procks.signed" ; else url="$1" ; fi
echo "downloading $url"
wget -O $HOME/.lokinet/bootstrap.signed "$url" || echo "failed to download bootstrap from $url"
wget -O $HOME/.lokinet/bootstrap.signed "$url" || echo "failed to download bootstrap from $url"

@ -0,0 +1,33 @@
#include <gtest/gtest.h>
#include <llarp/aligned.hpp>
using Buffer_t = llarp::AlignedBuffer< 32 >;
using Map_t = std::unordered_map< Buffer_t, int, Buffer_t::Hash >;
struct AlignedBufferTest : public ::testing::Test
{
AlignedBufferTest()
{
llarp_crypto_init(&crypto);
}
llarp_crypto crypto;
};
TEST_F(AlignedBufferTest, TestHash)
{
Buffer_t k, other_k;
k.Randomize();
other_k.Randomize();
Map_t m;
ASSERT_TRUE(m.empty());
ASSERT_TRUE(m.emplace(k, 1).second);
ASSERT_TRUE(m.find(k) != m.end());
ASSERT_TRUE(m[k] == 1);
ASSERT_FALSE(m.find(other_k) != m.end());
ASSERT_TRUE(m.size() == 1);
Buffer_t k_copy = k;
ASSERT_FALSE(m.emplace(k_copy, 2).second);
ASSERT_FALSE(m[k_copy] == 2);
ASSERT_TRUE(m[k_copy] == 1);
};

@ -0,0 +1,30 @@
#include <gtest/gtest.h>
#include <llarp/exit.hpp>
#include "router.hpp"
struct ExitTest : public ::testing::Test
{
ExitTest()
{
llarp_crypto_init(&r.crypto);
}
llarp_router r;
};
TEST_F(ExitTest, AddMultipleIP)
{
llarp::PubKey pk;
pk.Randomize();
llarp::PathID_t firstPath, secondPath;
firstPath.Randomize();
secondPath.Randomize();
llarp::exit::Context::Config_t conf;
conf.emplace("exit", "true");
conf.emplace("type", "null");
conf.emplace("ifaddr", "10.0.0.1/24");
ASSERT_TRUE(r.exitContext.AddExitEndpoint("test-exit", conf));
ASSERT_TRUE(r.exitContext.ObtainNewExit(pk, firstPath, true));
ASSERT_TRUE(r.exitContext.ObtainNewExit(pk, secondPath, true));
ASSERT_TRUE(r.exitContext.FindEndpointForPath(firstPath)->LocalIP()
== r.exitContext.FindEndpointForPath(secondPath)->LocalIP());
};

@ -163,7 +163,7 @@ struct ExceptionTester
}
};
std::atomic< std::thread::id > ExceptionTester::throwFrom = std::thread::id();
std::atomic< std::thread::id > ExceptionTester::throwFrom = {std::thread::id()};
void
sleepNWait(size_t microseconds, util::Barrier& barrier)
@ -211,7 +211,7 @@ struct MoveTester
MoveTester&
operator=(const MoveTester& rhs) = delete;
explicit MoveTester(MoveTester&& rhs)
MoveTester(MoveTester&& rhs)
: moved(false), moveCounter(rhs.moveCounter), value(rhs.value)
{
rhs.moved = true;
@ -495,10 +495,10 @@ TEST(TestQueue, exceptionSafety)
util::Semaphore semaphore{0};
std::atomic_size_t caught = 0;
std::atomic_size_t caught = {0};
std::thread producer{std::bind(&exceptionProducer, std::ref(queue),
std::ref(semaphore), std::ref(caught))};
std::thread producer(std::bind(&exceptionProducer, std::ref(queue),
std::ref(semaphore), std::ref(caught)));
ExceptionTester::throwFrom = std::this_thread::get_id();
@ -572,8 +572,13 @@ TEST(TestQueue, moveIt)
(void)popped;
ASSERT_EQ(5u, counter);
#if __cplusplus >= 201703L
std::optional< MoveTester >
#else
tl::optional< MoveTester >
#endif
optPopped = queue.tryPopFront();
std::optional< MoveTester > optPopped = queue.tryPopFront();
ASSERT_TRUE(optPopped.has_value());
// Moved twice here to construct the optional.

@ -1,6 +1,9 @@
#include <queue_manager.hpp>
#if __cplusplus >= 201703L
#include <optional>
#else
#include <tl/optional.hpp>
#endif
#include <vector>
#include <gtest/gtest.h>
@ -74,8 +77,11 @@ class IntQueue
return false;
}
}
#if __cplusplus >= 201703L
std::optional< int >
#else
tl::optional< int >
#endif
tryPopFront()
{
uint32_t gen = 0;

@ -370,7 +370,7 @@ TEST_P(TryAdd, noblocking)
util::Barrier startBarrier(d.threads + 1);
util::Barrier stopBarrier(d.threads + 1);
BarrierArgs args{startBarrier, stopBarrier, 0};
BarrierArgs args{startBarrier, stopBarrier, {0}};
auto simpleJob = std::bind(barrierFunction, std::ref(args));
@ -389,7 +389,7 @@ TEST_P(TryAdd, noblocking)
// and that we emptied the queue.
ASSERT_EQ(0u, pool.jobCount());
BasicWorkArgs basicWorkArgs = {0};
BasicWorkArgs basicWorkArgs = {{0}};
auto workJob = std::bind(basicWork, std::ref(basicWorkArgs));
@ -417,7 +417,7 @@ TEST(TestThreadPool, recurseJob)
ThreadPool pool(threads, capacity);
util::Barrier barrier(threads + 1);
std::atomic_size_t counter = 0;
std::atomic_size_t counter{0};
pool.start();

@ -36,16 +36,17 @@
#include <arpa/inet.h>
#include <netinet/in.h>
#if defined Linux
#include <netinet/ether.h>
#if defined(Linux)
#include <linux/if_tun.h>
#include <linux/if_ether.h>
#else
#include <net/if.h>
#if defined DragonFly
#if defined(DragonFly)
#include <net/tun/if_tun.h>
#elif defined ANDROID
#elif defined(ANDROID)
#include <linux/if_tun.h>
#elif !defined Darwin
#elif !defined(Darwin)
#include <net/if_tun.h>
#endif
#include <netinet/if_ether.h>

@ -30,13 +30,6 @@
#if defined Windows
#include <winsock2.h>
#include <ws2tcpip.h>
#include <wspiapi.h>
#if _WIN32_WINNT < 0x0600
extern "C" int
inet_pton(int af, const char *src, void *dst);
extern "C" const char *
inet_ntop(int af, const void *src, char *dst, size_t size);
#endif
#else
#include <arpa/inet.h>
#include <netinet/in.h>

@ -39,8 +39,9 @@ VersionInfoTextVersion=0.3.0-dev
VersionInfoProductName=loki-network
VersionInfoProductVersion=0.3.0
VersionInfoProductTextVersion=0.3.0-dev
InternalCompressLevel=ultra64
MinVersion=0,5.0
InternalCompressLevel=ultra64
; rip D:
MinVersion=0,6.0
ArchitecturesInstallIn64BitMode=x64
VersionInfoCopyright=Copyright ©2018 Loki Project
AlwaysRestart=yes
@ -65,52 +66,22 @@ Source: "{#DevPath}build\rcutil.exe"; DestDir: "{app}"; Flags: ignoreversion
; and download an initial RC
Source: "{#DevPath}lokinet-bootstrap.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "{#DevPath}win32-setup\7z.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "{tmp}\inet6.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
; Copy the correct tuntap driver for the selected platform
Source: "{tmp}\tuntapv9.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; OnlyBelowVersion: 0, 6.0
Source: "{tmp}\tuntapv9_n6.7z"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall; MinVersion: 0,6.0
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[UninstallDelete]
Type: filesandordirs; Name: "{app}\tap-windows*"
Type: filesandordirs; Name: "{app}\inet6_driver"; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
Type: filesandordirs; Name: "{userappdata}\.lokinet"
[UninstallRun]
Filename: "{app}\tap-windows-9.21.2\remove.bat"; WorkingDir: "{app}\tap-windows-9.21.2"; MinVersion: 0,6.0; Flags: runascurrentuser
Filename: "{app}\tap-windows-9.9.2\remove.bat"; WorkingDir: "{app}\tap-windows-9.9.2"; OnlyBelowVersion: 0,6.0; Flags: runascurrentuser
[Registry]
; TODO: BindView to activate inet6 protocol driver after restart
Root: "HKLM"; Subkey: "Software\Microsoft\Windows\CurrentVersion\RunOnce"; ValueType: string; ValueName: "ActivateInet6"; ValueData: "[insert bindview cmd line here]"; MinVersion: 0,5.0; OnlyBelowVersion: 0,5.1
[Code]
procedure InitializeWizard();
var
Version: TWindowsVersion;
S: String;
begin
GetWindowsVersionEx(Version);
if Version.NTPlatform and
(Version.Major < 6) then
begin
// Windows 2000, XP, .NET Svr 2003
// these have a horribly crippled WinInet that issues Triple-DES as its most secure
// cipher suite
idpAddFile('http://www.rvx86.net/files/tuntapv9.7z', ExpandConstant('{tmp}\tuntapv9.7z'));
// Windows 2000 only, we need to install inet6 separately
if (FileExists(ExpandConstant('{sys}\drivers\tcpip6.sys')) = false) and (Version.Major = 5) and (Version.Minor = 0) then
begin
idpAddFile('http://www.rvx86.net/files/inet6.7z', ExpandConstant('{tmp}\inet6.7z'));
end;
end
else
begin
// current versions of windows :-)
// (Arguably, one could pull this from any of the forks.)
idpAddFile('https://github.com/despair86/loki-network/raw/master/contrib/tuntapv9-ndis/tap-windows-9.21.2.7z', ExpandConstant('{tmp}\tuntapv9_n6.7z'));
end;
idpDownloadAfter(wpReady);
end;
@ -125,13 +96,7 @@ Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBa
[Run]
Filename: "{app}\{#MyAppExeName}"; Flags: nowait postinstall skipifsilent; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"
; wait until either one or two of these terminates
Filename: "{tmp}\7z.exe"; Parameters: "x tuntapv9.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract TUN/TAP-v9 driver"; StatusMsg: "Extracting driver..."; OnlyBelowVersion: 0, 6.0
Filename: "{tmp}\7z.exe"; Parameters: "x tuntapv9_n6.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract TUN/TAP-v9 driver"; StatusMsg: "Extracting driver..."; MinVersion: 0, 6.0
Filename: "{tmp}\7z.exe"; Parameters: "x inet6.7z"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "extract inet6 driver"; StatusMsg: "Extracting IPv6 driver..."; MinVersion: 0, 5.0; OnlyBelowVersion: 0, 5.1
Filename: "{tmp}\lokinet-bootstrap.exe"; WorkingDir: "{app}"; Flags: runascurrentuser waituntilterminated; Description: "bootstrap dht"; StatusMsg: "Downloading initial RC..."
; then ask to install drivers
Filename: "{app}\tap-windows-9.9.2\install.bat"; WorkingDir: "{app}\tap-windows-9.9.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; OnlyBelowVersion: 0, 6.0
Filename: "{app}\tap-windows-9.21.2\install.bat"; WorkingDir: "{app}\tap-windows-9.21.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; MinVersion: 0, 6.0
; install inet6 if not present. (I'd assume netsh displays something helpful if inet6 is already set up and configured.)
Filename: "{app}\inet6_driver\setup\hotfix.exe"; Parameters: "/m /z"; WorkingDir: "{app}\inet6_driver\setup\"; Flags: runascurrentuser waituntilterminated; Description: "Install IPv6 driver"; StatusMsg: "Installing IPv6..."; OnlyBelowVersion: 0, 5.1
Filename: "{sys}\netsh.exe"; Parameters: "int ipv6 install"; Flags: runascurrentuser waituntilterminated; Description: "install ipv6 on whistler"; StatusMsg: "Installing IPv6..."; MinVersion: 0,5.1; OnlyBelowVersion: 0,6.0
Filename: "{app}\tap-windows-9.21.2\install.bat"; WorkingDir: "{app}\tap-windows-9.21.2\"; Flags: runascurrentuser waituntilterminated; Description: "Install TUN/TAP-v9 driver"; StatusMsg: "Installing driver..."; MinVersion: 0, 6.0
Loading…
Cancel
Save