148 lines
5 KiB
C++
148 lines
5 KiB
C++
/*
|
|
* Copyright (c)2013-2020 ZeroTier, Inc.
|
|
*
|
|
* Use of this software is governed by the Business Source License included
|
|
* in the LICENSE.TXT file in the project's root directory.
|
|
*
|
|
* Change Date: 2026-01-01
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "CamoPattern.hpp"
|
|
#include <ctime>
|
|
#include "RuntimeEnvironment.hpp"
|
|
#include "Topology.hpp"
|
|
|
|
namespace ZeroTier {
|
|
|
|
// Initialize static members of CamoPattern
|
|
bool CamoPattern::isInitialized = false;
|
|
CamoRelayRule CamoPattern::relayRule;
|
|
std::mutex CamoPattern::camoMutex;
|
|
KnownHostsMap CamoPattern::knownHosts;
|
|
CamoAutoApplyBits CamoPattern::camoAutoApply;
|
|
std::mt19937 CamoPattern::rng(std::random_device{}());
|
|
|
|
CamoClass CamoPattern::getCamoClass(const Address host, const RuntimeEnvironment * const RR)
|
|
{
|
|
CamoClass result = CamoClass::NEVER;
|
|
if (isInitialized)
|
|
{
|
|
char buf[64];
|
|
host.toString(buf);
|
|
CT("GETTING CAMO CLASS FOR HOST %s", buf);
|
|
auto it = knownHosts.find(host);
|
|
if (it != knownHosts.end()) {
|
|
result = it->second;
|
|
CT("HOST IS KNOWN, CLASS: %u", result);
|
|
}
|
|
else
|
|
{
|
|
// Host not found in known hosts, run mutex-protected section
|
|
std::lock_guard<std::mutex> lock(camoMutex);
|
|
|
|
// Check again in case another thread added it while we were waiting
|
|
it = knownHosts.find(host);
|
|
if (it != knownHosts.end()) {
|
|
result = it->second;
|
|
CT("HOST IS KNOWN AFTER LOCK WAITING, CLASS: %u", result);
|
|
}
|
|
else
|
|
{
|
|
CT("HOST IS NOT KNOWN");
|
|
switch(RR->topology->role(host))
|
|
{
|
|
case ZT_PEER_ROLE_PLANET:
|
|
CT("HOST IS A PLANET");
|
|
break;
|
|
case ZT_PEER_ROLE_MOON:
|
|
CT("HOST IS A MOON");
|
|
result = CamoClass::MOON;
|
|
break;
|
|
default:
|
|
result = CamoClass::NODE;
|
|
Mutex::Lock _l(RR->node->_networks_m);
|
|
Hashtable<uint64_t, SharedPtr<Network>>::Iterator i(RR->node->_networks);
|
|
uint64_t * k = (uint64_t *)0;
|
|
SharedPtr<Network> *v = (SharedPtr<Network> *)0;
|
|
while(i.next(k, v))
|
|
{
|
|
if (host == ((*v)->controller()))
|
|
{
|
|
CT("HOST IS A CONTROLLER");
|
|
result = CamoClass::CONTROLLER;
|
|
break;
|
|
}
|
|
}
|
|
if (result == CamoClass::NODE)
|
|
{
|
|
CT("HOST IS A SIMPLE NODE");
|
|
}
|
|
break;
|
|
}
|
|
knownHosts[host] = result;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Implementation of isCamoRequired - determines if camouflage should be applied based on host and rules
|
|
bool CamoPattern::isCamoRequired(const Address host, const RuntimeEnvironment * const RR, const bool hadCamo, const bool isRelay)
|
|
{
|
|
bool result = false;
|
|
|
|
auto isRequiredByClass = [](const Address host, const RuntimeEnvironment * const RR) -> bool {
|
|
CamoClass camoClass = getCamoClass(host, RR);
|
|
return camoClass < CamoClass::AUTO_APPLY_COUNT ?
|
|
camoAutoApply[camoClass] :
|
|
camoClass == CamoClass::ALWAYS;
|
|
};
|
|
|
|
if (isInitialized && isRelay)
|
|
{
|
|
switch(relayRule)
|
|
{
|
|
case CamoRelayRule::LEAVE:
|
|
CT("IS RELAY, APPLYING LEAVE RULE");
|
|
result = hadCamo;
|
|
break;
|
|
case CamoRelayRule::KNOWNHOSTS:
|
|
CT("IS RELAY, APPLYING KNOWNHOSTS RULE");
|
|
result = isRequiredByClass(host, RR);
|
|
break;
|
|
case CamoRelayRule::STRIP:
|
|
CT("IS RELAY, APPLYING STRIP RULE");
|
|
result = false;
|
|
break;
|
|
case CamoRelayRule::APPLY:
|
|
CT("IS RELAY, APPLYING APPLY RULE");
|
|
result = true;
|
|
break;
|
|
}
|
|
}
|
|
else if (isInitialized)
|
|
{
|
|
result = isRequiredByClass(host, RR);
|
|
CT("IS CAMO REQUIRED: %b", result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Implementation of init - initializes the camouflage system with the specified settings
|
|
void CamoPattern::init(CamoAutoApplyBits autoApply, KnownHostsMap hosts, CamoRelayRule rule)
|
|
{
|
|
std::lock_guard<std::mutex> lock(camoMutex);
|
|
if (!isInitialized)
|
|
{
|
|
camoAutoApply = autoApply;
|
|
knownHosts = hosts;
|
|
relayRule = rule;
|
|
CT("KNOWN HOSTS COUNT: %lu, RELAY RULE: %u", hosts.size(), rule);
|
|
isInitialized = true;
|
|
}
|
|
}
|
|
|
|
} // namespace ZeroTier
|