feedback auth result via lmq rpc

pull/1526/head
Jeff Becker 3 years ago
parent c76f2fe8de
commit 6d5f1b0c6a
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -33,15 +33,27 @@ namespace llarp::rpc
});
}
bool
EndpointAuthRPC::AsyncAuthPending(service::ConvoTag tag) const
{
return m_PendingAuths.count(tag) > 0;
}
void
EndpointAuthRPC::AuthenticateAsync(
std::shared_ptr<llarp::service::ProtocolMessage> msg,
std::function<void(service::AuthResult)> hook)
{
service::ConvoTag tag = msg->tag;
m_PendingAuths.insert(tag);
const auto from = msg->sender.Addr();
auto reply = [logic = m_Endpoint->RouterLogic(), hook](service::AuthResult result) {
logic->Call([hook, result]() { hook(result); });
};
auto reply =
[self = this, tag, logic = m_Endpoint->RouterLogic(), hook](service::AuthResult result) {
logic->Call([self, hook, result, tag]() {
self->m_PendingAuths.erase(tag);
hook(result);
});
};
if (m_AuthWhitelist.count(from))
{
// explicitly whitelisted source

@ -33,6 +33,9 @@ namespace llarp::rpc
std::shared_ptr<llarp::service::ProtocolMessage> msg,
std::function<void(service::AuthResult)> hook) override;
bool
AsyncAuthPending(service::ConvoTag tag) const override;
private:
const std::string m_AuthURL;
const std::string m_AuthMethod;
@ -40,5 +43,6 @@ namespace llarp::rpc
LMQ_ptr m_LMQ;
Endpoint_ptr m_Endpoint;
std::optional<oxenmq::ConnectionID> m_Conn;
std::unordered_set<service::ConvoTag> m_PendingAuths;
};
} // namespace llarp::rpc

@ -6,6 +6,7 @@
#include <net/ip_range.hpp>
#include <net/route.hpp>
#include <service/context.hpp>
#include <service/outbound_context.hpp>
#include <service/auth.hpp>
#include <service/name.hpp>
#include <router/abstractrouter.hpp>
@ -247,20 +248,41 @@ namespace llarp::rpc
{
auto mapExit = [=](service::Address addr) mutable {
ep->MapExitRange(range, addr);
bool shouldSendAuth = false;
if (token.has_value())
{
shouldSendAuth = true;
ep->SetAuthInfoForEndpoint(*exit, service::AuthInfo{*token});
}
ep->EnsurePathToService(
addr,
[reply, ep, r](auto, service::OutboundContext* ctx) {
[reply, ep, r, shouldSendAuth](auto, service::OutboundContext* ctx) {
if (ctx == nullptr)
{
reply(CreateJSONError("could not find exit"));
return;
}
r->routePoker().Up();
reply(CreateJSONResponse("OK"));
auto onGoodResult = [r, ep, reply]() {
r->routePoker().Up();
reply(CreateJSONResponse("OK"));
};
if (not shouldSendAuth)
{
onGoodResult();
return;
}
ctx->AsyncSendAuth(
[onGoodResult, reply](service::AuthResult result) {
if (result != service::AuthResult::eAuthAccepted)
{
reply(CreateJSONError(
"authentication failed: "
+ service::AuthResultDescription(result)));
return;
}
onGoodResult();
});
},
5s);
};

@ -18,6 +18,24 @@ namespace llarp::service
return itr->second;
}
std::string
AuthResultDescription(AuthResult auth)
{
switch (auth)
{
case AuthResult::eAuthAccepted:
return "accepted";
case AuthResult::eAuthRejected:
return "rejected";
case AuthResult::eAuthPaymentRequired:
return "payment required";
case AuthResult::eAuthRateLimit:
return "rate limit hit";
default:
return "unknown";
}
}
AuthType
ParseAuthType(std::string data)
{

@ -23,6 +23,9 @@ namespace llarp::service
eAuthPaymentRequired = 4
};
std::string
AuthResultDescription(AuthResult result);
/// maybe get auth result from string
std::optional<AuthResult>
ParseAuthResult(std::string data);
@ -35,8 +38,11 @@ namespace llarp::service
/// result later
virtual void
AuthenticateAsync(
std::shared_ptr<llarp::service::ProtocolMessage> msg,
std::function<void(AuthResult)> hook) = 0;
std::shared_ptr<ProtocolMessage> msg, std::function<void(AuthResult)> hook) = 0;
/// return true if we are asynchronously processing authentication on this convotag
virtual bool
AsyncAuthPending(ConvoTag tag) const = 0;
};
/// info needed by clients in order to authenticate to a remote endpoint

@ -1054,7 +1054,11 @@ namespace llarp
{
if (m_AuthPolicy)
{
m_AuthPolicy->AuthenticateAsync(std::move(msg), std::move(hook));
if (not m_AuthPolicy->AsyncAuthPending(msg->tag))
{
// do 1 authentication attempt and drop everything else
m_AuthPolicy->AuthenticateAsync(std::move(msg), std::move(hook));
}
}
else
{
@ -1063,21 +1067,52 @@ namespace llarp
}
void
Endpoint::SendAuthReject(
Endpoint::SendAuthResult(
path::Path_ptr path, PathID_t replyPath, ConvoTag tag, AuthResult result)
{
if (result == AuthResult::eAuthAccepted)
// this should not run if we have no auth policy
if (m_AuthPolicy == nullptr)
return;
ProtocolFrame f;
f.R = result;
f.T = tag;
f.F = path->intro.pathID;
if (f.Sign(m_Identity))
if (result == AuthResult::eAuthAccepted)
{
ProtocolMessage msg;
std::array<byte_t, 2> tmp{'d', 'e'};
msg.PutBuffer(tmp);
f.N.Randomize();
f.C.Zero();
msg.proto = eProtocolAuth;
if (not GetReplyIntroFor(tag, msg.introReply))
{
LogError("Failed to send auth reply: no reply intro");
return;
}
msg.sender = m_Identity.pub;
SharedSecret sessionKey{};
if (not GetCachedSessionKeyFor(tag, sessionKey))
{
LogError("failed to send auth reply: no cached session key");
return;
}
if (not f.EncryptAndSign(msg, sessionKey, m_Identity))
{
LogError("Failed to encrypt and sign auth reply");
return;
}
}
else
{
m_SendQueue.tryPushBack(
SendEvent_t{std::make_shared<const routing::PathTransferMessage>(f, replyPath), path});
if (not f.Sign(m_Identity))
{
LogError("failed to sign auth reply result");
return;
}
}
m_SendQueue.tryPushBack(
SendEvent_t{std::make_shared<const routing::PathTransferMessage>(f, replyPath), path});
}
void

@ -263,7 +263,7 @@ namespace llarp
EnsureConvo(const AlignedBuffer<32> addr, bool snode, ConvoEventListener_ptr ev);
bool
SendTo(const ConvoTag tag, const llarp_buffer_t& pkt, ProtocolType t);
SendTo(ConvoTag tag, const llarp_buffer_t& pkt, ProtocolType t);
bool
HandleDataDrop(path::Path_ptr p, const PathID_t& dst, uint64_t s);
@ -390,7 +390,7 @@ namespace llarp
std::shared_ptr<ProtocolMessage> msg, std::function<void(AuthResult)> hook);
void
SendAuthReject(path::Path_ptr path, PathID_t replyPath, ConvoTag tag, AuthResult st);
SendAuthResult(path::Path_ptr path, PathID_t replyPath, ConvoTag tag, AuthResult st);
uint64_t
GenTXID();
@ -480,8 +480,11 @@ namespace llarp
m_StartupLNSMappings;
RecvPacketQueue_t m_InboundTrafficQueue;
public:
SendMessageQueue_t m_SendQueue;
protected:
void
FlushRecvData();

@ -81,4 +81,18 @@ namespace llarp
} // namespace service
} // namespace llarp
namespace std
{
template <>
struct hash<llarp::service::ConvoTag>
{
size_t
operator()(const llarp::service::ConvoTag& tag) const
{
std::hash<std::string_view> h{};
return h(std::string_view{reinterpret_cast<const char*>(tag.data()), tag.size()});
}
};
} // namespace std
#endif

@ -528,7 +528,66 @@ namespace llarp
{
m_LastInboundTraffic = m_Endpoint->Now();
m_GotInboundTraffic = true;
return m_Endpoint->HandleHiddenServiceFrame(p, frame);
if (frame.R)
{
// handle discard
ServiceInfo si;
if (!m_Endpoint->GetSenderFor(frame.T, si))
return false;
// verify source
if (!frame.Verify(si))
return false;
// remove convotag it doesn't exist
LogWarn("remove convotag T=", frame.T);
m_Endpoint->RemoveConvoTag(frame.T);
if (authResultListener)
{
switch (frame.R)
{
case 1:
authResultListener(eAuthRejected);
break;
case 2:
authResultListener(eAuthFailed);
break;
case 3:
authResultListener(eAuthRateLimit);
break;
case 4:
authResultListener(eAuthPaymentRequired);
break;
default:
authResultListener(eAuthFailed);
}
authResultListener = nullptr;
}
return true;
}
std::function<void(std::shared_ptr<ProtocolMessage>)> hook = nullptr;
if (authResultListener)
{
std::function<void(AuthResult)> handler = authResultListener;
authResultListener = nullptr;
hook = [handler](std::shared_ptr<ProtocolMessage>) { handler(AuthResult::eAuthAccepted); };
}
const auto& ident = m_Endpoint->GetIdentity();
if (not frame.AsyncDecryptAndVerify(m_Endpoint->EndpointLogic(), p, ident, m_Endpoint, hook))
{
// send reset convo tag message
ProtocolFrame f;
f.R = 1;
f.T = frame.T;
f.F = p->intro.pathID;
f.Sign(ident);
{
LogWarn("invalidating convotag T=", frame.T);
m_Endpoint->RemoveConvoTag(frame.T);
m_Endpoint->m_SendQueue.tryPushBack(
SendEvent_t{std::make_shared<const routing::PathTransferMessage>(f, frame.F), p});
}
}
return true;
}
void

