/* * 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 #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 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>::Iterator i(RR->node->_networks); uint64_t * k = (uint64_t *)0; SharedPtr *v = (SharedPtr *)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 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