Merge pull request #359 from majestrate/fix-libabyss-352

Fix #352
This commit is contained in:
Jeff 2019-02-27 11:18:46 -05:00 committed by GitHub
commit c10f7d82cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 698 additions and 559 deletions

View File

@ -51,7 +51,7 @@ GRADLE ?= gradle
JAVA_HOME ?= /usr/lib/jvm/default-java JAVA_HOME ?= /usr/lib/jvm/default-java
# jsonrpc server # jsonrpc server
JSONRPC ?= OFF JSONRPC ?= ON
# native avx2 code # native avx2 code
AVX2 ?= OFF AVX2 ?= OFF
# non x86 target # non x86 target
@ -63,7 +63,7 @@ NETNS ?= OFF
# cross compile? # cross compile?
CROSS ?= OFF CROSS ?= OFF
# build liblokinet-shared.so # build liblokinet-shared.so
SHARED_LIB ?= ON SHARED_LIB ?= OFF
# enable generating coverage # enable generating coverage
COVERAGE ?= OFF COVERAGE ?= OFF
COVERAGE_OUTDIR ?= "$(TMPDIR)/lokinet-coverage" COVERAGE_OUTDIR ?= "$(TMPDIR)/lokinet-coverage"

View File

@ -9,23 +9,66 @@ LLARP supports by default an authenticated message transport over a
datagram based network layer. datagram based network layer.
protocol phases:
first phase: proof of flow
second phase: session handshake
thrid phase: data transmission
proof of flow:
At any time before the data transfer phase a reject message
is sent the session is reset.
Alice (A) is the sender and Bob (B) is the recipiant.
A asks for a flow id from B.
B MAY send a flow id to A or MAY reject the message from A.
session handshake:
an encrypted session is established using establish wire session messages
using a newly created flow id.
outer message format: outer message format:
every outer message MAY be obfsucated via symettric encryption for dpi
resistance reasons, this is not authenticated encryption.
the message is first assumed to be sent in clear first.
if parsing of clear variant fails then the recipiant MUST fall back to assuming
the protocol is in obfuscated mode.
<16 bytes nounce, n>
<remaining bytes obsfucated, m>
obfuscated via:
K = HS(B_k)
N = HS(n + K)
X = SD(K, m, N[0:24])
outer-header: outer-header:
<1 byte command> <1 byte command>
<1 byte reserved, R, set to '=' (0x3d)> <1 byte reserved set to 0x3d>
<32 bytes flow id, B>
command 'O' - obtain flow id command 'O' - obtain flow id
obtain a handshake cookie obtain a flow id
<outer-header> <outer-header>
<32 bytes random> <6 magic bytes "netid?">
<8 bytes net id> <8 bytes netid, I>
<remaining discarded> <8 bytes timestamp milliseconds since epoch, T>
<32 bytes ed25519 public key of sender, A_k>
<0-N bytes discarded>
<last 64 bytes signature of unobfuscated packet, Z>
the if the network id differs from the current network's id a reject message the if the network id differs from the current network's id a reject message
MUST be sent MUST be sent
@ -35,106 +78,59 @@ MUST be replied to with a message rejected or a give handshake cookie
command 'G' - give flow id command 'G' - give flow id
<outer-header> <outer-header>
<32 byte new flow-id, X> <6 magic bytes "netid!">
<remaining discarded> <16 bytes new flow id>
<32 bytes ed25519 public key of sender, A_k>
<0-N bytes discarded>
<last 64 bytes signature of unobfsucated packet, Z>
give a flow id to a remote endpoint that asks for one after recieving a give flow id message a session negotiation can happen with that flow id.
B is the B value from the request flow id message command 'R' - flow rejected
X is a 32 byte the flow id, calcuated via:
r = RAND(32) reject new flow
a = "::ffff.<ascii representation of ipv4 address>" + ":" + "<port number>"
X = HS(a + B + r + net id)
resulting message:
"G=<32 byte flowid><32 bytes new flowid>"
after recieving a give flow id message a session negotiation can happen
command 'R' - message rejected
<outer-header> <outer-header>
<N arbitrary bytes reason for rejection> <14 ascii bytes reason for rejection null padded>
<8 bytes timestamp>
<32 bytes ed25519 public key of sender, A_k>
<0-N bytes discarded>
<last 64 bytes signature of unobsfucated packet, Z>
reject a message on a flow id command 'E' - establish wire session
B is the flow id from the recipiant establish an encrypted session using a flow id
resulting message of reject with reason "no you"
"R=<32 byte flow-id>no you"
command 'S' - session negotiation
negotiate encrypted session
<outer-header> <outer-header>
<24 bytes nounce, N> <16 bytes flow id, B>
<encrypted session negotiation data, X> <32 bytes ephemeral public encryption key, E>
<last 32 bytes keyed hash, Z> <8 bytes packet counter starting at 0>
<optional 32 bytes authenticated credentials, A>
<last 64 bytes signature of unobfuscated packet using identity key, Z>
B is the flow id from the recipiant generated by the give flow id message (from outer header) every time we try establishing a wire session we increment the counter
N is a random nounce by 1 for the next message we send.
X is encrypted session negotiation data
Z is a keyed hash
Z is generated via: when we get an establish wire session message
we reply with an establish wire session message with counter being counter + 1
msg.Z = '0x00' * 32 if A is provided that is interpreted as being generated via:
msg.Z = MDS(msg, tx_K)
session negotiation: h0 = HS('<insert some password here>')
h1 = EDDH(us, them)
A = HS(B + h0 + h1)
The session starts out with each side having 2 session keys rx_K and tx_K for each side establishes their own rx key using this message.
decrypting inbound messages and encrypting outbound messages respectively. when each side has both established thier rx key data can be transmitted.
The initiator (alice) and the recipiant (bob) start out with static session keys command 'D' - encrypted data transmission
k_a = HS(a.k) transmit encrypted data on a wire session
k_b = HS(b.k)
a.rx_K = k_a
b.rx_K = k_b
a.tx_K = k_b
b.tx_K = k_a
decryption is done via:
SD(msg.X, rx_K, msg.N)
encrypted payload is bencoded LIM (see proto_v0.txt)
the initiator starts out by sending a LIM a_LIM to the recipiant.
the recipiant replies with a LIM b_LIM to the initiator.
when the initiator gets a valid LIM from the recipiant the session keys for data
transmission are set to:
k_a = TKE(a.k, b.k, a.sk, a_LIM.n)
k_b = TKE(b.k, a.k, b.sk, b_LIM.n)
a.rx_K = k_a
b.rx_K = k_b
a.tx_K = k_b
b.tx_K = k_a
afterwards data transmission may happen.
the intiator's remote address is permitted to change during data transmission.
remote address of the last successfully
D - encrypted data transmission
transmit encrypted data on session
<outer-header> <outer-header>
<16 bytes flow-id, F>
<24 bytes nonce, N> <24 bytes nonce, N>
<encrypted data, X> <N encrypted data, X>
<last 32 bytes keyed hash of entire payload, Z> <last 32 bytes keyed hash of entire payload, Z>
@ -158,7 +154,7 @@ header:
<1 byte command> <1 byte command>
command: 'K' (keep alive) command: 'k' (keep alive)
tell other side to acknoledge they are alive tell other side to acknoledge they are alive
@ -171,7 +167,7 @@ tell other side to acknoledge they are alive
<8 bytes milliseconds since epoch our current time> <8 bytes milliseconds since epoch our current time>
<remaining bytes discarded> <remaining bytes discarded>
command: 'L' (keep alive ack) command: 'l' (keep alive ack)
acknolege keep alive message acknolege keep alive message
@ -183,7 +179,29 @@ acknolege keep alive message
<remaining bytes discarded> <remaining bytes discarded>
command: 'C' (congestion) command: 'n' (advertise neighboors)
tell peer about neighboors, only sent by non service nodes to other non service
nodes.
<header>
<route between us and them>
<0 or more intermediate routes>
<route from a service node>
route:
<1 byte route version (currently 0)>
<1 byte flags, lsb set indicates src is a service node>
<2 bytes latency in ms>
<2 bytes backpressure>
<2 bytes number of connected peers>
<8 bytes publish timestamp ms since epoch>
<32 bytes pubkey neighboor>
<32 bytes pubkey src>
<64 bytes signature of entire route signed by src>
command: 'c' (congestion)
tell other side to slow down tell other side to slow down
@ -192,7 +210,7 @@ tell other side to slow down
<4 bytes milliseconds slowdown lifetime> <4 bytes milliseconds slowdown lifetime>
<remaining bytes discarded> <remaining bytes discarded>
command: 'D' (anti-congestion) command: 'd' (anti-congestion)
tell other side to speed up tell other side to speed up
@ -201,26 +219,35 @@ tell other side to speed up
<4 bytes milliseconds speedup lifetime> <4 bytes milliseconds speedup lifetime>
<remaining bytes discarded> <remaining bytes discarded>
command: 'T' (transmit) command: 't' (transmit data)
transit fragment transmit a message to a peer
if this fragment is not addressed to us we route it to the neighboor
with the shortest route to the recipiant as advertised by all neighboors.
<header> <header>
<1 byte number of 16 byte blocks offset from beginning of message, O> <32 bytes public identity key of recipiant>
<1 byte number of 16 byte blocks size of fragment data, N> <32 bytes public identity key of sender>
<4 bytes sequence number> <24 bytes nounce, N>
<32 bytes expected digest of message, present if O is 0, otherwise omitted> <N bytes encrypted message, X>
<16 * N bytes of data> <last 32 bytes keyed hash, Z>
<remaining bytes discarded>
command: 'A' (ack) encrypted via:
acknoledge fragments K = EDDH(recipiant, sender)
X = SE(msg, K, N)
Z = MDS(X, K)
<header> encrypted message format:
<1 byte number of acks following, N>
<8 * N bytes acks> <1 byte version, currently 0>
<remaining bytes discarded> <1 byte number of acks following, aN>
<8 * aN bytes acks>
<4 byte sequence number of fragment or 0 if no fragment is included>
<2 byte 16 byte block offset in message of this fragment if it is included>
<remaining bytes fragment data aligned to 16 bytes>
<discard anything not aligned to 16 bytes>
ack format: ack format:
@ -231,7 +258,7 @@ ack format:
<1 byte bitmask fragments posative ack (msb is fragment 0, lsb is fragment 7)> <1 byte bitmask fragments posative ack (msb is fragment 0, lsb is fragment 7)>
command: 'R' (rotate keys) command: 'r' (rotate keys)
inform remote that their RX key should be rotated inform remote that their RX key should be rotated
@ -248,7 +275,7 @@ B.rx_K = n_K
<32 bytes next public encryption key, K> <32 bytes next public encryption key, K>
<remaining bytes discarded> <remaining bytes discarded>
command: 'U' (upgrade) command: 'u' (upgrade)
request protocol upgrade request protocol upgrade
@ -257,7 +284,7 @@ request protocol upgrade
<1 byte protocol max version to upgrade to> <1 byte protocol max version to upgrade to>
<remaining bytes discarded> <remaining bytes discarded>
command: 'V' (version upgrade) command: 'v' (version upgrade)
sent in response to upgrade message sent in response to upgrade message

