lokinet/llarp/path/transit_hop.cpp

492 lines
14 KiB
C++
Raw Normal View History

2019-01-11 01:19:36 +00:00
#include <path/path.hpp>
#include <dht/context.hpp>
#include <exit/context.hpp>
2019-06-15 14:55:14 +00:00
#include <exit/exit_messages.hpp>
#include <link/i_link_manager.hpp>
#include <messages/discard.hpp>
#include <messages/relay_commit.hpp>
#include <messages/relay_status.hpp>
2019-06-17 23:19:39 +00:00
#include <path/path_context.hpp>
#include <path/transit_hop.hpp>
#include <router/abstractrouter.hpp>
2019-06-19 22:30:07 +00:00
#include <routing/path_latency_message.hpp>
#include <routing/path_transfer_message.hpp>
2018-12-12 02:04:32 +00:00
#include <routing/handler.hpp>
#include <util/buffer.hpp>
#include <util/endian.hpp>
2018-06-22 00:25:30 +00:00
namespace llarp
{
namespace path
2018-06-22 00:25:30 +00:00
{
2019-06-17 23:19:39 +00:00
std::ostream&
TransitHopInfo::print(std::ostream& stream, int level, int spaces) const
{
Printer printer(stream, level, spaces);
printer.printAttribute("tx", txID);
printer.printAttribute("rx", rxID);
printer.printAttribute("upstream", upstream);
printer.printAttribute("downstream", downstream);
return stream;
}
TransitHop::TransitHop() : m_UpstreamGather(128), m_DownstreamGather(128)
{
m_UpstreamGather.enable();
m_DownstreamGather.enable();
m_UpstreamWorkCounter = 0;
m_DownstreamWorkCounter = 0;
}
2018-06-26 16:23:43 +00:00
bool
TransitHop::Expired(llarp_time_t now) const
{
return destroy || (now >= ExpireTime());
}
2018-06-22 00:25:30 +00:00
2018-08-22 16:19:51 +00:00
llarp_time_t
TransitHop::ExpireTime() const
{
return started + lifetime;
}
bool
TransitHop::HandleLRSM(uint64_t status,
std::array< EncryptedFrame, 8 >& frames,
AbstractRouter* r)
{
auto msg = std::make_shared< LR_StatusMessage >(frames);
msg->status = status;
msg->pathid = info.rxID;
// TODO: add to IHopHandler some notion of "path status"
const uint64_t ourStatus = LR_StatusRecord::SUCCESS;
if(!msg->AddFrame(pathKey, ourStatus))
{
return false;
}
LR_StatusMessage::QueueSendMessage(r, info.downstream, msg);
if((status & LR_StatusRecord::SUCCESS) == 0)
{
LogDebug(
"TransitHop received non-successful LR_StatusMessage, queueing "
"self-destruct");
QueueDestroySelf(r);
}
return true;
}
TransitHopInfo::TransitHopInfo(const RouterID& down,
const LR_CommitRecord& record)
: txID(record.txid)
, rxID(record.rxid)
, upstream(record.nextHop)
, downstream(down)
{
}
2018-06-22 00:25:30 +00:00
bool
TransitHop::SendRoutingMessage(const routing::IMessage& msg,
AbstractRouter* r)
{
if(!IsEndpoint(r->pubkey()))
return false;
2019-02-02 23:12:42 +00:00
std::array< byte_t, MAX_LINK_MSG_SIZE - 128 > tmp;
llarp_buffer_t buf(tmp);
if(!msg.BEncode(&buf))
{
llarp::LogError("failed to encode routing message");
return false;
}
TunnelNonce N;
N.Randomize();
buf.sz = buf.cur - buf.base;
// pad to nearest MESSAGE_PAD_SIZE bytes
2019-04-05 14:58:22 +00:00
auto dlt = buf.sz % pad_size;
if(dlt)
{
2019-04-05 14:58:22 +00:00
dlt = pad_size - dlt;
// randomize padding
CryptoManager::instance()->randbytes(buf.cur, dlt);
buf.sz += dlt;
}
buf.cur = buf.base;
return HandleDownstream(buf, N, r);
}
2018-06-22 00:25:30 +00:00
2019-09-05 17:39:09 +00:00
void
TransitHop::DownstreamWork(TrafficQueue_ptr msgs, AbstractRouter* r)
{
m_DownstreamWorkCounter++;
auto flushIt = [self = shared_from_this(), r]() {
std::vector< RelayDownstreamMessage > msgs;
do
{
auto maybe = self->m_DownstreamGather.tryPopFront();
if(not maybe.has_value())
break;
msgs.emplace_back(maybe.value());
} while(true);
self->HandleAllDownstream(std::move(msgs), r);
};
for(auto& ev : *msgs)
2019-09-05 17:39:09 +00:00
{
RelayDownstreamMessage msg;
2019-09-05 17:39:09 +00:00
const llarp_buffer_t buf(ev.first);
msg.pathid = info.rxID;
msg.Y = ev.second ^ nonceXOR;
CryptoManager::instance()->xchacha20(buf, pathKey, ev.second);
msg.X = buf;
llarp::LogDebug("relay ", msg.X.size(), " bytes downstream from ",
info.upstream, " to ", info.downstream);
if(m_DownstreamGather.full())
{
LogicCall(r->logic(), flushIt);
}
2019-11-29 00:37:58 +00:00
if(m_DownstreamGather.enabled())
2019-11-29 00:34:31 +00:00
m_DownstreamGather.pushBack(msg);
2019-09-05 17:39:09 +00:00
}
m_DownstreamWorkCounter--;
if(m_DownstreamWorkCounter == 0)
2019-11-28 21:19:50 +00:00
LogicCall(r->logic(), flushIt);
}
2018-06-22 00:25:30 +00:00
2019-09-05 17:39:09 +00:00
void
TransitHop::UpstreamWork(TrafficQueue_ptr msgs, AbstractRouter* r)
2019-09-05 17:39:09 +00:00
{
m_UpstreamWorkCounter++;
auto flushIt = [self = shared_from_this(), r]() {
std::vector< RelayUpstreamMessage > msgs;
do
{
auto maybe = self->m_UpstreamGather.tryPopFront();
if(not maybe.has_value())
break;
msgs.emplace_back(maybe.value());
} while(true);
self->HandleAllUpstream(std::move(msgs), r);
};
for(auto& ev : *msgs)
2019-09-05 17:39:09 +00:00
{
const llarp_buffer_t buf(ev.first);
RelayUpstreamMessage msg;
2019-09-05 17:39:09 +00:00
CryptoManager::instance()->xchacha20(buf, pathKey, ev.second);
msg.pathid = info.txID;
msg.Y = ev.second ^ nonceXOR;
msg.X = buf;
if(m_UpstreamGather.full())
{
LogicCall(r->logic(), flushIt);
}
2019-11-29 00:37:58 +00:00
if(m_UpstreamGather.enabled())
2019-11-29 00:34:31 +00:00
m_UpstreamGather.pushBack(msg);
2019-09-05 17:39:09 +00:00
}
m_UpstreamWorkCounter--;
if(m_UpstreamWorkCounter == 0)
2019-11-28 21:19:50 +00:00
LogicCall(r->logic(), flushIt);
2019-09-05 17:39:09 +00:00
}
void
TransitHop::HandleAllUpstream(std::vector< RelayUpstreamMessage > msgs,
AbstractRouter* r)
{
if(IsEndpoint(r->pubkey()))
2018-06-26 16:23:43 +00:00
{
2019-09-05 17:39:09 +00:00
for(const auto& msg : msgs)
{
const llarp_buffer_t buf(msg.X);
if(!r->ParseRoutingMessageBuffer(buf, this, info.rxID))
{
LogWarn("invalid upstream data on endpoint ", info);
}
2019-09-05 17:39:09 +00:00
m_LastActivity = r->Now();
}
FlushDownstream(r);
2019-11-21 14:34:30 +00:00
for(const auto& other : m_FlushOthers)
{
other->FlushUpstream(r);
}
m_FlushOthers.clear();
2018-06-26 16:23:43 +00:00
}
2019-09-05 17:39:09 +00:00
else
{
for(const auto& msg : msgs)
{
llarp::LogDebug("relay ", msg.X.size(), " bytes upstream from ",
info.downstream, " to ", info.upstream);
r->SendToOrQueue(info.upstream, &msg);
}
}
2020-01-03 12:00:02 +00:00
r->linkManager().PumpLinks();
2019-09-05 17:39:09 +00:00
}
2018-06-26 16:23:43 +00:00
2019-09-05 17:39:09 +00:00
void
TransitHop::HandleAllDownstream(std::vector< RelayDownstreamMessage > msgs,
AbstractRouter* r)
{
for(const auto& msg : msgs)
{
llarp::LogDebug("relay ", msg.X.size(), " bytes downstream from ",
info.upstream, " to ", info.downstream);
2019-09-05 17:39:09 +00:00
r->SendToOrQueue(info.downstream, &msg);
}
2020-01-03 12:00:02 +00:00
r->linkManager().PumpLinks();
2019-09-05 17:39:09 +00:00
}
2019-07-06 17:03:40 +00:00
2019-09-05 17:39:09 +00:00
void
TransitHop::FlushUpstream(AbstractRouter* r)
2019-09-05 17:39:09 +00:00
{
if(m_UpstreamQueue && !m_UpstreamQueue->empty())
2019-09-05 17:39:09 +00:00
r->threadpool()->addJob(std::bind(&TransitHop::UpstreamWork,
shared_from_this(),
std::move(m_UpstreamQueue), r));
m_UpstreamQueue = nullptr;
}
void
TransitHop::FlushDownstream(AbstractRouter* r)
{
if(m_DownstreamQueue && !m_DownstreamQueue->empty())
2019-09-05 17:39:09 +00:00
r->threadpool()->addJob(std::bind(&TransitHop::DownstreamWork,
shared_from_this(),
std::move(m_DownstreamQueue), r));
m_DownstreamQueue = nullptr;
2018-06-26 16:23:43 +00:00
}
bool
TransitHop::HandleDHTMessage(const llarp::dht::IMessage& msg,
AbstractRouter* r)
2018-06-26 16:23:43 +00:00
{
return r->dht()->impl->RelayRequestForPath(info.rxID, msg);
2018-06-26 16:23:43 +00:00
}
bool
TransitHop::HandlePathLatencyMessage(
const llarp::routing::PathLatencyMessage& msg, AbstractRouter* r)
2018-06-26 16:23:43 +00:00
{
llarp::routing::PathLatencyMessage reply;
reply.L = msg.T;
return SendRoutingMessage(reply, r);
}
2018-06-26 16:23:43 +00:00
bool
TransitHop::HandlePathConfirmMessage(
__attribute__((unused)) const llarp::routing::PathConfirmMessage& msg,
__attribute__((unused)) AbstractRouter* r)
2018-06-26 16:23:43 +00:00
{
llarp::LogWarn("unwarranted path confirm message on ", info);
2018-06-26 16:23:43 +00:00
return false;
}
bool
TransitHop::HandleDataDiscardMessage(
__attribute__((unused)) const llarp::routing::DataDiscardMessage& msg,
__attribute__((unused)) AbstractRouter* r)
{
llarp::LogWarn("unwarranted path data discard message on ", info);
return false;
}
bool
TransitHop::HandleObtainExitMessage(
const llarp::routing::ObtainExitMessage& msg, AbstractRouter* r)
{
if(msg.Verify()
&& r->exitContext().ObtainNewExit(msg.I, info.rxID, msg.E != 0))
2018-11-14 12:23:08 +00:00
{
llarp::routing::GrantExitMessage grant;
grant.S = NextSeqNo();
grant.T = msg.T;
if(!grant.Sign(r->identity()))
2018-11-14 21:16:11 +00:00
{
llarp::LogError("Failed to sign grant exit message");
2018-11-14 18:02:27 +00:00
return false;
2018-11-14 21:16:11 +00:00
}
return SendRoutingMessage(grant, r);
2018-11-14 12:23:08 +00:00
}
// TODO: exponential backoff
// TODO: rejected policies
llarp::routing::RejectExitMessage reject;
reject.S = NextSeqNo();
reject.T = msg.T;
if(!reject.Sign(r->identity()))
2018-11-14 21:16:11 +00:00
{
llarp::LogError("Failed to sign reject exit message");
2018-11-14 18:02:27 +00:00
return false;
2018-11-14 21:16:11 +00:00
}
return SendRoutingMessage(reject, r);
}
bool
TransitHop::HandleCloseExitMessage(
const llarp::routing::CloseExitMessage& msg, AbstractRouter* r)
{
2019-05-07 18:27:21 +00:00
const llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
auto ep = r->exitContext().FindEndpointForPath(info.rxID);
if(ep && msg.Verify(ep->PubKey()))
2018-11-14 18:02:27 +00:00
{
llarp::routing::CloseExitMessage reply;
2019-05-07 18:27:21 +00:00
reply.Y = msg.Y;
2018-11-14 18:02:27 +00:00
reply.S = NextSeqNo();
if(reply.Sign(r->identity()))
2019-05-07 18:27:21 +00:00
{
if(SendRoutingMessage(reply, r))
{
ep->Close();
return true;
}
}
2018-11-14 18:02:27 +00:00
}
return SendRoutingMessage(discard, r);
}
bool
2018-11-14 12:23:08 +00:00
TransitHop::HandleUpdateExitVerifyMessage(
const llarp::routing::UpdateExitVerifyMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
2018-11-14 12:23:08 +00:00
llarp::LogError("unwarranted exit verify on ", info);
return false;
}
2018-11-14 12:23:08 +00:00
bool
TransitHop::HandleUpdateExitMessage(
const llarp::routing::UpdateExitMessage& msg, AbstractRouter* r)
2018-11-14 12:23:08 +00:00
{
auto ep = r->exitContext().FindEndpointForPath(msg.P);
2018-11-14 12:23:08 +00:00
if(ep)
{
if(!msg.Verify(ep->PubKey()))
2018-11-14 18:02:27 +00:00
return false;
2018-11-14 21:02:36 +00:00
if(ep->UpdateLocalPath(info.rxID))
2018-11-14 12:23:08 +00:00
{
2018-11-14 18:02:27 +00:00
llarp::routing::UpdateExitVerifyMessage reply;
reply.T = msg.T;
2018-11-14 18:02:27 +00:00
reply.S = NextSeqNo();
return SendRoutingMessage(reply, r);
2018-11-14 12:23:08 +00:00
}
}
// on fail tell message was discarded
llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
return SendRoutingMessage(discard, r);
2018-11-14 12:23:08 +00:00
}
bool
TransitHop::HandleRejectExitMessage(
const llarp::routing::RejectExitMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
llarp::LogError(info, " got unwarranted RXM");
return false;
}
bool
TransitHop::HandleGrantExitMessage(
const llarp::routing::GrantExitMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
llarp::LogError(info, " got unwarranted GXM");
return false;
}
bool
TransitHop::HandleTransferTrafficMessage(
const llarp::routing::TransferTrafficMessage& msg, AbstractRouter* r)
{
auto endpoint = r->exitContext().FindEndpointForPath(info.rxID);
2018-11-15 13:54:53 +00:00
if(endpoint)
2018-11-14 18:02:27 +00:00
{
2018-11-28 17:29:29 +00:00
bool sent = true;
for(const auto& pkt : msg.X)
2018-11-29 21:19:20 +00:00
{
// check short packet buffer
if(pkt.size() <= 8)
continue;
uint64_t counter = bufbe64toh(pkt.data());
sent &= endpoint->QueueOutboundTraffic(
2019-02-03 00:48:10 +00:00
ManagedBuffer(llarp_buffer_t(pkt.data() + 8, pkt.size() - 8)),
2019-02-02 23:12:42 +00:00
counter);
2018-11-29 21:19:20 +00:00
}
2018-11-28 17:29:29 +00:00
return sent;
2018-11-14 18:02:27 +00:00
}
2019-07-06 17:03:40 +00:00
llarp::LogError("No exit endpoint on ", info);
2018-11-14 18:02:27 +00:00
// discarded
llarp::routing::DataDiscardMessage discard(info.rxID, msg.S);
return SendRoutingMessage(discard, r);
}
2018-06-26 16:23:43 +00:00
bool
TransitHop::HandlePathTransferMessage(
const llarp::routing::PathTransferMessage& msg, AbstractRouter* r)
2018-06-26 16:23:43 +00:00
{
auto path = r->pathContext().GetPathForTransfer(msg.P);
llarp::routing::DataDiscardMessage discarded(msg.P, msg.S);
if(path == nullptr || msg.T.F != info.txID)
2018-08-12 17:22:29 +00:00
{
return SendRoutingMessage(discarded, r);
2018-08-12 17:22:29 +00:00
}
2019-02-02 23:12:42 +00:00
std::array< byte_t, service::MAX_PROTOCOL_MESSAGE_SIZE > tmp;
llarp_buffer_t buf(tmp);
if(!msg.T.BEncode(&buf))
2018-08-12 17:22:29 +00:00
{
2018-11-14 18:02:27 +00:00
llarp::LogWarn(info, " failed to transfer data message, encode failed");
return SendRoutingMessage(discarded, r);
2018-08-12 17:22:29 +00:00
}
// rewind
2018-08-12 17:22:29 +00:00
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// send
if(path->HandleDownstream(buf, msg.Y, r))
2019-11-21 14:34:30 +00:00
{
m_FlushOthers.emplace(path);
2018-11-14 18:02:27 +00:00
return true;
2019-11-21 14:34:30 +00:00
}
return SendRoutingMessage(discarded, r);
2018-06-26 16:23:43 +00:00
}
2019-06-17 23:19:39 +00:00
std::ostream&
TransitHop::print(std::ostream& stream, int level, int spaces) const
{
Printer printer(stream, level, spaces);
printer.printAttribute("TransitHop", info);
printer.printAttribute("started", started);
printer.printAttribute("lifetime", lifetime);
return stream;
}
2019-11-29 00:34:31 +00:00
void
TransitHop::Stop()
{
m_UpstreamGather.disable();
m_DownstreamGather.disable();
}
void
TransitHop::SetSelfDestruct()
{
destroy = true;
}
void
TransitHop::QueueDestroySelf(AbstractRouter* r)
{
auto func = std::bind(&TransitHop::SetSelfDestruct, shared_from_this());
LogicCall(r->logic(), func);
}
} // namespace path
2018-06-22 05:44:19 +00:00
} // namespace llarp