more exit stuff

pull/66/head
Jeff Becker 6 years ago
parent f9a4c57d66
commit 5dbe41608f
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05

@ -553,7 +553,9 @@ ip address used for exit traffic.
A: "G",
S: uint64_sequence_number,
T: transaction_id_uint64,
V: 0
Y: "<16 byte nonce>",
V: 0,
Z: "<64 bytes signature>"
}
any TITM recieved on the same path will be forwarded out to the internet if
@ -571,14 +573,16 @@ was denied.
R: [list, of, rejected, traffic, policies],
S: uint64_sequence_number,
T: transaction_id_uint64,
V: 0
V: 0,
Y: "<16 byte nonce>",
Z: "<64 bytes signature>"
}
discarded data fragment message (DDFM)
sent in reply to TDFM when we don't have a path locally or are doing network
congestion control. indcates a TDFM was discarded.
congestion control from a TITM.
{
A: "D",
@ -732,24 +736,25 @@ transfer data on a session previously made
transfer ip traffic message (TITM)
transfer ip traffic for exit
transfer ip traffic
{
A: "I",
S: uint64_sequence_number,
V: 0,
X: "<N bytes ip packet>",
Y: "<16 bytes nonce>",
Z: "<64 bytes signature using previously provided signing key>"
}
X is parsed as an IP packet and the source addresss is extracted.
Next we find the corrisponding signing key for a previously granted exit address
Next we find the corrisponding signing key for a previously granted address
and use it to validate the siganture of the entire message. If the signing key
cannot be found or the signature is invalid this message is dropped, otherwise
the X value is sent on the appropriate exit network interface.
the X value is sent on the appropriate network interface.
When we recieve an ip packet from the internet to an exit address, we put it
into a TITM, signed with the exit info's signing key and send it downstream the
into a TITM, signed with the router's signing key and send it downstream the
corrisponding path in an LRDM.
update exit path message (UXPM)
@ -763,31 +768,35 @@ should use the new path that this message came from.
S: uint64_sequence_number,
T: uint64_txid,
V: 0,
Y: "<16 bytes nonce>",
Z: "<64 bytes signature using previously provided signing key>"
}
close exit path message (CXPM)
client sends a CXPM when the exit is no longer needed.
client sends a CXPM when the exit is no longer needed or by the exit if the
exit wants to close prematurely.
also sent by exit in reply to a CXPM to confirm close.
{
A: "C",
S: uint64_sequence_number,
T: transaction_id_uint64,
V: 0,
Z: "<64 bytes signagure using previously provided signing key>"
Y: "<16 bytes nonce>",
Z: "<64 bytes signature>"
}
update exit verify message (EXVM)
sent in reply to a UXPM to verify that the path handover was accepted
sent in reply to a CXPM to verify that the exit was closed
{
A: "V",
S: uint64_sequence_number,
T: uint64_txid,
V: 0
V: 0,
Y: "<16 bytes nonce>",
Z: "<64 bytes signature>"
}

@ -31,6 +31,14 @@ namespace llarp
llarp::exit::Endpoint *
FindEndpointForPath(const llarp::PathID_t &path) const;
/// calculate (pk, tx, rx) for all exit traffic
using TrafficStats =
std::unordered_map< PubKey, std::pair< uint64_t, uint64_t >,
PubKey::Hash >;
void
CalculateExitTraffic(TrafficStats &stats);
private:
llarp_router *m_Router;
std::unordered_map< std::string,

@ -24,10 +24,21 @@ namespace llarp
~Endpoint();
/// close ourselves
void
Close();
/// return true if we are expired right now
bool
IsExpired(llarp_time_t now) const;
bool
ExpiresSoon(llarp_time_t now, llarp_time_t dlt = 5000) const;
/// tick ourself, reset tx/rx rates
void
Tick(llarp_time_t now);
/// handle traffic from service node / internet
bool
SendInboundTraffic(llarp_buffer_t buff);
@ -57,11 +68,24 @@ namespace llarp
return m_CurrentPath;
}
uint64_t
TxRate() const
{
return m_TxRate;
}
uint64_t
RxRate() const
{
return m_RxRate;
}
private:
llarp::handlers::ExitEndpoint* m_Parent;
llarp::PubKey m_remoteSignKey;
llarp::PathID_t m_CurrentPath;
llarp::huint32_t m_IP;
uint64_t m_TxRate, m_RxRate;
bool m_RewriteSource;
};
} // namespace exit

@ -16,7 +16,7 @@ namespace llarp
bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop) override;
size_t hop, llarp::path::PathRole roles) override;
protected:
llarp::RouterID m_ExitRouter;

@ -34,10 +34,28 @@ namespace llarp
UpdateEndpointPath(const llarp::PubKey& remote,
const llarp::PathID_t& next);
template < typename Stats >
void
CalculateTrafficStats(Stats& stats)
{
auto itr = m_ActiveExits.begin();
while(itr != m_ActiveExits.end())
{
stats[itr->first].first += itr->second.TxRate();
stats[itr->first].second += itr->second.RxRate();
++itr;
}
}
/// DO NOT CALL ME IF YOU DONT KNOW WHAT THIS DOES
void
DelEndpointInfo(const llarp::PathID_t& path, const huint32_t& ip,
const llarp::PubKey& pk);
/// DO NOT CALL ME IF YOU DONT KNOW WHAT THIS DOES
void
RemoveExit(const llarp::exit::Endpoint* ep);
protected:
void
FlushSend();

