changed camouflaging scheme
This commit is contained in:
parent
235addc585
commit
98ccedecac
5 changed files with 235 additions and 319 deletions
|
@ -9,7 +9,6 @@
|
|||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#ifndef ZT_N_CAMOPATTERN_HPP
|
||||
#define ZT_N_CAMOPATTERN_HPP
|
||||
|
@ -19,20 +18,19 @@
|
|||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <bitset>
|
||||
|
||||
#include "Address.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
|
||||
#define BYTES_IN_WORD (sizeof(uint32_t) / sizeof(uint8_t))
|
||||
#define PATTERN_COUNT 16
|
||||
#define NO_CAMO PATTERN_COUNT
|
||||
|
||||
#define ZT_CAMO_DEFAULT_WORDSTR "DLGE"
|
||||
#define ID_SIZE (BYTES_IN_WORD * 2)
|
||||
|
||||
/**
|
||||
* Camo functions debug trace macro
|
||||
*/
|
||||
* Enables debug output when CAMO_TRACE is defined
|
||||
*/
|
||||
#ifdef CAMO_TRACE
|
||||
#define CT(...) do { \
|
||||
printf("%s:%d %s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__); \
|
||||
|
@ -43,35 +41,29 @@
|
|||
#define CT(...) ((void)0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type shorthands
|
||||
*/
|
||||
namespace ZeroTier {
|
||||
|
||||
enum class CamoLevel;
|
||||
/**
|
||||
* Camouflage class enum
|
||||
*/
|
||||
enum CamoClass {
|
||||
NODE,
|
||||
CONTROLLER,
|
||||
MOON,
|
||||
AUTO_APPLY_COUNT,
|
||||
ALWAYS = AUTO_APPLY_COUNT,
|
||||
NEVER
|
||||
};
|
||||
typedef std::bitset<CamoClass::AUTO_APPLY_COUNT> CamoAutoApplyBits;
|
||||
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;
|
||||
typedef std::unordered_map<Address, CamoClass> KnownHostsMap;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash functions for the respective unordered_maps
|
||||
* Hash function for the KnownHostsMap
|
||||
*/
|
||||
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 {
|
||||
|
@ -82,18 +74,6 @@ namespace std {
|
|||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Camouflage level enum
|
||||
*/
|
||||
enum class CamoLevel {
|
||||
NONE,
|
||||
NODE,
|
||||
CONTROLLER,
|
||||
MOON,
|
||||
PLANET,
|
||||
INAPPLICABLE
|
||||
};
|
||||
|
||||
enum class CamoRelayRule {
|
||||
LEAVE,
|
||||
KNOWNHOSTS,
|
||||
|
@ -107,146 +87,153 @@ enum class CamoRelayRule {
|
|||
class CamoPattern
|
||||
{
|
||||
/**
|
||||
* Check if buffer has camouflage applied
|
||||
* Check if the buffer has camo
|
||||
*
|
||||
* @param buffer Buffer to check
|
||||
* @return True if buffer has camouflage
|
||||
* @return True if the buffer has camo
|
||||
*/
|
||||
template<unsigned int C>
|
||||
static size_t getCamoIndex(const Buffer<C> &buffer)
|
||||
static bool hasCamo(const Buffer<C> &buffer)
|
||||
{
|
||||
size_t result = NO_CAMO;
|
||||
CamoPatternBytes camo;
|
||||
if (buffer.size() > BYTES_IN_WORD * 2)
|
||||
bool result = false;
|
||||
if (buffer.size() > (ID_SIZE * 2))
|
||||
{
|
||||
size_t a = 0;
|
||||
size_t b = BYTES_IN_WORD;
|
||||
size_t x = buffer.size() - ID_SIZE;
|
||||
size_t y = buffer.size() - BYTES_IN_WORD;
|
||||
result = true;
|
||||
for (size_t i = 0; i < BYTES_IN_WORD; i++)
|
||||
{
|
||||
camo[i] = buffer[i] ^ buffer[i + BYTES_IN_WORD];
|
||||
}
|
||||
auto it = camoIndices.find(camo);
|
||||
if (it != camoIndices.end())
|
||||
{
|
||||
result = it->second;
|
||||
CT("CAMO DETECTED, INDEX: %u", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
CT("CAMO NOT DETECTED");
|
||||
if ((buffer[a + i] ^ buffer[b + i]) != (buffer[x + i] ^ buffer [y + i]))
|
||||
{
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
CT("PACKET HAS CAMO: %b", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the host camo level
|
||||
* Check the host camo class
|
||||
*
|
||||
* @param host Destination address
|
||||
* @param RR RuntimeEnvironment pointer
|
||||
* @return Camo Level for this host
|
||||
* @return Camo class for this host
|
||||
*/
|
||||
static CamoLevel getCamoLevel(const Address host, const RuntimeEnvironment * const RR);
|
||||
static CamoClass getCamoClass(const Address host, const RuntimeEnvironment * const RR);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Determine if camouflage is required for a specific host
|
||||
*
|
||||
* @param host Destination address
|
||||
* @param RR RuntimeEnvironment pointer
|
||||
* @return True if host requires camo
|
||||
* @param hadCamo Whether the packet previously had camouflage applied
|
||||
* @param isRelay Whether this is a relay operation
|
||||
* @return True if host requires camouflage
|
||||
*/
|
||||
static bool isCamoRequired(const Address host, const RuntimeEnvironment * const RR, const bool hadCamo = false, const bool isRelay = false);
|
||||
|
||||
/**
|
||||
* Apply camouflage to buffer
|
||||
*
|
||||
* This increases buffer length by adding ID word to the end
|
||||
* This increases buffer length by adding ID to the end
|
||||
*
|
||||
* @param buffer Buffer to apply camouflage to
|
||||
*/
|
||||
template<unsigned int C>
|
||||
static void applyCamo(Buffer<C> &buffer)
|
||||
{
|
||||
size_t camoIndex = getCamoIndex(buffer);
|
||||
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_COUNT;
|
||||
CamoPatternBytes camo = camoValues[camoIndex];
|
||||
CT("APPLYING CAMO");
|
||||
if (isInitialized && !hasCamo(buffer))
|
||||
{
|
||||
// load random number into an array
|
||||
uint32_t camo = rng();
|
||||
CamoPatternBytes camoBytes;
|
||||
for (size_t i = 0; i < BYTES_IN_WORD; i++)
|
||||
{
|
||||
camoBytes[i] = camo >> 24;
|
||||
CT("CAMO BYTE %u: %02x", i, camoBytes[i]);
|
||||
camo <<= 8;
|
||||
}
|
||||
|
||||
// Increase buffer size first to avoid overflow
|
||||
//camouflage all the data
|
||||
uint8_t * const data = reinterpret_cast<uint8_t * const>(buffer.unsafeData());
|
||||
for (size_t i = ID_SIZE; i < buffer.size(); i++)
|
||||
{
|
||||
data[i] ^= camoBytes[i % BYTES_IN_WORD];
|
||||
}
|
||||
|
||||
// expand the buffer
|
||||
size_t originalSize = buffer.size();
|
||||
buffer.setSize(originalSize + BYTES_IN_WORD);
|
||||
uint8_t * const data = reinterpret_cast<uint8_t *>(buffer.unsafeData());
|
||||
|
||||
// Copy the second word to the end
|
||||
for (size_t i = 0; i < BYTES_IN_WORD; i++) {
|
||||
data[i + originalSize] = data[i + BYTES_IN_WORD];
|
||||
buffer.setSize(originalSize + ID_SIZE);
|
||||
//copy the id
|
||||
for (size_t i = 0; i < ID_SIZE; i++)
|
||||
{
|
||||
data[i + originalSize] = data[i] ^ camoBytes[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; i < buffer.size(); i++) {
|
||||
data[i] ^= camo[i % BYTES_IN_WORD];
|
||||
}
|
||||
|
||||
CT("PACKET CONTENTS AFTER APPLYING CAMO:");
|
||||
buffer.dump();
|
||||
CT("DONE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove camouflage from buffer
|
||||
*
|
||||
* This decreases buffer length by removing stored ID word from the end
|
||||
* This decreases buffer length by removing stored ID from the end
|
||||
*
|
||||
* @param buffer Buffer to remove camouflage from
|
||||
* @return True if buffer had camouflage and it was stripped
|
||||
*/
|
||||
template<unsigned int C>
|
||||
static bool stripCamo(Buffer<C> &buffer)
|
||||
{
|
||||
bool result = false;
|
||||
size_t camoIndex = NO_CAMO;
|
||||
if (isInitialized)
|
||||
{
|
||||
camoIndex = getCamoIndex(buffer);
|
||||
}
|
||||
if (camoIndex != NO_CAMO) {
|
||||
CT("PACKET CONTENTS BEFORE STRIPPING CAMO:");
|
||||
buffer.dump();
|
||||
uint8_t * const data = reinterpret_cast<uint8_t *>(buffer.unsafeData());
|
||||
CamoPatternBytes camo = camoValues[camoIndex];
|
||||
for (size_t i = BYTES_IN_WORD * 2; i < buffer.size(); i++)
|
||||
{
|
||||
data[i] ^= camo[i % BYTES_IN_WORD];
|
||||
}
|
||||
size_t storedWordIndex = buffer.size() - BYTES_IN_WORD;
|
||||
if (isInitialized && hasCamo(buffer)) {
|
||||
//retrieve the camo bytes
|
||||
uint8_t * a = &buffer[0];
|
||||
uint8_t * x = &buffer[buffer.size() - ID_SIZE];
|
||||
CamoPatternBytes camoBytes;
|
||||
for (size_t i = 0; i < BYTES_IN_WORD; i++)
|
||||
{
|
||||
data[i + BYTES_IN_WORD] = data[i + storedWordIndex];
|
||||
camoBytes[i] = a[i] ^ x[i];
|
||||
CT("CAMO BYTE %u: %02x", i, camoBytes[i]);
|
||||
}
|
||||
|
||||
//remove the duplicated id
|
||||
buffer.setSize(buffer.size() - ID_SIZE);
|
||||
|
||||
//strip camo
|
||||
uint8_t * const data = reinterpret_cast<uint8_t * const>(buffer.unsafeData());
|
||||
for (size_t i = ID_SIZE; i < buffer.size(); i++)
|
||||
{
|
||||
data[i] ^= camoBytes[i % BYTES_IN_WORD];
|
||||
}
|
||||
buffer.setSize(buffer.size() - BYTES_IN_WORD);
|
||||
result = true;
|
||||
CT("PACKET CONTENTS AFTER STRIPPING CAMO:");
|
||||
buffer.dump();
|
||||
}
|
||||
CT("CAMO STRIPPED: %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void init(CamoLevel level, uint32_t word, KnownHostsMap hosts, CamoRelayRule rule);
|
||||
|
||||
/**
|
||||
* Initialize the camo system
|
||||
*
|
||||
* @param autoApply Bits controlling automatic application to different host classes
|
||||
* @param hosts knownHosts preloading
|
||||
* @param relayRule Packet relay rule
|
||||
*/
|
||||
static void init(CamoAutoApplyBits autoApply, KnownHostsMap hosts, CamoRelayRule rule);
|
||||
|
||||
private:
|
||||
static bool isInitialized;
|
||||
static CamoLevel camoLevel;
|
||||
static uint32_t camoWord;
|
||||
static CamoAutoApplyBits camoAutoApply;
|
||||
static CamoRelayRule relayRule;
|
||||
static CamoPatternArray camoValues;
|
||||
static CamoIndexMap camoIndices;
|
||||
static std::mutex camoMutex;
|
||||
static KnownHostsMap knownHosts;
|
||||
static std::mt19937 rng;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue