Browse Source

Make encrypted HELLO a local.conf setting -- 99.999999% of users do not need it and it introduces scalability problems on large controllers.

Adam Ierymenko 4 weeks ago
parent
commit
ab208bb8f9
6 changed files with 55 additions and 13 deletions
  1. 29 1
      include/ZeroTierOne.h
  2. 4 3
      node/Node.cpp
  3. 14 6
      node/Node.hpp
  4. 1 1
      node/Peer.cpp
  5. 6 1
      service/OneService.cpp
  6. 1 1
      version.h

+ 29 - 1
include/ZeroTierOne.h

@@ -1745,6 +1745,33 @@ struct ZT_Node_Callbacks {
 	ZT_PathLookupFunction pathLookupFunction;
 };
 
+/**
+ * Node configuration options
+ */
+struct ZT_Node_Config {
+	/**
+	 * If non-zero enable encrypted HELLO packets.
+	 *
+	 * This attaches an ephemeral key to HELLO packets and encrypts them. It
+	 * increases CPU usage slightly, which can matter at scale for nodes that
+	 * handle huge numbers of clients like controllers. HELLO packets only
+	 * contain keys and a small amount of meta-data like node version, never
+	 * user data or information about things like network membership, so the
+	 * security impact of this is negligable. ZT1 does not and never has
+	 * guaranteed meta-data privacy, only data privacy. Enable only if you
+	 * need it for compliance reasons.
+	 */
+	int enableEncryptedHello;
+
+	/**
+	 * If non-zero enable low bandwidth mode.
+	 *
+	 * This reduces keepalive and path sensing traffic, which can slow fail-
+	 * over but reduces idle bandwidth. Enable in low bandwidth environments.
+	 */
+	int lowBandwidthMode;
+};
+
 /**
  * Create a new ZeroTier node
  *
@@ -1754,13 +1781,14 @@ struct ZT_Node_Callbacks {
  * to a few seconds depending on your CPU speed.
  *
  * @param node Result: pointer is set to new node instance on success
+ * @param config Node-wide configuration options set on startup
  * @param uptr User pointer to pass to functions/callbacks
  * @param tptr Thread pointer to pass to functions/callbacks resulting from this call
  * @param callbacks Callback function configuration
  * @param now Current clock in milliseconds
  * @return OK (0) or error code if a fatal error condition has occurred
  */
-ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node** node, void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now);
+ZT_SDK_API enum ZT_ResultCode ZT_Node_new(ZT_Node** node, const struct ZT_Node_Config* config, void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now);
 
 /**
  * Delete a node and free all resources it consumes

+ 4 - 3
node/Node.cpp

@@ -43,7 +43,7 @@ namespace ZeroTier {
 /* Public Node interface (C++, exposed via CAPI bindings)                   */
 /****************************************************************************/
 
-Node::Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now)
+Node::Node(void* uptr, void* tptr, const struct ZT_Node_Config* config, const struct ZT_Node_Callbacks* callbacks, int64_t now)
 	: _RR(this)
 	, RR(&_RR)
 	, _uPtr(uptr)
@@ -59,6 +59,7 @@ Node::Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, in
 		throw ZT_EXCEPTION_INVALID_ARGUMENT;
 	}
 	memcpy(&_cb, callbacks, sizeof(ZT_Node_Callbacks));
+	memcpy(&_config, config, sizeof(ZT_Node_Config));
 
 	// Initialize non-cryptographic PRNG from a good random source
 	Utils::getSecureRandom((void*)_prngState, sizeof(_prngState));