@ -49,7 +49,10 @@ namespace llarp
struct GrantExitMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
uint64_t T;
Nonce_t Y;
llarp::Signature Z;
GrantExitMessage() : IMessage()
{
}
@ -58,9 +61,18 @@ namespace llarp
{
}
GrantExitMessage&
operator=(const GrantExitMessage& other);
bool
BEncode(llarp_buffer_t* buf) const override;
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
bool
DecodeKey(llarp_buffer_t key, llarp_buffer_t* buf) override;
@ -70,9 +82,12 @@ namespace llarp
struct RejectExitMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
uint64_t B;
std::vector< llarp::exit::Policy > R;
uint64_t T;
Nonce_t Y;
llarp::Signature Z;
RejectExitMessage() : IMessage()
{
@ -82,6 +97,15 @@ namespace llarp
{
}
RejectExitMessage&
operator=(const RejectExitMessage& other);
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
bool
BEncode(llarp_buffer_t* buf) const override;
@ -94,7 +118,10 @@ namespace llarp
struct UpdateExitVerifyMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
uint64_t T;
Nonce_t Y;
llarp::Signature Z;
UpdateExitVerifyMessage() : IMessage()
{
@ -104,6 +131,15 @@ namespace llarp
{
}
UpdateExitVerifyMessage&
operator=(const UpdateExitVerifyMessage& other);
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
bool
BEncode(llarp_buffer_t* buf) const override;
@ -116,8 +152,10 @@ namespace llarp
struct UpdateExitMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
llarp::PathID_t P;
uint64_t T;
Nonce_t Y;
llarp::Signature Z;
UpdateExitMessage() : IMessage()
@ -149,6 +187,11 @@ namespace llarp
struct CloseExitMessage final : public IMessage
{
using Nonce_t = llarp::AlignedBuffer< 16 >;
Nonce_t Y;
llarp::Signature Z;
CloseExitMessage() : IMessage()
{
}
@ -157,6 +200,9 @@ namespace llarp
{
}
CloseExitMessage&
operator=(const CloseExitMessage& other);
bool
BEncode(llarp_buffer_t* buf) const override;
@ -165,6 +211,12 @@ namespace llarp
bool
HandleMessage(IMessageHandler* h, llarp_router* r) const override;
bool
Sign(llarp_crypto* c, const llarp::SecretKey& sk);
bool
Verify(llarp_crypto* c, const llarp::PubKey& pk) const;
};
} // namespace routing

@ -11,7 +11,10 @@ namespace llarp
constexpr size_t MaxExitMTU = 1500;
struct TransferTrafficMessage final : public IMessage
{
using Nonce_t = AlignedBuffer< 16 >;
std::vector< byte_t > X;
Nonce_t Y;
llarp::Signature Z;
TransferTrafficMessage&

@ -144,6 +144,10 @@ struct llarp_async_load_rc
void
llarp_nodedb_async_load_rc(struct llarp_async_load_rc *job);
bool
llarp_nodedb_select_random_exit(struct llarp_nodedb *n,
llarp::RouterContact &rc);
bool
llarp_nodedb_select_random_hop(struct llarp_nodedb *n,
const llarp::RouterContact &prev,

@ -104,6 +104,9 @@ namespace llarp
virtual bool
Expired(llarp_time_t now) const = 0;
virtual bool
ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const = 0;
/// send routing message and increment sequence number
virtual bool
SendRoutingMessage(const llarp::routing::IMessage* msg,
@ -162,7 +165,13 @@ namespace llarp
}
bool
Expired(llarp_time_t now) const;
Expired(llarp_time_t now) const override;
bool
ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const override
{
return now >= ExpireTime() - dlt;
}
// send routing message when end of path
bool
@ -274,6 +283,10 @@ namespace llarp
DataHandlerFunc;
typedef std::function< bool(Path*) > ExitUpdatedFunc;
typedef std::function< bool(Path*) > ExitClosedFunc;
typedef std::function< bool(Path*, llarp_buffer_t) >
ExitTrafficHandlerFunc;
/// (path, backoff) backoff is 0 on success
typedef std::function< bool(Path*, llarp_time_t) > ObtainedExitHandler;
HopList hops;
@ -282,13 +295,37 @@ namespace llarp
llarp::service::Introduction intro;
llarp_time_t buildStarted;
PathStatus _status;
Path(const std::vector< RouterContact >& routers, PathSet* parent);
Path(const std::vector< RouterContact >& routers, PathSet* parent,
PathRole startingRoles);
PathRole
Role() const
{
return _role;
}
bool
SupportsRoles(PathRole roles) const
{
return (_role & roles) == roles;
}
PathStatus
Status() const
{
return _status;
}
void
SetBuildResultHook(BuildResultHookFunc func);
void
SetExitTrafficHandler(ExitTrafficHandlerFunc handler)
{
m_ExitTrafficHandler = handler;
}
void
SetCloseExitFunc(ExitClosedFunc handler)
{
@ -328,6 +365,12 @@ namespace llarp
return buildStarted + hops[0].lifetime;
}
bool
ExpiresSoon(llarp_time_t now, llarp_time_t dlt = 5000) const
{
return now >= (ExpireTime() - dlt);
}
bool
Expired(llarp_time_t now) const;
@ -426,21 +469,36 @@ namespace llarp
std::string
Name() const;
/// ask endpoint for exit
/// call handler with result when we get it
/// returns false if we failed to send the OXM
bool
ObtainExit(llarp_router* r, ObtainedExitHandler handler) const;
protected:
llarp::routing::InboundMessageParser m_InboundMessageParser;
private:
/// call obtained exit hooks
bool
InformExitResult(llarp_time_t b);
BuildResultHookFunc m_BuiltHook;
DataHandlerFunc m_DataHandler;
DropHandlerFunc m_DropHandler;
CheckForDeadFunc m_CheckForDead;
ExitUpdatedFunc m_ExitUpdated;
ExitClosedFunc m_ExitClosed;
ExitTrafficHandlerFunc m_ExitTrafficHandler;
std::vector< ObtainedExitHandler > m_ObtainedExitHooks;
llarp_time_t m_LastRecvMessage = 0;
llarp_time_t m_LastLatencyTestTime = 0;
uint64_t m_LastLatencyTestID = 0;
uint64_t m_UpdateExitTX = 0;
uint64_t m_CloseExitTX = 0;
uint64_t m_ExitObtainTX = 0;
PathStatus _status;
PathRole _role;
};
enum PathBuildStatus

@ -26,7 +26,7 @@ namespace llarp
virtual bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop);
size_t hop, PathRole roles);
virtual bool
ShouldBuildMore(llarp_time_t now) const;
@ -35,16 +35,18 @@ namespace llarp
Now() const;
void
BuildOne();
BuildOne(PathRole roles = ePathRoleAny);
void
Build(const std::vector< RouterContact >& hops);
Build(const std::vector< RouterContact >& hops,
PathRole roles = ePathRoleAny);
bool
SelectHops(llarp_nodedb* db, std::vector< RouterContact >& hops);
SelectHops(llarp_nodedb* db, std::vector< RouterContact >& hops,
PathRole roles = ePathRoleAny);
void
ManualRebuild(size_t N);
ManualRebuild(size_t N, PathRole roles = ePathRoleAny);
virtual const byte_t*
GetTunnelEncryptionSecretKey() const;

