Ryan Tharp 6 years ago
commit 14ccb2f81e

@ -318,6 +318,7 @@ set(LIB_SRC
${UTP_SRC}
${NTRU_SRC}
llarp/address_info.cpp
llarp/arpc.cpp
llarp/bencode.cpp
llarp/buffer.cpp
llarp/config.cpp

@ -1,8 +1,6 @@
#include <llarp/logger.h>
#include <llarp/logger.hpp>
int
main(int argc, char* argv[])
{
return 1;
}
return 0;
}

@ -1,74 +0,0 @@
## Building on Linux
# or your OS or distro's package manager
$ sudo apt install build-essential libtool autoconf cmake git
$ git clone --recursive https://github.com/loki-project/lokinet-builder
$ cd lokinet-builder
$ make
## Building on Windows (mingw-w64 native, or wow64/linux/unix cross-compiler)
#i686 or x86_64
#if cross-compiling from anywhere other than wow64, export CC and CXX to
#$ARCH-w64-mingw32-g[cc++] respectively
$ pacman -Sy base-devel mingw-w64-$ARCH-toolchain git libtool autoconf cmake
$ git clone --recursive https://github.com/loki-project/lokinet-builder
$ cd lokinet-builder
$ make ensure sodium
$ cd build
$ cmake ../deps/llarp -DSODIUM_LIBRARIES=./prefix/lib/libsodium.a -DSODIUM_INCLUDE_DIR=./prefix/include -G "Unix Makefiles" -DHAVE_CXX17_FILESYSTEM=ON
$ make
$ cp llarpd ../lokinet.exe
## Building on Windows using Microsoft C/C++ (Visual Studio 2017)
* clone https://github.com/loki-project/lokinet-builder from git-bash or whatever git browser you use
* open `%CLONE_PATH%/lokinet-builder/deps/sodium/builds/msvc/vs2017/libsodium.sln` and build one of the targets
* create a `build` folder in `%CLONE_PATH%/lokinet-builder`
* run cmake-gui from `%CLONE_PATH%/lokinet-builder/deps/llarp` as the source directory
* define `SODIUM_LIB` to `%CLONE_PATH%/lokinet-builder/deps/sodium/bin/win32/%CONFIG%/%TOOLSET%/%TARGET%/libsodium.lib`
* define `SODIUM_INCLUDE_DIR` to `%CLONE_PATH%/lokinet-builder/deps/sodium/src/libsodium/include`
* define `HAVE_CXX17_FILESYSTEM` to `TRUE`
* select `Visual Studio 2017 15 %ARCH%` as the generator
* enter a custom toolset if desired (usually `v141_xp`)
* generate the developer studio project files and open in the IDE
* select a configuration
* press F7 to build everything
## Running
$ ./lokinet
or press `Debug`/`Local Windows Debugger` in the visual studio standard toolbar
### Development
Please note development builds are likely to be unstable.
##### Build requirements:
* CMake
* ninja (for unit testing with Google Tests)
* libsodium >= 1.0.14 (included here)
* c++ 11 capable C++ compiler
* if you have C++17 `<filesystem>` or `<experimental/filesystem>` declared and defined in your platform's C++ toolchain, re-run CMake (in `lokinet-builder/build`) with `-DHAVE_CXX17_FILESYSTEM=ON`.
* since each platform seems to have its own idea of where `std::[experimental::]filesystem` is defined, you will need to manually specify its library in `LDFLAGS` or `CMAKE_x_LINKER_FLAGS` as well.
##### Windows:
* Mingw-w64 is recommended for 32 or 64-bit builds.
* It *is* possible to compile with Microsoft C++ (v19 or later from VS2015+).
* `cpp17::filesystem` in `vendor/cppbackport-master` is not available for Windows.
#### Boxed warning
<div style="border:5px solid #f00;padding:5px">
<p>Inbound sessions are unsupported on Windows Server systems.</p>
<p><strong><em>Ignore this warning at your own peril.</em></strong></p>
</div>
##### Building a debug build:
#in lokinet-builder/
$ cd build
$ make

@ -0,0 +1,154 @@
LokiNET admin api
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
document are to be interpreted as described in RFC 2119 [RFC2119].
message format is jsonrpc 2.0 like api serialized with bittorrent encoding (BEncode) over
TCP
messages are prefixed with big endian 16 bit length field indicating how many bytes the next
message is.
a version 1 aRPC message is structured as the following message:
{
"aRPC-method": "llarp",
"id" : "some-id-here",
"params": {
"key1": "val1",
"key2": "val2"
},
"v" : version_integer,
"z-key" : "<optional 32 bytes public key>",
"z-sig" : "<64 bytes siganture of the entire message requried if z-key is provided>"
}
serialzied it would be:
d13:aRPC-method5:llarp2:id12:some-id-here6:paramsd4:key14:val14:key24:val2e5:z-key32:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5:z-sig64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAe
given the signature is 64 bytes of 'A' and the public key is 32 bytes of 'A'
responses are signed by the identity key and MUST be verified by the caller.
an example of a call to llarp.nodedb.getrc:
{
"aRPC-method": "llarp.nodedb.rc.getbykey",
"id" : "<12 bytes random>",
"params": {
"key" : "<32 bytes identity key>"
}
}
the reply MUST be signed by the router's identity key
{
"aRPC-method" : "llarp.nodedb.rc.getbykey",
"id" : "<12 bytes from before>",
"return": {
"value" : [RC, RC, RC]
}
"time": uint64_milliseconds_since_epoch_timestamp_now,
"z-key": "<32 bytes identity public key>",
"z-sig": "<64 bytes sig>"
}
and on error:
{
"aRPC-method" : "llarp.nodedb.rc.getbykey",
"id" : "<12 bytes from before>",
"return": {
"error": "error message goes here"
},
"time": uint64_milliseconds_since_epoch_timestamp_now,
"z-key": "<32 bytes identity public key>",
"z-sig": "<64 bytes sig>"
}
if requests are signed then they are authenticated by the signer's public key
requesters can be granted access based on their public key, some methods MAY
require this in order to be called.
------
the methods currently provided are:
llarp.rpc.ping
get a pong back
required parameters:
ping: integer
returns:
ping
llarp.nodedb.rc.getbykey
get rc by public identity key
required parameters:
key: 32 bytes public identity key
returns:
a list of RCs (see protocol v0 spec) that have this public identity key
usually 0 or 1 RCs
llarp.nodedb.rc.getbycidr
get a list of RCs in an address range
required parameters:
cidr: ipv6 network cidr string, i.e. "::ffff.21.0.0.0/8" or "fc00::/7"
limit: integer max number of items to fetch, zero or positive integer,
if zero no limit.
returns:
a list of 0 to limit RCs that advertise themselves as being reachble via an
address in the given CIDR.
llarp.admin.sys.uptime (authentication required)
required paramters:
(none)
returns:
an integer milliseconds since unix epoch we've been online
llarp.admin.link.neighboors (authentication required)
get a list of connected service nodes on all links
required parameters:
(none)
returns:
list of 0 to N dicts in the following format:
{
"connected" : uint64_milliseconds_timestamp_connected_at
"ident" : "<32 bytes public identity key>",
"laddr" : "local address",
"raddr" : "remote address"
}

