more ip endpoint fixes

spam dht with lookups less
pull/15/head
Jeff Becker 6 years ago
parent ffdff3e09c
commit 354df88367
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -154,6 +154,12 @@ namespace llarp
return true;
}
bool
HasRouterLookup(const RouterID& target) const
{
return pendingRouterLookups.HasLookupFor(target);
}
/// on behalf of whoasked request introsets with tag from dht router with
/// key askpeer with Recursion depth R
void
@ -264,6 +270,12 @@ namespace llarp
return itr->second.get();
}
bool
HasLookupFor(const K& target) const
{
return timeouts.find(target) != timeouts.end();
}
bool
HasPendingLookupFrom(const TXOwner& owner) const
{

@ -46,7 +46,7 @@ namespace llarp
/// overrides Endpoint
/// handle inbound traffic
void
HandleDataMessage(service::ProtocolMessage* msg);
HandleDataMessage(const PathID_t& src, service::ProtocolMessage* msg);
#ifndef _MINGW32_NO_THREADS
/// overrides Endpount

@ -11,6 +11,9 @@ namespace llarp
{
namespace service
{
// foward declare
struct AsyncKeyExchange;
struct Endpoint : public path::Builder,
public ILookupHolder,
public IDataHandler
@ -73,6 +76,9 @@ namespace llarp
bool
ShouldPublishDescriptors(llarp_time_t now) const;
void
EnsureReplyPath(const ServiceInfo& addr);
bool
PublishIntroSet(llarp_router* r);
@ -100,7 +106,7 @@ namespace llarp
ForgetPathToService(const Address& remote);
virtual void
HandleDataMessage(ProtocolMessage* msg)
HandleDataMessage(const PathID_t&, ProtocolMessage* msg)
{
// override me in subclass
}
@ -151,8 +157,46 @@ namespace llarp
typedef std::queue< PendingBuffer > PendingBufferQueue;
struct SendContext
{
SendContext(const ServiceInfo& ident, const Introduction& intro,
PathSet* send, Endpoint* ep);
void
AsyncEncryptAndSendTo(PathID_t pid, llarp_buffer_t payload,
ProtocolType t);
/// send a fully encrypted hidden service frame
/// via a path on our pathset with path id p
void
Send(PathID_t p, ProtocolFrame& f);
llarp::SharedSecret sharedKey;
ServiceInfo remoteIdent;
Introduction remoteIntro;
PathSet* m_PathSet;
IDataHandler* m_DataHandler;
Endpoint* m_Endpoint;
uint64_t sequenceNo = 0;
virtual void
ShiftIntroduction(){};
virtual void
UpdateIntroSet(){};
private:
void
EncryptAndSendTo(const PathID_t& p, llarp_buffer_t payload,
ProtocolType t);
virtual void
AsyncGenIntro(PathID_t p, llarp_buffer_t payload, ProtocolType t)
{
}
};
/// context needed to initiate an outbound hidden service session
struct OutboundContext : public path::Builder
struct OutboundContext : public path::Builder, public SendContext
{
OutboundContext(const IntroSet& introSet, Endpoint* parent);
~OutboundContext();
@ -160,10 +204,6 @@ namespace llarp
bool
HandleDataDrop(path::Path* p, const PathID_t& dst, uint64_t s);
/// the remote hidden service's curren intro set
IntroSet currentIntroSet;
/// the current selected intro
Introduction selectedIntro;
/// set to true if we are updating the remote introset right now
bool updatingIntroSet;
@ -178,7 +218,14 @@ namespace llarp
/// encrypt asynchronously and send to remote endpoint from us
void
AsyncEncryptAndSendTo(llarp_buffer_t D, ProtocolType protocol);
AsyncEncryptAndSendTo(llarp_buffer_t D, ProtocolType protocol)
{
auto path = m_PathSet->GetPathByRouter(remoteIntro.router);
if(path)
SendContext::AsyncEncryptAndSendTo(path->RXID(), D, protocol);
}
void
AsyncGenIntro(PathID_t p, llarp_buffer_t payload, ProtocolType t);
/// issues a lookup to find the current intro set of the remote service
void
@ -198,23 +245,14 @@ namespace llarp
Name() const;
private:
bool
OnIntroSetUpdate(const Address& addr, const IntroSet* i);
void
EncryptAndSendTo(path::Path* p, llarp_buffer_t payload, ProtocolType t);
void
AsyncGenIntro(path::Path* p, llarp_buffer_t payload, ProtocolType t);
OnGeneratedIntroFrame(AsyncKeyExchange* k, PathID_t p);
/// send a fully encrypted hidden service frame
void
Send(ProtocolFrame& f);
bool
OnIntroSetUpdate(const Address& addr, const IntroSet* i);
uint64_t sequenceNo = 0;
llarp::SharedSecret sharedKey;
Endpoint* m_Parent;
uint64_t m_UpdateIntrosetTX = 0;
IntroSet currentIntroSet;
};
// passed a sendto context when we have a path established otherwise
@ -333,6 +371,10 @@ namespace llarp
std::unordered_map< Address, std::unique_ptr< OutboundContext >,
Address::Hash >
m_RemoteSessions;
std::unordered_map< Address, ServiceInfo, Address::Hash >
m_AddressToService;
std::unordered_map< Address, PathEnsureHook, Address::Hash >
m_PendingServiceLookups;

@ -3,6 +3,8 @@
#include <llarp/aligned.hpp>
#include <llarp/crypto.hpp>
#include <llarp/service/IntroSet.hpp>
#include <llarp/path_types.hpp>
namespace llarp
{
namespace service
@ -13,7 +15,7 @@ namespace llarp
struct IDataHandler
{
virtual void
HandleDataMessage(ProtocolMessage* msg) = 0;
HandleDataMessage(const PathID_t&, ProtocolMessage* msg) = 0;
virtual bool
GetCachedSessionKeyFor(const ConvoTag& remote,
@ -41,4 +43,4 @@ namespace llarp
} // namespace service
} // namespace llarp
#endif
#endif

@ -34,6 +34,8 @@ namespace llarp
Introduction introReply;
ServiceInfo sender;
IDataHandler* handler = nullptr;
/// local path we got this message from
PathID_t srcPath;
ConvoTag tag;
bool

@ -197,10 +197,14 @@ namespace llarp
}
void
TunEndpoint::HandleDataMessage(service::ProtocolMessage *msg)
TunEndpoint::HandleDataMessage(const PathID_t &src,
service::ProtocolMessage *msg)
{
llarp::LogInfo(Name(), " handle data message ", msg->payload.size(),
" bytes");
EnsureReplyPath(msg->sender);
uint32_t themIP = ObtainIPForAddr(msg->sender.Addr());
uint32_t usIP = m_OurIP;
auto buf = llarp::Buffer(msg->payload);

@ -38,7 +38,7 @@ namespace llarp
while(count > 1)
{
sum += ntohs(*(uint16_t *)addr);
sum += *(uint16_t *)addr;
count -= sizeof(uint16_t);
addr += sizeof(uint16_t);
}
@ -48,7 +48,7 @@ namespace llarp
while(sum >> 16)
sum = (sum & 0xffff) + (sum >> 16);
hdr->check = htons(~sum);
hdr->check = ~sum;
}
} // namespace net

@ -369,11 +369,13 @@ llarp_router::TryEstablishTo(const llarp::RouterID &remote)
}
else if(!routerProfiling.IsBad(remote))
{
if(dht->impl.HasRouterLookup(remote))
return;
llarp::LogInfo("looking up router ", remote);
// dht lookup as we don't know it
dht->impl.LookupRouter(
remote,
std::bind(&llarp_router::HandleDHTLookupForTryEstablishTo, this,
std::bind(&llarp_router::HandleDHTLookupForTryEstablishTo, this, remote,
std::placeholders::_1));
}
}
@ -388,8 +390,12 @@ llarp_router::OnConnectTimeout(const llarp::RouterID &remote)
void
llarp_router::HandleDHTLookupForTryEstablishTo(
const std::vector< llarp::RouterContact > &results)
llarp::RouterID remote, const std::vector< llarp::RouterContact > &results)
{
if(results.size() == 0)
{
OnConnectTimeout(remote);
}
for(const auto &result : results)
{
llarp_nodedb_put_rc(nodedb, result);

@ -246,6 +246,7 @@ struct llarp_router
void
HandleDHTLookupForTryEstablishTo(
llarp::RouterID remote,
const std::vector< llarp::RouterContact > &results);
static void

@ -675,7 +675,7 @@ namespace llarp
llarp::LogWarn(Name(), " message ", seq, " dropped by endpoint ",
p->Endpoint(), " via ", dst);
// pick another intro
if(selectedIntro.router == p->Endpoint() && selectedIntro.pathID == dst)
if(remoteIntro.router == p->Endpoint() && remoteIntro.pathID == dst)
{
auto now = llarp_time_now_ms();
for(const auto& intro : currentIntroSet.I)
@ -684,8 +684,8 @@ namespace llarp
continue;
if(intro.pathID != dst)
{
bool shift = selectedIntro.router != intro.router;
selectedIntro = intro;
bool shift = remoteIntro.router != intro.router;
remoteIntro = intro;
if(shift)
ManualRebuild(1);
return true;
@ -703,6 +703,17 @@ namespace llarp
m_Identity, m_DataHandler);
}
Endpoint::SendContext::SendContext(const ServiceInfo& ident,
const Introduction& intro, PathSet* send,
Endpoint* ep)
: remoteIdent(ident)
, remoteIntro(intro)
, m_PathSet(send)
, m_DataHandler(ep)
, m_Endpoint(ep)
{
}
void
Endpoint::OutboundContext::HandlePathBuilt(path::Path* p)
{
@ -712,7 +723,7 @@ namespace llarp
p->SetDropHandler(std::bind(
&Endpoint::OutboundContext::HandleDataDrop, this,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
p->SetDeadChecker(std::bind(&Endpoint::CheckPathIsDead, m_Parent,
p->SetDeadChecker(std::bind(&Endpoint::CheckPathIsDead, m_Endpoint,
std::placeholders::_1,
std::placeholders::_2));
}
@ -727,7 +738,7 @@ namespace llarp
Endpoint::OutboundContext::HandleHiddenServiceFrame(
const ProtocolFrame* frame)
{
return m_Parent->HandleHiddenServiceFrame(frame);
return m_Endpoint->HandleHiddenServiceFrame(frame);
}
bool
@ -792,12 +803,11 @@ namespace llarp
Endpoint::OutboundContext::OutboundContext(const IntroSet& intro,
Endpoint* parent)
: path::Builder(parent->m_Router, parent->m_Router->dht, 2, 4)
, SendContext(intro.A, {}, this, parent)
, currentIntroSet(intro)
, m_Parent(parent)
{
updatingIntroSet = false;
selectedIntro.Clear();
ShiftIntroduction();
}
@ -822,6 +832,57 @@ namespace llarp
Endpoint::SendToOrQueue(const Address& remote, llarp_buffer_t data,
ProtocolType t)
{
{
auto itr = m_AddressToService.find(remote);
if(itr != m_AddressToService.end())
{
ProtocolFrame f;
path::Path* p = nullptr;
std::set< ConvoTag > tags;
if(!GetConvoTagsForService(itr->second, tags))
{
llarp::LogError("no convo tag");
return false;
}
Introduction intro;
const byte_t* K = nullptr;
for(const auto& tag : tags)
{
if(p == nullptr && GetIntroFor(tag, intro))
{
p = GetPathByRouter(intro.router);
if(p)
{
f.T = tag;
if(!GetCachedSessionKeyFor(tag, K))
{
llarp::LogError("no cached session key");
return false;
}
}
}
}
if(p == nullptr)
{
llarp::LogError("no path found");
return false;
}
ProtocolMessage m(f.T);
m.PutBuffer(data);
m.proto = t;
m.introReply = p->intro;
m.sender = m_Identity.pub;
f.N.Randomize();
f.C.Zero();
if(!f.EncryptAndSign(&Router()->crypto, m, K, m_Identity))
{
llarp::LogError("failed to encrypt and sign");
return false;
}
routing::PathTransferMessage transfer(f, intro.pathID);
return p->SendRoutingMessage(&transfer, Router());
}
}
if(HasPathToService(remote))
{
m_RemoteSessions[remote]->AsyncEncryptAndSendTo(data, t);
@ -868,14 +929,11 @@ namespace llarp
auto now = llarp_time_t();
for(const auto& intro : currentIntroSet.I)
{
m_Parent->EnsureRouterIsKnown(selectedIntro.router);
// check for stale intro
if(intro.expiresAt < now)
continue;
if(selectedIntro.expiresAt < intro.expiresAt)
m_Endpoint->EnsureRouterIsKnown(remoteIntro.router);
if(remoteIntro.expiresAt < intro.expiresAt)
{
selectedIntro = intro;
shifted = true;
remoteIntro = intro;
shifted = true;
}
}
if(shifted)
@ -883,36 +941,25 @@ namespace llarp
}
void
Endpoint::OutboundContext::AsyncEncryptAndSendTo(llarp_buffer_t data,
ProtocolType protocol)
Endpoint::SendContext::AsyncEncryptAndSendTo(PathID_t path,
llarp_buffer_t data,
ProtocolType protocol)
{
auto path = GetPathByRouter(selectedIntro.router);
if(!path)
{
llarp::LogError(Name(), " No Path to ", selectedIntro.router, " yet");
if(selectedIntro.ExpiresSoon(llarp_time_now_ms()))
{
ShiftIntroduction();
}
return;
}
if(sequenceNo)
{
llarp::LogInfo(Name(), " send packet ", sequenceNo);
EncryptAndSendTo(path, data, protocol);
}
else
{
llarp::LogInfo(Name(), " generate intro");
AsyncGenIntro(path, data, protocol);
}
}
struct AsyncIntroGen
struct AsyncKeyExchange
{
llarp_logic* logic;
llarp_crypto* crypto;
byte_t* sharedKey;
SharedSecret sharedKey;
ServiceInfo remote;
const Identity& m_LocalIdentity;
ProtocolMessage msg;
@ -922,13 +969,12 @@ namespace llarp
std::function< void(ProtocolFrame&) > hook;
IDataHandler* handler;
AsyncIntroGen(llarp_logic* l, llarp_crypto* c, byte_t* key,
const ServiceInfo& r, const Identity& localident,
const PQPubKey& introsetPubKey, const Introduction& us,
IDataHandler* h)
AsyncKeyExchange(llarp_logic* l, llarp_crypto* c, const ServiceInfo& r,
const Identity& localident,
const PQPubKey& introsetPubKey, const Introduction& us,
IDataHandler* h)
: logic(l)
, crypto(c)
, sharedKey(key)
, remote(r)
, m_LocalIdentity(localident)
, intro(us)
@ -940,7 +986,7 @@ namespace llarp
static void
Result(void* user)
{
AsyncIntroGen* self = static_cast< AsyncIntroGen* >(user);
AsyncKeyExchange* self = static_cast< AsyncKeyExchange* >(user);
// put values
self->handler->PutCachedSessionKeyFor(self->msg.tag, self->sharedKey);
self->handler->PutIntroFor(self->msg.tag, self->msg.introReply);
@ -949,10 +995,11 @@ namespace llarp
delete self;
}
/// given protocol message make protocol frame
static void
Work(void* user)
Encrypt(void* user)
{
AsyncIntroGen* self = static_cast< AsyncIntroGen* >(user);
AsyncKeyExchange* self = static_cast< AsyncKeyExchange* >(user);
// derive ntru session key component
SharedSecret K;
self->crypto->pqe_encrypt(self->frame.C, K, self->introPubKey);
@ -988,56 +1035,55 @@ namespace llarp
};
void
Endpoint::OutboundContext::AsyncGenIntro(path::Path* p,
llarp_buffer_t payload,
Endpoint::EnsureReplyPath(const ServiceInfo& ident)
{
auto itr = m_AddressToService.find(ident.Addr());
if(itr == m_AddressToService.end())
m_AddressToService.insert(std::make_pair(ident.Addr(), ident));
}
void
Endpoint::OutboundContext::AsyncGenIntro(PathID_t p, llarp_buffer_t payload,
ProtocolType t)
{
AsyncIntroGen* ex = new AsyncIntroGen(
m_Parent->RouterLogic(), m_Parent->Crypto(), sharedKey,
currentIntroSet.A, m_Parent->GetIdentity(), currentIntroSet.K,
selectedIntro, m_Parent->m_DataHandler);
ex->hook = std::bind(&Endpoint::OutboundContext::Send, this,
auto path = m_PathSet->GetPathByID(p);
if(path == nullptr)
return;
AsyncKeyExchange* ex =
new AsyncKeyExchange(m_Endpoint->RouterLogic(), m_Endpoint->Crypto(),
remoteIdent, m_Endpoint->GetIdentity(),
currentIntroSet.K, remoteIntro, m_DataHandler);
ex->hook = std::bind(&Endpoint::OutboundContext::Send, this, p,
std::placeholders::_1);
ex->msg.PutBuffer(payload);
ex->msg.introReply = p->intro;
llarp_threadpool_queue_job(m_Parent->Worker(),
{ex, &AsyncIntroGen::Work});
ex->msg.introReply = path->intro;
llarp_threadpool_queue_job(m_Endpoint->Worker(),
{ex, &AsyncKeyExchange::Encrypt});
}
void
Endpoint::OutboundContext::Send(ProtocolFrame& msg)
Endpoint::SendContext::Send(PathID_t p, ProtocolFrame& msg)
{
// in this context we assume the message contents are encrypted
auto now = llarp_time_now_ms();
if(currentIntroSet.HasExpiredIntros(now))
{
UpdateIntroSet();
}
if(selectedIntro.ExpiresSoon(now, 10000))
if(remoteIntro.ExpiresSoon(now, 10000))
{
ShiftIntroduction();
}
// XXX: this may be a different path that that was put into the protocol
// message inside the protocol frame
auto path = GetPathByRouter(selectedIntro.router);
auto path = m_PathSet->GetPathByID(p);
if(path)
{
routing::PathTransferMessage transfer(msg, selectedIntro.pathID);
llarp::LogInfo("sending frame via ", selectedIntro.pathID, " to ",
path->Endpoint(), " for ", Name());
if(!path->SendRoutingMessage(&transfer, m_Parent->Router()))
routing::PathTransferMessage transfer(msg, remoteIntro.pathID);
if(!path->SendRoutingMessage(&transfer, m_Endpoint->Router()))
llarp::LogError("Failed to send frame on path");
}
else
{
llarp::LogWarn("No path to ", selectedIntro.router);
}
}
std::string
Endpoint::OutboundContext::Name() const
{
return "OBContext:" + m_Parent->Name() + "-"
return "OBContext:" + m_Endpoint->Name() + "-"
+ currentIntroSet.A.Addr().ToString();
}
@ -1047,16 +1093,16 @@ namespace llarp
if(updatingIntroSet)
return;
auto addr = currentIntroSet.A.Addr();
auto path = m_Parent->PickRandomEstablishedPath();
auto path = m_Endpoint->PickRandomEstablishedPath();
if(path)
{
HiddenServiceAddressLookup* job = new HiddenServiceAddressLookup(
m_Parent,
m_Endpoint,
std::bind(&Endpoint::OutboundContext::OnIntroSetUpdate, this,
std::placeholders::_1, std::placeholders::_2),
addr, m_Parent->GenTXID());
addr, m_Endpoint->GenTXID());
updatingIntroSet = job->SendRequestViaPath(path, m_Parent->Router());
updatingIntroSet = job->SendRequestViaPath(path, m_Endpoint->Router());
}
else
{
@ -1069,11 +1115,11 @@ namespace llarp
bool
Endpoint::OutboundContext::Tick(llarp_time_t now)
{
if(selectedIntro.ExpiresSoon(now))
if(remoteIntro.ExpiresSoon(now))
{
ShiftIntroduction();
}
m_Parent->EnsureRouterIsKnown(selectedIntro.router);
m_Endpoint->EnsureRouterIsKnown(remoteIntro.router);
// TODO: check for expiration of outbound context
return false;
}
@ -1085,7 +1131,7 @@ namespace llarp
{
if(hop == numHops - 1)
{
if(llarp_nodedb_get_rc(db, selectedIntro.router, cur))
if(llarp_nodedb_get_rc(db, remoteIntro.router, cur))
{
return true;
}
@ -1095,13 +1141,12 @@ namespace llarp
llarp::LogError(
"cannot build aligned path, don't have router for "
"introduction ",
selectedIntro);
m_Parent->EnsureRouterIsKnown(selectedIntro.router);
remoteIntro);
m_Endpoint->EnsureRouterIsKnown(remoteIntro.router);
return false;
}
}
else
return path::Builder::SelectHop(db, prev, cur, hop);
return path::Builder::SelectHop(db, prev, cur, hop);
}
uint64_t
@ -1114,58 +1159,56 @@ namespace llarp
}
void
Endpoint::OutboundContext::EncryptAndSendTo(path::Path* p,
llarp_buffer_t payload,
ProtocolType t)
Endpoint::SendContext::EncryptAndSendTo(const PathID_t& p,
llarp_buffer_t payload,
ProtocolType t)
{
auto path = GetPathByRouter(selectedIntro.router);
if(path)
std::set< ConvoTag > tags;
if(!m_DataHandler->GetConvoTagsForService(remoteIdent, tags))
{
std::set< ConvoTag > tags;
if(!m_Parent->m_DataHandler->GetConvoTagsForService(currentIntroSet.A,
tags))
{
llarp::LogError("no open converstations with remote endpoint?");
return;
}
auto crypto = m_Parent->Crypto();
const byte_t* shared = nullptr;
routing::PathTransferMessage msg;
ProtocolFrame& f = msg.T;
f.N.Randomize();
f.T = *tags.begin();
f.S = m_Parent->GetSeqNoForConvo(f.T);
if(m_Parent->m_DataHandler->GetCachedSessionKeyFor(f.T, shared))
{
ProtocolMessage m;
m.proto = t;
m.introReply = path->intro;
m.sender = m_Parent->m_Identity.pub;
m.PutBuffer(payload);
llarp::LogError("no open converstations with remote endpoint?");
return;
}
auto crypto = m_Endpoint->Router()->crypto;
const byte_t* shared = nullptr;
routing::PathTransferMessage msg;
ProtocolFrame& f = msg.T;
f.N.Randomize();
f.T = *tags.begin();
f.S = m_Endpoint->GetSeqNoForConvo(f.T);
auto path = m_PathSet->GetPathByID(p);
if(!path)
{
llarp::LogError("cannot encrypt and send: no path with rxid=", p);
return;
}
if(!f.EncryptAndSign(crypto, m, shared, m_Parent->m_Identity))
{
llarp::LogError("failed to sign");
return;
}
}
else
{
llarp::LogError("No cached session key");
return;
}
if(m_DataHandler->GetCachedSessionKeyFor(f.T, shared))
{
ProtocolMessage m;
m.proto = t;
m.introReply = path->intro;
m.sender = m_Endpoint->m_Identity.pub;
m.PutBuffer(payload);
msg.P = selectedIntro.pathID;
msg.Y.Randomize();
if(!path->SendRoutingMessage(&msg, m_Parent->Router()))
if(!f.EncryptAndSign(&crypto, m, shared, m_Endpoint->m_Identity))
{
llarp::LogWarn("Failed to send routing message for data");
llarp::LogError("failed to sign");
return;
}
}
else
{
llarp::LogError("no outbound path for sending message");
llarp::LogError("No cached session key");
return;
}
msg.P = remoteIntro.pathID;
msg.Y.Randomize();
if(!path->SendRoutingMessage(&msg, m_Endpoint->Router()))
{
llarp::LogWarn("Failed to send routing message for data");
}
}

@ -32,7 +32,7 @@ namespace llarp
ProtocolMessage::ProcessAsync(void* user)
{
ProtocolMessage* self = static_cast< ProtocolMessage* >(user);
self->handler->HandleDataMessage(self);
self->handler->HandleDataMessage(self->srcPath, self);
delete self;
}
@ -249,7 +249,6 @@ namespace llarp
{
llarp::LogError("intro frame has invalid signature Z=",
self->frame->Z, " from ", self->msg->sender);
self->frame->Dump< MAX_PROTOCOL_MESSAGE_SIZE >();
delete self->msg;
delete self;
return;
@ -284,11 +283,12 @@ namespace llarp
ProtocolFrame&
ProtocolFrame::operator=(const ProtocolFrame& other)
{
C = other.C;
D = other.D;
N = other.N;
Z = other.Z;
T = other.T;
C = other.C;
D = other.D;
N = other.N;
Z = other.Z;
T = other.T;
version = other.version;
return *this;
}
@ -374,4 +374,4 @@ namespace llarp
}
} // namespace service
} // namespace llarp
} // namespace llarp

Loading…
Cancel
Save