@ -21,6 +21,7 @@ namespace llarp
namespace path
{
/// status of a path
enum PathStatus
{
ePathBuilding,
@ -28,6 +29,21 @@ namespace llarp
ePathTimeout,
ePathExpired
};
/// the role of this path can fuffill
using PathRole = int;
/// capable of any role
constexpr PathRole ePathRoleAny = 0;
/// outbound hs traffic capabale
constexpr PathRole ePathRoleOutboundHS = (1 << 0);
/// inbound hs traffic capable
constexpr PathRole ePathRoleInboundHS = (1 << 1);
/// exit traffic capable
constexpr PathRole ePathRoleExit = (1 << 2);
/// dht message capable
constexpr PathRole ePathRoleDHT = (1 << 3);
// forward declare
struct Path;
@ -63,9 +79,14 @@ namespace llarp
void
ExpirePaths(llarp_time_t now);
/// get the number of paths in this status
size_t
NumInStatus(PathStatus st) const;
/// get the number of paths that match the role that are available
size_t
AvailablePaths(PathRole role) const;
/// get time from event loop
virtual llarp_time_t
Now() const = 0;
@ -74,6 +95,14 @@ namespace llarp
virtual bool
ShouldBuildMore(llarp_time_t now) const;
/// return true if we need another path with the given path roles
virtual bool
ShouldBuildMoreForRoles(llarp_time_t now, PathRole roles) const;
/// return the minimum number of paths we want for given roles
virtual size_t
MinRequiredForRoles(PathRole roles) const;
/// return true if we should publish a new hidden service descriptor
virtual bool
ShouldPublishDescriptors(__attribute__((unused)) llarp_time_t now) const
@ -104,16 +133,19 @@ namespace llarp
}
Path*
GetEstablishedPathClosestTo(const RouterID& router) const;
GetEstablishedPathClosestTo(const RouterID& router,
PathRole roles = ePathRoleAny) const;
Path*
PickRandomEstablishedPath() const;
PickRandomEstablishedPath(PathRole roles = ePathRoleAny) const;
Path*
GetPathByRouter(const RouterID& router) const;
GetPathByRouter(const RouterID& router,
PathRole roles = ePathRoleAny) const;
Path*
GetNewestPathByRouter(const RouterID& router) const;
GetNewestPathByRouter(const RouterID& router,
PathRole roles = ePathRoleAny) const;
Path*
GetPathByID(const PathID_t& id) const;
@ -136,7 +168,7 @@ namespace llarp
virtual bool
SelectHop(llarp_nodedb* db, const RouterContact& prev, RouterContact& cur,
size_t hop) = 0;
size_t hop, PathRole roles) = 0;
protected:
size_t m_NumPaths;