@ -1 +0,0 @@
insert lokinet api overview here

@ -108,7 +108,7 @@ extern "C"
llarp_tun_io *
main_router_getRange(struct llarp_main *ptr);
/// map an ip to a hidden service address
/// map an (host byte order) ip to a hidden service address
bool
main_router_mapAddress(struct llarp_main *ptr,
const llarp::service::Address &addr, uint32_t ip);

@ -0,0 +1,64 @@
#ifndef LLARP_ARPC_HPP
#define LLARP_ARPC_HPP
#include <llarp/bencode.hpp>
#include <llarp/crypto.hpp>
#include <llarp/logger.hpp>
#include <llarp/time.h>
#include <llarp/endian.h>
#include <llarp/ev.h>
#include <functional>
#include <string>
#include <map>
#include <unordered_map>
#ifndef _WIN32
#include <sys/un.h>
#endif
#include <llarp/net.hpp>
// forward declare
struct llarp_router;
namespace llarp
{
namespace arpc
{
// forward declare
struct BaseMessage;
struct Server
{
llarp_tcp_acceptor m_acceptor;
llarp_router* router;
Server(llarp_router* r);
static void
OnAccept(llarp_tcp_acceptor* a, llarp_tcp_conn* conn);
bool
Start(const std::string& bindaddr);
const llarp_crypto*
Crypto() const;
const byte_t*
SigningPublicKey() const
{
return llarp::seckey_topublic(SigningPrivateKey());
}
const byte_t*
SigningPrivateKey() const;
bool
Sign(BaseMessage* msg) const;
};
} // namespace arpc
} // namespace llarp
#endif

@ -78,6 +78,54 @@ llarp_ev_udp_sendto(struct llarp_udp_io *udp, const struct sockaddr *to,
int
llarp_ev_close_udp(struct llarp_udp_io *udp);
// forward declare
struct llarp_tcp_acceptor;
/// a single tcp connection
struct llarp_tcp_conn
{
/// user data
void *user;
/// private implementation
void *impl;
/// parent loop (dont set me)
struct llarp_ev_loop *loop;
/// handle read event
void (*read)(struct llarp_tcp_conn *, const void *, size_t);
/// handle close event (free-ing is handled by event loop)
void (*closed)(struct llarp_tcp_conn *);
};
/// queue async write a buffer in full
void
llarp_tcp_conn_async_write(struct llarp_tcp_conn *, const void *, size_t);
/// close a tcp connection
void
llarp_tcp_conn_close(struct llarp_tcp_conn *);
struct llarp_tcp_acceptor
{
/// userdata pointer
void *user;
/// internal implementation
void *impl;
/// parent event loop (dont set me)
struct llarp_ev_loop *loop;
/// handle inbound connection
void (*accepted)(struct llarp_tcp_acceptor *, struct llarp_tcp_conn *);
};
/// bind to an address and start serving async
/// return false if failed to bind
/// return true on successs
bool
llarp_tcp_serve(struct llarp_tcp_acceptor *t, const sockaddr *bindaddr);
/// close and stop accepting connections
void
llarp_tcp_acceptor_close(struct llarp_tcp_acceptor *);
#ifdef _WIN32
#define IFNAMSIZ (16)
#endif

@ -33,7 +33,7 @@ namespace llarp
TickTun(llarp_time_t now);
bool
MapAddress(const service::Address& remote, uint32_t ip);
MapAddress(const service::Address& remote, huint32_t ip);
bool
Start();
@ -91,18 +91,18 @@ namespace llarp
PacketQueue_t m_NetworkToUserPktQueue;
/// return true if we have a remote loki address for this ip address
bool
HasRemoteForIP(const uint32_t& ipv4) const;
HasRemoteForIP(huint32_t ipv4) const;
/// get ip address for service address unconditionally
uint32_t
huint32_t
ObtainIPForAddr(const service::Address& addr);
/// mark this address as active
void
MarkIPActive(uint32_t ip);
MarkIPActive(huint32_t ip);
/// mark this address as active forever
void
MarkIPActiveForever(uint32_t ip);
MarkIPActiveForever(huint32_t ip);
void
FlushSend();
@ -120,18 +120,20 @@ namespace llarp
struct dotLokiLookup dll;
/// maps ip to service address (host byte order)
std::unordered_map< uint32_t, service::Address > m_IPToAddr;
std::unordered_map< huint32_t, service::Address, huint32_t::Hash >
m_IPToAddr;
/// maps service address to ip (host byte order)
std::unordered_map< service::Address, uint32_t, service::Address::Hash >
std::unordered_map< service::Address, huint32_t, service::Address::Hash >
m_AddrToIP;
/// maps ip address to timestamp last active
std::unordered_map< uint32_t, llarp_time_t > m_IPActivity;
std::unordered_map< huint32_t, llarp_time_t, huint32_t::Hash >
m_IPActivity;
/// our ip address (host byte order)
uint32_t m_OurIP;
huint32_t m_OurIP;
/// next ip address to allocate (host byte order)
uint32_t m_NextIP;
/// highest ip address to allocate
uint32_t m_MaxIP;
huint32_t m_NextIP;
/// highest ip address to allocate (host byte order)
huint32_t m_MaxIP;
};
} // namespace handlers
} // namespace llarp

@ -117,45 +117,49 @@ namespace llarp
}
};
ip_header*
inline ip_header*
Header()
{
return (ip_header*)&buf[0];
}
const ip_header*
inline const ip_header*
Header() const
{
return (ip_header*)&buf[0];
}
uint32_t
inline huint32_t
src()
{
return ntohl(Header()->saddr);
return huint32_t{ntohl(Header()->saddr)};
}
uint32_t
inline huint32_t
dst()
{
return ntohl(Header()->daddr);
return huint32_t{ntohl(Header()->daddr)};
}
void
src(uint32_t ip)
inline void
src(huint32_t ip)
{
Header()->saddr = htonl(ip);
Header()->saddr = htonl(ip.h);
}
void
dst(uint32_t ip)
inline void
dst(huint32_t ip)
{
Header()->daddr = htonl(ip);
Header()->daddr = htonl(ip.h);
}
// update ip packet checksum
// update ip packet (after packet gets out of network)
void
UpdatePacketOnDst(huint32_t nsrcIP, huint32_t ndstIP);
// update ip packet (before packet gets inserted into network)
void
UpdateChecksum();
UpdatePacketOnSrc();
};
} // namespace net

@ -82,15 +82,20 @@ namespace llarp
struct log_timestamp
{
std::string format = "%c %Z";
friend
std::ostream & operator << (std::ostream & out, const log_timestamp & ts)
const char* format;
log_timestamp(const char* fmt = "%c %Z") : format(fmt)
{
}
friend std::ostream&
operator<<(std::ostream& out, const log_timestamp& ts)
{
auto now = llarp::Clock_t::to_time_t(llarp::Clock_t::now());
return out << std::put_time(std::localtime(&now), ts.format.c_str());
return out << std::put_time(std::localtime(&now), ts.format);
}
};
/** internal */
template < typename... TArgs >
void

@ -53,6 +53,66 @@ llarp_getPrivateIfs();
namespace llarp
{
// clang-format off
struct huint32_t
{
uint32_t h;
constexpr huint32_t operator &(huint32_t x) const { return huint32_t{h & x.h}; }
constexpr huint32_t operator |(huint32_t x) const { return huint32_t{h | x.h}; }
constexpr huint32_t operator ~() const { return huint32_t{~h}; }
inline huint32_t operator ++() { ++h; return *this; }
inline huint32_t operator --() { --h; return *this; }
constexpr bool operator <(huint32_t x) const { return h < x.h; }
constexpr bool operator ==(huint32_t x) const { return h == x.h; }
struct Hash
{
inline size_t
operator()(huint32_t x) const
{
return std::hash< uint32_t >{}(x.h);
}
};
};
struct nuint32_t
{
uint32_t n;
constexpr nuint32_t operator &(nuint32_t x) const { return nuint32_t{n & x.n}; }
constexpr nuint32_t operator |(nuint32_t x) const { return nuint32_t{n | x.n}; }
constexpr nuint32_t operator ~() const { return nuint32_t{~n}; }
inline nuint32_t operator ++() { ++n; return *this; }
inline nuint32_t operator --() { --n; return *this; }
constexpr bool operator <(nuint32_t x) const { return n < x.n; }
constexpr bool operator ==(nuint32_t x) const { return n == x.n; }
struct Hash
{
inline size_t
operator()(nuint32_t x) const
{
return std::hash< uint32_t >{}(x.n);
}
};
};
// clang-format on
static inline huint32_t
xntohl(nuint32_t x)
{
return huint32_t{ntohl(x.n)};
}
static inline nuint32_t
xhtonl(huint32_t x)
{
return nuint32_t{htonl(x.h)};
}
struct Addr
{
// network order
@ -444,18 +504,30 @@ namespace llarp
return *this;
}
uint32_t
tohl()
inline uint32_t
tohl() const
{
return ntohl(addr4()->s_addr);
}
uint32_t
ton()
inline huint32_t
xtohl() const
{
return huint32_t{ntohl(addr4()->s_addr)};
}
inline uint32_t
ton() const
{
return addr4()->s_addr;
}
inline nuint32_t
xtonl() const
{
return nuint32_t{addr4()->s_addr};
}
bool
sameAddr(const Addr& other) const
{

@ -410,8 +410,8 @@ namespace llarp
GetByUpstream(const RouterID& id, const PathID_t& path);
IHopHandler*
GetPathForTransfer(const PathID_t & topath);
GetPathForTransfer(const PathID_t& topath);
IHopHandler*
GetByDownstream(const RouterID& id, const PathID_t& path);

@ -69,7 +69,10 @@ namespace llarp
version = other.version;
topic = other.topic;
if(W)
{
delete W;
W = nullptr;
}
if(other.W)
W = new llarp::PoW(*other.W);
Z = other.Z;
@ -82,6 +85,20 @@ namespace llarp
return A < other.A;
}
bool
operator==(const IntroSet& other) const
{
return A == other.A && I == other.I && K == other.K && T == other.T
&& version == other.version && topic == other.topic && W == other.W
&& Z == other.Z;
}
bool
operator!=(const IntroSet& other) const
{
return !(*this == other);
}
bool
OtherIsNewer(const IntroSet& other) const
{
@ -116,13 +133,7 @@ namespace llarp
}
llarp_time_t
GetNewestIntroExpiration() const
{
llarp_time_t t = 0;
for(const auto& intro : I)
t = std::max(intro.expiresAt, t);
return t;
}
GetNewestIntroExpiration() const;
bool
HasExpiredIntros(llarp_time_t now) const;

@ -1,6 +1,7 @@
#ifndef LLARP_SERVICE_CONTEXT_HPP
#define LLARP_SERVICE_CONTEXT_HPP
#include <llarp/router.h>
#include <llarp/net.hpp>
#include <llarp/service/config.hpp>
#include <llarp/service/endpoint.hpp>
#include <unordered_map>
@ -58,7 +59,7 @@ namespace llarp
/// punch a hole open for DNS to add mappings
/// ip is in network order
bool
MapAddress(const llarp::service::Address &addr, uint32_t ip);
MapAddress(const llarp::service::Address &addr, huint32_t ip);
bool
MapAddressAll(const llarp::service::Address &addr,

@ -8,5 +8,4 @@ namespace llarp
typedef std::chrono::system_clock Clock_t;
}
#endif

@ -0,0 +1,405 @@
#include <llarp/arpc.hpp>
namespace llarp
{
namespace arpc
{
/// interface for request messages
struct IRequest
{
/// returns false if errmsg is set
/// returns true if retval is set
virtual bool
HandleRequest(Server* ctx, std::unique_ptr< BaseMessage >& retval,
std::string& errmsg) const = 0;
};
struct BaseMessage : public llarp::IBEncodeMessage, public IRequest
{
static constexpr size_t MaxIDSize = 128;
/// maximum size of a message
static constexpr size_t MaxSize = 1024 * 8;
BaseMessage()
{
timestamp = llarp_time_now_ms();
zkey.Zero();
zsig.Zero();
}
std::string m_id;
llarp_time_t timestamp;
llarp::PubKey zkey;
llarp::Signature zsig;
/// override me
virtual std::string
Method() const = 0;
/// encode the entire message
bool
BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictString("aRPC-method", Method(), buf))
return false;
if(!BEncodeWriteDictString("id", m_id, buf))
return false;
if(!BEncodeBody(buf))
return false;
if(!zkey.IsZero())
{
if(!BEncodeWriteDictEntry("z-key", zkey, buf))
return false;
if(!BEncodeWriteDictEntry("z-sig", zsig, buf))
return false;
}
return bencode_end(buf);
}
bool
DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
{
if(llarp_buffer_eq(k, "id"))
{
return DecodeID(buf);
}
if(llarp_buffer_eq(k, "params"))
{
return DecodeParams(buf);
}
return false;
}
protected:
typedef bool (*ParamDecoder)(dict_reader*, llarp_buffer_t*);
virtual ParamDecoder
GetParamDecoder() const = 0;
bool
DecodeParams(llarp_buffer_t* buf)
{
dict_reader r;
r.user = this;
r.on_key = GetParamDecoder();
return bencode_read_dict(buf, &r);
}
bool
DecodeID(llarp_buffer_t* buf)
{
llarp_buffer_t strbuf;
if(!bencode_read_string(buf, &strbuf))
return false;
if(strbuf.sz > MaxIDSize) // too big
return false;
m_id = std::string((char*)strbuf.base, strbuf.sz);
return true;
}
/// encode body of message
virtual bool
BEncodeBody(llarp_buffer_t* buf) const = 0;
};
struct ConnHandler
{
ConnHandler(Server* s, llarp_tcp_conn* c) : parent(s), m_conn(c)
{
left = 0;
readingHeader = true;
}
bool readingHeader;
Server* parent;
llarp_tcp_conn* m_conn;
AlignedBuffer< BaseMessage::MaxSize > buf;
uint16_t left;
void
ParseMessage();
void
Close()
{
llarp_tcp_conn_close(m_conn);
}
static void
OnClosed(llarp_tcp_conn* conn)
{
ConnHandler* self = static_cast< ConnHandler* >(conn->user);
delete self;
}
static void
OnRead(llarp_tcp_conn* conn, const void* buf, size_t sz)
{
ConnHandler* self = static_cast< ConnHandler* >(conn->user);
const byte_t* ptr = (const byte_t*)buf;
do
{
if(self->readingHeader)
{
self->left = bufbe16toh(ptr);
sz -= 2;
ptr += 2;
self->readingHeader = false;
}
size_t dlt = std::min((size_t)self->left, sz);
memcpy(self->buf.data() + (self->buf.size() - self->left), ptr, dlt);
self->left -= dlt;
sz -= dlt;
if(self->left == 0)
{
self->ParseMessage();
self->readingHeader = true;
}
} while(sz > 0);
}
};
/// base type for ping req/resp
struct Ping : public BaseMessage
{
Ping() : BaseMessage()
{
}
uint64_t ping;
std::string
Method() const
{
return "llarp.rpc.ping";
}
bool
BEncodeBody(llarp_buffer_t* buf) const
{
if(!bencode_write_bytestring(buf, "params", 6))
return false;
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictInt("ping", ping, buf))
return false;
return bencode_end(buf);
}
static bool
OnParamKey(dict_reader* r, llarp_buffer_t* k)
{
Ping* self = static_cast< Ping* >(r->user);
if(k && llarp_buffer_eq(*k, "ping"))
{
return bencode_read_integer(r->buffer, &self->ping);
}
else
return k == nullptr;
}
virtual ParamDecoder
GetParamDecoder() const
{
return &OnParamKey;
}
};
struct PingResponse : public Ping
{
PingResponse(uint64_t p) : Ping()
{
ping = p;
}
bool
HandleRequest(Server*, std::unique_ptr< BaseMessage >&,
std::string&) const
{
/// TODO: handle client response
llarp::LogInfo(Method(), "pong ", ping);
return false;
}
};
struct PingRequest : public Ping
{
bool
HandleRequest(Server* serv, std::unique_ptr< BaseMessage >& retval,
std::string& errmsg) const
{
PingResponse* resp = new PingResponse(ping);
if(!serv->Sign(resp))
{
errmsg = "failed to sign response";
return false;
}
retval.reset(resp);
return true;
}
};
struct MessageReader
{
dict_reader m_reader;
BaseMessage* msg = nullptr;
MessageReader()
{
m_reader.user = this;
m_reader.on_key = &OnKey;
}
static bool
OnKey(dict_reader* r, llarp_buffer_t* key)
{
static std::unordered_map< std::string,
const std::function< BaseMessage*(void) > >
msgConstructors = {
{"llarp.rpc.ping",
[]() -> BaseMessage* { return new PingRequest(); }},
};
MessageReader* self = static_cast< MessageReader* >(r->user);
if(self->msg == nullptr)
{
// first key
if(key == nullptr || !llarp_buffer_eq(*key, "aRPC-method"))
{
// bad value
return false;
}
llarp_buffer_t strbuf;
if(!bencode_read_string(r->buffer, &strbuf))
return false;
std::string method = std::string((char*)strbuf.base, strbuf.sz);
auto itr = msgConstructors.find(method);
if(itr == msgConstructors.end())
{
// no such method
return false;
}
else
self->msg = itr->second();
return true;
}
else if(key)
return self->msg->DecodeKey(*key, r->buffer);
else
return true;
}
bool
DecodeMessage(llarp_buffer_t* buf,
std::unique_ptr< BaseMessage >& request)
{
msg = nullptr;
if(!bencode_read_dict(buf, &m_reader))
return false;
request.reset(msg);
return true;
}
};
Server::Server(llarp_router* r)
{
router = r;
m_acceptor.user = this;
m_acceptor.accepted = &OnAccept;
}
bool
Server::Start(const std::string& bindaddr)
{
llarp::Addr addr;
sockaddr* saddr = nullptr;
#ifndef _WIN32
sockaddr_un unaddr;
if(bindaddr.find("unix:") == 0)
{
unaddr.sun_family = AF_UNIX;
strncpy(unaddr.sun_path, bindaddr.substr(5).c_str(),
sizeof(unaddr.sun_path));
saddr = (sockaddr*)&unaddr;
}
else
#endif
{
// TODO: ipv6
auto idx = bindaddr.find(':');
std::string host = bindaddr.substr(0, idx);
uint16_t port = std::stoi(bindaddr.substr(idx + 1));
addr = llarp::Addr(host, port);
saddr = addr.getSockAddr();
}
return llarp_tcp_serve(&m_acceptor, saddr);
}
void
Server::OnAccept(llarp_tcp_acceptor* a, llarp_tcp_conn* conn)
{
Server* self = static_cast< Server* >(a->user);
conn->user = new ConnHandler(self, conn);
conn->read = &ConnHandler::OnRead;
conn->closed = &ConnHandler::OnClosed;
}
bool
Server::Sign(BaseMessage* msg) const
{
msg->zkey = SigningPublicKey();
msg->zsig.Zero();
llarp::Signature sig;
//
byte_t tmp[BaseMessage::MaxSize];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!msg->BEncode(&buf))
return false;
// rewind buffer
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
if(!Crypto()->sign(sig, SigningPrivateKey(), buf))
return false;
msg->zsig = sig;
return true;
}
void
ConnHandler::ParseMessage()
{
std::unique_ptr< BaseMessage > msg;
std::unique_ptr< BaseMessage > response;
std::string errmsg;
MessageReader r;
auto tmp = llarp::Buffer(buf);
if(!r.DecodeMessage(&tmp, msg))
{
llarp::LogError("failed to decode message");
Close();
return;
}
// handle request
if(!msg->HandleRequest(parent, response, errmsg))
{
// TODO: send error reply
llarp::LogError("failed to handle api message: ", errmsg);
Close();
return;
}
if(!parent->Sign(response.get()))
{
llarp::LogError("failed to sign response");
Close();
}
}
} // namespace arpc
} // namespace llarp

