Merge branch 'dev' into private-keys-backup-support

pull/921/head
Stephen Shelton 5 years ago committed by GitHub
commit 93b8832026
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -188,6 +188,10 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
if(NOT IOS AND NOT ANDROID AND NOT WIN32)
find_package(CURL REQUIRED)
endif()
include(cmake/static_link_runtime.cmake)
include(cmake/static_link.cmake)

@ -16,7 +16,7 @@ BUILD_TYPE ?= Debug
PYTHON ?= python
PYTHON3 ?= python3
FORMAT ?= clang-format
FORMAT ?= clang-format-8
SETCAP ?= which setcap && setcap cap_net_admin,cap_net_bind_service=+eip

@ -1,6 +1,7 @@
#include <config/config.hpp> // for ensure_config
#include <constants/version.hpp>
#include <llarp.h>
#include <util/lokinet_init.h>
#include <util/fs.hpp>
#include <util/logging/logger.hpp>
#include <util/logging/ostream_logger.hpp>
@ -83,6 +84,11 @@ run_main_context(std::string conffname, llarp_main_runtime_opts opts)
int
main(int argc, char *argv[])
{
auto result = Lokinet_INIT();
if(result)
{
return result;
}
llarp_main_runtime_opts opts;
const char *singleThreadVar = getenv("LLARP_SHADOW");
if(singleThreadVar && std::string(singleThreadVar) == "1")

@ -39,7 +39,7 @@ struct DemoCall : public abyss::http::IRPCClientHandler
bool HandleResponse(abyss::http::RPC_Response) override
{
llarp::LogInfo("response get");
m_Logic->queue_func([=]() { m_Callback(); });
LogicCall(m_Logic, m_Callback);
return true;
}

@ -26,6 +26,7 @@ set(LIB_UTIL_SRC
util/logging/ostream_logger.cpp
util/logging/syslog_logger.cpp
util/logging/win32_logger.cpp
util/lokinet_init.c
util/mem.cpp
util/meta/memfn_traits.cpp
util/meta/memfn.cpp
@ -83,7 +84,6 @@ set(LIB_PLATFORM_SRC
net/ip.cpp
net/net.cpp
net/net_addr.cpp
net/net_inaddr.cpp
net/net_int.cpp
# for android shim
${ANDROID_PLATFORM_SRC}
@ -254,7 +254,8 @@ if(TESTNET)
endif()
add_library(${STATIC_LIB} STATIC ${LIB_SRC})
target_link_libraries(${STATIC_LIB} PUBLIC cxxopts ${ABYSS_LIB} ${PLATFORM_LIB} ${UTIL_LIB} ${CRYPTOGRAPHY_LIB} ${FS_LIB})
target_include_directories(${STATIC_LIB} PUBLIC ${CURL_INCLUDE_DIRS})
target_link_libraries(${STATIC_LIB} PUBLIC cxxopts ${ABYSS_LIB} ${PLATFORM_LIB} ${UTIL_LIB} ${CRYPTOGRAPHY_LIB} ${FS_LIB} ${CURL_LIBRARIES})
if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
target_include_directories(${PLATFORM_LIB} SYSTEM PUBLIC /usr/local/include)

@ -11,6 +11,7 @@
#include <util/mem.hpp>
#include <util/meta/memfn.hpp>
#include <util/str.hpp>
#include <util/lokinet_init.h>
#include <absl/strings/strip.h>
@ -51,6 +52,15 @@ namespace llarp
void
RouterConfig::fromSection(string_view key, string_view val)
{
if(key == "job-queue-size")
{
auto sval = svtoi(val);
if(sval >= 1024)
{
m_JobQueueSize = sval;
LogInfo("Set job queue size to ", m_JobQueueSize);
}
}
if(key == "default-protocol")
{
m_DefaultLinkProto = tostr(val);
@ -459,6 +469,8 @@ namespace llarp
bool
Config::parse(const ConfigParser &parser)
{
if(Lokinet_INIT())
return false;
router = find_section< RouterConfig >(parser, "router");
network = find_section< NetworkConfig >(parser, "network");
connect = find_section< ConnectConfig >(parser, "connect");
@ -500,6 +512,8 @@ extern "C" bool
llarp_ensure_config(const char *fname, const char *basedir, bool overwrite,
bool asRouter)
{
if(Lokinet_INIT())
return false;
std::error_code ec;
if(fs::exists(fname, ec) && !overwrite)
{

@ -121,10 +121,13 @@ namespace llarp
int m_workerThreads = 1;
int m_numNetThreads = 1;
size_t m_JobQueueSize = size_t{1024 * 8};
std::string m_DefaultLinkProto = "iwp";
public:
// clang-format off
size_t jobQueueSize() const { return fromEnv(m_JobQueueSize, "JOB_QUEUE_SIZE"); }
size_t minConnectedRouters() const { return fromEnv(m_minConnectedRouters, "MIN_CONNECTED_ROUTERS"); }
size_t maxConnectedRouters() const { return fromEnv(m_maxConnectedRouters, "MAX_CONNECTED_ROUTERS"); }
std::string encryptionKeyfile() const { return fromEnv(m_encryptionKeyfile, "ENCRYPTION_KEYFILE"); }

@ -39,7 +39,7 @@ namespace llarp
bool
Context::CallSafe(std::function< void(void) > f)
{
return logic && logic->queue_func(std::move(f));
return logic && LogicCall(logic, f);
}
void
@ -51,7 +51,6 @@ namespace llarp
bool
Context::Configure()
{
logic = std::make_shared< Logic >();
// llarp::LogInfo("loading config at ", configfile);
if(configfile.size())
{
@ -73,6 +72,10 @@ namespace llarp
threads = 1;
worker = std::make_shared< llarp::thread::ThreadPool >(threads, 1024,
"llarp-worker");
auto jobQueueSize = config->router.jobQueueSize();
if(jobQueueSize < 1024)
jobQueueSize = 1024;
logic = std::make_shared< Logic >(jobQueueSize);
nodedb_dir = config->netdb.nodedbDir();
@ -482,8 +485,8 @@ extern "C"
void
llarp_main_signal(struct llarp_main *ptr, int sig)
{
ptr->ctx->logic->queue_func(
std::bind(&llarp::Context::HandleSignal, ptr->ctx.get(), sig));
LogicCall(ptr->ctx->logic,
std::bind(&llarp::Context::HandleSignal, ptr->ctx.get(), sig));
}
int

@ -87,6 +87,9 @@ namespace llarp
/// post quantum encrypt (buffer, sharedkey_dst, pub)
virtual bool
pqe_encrypt(PQCipherBlock &, SharedSecret &, const PQPubKey &) = 0;
virtual bool
check_identity_privkey(const SecretKey &) = 0;
};
inline Crypto::~Crypto() = default;

@ -214,6 +214,19 @@ namespace llarp
(void)sk_pk;
}
bool
CryptoLibSodium::check_identity_privkey(const llarp::SecretKey &keys)
{
AlignedBuffer< crypto_sign_SEEDBYTES > seed;
llarp::PubKey pk;
llarp::SecretKey sk;
if(crypto_sign_ed25519_sk_to_seed(seed.data(), keys.data()) == -1)
return false;
if(crypto_sign_seed_keypair(pk.data(), sk.data(), seed.data()) == -1)
return false;
return keys.toPublic() == pk && sk == keys;
}
void
CryptoLibSodium::encryption_keygen(llarp::SecretKey &keys)
{

@ -79,6 +79,9 @@ namespace llarp
/// post quantum encrypt (buffer, sharedkey_dst, pub)
bool
pqe_encrypt(PQCipherBlock &, SharedSecret &, const PQPubKey &) override;
bool
check_identity_privkey(const SecretKey &) override;
};
} // namespace sodium

@ -180,6 +180,12 @@ namespace llarp
std::copy_n(secret.begin(), SharedSecret::SIZE, block.begin());
return true;
}
bool
check_identity_privkey(const SecretKey &) override
{
return true;
}
};
} // namespace llarp

@ -58,20 +58,17 @@ namespace llarp
using User_ptr = std::shared_ptr< User >;
using DecryptHandler = std::function< void(llarp_buffer_t*, User_ptr) >;
static void
Decrypt(void* user)
void
Decrypt(User_ptr user)
{
auto* ctx = static_cast< AsyncFrameDecrypter< User >* >(user);
if(ctx->target.DecryptInPlace(ctx->seckey))
if(target.DecryptInPlace(seckey))
{
auto buf = ctx->target.Buffer();
auto buf = target.Buffer();
buf->cur = buf->base + EncryptedFrameOverheadSize;
ctx->result(buf, ctx->user);
result(buf, user);
}
else
ctx->result(nullptr, ctx->user);
ctx->user = nullptr;
result(nullptr, user);
}
AsyncFrameDecrypter(const SecretKey& secretkey, DecryptHandler h)
@ -80,7 +77,6 @@ namespace llarp
}
DecryptHandler result;
User_ptr user;
const SecretKey& seckey;
EncryptedFrame target;
@ -89,8 +85,8 @@ namespace llarp
const EncryptedFrame& frame, User_ptr u)
{
target = frame;
user = u;
worker->addJob(std::bind(&Decrypt, this));
worker->addJob(
[self = this, user = std::move(u)]() { self->Decrypt(user); });
}
};
} // namespace llarp

@ -199,14 +199,14 @@ namespace llarp
PutRCNodeAsync(const RCNode& val) override
{
auto func = std::bind(&Bucket< RCNode >::PutNode, Nodes(), val);
router->logic()->queue_func(func);
LogicCall(router->logic(), func);
}
void
DelRCNodeAsync(const Key_t& val) override
{
auto func = std::bind(&Bucket< RCNode >::DelNode, Nodes(), val);
router->logic()->queue_func(func);
LogicCall(router->logic(), func);
}
const Key_t&