View File

@ -24,15 +24,28 @@ struct DemoHandler : public abyss::httpd::IRPCHandler
struct DemoCall : public abyss::http::IRPCClientHandler struct DemoCall : public abyss::http::IRPCClientHandler
{ {
DemoCall(abyss::http::ConnImpl* impl) : abyss::http::IRPCClientHandler(impl) std::function< void(void) > m_Callback;
llarp::Logic* m_Logic;
DemoCall(abyss::http::ConnImpl* impl, llarp::Logic* logic,
std::function< void(void) > callback)
: abyss::http::IRPCClientHandler(impl)
, m_Callback(callback)
, m_Logic(logic)
{ {
llarp::LogInfo("new call"); llarp::LogInfo("new call");
} }
bool static void
HandleResponse(abyss::http::RPC_Response resp) override CallCallback(void* u)
{ {
llarp::json::ToString(resp, std::cout); static_cast< DemoCall* >(u)->m_Callback();
}
bool HandleResponse(abyss::http::RPC_Response) override
{
llarp::LogInfo("response get");
m_Logic->queue_job({this, &CallCallback});
return true; return true;
} }
@ -51,10 +64,18 @@ struct DemoCall : public abyss::http::IRPCClientHandler
struct DemoClient : public abyss::http::JSONRPC struct DemoClient : public abyss::http::JSONRPC
{ {
llarp_ev_loop* m_Loop;
llarp::Logic* m_Logic;
DemoClient(llarp_ev_loop* l, llarp::Logic* logic)
: abyss::http::JSONRPC(), m_Loop(l), m_Logic(logic)
{
}
abyss::http::IRPCClientHandler* abyss::http::IRPCClientHandler*
NewConn(abyss::http::ConnImpl* impl) NewConn(abyss::http::ConnImpl* impl)
{ {
return new DemoCall(impl); return new DemoCall(impl, m_Logic, std::bind(&llarp_ev_loop_stop, m_Loop));
} }
void void
@ -109,7 +130,7 @@ main(__attribute__((unused)) int argc, __attribute__((unused)) char* argv[])
addr.sin_port = htons(1222); addr.sin_port = htons(1222);
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
DemoServer serv; DemoServer serv;
DemoClient client; DemoClient client(loop, logic);
llarp::Addr a(addr); llarp::Addr a(addr);
while(true) while(true)
{ {

View File

@ -70,7 +70,7 @@ namespace abyss
ConnImpl* self = static_cast< ConnImpl* >(conn->user); ConnImpl* self = static_cast< ConnImpl* >(conn->user);
if(!self->ProcessRead((const char*)buf.base, buf.sz)) if(!self->ProcessRead((const char*)buf.base, buf.sz))
{ {
self->CloseError(); self->CloseError("on read failed");
} }
} }
@ -138,8 +138,8 @@ namespace abyss
Close(); Close();
return true; return true;
case json::IParser::eParseError: case json::IParser::eParseError:
handler->HandleError(); CloseError("json parse error");
return false; return true;
default: default:
return false; return false;
} }
@ -195,8 +195,9 @@ namespace abyss
} }
void void
CloseError() CloseError(const char* msg)
{ {
LogError("CloseError: ", msg);
if(handler) if(handler)
handler->HandleError(); handler->HandleError();
handler = nullptr; handler = nullptr;
@ -221,72 +222,20 @@ namespace abyss
std::stringstream ss; std::stringstream ss;
json::ToString(m_RequestBody, ss); json::ToString(m_RequestBody, ss);
body = ss.str(); body = ss.str();
// request base m_SendHeaders.emplace("Content-Type", "application/json");
char buf[512] = {0}; m_SendHeaders.emplace("Content-Length", std::to_string(body.size()));
int sz = snprintf(buf, sizeof(buf), m_SendHeaders.emplace("Accept", "application/json");
"POST /rpc HTTP/1.0\r\nContent-Type: " std::stringstream request;
"application/json\r\nContent-Length: %zu\r\nAccept: " request << "POST /json_rpc HTTP/1.0\r\n";
"application/json\r\n",
body.size());
if(sz <= 0)
return;
if(!llarp_tcp_conn_async_write(m_Conn, llarp_buffer_t(buf, sz)))
{
llarp::LogError("failed to write first part of request");
CloseError();
return;
}
// header delimiter
buf[0] = ':';
buf[1] = ' ';
// CRLF
buf[2] = '\r';
buf[3] = '\n';
// write extra request header
for(const auto& item : m_SendHeaders) for(const auto& item : m_SendHeaders)
request << item.first << ": " << item.second << "\r\n";
request << "\r\n" << body;
std::string buf = request.str();
if(!llarp_tcp_conn_async_write(m_Conn,
llarp_buffer_t(buf.c_str(), buf.size())))
{ {
// header name CloseError("failed to write request");
if(!llarp_tcp_conn_async_write(
m_Conn, llarp_buffer_t(item.first.c_str(), item.first.size())))
{
CloseError();
return;
}
// header delimiter
if(!llarp_tcp_conn_async_write(m_Conn,
llarp_buffer_t(buf, 2 * sizeof(char))))
{
CloseError();
return;
}
// header value
if(!llarp_tcp_conn_async_write(
m_Conn,
llarp_buffer_t(item.second.c_str(), item.second.size())))
{
CloseError();
return;
}
// CRLF
if(!llarp_tcp_conn_async_write(
m_Conn, llarp_buffer_t(buf + 2, 2 * sizeof(char))))
{
CloseError();
return;
}
}
// CRLF
if(!llarp_tcp_conn_async_write(
m_Conn, llarp_buffer_t(buf + 2, 2 * sizeof(char))))
{
CloseError();
return;
}
// request body
if(!llarp_tcp_conn_async_write(
m_Conn, llarp_buffer_t(body.c_str(), body.size())))
{
CloseError();
return; return;
} }
llarp::LogDebug("request sent"); llarp::LogDebug("request sent");

View File

@ -39,6 +39,16 @@ namespace llarp
return *this; return *this;
} }
void
Resize(size_t sz)
{
if(sz <= EncryptedFrameSize)
{
_sz = sz;
UpdateBuffer();
}
}
bool bool
DecryptInPlace(const SecretKey& seckey, llarp::Crypto* crypto); DecryptInPlace(const SecretKey& seckey, llarp::Crypto* crypto);

