Fix some identity verification stuff, performance improvements, build of root now requires libjemalloc.

This commit is contained in:
Adam Ierymenko 2021-06-18 16:14:59 -04:00
parent 311f9c5c2a
commit 5028aca372
2 changed files with 142 additions and 78 deletions

View file

@ -7,7 +7,7 @@ endif(WIN32)
add_executable(${PROJECT_NAME} root.cpp)
target_link_libraries(${PROJECT_NAME} zt_core zt_osdep pthread resolv)
target_link_libraries(${PROJECT_NAME} zt_core zt_osdep pthread resolv jemalloc)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)

View file

@ -48,7 +48,8 @@
* they appear with the first alive sibling being used.
*/
#include <Constants.hpp>
#include "../node/Constants.hpp"
#include <stdio.h>
#include <stdlib.h>
@ -71,20 +72,22 @@
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <json.hpp>
#include <httplib.h>
#include "../ext/json/json.hpp"
#include "../ext/cpp-httplib/httplib.h"
#include <Packet.hpp>
#include <Utils.hpp>
#include <Address.hpp>
#include <Identity.hpp>
#include <InetAddress.hpp>
#include <Mutex.hpp>
#include <SharedPtr.hpp>
#include <MulticastGroup.hpp>
#include <CertificateOfMembership.hpp>
#include <OSUtils.hpp>
#include <Meter.hpp>
#include "../node/Packet.hpp"
#include "../node/Utils.hpp"
#include "../node/Address.hpp"
#include "../node/Identity.hpp"
#include "../node/InetAddress.hpp"
#include "../node/Mutex.hpp"
#include "../node/SharedPtr.hpp"
#include "../node/MulticastGroup.hpp"
#include "../node/CertificateOfMembership.hpp"
#include "../node/Meter.hpp"
#include "../osdep/OSUtils.hpp"
#include "../osdep/BlockingQueue.hpp"
#include <string>
#include <thread>
@ -126,7 +129,7 @@ using json = nlohmann::json;
*/
struct RootPeer
{
ZT_ALWAYS_INLINE RootPeer() : v4s(-1),v6s(-1),lastSend(0),lastReceive(0),lastReceiveV4(0),lastReceiveV6(0),lastEcho(0),lastHello(0),vProto(-1),vMajor(-1),vMinor(-1),vRev(-1) {}
ZT_ALWAYS_INLINE RootPeer() : v4s(-1),v6s(-1),lastSend(0),lastReceive(0),lastReceiveV4(0),lastReceiveV6(0),lastEcho(0),lastHello(0),vProto(-1),vMajor(-1),vMinor(-1),vRev(-1),identityValidated(false),identityInvalid(false) {}
ZT_ALWAYS_INLINE ~RootPeer() { Utils::burn(key,sizeof(key)); }
Identity id; // Identity
@ -141,6 +144,8 @@ struct RootPeer
int64_t lastHello; // Time of last received HELLO
int vProto; // Protocol version or -1 if unknown
int vMajor,vMinor,vRev; // Peer version or -1,-1,-1 if unknown
bool identityValidated; // Identity has been fully verified
bool identityInvalid; // Identity validation failed, to be deleted
AtomicCounter __refCount;
};
@ -200,7 +205,8 @@ static Meter s_discardedForwardRate;
// These fields are locked using mutexes below as they're modified during runtime
static std::string s_planet;
static std::list< SharedPtr<RootPeer> > s_peers;
static std::vector< SharedPtr<RootPeer> > s_peers;
static std::vector< SharedPtr<RootPeer> > s_peersToValidate;
static std::unordered_map< uint64_t,std::unordered_map< MulticastGroup,std::unordered_map< Address,int64_t,AddressHasher >,MulticastGroupHasher > > s_multicastSubscriptions;
static std::unordered_map< Identity,SharedPtr<RootPeer>,IdentityHasher > s_peersByIdentity;
static std::unordered_map< Address,std::set< SharedPtr<RootPeer> >,AddressHasher > s_peersByVirtAddr;
@ -208,6 +214,7 @@ static std::unordered_map< RendezvousKey,RendezvousStats,RendezvousKey::Hasher >
static std::mutex s_planet_l;
static std::mutex s_peers_l;
static std::mutex s_peersToValidate_l;
static std::mutex s_multicastSubscriptions_l;
static std::mutex s_peersByIdentity_l;
static std::mutex s_peersByVirtAddr_l;
@ -262,12 +269,30 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
}
}
if (peer) {
// Peer found with this identity.
if (!pkt.dearmor(peer->key)) {
printf("%s HELLO rejected: packet authentication failed" ZT_EOL_S,ip->toString(ipstr));
return;
}
} else {
// Check to ensure that there is no peer with the same address as this identity. If there is,
// verify both identities to pick the one with this address.
bool needsValidation = false;
bool identityValidated = false;
{
std::lock_guard<std::mutex> pbv_l(s_peersByVirtAddr_l);
needsValidation = s_peersByVirtAddr.find(id.address()) != s_peersByVirtAddr.end();
}
if (unlikely(needsValidation)) {
if (!id.locallyValidate()) {
printf("%s HELLO rejected: identity validate failed" ZT_EOL_S,ip->toString(ipstr));
return;
}
identityValidated = true;
}
peer.set(new RootPeer);
peer->identityValidated = identityValidated;
if (!s_self.agree(id,peer->key)) {
printf("%s HELLO rejected: key agreement failed" ZT_EOL_S,ip->toString(ipstr));
@ -289,20 +314,29 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
{
std::lock_guard<std::mutex> pbi_l(s_peersByIdentity_l);
auto existing = s_peersByIdentity.find(id); // make sure another thread didn't do this while we were
if (existing == s_peersByIdentity.end()) {
if (likely(existing == s_peersByIdentity.end())) {
s_peersByIdentity.emplace(id,peer);
added = true;
} else {
peer = existing->second;
}
}
if (added) {
if (likely(added)) {
{
std::lock_guard<std::mutex> pl(s_peers_l);
s_peers.emplace_back(peer);
}
if (!peer->identityValidated) {
std::lock_guard<std::mutex> pv(s_peersToValidate_l);
s_peersToValidate.emplace_back(peer);
}
{
std::lock_guard<std::mutex> pbv_l(s_peersByVirtAddr_l);
std::set< SharedPtr<RootPeer> > &byVirt = s_peersByVirtAddr[id.address()];
for(auto i=byVirt.begin();i!=byVirt.end();++i) {
if (!(*i)->identityValidated)
(*i)->identityInvalid = !(*i)->id.locallyValidate();
}
s_peersByVirtAddr[id.address()].emplace(peer);
}
}
@ -317,6 +351,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
auto peers = s_peersByVirtAddr.find(source);
if (peers != s_peersByVirtAddr.end()) {
for(auto p=peers->second.begin();p!=peers->second.end();++p) {
if (!(*p)->identityInvalid) {
if (pkt.dearmor((*p)->key)) {
if (!pkt.uncompress()) {
printf("%s packet rejected: decompression failed" ZT_EOL_S,ip->toString(ipstr));
@ -328,6 +363,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
}
}
}
}
// If we found the peer, update IP and/or time and handle certain key packet types that the
// root must concern itself with.
@ -418,11 +454,13 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;(ptr+ZT_ADDRESS_LENGTH)<=pkt.size();ptr+=ZT_ADDRESS_LENGTH) {
auto peers = s_peersByVirtAddr.find(Address(pkt.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH));
if (peers != s_peersByVirtAddr.end()) {
for(auto p=peers->second.begin();p!=peers->second.end();++p)
for(auto p=peers->second.begin();p!=peers->second.end();++p) {
if (!(*p)->identityInvalid)
results.push_back(*p);
}
}
}
}
if (!results.empty()) {
const uint64_t origId = pkt.packetId();
@ -550,6 +588,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
auto peers = s_peersByVirtAddr.find(dest);
if (peers != s_peersByVirtAddr.end()) {
for(auto p=peers->second.begin();p!=peers->second.end();++p) {
if (!(*p)->identityInvalid) {
if (((*p)->v4s >= 0)&&((*p)->v6s >= 0)) {
if ((*p)->lastReceiveV4 > (*p)->lastReceiveV6) {
toAddrs.emplace_back(std::pair< InetAddress *,SharedPtr<RootPeer> >(&((*p)->ip4),*p));
@ -564,6 +603,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
}
}
}
}
if (toAddrs.empty()) {
s_discardedForwardRate.log(now,pkt.size());
return;
@ -895,6 +935,20 @@ int main(int argc,char **argv)
s_run = true;
threads.push_back(std::thread([]() {
while (s_run) {
std::vector< SharedPtr<RootPeer> > toValidate;
{
std::lock_guard<std::mutex> l(s_peersToValidate_l);
toValidate.swap(s_peersToValidate);
}
for(auto p=toValidate.begin();p!=toValidate.end();++p) {
if (!(*p)->identityValidated)
(*p)->identityInvalid = !(*p)->id.locallyValidate();
}
}
}));
for(auto port=s_ports.begin();port!=s_ports.end();++port) {
for(unsigned int tn=0;tn<ncores;++tn) {
struct sockaddr_in6 in6;
@ -1034,6 +1088,7 @@ int main(int argc,char **argv)
bool first = true;
std::lock_guard<std::mutex> l(s_peers_l);
for(auto p=s_peers.begin();p!=s_peers.end();++p) {
if (likely(!(*p)->identityInvalid)) {
if (first)
first = false;
else o << ',';
@ -1070,6 +1125,7 @@ int main(int argc,char **argv)
",\"versionMinor\":" << (*p)->vMinor <<
",\"versionRev\":" << (*p)->vRev << "}";
}
}
} catch ( ... ) {}
o << ']';
res.set_content(o.str(),"application/json");
@ -1094,12 +1150,14 @@ int main(int argc,char **argv)
{
std::lock_guard<std::mutex> l(s_peers_l);
for(auto p=s_peers.begin();p!=s_peers.end();++p) {
if (likely(!(*p)->identityInvalid)) {
if ((*p)->v4s >= 0)
ips[(*p)->ip4].insert((*p)->id.address());
if ((*p)->v6s >= 0)
ips[(*p)->ip6].insert((*p)->id.address());
}
}
}
for(auto p=ips.begin();p!=ips.end();++p) {
if (p->first.isV4()) {
@ -1201,19 +1259,25 @@ int main(int argc,char **argv)
}
}
// Remove expired peers
// Remove expired or otherwise invalid peers
try {
std::vector< SharedPtr<RootPeer> > toRemove;
toRemove.reserve(1024);
{
std::lock_guard<std::mutex> pbi_l(s_peers_l);
for(auto p=s_peers.begin();p!=s_peers.end();) {
if ((now - (*p)->lastReceive) > ZT_PEER_ACTIVITY_TIMEOUT) {
toRemove.emplace_back(*p);
s_peers.erase(p++);
} else ++p;
std::vector< SharedPtr<RootPeer> > newPeers;
newPeers.reserve(s_peers.size());
for(auto p=s_peers.begin();p!=s_peers.end();++p) {
if (((now - (*p)->lastReceive) > ZT_PEER_ACTIVITY_TIMEOUT)||((*p)->identityInvalid)) {
toRemove.emplace_back();
p->swap(toRemove.back());
} else {
newPeers.emplace_back();
p->swap(newPeers.back());
}
}
newPeers.swap(s_peers);
}
for(auto p=toRemove.begin();p!=toRemove.end();++p) {
{
std::lock_guard<std::mutex> pbi_l(s_peersByIdentity_l);
@ -1316,7 +1380,7 @@ int main(int argc,char **argv)
s_peersByIdentity_l.unlock();
fprintf(sf,"Peers : %llu" ZT_EOL_S,(unsigned long long)peersByIdentitySize);
s_peersByVirtAddr_l.lock();
fprintf(sf,"Virtual Address Collisions : %llu" ZT_EOL_S,(unsigned long long)(peersByIdentitySize - s_peersByVirtAddr.size()));
fprintf(sf,"Virtual Address Collisions : %lld" ZT_EOL_S,(long long)peersByIdentitySize - (long long)s_peersByVirtAddr.size());
s_peersByVirtAddr_l.unlock();
s_rendezvousTracking_l.lock();
uint64_t unsuccessfulp2p = 0;