@ -368,18 +368,13 @@ namespace llarp
AuthResult result) {
if (result == AuthResult::eAuthAccepted)
{
LogInfo("Accepted Convo T=", msg->tag);
handler->PutIntroFor(msg->tag, msg->introReply);
handler->PutReplyIntroFor(msg->tag, fromIntro);
handler->PutSenderFor(msg->tag, msg->sender, true);
handler->PutCachedSessionKeyFor(msg->tag, sharedKey);
ProtocolMessage::ProcessAsync(path, from, msg);
}
else
{
LogInfo("Rejected Convo T=", msg->tag);
handler->SendAuthReject(path, from, msg->tag, result);
}
handler->SendAuthResult(path, from, msg->tag, result);
});
}
};
@ -411,7 +406,8 @@ namespace llarp
std::shared_ptr<Logic> logic,
path::Path_ptr recvPath,
const Identity& localIdent,
Endpoint* handler) const
Endpoint* handler,
std::function<void(std::shared_ptr<ProtocolMessage>)> hook) const
{
auto msg = std::make_shared<ProtocolMessage>();
msg->handler = handler;
@ -440,23 +436,31 @@ namespace llarp
return false;
}
v->frame = *this;
handler->Router()->QueueWork([v, msg = std::move(msg), recvPath = std::move(recvPath)]() {
if (not v->frame.Verify(v->si))
{
LogError("Signature failure from ", v->si.Addr());
return;
}
if (not v->frame.DecryptPayloadInto(v->shared, *msg))
auto callback = [logic, hook](std::shared_ptr<ProtocolMessage> msg) {
if (hook)
{
LogError("failed to decrypt message");
return;
LogicCall(logic, [msg, hook]() { hook(msg); });
}
RecvDataEvent ev;
ev.fromPath = std::move(recvPath);
ev.pathid = v->frame.F;
ev.msg = std::move(msg);
msg->handler->QueueRecvData(std::move(ev));
});
};
handler->Router()->QueueWork(
[v, msg = std::move(msg), recvPath = std::move(recvPath), callback]() {
if (not v->frame.Verify(v->si))
{
LogError("Signature failure from ", v->si.Addr());
return;
}
if (not v->frame.DecryptPayloadInto(v->shared, *msg))
{
LogError("failed to decrypt message");
return;
}
callback(msg);
RecvDataEvent ev;
ev.fromPath = std::move(recvPath);
ev.pathid = v->frame.F;
ev.msg = std::move(msg);
msg->handler->QueueRecvData(std::move(ev));
});
return true;
}

@ -130,7 +130,8 @@ namespace llarp
std::shared_ptr<Logic> logic,
path::Path_ptr fromPath,
const Identity& localIdent,
Endpoint* handler) const;
Endpoint* handler,
std::function<void(std::shared_ptr<ProtocolMessage>)> hook = nullptr) const;
bool
DecryptPayloadInto(const SharedSecret& sharedkey, ProtocolMessage& into) const;

@ -108,6 +108,21 @@ namespace llarp
});
}
void
SendContext::AsyncSendAuth(std::function<void(AuthResult)> resultHandler)
{
const auto maybe = m_Endpoint->MaybeGetAuthInfoForEndpoint(remoteIdent.Addr());
if (maybe.has_value())
{
// send auth message
const llarp_buffer_t authdata(maybe->token);
AsyncGenIntro(authdata, eProtocolAuth);
authResultListener = resultHandler;
}
else
resultHandler(AuthResult::eAuthFailed);
}
void
SendContext::AsyncEncryptAndSendTo(const llarp_buffer_t& data, ProtocolType protocol)
{

@ -52,6 +52,8 @@ namespace llarp
using SendEvent_t = std::pair<Msg_ptr, path::Path_ptr>;
thread::Queue<SendEvent_t> m_SendQueue;
std::function<void(AuthResult)> authResultListener;
virtual bool
ShiftIntroduction(bool rebuild = true)
{
@ -65,6 +67,9 @@ namespace llarp
virtual bool
MarkCurrentIntroBad(llarp_time_t now) = 0;
void
AsyncSendAuth(std::function<void(AuthResult)> replyHandler);
private:
void
EncryptAndSendTo(const llarp_buffer_t& payload, ProtocolType t);

@ -7,10 +7,6 @@
#include <sodium/crypto_generichash.h>
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
namespace llarp
{
namespace service

Loading…
Cancel
Save