@ -53,6 +53,12 @@ namespace llarp
void
Clear();
bool
IsExit() const
{
return exits.size() > 0;
}
bool
BDecode(llarp_buffer_t *buf) override
{

@ -330,14 +330,6 @@ namespace llarp
EnsurePathToService(const Address& remote, PathEnsureHook h,
uint64_t timeoutMS, bool lookupOnRandomPath = false);
virtual bool
HandleAuthenticatedDataFrom(__attribute__((unused)) const Address& remote,
__attribute__((unused)) llarp_buffer_t data)
{
/// TODO: imlement me
return true;
}
void
PutSenderFor(const ConvoTag& tag, const ServiceInfo& info);

@ -8,18 +8,71 @@ namespace llarp
bool
CloseExitMessage::BEncode(llarp_buffer_t* buf) const
{
(void)buf;
// TODO: implement me
return false;
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "C"))
return false;
if(!BEncodeWriteDictInt("S", S, buf))
return false;
if(!BEncodeWriteDictInt("V", version, buf))
return false;
if(!BEncodeWriteDictEntry("Y", Y, buf))
return false;
if(!BEncodeWriteDictEntry("Z", Z, buf))
return false;
return bencode_end(buf);
}
bool
CloseExitMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
{
(void)k;
(void)buf;
// TODO: implement me
return false;
bool read = false;
if(!BEncodeMaybeReadDictInt("S", S, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Y", Y, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, k, buf))
return false;
return read;
}
bool
CloseExitMessage::Verify(llarp_crypto* c, const llarp::PubKey& pk) const
{
byte_t tmp[128] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
CloseExitMessage copy;
copy = *this;
copy.Z.Zero();
if(!copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->verify(pk, buf, Z);
}
bool
CloseExitMessage::Sign(llarp_crypto* c, const llarp::SecretKey& sk)
{
byte_t tmp[128] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
Z.Zero();
Y.Randomize();
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->sign(Z, sk, buf);
}
CloseExitMessage&
CloseExitMessage::operator=(const CloseExitMessage& other)
{
S = other.S;
version = other.version;
Y = other.Y;
Z = other.Z;
return *this;
}
bool

@ -22,6 +22,17 @@ namespace llarp
}
}
void
Context::CalculateExitTraffic(TrafficStats& stats)
{
auto itr = m_Exits.begin();
while(itr != m_Exits.end())
{
itr->second->CalculateTrafficStats(stats);
++itr;
}
}
llarp::exit::Endpoint*
Context::FindEndpointForPath(const llarp::PathID_t& path) const
{

@ -21,6 +21,12 @@ namespace llarp
m_Parent->DelEndpointInfo(m_CurrentPath, m_IP, m_remoteSignKey);
}
void
Endpoint::Close()
{
m_Parent->RemoveExit(this);
}
bool
Endpoint::UpdateLocalPath(const llarp::PathID_t& nextPath)
{
@ -30,6 +36,14 @@ namespace llarp
return true;
}
void
Endpoint::Tick(llarp_time_t now)
{
(void)now;
m_RxRate = 0;
m_TxRate = 0;
}
bool
Endpoint::IsExpired(llarp_time_t now) const
{
@ -42,6 +56,15 @@ namespace llarp
return true;
}
bool
Endpoint::ExpiresSoon(llarp_time_t now, llarp_time_t dlt) const
{
auto path = GetCurrentPath();
if(path)
return path->ExpiresSoon(now, dlt);
return true;
}
bool
Endpoint::SendOutboundTraffic(llarp_buffer_t buf)
{
@ -54,7 +77,10 @@ namespace llarp
else
dst = pkt.dst();
pkt.UpdateIPv4PacketOnDst(m_IP, dst);
return m_Parent->QueueOutboundTraffic(std::move(pkt));
if(!m_Parent->QueueOutboundTraffic(std::move(pkt)))
return false;
m_TxRate += buf.sz;
return true;
}
bool
@ -69,7 +95,10 @@ namespace llarp
msg.S = path->NextSeqNo();
if(!msg.Sign(m_Parent->Crypto(), m_Parent->Router()->identity))
return false;
return path->SendRoutingMessage(&msg, m_Parent->Router());
if(!path->SendRoutingMessage(&msg, m_Parent->Router()))
return false;
m_RxRate += buf.sz;
return true;
}
return false;
}