@ -35,8 +35,7 @@ namespace llarp
iwp_links = find_section(top, "bind", section_t{});
services = find_section(top, "services", section_t{});
system = find_section(top, "system", section_t{});
// std::ofstream ft("config_test.ini");
// parser.dump(ft);
api = find_section(top, "api", section_t{});
return true;
}
return false;
@ -130,6 +129,19 @@ llarp_generic_ensure_config(std::ofstream &f, std::string basepath)
f << "# nickname=lokinet" << std::endl;
f << std::endl << std::endl;
f << "# admin api (disabled by default)" << std::endl;
f << "[api]" << std::endl;
f << "enabled=false" << std::endl;
f << "# authkey=insertpubkey1here" << std::endl;
f << "# authkey=insertpubkey2here" << std::endl;
f << "# authkey=insertpubkey3here" << std::endl;
#ifdef _WIN32
f << "bind=127.0.0.1:1190" << std::endl;
#else
f << "bind=unix:" << basepath << "api.socket" << std::endl;
#endif
f << std::endl << std::endl;
f << "# system settings for priviledges and such" << std::endl;
f << "[system]" << std::endl;
#ifdef _WIN32
@ -302,10 +314,10 @@ extern "C"
{
iter->conf = conf;
std::map< std::string, llarp::Config::section_t & > sections = {
{"network", conf->impl.network}, {"connect", conf->impl.connect},
{"system", conf->impl.system}, {"bind", conf->impl.iwp_links},
{"netdb", conf->impl.netdb}, {"dns", conf->impl.dns},
{"services", conf->impl.services}};
{"network", conf->impl.network}, {"connect", conf->impl.connect},
{"system", conf->impl.system}, {"bind", conf->impl.iwp_links},
{"netdb", conf->impl.netdb}, {"dns", conf->impl.dns},
{"api", conf->impl.api}, {"services", conf->impl.services}};
for(const auto item : conf->impl.router)
iter->visit(iter, "router", item.first.c_str(), item.second.c_str());

@ -19,6 +19,7 @@ namespace llarp
section_t connect;
section_t services;
section_t system;
section_t api;
bool
Load(const char *fname);

@ -461,7 +461,7 @@ extern "C"
const llarp::service::Address &addr, uint32_t ip)
{
auto *endpoint = &ptr->ctx->router->hiddenServiceContext;
return endpoint->MapAddress(addr, ip);
return endpoint->MapAddress(addr, llarp::huint32_t{ip});
}
bool

@ -123,3 +123,28 @@ llarp_ev_tun_async_write(struct llarp_tun_io *tun, const void *pkt, size_t sz)
// TODO: queue write
return static_cast< llarp::ev_io * >(tun->impl)->do_write((void *)pkt, sz);
}
bool
llarp_tcp_serve(struct llarp_tcp_acceptor *tcp, const struct sockaddr *bindaddr)
{
// TODO: implement me
return false;
}
void
llarp_tcp_conn_close(struct llarp_tcp_conn *conn)
{
if(!conn)
return;
llarp::ev_io *impl = static_cast< llarp::ev_io * >(conn->impl);
conn->impl = nullptr;
// deregister
conn->loop->close_ev(impl);
// close fd and delete impl
delete impl;
// call hook if needed
if(conn->closed)
conn->closed(conn);
// delete
delete conn;
}

@ -7,7 +7,6 @@
#endif
#include <unistd.h>
#include <llarp/buffer.h>
#include <list>
#include <llarp/codel.hpp>
#include <vector>
@ -50,7 +49,7 @@ namespace llarp
virtual int
sendto(const sockaddr* dst, const void* data, size_t sz) = 0;
/// used for tun interface
/// used for tun interface and tcp conn
virtual bool
do_write(void* data, size_t sz)
{
@ -192,8 +191,8 @@ struct llarp_ev_loop
virtual ~llarp_ev_loop(){};
std::list< llarp_udp_io* > udp_listeners;
std::list< llarp_tun_io* > tun_listeners;
std::vector< llarp_udp_io* > udp_listeners;
std::vector< llarp_tun_io* > tun_listeners;
void
tick_listeners()

@ -320,7 +320,8 @@ struct llarp_epoll_loop : public llarp_ev_loop
close_ev(listener);
l->impl = nullptr;
delete listener;
udp_listeners.remove(l);
std::remove_if(udp_listeners.begin(), udp_listeners.end(),
[l](llarp_udp_io* i) -> bool { return i == l; });
}
return ret;
}

@ -361,7 +361,15 @@ struct llarp_kqueue_loop : public llarp_ev_loop
ret = close_ev(listener);
l->impl = nullptr;
delete listener;
udp_listeners.remove(l);
// std::remove_if
auto itr = udp_listeners.begin();
while(itr != udp_listeners.end())
{
if((*itr) == l)
itr = udp_listeners.erase(itr);
else
++itr;
}
}
return ret;
}

@ -410,7 +410,15 @@ struct llarp_win32_loop : public llarp_ev_loop
ret = close_ev(listener);
l->impl = nullptr;
delete listener;
udp_listeners.remove(l);
// std::remove_if
auto itr = udp_listeners.begin();
while(itr != udp_listeners.end())
{
if((*itr) == l)
itr = udp_listeners.remove(itr);
else
++itr;
}
}
return ret;
}