View File

@ -555,13 +555,22 @@ namespace llarp
void void
connected() connected()
{ {
// we are connected yeh boi sockaddr_storage st;
if(_conn) socklen_t sl;
if (getpeername(fd, (sockaddr*)&st, &sl) == 0)
{ {
if(_conn->connected && !_calledConnected) // we are connected yeh boi
_conn->connected(_conn, &tcp); if(_conn)
{
if(_conn->connected && !_calledConnected)
_conn->connected(_conn, &tcp);
}
_calledConnected = true;
}
else
{
error();
} }
_calledConnected = true;
} }
void void
@ -575,8 +584,9 @@ namespace llarp
} }
void void
error() error() override
{ {
_shouldClose = true;
if(_conn) if(_conn)
{ {
#ifndef _WIN32 #ifndef _WIN32
@ -591,6 +601,7 @@ namespace llarp
if(_conn->error) if(_conn->error)
_conn->error(_conn); _conn->error(_conn);
} }
} }
virtual ssize_t virtual ssize_t

View File

@ -20,7 +20,7 @@ namespace llarp
if(tcp.read) if(tcp.read)
tcp.read(&tcp, llarp_buffer_t(buf, amount)); tcp.read(&tcp, llarp_buffer_t(buf, amount));
} }
else else if(amount < 0)
{ {
// error // error
_shouldClose = true; _shouldClose = true;
@ -123,7 +123,7 @@ namespace llarp
return -1; return -1;
b.sz = ret; b.sz = ret;
udp->recvfrom(udp, addr, ManagedBuffer{b}); udp->recvfrom(udp, addr, ManagedBuffer{b});
return 0; return ret;
} }
int int
@ -323,6 +323,7 @@ llarp_epoll_loop::tick(int ms)
epoll_event events[1024]; epoll_event events[1024];
int result; int result;
result = epoll_wait(epollfd, events, 1024, ms); result = epoll_wait(epollfd, events, 1024, ms);
bool didIO = false;
if(result > 0) if(result > 0)
{ {
int idx = 0; int idx = 0;
@ -331,22 +332,27 @@ llarp_epoll_loop::tick(int ms)
llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr); llarp::ev_io* ev = static_cast< llarp::ev_io* >(events[idx].data.ptr);
if(ev) if(ev)
{ {
llarp::LogDebug(idx, " of ", result, llarp::LogDebug(idx, " of ", result, " on ", ev->fd,
" events=", std::to_string(events[idx].events)); " events=", std::to_string(events[idx].events));
if(events[idx].events & EPOLLERR) if(events[idx].events & EPOLLERR)
{ {
llarp::LogDebug("epoll error");
ev->error(); ev->error();
} }
else else
{ {
if(events[idx].events & EPOLLIN) // write THEN READ don't revert me
{
ev->read(readbuf, sizeof(readbuf));
}
if(events[idx].events & EPOLLOUT) if(events[idx].events & EPOLLOUT)
{ {
llarp::LogDebug("epoll out");
ev->flush_write(); ev->flush_write();
} }
if(events[idx].events & EPOLLIN)
{
llarp::LogDebug("epoll in");
if(ev->read(readbuf, sizeof(readbuf)) > 0)
didIO = true;
}
} }
} }
++idx; ++idx;
@ -354,6 +360,9 @@ llarp_epoll_loop::tick(int ms)
} }
if(result != -1) if(result != -1)
tick_listeners(); tick_listeners();
/// if we didn't get an io events we sleep to avoid 100% cpu use
if(!didIO)
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
return result; return result;
} }

View File

