From 475ac63f4aa95e493c5677050279c5460c3b9cee Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Tue, 9 Oct 2018 08:06:30 -0400 Subject: [PATCH] initial admin api infra --- CMakeLists.txt | 1 + client/main.cpp | 6 +- development.md | 74 ------- docs/lokinet_admin_v0.txt | 154 +++++++++++++++ docs/lokinet_api_v0.txt | 1 - include/llarp/arpc.hpp | 64 ++++++ include/llarp/ev.h | 48 +++++ llarp/arpc.cpp | 405 ++++++++++++++++++++++++++++++++++++++ llarp/config.cpp | 24 ++- llarp/config.hpp | 1 + llarp/ev.cpp | 25 +++ llarp/ev.hpp | 2 +- llarp/pathbuilder.cpp | 12 +- llarp/router.cpp | 49 ++++- llarp/router.hpp | 6 + 15 files changed, 780 insertions(+), 92 deletions(-) delete mode 100644 development.md create mode 100644 docs/lokinet_admin_v0.txt delete mode 100644 docs/lokinet_api_v0.txt create mode 100644 include/llarp/arpc.hpp create mode 100644 llarp/arpc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2108fc82a..b8c251475 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/client/main.cpp b/client/main.cpp index fc33c5182..33fe49995 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -1,8 +1,6 @@ -#include -#include int main(int argc, char* argv[]) { - return 1; -} \ No newline at end of file + return 0; +} diff --git a/development.md b/development.md deleted file mode 100644 index 42c2c0ed0..000000000 --- a/development.md +++ /dev/null @@ -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 `` or `` 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 -
-

Inbound sessions are unsupported on Windows Server systems.

-

Ignore this warning at your own peril.

-
- -##### Building a debug build: - - #in lokinet-builder/ - $ cd build - $ make \ No newline at end of file diff --git a/docs/lokinet_admin_v0.txt b/docs/lokinet_admin_v0.txt new file mode 100644 index 000000000..bcb411d24 --- /dev/null +++ b/docs/lokinet_admin_v0.txt @@ -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" : "", + "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" + } diff --git a/docs/lokinet_api_v0.txt b/docs/lokinet_api_v0.txt deleted file mode 100644 index 02db168e8..000000000 --- a/docs/lokinet_api_v0.txt +++ /dev/null @@ -1 +0,0 @@ -insert lokinet api overview here \ No newline at end of file diff --git a/include/llarp/arpc.hpp b/include/llarp/arpc.hpp new file mode 100644 index 000000000..842a48a5c --- /dev/null +++ b/include/llarp/arpc.hpp @@ -0,0 +1,64 @@ +#ifndef LLARP_ARPC_HPP +#define LLARP_ARPC_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + +#include + +// 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 diff --git a/include/llarp/ev.h b/include/llarp/ev.h index ae66fd6a2..935ffee2a 100644 --- a/include/llarp/ev.h +++ b/include/llarp/ev.h @@ -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 diff --git a/llarp/arpc.cpp b/llarp/arpc.cpp new file mode 100644 index 000000000..8a5e6017f --- /dev/null +++ b/llarp/arpc.cpp @@ -0,0 +1,405 @@ +#include + +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 diff --git a/llarp/config.cpp b/llarp/config.cpp index bf6e2a405..ef8799f04 100644 --- a/llarp/config.cpp +++ b/llarp/config.cpp @@ -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()); diff --git a/llarp/config.hpp b/llarp/config.hpp index 8de769aee..ba00b3b83 100644 --- a/llarp/config.hpp +++ b/llarp/config.hpp @@ -19,6 +19,7 @@ namespace llarp section_t connect; section_t services; section_t system; + section_t api; bool Load(const char *fname); diff --git a/llarp/ev.cpp b/llarp/ev.cpp index 07bf7d55b..b947479d5 100644 --- a/llarp/ev.cpp +++ b/llarp/ev.cpp @@ -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; +} diff --git a/llarp/ev.hpp b/llarp/ev.hpp index d91fe37e2..f27b57db8 100644 --- a/llarp/ev.hpp +++ b/llarp/ev.hpp @@ -50,7 +50,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) { diff --git a/llarp/pathbuilder.cpp b/llarp/pathbuilder.cpp index 4c10b8f78..20d66ca4d 100644 --- a/llarp/pathbuilder.cpp +++ b/llarp/pathbuilder.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include "buffer.hpp" #include "router.hpp" @@ -14,9 +16,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 +32,7 @@ namespace llarp AsyncPathKeyExchangeContext< User >* ctx = static_cast< AsyncPathKeyExchangeContext< User >* >(u); ctx->result(ctx); + delete ctx; } static void @@ -138,7 +142,6 @@ namespace llarp if(!router->SendToOrQueue(remote, &ctx->LRCM)) { llarp::LogError("failed to send LRCM"); - delete ctx; return; } @@ -146,7 +149,6 @@ namespace llarp router->PersistSessionUntil(remote, ctx->path->ExpireTime()); // add own path router->paths.AddOwnPath(ctx->pathset, ctx->path); - delete ctx; } namespace path diff --git a/llarp/router.cpp b/llarp/router.cpp index 982f7d06b..669c5af63 100644 --- a/llarp/router.cpp +++ b/llarp/router.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #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 sockaddr *dest = (sockaddr *)&this->ip4addr; @@ -1138,6 +1155,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)) @@ -1218,5 +1250,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 diff --git a/llarp/router.hpp b/llarp/router.hpp index a0ad8df2a..8b06aa9c8 100644 --- a/llarp/router.hpp +++ b/llarp/router.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -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;