@ -1,3 +1,4 @@
#include <algorithm>
// harmless on other platforms
#define __USE_MINGW_ANSI_STDIO 1
#include <llarp/handlers/tun.hpp>
@ -68,7 +69,7 @@ namespace llarp
llarp::LogError("cannot map to invalid ip ", ip_str);
return false;
}
return MapAddress(addr, ntohl(ip.s_addr));
return MapAddress(addr, huint32_t{ntohl(ip.s_addr)});
}
if(k == "ifname")
{
@ -119,17 +120,20 @@ namespace llarp
/// ip should be in host byte order
bool
TunEndpoint::MapAddress(const service::Address &addr, uint32_t ip)
TunEndpoint::MapAddress(const service::Address &addr, huint32_t ip)
{
nuint32_t nip = xhtonl(ip);
auto itr = m_IPToAddr.find(ip);
if(itr != m_IPToAddr.end())
{
llarp::LogWarn(inet_ntoa({ip}), " already mapped to ",
// XXX is calling inet_ntoa safe in this context? it's MP-unsafe
llarp::LogWarn(inet_ntoa({nip.n}), " already mapped to ",
itr->second.ToString());
return false;
}
llarp::LogInfo(Name() + " map ", addr.ToString(), " to ",
inet_ntoa({htonl(ip)}));
inet_ntoa({nip.n}));
m_IPToAddr.insert(std::make_pair(ip, addr));
m_AddrToIP.insert(std::make_pair(addr, ip));
MarkIPActiveForever(ip);
@ -174,12 +178,12 @@ namespace llarp
#endif
}
constexpr uint32_t
constexpr huint32_t
netmask_ipv4_bits(uint32_t netmask)
{
return (32 - netmask)
? (1 << (32 - (netmask + 1))) | netmask_ipv4_bits(netmask + 1)
: 0;
return (32 - netmask) ? (huint32_t{((uint32_t)1 << (32 - (netmask + 1)))}
| netmask_ipv4_bits(netmask + 1))
: huint32_t{0};
}
bool
@ -238,12 +242,12 @@ namespace llarp
llarp::Addr lAddr(tunif.ifaddr);
m_OurIP = lAddr.tohl();
m_NextIP = m_OurIP;
uint32_t mask = tunif.netmask;
m_OurIP = lAddr.xtohl();
m_NextIP = m_OurIP;
auto xmask = netmask_ipv4_bits(tunif.netmask);
uint32_t baseaddr = (m_OurIP & netmask_ipv4_bits(mask));
m_MaxIP = htonl(htonl(baseaddr) | ~htonl(netmask_ipv4_bits(mask)));
auto baseaddr = m_OurIP & xmask;
m_MaxIP = baseaddr | ~xmask;
char buf[128] = {0};
llarp::LogInfo(Name(), " set ", tunif.ifname, " to have address ", lAddr);
@ -304,9 +308,14 @@ namespace llarp
if(itr == m_IPToAddr.end())
{
llarp::LogWarn(Name(), " has no endpoint for ",
inet_ntoa({htonl(pkt.dst())}));
inet_ntoa({xhtonl(pkt.dst()).n}));
return true;
}
// prepare packet for insertion into network
// this includes clearing IP addresses, recalculating checksums, etc
pkt.UpdatePacketOnSrc();
if(!SendToOrQueue(itr->second, pkt.Buffer(), service::eProtocolTraffic))
{
llarp::LogWarn(Name(), " did not flush packets");
@ -318,31 +327,31 @@ namespace llarp
bool
TunEndpoint::ProcessDataMessage(service::ProtocolMessage *msg)
{
uint32_t themIP = ObtainIPForAddr(msg->sender.Addr());
uint32_t usIP = m_OurIP;
auto buf = llarp::Buffer(msg->payload);
auto themIP = ObtainIPForAddr(msg->sender.Addr());
auto usIP = m_OurIP;
auto buf = llarp::Buffer(msg->payload);
if(m_NetworkToUserPktQueue.EmplaceIf(
[buf, themIP, usIP](net::IPv4Packet &pkt) -> bool {
// do packet info rewrite here
// TODO: don't truncate packet here
pkt.sz = std::min(buf.sz, sizeof(pkt.buf));
memcpy(pkt.buf, buf.base, pkt.sz);
pkt.src(themIP);
pkt.dst(usIP);
pkt.UpdateChecksum();
// update packet to use proper addresses, recalc checksums
pkt.UpdatePacketOnDst(themIP, usIP);
return true;
}))
llarp::LogDebug(Name(), " handle data message ", msg->payload.size(),
" bytes from ", inet_ntoa({htonl(themIP)}));
" bytes from ", inet_ntoa({xhtonl(themIP).n}));
return true;
}
uint32_t
huint32_t
TunEndpoint::ObtainIPForAddr(const service::Address &addr)
{
llarp_time_t now = llarp_time_now_ms();
uint32_t nextIP = 0;
huint32_t nextIP = {0};
{
// previously allocated address
auto itr = m_AddrToIP.find(addr);
@ -366,7 +375,7 @@ namespace llarp
m_AddrToIP.insert(std::make_pair(addr, nextIP));
m_IPToAddr.insert(std::make_pair(nextIP, addr));
llarp::LogInfo(Name(), " mapped ", addr, " to ",
inet_ntoa({htonl(nextIP)}));
inet_ntoa({xhtonl(nextIP).n}));
MarkIPActive(nextIP);
return nextIP;
}
@ -375,7 +384,7 @@ namespace llarp
// we are full
// expire least active ip
// TODO: prevent DoS
std::pair< uint32_t, llarp_time_t > oldest = {0, 0};
std::pair< huint32_t, llarp_time_t > oldest = {huint32_t{0}, 0};
// find oldest entry
auto itr = m_IPActivity.begin();
@ -403,19 +412,19 @@ namespace llarp
}
bool
TunEndpoint::HasRemoteForIP(const uint32_t &ip) const
TunEndpoint::HasRemoteForIP(huint32_t ip) const
{
return m_IPToAddr.find(ip) != m_IPToAddr.end();
}
void
TunEndpoint::MarkIPActive(uint32_t ip)
TunEndpoint::MarkIPActive(huint32_t ip)
{
m_IPActivity[ip] = std::max(llarp_time_now_ms(), m_IPActivity[ip]);
}
void
TunEndpoint::MarkIPActiveForever(uint32_t ip)
TunEndpoint::MarkIPActiveForever(huint32_t ip)
{
m_IPActivity[ip] = std::numeric_limits< uint64_t >::max();
}