@ -1,23 +1,207 @@
#include <link/iwp.hpp> #include <link/iwp.hpp>
#include <link/iwp_internal.hpp> #include <link/iwp_internal.hpp>
#include <router/abstractrouter.hpp>
namespace llarp namespace llarp
{ {
namespace iwp namespace iwp
{ {
std::unique_ptr< ILinkLayer > void
NewServerFromRouter(AbstractRouter*) OuterMessage::Clear()
{ {
command = 0;
flow.Zero();
netid.Zero();
nextFlowID.Zero();
rejectReason.clear();
N.Zero();
X.Zero();
Xsize = 0;
Z.Zero();
}
bool
OuterMessage::Decode(llarp_buffer_t* buf)
{
if(buf->size_left() < 34)
return false;
command = *buf->cur;
++buf->cur;
if(*buf->cur != '=')
return false;
std::copy_n(flow.begin(), 32, buf->cur);
buf->cur += 32;
switch(command)
{
case eOCMD_ObtainFlowID:
if(buf->size_left() < 40)
return false;
buf->cur += 32;
std::copy_n(netid.begin(), 8, buf->cur);
return true;
case eOCMD_GiveFlowID:
if(buf->size_left() < 32)
return false;
std::copy_n(nextFlowID.begin(), 32, buf->cur);
return true;
case eOCMD_Reject:
rejectReason = std::string(buf->cur, buf->base + buf->sz);
return true;
case eOCMD_SessionNegotiate:
// explicit fallthrough
case eOCMD_TransmitData:
if(buf->size_left() <= 56)
return false;
std::copy_n(N.begin(), N.size(), buf->cur);
buf->cur += N.size();
Xsize = buf->size_left() - Z.size();
if(Xsize > X.size())
return false;
std::copy_n(X.begin(), Xsize, buf->cur);
buf->cur += Xsize;
std::copy_n(Z.begin(), Z.size(), buf->cur);
return true;
default:
return false;
}
}
LinkLayer::LinkLayer(Crypto* c, const SecretKey& enckey, GetRCFunc getrc,
LinkMessageHandler h, SessionEstablishedHandler est,
SessionRenegotiateHandler reneg, SignBufferFunc sign,
TimeoutHandler t, SessionClosedHandler closed)
: ILinkLayer(enckey, getrc, h, sign, est, reneg, t, closed), crypto(c)
{
}
LinkLayer::~LinkLayer()
{
}
void
LinkLayer::Pump()
{
ILinkLayer::Pump();
}
const char*
LinkLayer::Name() const
{
return "iwp";
}
bool
LinkLayer::KeyGen(SecretKey& k)
{
k.Zero();
crypto->encryption_keygen(k);
return !k.IsZero();
}
uint16_t
LinkLayer::Rank() const
{
return 2;
}
bool
LinkLayer::Start(Logic* l)
{
if(!ILinkLayer::Start(l))
return false;
/// TODO: change me to true when done
return false;
}
void
LinkLayer::RecvFrom(const Addr& from, const void* pkt, size_t sz)
{
m_OuterMsg.Clear();
llarp_buffer_t buf(pkt, sz);
if(!m_OuterMsg.Decode(&buf))
{
LogError("failed to decode outer message");
return;
}
NetID ourNetID;
switch(m_OuterMsg.command)
{
case eOCMD_ObtainFlowID:
if(!ShouldSendFlowID(from))
return; // drop
if(m_OuterMsg.netid == ourNetID)
SendFlowID(from, m_OuterMsg.flow);
else
SendReject(from, m_OuterMsg.flow, "bad net id");
}
}
ILinkSession*
LinkLayer::NewOutboundSession(const RouterContact& rc,
const AddressInfo& ai)
{
(void)rc;
(void)ai;
// TODO: implement me // TODO: implement me
return nullptr; return nullptr;
} }
std::unique_ptr< ILinkLayer > void
NewServer(llarp::Crypto*, const SecretKey&, llarp::GetRCFunc, LinkLayer::SendFlowID(const Addr& to, const FlowID_t& flow)
llarp::LinkMessageHandler, llarp::SessionEstablishedHandler,
llarp::SessionRenegotiateHandler, llarp::SignBufferFunc,
llarp::TimeoutHandler, llarp::SessionClosedHandler)
{ {
// TODO: implement me
(void)to;
(void)flow;
}
bool
LinkLayer::ShouldSendFlowID(const Addr& to) const
{
(void)to;
// TODO: implement me
return false;
}
void
LinkLayer::SendReject(const Addr& to, const FlowID_t& flow, const char* msg)
{
// TODO: implement me
(void)to;
(void)flow;
(void)msg;
}
std::unique_ptr< ILinkLayer >
NewServerFromRouter(AbstractRouter* r)
{
using namespace std::placeholders;
return NewServer(
r->crypto(), r->encryption(), std::bind(&AbstractRouter::rc, r),
std::bind(&AbstractRouter::HandleRecvLinkMessageBuffer, r, _1, _2),
std::bind(&AbstractRouter::OnSessionEstablished, r, _1),
std::bind(&AbstractRouter::CheckRenegotiateValid, r, _1, _2),
std::bind(&AbstractRouter::Sign, r, _1, _2),
std::bind(&AbstractRouter::OnConnectTimeout, r, _1),
std::bind(&AbstractRouter::SessionClosed, r, _1));
}
std::unique_ptr< ILinkLayer >
NewServer(Crypto* c, const SecretKey& enckey, GetRCFunc getrc,
LinkMessageHandler h, SessionEstablishedHandler est,
SessionRenegotiateHandler reneg, SignBufferFunc sign,
TimeoutHandler t, SessionClosedHandler closed)
{
(void)c;
(void)enckey;
(void)getrc;
(void)h;
(void)est;
(void)reneg;
(void)sign;
(void)t;
(void)closed;
// TODO: implement me // TODO: implement me
return nullptr; return nullptr;
} }

View File

@ -3,6 +3,7 @@
#include <constants/link_layer.hpp> #include <constants/link_layer.hpp>
#include <crypto/crypto.hpp> #include <crypto/crypto.hpp>
#include <crypto/encrypted.hpp>
#include <crypto/types.hpp> #include <crypto/types.hpp>
#include <link/server.hpp> #include <link/server.hpp>
#include <link/session.hpp> #include <link/session.hpp>
@ -17,6 +18,117 @@ namespace llarp
{ {
struct LinkLayer; struct LinkLayer;
using FlowID_t = llarp::AlignedBuffer< 32 >;
using OuterCommand_t = byte_t;
constexpr OuterCommand_t eOCMD_ObtainFlowID = 'O';
constexpr OuterCommand_t eOCMD_GiveFlowID = 'G';
constexpr OuterCommand_t eOCMD_Reject = 'R';
constexpr OuterCommand_t eOCMD_SessionNegotiate = 'S';
constexpr OuterCommand_t eOCMD_TransmitData = 'D';
using InnerCommand_t = byte_t;
constexpr InnerCommand_t eICMD_KeepAlive = 'k';
constexpr InnerCommand_t eICMD_KeepAliveAck = 'l';
constexpr InnerCommand_t eICMD_Congestion = 'c';
constexpr InnerCommand_t eICMD_AntiCongestion = 'd';
constexpr InnerCommand_t eICMD_Transmit = 't';
constexpr InnerCommand_t eICMD_Ack = 'a';
constexpr InnerCommand_t eICMD_RotateKeys = 'r';
constexpr InnerCommand_t eICMD_UpgradeProtocol = 'u';
constexpr InnerCommand_t eICMD_VersionUpgrade = 'v';
struct OuterMessage
{
// required memebers
byte_t command;
FlowID_t flow;
// optional memebers follow
NetID netid;
FlowID_t nextFlowID;
std::string rejectReason;
AlignedBuffer< 24 > N;
// TODO: compute optimal size
AlignedBuffer< 1440 > X;
size_t Xsize;
ShortHash Z;
/// encode to buffer
bool
Encode(llarp_buffer_t *buf) const;
/// decode from buffer
bool
Decode(llarp_buffer_t *buf);
/// verify signature if needed
bool
Verify(const SharedSecret &K) const;
/// clear members
void
Clear();
};
/// TODO: fixme
constexpr size_t MaxFrags = 8;
using MessageBuffer_t = AlignedBuffer< MAX_LINK_MSG_SIZE >;
using FragmentLen_t = uint16_t;
using SequenceNum_t = uint32_t;
using WritePacketFunc = std::function< void(const llarp_buffer_t &) >;
struct MessageState
{
/// default
MessageState();
/// inbound
MessageState(const ShortHash &digest, SequenceNum_t num);
/// outbound
MessageState(const ShortHash &digest, const llarp_buffer_t &buf,
SequenceNum_t num);
/// the expected hash of the message
const ShortHash expectedHash;
/// which fragments have we got
std::bitset< MaxFrags > acks;
/// the message buffer
MessageBuffer_t msg;
/// the message's size
FragmentLen_t sz;
/// the last activity we have had
llarp_time_t lastActiveAt;
// sequence number
const SequenceNum_t seqno;
/// return true if this message is to be removed
/// because of inactivity
bool
IsExpired(llarp_time_t now) const;
/// return true if we have recvieved or sent the underlying message in
/// full.
bool
IsDone() const;
/// return true if we should retransmit some packets
bool
ShouldRetransmit(llarp_time_t now) const;
/// transmit unacked fragments
bool
TransmitUnacked(WritePacketFunc write_pkt) const;
/// transmit acks packet
bool
TransmitAcks(WritePacketFunc write_pkt);
};
struct Session final : public llarp::ILinkSession struct Session final : public llarp::ILinkSession
{ {
/// base /// base
@ -35,12 +147,15 @@ namespace llarp
return {}; return {};
} }
/// pump ll io
void void
PumpIO(); PumpIO();
/// tick every 1 s
void void
TickIO(llarp_time_t now); TickIO(llarp_time_t now);
/// queue full message
bool bool
QueueMessageBuffer(const llarp_buffer_t &buf); QueueMessageBuffer(const llarp_buffer_t &buf);
@ -57,6 +172,7 @@ namespace llarp
void void
Close(); Close();
/// start outbound handshake
void void
Connect(); Connect();
@ -105,196 +221,6 @@ namespace llarp
/// maximum fragment size /// maximum fragment size
static constexpr FragLen_t fragsize = MAX_LINK_MSG_SIZE / maxfrags; static constexpr FragLen_t fragsize = MAX_LINK_MSG_SIZE / maxfrags;
struct FragmentHeader
{
/// protocol version, always LLARP_PROTO_VERSION
Proto_t version = LLARP_PROTO_VERSION;
/// fragment command type
Cmd_t cmd = 0;
/// if cmd is XMIT this is the number of additional fragments this
/// message has
/// if cmd is FACK this is the fragment bitfield of the
/// messages acked otherwise 0
Flags_t flags = 0;
/// if cmd is XMIT this is the fragment index
/// if cmd is FACK this is set to 0xff to indicate message drop
/// otherwise set to 0
/// any other cmd it is set to 0
Fragno_t fragno = 0;
/// if cmd is XMIT then this is the size of the current fragment
/// if cmd is FACK then this MUST be set to 0
FragLen_t fraglen = 0;
/// if cmd is XMIT or FACK this is the sequence number of the message
/// otherwise it's 0
Seqno_t seqno = 0;
bool
Decode(llarp_buffer_t *buf)
{
if(buf->size_left() < fragoverhead)
return false;
version = *buf->cur;
if(version != LLARP_PROTO_VERSION)
return false;
buf->cur++;
cmd = *buf->cur;
buf->cur++;
flags = *buf->cur;
buf->cur++;
fragno = *buf->cur;
buf->cur++;
buf->read_uint16(fraglen);
buf->read_uint32(seqno);
return fraglen <= fragsize;
}
bool
Encode(llarp_buffer_t *buf, const llarp_buffer_t &body)
{
if(body.sz > fragsize)
return false;
fraglen = body.sz;
if(buf->size_left() < (fragoverhead + fraglen))
return false;
*buf->cur = LLARP_PROTO_VERSION;
buf->cur++;
*buf->cur = cmd;
buf->cur++;
*buf->cur = flags;
buf->cur++;
*buf->cur = fragno;
buf->cur++;
buf->put_uint16(fraglen);
buf->put_uint32(seqno);
if(fraglen)
memcpy(buf->cur, body.base, fraglen);
buf->cur += fraglen;
return true;
}
};
struct MessageState
{
/// default
MessageState(){};
/// inbound
MessageState(Flags_t numfrags)
{
acks.set();
if(numfrags <= maxfrags)
{
while(numfrags)
acks.reset(maxfrags - (numfrags--));
}
else // invalid value
return;
}
/// outbound
MessageState(const llarp_buffer_t &buf)
{
sz = std::min(buf.sz, MAX_LINK_MSG_SIZE);
memcpy(msg.data(), buf.base, sz);
size_t idx = 0;
acks.set();
while(idx * fragsize < sz)
acks.reset(idx++);
};
/// which fragments have we got
std::bitset< maxfrags > acks;
/// the message buffer
MessageBuffer_t msg;
/// the message's size
FragLen_t sz;
/// the last activity we have had
llarp_time_t lastActiveAt;
/// return true if this message is to be removed
/// because of inactivity
bool
IsExpired(llarp_time_t now) const
{
return now > lastActiveAt && now - lastActiveAt > 2000;
}
bool
IsDone() const
{
return acks.all();
}
bool
ShouldRetransmit(llarp_time_t now) const
{
if(IsDone())
return false;
return now > lastActiveAt && now - lastActiveAt > 500;
}
template < typename write_pkt_func >
bool
TransmitUnacked(write_pkt_func write_pkt, Seqno_t seqno) const
{
static FragLen_t maxfragsize = fragsize;
FragmentHeader hdr;
hdr.seqno = seqno;
hdr.cmd = XMIT;
AlignedBuffer< fragoverhead + fragsize > frag;
llarp_buffer_t buf(frag);
const byte_t *ptr = msg.data();
Fragno_t idx = 0;
FragLen_t len = sz;
while(idx < maxfrags)
{
const FragLen_t l = std::min(len, maxfragsize);
if(!acks.test(idx))
{
hdr.fragno = idx;
hdr.fraglen = l;
if(!hdr.Encode(&buf, llarp_buffer_t(ptr, l)))
return false;
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
len -= l;
if(write_pkt(buf.base, buf.sz) != int(buf.sz))
return false;
}
ptr += l;
len -= l;
if(l >= fragsize)
++idx;
else
break;
}
return true;
}
template < typename write_pkt_func >
bool
TransmitAcks(write_pkt_func write_pkt, Seqno_t seqno)
{
FragmentHeader hdr;
hdr.seqno = seqno;
hdr.cmd = FACK;
hdr.flags = 0;
byte_t idx = 0;
while(idx < maxfrags)
{
if(acks.test(idx))
hdr.flags |= 1 << idx;
++idx;
}
hdr.fraglen = 0;
hdr.fragno = 0;
AlignedBuffer< fragoverhead > frag;
llarp_buffer_t buf(frag);
if(!hdr.Encode(&buf, llarp_buffer_t(nullptr, nullptr, 0)))
return false;
return write_pkt(buf.base, buf.sz) == int(buf.sz);
}
};
using MessageHolder_t = std::unordered_map< Seqno_t, MessageState >; using MessageHolder_t = std::unordered_map< Seqno_t, MessageState >;
MessageHolder_t m_Inbound; MessageHolder_t m_Inbound;
@ -310,11 +236,10 @@ namespace llarp
struct LinkLayer final : public llarp::ILinkLayer struct LinkLayer final : public llarp::ILinkLayer
{ {
LinkLayer(llarp::Crypto *crypto, const SecretKey &encryptionSecretKey, LinkLayer(llarp::Crypto *crypto, const SecretKey &encryptionSecretKey,
const SecretKey &identitySecretKey, llarp::GetRCFunc getrc, llarp::GetRCFunc getrc, llarp::LinkMessageHandler h,
llarp::LinkMessageHandler h, llarp::SignBufferFunc sign,
llarp::SessionEstablishedHandler established, llarp::SessionEstablishedHandler established,
llarp::SessionRenegotiateHandler reneg, llarp::SessionRenegotiateHandler reneg,
llarp::TimeoutHandler timeout, llarp::SignBufferFunc sign, llarp::TimeoutHandler timeout,
llarp::SessionClosedHandler closed); llarp::SessionClosedHandler closed);
~LinkLayer(); ~LinkLayer();
@ -339,36 +264,37 @@ namespace llarp
uint16_t uint16_t
Rank() const override; Rank() const override;
const byte_t * /// verify that a new flow id matches addresses and old flow id
IndentityKey() const bool
{ VerifyFlowID(const FlowID_t &newID, const Addr &from,
return m_IdentityKey.data(); const FlowID_t &oldID) const;
}
const AlignedBuffer< 32 > & void
CookieSec() const RecvFrom(const llarp::Addr &from, const void *buf, size_t sz) override;
{
return m_CookieSec;
}
RouterID
GetRouterID() const
{
return m_IdentityKey.toPublic();
}
private: private:
bool bool
SignBuffer(llarp::Signature &sig, llarp_buffer_t buf) const ShouldSendFlowID(const Addr &from) const;
{
return crypto->sign(sig, m_IdentityKey, buf);
}
const llarp::SecretKey m_IdentityKey;
AlignedBuffer< 32 > m_CookieSec;
/// handle ll recv
void void
RecvFrom(const llarp::Addr &from, const void *buf, size_t sz) override; SendReject(const Addr &to, const FlowID_t &flow, const char *msg);
void
SendFlowID(const Addr &to, const FlowID_t &flow);
using ActiveFlows_t =
std::unordered_map< FlowID_t, RouterID, FlowID_t::Hash >;
ActiveFlows_t m_ActiveFlows;
using PendingFlows_t = std::unordered_map< Addr, FlowID_t, Addr::Hash >;
/// flows that are pending authentication
PendingFlows_t m_PendingFlows;
/// cookie used in flow id computation
AlignedBuffer< 32 > m_FlowCookie;
OuterMessage m_OuterMsg;
}; };
} // namespace iwp } // namespace iwp
} // namespace llarp } // namespace llarp

View File

@ -30,7 +30,9 @@ namespace llarp
using GetRCFunc = std::function< const llarp::RouterContact&(void) >; using GetRCFunc = std::function< const llarp::RouterContact&(void) >;
/// handler of session established /// handler of session established
using SessionEstablishedHandler = std::function< void(llarp::RouterContact) >; /// return false to reject
/// return true to accept
using SessionEstablishedHandler = std::function< bool(ILinkSession*) >;
/// f(new, old) /// f(new, old)
/// handler of session renegotiation /// handler of session renegotiation

View File

@ -777,10 +777,10 @@ namespace llarp
Close(); Close();
return false; return false;
} }
EnterState(eSessionReady);
/// future LIM are used for session renegotiation /// future LIM are used for session renegotiation
GotLIM = std::bind(&Session::GotSessionRenegotiate, this, GotLIM = std::bind(&Session::GotSessionRenegotiate, this,
std::placeholders::_1); std::placeholders::_1);
EnterState(eSessionReady);
return true; return true;
} }
@ -982,7 +982,8 @@ namespace llarp
if(st == eSessionReady) if(st == eSessionReady)
{ {
parent->MapAddr(remoteRC.pubkey.as_array(), this); parent->MapAddr(remoteRC.pubkey.as_array(), this);
parent->SessionEstablished(remoteRC); if(!parent->SessionEstablished(this))
Close();
} }
} }

