lokinet/llarp/relay_commit.cpp

331 lines
9.8 KiB
C++
Raw Normal View History

#include <llarp/bencode.hpp>
2018-06-22 00:25:30 +00:00
#include <llarp/messages/path_confirm.hpp>
2018-06-01 14:08:54 +00:00
#include <llarp/messages/relay_commit.hpp>
2018-06-22 00:25:30 +00:00
#include "buffer.hpp"
2018-06-10 14:05:48 +00:00
#include "logger.hpp"
#include "router.hpp"
2018-06-01 14:08:54 +00:00
namespace llarp
{
LR_CommitMessage::~LR_CommitMessage()
{
}
bool
LR_CommitMessage::DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf)
{
2018-06-11 13:25:10 +00:00
if(llarp_buffer_eq(key, "c"))
{
2018-08-30 18:48:43 +00:00
return BEncodeReadArray(frames, buf);
2018-06-11 13:25:10 +00:00
}
bool read = false;
if(!BEncodeMaybeReadVersion("v", version, LLARP_PROTO_VERSION, read, key,
buf))
return false;
2018-06-11 13:25:10 +00:00
return read;
2018-06-11 13:25:10 +00:00
}
2018-06-01 14:08:54 +00:00
bool
LR_CommitMessage::BEncode(llarp_buffer_t* buf) const
{
2018-06-11 13:25:10 +00:00
if(!bencode_start_dict(buf))
return false;
// msg type
if(!BEncodeWriteDictMsgType(buf, "a", "c"))
2018-06-11 13:25:10 +00:00
return false;
// frames
2018-08-30 18:48:43 +00:00
if(!BEncodeWriteDictArray("c", frames, buf))
return false;
// version
if(!bencode_write_version_entry(buf))
2018-06-11 13:25:10 +00:00
return false;
return bencode_end(buf);
2018-06-01 14:08:54 +00:00
}
bool
LR_CommitMessage::HandleMessage(llarp_router* router) const
{
2018-06-18 22:03:50 +00:00
if(frames.size() != MAXHOPS)
{
2018-07-17 04:37:50 +00:00
llarp::LogError("LRCM invalid number of records, ", frames.size(),
"!=", MAXHOPS);
2018-06-18 22:03:50 +00:00
return false;
}
if(!router->paths.AllowingTransit())
{
2018-09-07 17:41:49 +00:00
llarp::LogError("got LRCM when not permitting transit");
2018-06-18 22:03:50 +00:00
return false;
}
return AsyncDecrypt(&router->paths);
2018-06-10 14:05:48 +00:00
}
bool
LR_CommitRecord::BEncode(llarp_buffer_t* buf) const
{
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictEntry("c", commkey, buf))
return false;
if(!BEncodeWriteDictEntry("i", nextHop, buf))
return false;
if(lifetime > 10 && lifetime < 600)
{
if(!BEncodeWriteDictInt("i", lifetime, buf))
return false;
}
if(!BEncodeWriteDictEntry("n", tunnelNonce, buf))
return false;
2018-06-22 00:25:30 +00:00
if(!BEncodeWriteDictEntry("r", rxid, buf))
return false;
if(!BEncodeWriteDictEntry("t", txid, buf))
return false;
if(!bencode_write_version_entry(buf))
return false;
2018-06-18 22:03:50 +00:00
if(work && !BEncodeWriteDictEntry("w", *work, buf))
return false;
return bencode_end(buf);
2018-06-01 14:08:54 +00:00
}
2018-06-10 14:05:48 +00:00
2018-06-18 22:03:50 +00:00
LR_CommitRecord::~LR_CommitRecord()
{
if(work)
delete work;
}
2018-06-10 14:05:48 +00:00
bool
LR_CommitRecord::OnKey(dict_reader* r, llarp_buffer_t* key)
{
if(!key)
return true;
LR_CommitRecord* self = static_cast< LR_CommitRecord* >(r->user);
bool read = false;
2018-06-10 14:05:48 +00:00
if(!BEncodeMaybeReadDictEntry("c", self->commkey, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("i", self->nextHop, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictInt("l", self->lifetime, read, *key, r->buffer))
return false;
2018-06-21 12:55:02 +00:00
if(!BEncodeMaybeReadDictEntry("n", self->tunnelNonce, read, *key,
r->buffer))
return false;
2018-06-22 00:25:30 +00:00
if(!BEncodeMaybeReadDictEntry("r", self->rxid, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadDictEntry("t", self->txid, read, *key, r->buffer))
return false;
if(!BEncodeMaybeReadVersion("v", self->version, LLARP_PROTO_VERSION, read,
*key, r->buffer))
return false;
2018-06-18 22:03:50 +00:00
if(llarp_buffer_eq(*key, "w"))
{
// check for duplicate
if(self->work)
2018-06-21 12:55:02 +00:00
{
llarp::LogWarn("duplicate POW in LRCR");
2018-06-18 22:03:50 +00:00
return false;
2018-06-21 12:55:02 +00:00
}
2018-06-10 14:05:48 +00:00
self->work = new PoW();
2018-06-18 22:03:50 +00:00
return self->work->BDecode(r->buffer);
}
return read;
2018-06-10 14:05:48 +00:00
}
bool
LR_CommitRecord::BDecode(llarp_buffer_t* buf)
{
dict_reader r;
r.user = this;
r.on_key = &OnKey;
return bencode_read_dict(buf, &r);
}
2018-06-18 22:03:50 +00:00
2018-06-21 12:55:02 +00:00
bool
LR_CommitRecord::operator==(const LR_CommitRecord& other) const
{
if(work && other.work)
{
if(*work != *other.work)
return false;
}
return nextHop == other.nextHop && commkey == other.commkey
2018-06-22 00:25:30 +00:00
&& txid == other.txid && rxid == other.rxid;
2018-06-21 12:55:02 +00:00
}
2018-06-18 22:03:50 +00:00
struct LRCMFrameDecrypt
{
typedef llarp::path::PathContext Context;
typedef llarp::path::TransitHop Hop;
2018-06-18 22:03:50 +00:00
typedef AsyncFrameDecrypter< LRCMFrameDecrypt > Decrypter;
Decrypter* decrypter;
2018-08-30 18:48:43 +00:00
std::array< EncryptedFrame, 8 > frames;
Context* context;
2018-06-18 22:03:50 +00:00
// decrypted record
LR_CommitRecord record;
// the actual hop
2018-10-21 13:07:33 +00:00
std::shared_ptr< Hop > hop;
2018-06-18 22:03:50 +00:00
LRCMFrameDecrypt(Context* ctx, Decrypter* dec,
2018-06-18 22:03:50 +00:00
const LR_CommitMessage* commit)
2018-08-30 18:48:43 +00:00
: decrypter(dec), frames(commit->frames), context(ctx), hop(new Hop())
2018-06-18 22:03:50 +00:00
{
hop->info.downstream = commit->session->GetPubKey();
2018-06-18 22:03:50 +00:00
}
~LRCMFrameDecrypt()
2018-10-29 16:48:36 +00:00
{
2018-06-18 22:03:50 +00:00
delete decrypter;
}
2018-08-23 14:35:29 +00:00
/// this is done from logic thread
2018-06-18 22:03:50 +00:00
static void
SendLRCM(void* user)
{
LRCMFrameDecrypt* self = static_cast< LRCMFrameDecrypt* >(user);
2018-08-23 14:35:29 +00:00
// persist sessions to upstream and downstream routers until the commit
// ends
2018-08-22 16:19:51 +00:00
self->context->Router()->PersistSessionUntil(self->hop->info.downstream,
self->hop->ExpireTime());
self->context->Router()->PersistSessionUntil(self->hop->info.upstream,
self->hop->ExpireTime());
2018-10-21 13:07:33 +00:00
// put hop
self->context->PutTransitHop(self->hop);
2018-08-23 14:35:29 +00:00
// forward to next hop
2018-06-22 00:25:30 +00:00
self->context->ForwardLRCM(self->hop->info.upstream, self->frames);
2018-10-21 14:57:36 +00:00
self->hop = nullptr;
2018-06-18 22:03:50 +00:00
delete self;
}
2018-08-23 14:35:29 +00:00
// this is called from the logic thread
2018-06-18 22:03:50 +00:00
static void
2018-06-22 00:25:30 +00:00
SendPathConfirm(void* user)
2018-06-18 22:03:50 +00:00
{
2018-06-22 00:25:30 +00:00
LRCMFrameDecrypt* self = static_cast< LRCMFrameDecrypt* >(user);
2018-08-23 14:35:29 +00:00
// persist session to downstream until path expiration
self->context->Router()->PersistSessionUntil(self->hop->info.downstream,
self->hop->ExpireTime());
2018-10-21 13:07:33 +00:00
// put hop
self->context->PutTransitHop(self->hop);
2018-08-23 14:35:29 +00:00
// send path confirmation
2018-06-22 00:25:30 +00:00
llarp::routing::PathConfirmMessage confirm(self->hop->lifetime);
if(!self->hop->SendRoutingMessage(&confirm, self->context->Router()))
{
llarp::LogError("failed to send path confirmation for ",
self->hop->info);
2018-06-22 00:25:30 +00:00
}
2018-10-21 14:57:36 +00:00
self->hop = nullptr;
2018-06-22 00:25:30 +00:00
delete self;
2018-06-18 22:03:50 +00:00
}
static void
HandleDecrypted(llarp_buffer_t* buf, LRCMFrameDecrypt* self)
{
2018-10-29 16:48:36 +00:00
auto now = self->context->Router()->Now();
2018-06-22 00:25:30 +00:00
auto& info = self->hop->info;
2018-06-18 22:03:50 +00:00
if(!buf)
{
llarp::LogError("LRCM decrypt failed from ", info.downstream);
2018-06-18 22:03:50 +00:00
delete self;
return;
}
2018-06-21 12:55:02 +00:00
buf->cur = buf->base + EncryptedFrame::OverheadSize;
llarp::LogDebug("decrypted LRCM from ", info.downstream);
2018-06-18 22:03:50 +00:00
// successful decrypt
if(!self->record.BDecode(buf))
{
llarp::LogError("malformed frame inside LRCM from ", info.downstream);
2018-06-18 22:03:50 +00:00
delete self;
return;
}
2018-06-22 00:25:30 +00:00
info.txID = self->record.txid;
info.rxID = self->record.rxid;
2018-06-18 22:03:50 +00:00
info.upstream = self->record.nextHop;
if(self->context->HasTransitHop(info))
{
llarp::LogError("duplicate transit hop ", info);
2018-06-18 22:03:50 +00:00
delete self;
return;
}
// generate path key as we are in a worker thread
auto DH = self->context->Crypto()->dh_server;
2018-06-22 00:25:30 +00:00
if(!DH(self->hop->pathKey, self->record.commkey,
2018-06-18 22:03:50 +00:00
self->context->EncryptionSecretKey(), self->record.tunnelNonce))
{
llarp::LogError("LRCM DH Failed ", info);
2018-06-18 22:03:50 +00:00
delete self;
return;
}
// generate hash of hop key for nonce mutation
self->context->Crypto()->shorthash(self->hop->nonceXOR,
llarp::Buffer(self->hop->pathKey));
2018-06-18 22:03:50 +00:00
if(self->record.work
2018-10-29 16:48:36 +00:00
&& self->record.work->IsValid(self->context->Crypto()->shorthash, now))
2018-06-18 22:03:50 +00:00
{
2018-07-20 04:50:28 +00:00
llarp::LogDebug("LRCM extended lifetime by ",
self->record.work->extendedLifetime, " seconds for ",
info);
2018-06-22 00:25:30 +00:00
self->hop->lifetime += 1000 * self->record.work->extendedLifetime;
2018-06-18 22:03:50 +00:00
}
else if(self->record.lifetime < 600 && self->record.lifetime > 10)
{
self->hop->lifetime = self->record.lifetime;
2018-07-20 04:50:28 +00:00
llarp::LogDebug("LRCM short lifespan set to ", self->hop->lifetime,
" seconds for ", info);
}
2018-06-18 22:03:50 +00:00
// TODO: check if we really want to accept it
2018-10-29 16:48:36 +00:00
self->hop->started = now;
2018-06-18 22:03:50 +00:00
2018-08-30 18:48:43 +00:00
size_t sz = self->frames[0].size();
// shift
std::array< EncryptedFrame, 8 > frames;
frames[0] = self->frames[1];
frames[1] = self->frames[2];
frames[2] = self->frames[3];
frames[3] = self->frames[4];
frames[4] = self->frames[5];
frames[5] = self->frames[6];
frames[6] = self->frames[7];
2018-06-18 22:03:50 +00:00
// put our response on the end
2018-08-30 18:48:43 +00:00
frames[7] = EncryptedFrame(sz - EncryptedFrame::OverheadSize);
2018-06-21 12:55:02 +00:00
// random junk for now
2018-08-30 18:48:43 +00:00
frames[7].Randomize();
self->frames = std::move(frames);
2018-06-18 22:03:50 +00:00
if(self->context->HopIsUs(info.upstream))
{
// we are the farthest hop
2018-07-20 04:50:28 +00:00
llarp::LogDebug("We are the farthest hop for ", info);
2018-06-18 22:03:50 +00:00
// send a LRAM down the path
2018-06-22 00:25:30 +00:00
llarp_logic_queue_job(self->context->Logic(), {self, &SendPathConfirm});
2018-06-18 22:03:50 +00:00
}
else
{
// forward upstream
// we are still in the worker thread so post job to logic
llarp_logic_queue_job(self->context->Logic(), {self, &SendLRCM});
}
}
};
bool
LR_CommitMessage::AsyncDecrypt(llarp::path::PathContext* context) const
2018-06-18 22:03:50 +00:00
{
LRCMFrameDecrypt::Decrypter* decrypter = new LRCMFrameDecrypt::Decrypter(
context->Crypto(), context->EncryptionSecretKey(),
&LRCMFrameDecrypt::HandleDecrypted);
// copy frames so we own them
LRCMFrameDecrypt* frames = new LRCMFrameDecrypt(context, decrypter, this);
// decrypt frames async
2018-08-30 18:48:43 +00:00
decrypter->AsyncDecrypt(context->Worker(), &frames->frames[0], frames);
2018-06-18 22:03:50 +00:00
return true;
}
} // namespace llarp