@ -8,6 +8,7 @@
#endif
#include <llarp/endian.h>
#include <map>
#include <algorithm>
namespace llarp
{
@ -16,11 +17,7 @@ namespace llarp
bool
IPv4Packet::Load(llarp_buffer_t pkt)
{
#ifndef MIN
#define MIN(a, b) (a < b ? a : b)
sz = MIN(pkt.sz, sizeof(buf));
#undef MIN
#endif
sz = std::min(pkt.sz, sizeof(buf));
memcpy(buf, pkt.base, sz);
return true;
}
@ -31,6 +28,17 @@ namespace llarp
return llarp::InitBuffer(buf, sz);
}
static uint32_t
ipchksum_pseudoIPv4(nuint32_t src_ip, nuint32_t dst_ip, uint8_t proto,
uint16_t innerlen)
{
#define IPCS(x) ((uint32_t)(x & 0xFFFF) + (uint32_t)(x >> 16))
uint32_t sum = IPCS(src_ip.n) + IPCS(dst_ip.n) + (uint32_t)proto
+ (uint32_t)htons(innerlen);
#undef IPCS
return sum;
}
static uint16_t
ipchksum(const byte_t *buf, size_t sz, uint32_t sum = 0)
{
@ -49,47 +57,195 @@ namespace llarp
return ~sum;
}
static uint16_t
deltachksum(uint16_t old_sum, huint32_t old_src_ip, huint32_t old_dst_ip,
huint32_t new_src_ip, huint32_t new_dst_ip)
{
#define ADDIPCS(x) ((uint32_t)(x.h & 0xFFFF) + (uint32_t)(x.h >> 16))
#define SUBIPCS(x) ((uint32_t)((~x.h) & 0xFFFF) + (uint32_t)((~x.h) >> 16))
uint32_t sum = ntohs(old_sum) + ADDIPCS(old_src_ip) + ADDIPCS(old_dst_ip)
+ SUBIPCS(new_src_ip) + SUBIPCS(new_dst_ip);
#undef ADDIPCS
#undef SUBIPCS
while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
return htons(sum);
}
static std::map<
byte_t, std::function< void(const ip_header *, byte_t *, size_t) > >
protoCheckSummer = {
/// ICMP
{1,
[](const ip_header *hdr, byte_t *buf, size_t sz) {
auto len = hdr->ihl * 4;
uint16_t *check = (uint16_t *)buf + len + 2;
*check = 0;
*check = ipchksum(buf, sz);
byte_t,
std::function< void(const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP,
huint32_t nSrcIP, huint32_t nDstIP) > >
protoDstCheckSummer = {
// {RFC3022} says that IPv4 hdr isn't included in ICMP checksum calc
// and that we don't need to modify it
{// TCP
6,
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP, huint32_t nSrcIP,
huint32_t nDstIP) {
uint16_t *check = (uint16_t *)(pld + 16);
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
}},
{// UDP
17,
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP, huint32_t nSrcIP,
huint32_t nDstIP) {
uint16_t *check = (uint16_t *)(pld + 6);
if(*check != 0xFFff)
{
if(*check == 0x0000)
return; // don't change zero
*check = deltachksum(*check, oSrcIP, oDstIP, nSrcIP, nDstIP);
if(*check == 0x0000)
*check = 0xFFff;
}
else
{
// such checksum can mean 2 things: 0x0000 or 0xFFff
// we can only know by looking at data :<
auto pakcs = *check; // save
*check = 0; // zero checksum before calculation
auto cs = ipchksum(
pld, psz,
ipchksum_pseudoIPv4(nuint32_t{ohdr->saddr},
nuint32_t{ohdr->daddr}, 17, psz));
auto new_cs = deltachksum(cs, oSrcIP, oDstIP, nSrcIP, nDstIP);
if(cs != 0x0000 && cs != 0xFFff)
{
// packet was bad - sabotage new checksum
new_cs += pakcs - cs;
}
// 0x0000 is reserved for no checksum
if(new_cs == 0x0000)
new_cs = 0xFFff;
// put it in
*check = new_cs;
}
}},
/// TCP
{6, [](const ip_header *hdr, byte_t *pkt, size_t sz) {
byte_t pktbuf[1500];
auto len = hdr->ihl * 4;
size_t pktsz = sz - len;
uint16_t *check = (uint16_t *)(pkt + len + 16);
*check = 0;
memcpy(pktbuf, &hdr->saddr, 4);
memcpy(pktbuf + 4, &hdr->daddr, 4);
pktbuf[8] = 0;
pktbuf[9] = 6;
// TODO: endian (?)
pktbuf[10] = (pktsz & 0xff00) >> 8;
pktbuf[11] = pktsz & 0x00ff;
memcpy(pktbuf + 12, pkt + len, pktsz);
*check = ipchksum(pktbuf, 12 + pktsz);
}}};
};
void
IPv4Packet::UpdateChecksum()
IPv4Packet::UpdatePacketOnDst(huint32_t nSrcIP, huint32_t nDstIP)
{
auto hdr = Header();
hdr->check = 0;
auto len = hdr->ihl * 4;
hdr->check = ipchksum(buf, len);
auto hdr = Header();
auto oSrcIP = xntohl(nuint32_t{hdr->saddr});
auto oDstIP = xntohl(nuint32_t{hdr->daddr});
// IPv4 checksum
hdr->check = deltachksum(hdr->check, oSrcIP, oDstIP, nSrcIP, nDstIP);
// L4 checksum
auto proto = hdr->protocol;
auto itr = protoDstCheckSummer.find(proto);
size_t ihs;
if(itr != protoDstCheckSummer.end() && (ihs = size_t(hdr->ihl * 4)) <= sz)
{
itr->second(hdr, buf + ihs, sz - ihs, oSrcIP, oDstIP, nSrcIP, nDstIP);
}
// write new IP addresses
hdr->saddr = xhtonl(nSrcIP).n;
hdr->daddr = xhtonl(nDstIP).n;
}
static std::map<
byte_t,
std::function< void(const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP) > >
protoSrcCheckSummer = {
{// TCP
6,
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP) {
uint16_t *check = (uint16_t *)(pld + 16);
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
}},
{// UDP
17,
[](const ip_header *ohdr, byte_t *pld, size_t psz,
huint32_t oSrcIP, huint32_t oDstIP) {
uint16_t *check = (uint16_t *)(pld + 6);
if(*check != 0xFFff)
{
if(*check == 0x0000)
return; // don't change zero
*check = deltachksum(*check, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
if(*check == 0x0000)
*check = 0xFFff;
}
else
{
// such checksum can mean 2 things: 0x0000 or 0xFFff
// we can only know by looking at data :<
auto pakcs = *check; // save
*check = 0; // zero checksum before calculation
auto cs = ipchksum(
pld, psz,
ipchksum_pseudoIPv4(nuint32_t{ohdr->saddr},
nuint32_t{ohdr->daddr}, 17, psz));
auto new_cs = deltachksum(cs, oSrcIP, oDstIP, huint32_t{0},
huint32_t{0});
if(cs != 0x0000 && cs != 0xFFff)
{
// packet was bad - sabotage new checksum
new_cs += pakcs - cs;
}
// 0x0000 is reserved for no checksum
if(new_cs == 0x0000)
new_cs = 0xFFff;
// put it in
*check = new_cs;
}
}},
};
void
IPv4Packet::UpdatePacketOnSrc()
{
auto hdr = Header();
auto oSrcIP = xntohl(nuint32_t{hdr->saddr});
auto oDstIP = xntohl(nuint32_t{hdr->daddr});
// L4
auto proto = hdr->protocol;
auto itr = protoCheckSummer.find(proto);
if(itr != protoCheckSummer.end())
auto itr = protoSrcCheckSummer.find(proto);
size_t ihs;
if(itr != protoSrcCheckSummer.end() && (ihs = size_t(hdr->ihl * 4)) <= sz)
{
itr->second(hdr, buf, sz);
itr->second(hdr, buf + ihs, sz - ihs, oSrcIP, oDstIP);
}
// IPv4
hdr->check =
deltachksum(hdr->check, oSrcIP, oDstIP, huint32_t{0}, huint32_t{0});
// clear addresses
hdr->saddr = 0;
hdr->daddr = 0;
}
} // namespace net
} // namespace llarp

@ -204,8 +204,8 @@ namespace llarp
return m_Router;
}
IHopHandler *
PathContext::GetPathForTransfer(const PathID_t & id)
IHopHandler*
PathContext::GetPathForTransfer(const PathID_t& id)
{
RouterID us(OurRouterID());
auto& map = m_TransitPaths;
@ -220,7 +220,7 @@ namespace llarp
}
return nullptr;
}
void
PathContext::PutTransitHop(TransitHop* hop)
{

@ -2,6 +2,7 @@
#include <llarp/path.hpp>
#include <llarp/pathbuilder.hpp>
#include <functional>
#include "buffer.hpp"
#include "router.hpp"
@ -14,9 +15,10 @@ namespace llarp
typedef llarp::path::PathSet PathSet_t;
PathSet_t* pathset = nullptr;
Path_t* path = nullptr;
typedef void (*Handler)(AsyncPathKeyExchangeContext< User >*);
User* user = nullptr;
Handler result = nullptr;
typedef std::function< void(AsyncPathKeyExchangeContext< User >*) > Handler;
User* user = nullptr;
Handler result;
size_t idx = 0;
llarp_threadpool* worker = nullptr;
llarp_logic* logic = nullptr;
@ -29,6 +31,7 @@ namespace llarp
AsyncPathKeyExchangeContext< User >* ctx =
static_cast< AsyncPathKeyExchangeContext< User >* >(u);
ctx->result(ctx);
delete ctx;
}
static void
@ -138,7 +141,6 @@ namespace llarp
if(!router->SendToOrQueue(remote, &ctx->LRCM))
{
llarp::LogError("failed to send LRCM");
delete ctx;
return;
}
@ -146,7 +148,6 @@ namespace llarp
router->PersistSessionUntil(remote, ctx->path->ExpireTime());
// add own path
router->paths.AddOwnPath(ctx->pathset, ctx->path);
delete ctx;
}
namespace path
@ -171,20 +172,16 @@ namespace llarp
Builder::SelectHop(llarp_nodedb* db, const RouterContact& prev,
RouterContact& cur, size_t hop)
{
if(hop == 0)
{
if(router->NumberOfConnectedRouters())
return router->GetRandomConnectedRouter(cur);
else
return llarp_nodedb_select_random_hop(db, prev, cur, 0);
}
if(hop == 0 && router->NumberOfConnectedRouters())
return router->GetRandomConnectedRouter(cur);
size_t tries = 5;
do
{
--tries;
llarp_nodedb_select_random_hop(db, prev, cur, hop);
} while(router->routerProfiling.IsBad(cur.pubkey) && tries > 0);
return tries > 0;
return !router->routerProfiling.IsBad(cur.pubkey);
}
const byte_t*

@ -3,6 +3,7 @@
#include <llarp/iwp.hpp>
#include <llarp/link_message.hpp>
#include <llarp/link/utp.hpp>
#include <llarp/arpc.hpp>
#include "buffer.hpp"
#include "encode.hpp"
@ -647,6 +648,22 @@ llarp_router::async_verify_RC(const llarp::RouterContact &rc)
void
llarp_router::Run()
{
if(enableRPCServer)
{
if(rpcBindAddr.empty())
{
rpcBindAddr = DefaultRPCBindAddr;
}
rpcServer = std::make_unique< llarp::arpc::Server >(this);
if(!rpcServer->Start(rpcBindAddr))
{
llarp::LogError("Binding rpc server to ", rpcBindAddr, " failed");
rpcServer.reset();
}
else
llarp::LogInfo("Bound RPC server to ", rpcBindAddr);
}
routerProfiling.Load(routerProfilesFile.c_str());
// zero out router contact
const sockaddr *dest = (sockaddr *)&this->ip4addr;
@ -1135,6 +1152,21 @@ namespace llarp
self->defaultIfName = val;
}
}
else if(StrEq(section, "api"))
{
if(StrEq(key, "enabled"))
{
self->enableRPCServer = IsTrueValue(val);
}
if(StrEq(key, "bind"))
{
self->rpcBindAddr = val;
}
if(StrEq(key, "authkey"))
{
// TODO: add pubkey to whitelist
}
}
else if(StrEq(section, "services"))
{
if(self->LoadHiddenServiceConfig(val))
@ -1215,5 +1247,20 @@ namespace llarp
self->publicOverride = true;
}
}
} // namespace llarp
}
namespace arpc
{
const byte_t *
Server::SigningPrivateKey() const
{
return router->identity;
}
const llarp_crypto *
Server::Crypto() const
{
return &router->crypto;
}
} // namespace arpc
} // namespace llarp

@ -5,6 +5,7 @@
#include <llarp/router_contact.hpp>
#include <llarp/path.hpp>
#include <llarp/link_layer.hpp>
#include <llarp/arpc.hpp>
#include <functional>
#include <list>
@ -102,6 +103,11 @@ struct llarp_router
bool
ShouldCreateDefaultHiddenService();
std::string DefaultRPCBindAddr = "127.0.0.1:1190";
bool enableRPCServer = false;
std::unique_ptr< llarp::arpc::Server > rpcServer;
std::string rpcBindAddr = DefaultRPCBindAddr;
std::unique_ptr< llarp::ILinkLayer > outboundLink;
std::vector< std::unique_ptr< llarp::ILinkLayer > > inboundLinks;

@ -109,9 +109,7 @@ namespace llarp
bool
IntroSet::IsExpired(llarp_time_t now) const
{
if(now > T)
return false;
return now - T > DEFAULT_PATH_LIFETIME;
return GetNewestIntroExpiration() < now;
}
Introduction::~Introduction()
@ -342,6 +340,15 @@ namespace llarp
return true;
}
llarp_time_t
IntroSet::GetNewestIntroExpiration() const
{
llarp_time_t t = 0;
for(const auto& intro : I)
t = std::max(intro.expiresAt, t);
return t;
}
bool
Config::Load(const std::string& fname)
{

@ -115,7 +115,7 @@ namespace llarp
}
bool
Context::MapAddress(const llarp::service::Address &addr, uint32_t ip)
Context::MapAddress(const llarp::service::Address &addr, huint32_t ip)
{
if(!m_Endpoints.size())
{
@ -148,7 +148,7 @@ namespace llarp
return false;
}
return tunEndpoint->MapAddress(context->serviceAddr,
context->localPrivateIpAddr.tohl());
context->localPrivateIpAddr.xtohl());
}
bool

@ -843,13 +843,15 @@ namespace llarp
bool
Endpoint::OnOutboundLookup(const Address& addr, const IntroSet* introset)
{
if(!introset)
auto now = llarp_time_now_ms();
if(introset == nullptr || introset->IsExpired(now))
{
auto itr = m_PendingServiceLookups.find(addr);
if(itr != m_PendingServiceLookups.end())
{
auto func = itr->second;
m_PendingServiceLookups.erase(itr);
itr->second(addr, nullptr);
func(addr, nullptr);
}
return false;
}
@ -963,6 +965,12 @@ namespace llarp
llarp::LogInfo("introset is old, dropping");
return true;
}
auto now = llarp_time_now_ms();
if(i->IsExpired(now))
{
llarp::LogError("got expired introset from lookup");
return true;
}
currentIntroSet = *i;
if(!ShiftIntroduction())
{
@ -1418,7 +1426,7 @@ namespace llarp
{
// shift intro if it expires "soon"
ShiftIntroduction();
if(remoteIntro != m_NextIntro)
{
if(GetPathByRouter(m_NextIntro.router) != nullptr)

@ -32,6 +32,7 @@ TEST_F(HiddenServiceTest, TestGenerateIntroSet)
ASSERT_TRUE(ident.pub.CalculateAddress(addr.data()));
llarp::service::IntroSet I;
auto now = llarp_time_now_ms();
I.T = now;
while(I.I.size() < 10)
{
llarp::service::Introduction intro;

Loading…
Cancel
Save