added readme; added special case camouflaging
This commit is contained in:
parent
5fb3f5c228
commit
235addc585
9 changed files with 290 additions and 59 deletions
|
@ -22,10 +22,10 @@ bool CamoPattern::isInitialized = false;
|
|||
CamoLevel CamoPattern::camoLevel;
|
||||
uint32_t CamoPattern::camoWord;
|
||||
CamoRelayRule CamoPattern::relayRule;
|
||||
std::array<std::array<uint8_t, BYTES_IN_WORD>, PATTERN_COUNT> CamoPattern::camoValues;
|
||||
std::unordered_map<std::array<uint8_t, BYTES_IN_WORD>, size_t> CamoPattern::camoIndices;
|
||||
CamoPatternArray CamoPattern::camoValues;
|
||||
CamoIndexMap CamoPattern::camoIndices;
|
||||
std::mutex CamoPattern::camoMutex;
|
||||
std::unordered_map<Address, CamoLevel> CamoPattern::knownHosts;
|
||||
KnownHostsMap CamoPattern::knownHosts;
|
||||
|
||||
|
||||
// Implementation of getCamoLevel
|
||||
|
@ -138,7 +138,7 @@ bool CamoPattern::isCamoRequired(const Address host, const RuntimeEnvironment *
|
|||
|
||||
|
||||
// Implementation of init
|
||||
void CamoPattern::init(CamoLevel level, uint32_t word, std::unordered_map<Address, CamoLevel> hosts, CamoRelayRule rule)
|
||||
void CamoPattern::init(CamoLevel level, uint32_t word, KnownHostsMap hosts, CamoRelayRule rule)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(camoMutex);
|
||||
if (!isInitialized)
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#ifndef ZT_N_CAMOPATTERN_HPP
|
||||
#define ZT_N_CAMOPATTERN_HPP
|
||||
|
||||
#define CAMO_TRACE
|
||||
|
||||
#include <stdint.h>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
@ -26,33 +24,12 @@
|
|||
#include "Buffer.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
|
||||
#define BYTES_IN_WORD 4
|
||||
#define BYTES_IN_WORD (sizeof(uint32_t) / sizeof(uint8_t))
|
||||
#define PATTERN_COUNT 16
|
||||
#define PATTERN_INDEX_MASK 0xf
|
||||
#define NO_CAMO PATTERN_COUNT
|
||||
|
||||
#define ZT_CAMO_DEFAULT_WORDSTR "DLGE"
|
||||
|
||||
namespace std {
|
||||
template<typename T, size_t N>
|
||||
struct hash<std::array<T, N>> {
|
||||
size_t operator()(const std::array<T, N>& array) const {
|
||||
size_t hash = 0;
|
||||
for (const auto& element : array) {
|
||||
hash = hash * 31 + std::hash<T>{}(element);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<ZeroTier::Address> {
|
||||
size_t operator()(const ZeroTier::Address& address) const {
|
||||
return std::hash<uint64_t>{}(address.toInt());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Camo functions debug trace macro
|
||||
*/
|
||||
|
@ -66,6 +43,43 @@ namespace std {
|
|||
#define CT(...) ((void)0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type shorthands
|
||||
*/
|
||||
namespace ZeroTier {
|
||||
|
||||
enum class CamoLevel;
|
||||
typedef std::array<uint8_t, BYTES_IN_WORD> CamoPatternBytes;
|
||||
typedef std::array<CamoPatternBytes, PATTERN_COUNT> CamoPatternArray;
|
||||
typedef std::unordered_map<CamoPatternBytes, size_t> CamoIndexMap;
|
||||
typedef std::unordered_map<Address, CamoLevel> KnownHostsMap;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash functions for the respective unordered_maps
|
||||
*/
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<ZeroTier::CamoPatternBytes> {
|
||||
size_t operator()(const ZeroTier::CamoPatternBytes& bytes) const {
|
||||
uint32_t word = 0;
|
||||
for (const auto& byte : bytes) {
|
||||
word <<= 8;
|
||||
word |= byte;
|
||||
}
|
||||
return std::hash<uint32_t>{}(word);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<ZeroTier::Address> {
|
||||
size_t operator()(const ZeroTier::Address& address) const {
|
||||
return std::hash<uint64_t>{}(address.toInt());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
|
@ -102,7 +116,7 @@ class CamoPattern
|
|||
static size_t getCamoIndex(const Buffer<C> &buffer)
|
||||
{
|
||||
size_t result = NO_CAMO;
|
||||
std::array<uint8_t, BYTES_IN_WORD> camo;
|
||||
CamoPatternBytes camo;
|
||||
if (buffer.size() > BYTES_IN_WORD * 2)
|
||||
{
|
||||
for (size_t i = 0; i < BYTES_IN_WORD; i++)
|
||||
|
@ -144,6 +158,8 @@ public:
|
|||
/**
|
||||
* Apply camouflage to buffer
|
||||
*
|
||||
* This increases buffer length by adding ID word to the end
|
||||
*
|
||||
* @param buffer Buffer to apply camouflage to
|
||||
*/
|
||||
template<unsigned int C>
|
||||
|
@ -153,8 +169,8 @@ public:
|
|||
if (isInitialized && (camoIndex == NO_CAMO)) { // Only apply if not already applied
|
||||
CT("PACKET CONTENTS BEFORE APPLYING CAMO:");
|
||||
buffer.dump();
|
||||
camoIndex = std::minstd_rand(std::time(nullptr))() & PATTERN_INDEX_MASK;
|
||||
std::array<uint8_t, BYTES_IN_WORD> camo = camoValues[camoIndex];
|
||||
camoIndex = std::minstd_rand(std::time(nullptr))() % PATTERN_COUNT;
|
||||
CamoPatternBytes camo = camoValues[camoIndex];
|
||||
|
||||
// Increase buffer size first to avoid overflow
|
||||
size_t originalSize = buffer.size();
|
||||
|
@ -166,15 +182,16 @@ public:
|
|||
data[i + originalSize] = data[i + BYTES_IN_WORD];
|
||||
}
|
||||
|
||||
// Copy the first word on the second word's place
|
||||
for (size_t i = 0; i < BYTES_IN_WORD; i++) {
|
||||
data[i + BYTES_IN_WORD] = data[i];
|
||||
}
|
||||
|
||||
// Apply XOR to the rest of the buffer
|
||||
for (size_t i = BYTES_IN_WORD * 2; i < buffer.size(); i++) {
|
||||
for (size_t i = BYTES_IN_WORD; i < buffer.size(); i++) {
|
||||
data[i] ^= camo[i % BYTES_IN_WORD];
|
||||
}
|
||||
|
||||
// Apply XOR to create the camouflage pattern in the second word
|
||||
for (size_t i = 0; i < BYTES_IN_WORD; i++) {
|
||||
data[i + BYTES_IN_WORD] = data[i] ^ camo[i];
|
||||
}
|
||||
CT("PACKET CONTENTS AFTER APPLYING CAMO:");
|
||||
buffer.dump();
|
||||
}
|
||||
|
@ -183,7 +200,7 @@ public:
|
|||
/**
|
||||
* Remove camouflage from buffer
|
||||
*
|
||||
* This decreases buffer length by removing 'CAMO' from the end
|
||||
* This decreases buffer length by removing stored ID word from the end
|
||||
*
|
||||
* @param buffer Buffer to remove camouflage from
|
||||
*/
|
||||
|
@ -200,10 +217,10 @@ public:
|
|||
CT("PACKET CONTENTS BEFORE STRIPPING CAMO:");
|
||||
buffer.dump();
|
||||
uint8_t * const data = reinterpret_cast<uint8_t *>(buffer.unsafeData());
|
||||
std::array<uint8_t, BYTES_IN_WORD> camo = camoValues[camoIndex];
|
||||
CamoPatternBytes camo = camoValues[camoIndex];
|
||||
for (size_t i = BYTES_IN_WORD * 2; i < buffer.size(); i++)
|
||||
{
|
||||
data[i] ^= camo[i % BYTES_IN_WORD];
|
||||
data[i] ^= camo[i % BYTES_IN_WORD];
|
||||
}
|
||||
size_t storedWordIndex = buffer.size() - BYTES_IN_WORD;
|
||||
for (size_t i = 0; i < BYTES_IN_WORD; i++)
|
||||
|
@ -218,7 +235,7 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
static void init(CamoLevel level, uint32_t word, std::unordered_map<Address, CamoLevel> hosts, CamoRelayRule rule);
|
||||
static void init(CamoLevel level, uint32_t word, KnownHostsMap hosts, CamoRelayRule rule);
|
||||
|
||||
|
||||
private:
|
||||
|
@ -226,10 +243,10 @@ private:
|
|||
static CamoLevel camoLevel;
|
||||
static uint32_t camoWord;
|
||||
static CamoRelayRule relayRule;
|
||||
static std::array<std::array<uint8_t, BYTES_IN_WORD>, PATTERN_COUNT> camoValues;
|
||||
static std::unordered_map<std::array<uint8_t, BYTES_IN_WORD>, size_t> camoIndices;
|
||||
static CamoPatternArray camoValues;
|
||||
static CamoIndexMap camoIndices;
|
||||
static std::mutex camoMutex;
|
||||
static std::unordered_map<Address, CamoLevel> knownHosts;
|
||||
static KnownHostsMap knownHosts;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -435,7 +435,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
|||
Metrics::pkt_error_out++;
|
||||
Metrics::pkt_error_identity_collision_out++;
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
} else {
|
||||
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC");
|
||||
|
@ -595,7 +599,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
|||
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
|
||||
Metrics::pkt_ok_out++;
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
|
||||
peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
|
||||
|
@ -1000,7 +1008,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
|
|||
Metrics::pkt_ok_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
|
||||
|
@ -1032,7 +1044,11 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share
|
|||
Metrics::pkt_ok_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
|
||||
peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
|
@ -1231,7 +1247,11 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void
|
|||
Metrics::pkt_error_unsupported_op_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
|
||||
|
@ -1258,7 +1278,11 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c
|
|||
Metrics::pkt_ok_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
}
|
||||
|
@ -1304,7 +1328,11 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
|
|||
Metrics::pkt_ok_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
}
|
||||
}
|
||||
|
@ -1414,7 +1442,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
|
|||
Metrics::pkt_ok_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
}
|
||||
|
@ -1559,7 +1591,11 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void
|
|||
Metrics::pkt_error_need_membership_cert_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
|
||||
|
|
|
@ -203,7 +203,11 @@ void Multicaster::send(
|
|||
Metrics::pkt_multicast_frame_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED MULTICAST, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED MULTICAST, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -250,7 +250,12 @@ void Peer::received(
|
|||
Metrics::pkt_push_direct_paths_out++;
|
||||
char buf[64];
|
||||
outp->destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp->packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp->packetId(), buf);
|
||||
|
||||
if (CamoPattern::isCamoRequired(outp->destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(*outp);
|
||||
}
|
||||
path->send(RR,tPtr,outp->data(),outp->size(),now);
|
||||
}
|
||||
delete outp;
|
||||
|
@ -399,7 +404,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
|
|||
Metrics::pkt_rendezvous_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
_paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
} else {
|
||||
Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS);
|
||||
|
@ -417,7 +426,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
|
|||
Metrics::pkt_rendezvous_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
if (CamoPattern::isCamoRequired(outp.destination(), RR))
|
||||
{
|
||||
CamoPattern::applyCamo(outp);
|
||||
}
|
||||
other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
}
|
||||
++alt;
|
||||
|
@ -468,7 +481,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
|
|||
RR->node->expectReplyTo(outp.packetId());
|
||||
char buf[64];
|
||||
outp.destination().toString(buf);
|
||||
CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
CT("SWITCH PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf);
|
||||
RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue