Browse Source

Moar build fixes, clock perf improvement.

Adam Ierymenko 5 years ago
parent
commit
490b9c4d79

+ 3 - 1
doc/SECURITY.md

@@ -27,7 +27,7 @@ A ZeroTier identity is comprised of one or more cryptographic public keys and a
 #### Identity Types and Corresponding Algorithms
 #### Identity Types and Corresponding Algorithms
 
 
 * **Type 0** (v1.x and v2.x): one Curve25519 key for elliptic curve Diffie-Hellman and one Ed25519 key for Ed25519 signatures, with the address and fingerprint computed from a hash of both.
 * **Type 0** (v1.x and v2.x): one Curve25519 key for elliptic curve Diffie-Hellman and one Ed25519 key for Ed25519 signatures, with the address and fingerprint computed from a hash of both.
-* **Type 1** (v2.x only): Curve25519, Ed25519, and NIST P-384 public keys, with the latter being used for signatures (the Ed25519 key is still there but is presently unused) and with *both* keys being used for elliptic curve Diffie-Hellman key agreement. In key agreement the resulting raw secret keys are hashed together using SHA-384 to combine them and yield a single session key.
+* **Type 1** (v2.x only): Curve25519, Ed25519, and NIST P-384 public keys, with the latter being used for signatures (the Ed25519 key is still there but is presently unused) and with *both* Curve25519 and NIST P-384 being used for elliptic curve Diffie-Hellman key agreement. In key agreement the resulting raw secret keys are hashed together using SHA-384 to combine them and yield a single session key.
 
 
 Session keys resulting from identity key exchange and agreement are *long-lived keys* that remain static for the lifetime of a particular pair of identities. A different mechanism is used for ephemeral key negotiation.
 Session keys resulting from identity key exchange and agreement are *long-lived keys* that remain static for the lifetime of a particular pair of identities. A different mechanism is used for ephemeral key negotiation.
 
 
@@ -52,6 +52,8 @@ bzg7fc3sn46fzyxcxw2ev4c4m2u5fyisb3o4wz5hfmvexbzwk6et3fsglkdcn6nnjobxi3bq7hgxqox3
 
 
 These are too large to type but not to copy/paste, store in databases, or use in scripts and APIs.
 These are too large to type but not to copy/paste, store in databases, or use in scripts and APIs.
 
 
+Once a device has joined a network, network controllers will remember and check its full identity or identity fingerprint (depending on implementation) rather than just the device's ZeroTier address.
+
 ## VL1 Wire Protocol
 ## VL1 Wire Protocol
 
 
 ZeroTier's wire protocol is packet based with packets having the following format:
 ZeroTier's wire protocol is packet based with packets having the following format:

+ 4 - 0
go/cmd/zerotier-fuzz/zerotier-fuzz.go

@@ -0,0 +1,4 @@
+package main
+
+func main() {
+}

+ 0 - 1
go/cmd/zerotier/cli/help.go

@@ -37,7 +37,6 @@ Global Options:
 Commands:
 Commands:
   help                                 Show this help
   help                                 Show this help
   version                              Print version
   version                              Print version
-  selftest                             Run internal tests
   service                              Start as service
   service                              Start as service
   status                               Show ZeroTier status and config
   status                               Show ZeroTier status and config
   peers                                Show VL1 peers and link information
   peers                                Show VL1 peers and link information

+ 0 - 29
go/cmd/zerotier/cli/selftest.go

@@ -1,29 +0,0 @@
-/*
- * 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: 2024-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.
- */
-/****/
-
-package cli
-
-import (
-	"fmt"
-	"os"
-
-	"zerotier/pkg/zerotier"
-)
-
-func SelfTest() {
-	if !zerotier.SelfTest() {
-		fmt.Println("FAILED: at least one ZeroTier self-test reported failure.")
-		os.Exit(1)
-	}
-	os.Exit(0)
-}

+ 0 - 3
go/cmd/zerotier/zerotier.go