@ -18,6 +18,10 @@ namespace llarp
return false;
if(!BEncodeWriteDictInt("V", version, buf))
return false;
if(!BEncodeWriteDictEntry("Y", Y, buf))
return false;
if(!BEncodeWriteDictEntry("Z", Z, buf))
return false;
return bencode_end(buf);
}
@ -31,9 +35,51 @@ namespace llarp
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Y", Y, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, k, buf))
return false;
return read;
}
bool
GrantExitMessage::Verify(llarp_crypto* c, const llarp::PubKey& pk) const
{
byte_t tmp[128] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
GrantExitMessage copy;
copy = *this;
copy.Z.Zero();
if(!copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->verify(pk, buf, Z);
}
bool
GrantExitMessage::Sign(llarp_crypto* c, const llarp::SecretKey& sk)
{
byte_t tmp[128] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
Z.Zero();
Y.Randomize();
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->sign(Z, sk, buf);
}
GrantExitMessage&
GrantExitMessage::operator=(const GrantExitMessage& other)
{
S = other.S;
T = other.T;
version = other.version;
Y = other.Y;
Z = other.Z;
return *this;
}
bool
GrantExitMessage::HandleMessage(IMessageHandler* h, llarp_router* r) const
{

@ -8,19 +8,86 @@ namespace llarp
bool
RejectExitMessage::BEncode(llarp_buffer_t* buf) const
{
(void)buf;
// TODO: implement me
return false;
if(!bencode_start_dict(buf))
return false;
if(!BEncodeWriteDictMsgType(buf, "A", "J"))
return false;
if(!BEncodeWriteDictInt("B", B, buf))
return false;
if(!BEncodeWriteDictList("R", R, buf))
return false;
if(!BEncodeWriteDictInt("S", S, buf))
return false;
if(!BEncodeWriteDictInt("T", T, buf))
return false;
if(!BEncodeWriteDictInt("V", version, buf))
return false;
if(!BEncodeWriteDictEntry("Y", Y, buf))
return false;
if(!BEncodeWriteDictEntry("Z", Z, buf))
return false;
return bencode_end(buf);
}
bool
RejectExitMessage::DecodeKey(llarp_buffer_t k, llarp_buffer_t* buf)
{
(void)k;
(void)buf;
// TODO: implement me
return false;
bool read = false;
if(!BEncodeMaybeReadDictInt("B", B, read, k, buf))
return false;
if(!BEncodeMaybeReadDictList("R", R, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("S", S, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("T", T, read, k, buf))
return false;
if(!BEncodeMaybeReadDictInt("V", version, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Y", Y, read, k, buf))
return false;
if(!BEncodeMaybeReadDictEntry("Z", Z, read, k, buf))
return false;
return read;
}
RejectExitMessage&
RejectExitMessage::operator=(const RejectExitMessage& other)
{
B = other.B;
R = other.R;
S = other.S;
T = other.T;
version = other.version;
Y = other.Y;
Z = other.Z;
return *this;
}
bool
RejectExitMessage::Sign(llarp_crypto* c, const llarp::SecretKey& sk)
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
Z.Zero();
Y.Randomize();
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->sign(Z, sk, buf);
}
bool
RejectExitMessage::Verify(llarp_crypto* c, const llarp::PubKey& pk) const
{
byte_t tmp[512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
RejectExitMessage copy;
copy = *this;
copy.Z.Zero();
if(!copy.BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;
return c->verify(pk, buf, Z);
}
bool

@ -10,23 +10,22 @@ namespace llarp
{
byte_t tmp[MaxExitMTU + 512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
llarp::Signature sig;
// zero out sig
Z.Zero();
// randomize nonce
Y.Randomize();
if(!BEncode(&buf))
return false;
// rewind buffer
buf.sz = buf.cur - buf.base;
if(!c->sign(sig, k, buf))
return false;
Z = sig;
return true;
return c->sign(Z, k, buf);
}
TransferTrafficMessage&
TransferTrafficMessage::operator=(const TransferTrafficMessage& other)
{
Z = other.Z;
Y = other.Y;
S = other.S;
version = other.version;
X = other.X;
@ -39,7 +38,6 @@ namespace llarp
{
byte_t tmp[MaxExitMTU + 512] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
llarp::Signature sig;
// make copy
TransferTrafficMessage copy;
copy = *this;

@ -64,6 +64,7 @@ namespace llarp
S = other.S;
T = other.T;
version = other.version;
Y = other.Y;
Z = other.Z;
return *this;
}
@ -73,6 +74,7 @@ namespace llarp
{
byte_t tmp[128] = {0};
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
Y.Randomize();
if(!BEncode(&buf))
return false;
buf.sz = buf.cur - buf.base;

@ -85,6 +85,7 @@ namespace llarp
void
ExitEndpoint::FlushSend()
{
auto now = Now();
m_UserToNetworkPktQueue.Process([&](net::IPv4Packet &pkt) {
// find pubkey for addr
if(!HasLocalIP(pkt.dst()))
@ -94,16 +95,24 @@ namespace llarp
}
llarp::PubKey pk = ObtainAddrForIP< llarp::PubKey >(pkt.dst());
pkt.UpdateIPv4PacketOnDst(pkt.src(), {0});
auto range = m_ActiveExits.equal_range(pk);
auto exit_itr = range.first;
while(exit_itr != range.second)
llarp::exit::Endpoint *ep = nullptr;
auto range = m_ActiveExits.equal_range(pk);
auto itr = range.first;
uint64_t min = std::numeric_limits< uint64_t >::max();
/// pick path with lowest rx rate
while(itr != range.second)
{
if(exit_itr->second.SendInboundTraffic(pkt.Buffer()))
return true;
++exit_itr;
if(ep == nullptr)
ep = &itr->second;
else if(itr->second.RxRate() < min && !itr->second.ExpiresSoon(now))
{
min = ep->RxRate();
ep = &itr->second;
}
++itr;
}
// dropped
llarp::LogWarn(Name(), " dropped traffic to ", pk);
if(!ep->SendInboundTraffic(pkt.Buffer()))
llarp::LogWarn(Name(), " dropped traffic to ", pk);
return true;
});
}
@ -123,6 +132,23 @@ namespace llarp
m_AddrToIP.erase(pk);
}
void
ExitEndpoint::RemoveExit(const llarp::exit::Endpoint *ep)
{
auto range = m_ActiveExits.equal_range(ep->PubKey());
auto itr = range.first;
while(itr != range.second)
{
if(itr->second.LocalPath() == ep->LocalPath())
{
itr = m_ActiveExits.erase(itr);
// now ep is gone af
return;
}
++itr;
}
}
void
ExitEndpoint::Tick(llarp_time_t now)
{
@ -134,7 +160,10 @@ namespace llarp
itr = m_ActiveExits.erase(itr);
}
else
{
itr->second.Tick(now);
++itr;
}
}
// call parent
TunEndpoint::Tick(now);

@ -411,6 +411,40 @@ llarp_nodedb_del_rc(struct llarp_nodedb *n, const llarp::RouterID &pk)
return n->Remove(pk);
}
bool
llarp_nodedb_select_random_exit(struct llarp_nodedb *n,
llarp::RouterContact &result)
{
const auto sz = n->entries.size();
auto itr = n->entries.begin();
if(sz < 3)
return false;
auto idx = llarp_randint() % sz;
if(idx)
std::advance(itr, idx - 1);
while(itr != n->entries.end())
{
if(itr->second.IsExit())
{
result = itr->second;
return true;
}
++itr;
}
// wrap arround
itr = n->entries.begin();
while(idx--)
{
if(itr->second.IsExit())
{
result = itr->second;
return true;
}
++itr;
}
return false;
}
bool
llarp_nodedb_select_random_hop(struct llarp_nodedb *n,
const llarp::RouterContact &prev,

@ -263,7 +263,11 @@ namespace llarp
{
if(builder->ShouldBuildMore(now))
{
builder->BuildOne();
builder->BuildOne(ePathRoleAny);
}
if(builder->ShouldBuildMoreForRoles(now, ePathRoleExit))
{
builder->BuildOne(ePathRoleExit);
}
}
}
@ -336,8 +340,9 @@ namespace llarp
{
}
Path::Path(const std::vector< RouterContact >& h, PathSet* parent)
: m_PathSet(parent)
Path::Path(const std::vector< RouterContact >& h, PathSet* parent,
PathRole startingRoles)
: m_PathSet(parent), _role(startingRoles)
{
hops.resize(h.size());
size_t hsz = h.size();
@ -649,13 +654,13 @@ namespace llarp
const llarp::routing::PathLatencyMessage* msg, llarp_router* r)
{
auto now = r->Now();
// TODO: reanimate dead paths if they get this message
if(msg->L == m_LastLatencyTestID && _status == ePathEstablished)
if(msg->L == m_LastLatencyTestID)
{
intro.latency = now - m_LastLatencyTestTime;
llarp::LogDebug("path latency is ", intro.latency,
" ms for tx=", TXID(), " rx=", RXID());
m_LastLatencyTestID = 0;
_status = ePathEstablished;
return true;
}
else
@ -680,9 +685,20 @@ namespace llarp
Path::HandleCloseExitMessage(const llarp::routing::CloseExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
/// allows exits to close from their end
if(SupportsRoles(ePathRoleExit))
{
if(msg->Verify(&r->crypto, Endpoint()))
{
llarp::LogInfo(Name(), " had its exit closed");
_role &= ~ePathRoleExit;
return true;
}
else
llarp::LogError(Name(), " CXM from exit with bad signature");
}
else
llarp::LogError(Name(), " unwarrented CXM");
return false;
}
@ -690,9 +706,9 @@ namespace llarp
Path::HandleObtainExitMessage(const llarp::routing::ObtainExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
llarp::LogError(Name(), " got unwarrented OXM");
return false;
}
@ -700,9 +716,9 @@ namespace llarp
Path::HandleUpdateExitMessage(const llarp::routing::UpdateExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
llarp::LogError(Name(), " got unwarrented UXM");
return false;
}
@ -710,9 +726,16 @@ namespace llarp
Path::HandleRejectExitMessage(const llarp::routing::RejectExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
if(m_ExitObtainTX && msg->T == m_ExitObtainTX)
{
if(!msg->Verify(&r->crypto, Endpoint()))
{
llarp::LogError(Name(), "RXM invalid signature");
return false;
}
return InformExitResult(msg->B);
}
llarp::LogError(Name(), " got unwarrented RXM");
return false;
}
@ -720,19 +743,48 @@ namespace llarp
Path::HandleGrantExitMessage(const llarp::routing::GrantExitMessage* msg,
llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
if(m_ExitObtainTX && msg->T == m_ExitObtainTX)
{
if(!msg->Verify(&r->crypto, Endpoint()))
{
llarp::LogError(Name(), " GXM signature failed");
return false;
}
// we now can send exit traffic
_role |= ePathRoleExit;
return InformExitResult(0);
}
llarp::LogError(Name(), " got unwarrented GXM");
return false;
}
bool
Path::InformExitResult(llarp_time_t B)
{
bool result = true;
for(const auto& hook : m_ObtainedExitHooks)
result &= hook(this, B);
m_ObtainedExitHooks.clear();
return result;
}
bool
Path::HandleTransferTrafficMessage(
const llarp::routing::TransferTrafficMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
// check if we can handle exit data
if(!SupportsRoles(ePathRoleExit))
return false;
// verify sig
if(!msg->Verify(&r->crypto, Endpoint()))
{
llarp::LogError(Name(), " bad signature on inbound traffic");
return false;
}
// handle traffic if we have a handler
if(m_ExitTrafficHandler)
return m_ExitTrafficHandler(this, llarp::ConstBuffer(msg->X));
// fail if no handler
return false;
}

@ -176,7 +176,7 @@ namespace llarp
bool
Builder::SelectHop(llarp_nodedb* db, const RouterContact& prev,
RouterContact& cur, size_t hop)
RouterContact& cur, size_t hop, PathRole roles)
{
if(hop == 0 && router->NumberOfConnectedRouters())
return router->GetRandomConnectedRouter(cur);
@ -185,7 +185,10 @@ namespace llarp
do
{
--tries;
llarp_nodedb_select_random_hop(db, prev, cur, hop);
if(hop == numHops - 1 && roles & ePathRoleExit)
llarp_nodedb_select_random_exit(db, cur);
else
llarp_nodedb_select_random_hop(db, prev, cur, hop);
} while(router->routerProfiling.IsBad(cur.pubkey) && tries > 0);
return !router->routerProfiling.IsBad(cur.pubkey);
}
@ -204,16 +207,16 @@ namespace llarp
}
void
Builder::BuildOne()
Builder::BuildOne(PathRole roles)
{
std::vector< RouterContact > hops;
if(SelectHops(router->nodedb, hops))
Build(hops);
if(SelectHops(router->nodedb, hops, roles))
Build(hops, roles);
}
bool
Builder::SelectHops(llarp_nodedb* nodedb,
std::vector< RouterContact >& hops)
std::vector< RouterContact >& hops, PathRole roles)
{
hops.resize(numHops);
size_t idx = 0;
@ -221,7 +224,7 @@ namespace llarp
{
if(idx == 0)
{
if(!SelectHop(nodedb, hops[0], hops[0], 0))
if(!SelectHop(nodedb, hops[0], hops[0], 0, roles))
{
llarp::LogError("failed to select first hop");
return false;
@ -229,7 +232,7 @@ namespace llarp
}
else
{
if(!SelectHop(nodedb, hops[idx - 1], hops[idx], idx))
if(!SelectHop(nodedb, hops[idx - 1], hops[idx], idx, roles))
{
/// TODO: handle this failure properly
llarp::LogWarn("Failed to select hop ", idx);
@ -248,14 +251,14 @@ namespace llarp
}
void
Builder::Build(const std::vector< RouterContact >& hops)
Builder::Build(const std::vector< RouterContact >& hops, PathRole roles)
{
lastBuild = Now();
// async generate keys
AsyncPathKeyExchangeContext< Builder >* ctx =
new AsyncPathKeyExchangeContext< Builder >(&router->crypto);
ctx->pathset = this;
auto path = new llarp::path::Path(hops, this);
auto path = new llarp::path::Path(hops, this, roles);
path->SetBuildResultHook(std::bind(&llarp::path::Builder::HandlePathBuilt,
this, std::placeholders::_1));
ctx->AsyncGenerateKeys(path, router->logic, router->tp, this,
@ -278,11 +281,11 @@ namespace llarp
}
void
Builder::ManualRebuild(size_t num)
Builder::ManualRebuild(size_t num, PathRole roles)
{
llarp::LogDebug("manual rebuild ", num);
while(num--)
BuildOne();
BuildOne(roles);
}
} // namespace path

@ -18,6 +18,31 @@ namespace llarp
return m_Paths.size() < m_NumPaths;
}
bool
PathSet::ShouldBuildMoreForRoles(llarp_time_t now, PathRole roles) const
{
const size_t required = MinRequiredForRoles(roles);
size_t has = 0;
for(const auto& item : m_Paths)
{
if(item.second->SupportsRoles(roles))
{
if(!item.second->ExpiresSoon(now))
++has;
}
}
return has < required;
}
size_t
PathSet::MinRequiredForRoles(PathRole roles) const
{
size_t require = m_NumPaths > 1 ? m_NumPaths / 2 : m_NumPaths;
if(roles & ePathRoleInboundHS || roles & ePathRoleOutboundHS)
require += 2;
return require;
}
void
PathSet::Tick(llarp_time_t now, llarp_router* r)
{
@ -46,7 +71,8 @@ namespace llarp
}
Path*
PathSet::GetEstablishedPathClosestTo(const AlignedBuffer< 32 >& id) const
PathSet::GetEstablishedPathClosestTo(const AlignedBuffer< 32 >& id,
PathRole roles) const
{
Path* path = nullptr;
AlignedBuffer< 32 > dist;
@ -55,6 +81,8 @@ namespace llarp
{
if(!item.second->IsReady())
continue;
if(!item.second->SupportsRoles(roles))
continue;
AlignedBuffer< 32 > localDist = item.second->Endpoint() ^ id;
if(localDist < dist)
{
@ -66,13 +94,13 @@ namespace llarp
}
Path*
PathSet::GetNewestPathByRouter(const RouterID& id) const
PathSet::GetNewestPathByRouter(const RouterID& id, PathRole roles) const
{
Path* chosen = nullptr;
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->IsReady())
if(itr->second->IsReady() && itr->second->SupportsRoles(roles))
{
if(itr->second->Endpoint() == id)
{
@ -88,13 +116,13 @@ namespace llarp
}
Path*
PathSet::GetPathByRouter(const RouterID& id) const
PathSet::GetPathByRouter(const RouterID& id, PathRole roles) const
{
Path* chosen = nullptr;
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->IsReady())
if(itr->second->IsReady() && itr->second->SupportsRoles(roles))
{
if(itr->second->Endpoint() == id)
{
@ -129,7 +157,7 @@ namespace llarp
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->_status == st)
if(itr->second->Status() == st)
++count;
++itr;
}
@ -232,13 +260,13 @@ namespace llarp
}
Path*
PathSet::PickRandomEstablishedPath() const
PathSet::PickRandomEstablishedPath(PathRole roles) const
{
std::vector< Path* > established;
auto itr = m_Paths.begin();
while(itr != m_Paths.end())
{
if(itr->second->IsReady())
if(itr->second->IsReady() && itr->second->SupportsRoles(roles))
established.push_back(itr->second);
++itr;
}

@ -1197,7 +1197,13 @@ namespace llarp
{
self->defaultIfName = val;
}
if(!StrEq(key, "profiles"))
if(StrEq(key, "profiles"))
{
self->routerProfilesFile = val;
self->routerProfiling.Load(val);
llarp::LogInfo("setting profiles to ", self->routerProfilesFile);
}
else
{
self->exitConf.insert(std::make_pair(key, val));
}
@ -1245,23 +1251,6 @@ namespace llarp
{
self->connect[key] = val;
}
else if(StrEq(section, "network"))
{
if(StrEq(key, "profiles"))
{
self->routerProfilesFile = val;
self->routerProfiling.Load(val);
llarp::LogInfo("setting profiles to ", self->routerProfilesFile);
}
if(StrEq(key, "min-connected"))
{
self->minConnectedRouters = std::max(atoi(val), 0);
}
if(StrEq(key, "max-connected"))
{
self->maxConnectedRouters = std::max(atoi(val), 1);
}
}
else if(StrEq(section, "router"))
{
if(StrEq(key, "nickname"))
@ -1313,5 +1302,5 @@ namespace llarp
self->publicOverride = true;
}
}
}
} // namespace llarp
} // namespace llarp

@ -88,11 +88,7 @@ namespace llarp
AsyncVerifyRouter(llarp::PubKey pk,
std::function< void(llarp::PubKey, bool) > handler)
{
abyss::json::Value params;
params.SetObject();
QueueRPC("get_service_node", std::move(params),
std::bind(&CallerImpl::NewConn, this, pk, handler,
std::placeholders::_1));
handler(pk, true);
}
~CallerImpl()
@ -112,6 +108,30 @@ namespace llarp
{
}
bool
ListExitLevels(Response& resp) const
{
llarp::exit::Context::TrafficStats stats;
router->exitContext.CalculateExitTraffic(stats);
auto& alloc = resp.GetAllocator();
abyss::json::Value exits;
exits.SetArray();
auto itr = stats.begin();
while(itr != stats.end())
{
abyss::json::Value info, ident;
info.SetObject();
ident.SetString(itr->first.ToHex().c_str(), alloc);
info.AddMember("ident", ident, alloc);
info.AddMember("tx", abyss::json::Value(itr->second.first), alloc);
info.AddMember("rx", abyss::json::Value(itr->second.second), alloc);
exits.PushBack(info, alloc);
++itr;
}
resp.AddMember("result", exits, alloc);
return true;
}
bool
ListNeighboors(Response& resp) const
{
@ -148,6 +168,10 @@ namespace llarp
{
return ListNeighboors(response);
}
else if(method == "llarp.admin.exit.list")
{
return ListExitLevels(response);
}
return false;
}
};

@ -1536,7 +1536,8 @@ namespace llarp
return false;
}
}
return path::Builder::SelectHop(db, prev, cur, hop);
return path::Builder::SelectHop(db, prev, cur, hop,
llarp::path::ePathRoleOutboundHS);
}
uint64_t
@ -1553,7 +1554,8 @@ namespace llarp
{
if(markedBad)
return false;
bool should = path::Builder::ShouldBuildMore(now);
bool should = path::Builder::ShouldBuildMoreForRoles(
now, llarp::path::ePathRoleOutboundHS);
// determinte newest intro
Introduction intro;
if(!GetNewestIntro(intro))

@ -15,7 +15,7 @@ namespace llarp
bool
TransitHop::Expired(llarp_time_t now) const
{
return now > ExpireTime();
return now >= ExpireTime();
}
llarp_time_t
@ -159,6 +159,8 @@ namespace llarp
llarp::routing::GrantExitMessage grant;
grant.S = NextSeqNo();
grant.T = msg->T;
if(!grant.Sign(&r->crypto, r->identity))
return false;
return SendRoutingMessage(&grant, r);
}
// TODO: exponential backoff
@ -166,6 +168,8 @@ namespace llarp
llarp::routing::RejectExitMessage reject;
reject.S = NextSeqNo();
reject.T = msg->T;
if(!reject.Sign(&r->crypto, r->identity))
return false;
return SendRoutingMessage(&reject, r);
}
@ -173,10 +177,18 @@ namespace llarp
TransitHop::HandleCloseExitMessage(
const llarp::routing::CloseExitMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
return false;
llarp::routing::DataDiscardMessage discard(info.txID, msg->S);
auto ep = r->exitContext.FindEndpointForPath(info.txID);
if(ep && msg->Verify(&r->crypto, ep->PubKey()))
{
ep->Close();
// ep is now gone af
llarp::routing::CloseExitMessage reply;
reply.S = NextSeqNo();
if(reply.Sign(&r->crypto, r->identity))
return SendRoutingMessage(&reply, r);
}
return SendRoutingMessage(&discard, r);
}
bool
@ -196,15 +208,15 @@ namespace llarp
auto ep = r->exitContext.FindEndpointForPath(msg->P);
if(ep)
{
if(msg->Verify(&r->crypto, ep->PubKey()))
if(!msg->Verify(&r->crypto, ep->PubKey()))
return false;
if(ep->UpdateLocalPath(info.txID))
{
if(ep->UpdateLocalPath(info.txID))
{
llarp::routing::UpdateExitVerifyMessage reply;
reply.T = msg->T;
reply.S = NextSeqNo();
return SendRoutingMessage(&reply, r);
}
llarp::routing::UpdateExitVerifyMessage reply;
reply.T = msg->T;
reply.S = NextSeqNo();
return SendRoutingMessage(&reply, r);
}
}
// on fail tell message was discarded
@ -216,9 +228,9 @@ namespace llarp
TransitHop::HandleRejectExitMessage(
const llarp::routing::RejectExitMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
llarp::LogError(info, " got unwarrented RXM");
return false;
}
@ -226,9 +238,9 @@ namespace llarp
TransitHop::HandleGrantExitMessage(
const llarp::routing::GrantExitMessage* msg, llarp_router* r)
{
// TODO: implement me
(void)msg;
(void)r;
llarp::LogError(info, " got unwarrented GXM");
return false;
}
@ -237,11 +249,14 @@ namespace llarp
const llarp::routing::TransferTrafficMessage* msg, llarp_router* r)
{
auto endpoint = r->exitContext.FindEndpointForPath(info.txID);
if(endpoint == nullptr)
return false;
if(!msg->Verify(&r->crypto, endpoint->PubKey()))
return false;
return endpoint->SendOutboundTraffic(llarp::ConstBuffer(msg->X));
if(endpoint && msg->Verify(&r->crypto, endpoint->PubKey()))
{
if(endpoint->SendOutboundTraffic(llarp::ConstBuffer(msg->X)))
return true;
}
// discarded
llarp::routing::DataDiscardMessage discard(info.txID, msg->S);
return SendRoutingMessage(&discard, r);
}
bool
@ -249,25 +264,26 @@ namespace llarp
const llarp::routing::PathTransferMessage* msg, llarp_router* r)
{
auto path = r->paths.GetPathForTransfer(msg->P);
llarp::routing::DataDiscardMessage discarded(msg->P, msg->S);
if(!path)
{
llarp::routing::DataDiscardMessage discarded(msg->P, msg->S);
path = r->paths.GetPathForTransfer(msg->from);
return path && path->SendRoutingMessage(&discarded, r);
return SendRoutingMessage(&discarded, r);
}
byte_t tmp[service::MAX_PROTOCOL_MESSAGE_SIZE];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
if(!msg->T.BEncode(&buf))
{
llarp::LogWarn("failed to transfer data message, encode failed");
return false;
llarp::LogWarn(info, " failed to transfer data message, encode failed");
return SendRoutingMessage(&discarded, r);
}
// rewind0
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
// send
return path->HandleDownstream(buf, msg->Y, r);
if(path->HandleDownstream(buf, msg->Y, r))
return true;
return SendRoutingMessage(&discarded, r);
}
} // namespace path

Loading…
Cancel
Save