@ -39,10 +39,10 @@ namespace llarp
m_Resolvers = resolvers;
const llarp::Addr any("0.0.0.0", 0);
auto self = shared_from_this();
m_ClientLogic->queue_func([=]() {
LogicCall(m_ClientLogic, [=]() {
llarp_ev_add_udp(self->m_ClientLoop.get(), &self->m_Client, any);
});
m_ServerLogic->queue_func([=]() {
LogicCall(m_ServerLogic, [=]() {
llarp_ev_add_udp(self->m_ServerLoop.get(), &self->m_Server, addr);
});
return true;
@ -65,8 +65,9 @@ namespace llarp
auto self = static_cast< Proxy* >(u->user)->shared_from_this();
// yes we use the server loop here because if the server loop is not the
// client loop we'll crash again
self->m_ServerLogic->queue_func(
[self, addr, msgbuf]() { self->HandlePktServer(addr, msgbuf); });
LogicCall(self->m_ServerLogic, [self, addr, msgbuf]() {
self->HandlePktServer(addr, msgbuf);
});
}
void
@ -76,8 +77,9 @@ namespace llarp
const llarp::Addr addr(*from);
Buffer_t msgbuf = CopyBuffer(buf.underlying);
auto self = static_cast< Proxy* >(u->user)->shared_from_this();
self->m_ServerLogic->queue_func(
[self, addr, msgbuf]() { self->HandlePktClient(addr, msgbuf); });
LogicCall(self->m_ServerLogic, [self, addr, msgbuf]() {
self->HandlePktClient(addr, msgbuf);
});
}
llarp::Addr
@ -100,7 +102,7 @@ namespace llarp
Proxy::SendServerMessageTo(llarp::Addr to, Message msg)
{
auto self = shared_from_this();
m_ServerLogic->queue_func([to, msg, self]() {
LogicCall(m_ServerLogic, [to, msg, self]() {
std::array< byte_t, 1500 > tmp = {{0}};
llarp_buffer_t buf(tmp);
if(msg.Encode(&buf))
@ -118,7 +120,7 @@ namespace llarp
Proxy::SendClientMessageTo(llarp::Addr to, Message msg)
{
auto self = shared_from_this();
m_ClientLogic->queue_func([to, msg, self]() {
LogicCall(m_ClientLogic, [to, msg, self]() {
std::array< byte_t, 1500 > tmp = {{0}};
llarp_buffer_t buf(tmp);
if(msg.Encode(&buf))
@ -151,7 +153,7 @@ namespace llarp
const Addr requester = itr->second;
auto self = shared_from_this();
m_ServerLogic->queue_func([=]() {
LogicCall(m_ServerLogic, [=]() {
// forward reply to requester via server
const llarp_buffer_t tmpbuf(buf);
llarp_ev_udp_sendto(&self->m_Server, requester, tmpbuf);
@ -222,7 +224,7 @@ namespace llarp
// new forwarded query
tx.from = PickRandomResolver();
m_Forwarded[tx] = from;
m_ClientLogic->queue_func([=] {
LogicCall(m_ClientLogic, [=] {
// do query
const llarp_buffer_t tmpbuf(buf);
llarp_ev_udp_sendto(&self->m_Client, tx.from, tmpbuf);
@ -232,7 +234,7 @@ namespace llarp
{
// send the query again because it's probably FEC from the requester
const auto resolver = itr->first.from;
m_ClientLogic->queue_func([=] {
LogicCall(m_ClientLogic, [=] {
// send it
const llarp_buffer_t tmpbuf(buf);
llarp_ev_udp_sendto(&self->m_Client, resolver, tmpbuf);

@ -40,7 +40,7 @@ typedef SSIZE_T ssize_t;
* event handler (cross platform high performance event system for IO)
*/
#define EV_TICK_INTERVAL 100
#define EV_TICK_INTERVAL 10
// forward declare
struct llarp_threadpool;

@ -7,13 +7,8 @@
namespace libuv
{
/// call a function in logic thread via a handle
template < typename Handle, typename Func >
void
Call(Handle* h, Func&& f)
{
static_cast< Loop* >(h->loop->data)->Call(f);
}
#define LoopCall(h, ...) \
LogicCall(static_cast< Loop* >((h)->loop->data)->m_Logic, __VA_ARGS__)
struct glue
{
@ -110,8 +105,8 @@ namespace libuv
OnOutboundConnect(uv_connect_t* c, int status)
{
conn_glue* self = static_cast< conn_glue* >(c->data);
Call(self->Stream(),
std::bind(&conn_glue::HandleConnectResult, self, status));
LoopCall(self->Stream(),
std::bind(&conn_glue::HandleConnectResult, self, status));
c->data = nullptr;
}
@ -145,7 +140,7 @@ namespace libuv
if(nread >= 0)
{
auto* conn = static_cast< conn_glue* >(stream->data);
Call(stream, std::bind(&conn_glue::Read, conn, buf->base, nread));
LoopCall(stream, std::bind(&conn_glue::Read, conn, buf->base, nread));
return;
}
else if(nread < 0)
@ -262,7 +257,7 @@ namespace libuv
OnClosed(uv_handle_t* h)
{
conn_glue* conn = static_cast< conn_glue* >(h->data);
Call(h, std::bind(&conn_glue::HandleClosed, conn));
LoopCall(h, std::bind(&conn_glue::HandleClosed, conn));
}
static void
@ -329,7 +324,7 @@ namespace libuv
if(status == 0)
{
conn_glue* conn = static_cast< conn_glue* >(stream->data);
Call(stream, std::bind(&conn_glue::Accept, conn));
LoopCall(stream, std::bind(&conn_glue::Accept, conn));
}
else
{
@ -347,7 +342,7 @@ namespace libuv
OnTick(uv_check_t* t)
{
conn_glue* conn = static_cast< conn_glue* >(t->data);
Call(t, std::bind(&conn_glue::Tick, conn));
LoopCall(t, std::bind(&conn_glue::Tick, conn));
}
void
@ -416,7 +411,7 @@ namespace libuv
OnTick(uv_check_t* t)
{
ticker_glue* ticker = static_cast< ticker_glue* >(t->data);
Call(&ticker->m_Ticker, [ticker]() { ticker->func(); });
LoopCall(t, ticker->func);
}
bool
@ -429,8 +424,11 @@ namespace libuv
Close() override
{
uv_check_stop(&m_Ticker);
m_Ticker.data = nullptr;
delete this;
uv_close((uv_handle_t*)&m_Ticker, [](auto h) {
ticker_glue* self = (ticker_glue*)h->data;
h->data = nullptr;
delete self;
});
}
uv_check_t m_Ticker;
@ -586,7 +584,7 @@ namespace libuv
void
Tick()
{
Call(&m_Handle, std::bind(&llarp_ev_pkt_pipe::tick, m_Pipe));
LoopCall(&m_Handle, std::bind(&llarp_ev_pkt_pipe::tick, m_Pipe));
}
static void
@ -626,7 +624,7 @@ namespace libuv
OnTick(uv_check_t* h)
{
pipe_glue* pipe = static_cast< pipe_glue* >(h->data);
Call(h, std::bind(&pipe_glue::Tick, pipe));
LoopCall(h, std::bind(&pipe_glue::Tick, pipe));
}
bool
@ -668,7 +666,7 @@ namespace libuv
OnTick(uv_check_t* timer)
{
tun_glue* tun = static_cast< tun_glue* >(timer->data);
Call(timer, std::bind(&tun_glue::Tick, tun));
tun->Tick();
}
static void
@ -687,7 +685,7 @@ namespace libuv
if(sz > 0)
{
llarp::LogDebug("tun read ", sz);
llarp_buffer_t pkt(m_Buffer, sz);
const llarp_buffer_t pkt(m_Buffer, sz);
if(m_Tun && m_Tun->recvpkt)
m_Tun->recvpkt(m_Tun, pkt);
}
@ -716,9 +714,14 @@ namespace libuv
void
Close() override
{
if(m_Tun->impl == nullptr)
return;
m_Tun->impl = nullptr;
uv_check_stop(&m_Ticker);
uv_close((uv_handle_t*)&m_Handle, &OnClosed);
uv_close((uv_handle_t*)&m_Ticker, [](uv_handle_t* h) {
tun_glue* glue = static_cast< tun_glue* >(h->data);
uv_close((uv_handle_t*)&glue->m_Handle, &OnClosed);
});
}
bool
@ -760,6 +763,9 @@ namespace libuv
" has invalid fd: ", m_Device->tun_fd);
return false;
}
tuntap_set_nonblocking(m_Device, 1);
if(uv_poll_init(loop, &m_Handle, m_Device->tun_fd) == -1)
{
llarp::LogError("failed to start polling on ", m_Tun->ifname);
@ -788,6 +794,12 @@ namespace libuv
{
if(uv_loop_init(&m_Impl) == -1)
return false;
#ifdef LOKINET_DEBUG
last_time = 0;
loop_run_count = 0;
#endif
m_Impl.data = this;
uv_loop_configure(&m_Impl, UV_LOOP_BLOCK_SIGNAL, SIGPIPE);
m_TickTimer.data = this;
@ -829,18 +841,35 @@ namespace libuv
int
Loop::tick(int ms)
{
uv_timer_start(&m_TickTimer, &OnTickTimeout, ms, 0);
uv_run(&m_Impl, UV_RUN_ONCE);
if(m_Run)
{
#ifdef LOKINET_DEBUG
if((uv_now(&m_Impl) - last_time) > 1000)
{
llarp::LogInfo("UV EVENT LOOP TICKS LAST SECOND: ", loop_run_count,
", LOGIC THREAD JOBS: ", m_Logic->numPendingJobs());
loop_run_count = 0;
last_time = uv_now(&m_Impl);
}
loop_run_count++;
#endif
uv_timer_start(&m_TickTimer, &OnTickTimeout, ms, 0);
uv_run(&m_Impl, UV_RUN_ONCE);
}
return 0;
}
void
Loop::stop()
{
uv_stop(&m_Impl);
llarp::LogInfo("stopping event loop");
if(m_Run)
{
llarp::LogInfo("stopping event loop");
CloseAll();
// uv_stop(&m_Impl);
}
m_Run.store(false);
CloseAll();
}
void
@ -945,4 +974,4 @@ bool
llarp_ev_udp_recvmany(struct llarp_udp_io* u, struct llarp_pkt_list* pkts)
{
return static_cast< libuv::udp_glue* >(u->impl)->RecvMany(pkts);
}
}

@ -92,19 +92,17 @@ namespace libuv
m_Logic = l;
}
/// call function in logic thread
template < typename F >
void
Call(F f)
{
m_Logic->queue_func(f);
}
std::shared_ptr< llarp::Logic > m_Logic;
private:
uv_loop_t m_Impl;
uv_timer_t m_TickTimer;
std::atomic< bool > m_Run;
std::shared_ptr< llarp::Logic > m_Logic;
#ifdef LOKINET_DEBUG
uint64_t last_time;
uint64_t loop_run_count;
#endif
};
} // namespace libuv

@ -144,7 +144,7 @@ tun_ev_loop(void* unused)
while(true)
{
alert =
GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl, 100);
GetQueuedCompletionStatus(tun_event_queue, &size, &listener, &ovl, EV_TICK_INTERVAL);
if(!alert)
{
@ -727,7 +727,7 @@ llarp_win32_loop::tick_listeners()
{
llarp_ev_loop::tick_listeners();
for(auto& func : m_Tickers)
m_Logic->queue_func([func]() { func(); });
LogicCall(m_Logic, func);
}
bool

@ -16,14 +16,20 @@ namespace llarp
static void
ExitHandlerRecvPkt(llarp_tun_io *tun, const llarp_buffer_t &buf)
{
static_cast< ExitEndpoint * >(tun->user)->OnInetPacket(buf);
std::vector< byte_t > pkt;
pkt.resize(buf.sz);
std::copy_n(buf.base, buf.sz, pkt.data());
auto self = static_cast< ExitEndpoint * >(tun->user);
LogicCall(self->GetRouter()->logic(), [self, pktbuf = std::move(pkt)]() {
self->OnInetPacket(std::move(pktbuf));
});
}
static void
ExitHandlerFlush(llarp_tun_io *tun)
{
auto *ep = static_cast< ExitEndpoint * >(tun->user);
ep->GetRouter()->logic()->queue_func(std::bind(&ExitEndpoint::Flush, ep));
LogicCall(ep->GetRouter()->logic(), std::bind(&ExitEndpoint::Flush, ep));
}
ExitEndpoint::ExitEndpoint(const std::string &name, AbstractRouter *r)
@ -457,10 +463,13 @@ namespace llarp
}
void
ExitEndpoint::OnInetPacket(const llarp_buffer_t &buf)
ExitEndpoint::OnInetPacket(std::vector< byte_t > buf)
{
const llarp_buffer_t buffer(buf);
m_InetToNetwork.EmplaceIf(
[b = ManagedBuffer(buf)](Pkt_t &pkt) -> bool { return pkt.Load(b); });
[b = ManagedBuffer(buffer)](Pkt_t &pkt) -> bool {
return pkt.Load(b);
});
}
bool

@ -57,7 +57,7 @@ namespace llarp
/// handle ip packet from outside
void
OnInetPacket(const llarp_buffer_t& buf);
OnInetPacket(std::vector< byte_t > buf);
AbstractRouter*
GetRouter();

@ -32,11 +32,23 @@ namespace llarp
m_NetworkToUserPktQueue.Process(send);
}
static void
tunifTick(llarp_tun_io *tun)
bool
TunEndpoint::ShouldFlushNow(llarp_time_t now) const
{
auto *self = static_cast< TunEndpoint * >(tun->user);
self->Flush();
static constexpr llarp_time_t FlushInterval = 25;
return now >= m_LastFlushAt + FlushInterval;
}
void
TunEndpoint::tunifTick(llarp_tun_io *tun)
{
auto *self = static_cast< TunEndpoint * >(tun->user);
const auto now = self->Now();
if(self->ShouldFlushNow(now))
{
self->m_LastFlushAt = now;
LogicCall(self->m_router->logic(), [self]() { self->Flush(); });
}
}
TunEndpoint::TunEndpoint(const std::string &nickname, AbstractRouter *r,
@ -308,13 +320,20 @@ namespace llarp
void
TunEndpoint::Flush()
{
auto self = shared_from_this();
FlushSend();
RouterLogic()->queue_func([=] {
static const auto func = [](auto self) {
self->FlushSend();
self->m_ExitMap.ForEachValue(
[](const auto &exit) { exit->FlushUpstream(); });
self->Pump(self->Now());
});
};
if(NetworkIsIsolated())
{
LogicCall(RouterLogic(), std::bind(func, shared_from_this()));
}
else
{
func(this);
}
}
static bool
@ -329,6 +348,32 @@ namespace llarp
return msg.questions[0].IsName("localhost.loki");
}
template <>
bool
TunEndpoint::FindAddrForIP(service::Address &addr, huint128_t ip)
{
auto itr = m_IPToAddr.find(ip);
if(itr != m_IPToAddr.end() and not m_SNodes[itr->second])
{
addr = service::Address(itr->second.as_array());
return true;
}
return false;
}
template <>
bool
TunEndpoint::FindAddrForIP(RouterID &addr, huint128_t ip)
{
auto itr = m_IPToAddr.find(ip);
if(itr != m_IPToAddr.end() and m_SNodes[itr->second])
{
addr = RouterID(itr->second.as_array());
return true;
}
return false;
}
bool
TunEndpoint::HandleHookedDNSMessage(
dns::Message &&msg, std::function< void(dns::Message) > reply)
@ -472,18 +517,17 @@ namespace llarp
reply(msg);
return true;
}
llarp::service::Address addr(
ObtainAddrForIP< llarp::service::Address >(ip, true));
if(!addr.IsZero())
RouterID snodeAddr;
if(FindAddrForIP(snodeAddr, ip))
{
msg.AddAReply(addr.ToString(".snode"));
msg.AddAReply(snodeAddr.ToString());
reply(msg);
return true;
}
addr = ObtainAddrForIP< llarp::service::Address >(ip, false);
if(!addr.IsZero())
service::Address lokiAddr;
if(FindAddrForIP(lokiAddr, ip))
{
msg.AddAReply(addr.ToString(".loki"));
msg.AddAReply(lokiAddr.ToString());
reply(msg);
return true;
}
@ -701,7 +745,13 @@ namespace llarp
llarp::LogInfo(Name(), " allocated up to ", m_MaxIP, " on range ",
m_OurRange);
MapAddress(m_Identity.pub.Addr(), m_OurIP, IsSNode());
const service::Address ourAddr = m_Identity.pub.Addr();
if(not MapAddress(ourAddr, GetIfAddr(), false))
{
return false;
}
if(m_OnUp)
{
m_OnUp->NotifyAsync(NotifyParams());
@ -710,7 +760,8 @@ namespace llarp
{
vpnif->injected(vpnif, true);
}
return true;
return HasAddress(ourAddr);
}
std::unordered_map< std::string, std::string >
@ -749,13 +800,11 @@ namespace llarp
void
TunEndpoint::Tick(llarp_time_t now)
{
EndpointLogic()->queue_func([&]() {
m_ExitMap.ForEachValue([&](const auto &exit) {
this->EnsureRouterIsKnown(exit->Endpoint());
exit->Tick(now);
});
Endpoint::Tick(now);
m_ExitMap.ForEachValue([&](const auto &exit) {
this->EnsureRouterIsKnown(exit->Endpoint());
exit->Tick(now);
});
Endpoint::Tick(now);
}
bool
@ -973,17 +1022,24 @@ namespace llarp
TunEndpoint::tunifBeforeWrite(llarp_tun_io *tun)
{
// called in the isolated network thread
auto *self = static_cast< TunEndpoint * >(tun->user);
auto sendpkt = [self, tun](net::IPPacket &pkt) -> bool {
if(!llarp_ev_tun_async_write(tun, pkt.Buffer()))
auto *self = static_cast< TunEndpoint * >(tun->user);
auto _pkts = std::move(self->m_TunPkts);
self->m_TunPkts = std::vector< net::IPPacket >();
LogicCall(self->EndpointLogic(), [tun, self, pkts = std::move(_pkts)]() {
for(auto &pkt : pkts)
{
llarp::LogWarn(self->Name(), " packet dropped");
return true;
self->m_UserToNetworkPktQueue.Emplace(pkt);
}
return false;
};
self->EndpointLogic()->queue_func(std::bind(
&TunEndpoint::FlushToUser, self->shared_from_this(), sendpkt));
self->FlushToUser([self, tun](net::IPPacket &pkt) -> bool {
if(!llarp_ev_tun_async_write(tun, pkt.Buffer()))
{
llarp::LogWarn(self->Name(), " packet dropped");
return true;
}
return false;
});
});
}
void
@ -991,9 +1047,10 @@ namespace llarp
{
// called for every packet read from user in isolated network thread
auto *self = static_cast< TunEndpoint * >(tun->user);
const ManagedBuffer pkt(b);
self->m_UserToNetworkPktQueue.EmplaceIf(
[&pkt](net::IPPacket &p) -> bool { return p.Load(pkt); });
net::IPPacket pkt;
if(not pkt.Load(b))
return;
self->m_TunPkts.emplace_back(pkt);
}
TunEndpoint::~TunEndpoint() = default;

@ -56,6 +56,9 @@ namespace llarp
void
TickTun(llarp_time_t now);
static void
tunifTick(llarp_tun_io*);
bool
MapAddress(const service::Address& remote, huint128_t ip, bool SNode);
@ -145,22 +148,24 @@ namespace llarp
handleTickTun(void* u);
/// get a key for ip address
template < typename Addr >
Addr
template < typename Addr_t >
Addr_t
ObtainAddrForIP(huint128_t ip, bool isSNode)
{
Addr_t addr;
auto itr = m_IPToAddr.find(ip);
if(itr == m_IPToAddr.end() || m_SNodes[itr->second] != isSNode)
if(itr != m_IPToAddr.end() and m_SNodes[itr->second] == isSNode)
{
// not found
Addr addr;
addr.Zero();
return addr;
addr = Addr_t(itr->second);
}
// found
return Addr{itr->second};
return addr;
}
template < typename Addr_t >
bool
FindAddrForIP(Addr_t& addr, huint128_t ip);
bool
HasAddress(const AlignedBuffer< 32 >& addr) const
{
@ -179,9 +184,16 @@ namespace llarp
ResetInternalState() override;
protected:
using PacketQueue_t = llarp::util::CoDelQueue<
bool
ShouldFlushNow(llarp_time_t now) const;
llarp_time_t m_LastFlushAt = 0;
using PacketQueue_t = llarp::util::CoDelQueue<
net::IPPacket, net::IPPacket::GetTime, net::IPPacket::PutTime,
net::IPPacket::CompareOrder, net::IPPacket::GetNow >;
/// queue packet for send on net thread from user
std::vector< net::IPPacket > m_TunPkts;
/// queue for sending packets over the network from us
PacketQueue_t m_UserToNetworkPktQueue;
/// queue for sending packets to user from network
@ -308,6 +320,7 @@ namespace llarp
void
FlushToUser(std::function< bool(net::IPPacket&) > sendfunc);
};
} // namespace handlers
} // namespace llarp

@ -22,34 +22,6 @@ namespace llarp
LinkLayer::~LinkLayer() = default;
void
LinkLayer::Pump()
{
std::unordered_set< RouterID, RouterID::Hash > sessions;
{
ACQUIRE_LOCK(Lock_t l, m_AuthedLinksMutex);
auto itr = m_AuthedLinks.begin();
while(itr != m_AuthedLinks.end())
{
const RouterID r{itr->first};
sessions.emplace(r);
++itr;
}
}
ILinkLayer::Pump();
{
ACQUIRE_LOCK(Lock_t l, m_AuthedLinksMutex);
for(const auto& pk : sessions)
{
if(m_AuthedLinks.count(pk) == 0)
{
// all sessions were removed
SessionClosed(pk);
}
}
}
}
const char*
LinkLayer::Name() const
{

@ -29,6 +29,7 @@ namespace llarp
NewOutboundSession(const RouterContact &rc,
const AddressInfo &ai) override;
void
Pump() override;

@ -28,14 +28,15 @@ namespace llarp
return pkt;
}
Session::Session(LinkLayer* p, RouterContact rc, AddressInfo ai)
Session::Session(LinkLayer* p, const RouterContact& rc,
const AddressInfo& ai)
: m_State{State::Initial}
, m_Inbound{false}
, m_Parent{p}
, m_Parent(p)
, m_CreatedAt{p->Now()}
, m_RemoteAddr{ai}
, m_ChosenAI{std::move(ai)}
, m_RemoteRC{std::move(rc)}
, m_RemoteAddr(ai)
, m_ChosenAI(ai)
, m_RemoteRC(rc)
{
token.Zero();
GotLIM = util::memFn(&Session::GotOutboundLIM, this);
@ -43,12 +44,12 @@ namespace llarp
llarp_buffer_t(rc.pubkey));
}
Session::Session(LinkLayer* p, Addr from)
Session::Session(LinkLayer* p, const Addr& from)
: m_State{State::Initial}
, m_Inbound{true}
, m_Parent{p}
, m_Parent(p)
, m_CreatedAt{p->Now()}
, m_RemoteAddr{from}
, m_RemoteAddr(from)
{
token.Randomize();
GotLIM = util::memFn(&Session::GotInboundLIM, this);
@ -57,9 +58,10 @@ namespace llarp
}
void
Session::Send_LL(const llarp_buffer_t& pkt)
Session::Send_LL(const byte_t* buf, size_t sz)
{
LogDebug("send ", pkt.sz, " to ", m_RemoteAddr);
LogDebug("send ", sz, " to ", m_RemoteAddr);
const llarp_buffer_t pkt(buf, sz);
m_Parent->SendTo_LL(m_RemoteAddr, pkt);
m_LastTX = time_now_ms();
}
@ -144,8 +146,10 @@ namespace llarp
Session::EncryptWorker(CryptoQueue_ptr msgs)
{
LogDebug("encrypt worker ", msgs->size(), " messages");
for(auto& pkt : *msgs)
auto itr = msgs->begin();
while(itr != msgs->end())
{
Packet_t pkt = std::move(*itr);
llarp_buffer_t pktbuf(pkt);
const TunnelNonce nonce_ptr{pkt.data() + HMACSIZE};
pktbuf.base += PacketOverhead;
@ -155,10 +159,8 @@ namespace llarp
pktbuf.base = pkt.data() + HMACSIZE;
pktbuf.sz = pkt.size() - HMACSIZE;
CryptoManager::instance()->hmac(pkt.data(), pktbuf, m_SessionKey);
pktbuf.base = pkt.data();
pktbuf.cur = pkt.data();
pktbuf.sz = pkt.size();
Send_LL(pktbuf);
Send_LL(pkt.data(), pkt.size());
++itr;
}
}
@ -361,24 +363,27 @@ namespace llarp
{
TunnelNonce N;
N.Randomize();
ILinkSession::Packet_t req(Introduction::SIZE + PacketOverhead);
const auto pk = m_Parent->GetOurRC().pubkey;
const auto e_pk = m_Parent->RouterEncryptionSecret().toPublic();
auto itr = req.data() + PacketOverhead;
std::copy_n(pk.data(), pk.size(), itr);
itr += pk.size();
std::copy_n(e_pk.data(), e_pk.size(), itr);
itr += e_pk.size();
std::copy_n(N.data(), N.size(), itr);
Signature Z;
llarp_buffer_t signbuf(req.data() + PacketOverhead,
Introduction::SIZE - Signature::SIZE);
m_Parent->Sign(Z, signbuf);
std::copy_n(
Z.data(), Z.size(),
req.data() + PacketOverhead + (Introduction::SIZE - Signature::SIZE));
CryptoManager::instance()->randbytes(req.data() + HMACSIZE, TUNNONCESIZE);
EncryptAndSend(std::move(req));
{
ILinkSession::Packet_t req(Introduction::SIZE + PacketOverhead);
const auto pk = m_Parent->GetOurRC().pubkey;
const auto e_pk = m_Parent->RouterEncryptionSecret().toPublic();
auto itr = req.data() + PacketOverhead;
std::copy_n(pk.data(), pk.size(), itr);
itr += pk.size();
std::copy_n(e_pk.data(), e_pk.size(), itr);
itr += e_pk.size();
std::copy_n(N.data(), N.size(), itr);
Signature Z;
llarp_buffer_t signbuf(req.data() + PacketOverhead,
Introduction::SIZE - Signature::SIZE);
m_Parent->Sign(Z, signbuf);
std::copy_n(Z.data(), Z.size(),
req.data() + PacketOverhead
+ (Introduction::SIZE - Signature::SIZE));
CryptoManager::instance()->randbytes(req.data() + HMACSIZE,
TUNNONCESIZE);
EncryptAndSend(std::move(req));
}
m_State = State::Introduction;
if(not CryptoManager::instance()->transport_dh_client(
m_SessionKey, m_ChosenAI.pubkey,
@ -557,7 +562,8 @@ namespace llarp
recvMsgs->emplace_back(std::move(pkt));
}
LogDebug("decrypted ", recvMsgs->size(), " packets from ", m_RemoteAddr);
m_Parent->logic()->queue_func(
LogicCall(
m_Parent->logic(),
std::bind(&Session::HandlePlaintext, shared_from_this(), recvMsgs));
}

@ -39,9 +39,10 @@ namespace llarp
static constexpr std::size_t MaxACKSInMACK = 1024 / sizeof(uint64_t);
/// outbound session
Session(LinkLayer* parent, RouterContact rc, AddressInfo ai);
Session(LinkLayer* parent, const RouterContact& rc,
const AddressInfo& ai);
/// inbound session
Session(LinkLayer* parent, Addr from);
Session(LinkLayer* parent, const Addr& from);
~Session() = default;
@ -62,7 +63,7 @@ namespace llarp
CompletionHandler resultHandler) override;
void
Send_LL(const llarp_buffer_t& pkt);
Send_LL(const byte_t* buf, size_t sz);
void EncryptAndSend(ILinkSession::Packet_t);

@ -5,6 +5,7 @@
#include <memory>
#include <util/fs.hpp>
#include <utility>
#include <unordered_set>
namespace llarp
{
@ -128,6 +129,8 @@ namespace llarp
void
ILinkLayer::Pump()
{
std::unordered_set< RouterID, RouterID::Hash > closedSessions;
std::vector< std::shared_ptr< ILinkSession > > closedPending;
auto _now = Now();
{
ACQUIRE_LOCK(Lock_t l, m_AuthedLinksMutex);
@ -144,6 +147,7 @@ namespace llarp
llarp::LogInfo("session to ", RouterID(itr->second->GetPubKey()),
" timed out");
itr->second->Close();
closedSessions.emplace(itr->first);
itr = m_AuthedLinks.erase(itr);
}
}
@ -163,15 +167,25 @@ namespace llarp
{
LogInfo("pending session at ", itr->first, " timed out");
// defer call so we can acquire mutexes later
auto self = itr->second->BorrowSelf();
m_Logic->queue_func([&, self]() {
this->HandleTimeout(self.get());
self->Close();
});
closedPending.emplace_back(std::move(itr->second));
itr = m_Pending.erase(itr);
}
}
}
{
ACQUIRE_LOCK(Lock_t l, m_AuthedLinksMutex);
for(const auto& r : closedSessions)
{
if(m_AuthedLinks.count(r) == 0)
{
SessionClosed(r);
}
}
}
for(const auto& pending : closedPending)
{
HandleTimeout(pending.get());
}
}
bool
@ -444,7 +458,7 @@ namespace llarp
auto logic = link->logic();
if(logic == nullptr)
return;
logic->queue_func([pkts, link]() {
LogicCall(logic, [pkts, link]() {
auto itr = pkts->begin();
while(itr != pkts->end())
{

@ -410,7 +410,7 @@ namespace llarp
// we are the farthest hop
llarp::LogDebug("We are the farthest hop for ", info);
// send a LRSM down the path
self->context->logic()->queue_func([=]() {
LogicCall(self->context->logic(), [=]() {
SendPathConfirm(self);
self->decrypter = nullptr;
});
@ -419,7 +419,7 @@ namespace llarp
{
// forward upstream
// we are still in the worker thread so post job to logic
self->context->logic()->queue_func([=]() {
LogicCall(self->context->logic(), [=]() {
SendLRCM(self);
self->decrypter = nullptr;
});

@ -222,7 +222,7 @@ namespace llarp
std::shared_ptr< LR_StatusMessage > msg)
{
auto func = std::bind(&LR_StatusMessage::SendMessage, router, nextHop, msg);
router->pathContext().logic()->queue_func(func);
LogicCall(router->logic(), func);
}
void

@ -23,7 +23,7 @@ namespace llarp
uint16_t rank;
std::string dialect;
llarp::PubKey pubkey;
struct in6_addr ip;
in6_addr ip = {0};
uint16_t port;
uint64_t version = LLARP_PROTO_VERSION;

@ -18,8 +18,8 @@ namespace llarp
{
struct ExitInfo
{
struct in6_addr address;
struct in6_addr netmask;
in6_addr address = {0};
in6_addr netmask = {0};
PubKey pubkey;
uint64_t version = LLARP_PROTO_VERSION;

@ -87,7 +87,7 @@ namespace llarp
bool
IPPacket::Load(const llarp_buffer_t &pkt)
{
if(pkt.sz > sizeof(buf))
if(pkt.sz > sizeof(buf) or pkt.sz == 0)
return false;
sz = pkt.sz;
std::copy_n(pkt.base, sz, buf);

@ -1078,7 +1078,7 @@ namespace llarp
{
char buf[INET6_ADDRSTRLEN + 1] = {0};
std::string str;
in6_addr inaddr;
in6_addr inaddr = {0};
size_t numset = 0;
absl::uint128 bits = netmask_bits.h;
while(bits)

@ -191,6 +191,5 @@ namespace llarp
} // namespace llarp
#include <net/net_addr.hpp>
#include <net/net_inaddr.hpp>
#endif

@ -16,7 +16,13 @@
namespace llarp
{
Addr::Addr() = default;
Addr::Addr()
{
llarp::Zero(&_addr4, sizeof(_addr4));
_addr4.sin_family = AF_INET;
llarp::Zero(&_addr, sizeof(_addr));
_addr.sin6_family = AF_INET6;
}
Addr::~Addr() = default;
void
@ -53,18 +59,18 @@ namespace llarp
return (const in_addr*)&_addr.sin6_addr.s6_addr[12];
}
Addr::Addr(string_view str)
Addr::Addr(string_view str) : Addr()
{
this->from_char_array(str);
}
Addr::Addr(string_view str, const uint16_t p_port)
Addr::Addr(string_view str, const uint16_t p_port) : Addr()
{
this->from_char_array(str);
this->port(p_port);
}
Addr::Addr(string_view addr_str, string_view port_str)
Addr::Addr(string_view addr_str, string_view port_str) : Addr()
{
this->from_char_array(string_view_string(addr_str).c_str());
this->port(std::strtoul(string_view_string(port_str).c_str(), nullptr, 10));
@ -174,18 +180,20 @@ namespace llarp
Addr::Addr(const uint8_t one, const uint8_t two, const uint8_t three,
const uint8_t four)
: Addr()
{
this->from_4int(one, two, three, four);
}
Addr::Addr(const uint8_t one, const uint8_t two, const uint8_t three,
const uint8_t four, const uint16_t p_port)
: Addr()
{
this->from_4int(one, two, three, four);
this->port(p_port);
}
Addr::Addr(const AddressInfo& other)
Addr::Addr(const AddressInfo& other) : Addr()
{
memcpy(addr6(), other.ip.s6_addr, 16);
_addr.sin6_port = htons(other.port);
@ -200,7 +208,7 @@ namespace llarp
_addr.sin6_family = AF_INET6;
}
Addr::Addr(const sockaddr_in& other)
Addr::Addr(const sockaddr_in& other) : Addr()
{
Zero(&_addr, sizeof(sockaddr_in6));
_addr.sin6_family = AF_INET;
@ -217,7 +225,7 @@ namespace llarp
memcpy(&_addr4.sin_addr.s_addr, addr4(), sizeof(in_addr));
}
Addr::Addr(const sockaddr_in6& other)
Addr::Addr(const sockaddr_in6& other) : Addr()
{
memcpy(addr6(), other.sin6_addr.s6_addr, 16);
_addr.sin6_port = htons(other.sin6_port);
@ -236,7 +244,7 @@ namespace llarp
_addr.sin6_family = AF_INET6;
}
Addr::Addr(const sockaddr& other)
Addr::Addr(const sockaddr& other) : Addr()
{
Zero(&_addr, sizeof(sockaddr_in6));
_addr.sin6_family = other.sa_family;

@ -16,7 +16,7 @@ namespace llarp
{
// network order
sockaddr_in6 _addr;
sockaddr_in _addr4; // why do we even have this? favor cpu over memory
sockaddr_in _addr4;
~Addr();
Addr();

@ -1,228 +0,0 @@
#include <net/net_inaddr.hpp>
std::ostream&
operator<<(std::ostream& out, const llarp::inAddr& a)
{
char tmp[128] = {0};
if(a.isIPv6Mode())
{
out << "[";
}
if(inet_ntop(a.isIPv4Mode() ? AF_INET : AF_INET6, (void*)&a._addr, tmp,
sizeof(tmp)))
{
out << tmp;
if(a.isIPv6Mode())
out << "]";
}
return out;
}
namespace llarp
{
void
inAddr::reset()
{
llarp::Zero(&this->_addr, sizeof(in6_addr));
}
bool
inAddr::from_char_array(const char* str)
{
this->reset();
// maybe refactor the family detection out
struct addrinfo hint, *res = nullptr;
int ret;
memset(&hint, '\0', sizeof hint);
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo(str, nullptr, &hint, &res);
if(ret)
{
llarp::LogError("failed to determine address family: ", str);
return false;
}
if(res->ai_family != AF_INET && res->ai_family != AF_INET6)
{
llarp::LogError("Address family not supported yet", str);
return false;
}
// convert detected-family (ipv4 or ipv6) str to in6_addr
/*
if (res->ai_family == AF_INET)
{
freeaddrinfo(res);
// get IPv4
struct in_addr addr; // basically a uint32_t network order
if(inet_aton(str, &addr) == 0)
{
llarp::LogError("failed to parse ", str);
return false;
}
nuint32_t result;
result.n = addr.s_addr;
this->fromN32(result);
return true;
}
*/
ret = inet_pton(res->ai_family, str, &this->_addr);
// inet_pton won't set SIIT
// this->hexDebug();
freeaddrinfo(res);
if(ret <= 0)
{
if(ret == 0)
{
llarp::LogWarn("Not in presentation format");
return false;
}
llarp::LogWarn("inet_pton failure");
return false;
}
return true;
}
void
inAddr::fromSIIT()
{
if(ipv6_is_siit(this->_addr))
{
this->_addr.s6_addr[0] = this->_addr.s6_addr[12];
this->_addr.s6_addr[1] = this->_addr.s6_addr[13];
this->_addr.s6_addr[2] = this->_addr.s6_addr[14];
this->_addr.s6_addr[3] = this->_addr.s6_addr[15];
this->setIPv4Mode();
}
}
void
inAddr::toSIIT()
{
if(!ipv6_is_siit(this->_addr))
{
this->_addr.s6_addr[10] = 0xff;
this->_addr.s6_addr[11] = 0xff;
this->_addr.s6_addr[12] = this->_addr.s6_addr[0];
this->_addr.s6_addr[13] = this->_addr.s6_addr[1];
this->_addr.s6_addr[14] = this->_addr.s6_addr[2];
this->_addr.s6_addr[15] = this->_addr.s6_addr[3];
llarp::Zero(&this->_addr, sizeof(in6_addr) - 6);
}
}
inline bool
inAddr::isIPv6Mode() const
{
return !this->isIPv4Mode();
}
bool
inAddr::isIPv4Mode() const
{
return ipv6_is_siit(this->_addr)
|| (this->_addr.s6_addr[4] == 0 && this->_addr.s6_addr[5] == 0
&& this->_addr.s6_addr[6] == 0 && this->_addr.s6_addr[7] == 0
&& this->_addr.s6_addr[8] == 0 && this->_addr.s6_addr[9] == 0
&& this->_addr.s6_addr[10] == 0 && this->_addr.s6_addr[11] == 0
&& this->_addr.s6_addr[12] == 0 && this->_addr.s6_addr[13] == 0
&& this->_addr.s6_addr[14] == 0 && this->_addr.s6_addr[15] == 0);
}
void
inAddr::setIPv4Mode()
{
// keep first 4
// llarp::Zero(&this->_addr + 4, sizeof(in6_addr) - 4);
this->_addr.s6_addr[4] = 0;
this->_addr.s6_addr[5] = 0;
this->_addr.s6_addr[6] = 0;
this->_addr.s6_addr[7] = 0;
this->_addr.s6_addr[8] = 0;
this->_addr.s6_addr[9] = 0;
this->_addr.s6_addr[10] = 0;
this->_addr.s6_addr[11] = 0;
this->_addr.s6_addr[12] = 0;
this->_addr.s6_addr[13] = 0;
this->_addr.s6_addr[14] = 0;
this->_addr.s6_addr[15] = 0;
}
void
inAddr::hexDebug()
{
char hex_buffer[16 * 3 + 1];
hex_buffer[16 * 3] = 0;
for(unsigned int j = 0; j < 16; j++)
sprintf(&hex_buffer[3 * j], "%02X ", this->_addr.s6_addr[j]);
printf("in6_addr: [%s]\n", hex_buffer);
}
//
// IPv4 specific functions
//
in_addr
inAddr::toIAddr()
{
in_addr res;
res.s_addr = toN32().n;
return res;
}
void
inAddr::from4int(const uint8_t one, const uint8_t two, const uint8_t three,
const uint8_t four)
{
this->reset();
this->setIPv4Mode();
// Network byte order
this->_addr.s6_addr[0] = one;
this->_addr.s6_addr[1] = two;
this->_addr.s6_addr[2] = three;
this->_addr.s6_addr[3] = four;
}
void
inAddr::fromN32(nuint32_t in)
{
this->reset();
this->setIPv4Mode();
memcpy(&this->_addr, &in.n, sizeof(uint32_t));
}
void
inAddr::fromH32(huint32_t in)
{
this->fromN32(xhtonl(in));
}
nuint32_t
inAddr::toN32()
{
nuint32_t result;
result.n = 0; // return 0 for IPv6
if(this->isIPv4Mode())
{
memcpy(&result.n, &this->_addr, sizeof(uint32_t));
}
return result;
}
huint32_t
inAddr::toH32()
{
return xntohl(this->toN32());
}
//
// IPv6 specific functions
//
} // namespace llarp

@ -1,81 +0,0 @@
#ifndef LLARP_NET_INADDR_HPP
#define LLARP_NET_INADDR_HPP
#include <net/net.hpp>
namespace llarp
{
/// IPv4 or IPv6 holder
struct inAddr
{
// unsigned char s6_addr[16];
struct in6_addr _addr; // store in network order
/// zero out
void
reset();
/// from char*
bool
from_char_array(const char* str);
/// convert from SIIT to IPv4 Mode
void
fromSIIT();
/// convert from IPv4 Mode to SIIT
void
toSIIT();
/// not IPv4 Mode (an actual IPv6 address)
inline bool
isIPv6Mode() const;
/// IPv4 mode (not SIIT)
bool
isIPv4Mode() const;
/// clear out bytes 5-15 (Last 12 bytes)
/// This is how inet_pton works with IPv4 addresses
void
setIPv4Mode();
/// make debugging/testing easier
void
hexDebug();
//
// IPv4 specific functions
//
/// make ipv4 in_addr struct
in_addr
toIAddr();
/// set an IPv4 addr
void
from4int(const uint8_t one, const uint8_t two, const uint8_t three,
const uint8_t four);
/// set from an net-order uint32_t
void
fromN32(nuint32_t in);
/// set from an host-order uint32_t
void
fromH32(huint32_t in);
/// output as net-order uint32_t
nuint32_t
toN32();
/// output as host-order uint32_t
huint32_t
toH32();
//
// IPv6 specific functions
//
// coming soon
};
} // namespace llarp
#endif

@ -122,7 +122,7 @@ llarp_nodedb::InsertAsync(llarp::RouterContact rc,
this->Insert(rc);
if(logic && completionHandler)
{
logic->queue_func([completionHandler] { completionHandler(); });
LogicCall(logic, completionHandler);
}
});
}

@ -155,7 +155,7 @@ namespace llarp
{
llarp::LogDebug("LR_Status message processed, path build successful");
auto self = shared_from_this();
r->logic()->queue_func([=]() { self->HandlePathConfirmMessage(r); });
LogicCall(r->logic(), [=]() { self->HandlePathConfirmMessage(r); });
}
else
{
@ -206,8 +206,8 @@ namespace llarp
llarp::LogDebug("Path build failed for an unspecified reason");
}
auto self = shared_from_this();
r->logic()->queue_func(
[=]() { self->EnterState(ePathFailed, r->Now()); });
LogicCall(r->logic(),
[=]() { self->EnterState(ePathFailed, r->Now()); });
}
// TODO: meaningful return value?
@ -411,9 +411,9 @@ namespace llarp
msg.pathid = TXID();
++idx;
}
r->logic()->queue_func(std::bind(&Path::HandleAllUpstream,
shared_from_this(), std::move(sendmsgs),
r));
LogicCall(r->logic(),
std::bind(&Path::HandleAllUpstream, shared_from_this(),
std::move(sendmsgs), r));
}
void
@ -482,9 +482,9 @@ namespace llarp
sendMsgs[idx].X = buf;
++idx;
}
r->logic()->queue_func(std::bind(&Path::HandleAllDownstream,
shared_from_this(), std::move(sendMsgs),
r));
LogicCall(r->logic(),
std::bind(&Path::HandleAllDownstream, shared_from_this(),
std::move(sendMsgs), r));
}
void

@ -239,10 +239,10 @@ namespace llarp
return m_Router;
}
HopHandler_ptr
TransitHop_ptr
PathContext::GetPathForTransfer(const PathID_t& id)
{
RouterID us(OurRouterID());
const RouterID us(OurRouterID());
auto& map = m_TransitPaths;
{
SyncTransitMap_t::Lock_t lock(&map.first);

@ -67,7 +67,7 @@ namespace llarp
bool
TransitHopPreviousIsRouter(const PathID_t& path, const RouterID& r);
HopHandler_ptr
TransitHop_ptr
GetPathForTransfer(const PathID_t& topath);
HopHandler_ptr

@ -98,7 +98,7 @@ namespace llarp
{
// farthest hop
// TODO: encrypt junk frames because our public keys are not eligator
logic->queue_func(std::bind(result, shared_from_this()));
LogicCall(logic, std::bind(result, shared_from_this()));
}
else
{

@ -32,7 +32,13 @@ namespace llarp
return stream;
}
TransitHop::TransitHop() = default;
TransitHop::TransitHop() : m_UpstreamGather(128), m_DownstreamGather(128)
{
m_UpstreamGather.enable();
m_DownstreamGather.enable();
m_UpstreamWorkCounter = 0;
m_DownstreamWorkCounter = 0;
}
bool
TransitHop::Expired(llarp_time_t now) const
@ -118,43 +124,73 @@ namespace llarp
void
TransitHop::DownstreamWork(TrafficQueue_ptr msgs, AbstractRouter* r)
{
std::vector< RelayDownstreamMessage > sendmsgs(msgs->size());
size_t idx = 0;
m_DownstreamWorkCounter++;
auto flushIt = [self = shared_from_this(), r]() {
std::vector< RelayDownstreamMessage > msgs;
do
{
auto maybe = self->m_DownstreamGather.tryPopFront();
if(not maybe.has_value())
break;
msgs.emplace_back(maybe.value());
} while(true);
self->HandleAllDownstream(std::move(msgs), r);
};
for(auto& ev : *msgs)
{
RelayDownstreamMessage msg;
const llarp_buffer_t buf(ev.first);
auto& msg = sendmsgs[idx];
msg.pathid = info.rxID;
msg.Y = ev.second ^ nonceXOR;
CryptoManager::instance()->xchacha20(buf, pathKey, ev.second);
msg.X = buf;
llarp::LogDebug("relay ", msg.X.size(), " bytes downstream from ",
info.upstream, " to ", info.downstream);
++idx;
if(m_DownstreamGather.full())
{
LogicCall(r->logic(), flushIt);
}
if(m_DownstreamGather.enabled())
m_DownstreamGather.pushBack(msg);
}
r->logic()->queue_func(std::bind(&TransitHop::HandleAllDownstream,
shared_from_this(), std::move(sendmsgs),
r));
m_DownstreamWorkCounter--;
if(m_DownstreamWorkCounter == 0)
LogicCall(r->logic(), flushIt);
}
void
TransitHop::UpstreamWork(TrafficQueue_ptr msgs, AbstractRouter* r)
{
std::vector< RelayUpstreamMessage > sendmsgs(msgs->size());
size_t idx = 0;
m_UpstreamWorkCounter++;
auto flushIt = [self = shared_from_this(), r]() {
std::vector< RelayUpstreamMessage > msgs;
do
{
auto maybe = self->m_UpstreamGather.tryPopFront();
if(not maybe.has_value())
break;
msgs.emplace_back(maybe.value());
} while(true);
self->HandleAllUpstream(std::move(msgs), r);
};
for(auto& ev : *msgs)
{
const llarp_buffer_t buf(ev.first);
auto& msg = sendmsgs[idx];
RelayUpstreamMessage msg;
CryptoManager::instance()->xchacha20(buf, pathKey, ev.second);
msg.pathid = info.txID;
msg.Y = ev.second ^ nonceXOR;
msg.X = buf;
++idx;
if(m_UpstreamGather.full())
{
LogicCall(r->logic(), flushIt);
}
if(m_UpstreamGather.enabled())
m_UpstreamGather.pushBack(msg);
}
r->logic()->queue_func(std::bind(&TransitHop::HandleAllUpstream,
shared_from_this(), std::move(sendmsgs),
r));
m_UpstreamWorkCounter--;
if(m_UpstreamWorkCounter == 0)
LogicCall(r->logic(), flushIt);
}
void
@ -173,6 +209,11 @@ namespace llarp
m_LastActivity = r->Now();
}
FlushDownstream(r);
for(const auto& other : m_FlushOthers)
{
other->FlushUpstream(r);
}
m_FlushOthers.clear();
}
else
{
@ -183,7 +224,7 @@ namespace llarp
r->SendToOrQueue(info.upstream, &msg);
}
}
r->linkManager().PumpLinks();
r->PumpLL();
}
void
@ -196,7 +237,7 @@ namespace llarp
info.upstream, " to ", info.downstream);
r->SendToOrQueue(info.downstream, &msg);
}
r->linkManager().PumpLinks();
r->PumpLL();
}
void
@ -410,7 +451,10 @@ namespace llarp
buf.cur = buf.base;
// send
if(path->HandleDownstream(buf, msg.Y, r))
{
m_FlushOthers.emplace(path);
return true;
}
return SendRoutingMessage(discarded, r);
}
@ -421,10 +465,16 @@ namespace llarp
printer.printAttribute("TransitHop", info);
printer.printAttribute("started", started);
printer.printAttribute("lifetime", lifetime);
return stream;
}
void
TransitHop::Stop()
{
m_UpstreamGather.disable();
m_DownstreamGather.disable();
}
void
TransitHop::SetSelfDestruct()
{
@ -435,7 +485,7 @@ namespace llarp
TransitHop::QueueDestroySelf(AbstractRouter* r)
{
auto func = std::bind(&TransitHop::SetSelfDestruct, shared_from_this());
r->logic()->queue_func(func);
LogicCall(r->logic(), func);
}
} // namespace path
} // namespace llarp

@ -6,6 +6,7 @@
#include <path/path_types.hpp>
#include <routing/handler.hpp>
#include <router_id.hpp>
#include <util/compare_ptr.hpp>
namespace llarp
{
@ -94,8 +95,17 @@ namespace llarp
llarp_proto_version_t version;
llarp_time_t m_LastActivity = 0;
void
Stop();
bool destroy = false;
bool
operator<(const TransitHop& other) const
{
return info < other.info;
}
bool
IsEndpoint(const RouterID& us) const
{
@ -222,6 +232,14 @@ namespace llarp
void
QueueDestroySelf(AbstractRouter* r);
std::set< std::shared_ptr< TransitHop >,
ComparePtr< std::shared_ptr< TransitHop > > >
m_FlushOthers;
thread::Queue< RelayUpstreamMessage > m_UpstreamGather;
thread::Queue< RelayDownstreamMessage > m_DownstreamGather;
std::atomic< uint32_t > m_UpstreamWorkCounter;
std::atomic< uint32_t > m_DownstreamWorkCounter;
};
inline std::ostream&

@ -71,15 +71,18 @@ namespace llarp
void
OutboundMessageHandler::Tick()
{
ProcessOutboundQueue();
RemoveEmptyPathQueues();
SendRoundRobin();
m_Killer.TryAccess([self = this]() {
self->ProcessOutboundQueue();
self->RemoveEmptyPathQueues();
self->SendRoundRobin();
});
}
void
OutboundMessageHandler::QueueRemoveEmptyPath(const PathID_t &pathid)
{
removedPaths.pushBack(pathid);
m_Killer.TryAccess(
[self = this, pathid]() { self->removedPaths.pushBack(pathid); });
}
// TODO: this
@ -164,8 +167,8 @@ namespace llarp
{
if(callback)
{
auto func = std::bind(callback, status);
_logic->queue_func(func);
auto f = std::bind(callback, status);
LogicCall(_logic, [self = this, f]() { self->m_Killer.TryAccess(f); });
}
}
@ -265,7 +268,9 @@ namespace llarp
void
OutboundMessageHandler::RemoveEmptyPathQueues()
{
removedSomePaths = (not removedPaths.empty());
removedSomePaths = false;
if(removedPaths.empty())
return;
while(not removedPaths.empty())
{
@ -275,6 +280,7 @@ namespace llarp
outboundMessageQueues.erase(itr);
}
}
removedSomePaths = true;
}
void
@ -282,7 +288,7 @@ namespace llarp
{
// send non-routing messages first priority
auto &non_routing_mq = outboundMessageQueues[zeroID];
while(!non_routing_mq.empty())
while(not non_routing_mq.empty())
{
MessageQueueEntry entry = std::move(non_routing_mq.front());
non_routing_mq.pop();

@ -123,6 +123,8 @@ namespace llarp
ILinkManager *_linkManager;
std::shared_ptr< Logic > _logic;
util::ContentionKiller m_Killer;
// paths cannot have pathid "0", so it can be used as the "pathid"
// for non-traffic (control) messages, so they can be prioritized.
static const PathID_t zeroID;

@ -123,11 +123,6 @@ namespace llarp
int remainingDesired = numDesired;
_nodedb->visit([&](const RouterContact &other) -> bool {
// check if we really remainingDesired to
if(other.ExpiresSoon(now, 30000)) // TODO: make delta configurable
{
return remainingDesired > 0;
}
if(!_rcLookup->RemoteIsAllowed(other.pubkey))
{
return remainingDesired > 0;
@ -219,7 +214,7 @@ namespace llarp
if(ShouldConnectTo(router))
{
auto fn = std::bind(&OutboundSessionMaker::DoEstablish, this, router);
_logic->queue_func(fn);
LogicCall(_logic, fn);
}
}
@ -326,7 +321,7 @@ namespace llarp
for(const auto &callback : movedCallbacks)
{
auto func = std::bind(callback, router, type);
_logic->queue_func(func);
LogicCall(_logic, func);
}
{

@ -29,8 +29,13 @@
#include <iterator>
#include <unordered_map>
#include <utility>
#if defined(RPI) || defined(ANDROID)
#if defined(ANDROID) || defined(IOS)
#include <unistd.h>
#else
#if defined(_WIN32)
#else
#include <curl/curl.h>
#endif
#endif
bool
@ -143,9 +148,17 @@ namespace llarp
void
Router::PumpLL()
{
static constexpr size_t PumpJobThreshhold = 50;
static constexpr llarp_time_t PumpInterval = 25;
const auto now = Now();
if(_stopping.load())
return;
if(_logic->numPendingJobs() >= PumpJobThreshhold
&& _lastPump + PumpInterval >= now)
{
return;
}
_lastPump = now;
paths.PumpDownstream();
paths.PumpUpstream();
@ -197,6 +210,14 @@ namespace llarp
LogError(rcfile, " contains invalid RC");
}
static size_t
RecvIdentKey(char *ptr, size_t, size_t nmemb, void *userdata)
{
for(size_t idx = 0; idx < nmemb; idx++)
static_cast< std::vector< char > * >(userdata)->push_back(ptr[idx]);
return nmemb;
}
bool
Router::EnsureIdentity()
{
@ -207,10 +228,120 @@ namespace llarp
if (_identity.IsZero())
return false;
if (_encryption.IsZero())
return false;
if(whitelistRouters)
{
#if defined(ANDROID) || defined(IOS)
LogError("running a service node on mobile device is not possible.");
return false;
#else
#if defined(_WIN32)
LogError("running a service node on windows is not possible.");
return false;
#else
CURL *curl = curl_easy_init();
if(curl)
{
bool ret = false;
std::stringstream ss;
ss << "http://" << lokidRPCAddr << "/json_rpc";
const auto url = ss.str();
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
const auto auth = lokidRPCUser + ":" + lokidRPCPassword;
curl_easy_setopt(curl, CURLOPT_USERPWD, auth.c_str());
curl_slist *list = nullptr;
list = curl_slist_append(list, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
nlohmann::json request = {{"id", "0"},
{"jsonrpc", "2.0"},
{"method", "get_service_node_privkey"}};
const auto data = request.dump();
std::vector< char > resp;
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &RecvIdentKey);
do
{
resp.clear();
LogInfo("Getting Identity Keys from lokid...");
if(curl_easy_perform(curl) == CURLE_OK)
{
try
{
auto j = nlohmann::json::parse(resp);
if(not j.is_object())
continue;
const auto itr = j.find("result");
if(itr == j.end())
continue;
if(not itr->is_object())
continue;
const auto k =
(*itr)["service_node_ed25519_privkey"].get< std::string >();
if(k.size() != (_identity.size() * 2))
{
if(k.empty())
{
LogError("lokid gave no identity key");
}
else
{
LogError("lokid gave invalid identity key");
}
return false;
}
if(not HexDecode(k.c_str(), _identity.data(), _identity.size()))
continue;
if(CryptoManager::instance()->check_identity_privkey(_identity))
{
ret = true;
}
else
{
LogError("lokid gave bogus identity key");
}
}
catch(nlohmann::json::exception &ex)
{
LogError("Bad response from lokid: ", ex.what());
}
}
else
{
LogError("failed to get identity keys");
}
if(ret)
{
LogInfo("Got Identity Keys from lokid: ", RouterID(pubkey()));
break;
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
} while(true);
curl_easy_cleanup(curl);
curl_slist_free_all(list);
return ret;
}
else
{
LogError("failed to init curl");
return false;
}
#endif
#endif
}
return llarp_findOrCreateIdentity(ident_keyfile, _identity);
}
if(usingSNSeed)
{
LogError("FIXME: load identity key from SNode seed");
@ -287,7 +418,7 @@ namespace llarp
return;
auto *self = static_cast< Router * >(user);
self->ticker_job_id = 0;
self->logic()->queue_func(std::bind(&Router::Tick, self));
LogicCall(self->logic(), std::bind(&Router::Tick, self));
self->ScheduleTicker(orig);
}

@ -54,6 +54,7 @@ namespace llarp
{
struct Router final : public AbstractRouter
{
llarp_time_t _lastPump = 0;
bool ready;
// transient iwp encryption key
fs::path transport_keyfile = "transport.key";

@ -53,6 +53,48 @@ namespace llarp
PopulateReqHeaders(abyss::http::Headers_t& hdr) override;
};
struct LokiPingHandler final : public CallerHandler
{
~LokiPingHandler() override = default;
LokiPingHandler(::abyss::http::ConnImpl* impl, CallerImpl* parent)
: CallerHandler(impl, parent)
{
}
bool
HandleJSONResult(const nlohmann::json& result) override
{
if(not result.is_object())
{
LogError("invalid result from lokid ping, not an object");
return false;
}
const auto itr = result.find("status");
if(itr == result.end())
{
LogError("invalid result from lokid ping, no result");
return false;
}
if(not itr->is_string())
{
LogError("invalid result from lokid ping, status not an string");
return false;
}
const auto status = itr->get< std::string >();
if(status != "OK")
{
LogError("lokid ping failed: '", status, "'");
return false;
}
LogInfo("lokid ping: '", status, "'");
return true;
}
void
HandleError() override
{
LogError("Failed to ping lokid");
}
};
struct GetServiceNodeListHandler final : public CallerHandler
{
using PubkeyList_t = std::vector< RouterID >;
@ -120,7 +162,9 @@ namespace llarp
{
AbstractRouter* router;
llarp_time_t m_NextKeyUpdate = 0;
llarp_time_t m_NextPing = 0;
const llarp_time_t KeyUpdateInterval = 5000;
const llarp_time_t PingInterval = 60 * 5 * 1000;
using PubkeyList_t = GetServiceNodeListHandler::PubkeyList_t;
CallerImpl(AbstractRouter* r) : ::abyss::http::JSONRPC(), router(r)
@ -130,11 +174,18 @@ namespace llarp
void
Tick(llarp_time_t now)
{
if(not router->IsRunning())
return;
if(now >= m_NextKeyUpdate)
{
AsyncUpdatePubkeyList();
m_NextKeyUpdate = now + KeyUpdateInterval;
}
if(now >= m_NextPing)
{
AsyncLokiPing();
m_NextPing = now + PingInterval;
}
Flush();
}
@ -145,6 +196,20 @@ namespace llarp
password = passwd;
}
void
AsyncLokiPing()
{
LogInfo("Pinging Lokid");
static nlohmann::json::number_unsigned_t major(atoi(LLARP_VERSION_MAJ));
static nlohmann::json::number_unsigned_t minor(atoi(LLARP_VERSION_MIN));
static nlohmann::json::number_unsigned_t patch(
atoi(LLARP_VERSION_PATCH));
nlohmann::json params = {
{"version", nlohmann::json::array({major, minor, patch})}};
QueueRPC("lokinet_ping", std::move(params),
util::memFn(&CallerImpl::NewLokinetPingConn, this));
}
void
AsyncUpdatePubkeyList()
{
@ -162,6 +227,12 @@ namespace llarp
return RunAsync(router->netloop(), remote);
}
abyss::http::IRPCClientHandler*
NewLokinetPingConn(abyss::http::ConnImpl* impl)
{
return new LokiPingHandler(impl, this);
}
abyss::http::IRPCClientHandler*
NewAsyncUpdatePubkeyListConn(abyss::http::ConnImpl* impl)
{

@ -17,7 +17,6 @@ namespace llarp
: logic(std::move(l))
, m_remote(std::move(r))
, m_LocalIdentity(localident)
, frame(std::make_shared< ProtocolFrame >())
, introPubKey(introsetPubKey)
, remoteIntro(remote)
, handler(h)
@ -27,31 +26,33 @@ namespace llarp
}
void
AsyncKeyExchange::Result(std::shared_ptr< AsyncKeyExchange > self)
AsyncKeyExchange::Result(std::shared_ptr< AsyncKeyExchange > self,
std::shared_ptr< ProtocolFrame > frame)
{
// put values
self->handler->PutSenderFor(self->msg.tag, self->m_remote, false);
self->handler->PutCachedSessionKeyFor(self->msg.tag, self->sharedKey);
self->handler->PutIntroFor(self->msg.tag, self->remoteIntro);
self->handler->PutReplyIntroFor(self->msg.tag, self->msg.introReply);
self->hook(self->frame);
self->hook(frame);
}
void
AsyncKeyExchange::Encrypt(std::shared_ptr< AsyncKeyExchange > self)
AsyncKeyExchange::Encrypt(std::shared_ptr< AsyncKeyExchange > self,
std::shared_ptr< ProtocolFrame > frame)
{
// derive ntru session key component
SharedSecret K;
auto crypto = CryptoManager::instance();
crypto->pqe_encrypt(self->frame->C, K, self->introPubKey);
crypto->pqe_encrypt(frame->C, K, self->introPubKey);
// randomize Nonce
self->frame->N.Randomize();
frame->N.Randomize();
// compure post handshake session key
// PKE (A, B, N)
SharedSecret sharedSecret;
path_dh_func dh_client = util::memFn(&Crypto::dh_client, crypto);
if(!self->m_LocalIdentity.KeyExchange(dh_client, sharedSecret,
self->m_remote, self->frame->N))
self->m_remote, frame->N))
{
LogError("failed to derive x25519 shared key component");
}
@ -68,8 +69,9 @@ namespace llarp
// set version
self->msg.version = LLARP_PROTO_VERSION;
// encrypt and sign
if(self->frame->EncryptAndSign(self->msg, K, self->m_LocalIdentity))
self->logic->queue_func(std::bind(&AsyncKeyExchange::Result, self));
if(frame->EncryptAndSign(self->msg, K, self->m_LocalIdentity))
LogicCall(self->logic,
std::bind(&AsyncKeyExchange::Result, self, frame));
else
{
LogError("failed to encrypt and sign");

@ -19,7 +19,6 @@ namespace llarp
ServiceInfo m_remote;
const Identity& m_LocalIdentity;
ProtocolMessage msg;
std::shared_ptr< ProtocolFrame > frame;
Introduction intro;
const PQPubKey introPubKey;
Introduction remoteIntro;
@ -34,11 +33,13 @@ namespace llarp
const ConvoTag& t, ProtocolType proto);
static void
Result(std::shared_ptr< AsyncKeyExchange > user);
Result(std::shared_ptr< AsyncKeyExchange > user,
std::shared_ptr< ProtocolFrame > frame);
/// given protocol message make protocol frame
static void
Encrypt(std::shared_ptr< AsyncKeyExchange > user);
Encrypt(std::shared_ptr< AsyncKeyExchange > user,
std::shared_ptr< ProtocolFrame > frame);
};
} // namespace service

@ -29,12 +29,15 @@ namespace llarp
{
Endpoint::Endpoint(const std::string& name, AbstractRouter* r,
Context* parent)
: path::Builder(r, 3, path::default_len), context(parent)
: path::Builder(r, 3, path::default_len)
, context(parent)
, m_RecvQueue(128)
{
m_state = std::make_unique< EndpointState >();
m_state->m_Router = r;
m_state->m_Name = name;
m_state->m_Tag.Zero();
m_RecvQueue.enable();
}
bool
@ -805,6 +808,30 @@ namespace llarp
return {{"LOKINET_ADDR", m_Identity.pub.Addr().ToString()}};
}
void
Endpoint::FlushRecvData()
{
do
{
auto maybe = m_RecvQueue.tryPopFront();
if(not maybe.has_value())
return;
auto ev = std::move(maybe.value());
ProtocolMessage::ProcessAsync(ev.fromPath, ev.pathid, ev.msg);
} while(true);
}
void
Endpoint::QueueRecvData(RecvDataEvent ev)
{
if(m_RecvQueue.full() || m_RecvQueue.empty())
{
auto self = this;
LogicCall(m_router->logic(), [self]() { self->FlushRecvData(); });
}
m_RecvQueue.pushBack(std::move(ev));
}
bool
Endpoint::HandleDataMessage(path::Path_ptr path, const PathID_t from,
std::shared_ptr< ProtocolMessage > msg)
@ -1046,20 +1073,31 @@ namespace llarp
{
const auto& sessions = m_state->m_SNodeSessions;
auto& queue = m_state->m_InboundTrafficQueue;
EndpointLogic()->queue_func([&]() {
auto epPump = [&]() {
FlushRecvData();
// send downstream packets to user for snode
for(const auto& item : sessions)
item.second.first->FlushDownstream();
// send downstream traffic to user for hidden service
util::Lock lock(&m_state->m_InboundTrafficQueueMutex);
while(queue.size())
while(not queue.empty())
{
const auto& msg = queue.top();
const llarp_buffer_t buf(msg->payload);
HandleInboundPacket(msg->tag, buf, msg->proto);
queue.pop();
}
});
};
if(NetworkIsIsolated())
{
LogicCall(EndpointLogic(), epPump);
}
else
{
epPump();
}
auto router = Router();
// TODO: locking on this container
@ -1068,14 +1106,16 @@ namespace llarp
// TODO: locking on this container
for(const auto& item : sessions)
item.second.first->FlushUpstream();
util::Lock lock(&m_state->m_SendQueueMutex);
// send outbound traffic
for(const auto& item : m_state->m_SendQueue)
{
item.second->SendRoutingMessage(*item.first, router);
MarkConvoTagActive(item.first->T.T);
util::Lock lock(&m_state->m_SendQueueMutex);
// send outbound traffic
for(const auto& item : m_state->m_SendQueue)
{
item.second->SendRoutingMessage(*item.first, router);
MarkConvoTagActive(item.first->T.T);
}
m_state->m_SendQueue.clear();
}
m_state->m_SendQueue.clear();
router->PumpLL();
}
@ -1096,6 +1136,8 @@ namespace llarp
Endpoint::SendToServiceOrQueue(const service::Address& remote,
const llarp_buffer_t& data, ProtocolType t)
{
if(data.sz == 0)
return false;
// inbound converstation
const auto now = Now();

@ -78,6 +78,9 @@ namespace llarp
bool
IsReady() const;
void
QueueRecvData(RecvDataEvent ev) override;
/// return true if our introset has expired intros
bool
IntrosetIsStale() const;
@ -436,6 +439,9 @@ namespace llarp
hooks::Backend_ptr m_OnReady;
private:
void
FlushRecvData();
friend struct EndpointUtil;
// clang-format off
@ -448,6 +454,7 @@ namespace llarp
// clang-format on
std::unique_ptr< EndpointState > m_state;
thread::Queue< RecvDataEvent > m_RecvQueue;
};
using Endpoint_ptr = std::shared_ptr< Endpoint >;

@ -14,6 +14,14 @@ namespace llarp
namespace service
{
using ConvoTag = AlignedBuffer< 16 >;
struct ProtocolMessage;
struct RecvDataEvent
{
path::Path_ptr fromPath;
PathID_t pathid;
std::shared_ptr< ProtocolMessage > msg;
};
struct ProtocolMessage;
struct IDataHandler
@ -63,6 +71,9 @@ namespace llarp
virtual bool
HasInboundConvo(const Address& addr) const = 0;
virtual void
QueueRecvData(RecvDataEvent ev) = 0;
};
} // namespace service
} // namespace llarp

@ -26,7 +26,7 @@ namespace llarp
if(!msg)
return false;
endpoint = path->Endpoint();
r->logic()->queue_func([=]() { path->SendRoutingMessage(*msg, r); });
LogicCall(r->logic(), [=]() { path->SendRoutingMessage(*msg, r); });
return true;
}
} // namespace service

@ -62,7 +62,6 @@ namespace llarp
if(intro.expiresAt > m_NextIntro.expiresAt)
m_NextIntro = intro;
}
currentConvoTag.Randomize();
}
OutboundContext::~OutboundContext() = default;
@ -176,6 +175,8 @@ namespace llarp
OutboundContext::AsyncGenIntro(const llarp_buffer_t& payload,
ProtocolType t)
{
if(not currentConvoTag.IsZero())
return;
if(remoteIntro.router.IsZero())
SwapIntros();
@ -193,7 +194,9 @@ namespace llarp
return;
}
}
auto ex = std::make_shared< AsyncKeyExchange >(
currentConvoTag.Randomize();
auto frame = std::make_shared< ProtocolFrame >();
auto ex = std::make_shared< AsyncKeyExchange >(
m_Endpoint->RouterLogic(), remoteIdent, m_Endpoint->GetIdentity(),
currentIntroSet.K, remoteIntro, m_DataHandler, currentConvoTag, t);
@ -202,9 +205,9 @@ namespace llarp
ex->msg.PutBuffer(payload);
ex->msg.introReply = path->intro;
ex->frame->F = ex->msg.introReply.pathID;
frame->F = ex->msg.introReply.pathID;
m_Endpoint->CryptoWorker()->addJob(
std::bind(&AsyncKeyExchange::Encrypt, ex));
std::bind(&AsyncKeyExchange::Encrypt, ex, frame));
}
std::string

@ -343,8 +343,8 @@ namespace llarp
std::shared_ptr< ProtocolMessage > msg = std::move(self->msg);
path::Path_ptr path = std::move(self->path);
const PathID_t from = self->frame.F;
self->logic->queue_func(
[=]() { ProtocolMessage::ProcessAsync(path, from, msg); });
LogicCall(self->logic,
[=]() { ProtocolMessage::ProcessAsync(path, from, msg); });
delete self;
}
};
@ -364,13 +364,21 @@ namespace llarp
return *this;
}
struct AsyncDecrypt
{
ServiceInfo si;
SharedSecret shared;
ProtocolFrame frame;
};
bool
ProtocolFrame::AsyncDecryptAndVerify(
std::shared_ptr< Logic > logic, path::Path_ptr recvPath,
const std::shared_ptr< llarp::thread::ThreadPool >& worker,
const Identity& localIdent, IDataHandler* handler) const
{
auto msg = std::make_shared< ProtocolMessage >();
auto msg = std::make_shared< ProtocolMessage >();
msg->handler = handler;
if(T.IsZero())
{
LogInfo("Got protocol frame with new convo");
@ -380,38 +388,44 @@ namespace llarp
dh->path = recvPath;
return worker->addJob(std::bind(&AsyncFrameDecrypt::Work, dh));
}
SharedSecret shared;
if(!handler->GetCachedSessionKeyFor(T, shared))
auto v = new AsyncDecrypt();
if(!handler->GetCachedSessionKeyFor(T, v->shared))
{
LogError("No cached session for T=", T);
delete v;
return false;
}
ServiceInfo si;
if(!handler->GetSenderFor(T, si))
if(!handler->GetSenderFor(T, v->si))
{
LogError("No sender for T=", T);
delete v;
return false;
}
if(!Verify(si))
{
LogError("Signature failure from ", si.Addr());
return false;
}
if(!DecryptPayloadInto(shared, *msg))
{
LogError("failed to decrypt message");
return false;
}
if(T != msg->tag && !msg->tag.IsZero())
{
LogError("convotag missmatch: ", T, " != ", msg->tag);
return false;
}
msg->handler = handler;
const PathID_t fromPath = F;
logic->queue_func(
[=]() { ProtocolMessage::ProcessAsync(recvPath, fromPath, msg); });
return true;
v->frame = *this;
return worker->addJob(
[v, msg = std::move(msg), recvPath = std::move(recvPath)]() {
if(not v->frame.Verify(v->si))
{
LogError("Signature failure from ", v->si.Addr());
delete v;
return;
}
if(not v->frame.DecryptPayloadInto(v->shared, *msg))
{
LogError("failed to decrypt message");
delete v;
return;
}
RecvDataEvent ev;
ev.fromPath = std::move(recvPath);
ev.pathid = v->frame.F;
ev.msg = std::move(msg);
msg->handler->QueueRecvData(std::move(ev));
delete v;
});
}
bool

@ -95,15 +95,12 @@ namespace llarp
m->PutBuffer(payload);
auto self = this;
m_Endpoint->CryptoWorker()->addJob([f, m, shared, path, self]() {
if(!f->EncryptAndSign(*m, shared, self->m_Endpoint->GetIdentity()))
if(not f->EncryptAndSign(*m, shared, self->m_Endpoint->GetIdentity()))
{
LogError(self->m_Endpoint->Name(), " failed to sign message");
return;
}
self->m_Endpoint->RouterLogic()->queue_func([self, f, path]() {
self->Send(f, path);
self->FlushUpstream();
});
self->Send(f, path);
});
}
@ -111,7 +108,7 @@ namespace llarp
SendContext::AsyncEncryptAndSendTo(const llarp_buffer_t& data,
ProtocolType protocol)
{
if(lastGoodSend)
if(lastGoodSend != 0)
{
EncryptAndSendTo(data, protocol);
}

@ -14,9 +14,10 @@ namespace llarp
switch(lvl)
{
case eLogNone:
break;
case eLogDebug:
ss << "[DBG] ";
return;
case eLogTrace:
ss << "[TRC] ";
break case eLogDebug : ss << "[DBG] ";
break;
case eLogInfo:
ss << "[NFO] ";
@ -49,6 +50,9 @@ namespace llarp
str += tag;
switch(lvl)
{
case eLogTrace:
__android_log_write(ANDROID_LOG_TRACE, str.c_str(), msg.c_str());
return;
case eLogDebug:
__android_log_write(ANDROID_LOG_DEBUG, str.c_str(), msg.c_str());
return;

@ -5,28 +5,46 @@
namespace llarp
{
namespace
void
FileLogStream::Flush(Lines_t *lines, FILE *const f)
{
static void
Flush(std::deque< std::string > lines, FILE *const f)
bool wrote_stuff = false;
do
{
for(const auto &line : lines)
fprintf(f, "%s\n", line.c_str());
auto maybe_line = lines->tryPopFront();
if(not maybe_line.has_value())
break;
const auto &line = maybe_line.value();
if(fprintf(f, "%s\n", line.c_str()) >= 0)
wrote_stuff = true;
} while(true);
if(wrote_stuff)
fflush(f);
}
} // namespace
}
// namespace
FileLogStream::FileLogStream(std::shared_ptr< thread::ThreadPool > disk,
FILE *f, llarp_time_t flushInterval,
bool closeFile)
: m_Disk(std::move(disk))
: m_Lines(1024 * 8)
, m_Disk(std::move(disk))
, m_File(f)
, m_FlushInterval(flushInterval)
, m_Close(closeFile)
{
m_Lines.enable();
}
FileLogStream::~FileLogStream()
{
m_Lines.disable();
do
{
auto line = m_Lines.tryPopFront();
if(not line.has_value())
break;
} while(true);
fflush(m_File);
if(m_Close)
fclose(m_File);
@ -35,6 +53,8 @@ namespace llarp
bool
FileLogStream::ShouldFlush(llarp_time_t now) const
{
if(m_Lines.full())
return true;
if(m_LastFlush >= now)
return false;
const auto dlt = now - m_LastFlush;
@ -54,7 +74,15 @@ namespace llarp
void
FileLogStream::Print(LogLevel, const char *, const std::string &msg)
{
m_Lines.emplace_back(msg);
m_Lines.pushBack(msg);
}
void
FileLogStream::AppendLog(LogLevel lvl, const char *fname, int lineno,
const std::string &nodename, const std::string msg)
{
ILogStream::AppendLog(lvl, fname, lineno, nodename, msg);
Tick(llarp::time_now_ms());
}
void
@ -68,9 +96,8 @@ namespace llarp
FileLogStream::FlushLinesToDisk(llarp_time_t now)
{
FILE *const f = m_File;
std::deque< std::string > lines(m_Lines);
m_Disk->addJob([=]() { Flush(lines, f); });
m_Lines.clear();
auto lines = &m_Lines;
m_Disk->addJob([f, lines]() { Flush(lines, f); });
m_LastFlush = now;
}
} // namespace llarp

@ -4,6 +4,7 @@
#include <util/logging/logstream.hpp>
#include <util/thread/thread_pool.hpp>
#include <util/thread/queue.hpp>
#include <util/time.hpp>
#include <deque>
@ -29,14 +30,21 @@ namespace llarp
Tick(llarp_time_t now) override;
void
PostLog(std::stringstream&) const override
{
}
PostLog(std::stringstream&) const override{};
void
AppendLog(LogLevel lvl, const char* fname, int lineno,
const std::string& nodename, const std::string msg) override;
using Lines_t = thread::Queue< std::string >;
protected:
std::deque< std::string > m_Lines;
Lines_t m_Lines;
private:
static void
Flush(Lines_t* const, FILE* const);
bool
ShouldFlush(llarp_time_t now) const;

@ -14,7 +14,7 @@ namespace llarp
obj["line"] = lineno;
obj["level"] = LogLevelToString(lvl);
obj["message"] = msg;
m_Lines.emplace_back(obj.dump());
m_Lines.pushBack(obj.dump());
}
} // namespace llarp

@ -236,15 +236,29 @@ namespace llarp
*/
} // namespace llarp
#define LogTrace(...) _Log(llarp::eLogTrace, LOG_TAG, __LINE__, __VA_ARGS__)
#define LogDebug(...) _Log(llarp::eLogDebug, LOG_TAG, __LINE__, __VA_ARGS__)
#define LogInfo(...) _Log(llarp::eLogInfo, LOG_TAG, __LINE__, __VA_ARGS__)
#define LogWarn(...) _Log(llarp::eLogWarn, LOG_TAG, __LINE__, __VA_ARGS__)
#define LogError(...) _Log(llarp::eLogError, LOG_TAG, __LINE__, __VA_ARGS__)
#define LogTraceTag(tag, ...) _Log(llarp::eLogTrace, tag, __LINE__, __VA_ARGS__)
#define LogDebugTag(tag, ...) _Log(llarp::eLogDebug, tag, __LINE__, __VA_ARGS__)
#define LogInfoTag(tag, ...) _Log(llarp::eLogInfo, tag, __LINE__, __VA_ARGS__)
#define LogWarnTag(tag, ...) _Log(llarp::eLogWarn, tag, __LINE__, __VA_ARGS__)
#define LogErrorTag(tag, ...) _Log(llarp::eLogError, tag, __LINE__, __VA_ARGS__)
#define LogTraceExplicit(tag, line, ...) \
_Log(llarp::eLogTrace, tag, line, __VA_ARGS__)
#define LogDebugExplicit(tag, line, ...) \
_Log(llarp::eLogDebug, tag, line, __VA_ARGS__)
#define LogInfoExplicit(tag, line, ...) \
_Log(llarp::eLogInfo, tag, line __VA_ARGS__)
#define LogWarnExplicit(tag, line, ...) \
_Log(llarp::eLogWarn, tag, line, __VA_ARGS__)
#define LogErrorExplicit(tag, line, ...) \
_Log(llarp::eLogError, tag, line, __VA_ARGS__)
#ifndef LOG_TAG
#define LOG_TAG "default"
#endif

@ -7,6 +7,8 @@ namespace llarp
{
switch(lvl)
{
case eLogTrace:
return "TRC";
case eLogDebug:
return "DBG";
case eLogInfo:

@ -7,6 +7,7 @@ namespace llarp
// probably will need to move out of llarp namespace for c api
enum LogLevel
{
eLogTrace,
eLogDebug,
eLogInfo,
eLogWarn,

@ -18,7 +18,8 @@ namespace llarp
switch(lvl)
{
case eLogNone:
break;
return;
case eLogTrace:
case eLogDebug:
ss << (char)27 << "[0m";
break;

@ -23,6 +23,7 @@ namespace llarp
{
case eLogNone:
return;
case eLogTrace:
case eLogDebug:
::syslog(LOG_DEBUG, "%s", msg.c_str());
return;

@ -34,6 +34,8 @@ namespace llarp
{
case eLogNone:
break;
case eLogTrace:
ss << "[TRC] ";
case eLogDebug:
ss << "[DBG] ";
break;

@ -0,0 +1,35 @@
#include <util/lokinet_init.h>
#if defined(_WIN32)
#include <windows.h>
#include <winuser.h>
#include <stdio.h>
int
Lokinet_INIT(void)
{
static const char *(CDECL * pwine_get_version)(void);
HMODULE hntdll = GetModuleHandle("ntdll.dll");
if(hntdll)
{
pwine_get_version = (void *)GetProcAddress(hntdll, "wine_get_version");
if(pwine_get_version)
{
static const char *text =
"dont run lokinet in wine like wtf man we support linux and pretty "
"much every flavour of BSD, and even some flavours of unix system "
"5.x.\nThis Program Will now crash lmao.";
static const char *title = "srsly fam wtf";
MessageBoxA(NULL, text, title, MB_ICONHAND);
abort();
}
}
return 0;
}
#else
int
Lokinet_INIT(void)
{
return 0;
}
#endif

@ -0,0 +1,24 @@
#ifndef LLARP_UTIL_LOKINET_INIT_H
#define LLARP_UTIL_LOKINET_INIT_H
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef Lokinet_INIT
#if defined(_WIN32)
#define Lokinet_INIT \
DieInCaseSomehowThisGetsRunInWineButLikeWTFThatShouldNotHappenButJustInCaseHandleItWithAPopupOrSomeShit
#else
#define Lokinet_INIT _lokinet_non_shit_platform_INIT
#endif
#endif
int
Lokinet_INIT(void);
#ifdef __cplusplus
}
#endif
#endif

@ -2,6 +2,7 @@
#include <util/thread/timer.hpp>
#include <util/logging/logger.hpp>
#include <util/mem.h>
#include <util/metrics/metrics.hpp>
#include <future>
@ -13,8 +14,8 @@ namespace llarp
llarp_timer_tick_all_async(m_Timer, m_Thread, now);
}
Logic::Logic()
: m_Thread(llarp_init_threadpool(1, "llarp-logic"))
Logic::Logic(size_t sz)
: m_Thread(llarp_init_threadpool(1, "llarp-logic", sz))
, m_Timer(llarp_init_timer())
{
llarp_threadpool_start(m_Thread);
@ -36,10 +37,17 @@ namespace llarp
llarp_free_timer(m_Timer);
}
size_t
Logic::numPendingJobs() const
{
return m_Thread->pendingJobs();
}
bool
Logic::queue_job(struct llarp_thread_job job)
{
return job.user && job.work && queue_func(std::bind(job.work, job.user));
return job.user && job.work
&& LogicCall(this, std::bind(job.work, job.user));
}
void
@ -47,28 +55,61 @@ namespace llarp
{
llarp::LogDebug("logic thread stop");
// stop all timers from happening in the future
queue_func(std::bind(&llarp_timer_stop, m_Timer));
LogicCall(this, std::bind(&llarp_timer_stop, m_Timer));
// stop all operations on threadpool
llarp_threadpool_stop(m_Thread);
}
bool
Logic::queue_func(std::function< void(void) > f)
Logic::_traceLogicCall(std::function< void(void) > func, const char* tag,
int line)
{
#define TAG (tag ? tag : LOG_TAG)
#define LINE (line ? line : __LINE__)
// wrap the function so that we ensure that it's always calling stuff one at
// a time
#if defined(LOKINET_DEBUG)
#define METRIC(action) \
metrics::integerTick("logic", action, 1, "tag", TAG, "line", \
std::to_string(LINE))
#else
#define METRIC(action) \
do \
{ \
} while(false)
#endif
METRIC("queue");
auto f = [self = this, func, tag, line]() {
#if defined(LOKINET_DEBUG)
metrics::TimerGuard g("logic",
std::string(TAG) + ":" + std::to_string(LINE));
#endif
self->m_Killer.TryAccess(func);
};
if(can_flush())
{
METRIC("fired");
f();
return true;
}
if(m_Thread->LooksFull(5))
{
LogWarn(
"holy crap, we are trying to queue a job onto the logic thread but "
"it looks full");
if(can_flush())
{
// we are calling in the logic thread and our queue looks full
// defer call to a later time so we don't die like a little bitch
call_later(m_Thread->GuessJobLatency() / 2, f);
return true;
}
LogErrorExplicit(TAG, LINE, "holy crap, we are trying to queue a job "
"onto the logic thread but it looks full");
METRIC("full");
std::abort();
}
auto ret = llarp_threadpool_queue_job(m_Thread, f);
if(not ret)
{
METRIC("dropped");
}
return llarp_threadpool_queue_job(m_Thread, f);
return ret;
#undef TAG
#undef LINE
#undef METRIC
}
void

@ -11,7 +11,7 @@ namespace llarp
class Logic
{
public:
Logic();
Logic(size_t queueLength = size_t{1024 * 8});
~Logic();
@ -27,7 +27,8 @@ namespace llarp
queue_job(struct llarp_thread_job job);
bool
queue_func(std::function< void(void) > func);
_traceLogicCall(std::function< void(void) > func, const char* filename,
int lineo);
uint32_t
call_later(const llarp_timeout_job& job);
@ -41,6 +42,9 @@ namespace llarp
void
remove_call(uint32_t id);
size_t
numPendingJobs() const;
bool
can_flush() const;
@ -49,7 +53,19 @@ namespace llarp
llarp_threadpool* const m_Thread;
llarp_timer_context* const m_Timer;
absl::optional< ID_t > m_ID;
util::ContentionKiller m_Killer;
};
} // namespace llarp
#ifndef LogicCall
#if defined(LOKINET_DEBUG)
#ifdef LOG_TAG
#define LogicCall(l, ...) l->_traceLogicCall(__VA_ARGS__, LOG_TAG, __LINE__)
#else
#define LogicCall(l, ...) l->_traceLogicCall(__VA_ARGS__, __FILE__, __LINE__)
#endif
#else
#define LogicCall(l, ...) l->_traceLogicCall(__VA_ARGS__, 0, 0)
#endif
#endif
#endif

@ -156,6 +156,21 @@ namespace llarp
return ::getpid();
#endif
}
// type for detecting contention on a resource
struct ContentionKiller
{
template < typename F >
void
TryAccess(F visit) const
{
NullLock lock(&__access);
visit();
}
private:
mutable NullMutex __access;
};
} // namespace util
} // namespace llarp

@ -8,11 +8,11 @@
#include <queue>
struct llarp_threadpool *
llarp_init_threadpool(int workers, const char *name)
llarp_init_threadpool(int workers, const char *name, size_t queueLength)
{
if(workers <= 0)
workers = 1;
return new llarp_threadpool(workers, name);
return new llarp_threadpool(workers, name, queueLength);
}
void

@ -19,7 +19,7 @@ struct llarp_threadpool
std::unique_ptr< llarp::thread::ThreadPool > impl;
llarp_threadpool(int workers, llarp::string_view name,
size_t queueLength = size_t{1024})
size_t queueLength = size_t{1024 * 8})
: impl(std::make_unique< llarp::thread::ThreadPool >(
workers, std::max(queueLength, size_t{32}), name))
{
@ -48,7 +48,7 @@ struct llarp_threadpool
#endif
struct llarp_threadpool *
llarp_init_threadpool(int workers, const char *name);
llarp_init_threadpool(int workers, const char *name, size_t queueLength);
void
llarp_free_threadpool(struct llarp_threadpool **tp);

@ -45,12 +45,6 @@ namespace llarp
{
static_cast< timer* >(user)->exec();
}
bool
operator<(const timer& other) const
{
return (started + timeout) < (other.started + other.timeout);
}
};
} // namespace llarp
@ -59,7 +53,6 @@ struct llarp_timer_context
llarp::util::Mutex timersMutex; // protects timers
std::unordered_map< uint32_t, std::unique_ptr< llarp::timer > > timers
GUARDED_BY(timersMutex);
std::priority_queue< std::unique_ptr< llarp::timer > > calling;
llarp::util::Mutex tickerMutex;
std::unique_ptr< llarp::util::Condition > ticker;
absl::Duration nextTickLen = absl::Milliseconds(100);
@ -230,14 +223,15 @@ llarp_timer_tick_all(struct llarp_timer_context* t)
{
if(!t->run())
return;
const auto now = llarp::time_now_ms();
t->m_Now = now;
std::list< std::unique_ptr< llarp::timer > > hit;
{
llarp::util::Lock lock(&t->timersMutex);
auto itr = t->timers.begin();
while(itr != t->timers.end())
{
if(t->m_Now - itr->second->started >= itr->second->timeout
if(now - itr->second->started >= itr->second->timeout
|| itr->second->canceled)
{
// timer hit
@ -253,14 +247,14 @@ llarp_timer_tick_all(struct llarp_timer_context* t)
while(not hit.empty())
{
const auto& h = hit.front();
h->called_at = t->m_Now;
h->called_at = now;
h->exec();
hit.pop_front();
}
// reindex next tick info
{
llarp::util::Lock lock(&t->timersMutex);
t->m_Now = llarp::time_now_ms();
t->m_Now = now;
t->m_NextRequiredTickAt = std::numeric_limits< llarp_time_t >::max();
for(const auto& item : t->timers)
{

@ -71,12 +71,13 @@ Build requirements:
* gcovr (if generating test coverage with gcc)
* libuv >= 1.27.0
* libsodium (A patch that removes `undocumented system call` from the Win32 build is in `llarp/win32`.)
* libcurl
### Linux
build:
$ sudo apt install build-essential cmake git libcap-dev curl libuv1-dev libsodium-dev
$ sudo apt install build-essential cmake git libcap-dev curl libuv1-dev libsodium-dev libcurl-dev
$ git clone https://github.com/loki-project/loki-network
$ cd loki-network
$ make

@ -18,7 +18,6 @@ list(APPEND TEST_SRC
exit/test_llarp_exit_context.cpp
link/test_llarp_link.cpp
llarp_test.cpp
net/test_llarp_net_inaddr.cpp
net/test_llarp_net.cpp
routing/llarp_routing_transfer_traffic.cpp
routing/test_llarp_routing_obtainexitmessage.cpp

@ -69,6 +69,8 @@ namespace llarp
MOCK_METHOD3(pqe_encrypt,
bool(PQCipherBlock &, SharedSecret &, const PQPubKey &));
MOCK_METHOD1(check_identity_privkey, bool(const SecretKey&));
};
} // namespace test
} // namespace llarp

@ -127,7 +127,7 @@ struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
Context Bob;
bool success = false;
const bool shouldDebug = true;
const bool shouldDebug = false;
llarp_ev_loop_ptr netLoop;
std::shared_ptr< Logic > m_logic;
@ -144,7 +144,7 @@ struct LinkLayerTest : public test::LlarpTest< llarp::sodium::CryptoLibSodium >
{
oldLevel = llarp::LogContext::Instance().minLevel;
if(shouldDebug)
llarp::SetLogLevel(eLogDebug);
llarp::SetLogLevel(eLogTrace);
oldRCLifetime = RouterContact::Lifetime;
RouterContact::BlockBogons = false;
RouterContact::Lifetime = 500;
@ -288,7 +288,7 @@ TEST_F(LinkLayerTest, TestIWP)
ASSERT_TRUE(Alice.Start(m_logic, netLoop, AlicePort));
ASSERT_TRUE(Bob.Start(m_logic, netLoop, BobPort));
m_logic->queue_func([&]() { ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC())); });
LogicCall(m_logic, [&]() { ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC())); });
RunMainloop();
ASSERT_TRUE(Alice.IsGucci());

@ -1,7 +1,6 @@
#include <gtest/gtest.h>
#include <net/net.hpp>
#include <net/net_inaddr.hpp>
#include <net/net_int.hpp>
#include <net/ip.hpp>

@ -1,106 +0,0 @@
#include <gtest/gtest.h>
#include <net/net_inaddr.hpp>
struct TestNetInAddr : public ::testing::Test
{
};
TEST_F(TestNetInAddr, TestinAddrFrom4Int)
{
llarp::inAddr test;
test.from4int(127, 0, 0, 1);
char str[INET6_ADDRSTRLEN];
if(inet_ntop(AF_INET, &test._addr, str, INET6_ADDRSTRLEN) == NULL)
{
ASSERT_TRUE(false);
}
ASSERT_TRUE(strcmp("127.0.0.1", str) == 0);
}
TEST_F(TestNetInAddr, TestinAddrFromStr)
{
llarp::inAddr test;
test.from_char_array("127.0.0.1");
char str[INET6_ADDRSTRLEN];
if(inet_ntop(AF_INET, &test._addr, str, INET6_ADDRSTRLEN) == NULL)
{
ASSERT_TRUE(false);
}
ASSERT_TRUE(strcmp("127.0.0.1", str) == 0);
}
TEST_F(TestNetInAddr, TestinAddrReset)
{
llarp::inAddr test;
test.from_char_array("127.0.0.1");
test.reset();
char str[INET6_ADDRSTRLEN];
if(inet_ntop(AF_INET, &test._addr, str, INET6_ADDRSTRLEN) == NULL)
{
ASSERT_TRUE(false);
}
ASSERT_TRUE(strcmp("0.0.0.0", str) == 0);
}
TEST_F(TestNetInAddr, TestinAddrModeSet)
{
llarp::inAddr test;
test.from_char_array("127.0.0.1");
// test.hexDebug();
ASSERT_TRUE(test.isIPv4Mode());
// corrupt it
test._addr.s6_addr[10] = 0xfe;
test._addr.s6_addr[11] = 0xfe;
test.setIPv4Mode();
// test.hexDebug();
ASSERT_TRUE(test.isIPv4Mode());
}
TEST_F(TestNetInAddr, TestinAddrSIIT)
{
llarp::inAddr test;
test.from_char_array("127.0.0.1");
test.toSIIT();
// test.hexDebug();
ASSERT_TRUE(llarp::ipv6_is_siit(test._addr));
test.fromSIIT();
// test.hexDebug();
ASSERT_TRUE(!llarp::ipv6_is_siit(test._addr));
}
TEST_F(TestNetInAddr, TestinAddrN32)
{
llarp::inAddr test;
test.from_char_array("127.0.0.1");
llarp::nuint32_t netOrder = test.toN32();
llarp::inAddr test2;
test2.fromN32(netOrder);
char str[INET6_ADDRSTRLEN];
if(inet_ntop(AF_INET, &test2._addr, str, INET6_ADDRSTRLEN) == NULL)
{
ASSERT_TRUE(false);
}
// printf("[%s]\n", str);
ASSERT_TRUE(strcmp("127.0.0.1", str) == 0);
}
TEST_F(TestNetInAddr, TestinAddrH32)
{
llarp::inAddr test;
test.from_char_array("127.0.0.1");
llarp::huint32_t netOrder = test.toH32();
llarp::inAddr test2;
test2.fromH32(netOrder);
char str[INET6_ADDRSTRLEN];
if(inet_ntop(AF_INET, &test2._addr, str, INET6_ADDRSTRLEN) == NULL)
{
ASSERT_TRUE(false);
}
// printf("[%s]\n", str);
ASSERT_TRUE(strcmp("127.0.0.1", str) == 0);
}

@ -10,11 +10,11 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("LokiNET")]
[assembly: AssemblyDescription("LokiNET end-user UI")]
[assembly: AssemblyTitle("Lokinet for Windows")]
[assembly: AssemblyDescription("Lokinet end-user UI")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Loki Project")]
[assembly: AssemblyProduct("LokiNET Launcher")]
[assembly: AssemblyProduct("Lokinet Launcher")]
[assembly: AssemblyCopyright("Copyright ©2018-2019 Loki Project. All rights reserved. See LICENSE for more details.")]
[assembly: AssemblyTrademark("Loki, Loki Project, LokiNET are ™ & ©2018-2019 Loki Foundation")]
[assembly: AssemblyCulture("")]
@ -37,10 +37,10 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.5.2")]
[assembly: AssemblyFileVersion("0.5.2")]
[assembly: AssemblyVersion("0.6.0")]
[assembly: AssemblyFileVersion("0.6.0")]
#if DEBUG
[assembly: AssemblyInformationalVersion("0.5.2-dev-{chash:8}")]
[assembly: AssemblyInformationalVersion("0.6.0-dev-{chash:8}")]
#else
[assembly: AssemblyInformationalVersion("0.5.2 (RELEASE_CODENAME)")]
[assembly: AssemblyInformationalVersion("0.6.0 (RELEASE_CODENAME)")]
#endif

@ -28,66 +28,66 @@
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(dlgBootstrap));
this.label1 = new System.Windows.Forms.Label();
this.uriBox = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.btnDownload = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// uriBox
//
resources.ApplyResources(this.uriBox, "uriBox");
this.uriBox.Name = "uriBox";
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// btnDownload
//
resources.ApplyResources(this.btnDownload, "btnDownload");
this.btnDownload.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnDownload.Name = "btnDownload";
this.btnDownload.UseVisualStyleBackColor = true;
this.btnDownload.Click += new System.EventHandler(this.button1_Click);
//
// btnCancel
//
resources.ApplyResources(this.btnCancel, "btnCancel");
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Name = "btnCancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.button1_Click_1);
//
// bootstrap
//
this.AcceptButton = this.btnDownload;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ControlBox = false;
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnDownload);
this.Controls.Add(this.label2);
this.Controls.Add(this.uriBox);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "bootstrap";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.ResumeLayout(false);
this.PerformLayout();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(dlgBootstrap));
this.label1 = new System.Windows.Forms.Label();
this.uriBox = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.btnDownload = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label1
//
resources.ApplyResources(this.label1, "label1");
this.label1.Name = "label1";
//
// uriBox
//
resources.ApplyResources(this.uriBox, "uriBox");
this.uriBox.Name = "uriBox";
//
// label2
//
resources.ApplyResources(this.label2, "label2");
this.label2.Name = "label2";
//
// btnDownload
//
resources.ApplyResources(this.btnDownload, "btnDownload");
this.btnDownload.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnDownload.Name = "btnDownload";
this.btnDownload.UseVisualStyleBackColor = true;
this.btnDownload.Click += new System.EventHandler(this.button1_Click);
//
// btnCancel
//
resources.ApplyResources(this.btnCancel, "btnCancel");
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Name = "btnCancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.button1_Click_1);
//
// dlgBootstrap
//
this.AcceptButton = this.btnDownload;
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ControlBox = false;
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnDownload);
this.Controls.Add(this.label2);
this.Controls.Add(this.uriBox);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "dlgBootstrap";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion

@ -1,276 +1,279 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="mscorlib" name="mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="label1.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="label1.Location" type="System.Drawing.Point, System.Drawing">
<value>13, 13</value>
</data>
<data name="label1.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 13</value>
</data>
<data name="label1.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="label1.Text" xml:space="preserve">
<value>Enter a URI to a node to bootstrap from:</value>
</data>
<data name="&gt;&gt;label1.Name" xml:space="preserve">
<value>label1</value>
</data>
<data name="&gt;&gt;label1.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label1.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;label1.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="uriBox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Left, Right</value>
</data>
<data name="uriBox.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 29</value>
</data>
<data name="uriBox.Size" type="System.Drawing.Size, System.Drawing">
<value>520, 20</value>
</data>
<data name="uriBox.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="&gt;&gt;uriBox.Name" xml:space="preserve">
<value>uriBox</value>
</data>
<data name="&gt;&gt;uriBox.Type" xml:space="preserve">
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;uriBox.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;uriBox.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="label2.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="label2.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 52</value>
</data>
<data name="label2.Size" type="System.Drawing.Size, System.Drawing">
<value>347, 13</value>
</data>
<data name="label2.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="label2.Text" xml:space="preserve">
<value>This file is automatically saved as $APPDATA\.lokinet\bootstrap.signed.</value>
</data>
<data name="&gt;&gt;label2.Name" xml:space="preserve">
<value>label2</value>
</data>
<data name="&gt;&gt;label2.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label2.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;label2.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="btnDownload.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Bottom</value>
</data>
<data name="btnDownload.Location" type="System.Drawing.Point, System.Drawing">
<value>196, 75</value>
</data>
<data name="btnDownload.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="btnDownload.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="btnDownload.Text" xml:space="preserve">
<value>OK</value>
</data>
<data name="&gt;&gt;btnDownload.Name" xml:space="preserve">
<value>btnDownload</value>
</data>
<data name="&gt;&gt;btnDownload.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;btnDownload.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;btnDownload.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="btnCancel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Bottom</value>
</data>
<data name="btnCancel.Location" type="System.Drawing.Point, System.Drawing">
<value>278, 75</value>
</data>
<data name="btnCancel.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="btnCancel.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
</data>
<data name="btnCancel.Text" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="&gt;&gt;btnCancel.Name" xml:space="preserve">
<value>btnCancel</value>
</data>
<data name="&gt;&gt;btnCancel.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;btnCancel.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;btnCancel.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>6, 13</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>548, 111</value>
</data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>CenterParent</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>bootstrap from web...</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>bootstrap</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="mscorlib" name="mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="label1.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="label1.Location" type="System.Drawing.Point, System.Drawing">
<value>13, 13</value>
</data>
<data name="label1.Size" type="System.Drawing.Size, System.Drawing">
<value>196, 13</value>
</data>
<data name="label1.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="label1.Text" xml:space="preserve">
<value>Enter a URI to a node to bootstrap from:</value>
</data>
<data name="&gt;&gt;label1.Name" xml:space="preserve">
<value>label1</value>
</data>
<data name="&gt;&gt;label1.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label1.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;label1.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="uriBox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Left, Right</value>
</data>
<data name="uriBox.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 29</value>
</data>
<data name="uriBox.Size" type="System.Drawing.Size, System.Drawing">
<value>520, 20</value>
</data>
<data name="uriBox.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="uriBox.Text" xml:space="preserve">
<value>https://seed.lokinet.org/bootstrap.signed</value>
</data>
<data name="&gt;&gt;uriBox.Name" xml:space="preserve">
<value>uriBox</value>
</data>
<data name="&gt;&gt;uriBox.Type" xml:space="preserve">
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;uriBox.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;uriBox.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="label2.AutoSize" type="System.Boolean, mscorlib">
<value>True</value>
</data>
<data name="label2.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 52</value>
</data>
<data name="label2.Size" type="System.Drawing.Size, System.Drawing">
<value>347, 13</value>
</data>
<data name="label2.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="label2.Text" xml:space="preserve">
<value>This file is automatically saved as $APPDATA\.lokinet\bootstrap.signed.</value>
</data>
<data name="&gt;&gt;label2.Name" xml:space="preserve">
<value>label2</value>
</data>
<data name="&gt;&gt;label2.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;label2.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;label2.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="btnDownload.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Bottom</value>
</data>
<data name="btnDownload.Location" type="System.Drawing.Point, System.Drawing">
<value>196, 75</value>
</data>
<data name="btnDownload.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="btnDownload.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="btnDownload.Text" xml:space="preserve">
<value>OK</value>
</data>
<data name="&gt;&gt;btnDownload.Name" xml:space="preserve">
<value>btnDownload</value>
</data>
<data name="&gt;&gt;btnDownload.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;btnDownload.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;btnDownload.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="btnCancel.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Bottom</value>
</data>
<data name="btnCancel.Location" type="System.Drawing.Point, System.Drawing">
<value>278, 75</value>
</data>
<data name="btnCancel.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>
</data>
<data name="btnCancel.TabIndex" type="System.Int32, mscorlib">
<value>4</value>
</data>
<data name="btnCancel.Text" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="&gt;&gt;btnCancel.Name" xml:space="preserve">
<value>btnCancel</value>
</data>
<data name="&gt;&gt;btnCancel.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;btnCancel.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;btnCancel.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>6, 13</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>548, 111</value>
</data>
<data name="$this.StartPosition" type="System.Windows.Forms.FormStartPosition, System.Windows.Forms">
<value>CenterParent</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>bootstrap from web...</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>dlgBootstrap</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>System.Windows.Forms.Form, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>
Loading…
Cancel
Save