@@ -123,9 +123,6 @@ func main() {
 	case "version":
 	case "version":
 		fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
 		fmt.Printf("%d.%d.%d\n", zerotier.CoreVersionMajor, zerotier.CoreVersionMinor, zerotier.CoreVersionRevision)
 		os.Exit(0)
 		os.Exit(0)
-	case "selftest":
-		cli.SelfTest()
-		os.Exit(0)
 	case "service":
 	case "service":
 		cli.Service(basePath, authToken, cmdArgs)
 		cli.Service(basePath, authToken, cmdArgs)
 	case "status":
 	case "status":

+ 1 - 1
go/pkg/zerotier/identity.go

@@ -46,7 +46,7 @@ type Identity struct {
 	idtype     int
 	idtype     int
 	publicKey  []byte
 	publicKey  []byte
 	privateKey []byte
 	privateKey []byte
-	cid        unsafe.Pointer
+	cid        unsafe.Pointer // ZT_Identity
 }
 }
 
 
 func identityFinalizer(obj interface{}) {
 func identityFinalizer(obj interface{}) {

+ 6 - 2
go/pkg/zerotier/localconfig.go

@@ -45,10 +45,10 @@ type ExternalAddress struct {
 
 
 // LocalConfigSettings contains node settings
 // LocalConfigSettings contains node settings
 type LocalConfigSettings struct {
 type LocalConfigSettings struct {
-	// PrimaryPort is the main UDP port and must be set (defaults to 9993)
+	// PrimaryPort is the main UDP port and must be set.
 	PrimaryPort int `json:"primaryPort"`
 	PrimaryPort int `json:"primaryPort"`
 
 
-	// SecondaryPort is the secondary UDP port, set to 0 to disbale (picked at random by default)
+	// SecondaryPort is the secondary UDP port, set to 0 to disable (picked at random by default)
 	SecondaryPort int `json:"secondaryPort"`
 	SecondaryPort int `json:"secondaryPort"`
 
 
 	// PortSearch causes ZeroTier to try other ports automatically if it can't bind to configured ports
 	// PortSearch causes ZeroTier to try other ports automatically if it can't bind to configured ports
@@ -100,6 +100,10 @@ func (lc *LocalConfig) Read(p string, saveDefaultsIfNotExist bool, isTotallyNewN
 		if isTotallyNewNode {
 		if isTotallyNewNode {
 			lc.Settings.PrimaryPort = 793
 			lc.Settings.PrimaryPort = 793
 		} else {
 		} else {
+			// For legacy reasons we keep nodes that already existed prior to 2.0 (upgraded nodes)
+			// at 9993 by default if there is no existing primary port configured. This is for
+			// principle of least surprise since some admins may have special firewall rules for
+			// this port.
 			lc.Settings.PrimaryPort = 9993
 			lc.Settings.PrimaryPort = 9993
 		}
 		}
 		lc.Settings.SecondaryPort = unassignedPrivilegedPorts[randomUInt()%uint(len(unassignedPrivilegedPorts))]
 		lc.Settings.SecondaryPort = unassignedPrivilegedPorts[randomUInt()%uint(len(unassignedPrivilegedPorts))]

+ 2 - 2
node/AES.cpp

@@ -899,7 +899,7 @@ void AES::CTR::finish() noexcept
 // Software AES and AES key expansion ---------------------------------------------------------------------------------
 // Software AES and AES key expansion ---------------------------------------------------------------------------------
 
 
 #ifdef ZT_NO_UNALIGNED_ACCESS
 #ifdef ZT_NO_UNALIGNED_ACCESS
-static inline uint32_t readuint32_t(const void *in)
+static ZT_INLINE uint32_t readuint32_t(const void *in)
 {
 {
 	uint32_t v = ((const uint8_t *)in)[0];
 	uint32_t v = ((const uint8_t *)in)[0];
 	v <<= 8;
 	v <<= 8;
@@ -910,7 +910,7 @@ static inline uint32_t readuint32_t(const void *in)
 	v |= ((const uint8_t *)in)[3];
 	v |= ((const uint8_t *)in)[3];
 	return v;
 	return v;
 }
 }
-static inline void writeuint32_t(void *out,const uint32_t v)
+static ZT_INLINE void writeuint32_t(void *out,const uint32_t v)
 {
 {
 	((uint8_t *)out)[0] = (uint8_t)(v >> 24);
 	((uint8_t *)out)[0] = (uint8_t)(v >> 24);
 	((uint8_t *)out)[1] = (uint8_t)(v >> 16);
 	((uint8_t *)out)[1] = (uint8_t)(v >> 16);

+ 2 - 0
node/Address.hpp

@@ -24,6 +24,8 @@ namespace ZeroTier {
 
 
 /**
 /**
  * A ZeroTier address
  * A ZeroTier address
+ *
+ * This is merely a 40-bit short address packed into a uint64_t and wrapped with methods.
  */
  */
 class Address : public TriviallyCopyable
 class Address : public TriviallyCopyable
 {
 {

+ 0 - 26
node/LZ4.hpp

@@ -1,26 +0,0 @@
-/*
- * 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: 2024-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.
- */
-/****/
-
-#ifndef ZT_LZ4_HPP
-#define ZT_LZ4_HPP
-
-#include "Constants.hpp"
-
-namespace ZeroTier {
-
-int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1) noexcept;
-int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize) noexcept;
-
-} // namespace ZeroTier
-
-#endif

+ 32 - 23
node/Node.cpp

@@ -36,6 +36,13 @@ namespace ZeroTier {
 
 
 namespace {
 namespace {
 
 
+/**
+ * All core objects of a ZeroTier node.
+ *
+ * This is just a box that allows us to allocate all core objects
+ * and data structures at once for a bit of memory saves and improved
+ * cache adjacency.
+ */
 struct _NodeObjects
 struct _NodeObjects
 {
 {
 	ZT_INLINE _NodeObjects(RuntimeEnvironment *const RR,void *const tPtr) :
 	ZT_INLINE _NodeObjects(RuntimeEnvironment *const RR,void *const tPtr) :
@@ -190,11 +197,17 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
 	}
 	}
 }
 }
 
 
-struct _processBackgroundTasks_ping_eachPeer
+struct _processBackgroundTasks_eachPeer
 {
 {
-	int64_t now;
-	Node *parent;
-	void *tPtr;
+	ZT_INLINE _processBackgroundTasks_eachPeer(const int64_t now_,Node *const parent_,void *const tPtr_) :
+		now(now_),
+		parent(parent_),
+		tPtr(tPtr_),
+		online(false),
+		rootsNotOnline() {}
+	const int64_t now;
+	Node *const parent;
+	void *const tPtr;
 	bool online;
 	bool online;
 	std::vector<Address> rootsNotOnline;
 	std::vector<Address> rootsNotOnline;
 	ZT_INLINE void operator()(const SharedPtr<Peer> &peer,const bool isRoot)
 	ZT_INLINE void operator()(const SharedPtr<Peer> &peer,const bool isRoot)
@@ -209,22 +222,25 @@ struct _processBackgroundTasks_ping_eachPeer
 		}
 		}
 	}
 	}
 };
 };
-
-static uint8_t keepAlivePayload = 0; // junk payload for keepalive packets
-struct _processBackgroundTasks_path_keepalive
+struct _processBackgroundTasks_eachPath
 {
 {
-	int64_t now;
-	RuntimeEnvironment *RR;
-	void *tPtr;
+	ZT_INLINE _processBackgroundTasks_eachPath(const int64_t now_,const RuntimeEnvironment *const RR_,void *const tPtr_) :
+		now(now_),
+		RR(RR_),
+		tPtr(tPtr_),
+		keepAlivePayload((uint8_t)now_) {}
+	const int64_t now;
+	const RuntimeEnvironment *const RR;
+	void *const tPtr;
+	uint8_t keepAlivePayload;
 	ZT_INLINE void operator()(const SharedPtr<Path> &path)
 	ZT_INLINE void operator()(const SharedPtr<Path> &path)
 	{
 	{
 		if ((now - path->lastOut()) >= ZT_PATH_KEEPALIVE_PERIOD) {
 		if ((now - path->lastOut()) >= ZT_PATH_KEEPALIVE_PERIOD) {
 			++keepAlivePayload;
 			++keepAlivePayload;
-			path->send(RR,tPtr,&keepAlivePayload,1,now);
+			path->send(RR,tPtr,&keepAlivePayload,sizeof(keepAlivePayload),now);
 		}
 		}
 	}
 	}
 };
 };
-
 ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline)
 ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline)
 {
 {
 	_now = now;
 	_now = now;
@@ -233,12 +249,8 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int
 	if ((now - _lastPing) >= ZT_PEER_PING_PERIOD) {
 	if ((now - _lastPing) >= ZT_PEER_PING_PERIOD) {
 		_lastPing = now;
 		_lastPing = now;
 		try {
 		try {
-			_processBackgroundTasks_ping_eachPeer pf;
-			pf.now = now;
-			pf.parent = this;
-			pf.tPtr = tPtr;
-			pf.online = false;
-			RR->topology->eachPeerWithRoot<_processBackgroundTasks_ping_eachPeer &>(pf);
+			_processBackgroundTasks_eachPeer pf(now,this,tPtr);
+			RR->topology->eachPeerWithRoot<_processBackgroundTasks_eachPeer &>(pf);
 
 
 			if (pf.online != _online) {
 			if (pf.online != _online) {
 				_online = pf.online;
 				_online = pf.online;
@@ -300,11 +312,8 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int
 
 
 	if ((now - _lastPathKeepaliveCheck) >= ZT_PATH_KEEPALIVE_PERIOD) {
 	if ((now - _lastPathKeepaliveCheck) >= ZT_PATH_KEEPALIVE_PERIOD) {
 		_lastPathKeepaliveCheck = now;
 		_lastPathKeepaliveCheck = now;
-		_processBackgroundTasks_path_keepalive pf;
-		pf.now = now;
-		pf.RR = RR;
-		pf.tPtr = tPtr;
-		RR->topology->eachPath<_processBackgroundTasks_path_keepalive &>(pf);
+		_processBackgroundTasks_eachPath pf(now,RR,tPtr);
+		RR->topology->eachPath<_processBackgroundTasks_eachPath &>(pf);
 	}
 	}
 
 
 	int64_t earliestAlarmAt = 0x7fffffffffffffffLL;
 	int64_t earliestAlarmAt = 0x7fffffffffffffffLL;

+ 10 - 0
osdep/OSUtils.cpp

@@ -30,6 +30,16 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
+#ifdef __APPLE__
+static clock_serv_t _machGetRealtimeClock() noexcept
+{
+	clock_serv_t c;
+	host_get_clock_service(mach_host_self(),CALENDAR_CLOCK,&c);
+	return c;
+}
+static clock_serv_t s_machRealtimeClock = _machGetRealtimeClock();
+#endif
+
 unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...)
 unsigned int OSUtils::ztsnprintf(char *buf,unsigned int len,const char *fmt,...)
 {
 {
 	va_list ap;
 	va_list ap;

+ 27 - 4
osdep/OSUtils.hpp

@@ -32,6 +32,12 @@
 #include <unistd.h>
 #include <unistd.h>
 #endif
 #endif
 
 
+#ifdef __APPLE__
+#include <mach/mach.h>
+#include <mach/clock.h>
+#include <mach/mach_time.h>
+#endif
+
 #ifndef OMIT_JSON_SUPPORT
 #ifndef OMIT_JSON_SUPPORT
 #include "../ext/json/json.hpp"
 #include "../ext/json/json.hpp"
 #endif
 #endif
@@ -43,6 +49,11 @@ namespace ZeroTier {
  */
  */
 class OSUtils
 class OSUtils
 {
 {
+private:
+#ifdef __APPLE__
+	static clock_serv_t s_machRealtimeClock;
+#endif
+
 public:
 public:
 	/**
 	/**
 	 * Variant of snprintf that is portable and throws an exception
 	 * Variant of snprintf that is portable and throws an exception
@@ -161,14 +172,26 @@ public:
 		tmp.LowPart = ft.dwLowDateTime;
 		tmp.LowPart = ft.dwLowDateTime;
 		tmp.HighPart = ft.dwHighDateTime;
 		tmp.HighPart = ft.dwHighDateTime;
 		return (int64_t)( ((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds );
 		return (int64_t)( ((tmp.QuadPart - 116444736000000000LL) / 10000L) + st.wMilliseconds );
+#else
+#ifdef __LINUX__
+		timespec ts;
+#ifdef CLOCK_REALTIME_COARSE
+		clock_gettime(CLOCK_REALTIME_COARSE,&ts);
+#else
+		clock_gettime(CLOCK_REALTIME,&ts);
+#endif
+		return ( (1000LL * (int64_t)ts.tv_sec) + ((int64_t)(ts.tv_nsec / 1000000)) );
+#else
+#ifdef __APPLE__
+		mach_timespec_t mts;
+		clock_get_time(s_machRealtimeClock,&mts);
+		return ( (1000LL * (int64_t)mts.tv_sec) + ((int64_t)(mts.tv_nsec / 1000000)) );
 #else
 #else
 		timeval tv;
 		timeval tv;
-// #ifdef __LINUX__
-// 		syscall(SYS_gettimeofday,&tv,0); /* fix for musl libc broken gettimeofday bug */
-// #else
 		gettimeofday(&tv,(struct timezone *)0);
 		gettimeofday(&tv,(struct timezone *)0);
-// #endif
 		return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) );
 		return ( (1000LL * (int64_t)tv.tv_sec) + (int64_t)(tv.tv_usec / 1000) );
+#endif
+#endif
 #endif
 #endif
 	};
 	};