You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lokinet/llarp/path/path.cpp

930 lines
25 KiB
C++

#include "path.hpp"
#include <llarp/dht/context.hpp>
#include <llarp/exit/exit_messages.hpp>
#include <llarp/link/link_manager.hpp>
#include <llarp/messages/discard.hpp>
#include <llarp/messages/relay_commit.hpp>
#include <llarp/messages/relay_status.hpp>
#include "pathbuilder.hpp"
#include "transit_hop.hpp"
#include <llarp/nodedb.hpp>
#include <llarp/profiling.hpp>
#include <llarp/router/abstractrouter.hpp>
#include <llarp/routing/path_dht_message.hpp>
#include <llarp/routing/path_latency_message.hpp>
#include <llarp/routing/transfer_traffic_message.hpp>
#include <llarp/util/buffer.hpp>
#include <llarp/tooling/path_event.hpp>
#include <oxenc/endian.h>
#include <deque>
#include <queue>
10 months ago
namespace llarp::path
{
10 months ago
Path::Path(
const std::vector<RouterContact>& h,
std::weak_ptr<PathSet> pathset,
PathRole startingRoles,
std::string shortName)
: m_PathSet{std::move(pathset)}, _role{startingRoles}, m_shortName{std::move(shortName)}
10 months ago
{
hops.resize(h.size());
size_t hsz = h.size();
for (size_t idx = 0; idx < hsz; ++idx)
{
10 months ago
hops[idx].rc = h[idx];
do
{
10 months ago
hops[idx].txID.Randomize();
} while (hops[idx].txID.IsZero());
10 months ago
do
{
10 months ago
hops[idx].rxID.Randomize();
} while (hops[idx].rxID.IsZero());
}
10 months ago
for (size_t idx = 0; idx < hsz - 1; ++idx)
{
10 months ago
hops[idx].txID = hops[idx + 1].rxID;
}
10 months ago
// initialize parts of the introduction
intro.router = hops[hsz - 1].rc.pubkey;
intro.path_id = hops[hsz - 1].txID;
10 months ago
if (auto parent = m_PathSet.lock())
EnterState(ePathBuilding, parent->Now());
}
10 months ago
void
Path::SetBuildResultHook(BuildResultHookFunc func)
{
m_BuiltHook = func;
}
10 months ago
bool
Path::HandleUpstream(const llarp_buffer_t& X, const TunnelNonce& Y, AbstractRouter* r)
{
if (not m_UpstreamReplayFilter.Insert(Y))
return false;
return IHopHandler::HandleUpstream(X, Y, r);
}
10 months ago
bool
Path::HandleDownstream(const llarp_buffer_t& X, const TunnelNonce& Y, AbstractRouter* r)
{
if (not m_DownstreamReplayFilter.Insert(Y))
return false;
return IHopHandler::HandleDownstream(X, Y, r);
}
10 months ago
RouterID
Path::Endpoint() const
{
return hops[hops.size() - 1].rc.pubkey;
}
10 months ago
PubKey
Path::EndpointPubKey() const
{
return hops[hops.size() - 1].rc.pubkey;
}
10 months ago
PathID_t
Path::TXID() const
{
return hops[0].txID;
}
10 months ago
PathID_t
Path::RXID() const
{
return hops[0].rxID;
}
10 months ago
bool
Path::IsReady() const
{
if (Expired(llarp::time_now_ms()))
return false;
return intro.latency > 0s && _status == ePathEstablished;
}
5 years ago
10 months ago
bool
Path::IsEndpoint(const RouterID& r, const PathID_t& id) const
{
return hops[hops.size() - 1].rc.pubkey == r && hops[hops.size() - 1].txID == id;
}
RouterID
Path::Upstream() const
{
return hops[0].rc.pubkey;
}
10 months ago
const std::string&
Path::ShortName() const
{
return m_shortName;
}
std::string
Path::HopsString() const
{
std::string hops_str;
hops_str.reserve(hops.size() * 62); // 52 for the pkey, 6 for .snode, 4 for the ' -> ' joiner
for (const auto& hop : hops)
{
10 months ago
if (!hops.empty())
hops_str += " -> ";
hops_str += RouterID(hop.rc.pubkey).ToString();
}
10 months ago
return hops_str;
}
bool
Path::HandleLRSM(uint64_t status, std::array<EncryptedFrame, 8>& frames, AbstractRouter* r)
{
uint64_t currentStatus = status;
10 months ago
size_t index = 0;
std::optional<RouterID> failedAt;
while (index < hops.size())
{
10 months ago
if (!frames[index].DoDecrypt(hops[index].shared))
{
10 months ago
currentStatus = LR_StatusRecord::FAIL_DECRYPT_ERROR;
failedAt = hops[index].rc.pubkey;
break;
}
10 months ago
llarp::LogDebug("decrypted LRSM frame from ", hops[index].rc.pubkey);
10 months ago
llarp_buffer_t* buf = frames[index].Buffer();
buf->cur = buf->base + EncryptedFrameOverheadSize;
10 months ago
LR_StatusRecord record;
// successful decrypt
if (!record.BDecode(buf))
{
10 months ago
llarp::LogWarn("malformed frame inside LRCM from ", hops[index].rc.pubkey);
currentStatus = LR_StatusRecord::FAIL_MALFORMED_RECORD;
failedAt = hops[index].rc.pubkey;
break;
}
llarp::LogDebug("Decoded LR Status Record from ", hops[index].rc.pubkey);
10 months ago
currentStatus = record.status;
if ((record.status & LR_StatusRecord::SUCCESS) != LR_StatusRecord::SUCCESS)
{
if (record.status & LR_StatusRecord::FAIL_CONGESTION and index == 0)
{
10 months ago
// first hop building too fast
failedAt = hops[index].rc.pubkey;
break;
}
10 months ago
// failed at next hop
if (index + 1 < hops.size())
{
10 months ago
failedAt = hops[index + 1].rc.pubkey;
}
10 months ago
break;
}
10 months ago
++index;
}
10 months ago
if ((currentStatus & LR_StatusRecord::SUCCESS) == LR_StatusRecord::SUCCESS)
{
llarp::LogDebug("LR_Status message processed, path build successful");
r->loop()->call([r, self = shared_from_this()] { self->HandlePathConfirmMessage(r); });
}
else
{
if (failedAt)
{
10 months ago
r->NotifyRouterEvent<tooling::PathBuildRejectedEvent>(Endpoint(), RXID(), *failedAt);
LogWarn(
Name(),
" build failed at ",
*failedAt,
" status=",
LRStatusCodeToString(currentStatus),
" hops=",
HopsString());
r->routerProfiling().MarkHopFail(*failedAt);
}
else
10 months ago
r->routerProfiling().MarkPathFail(this);
llarp::LogDebug("LR_Status message processed, path build failed");
10 months ago
if (currentStatus & LR_StatusRecord::FAIL_TIMEOUT)
{
10 months ago
llarp::LogDebug("Path build failed due to timeout");
}
10 months ago
else if (currentStatus & LR_StatusRecord::FAIL_CONGESTION)
{
10 months ago
llarp::LogDebug("Path build failed due to congestion");
}
10 months ago
else if (currentStatus & LR_StatusRecord::FAIL_DEST_UNKNOWN)
{
10 months ago
llarp::LogDebug(
"Path build failed due to one or more nodes giving destination "
"unknown");
}
10 months ago
else if (currentStatus & LR_StatusRecord::FAIL_DEST_INVALID)
{
10 months ago
llarp::LogDebug(
"Path build failed due to one or more nodes considered an "
"invalid destination");
if (failedAt)
{
10 months ago
r->loop()->call([nodedb = r->nodedb(), router = *failedAt]() {
LogInfo("router ", router, " is deregistered so we remove it");
nodedb->Remove(router);
});
}
}
10 months ago
else if (currentStatus & LR_StatusRecord::FAIL_CANNOT_CONNECT)
5 years ago
{
10 months ago
llarp::LogDebug(
"Path build failed due to a node being unable to connect to the "
"next hop");
5 years ago
}
10 months ago
else if (currentStatus & LR_StatusRecord::FAIL_MALFORMED_RECORD)
{
10 months ago
llarp::LogDebug(
"Path build failed due to a malformed record in the build status "
"message");
}
10 months ago
else if (currentStatus & LR_StatusRecord::FAIL_DECRYPT_ERROR)
{
10 months ago
llarp::LogDebug(
"Path build failed due to a decrypt error in the build status "
"message");
}
10 months ago
else
{
10 months ago
llarp::LogDebug("Path build failed for an unspecified reason");
}
10 months ago
RouterID edge{};
if (failedAt)
edge = *failedAt;
r->loop()->call([r, self = shared_from_this(), edge]() {
self->EnterState(ePathFailed, r->Now());
if (auto parent = self->m_PathSet.lock())
{
parent->HandlePathBuildFailedAt(self, edge);
}
});
}
10 months ago
// TODO: meaningful return value?
return true;
} // namespace path
void
Path::EnterState(PathStatus st, llarp_time_t now)
{
if (st == ePathFailed)
{
10 months ago
_status = st;
return;
}
10 months ago
if (st == ePathExpired && _status == ePathBuilding)
{
10 months ago
_status = st;
if (auto parent = m_PathSet.lock())
{
10 months ago
parent->HandlePathBuildTimeout(shared_from_this());
}
}
10 months ago
else if (st == ePathBuilding)
6 years ago
{
10 months ago
LogInfo("path ", Name(), " is building");
buildStarted = now;
}
10 months ago
else if (st == ePathEstablished && _status == ePathBuilding)
{
10 months ago
LogInfo("path ", Name(), " is built, took ", ToString(now - buildStarted));
}
10 months ago
else if (st == ePathTimeout && _status == ePathEstablished)
{
10 months ago
LogInfo("path ", Name(), " died");
_status = st;
if (auto parent = m_PathSet.lock())
{
10 months ago
parent->HandlePathDied(shared_from_this());
}
}
10 months ago
else if (st == ePathEstablished && _status == ePathTimeout)
{
10 months ago
LogInfo("path ", Name(), " reanimated");
6 years ago
}
10 months ago
else if (st == ePathIgnore)
{
10 months ago
LogInfo("path ", Name(), " ignored");
}
10 months ago
_status = st;
}
6 years ago
10 months ago
util::StatusObject
PathHopConfig::ExtractStatus() const
{
const auto ip = net::In6ToHUInt(rc.addrs[0].ip);
util::StatusObject obj{
{"ip", ip.ToString()},
{"lifetime", to_json(lifetime)},
{"router", rc.pubkey.ToHex()},
{"txid", txID.ToHex()},
{"rxid", rxID.ToHex()}};
return obj;
}
util::StatusObject
Path::ExtractStatus() const
{
auto now = llarp::time_now_ms();
util::StatusObject obj{
{"intro", intro.ExtractStatus()},
{"lastRecvMsg", to_json(m_LastRecvMessage)},
{"lastLatencyTest", to_json(m_LastLatencyTestTime)},
{"buildStarted", to_json(buildStarted)},
{"expired", Expired(now)},
{"expiresSoon", ExpiresSoon(now)},
{"expiresAt", to_json(ExpireTime())},
{"ready", IsReady()},
{"txRateCurrent", m_LastTXRate},
{"rxRateCurrent", m_LastRXRate},
{"replayTX", m_UpstreamReplayFilter.Size()},
{"replayRX", m_DownstreamReplayFilter.Size()},
{"hasExit", SupportsAnyRoles(ePathRoleExit)}};
std::vector<util::StatusObject> hopsObj;
std::transform(
hops.begin(),
hops.end(),
std::back_inserter(hopsObj),
[](const auto& hop) -> util::StatusObject { return hop.ExtractStatus(); });
obj["hops"] = hopsObj;
switch (_status)
{
case ePathBuilding:
obj["status"] = "building";
break;
case ePathEstablished:
obj["status"] = "established";
break;
case ePathTimeout:
obj["status"] = "timeout";
break;
case ePathExpired:
obj["status"] = "expired";
break;
case ePathFailed:
obj["status"] = "failed";
break;
case ePathIgnore:
obj["status"] = "ignored";
break;
default:
obj["status"] = "unknown";
break;
}
return obj;
}
void
Path::Rebuild()
{
if (auto parent = m_PathSet.lock())
{
10 months ago
std::vector<RouterContact> newHops;
for (const auto& hop : hops)
newHops.emplace_back(hop.rc);
LogInfo(Name(), " rebuilding on ", ShortName());
parent->Build(newHops);
}
10 months ago
}
bool
Path::SendLatencyMessage(AbstractRouter* r)
{
const auto now = r->Now();
// send path latency test
routing::PathLatencyMessage latency{};
latency.sent_time = randint();
latency.sequence_number = NextSeqNo();
m_LastLatencyTestID = latency.sent_time;
10 months ago
m_LastLatencyTestTime = now;
LogDebug(Name(), " send latency test id=", latency.sent_time);
10 months ago
if (not SendRoutingMessage(latency, r))
return false;
FlushUpstream(r);
return true;
}
void
Path::Tick(llarp_time_t now, AbstractRouter* r)
{
if (Expired(now))
return;
10 months ago
m_LastRXRate = m_RXRate;
m_LastTXRate = m_TXRate;
m_RXRate = 0;
m_TXRate = 0;
if (_status == ePathBuilding)
{
10 months ago
if (buildStarted == 0s)
return;
if (now >= buildStarted)
{
10 months ago
const auto dlt = now - buildStarted;
if (dlt >= path::build_timeout)
{
10 months ago
LogWarn(Name(), " waited for ", ToString(dlt), " and no path was built");
r->routerProfiling().MarkPathFail(this);
EnterState(ePathExpired, now);
return;
}
}
}
10 months ago
// check to see if this path is dead
if (_status == ePathEstablished)
{
10 months ago
auto dlt = now - m_LastLatencyTestTime;
if (dlt > path::latency_interval && m_LastLatencyTestID == 0)
{
10 months ago
SendLatencyMessage(r);
// latency test FEC
r->loop()->call_later(2s, [self = shared_from_this(), r]() {
if (self->m_LastLatencyTestID)
self->SendLatencyMessage(r);
});
return;
}
10 months ago
dlt = now - m_LastRecvMessage;
if (dlt >= path::alive_timeout)
{
10 months ago
LogWarn(Name(), " waited for ", ToString(dlt), " and path looks dead");
r->routerProfiling().MarkPathFail(this);
EnterState(ePathTimeout, now);
}
}
10 months ago
if (_status == ePathIgnore and now - m_LastRecvMessage >= path::alive_timeout)
{
// clean up this path as we dont use it anymore
EnterState(ePathExpired, now);
}
}
10 months ago
void
Path::HandleAllUpstream(std::vector<RelayUpstreamMessage> msgs, AbstractRouter* r)
{
for (const auto& msg : msgs)
6 years ago
{
10 months ago
if (r->SendToOrQueue(Upstream(), msg))
6 years ago
{
10 months ago
m_TXRate += msg.enc.size();
6 years ago
}
10 months ago
else
6 years ago
{
10 months ago
LogDebug("failed to send upstream to ", Upstream());
6 years ago
}
}
10 months ago
r->TriggerPump();
}
6 years ago
10 months ago
void
Path::UpstreamWork(TrafficQueue_t msgs, AbstractRouter* r)
{
std::vector<RelayUpstreamMessage> sendmsgs(msgs.size());
size_t idx = 0;
for (auto& ev : msgs)
{
10 months ago
const llarp_buffer_t buf(ev.first);
TunnelNonce n = ev.second;
for (const auto& hop : hops)
{
10 months ago
CryptoManager::instance()->xchacha20(buf, hop.shared, n);
n ^= hop.nonceXOR;
}
10 months ago
auto& msg = sendmsgs[idx];
msg.enc = buf;
msg.nonce = ev.second;
msg.pathid = TXID();
++idx;
}
10 months ago
r->loop()->call([self = shared_from_this(), data = std::move(sendmsgs), r]() mutable {
self->HandleAllUpstream(std::move(data), r);
});
}
10 months ago
void
Path::FlushUpstream(AbstractRouter* r)
{
if (not m_UpstreamQueue.empty())
{
10 months ago
r->QueueWork([self = shared_from_this(),
data = std::exchange(m_UpstreamQueue, {}),
r]() mutable { self->UpstreamWork(std::move(data), r); });
}
10 months ago
}
10 months ago
void
Path::FlushDownstream(AbstractRouter* r)
{
if (not m_DownstreamQueue.empty())
{
10 months ago
r->QueueWork([self = shared_from_this(),
data = std::exchange(m_DownstreamQueue, {}),
r]() mutable { self->DownstreamWork(std::move(data), r); });
}
10 months ago
}
10 months ago
/// how long we wait for a path to become active again after it times out
constexpr auto PathReanimationTimeout = 45s;
10 months ago
bool
Path::Expired(llarp_time_t now) const
{
if (_status == ePathFailed)
return true;
if (_status == ePathBuilding)
return false;
10 months ago
if (_status == ePathTimeout)
{
return now >= m_LastRecvMessage + PathReanimationTimeout;
}
10 months ago
if (_status == ePathEstablished or _status == ePathIgnore)
{
10 months ago
return now >= ExpireTime();
}
10 months ago
return true;
}
10 months ago
std::string
Path::Name() const
{
return fmt::format("TX={} RX={}", TXID(), RXID());
}
void
Path::DownstreamWork(TrafficQueue_t msgs, AbstractRouter* r)
{
std::vector<RelayDownstreamMessage> sendMsgs(msgs.size());
size_t idx = 0;
for (auto& ev : msgs)
{
10 months ago
const llarp_buffer_t buf(ev.first);
sendMsgs[idx].nonce = ev.second;
for (const auto& hop : hops)
{
10 months ago
sendMsgs[idx].nonce ^= hop.nonceXOR;
CryptoManager::instance()->xchacha20(buf, hop.shared, sendMsgs[idx].nonce);
}
10 months ago
sendMsgs[idx].enc = buf;
++idx;
}
10 months ago
r->loop()->call([self = shared_from_this(), msgs = std::move(sendMsgs), r]() mutable {
self->HandleAllDownstream(std::move(msgs), r);
});
}
10 months ago
void
Path::HandleAllDownstream(std::vector<RelayDownstreamMessage> msgs, AbstractRouter* r)
{
for (const auto& msg : msgs)
{
10 months ago
const llarp_buffer_t buf{msg.enc};
m_RXRate += buf.sz;
if (HandleRoutingMessage(buf, r))
{
10 months ago
r->TriggerPump();
m_LastRecvMessage = r->Now();
}
}
10 months ago
}
10 months ago
bool
Path::HandleRoutingMessage(const llarp_buffer_t& buf, AbstractRouter* r)
{
if (!r->ParseRoutingMessageBuffer(buf, this, RXID()))
{
10 months ago
LogWarn("Failed to parse inbound routing message");
return false;
}
10 months ago
return true;
}
6 years ago
10 months ago
bool
Path::HandleUpdateExitVerifyMessage(
const routing::UpdateExitVerifyMessage& msg, AbstractRouter* r)
{
(void)r;
if (m_UpdateExitTX && msg.tx_id == m_UpdateExitTX)
{
10 months ago
if (m_ExitUpdated)
return m_ExitUpdated(shared_from_this());
}
if (m_CloseExitTX && msg.tx_id == m_CloseExitTX)
10 months ago
{
if (m_ExitClosed)
return m_ExitClosed(shared_from_this());
}
return false;
}
/** Note: this is one of two places where AbstractRoutingMessage::bt_encode() is called, the
other of which is llarp/path/transit_hop.cpp in TransitHop::SendRoutingMessage(). For now,
we will default to the override of ::bt_encode() that returns an std::string. The role that
llarp_buffer_t plays here is likely superfluous, and can be replaced with either a leaner
llarp_buffer, or just handled using strings.
One important consideration is the frequency at which routing messages are sent, making
superfluous copies important to optimize out here. We have to instantiate at least one
std::string whether we pass a bt_dict_producer as a reference or create one within the
::bt_encode() call.
If we decide to stay with std::strings, the function Path::HandleUpstream (along with the
functions it calls and so on) will need to be modified to take an std::string that we can
std::move around.
*/
10 months ago
bool
Path::SendRoutingMessage(const routing::AbstractRoutingMessage& msg, AbstractRouter* r)
{
std::array<byte_t, MAX_LINK_MSG_SIZE / 2> tmp;
llarp_buffer_t buf(tmp);
// should help prevent bad paths with uninitialized members
// FIXME: Why would we get uninitialized IMessages?
if (msg.version != llarp::constants::proto_version)
return false;
auto bte = msg.bt_encode();
buf.write(bte.begin(), bte.end());
10 months ago
// make nonce
TunnelNonce N;
N.Randomize();
buf.sz = buf.cur - buf.base;
// pad smaller messages
if (buf.sz < pad_size)
{
// randomize padding
CryptoManager::instance()->randbytes(buf.cur, pad_size - buf.sz);
buf.sz = pad_size;
}
buf.cur = buf.base;
LogDebug(
"send routing message ",
msg.sequence_number,
" with ",
buf.sz,
" bytes to endpoint ",
Endpoint());
10 months ago
return HandleUpstream(buf, N, r);
}
bool
Path::HandlePathTransferMessage(
const routing::PathTransferMessage& /*msg*/, AbstractRouter* /*r*/)
{
LogWarn("unwarranted path transfer message on tx=", TXID(), " rx=", RXID());
return false;
}
10 months ago
bool
Path::HandleDataDiscardMessage(const routing::DataDiscardMessage& msg, AbstractRouter* r)
{
MarkActive(r->Now());
if (m_DropHandler)
return m_DropHandler(shared_from_this(), msg.path_id, msg.sequence_number);
10 months ago
return true;
}
bool
Path::HandlePathConfirmMessage(AbstractRouter* r)
{
LogDebug("Path Build Confirm, path: ", ShortName());
const auto now = llarp::time_now_ms();
if (_status == ePathBuilding)
{
10 months ago
// finish initializing introduction
intro.expiry = buildStarted + hops[0].lifetime;
10 months ago
r->routerProfiling().MarkPathSuccess(this);
// persist session with upstream router until the path is done
r->PersistSessionUntil(Upstream(), intro.expiry);
10 months ago
MarkActive(now);
return SendLatencyMessage(r);
}
10 months ago
LogWarn("got unwarranted path confirm message on tx=", RXID(), " rx=", RXID());
return false;
}
10 months ago
bool
Path::HandlePathConfirmMessage(const routing::PathConfirmMessage& /*msg*/, AbstractRouter* r)
{
return HandlePathConfirmMessage(r);
}
bool
Path::HandleHiddenServiceFrame(const service::ProtocolFrameMessage& frame)
10 months ago
{
if (auto parent = m_PathSet.lock())
{
10 months ago
MarkActive(parent->Now());
return m_DataHandler && m_DataHandler(shared_from_this(), frame);
}
10 months ago
return false;
}
10 months ago
template <typename Samples_t>
static llarp_time_t
computeLatency(const Samples_t& samps)
{
llarp_time_t mean = 0s;
if (samps.empty())
return mean;
for (const auto& samp : samps)
mean += samp;
return mean / samps.size();
}
constexpr auto MaxLatencySamples = 8;
bool
Path::HandlePathLatencyMessage(const routing::PathLatencyMessage&, AbstractRouter* r)
{
const auto now = r->Now();
MarkActive(now);
if (m_LastLatencyTestID)
{
10 months ago
m_LatencySamples.emplace_back(now - m_LastLatencyTestTime);
while (m_LatencySamples.size() > MaxLatencySamples)
m_LatencySamples.pop_front();
intro.latency = computeLatency(m_LatencySamples);
m_LastLatencyTestID = 0;
EnterState(ePathEstablished, now);
if (m_BuiltHook)
m_BuiltHook(shared_from_this());
m_BuiltHook = nullptr;
}
10 months ago
return true;
}
10 months ago
/// this is the Client's side of handling a DHT message. it's handled
/// in-place.
bool
Path::HandleDHTMessage(const dht::AbstractDHTMessage& msg, AbstractRouter* r)
{
MarkActive(r->Now());
routing::PathDHTMessage reply;
if (not r->dht()->handle_message(msg, reply.dht_msgs))
return false;
if (reply.dht_msgs.size())
10 months ago
return SendRoutingMessage(reply, r);
return true;
}
10 months ago
bool
Path::HandleCloseExitMessage(const routing::CloseExitMessage& msg, AbstractRouter* /*r*/)
{
/// allows exits to close from their end
if (SupportsAnyRoles(ePathRoleExit | ePathRoleSVC))
{
10 months ago
if (msg.Verify(EndpointPubKey()))
6 years ago
{
10 months ago
LogInfo(Name(), " had its exit closed");
_role &= ~ePathRoleExit;
return true;
6 years ago
}
10 months ago
LogError(Name(), " CXM from exit with bad signature");
}
10 months ago
else
LogError(Name(), " unwarranted CXM");
return false;
}
bool
Path::SendExitRequest(const routing::ObtainExitMessage& msg, AbstractRouter* r)
{
LogInfo(Name(), " sending exit request to ", Endpoint());
m_ExitObtainTX = msg.tx_id;
10 months ago
return SendRoutingMessage(msg, r);
}
10 months ago
bool
Path::SendExitClose(const routing::CloseExitMessage& msg, AbstractRouter* r)
{
LogInfo(Name(), " closing exit to ", Endpoint());
// mark as not exit anymore
_role &= ~ePathRoleExit;
return SendRoutingMessage(msg, r);
}
bool
Path::HandleObtainExitMessage(const routing::ObtainExitMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
LogError(Name(), " got unwarranted OXM");
return false;
}
bool
Path::HandleUpdateExitMessage(const routing::UpdateExitMessage& msg, AbstractRouter* r)
{
(void)msg;
(void)r;
LogError(Name(), " got unwarranted UXM");
return false;
}
bool
Path::HandleRejectExitMessage(const routing::RejectExitMessage& msg, AbstractRouter* r)
{
if (m_ExitObtainTX && msg.tx_id == m_ExitObtainTX)
{
10 months ago
if (!msg.Verify(EndpointPubKey()))
6 years ago
{
10 months ago
LogError(Name(), "RXM invalid signature");
return false;
6 years ago
}
10 months ago
LogInfo(Name(), " ", Endpoint(), " Rejected exit");
MarkActive(r->Now());
return InformExitResult(llarp_time_t(msg.backoff_time));
}
10 months ago
LogError(Name(), " got unwarranted RXM");
return false;
}
10 months ago
bool
Path::HandleGrantExitMessage(const routing::GrantExitMessage& msg, AbstractRouter* r)
{
if (m_ExitObtainTX && msg.tx_id == m_ExitObtainTX)
6 years ago
{
10 months ago
if (!msg.Verify(EndpointPubKey()))
{
LogError(Name(), " GXM signature failed");
return false;
}
// we now can send exit traffic
_role |= ePathRoleExit;
LogInfo(Name(), " ", Endpoint(), " Granted exit");
MarkActive(r->Now());
return InformExitResult(0s);
6 years ago
}
10 months ago
LogError(Name(), " got unwarranted GXM");
return false;
}
6 years ago
10 months ago
bool
Path::InformExitResult(llarp_time_t B)
{
auto self = shared_from_this();
bool result = true;
for (const auto& hook : m_ObtainedExitHooks)
result = hook(self, B) and result;
m_ObtainedExitHooks.clear();
return result;
}
bool
Path::HandleTransferTrafficMessage(const routing::TransferTrafficMessage& msg, AbstractRouter* r)
{
// check if we can handle exit data
if (!SupportsAnyRoles(ePathRoleExit | ePathRoleSVC))
return false;
// handle traffic if we have a handler
if (!m_ExitTrafficHandler)
return false;
bool sent = msg.enc_buf.size() > 0;
10 months ago
auto self = shared_from_this();
for (const auto& pkt : msg.enc_buf)
{
10 months ago
if (pkt.size() <= 8)
continue;
auto counter = oxenc::load_big_to_host<uint64_t>(pkt.data());
if (m_ExitTrafficHandler(
self, llarp_buffer_t(pkt.data() + 8, pkt.size() - 8), counter, msg.protocol))
{
10 months ago
MarkActive(r->Now());
EnterState(ePathEstablished, r->Now());
}
}
10 months ago
return sent;
}
10 months ago
} // namespace llarp::path