View File

@ -89,17 +89,18 @@ namespace llarp
record.nextHop = hop.upstream; record.nextHop = hop.upstream;
record.commkey = seckey_topublic(hop.commkey); record.commkey = seckey_topublic(hop.commkey);
auto buf = frame.Buffer(); llarp_buffer_t buf(frame.data(), frame.size());
buf->cur = buf->base + EncryptedFrameOverheadSize; buf.cur = buf.base + EncryptedFrameOverheadSize;
// encode record // encode record
if(!record.BEncode(buf)) if(!record.BEncode(&buf))
{ {
// failed to encode? // failed to encode?
LogError("Failed to generate Commit Record"); LogError("Failed to generate Commit Record");
DumpBuffer(*buf); DumpBuffer(buf);
delete ctx; delete ctx;
return; return;
} }
frame.Resize(buf.cur - buf.base);
// use ephemeral keypair for frame // use ephemeral keypair for frame
SecretKey framekey; SecretKey framekey;
ctx->crypto->encryption_keygen(framekey); ctx->crypto->encryption_keygen(framekey);

View File

@ -47,8 +47,8 @@ namespace llarp
struct AbstractRouter : public util::IStateful struct AbstractRouter : public util::IStateful
{ {
virtual void virtual bool
OnSessionEstablished(RouterContact rc) = 0; OnSessionEstablished(ILinkSession *) = 0;
virtual bool virtual bool
HandleRecvLinkMessageBuffer(ILinkSession *from, HandleRecvLinkMessageBuffer(ILinkSession *from,
@ -121,6 +121,9 @@ namespace llarp
virtual void virtual void
OnConnectTimeout(ILinkSession *session) = 0; OnConnectTimeout(ILinkSession *session) = 0;
/// connect to N random routers
virtual void
ConnectToRandomRouters(int N) = 0;
/// inject configuration and reconfigure router /// inject configuration and reconfigure router
virtual bool virtual bool
Reconfigure(Config *conf) = 0; Reconfigure(Config *conf) = 0;

View File

@ -192,11 +192,10 @@ namespace llarp
return false; return false;
} }
void bool
Router::OnSessionEstablished(RouterContact rc) Router::OnSessionEstablished(ILinkSession * s)
{ {
async_verify_RC(rc, nullptr); return async_verify_RC(s->GetRemoteRC());
LogInfo("session with ", RouterID(rc.pubkey), " established");
} }
Router::Router(struct llarp_threadpool *_tp, struct llarp_ev_loop *__netloop, Router::Router(struct llarp_threadpool *_tp, struct llarp_ev_loop *__netloop,
@ -851,7 +850,7 @@ namespace llarp
{ {
whitelistRouters = IsTrueValue(val); whitelistRouters = IsTrueValue(val);
} }
if(StrEq(key, "jsonrpc")) if(StrEq(key, "jsonrpc") || StrEq(key, "addr"))
{ {
lokidRPCAddr = val; lokidRPCAddr = val;
} }
@ -989,7 +988,8 @@ namespace llarp
return false; return false;
// store it in nodedb async // store it in nodedb async
async_verify_RC(newrc, nullptr); if(!async_verify_RC(newrc))
return false;
// update dht if required // update dht if required
if(dht()->impl->Nodes()->HasNode(dht::Key_t{newrc.pubkey})) if(dht()->impl->Nodes()->HasNode(dht::Key_t{newrc.pubkey}))
{ {
@ -1086,15 +1086,18 @@ namespace llarp
LogError("we have no bootstrap nodes specified"); LogError("we have no bootstrap nodes specified");
} }
if(inboundLinks.size() == 0) if(!IsServiceNode())
{ {
size_t connected = NumberOfConnectedRouters();
if(connected < minConnectedRouters)
{
size_t dlt = minConnectedRouters - connected;
LogInfo("connecting to ", dlt, " random routers to keep alive");
ConnectToRandomRouters(dlt);
}
paths.BuildPaths(now); paths.BuildPaths(now);
_hiddenServiceContext.Tick(now); _hiddenServiceContext.Tick(now);
} }
if(NumberOfConnectedRouters() < minConnectedRouters)
{
ConnectToRandomRouters(minConnectedRouters);
}
_exitContext.Tick(now); _exitContext.Tick(now);
if(rpcCaller) if(rpcCaller)
rpcCaller->Tick(now); rpcCaller->Tick(now);
@ -1222,20 +1225,21 @@ namespace llarp
return false; return false;
} }
void bool
Router::async_verify_RC(const RouterContact &rc, ILinkLayer *link) Router::async_verify_RC(const RouterContact &rc)
{ {
if(pendingVerifyRC.count(rc.pubkey))
return; if(rc.IsPublicRouter() && whitelistRouters && IsServiceNode())
if(rc.IsPublicRouter() && whitelistRouters)
{ {
if(lokinetRouters.find(rc.pubkey) == lokinetRouters.end()) if(lokinetRouters.find(rc.pubkey) == lokinetRouters.end())
{ {
LogInfo(rc.pubkey, " is NOT a valid service node, rejecting"); LogInfo(rc.pubkey, " is NOT a valid service node, rejecting");
link->CloseSessionTo(rc.pubkey); return false;
return;
} }
} }
if(pendingVerifyRC.count(rc.pubkey))
return true;
LogInfo("session with ", RouterID(rc.pubkey), " established");
llarp_async_verify_rc *job = &pendingVerifyRC[rc.pubkey]; llarp_async_verify_rc *job = &pendingVerifyRC[rc.pubkey];
async_verify_context *ctx = new async_verify_context(); async_verify_context *ctx = new async_verify_context();
ctx->router = this; ctx->router = this;
@ -1260,6 +1264,7 @@ namespace llarp
job->hook = &Router::on_verify_client_rc; job->hook = &Router::on_verify_client_rc;
llarp_nodedb_async_verify(job); llarp_nodedb_async_verify(job);
return true;
} }
void void

View File

@ -211,7 +211,7 @@ namespace llarp
uint16_t m_OutboundPort = 0; uint16_t m_OutboundPort = 0;
/// always maintain this many connections to other routers /// always maintain this many connections to other routers
size_t minConnectedRouters = 1; size_t minConnectedRouters = 3;
/// hard upperbound limit on the number of router to router connections /// hard upperbound limit on the number of router to router connections
size_t maxConnectedRouters = 2000; size_t maxConnectedRouters = 2000;
@ -321,8 +321,8 @@ namespace llarp
~Router(); ~Router();
void bool
OnSessionEstablished(RouterContact rc) override; OnSessionEstablished(ILinkSession *) override;
bool bool
HandleRecvLinkMessageBuffer(ILinkSession *from, HandleRecvLinkMessageBuffer(ILinkSession *from,
@ -493,7 +493,7 @@ namespace llarp
const PathID_t &rxid) override; const PathID_t &rxid) override;
void void
ConnectToRandomRouters(int N); ConnectToRandomRouters(int N) override;
size_t size_t
NumberOfConnectedRouters() const override; NumberOfConnectedRouters() const override;
@ -504,8 +504,8 @@ namespace llarp
bool bool
GetRandomConnectedRouter(RouterContact &result) const override; GetRandomConnectedRouter(RouterContact &result) const override;
void bool
async_verify_RC(const RouterContact &rc, ILinkLayer *link); async_verify_RC(const RouterContact &rc);
void void
HandleDHTLookupForSendTo(RouterID remote, HandleDHTLookupForSendTo(RouterID remote,

View File

@ -130,6 +130,12 @@ namespace llarp
&& nickname == other.nickname && last_updated == other.last_updated && nickname == other.nickname && last_updated == other.last_updated
&& netID == other.netID; && netID == other.netID;
} }
bool
operator!=(const RouterContact & other) const
{
return !(*this == other);
}
void void
Clear(); Clear();

View File

@ -1011,9 +1011,6 @@ namespace llarp
p->SetDropHandler(std::bind( p->SetDropHandler(std::bind(
&Endpoint::OutboundContext::HandleDataDrop, this, &Endpoint::OutboundContext::HandleDataDrop, this,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
p->SetDeadChecker(std::bind(&Endpoint::CheckPathIsDead, m_Endpoint,
std::placeholders::_1,
std::placeholders::_2));
} }
void void
@ -1024,10 +1021,15 @@ namespace llarp
} }
bool bool
Endpoint::CheckPathIsDead(__attribute__((unused)) path::Path* p, Endpoint::CheckPathIsDead(path::Path*, llarp_time_t)
__attribute__((unused)) llarp_time_t latency)
{ {
return false; RouterLogic()->call_later(
{100, this, [](void* u, uint64_t, uint64_t left) {
if(left)
return;
HandlePathDead(u);
}});
return true;
} }
bool bool

View File

@ -31,7 +31,7 @@ namespace llarp
{ {
/// minimum interval for publishing introsets /// minimum interval for publishing introsets
static const llarp_time_t INTROSET_PUBLISH_INTERVAL = static const llarp_time_t INTROSET_PUBLISH_INTERVAL =
DEFAULT_PATH_LIFETIME / 4; DEFAULT_PATH_LIFETIME / 8;
static const llarp_time_t INTROSET_PUBLISH_RETRY_INTERVAL = 5000; static const llarp_time_t INTROSET_PUBLISH_RETRY_INTERVAL = 5000;

View File

@ -189,9 +189,9 @@ TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob)
return true; return true;
} }
}, },
[&](llarp::RouterContact rc) { [&](llarp::ILinkSession * s) -> bool {
ASSERT_EQ(rc, Bob.GetRC()); const auto rc = s->GetRemoteRC();
llarp::LogInfo("alice established with bob"); return rc.pubkey == Bob.GetRC().pubkey;
}, },
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; }, [&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
[&](llarp::Signature& sig, const llarp_buffer_t& buf) -> bool { [&](llarp::Signature& sig, const llarp_buffer_t& buf) -> bool {
@ -228,10 +228,11 @@ TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob)
Bob.gotLIM = true; Bob.gotLIM = true;
return sendDiscardMessage(s); return sendDiscardMessage(s);
}, },
[&](llarp::RouterContact rc) { [&](llarp::ILinkSession * s) -> bool {
ASSERT_EQ(rc, Alice.GetRC()); if(s->GetRemoteRC().pubkey != Alice.GetRC().pubkey)
return false;
llarp::LogInfo("bob established with alice"); llarp::LogInfo("bob established with alice");
Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(), return Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(),
sendDiscardMessage); sendDiscardMessage);
}, },
[&](llarp::RouterContact newrc, llarp::RouterContact oldrc) -> bool { [&](llarp::RouterContact newrc, llarp::RouterContact oldrc) -> bool {
@ -252,7 +253,6 @@ TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob)
ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC())); ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC()));
RunMainloop(); RunMainloop();
ASSERT_TRUE(Alice.gotLIM);
ASSERT_TRUE(Bob.gotLIM); ASSERT_TRUE(Bob.gotLIM);
ASSERT_TRUE(success); ASSERT_TRUE(success);
} }
@ -260,6 +260,74 @@ TEST_F(LinkLayerTest, TestUTPAliceRenegWithBob)
TEST_F(LinkLayerTest, TestUTPAliceConnectToBob) TEST_F(LinkLayerTest, TestUTPAliceConnectToBob)
{ {
Alice.link = llarp::utp::NewServer( Alice.link = llarp::utp::NewServer(
&crypto, Alice.encryptionKey,
[&]() -> const llarp::RouterContact& { return Alice.GetRC(); },
[&](llarp::ILinkSession*, const llarp_buffer_t& buf) -> bool {
return AliceGotMessage(buf);
},
[&](llarp::ILinkSession * s) -> bool {
if(s->GetRemoteRC().pubkey != Bob.GetRC().pubkey)
return false;
llarp::LogInfo("alice established with bob");
return true;
},
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
[&](llarp::Signature& sig, const llarp_buffer_t& buf) -> bool {
return crypto.sign(sig, Alice.signingKey, buf);
},
[&](llarp::ILinkSession* session) {
ASSERT_FALSE(session->IsEstablished());
Stop();
},
[&](llarp::RouterID router) { ASSERT_EQ(router, Bob.GetRouterID()); });
Bob.link = llarp::utp::NewServer(
&crypto, Bob.encryptionKey,
[&]() -> const llarp::RouterContact& { return Bob.GetRC(); },
[&](llarp::ILinkSession*, const llarp_buffer_t& ) -> bool {
return true;
},
[&](llarp::ILinkSession * s) -> bool {
if(s->GetRemoteRC().pubkey != Alice.GetRC().pubkey)
return false;
llarp::LogInfo("bob established with alice");
logic->queue_job({s, [](void * u) {
llarp::ILinkSession * self = static_cast<llarp::ILinkSession*>(u);
std::array< byte_t, 32 > tmp;
llarp_buffer_t otherBuf(tmp);
llarp::DiscardMessage discard;
if(!discard.BEncode(&otherBuf))
return;
otherBuf.sz = otherBuf.cur - otherBuf.base;
otherBuf.cur = otherBuf.base;
self->SendMessageBuffer(otherBuf);
}});
return true;
},
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
[&](llarp::Signature& sig, const llarp_buffer_t& buf) -> bool {
return crypto.sign(sig, Bob.signingKey, buf);
},
[&](llarp::ILinkSession* session) {
ASSERT_FALSE(session->IsEstablished());
},
[&](llarp::RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); });
ASSERT_TRUE(Alice.Start(logic.get(), netLoop, AlicePort));
ASSERT_TRUE(Bob.Start(logic.get(), netLoop, BobPort));
ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC()));
RunMainloop();
ASSERT_TRUE(Bob.gotLIM);
ASSERT_TRUE(success);
}
/*
TEST_F(LinkLayerTest, TestIWPAliceConnectToBob)
{
Alice.link = llarp::iwp::NewServer(
&crypto, Alice.encryptionKey, &crypto, Alice.encryptionKey,
[&]() -> const llarp::RouterContact& { return Alice.GetRC(); }, [&]() -> const llarp::RouterContact& { return Alice.GetRC(); },
[&](llarp::ILinkSession* s, const llarp_buffer_t& buf) -> bool { [&](llarp::ILinkSession* s, const llarp_buffer_t& buf) -> bool {
@ -305,7 +373,7 @@ TEST_F(LinkLayerTest, TestUTPAliceConnectToBob)
return s->SendMessageBuffer(otherBuf); return s->SendMessageBuffer(otherBuf);
}; };
Bob.link = llarp::utp::NewServer( Bob.link = llarp::iwp::NewServer(
&crypto, Bob.encryptionKey, &crypto, Bob.encryptionKey,
[&]() -> const llarp::RouterContact& { return Bob.GetRC(); }, [&]() -> const llarp::RouterContact& { return Bob.GetRC(); },
[&](llarp::ILinkSession* s, const llarp_buffer_t& buf) -> bool { [&](llarp::ILinkSession* s, const llarp_buffer_t& buf) -> bool {
@ -342,91 +410,5 @@ TEST_F(LinkLayerTest, TestUTPAliceConnectToBob)
ASSERT_TRUE(Alice.gotLIM); ASSERT_TRUE(Alice.gotLIM);
ASSERT_TRUE(Bob.gotLIM); ASSERT_TRUE(Bob.gotLIM);
ASSERT_TRUE(success); ASSERT_TRUE(success);
} };
*/
TEST_F(LinkLayerTest, TestIWPAliceConnectToBob)
{
/*
Alice.link = llarp::iwp::NewServer(
&crypto, Alice.encryptionKey,
[&]() -> const llarp::RouterContact& { return Alice.GetRC(); },
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
if(Alice.gotLIM)
{
return AliceGotMessage(buf);
}
else
{
llarp::LinkIntroMessage msg;
if(!msg.BDecode(&buf))
return false;
if(!s->GotLIM(&msg))
return false;
Alice.gotLIM = true;
return true;
}
},
[&](llarp::RouterContact rc) {
ASSERT_EQ(rc, Bob.GetRC());
llarp::LogInfo("alice established with bob");
},
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
return crypto.sign(sig, Alice.signingKey, buf);
},
[&](llarp::ILinkSession* session) {
ASSERT_FALSE(session->IsEstablished());
Stop();
},
[&](llarp::RouterID router) { ASSERT_EQ(router, Bob.GetRouterID()); });
auto sendDiscardMessage = [](llarp::ILinkSession* s) -> bool {
// send discard message in reply to complete unit test
byte_t tmp[32] = {0};
auto otherBuf = llarp::StackBuffer< decltype(tmp) >(tmp);
llarp::DiscardMessage discard;
if(!discard.BEncode(&otherBuf))
return false;
otherBuf.sz = otherBuf.cur - otherBuf.base;
otherBuf.cur = otherBuf.base;
return s->SendMessageBuffer(otherBuf);
};
Bob.link = llarp::iwp::NewServer(
&crypto, Bob.encryptionKey,
[&]() -> const llarp::RouterContact& { return Bob.GetRC(); },
[&](llarp::ILinkSession* s, llarp_buffer_t buf) -> bool {
llarp::LinkIntroMessage msg;
if(!msg.BDecode(&buf))
return false;
if(!s->GotLIM(&msg))
return false;
Bob.gotLIM = true;
return true;
},
[&](llarp::RouterContact rc) {
ASSERT_EQ(rc, Alice.GetRC());
llarp::LogInfo("bob established with alice");
Bob.link->VisitSessionByPubkey(Alice.GetRC().pubkey.as_array(),
sendDiscardMessage);
},
[&](llarp::RouterContact, llarp::RouterContact) -> bool { return true; },
[&](llarp::Signature& sig, llarp_buffer_t buf) -> bool {
return crypto.sign(sig, Bob.signingKey, buf);
},
[&](llarp::ILinkSession* session) {
ASSERT_FALSE(session->IsEstablished());
},
[&](llarp::RouterID router) { ASSERT_EQ(router, Alice.GetRouterID()); });
ASSERT_TRUE(Alice.Start(logic.get(), netLoop, AlicePort));
ASSERT_TRUE(Bob.Start(logic.get(), netLoop, BobPort));
ASSERT_TRUE(Alice.link->TryEstablishTo(Bob.GetRC()));
RunMainloop();
ASSERT_TRUE(Alice.gotLIM);
ASSERT_TRUE(Bob.gotLIM);
ASSERT_TRUE(success);
*/
}