@@ -918,11 +919,11 @@ void Node::ncSendError(uint64_t nwid, uint64_t requestPacketId, const Address& d
 
 extern "C" {
 
-enum ZT_ResultCode ZT_Node_new(ZT_Node** node, void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now)
+enum ZT_ResultCode ZT_Node_new(ZT_Node** node, const struct ZT_Node_Config* config, void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now)
 {
 	*node = (ZT_Node*)0;
 	try {
-		*node = reinterpret_cast<ZT_Node*>(new ZeroTier::Node(uptr, tptr, callbacks, now));
+		*node = reinterpret_cast<ZT_Node*>(new ZeroTier::Node(uptr, tptr, config, callbacks, now));
 		return ZT_RESULT_OK;
 	}
 	catch (std::bad_alloc& exc) {

+ 14 - 6
node/Node.hpp

@@ -20,13 +20,10 @@
 #include "NetworkController.hpp"
 #include "Path.hpp"
 #include "RuntimeEnvironment.hpp"
-#include "Salsa20.hpp"
 #include "SelfAwareness.hpp"
 
-#include <map>
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <vector>
 
 // Bit mask for "expecting reply" hash
@@ -44,7 +41,7 @@ class World;
  */
 class Node : public NetworkController::Sender {
   public:
-	Node(void* uptr, void* tptr, const struct ZT_Node_Callbacks* callbacks, int64_t now);
+	Node(void* uptr, void* tptr, const struct ZT_Node_Config* config, const struct ZT_Node_Callbacks* callbacks, int64_t now);
 	virtual ~Node();
 
 	// Get rid of alignment warnings on 32-bit Windows and possibly improve performance
@@ -285,12 +282,22 @@ class Node : public NetworkController::Sender {
 
 	inline void setLowBandwidthMode(bool isEnabled)
 	{
-		_lowBandwidthMode = isEnabled;
+		_config.lowBandwidthMode = (int)isEnabled;
+	}
+
+	inline void setEncryptedHelloEnabled(bool isEnabled)
+	{
+		_config.enableEncryptedHello = (int)isEnabled;
 	}
 
 	inline bool lowBandwidthModeEnabled()
 	{
-		return _lowBandwidthMode;
+		return _config.lowBandwidthMode != 0;
+	}
+
+	inline bool encryptedHelloEnabled()
+	{
+		return _config.enableEncryptedHello != 0;
 	}
 
 	void initMultithreading(unsigned int concurrency, bool cpuPinningEnabled);
@@ -300,6 +307,7 @@ class Node : public NetworkController::Sender {
 	RuntimeEnvironment* RR;
 	void* _uPtr;   // _uptr (lower case) is reserved in Visual Studio :P
 	ZT_Node_Callbacks _cb;
+	ZT_Node_Config _config;
 
 	// For tracking packet IDs to filter out OK/ERROR replies to packets we did not send
 	uint8_t _expectingRepliesToBucketPtr[ZT_EXPECTING_REPLIES_BUCKET_MASK1 + 1];

+ 1 - 1
node/Peer.cpp

@@ -459,7 +459,7 @@ void Peer::sendHELLO(void* tPtr, const int64_t localSocket, const InetAddress& a
 	Metrics::pkt_hello_out++;
 
 	if (atAddress) {
-		outp.armor(_key, false, true, nullptr, _id);
+		outp.armor(_key, false, RR->node->encryptedHelloEnabled(), nullptr, _id);
 		RR->node->expectReplyTo(outp.packetId());
 		RR->node->putPacket(tPtr, RR->node->lowBandwidthModeEnabled() ? localSocket : -1, atAddress, outp.data(), outp.size());
 	}

+ 6 - 1
service/OneService.cpp

@@ -1158,7 +1158,11 @@ class OneServiceImpl : public OneService {
 				cb.eventCallback = SnodeEventCallback;
 				cb.pathCheckFunction = SnodePathCheckFunction;
 				cb.pathLookupFunction = SnodePathLookupFunction;
-				_node = new Node(this, (void*)0, &cb, OSUtils::now());
+				// These settings can get set later when local.conf is checked.
+				struct ZT_Node_Config config;
+				config.enableEncryptedHello = 0;
+				config.lowBandwidthMode = 0;
+				_node = new Node(this, (void*)0, &config, &cb, OSUtils::now());
 			}
 
 			// local.conf
@@ -2880,6 +2884,7 @@ class OneServiceImpl : public OneService {
 			fprintf(stderr, "WARNING: using manually-specified secondary and/or tertiary ports. This can cause NAT issues." ZT_EOL_S);
 		}
 		_portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"], true);
+		_node->setEncryptedHelloEnabled(OSUtils::jsonBool(settings["encryptedHelloEnabled"], false));
 		_node->setLowBandwidthMode(OSUtils::jsonBool(settings["lowBandwidthMode"], false));
 #if defined(__LINUX__) || defined(__FreeBSD__)
 		_multicoreEnabled = OSUtils::jsonBool(settings["multicoreEnabled"], false);

+ 1 - 1
version.h

@@ -27,7 +27,7 @@
 /**
  * Revision
  */
-#define ZEROTIER_ONE_VERSION_REVISION 2
+#define ZEROTIER_ONE_VERSION_REVISION 3
 
 /**
  * Build version