Ver Fonte

A bunch of warning removal, build fixes, and cleanup.

Adam Ierymenko há 5 anos atrás
pai
commit
6051c973d3

+ 22 - 28
attic/MIMC52.cpp

@@ -14,6 +14,7 @@
 #include "MIMC52.hpp"
 #include "SHA512.hpp"
 #include "Utils.hpp"
+#include "Salsa20.hpp"
 
 // This gets defined on any architecture whose FPU is not capable of doing the mulmod52() FPU trick.
 //#define ZT_MIMC52_NO_FPU
@@ -98,60 +99,52 @@ ZT_INLINE uint64_t modpow52(uint64_t a,uint64_t e,const uint64_t p) noexcept
 
 } // anonymous namespace
 
+#define ZT_MIMC52_ROUND_CONSTANT_COUNT 1048576
+
 uint64_t mimc52Delay(const void *const salt,const unsigned int saltSize,const unsigned long rounds)
 {
-	uint64_t hash[6];
-	SHA384(hash,salt,saltSize);
+	uint64_t hash[8];
+	SHA512(hash,salt,saltSize);
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-	uint64_t p = s_mimc52Primes[hash[0] & 511U];
+	const uint64_t p = s_mimc52Primes[hash[0] & 511U];
 	uint64_t x = hash[1] % p;
 #else
-	uint64_t p = s_mimc52Primes[Utils::swapBytes(hash[0]) & 511U];
+	const uint64_t p = s_mimc52Primes[Utils::swapBytes(hash[0]) & 511U];
 	uint64_t x = Utils::swapBytes(hash[1]) % p;
 #endif
 
-	//Speck128<8> roundConstantGenerator(hash + 2);
 	const uint64_t e = ((p * 2) - 1) / 3;
 	const uint64_t m52 = 0xfffffffffffffULL;
-	const uint64_t rmin1 = rounds - 1;
-	const uint64_t sxx = hash[4];
-#pragma unroll 16
-	for(unsigned long r=0;r<rounds;++r) {
-		uint64_t sx = sxx,sy = rmin1 - r;
-		//roundConstantGenerator.encryptXY(sx,sy);
-		x = (x - sy) & m52;
+	const uint32_t rminus1 = rounds - 1;
+	for(uint32_t r=0;r<rounds;++r) {
+		x = (x - (uint64_t)sy) & m52;
 		x = modpow52(x,e,p);
 	}
 
 	return x;
 }
 
-bool mimc52Verify(const void *const salt,const unsigned int saltSize,unsigned long rounds,const uint64_t proof)
+bool mimc52Verify(const void *const salt,const unsigned int saltSize,const unsigned long rounds,const uint64_t proof)
 {
 	uint64_t hash[6];
 	SHA384(hash,salt,saltSize);
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
-	uint64_t p = s_mimc52Primes[hash[0] & 511U];
-	uint64_t x = hash[1] % p;
-#else
-	uint64_t p = s_mimc52Primes[Utils::swapBytes(hash[0]) & 511U];
+	const uint64_t p = s_mimc52Primes[Utils::swapBytes(hash[0]) & 511U];
 	uint64_t x = Utils::swapBytes(hash[1]) % p;
+#else
+	const uint64_t p = s_mimc52Primes[hash[0] & 511U];
+	uint64_t x = hash[1] % p;
 #endif
 
-	//Speck128<8> roundConstantGenerator(hash + 2);
 	const uint64_t m52 = 0xfffffffffffffULL;
 	uint64_t y = proof & m52;
-	const uint64_t sxx = hash[4];
-#if !defined(ZT_MIMC52_NO_FPU)
-	double ii,of,pp = (double)p;
+#ifndef ZT_MIMC52_NO_FPU
+	double dy,ii,of,pp = (double)p;
 	uint64_t oi,one = 1;
 #endif
-#pragma unroll 16
 	for(unsigned long r=0;r<rounds;++r) {
-		uint64_t sx = sxx,sy = r;
-		//roundConstantGenerator.encryptXY(sx,sy);
 #ifdef ZT_MIMC52_NO_FPU
 #ifdef x64_cubemod
 		x64_cubemod(y,p);
@@ -160,18 +153,19 @@ bool mimc52Verify(const void *const salt,const unsigned int saltSize,unsigned lo
 #endif
 #else
 		// mulmod52(mulmod52(y,y,p),y,p)
-		of = (double)y;
+		dy = (double)y;
+		of = dy;
 		oi = y;
 		ii = (of * of) / pp;
 		y *= oi;
 		y -= ((uint64_t)ii - one) * p;
-		//y %= p;
-		ii = ((double)y * of) / pp;
+		//y %= p; // does not seem to be necessary
+		ii = (dy * of) / pp;
 		y *= oi;
 		y -= ((uint64_t)ii - one) * p;
 		y %= p;
 #endif
-		y = (y + sy) & m52;
+		y = (y + (uint64_t)sy) & m52;
 	}
 
 	return (y % p) == x;

+ 0 - 0
node/PeerList.hpp → attic/PeerList.hpp


+ 35 - 34
go/cmd/zerotier/cli/help.go

@@ -27,42 +27,43 @@ Licensed under the ZeroTier BSL (see LICENSE.txt)
 Usage: zerotier [-options] <command> [command args]
 
 Global Options:
-  -j                                   Output raw JSON where applicable
-  -p <path>                            Use alternate base path
-  -t <path>                            Use secret auth token from this file
+  -j                                    Output raw JSON where applicable
+  -p <path>                             Use alternate base path
+  -t <path>                             Load secret auth token from a file
+  -T <token>                            Set secret auth token on command line
 
 Commands:
-  help                                 Show this help
-  version                              Print version
-  service                              Start as service
-  status                               Show node status, identity, and config
-  peers                                List all VL1 peers
-  roots                                List root peers
-  addroot <path/URL to spec>           Add root
-  removeroot <address>                 Remove a peer from the root list
-  join <network ID> [fingerprint]      Join a virtual network
-  leave <network ID>                   Leave a virtual network
-  networks                             List VL2 virtual networks
-  network <network ID>                 Show verbose network info
-  set <network ID> [option] [value]    Get or set a network config option
-    manageips <boolean>                Is IP management allowed?
-    manageroutes <boolean>             Is route management allowed?
-    globalips <boolean>                Allow assignment of global IPs?
-    globalroutes <boolean>             Can global IP space routes be set?
-    defaultroute <boolean>             Can default route be overridden?
-  set [option] [value]                 Get or set a service config option
-    port <port>                        Primary P2P port
-    secondaryport <port/0>             Secondary P2P port (0 to disable)
-    blacklist cidr <IP/bits> <boolean> Toggle physical path blacklisting
-    blacklist if <prefix> <boolean>    Toggle interface prefix blacklisting
-    portmap <boolean>                  Toggle use of uPnP or NAT-PMP
-  identity <command> [args]            Identity management commands
-    new [c25519|p384]                  Create identity pair (default: c25519)
-    getpublic <identity>               Extract only public part of identity
-    validate <identity>                Locally validate an identity
-    sign <identity> <file>             Sign a file with an identity's key
-    verify <identity> <file> <sig>     Verify a signature
-    makeroot <identity> <address> ...  Make a root spec (see docs)
+  help                                  Show this help
+  version                               Print version
+  service                               Start as service
+  status                                Show node status, identity, and config
+  peers                                 List all VL1 peers
+  roots                                 List root peers
+  addroot <path | URL>                  Add root from root spec file or URL
+  removeroot <address>                  Remove a peer from the root list
+  join <network ID> [fingerprint]       Join a virtual network
+  leave <network ID>                    Leave a virtual network
+  networks                              List VL2 virtual networks
+  network <network ID>                  Show verbose network info
+  set <network ID> [option] [value]     Get or set a network config option
+    manageips <boolean>                 Is IP management allowed?
+    manageroutes <boolean>              Is route management allowed?
+    globalips <boolean>                 Allow assignment of global IPs?
+    globalroutes <boolean>              Can global IP space routes be set?
+    defaultroute <boolean>              Can default route be overridden?
+  set [option] [value]                  Get or set a service config option
+    port <port>                         Primary P2P port
+    secondaryport <port/0>              Secondary P2P port (0 to disable)
+    blacklist cidr <IP/bits> <boolean>  Toggle physical path blacklisting
+    blacklist if <prefix> <boolean>     Toggle interface prefix blacklisting
+    portmap <boolean>                   Toggle use of uPnP or NAT-PMP
+  identity <command> [args]             Identity management commands
+    new [c25519|p384]                   Create identity pair (default: c25519)
+    getpublic <identity>                Extract only public part of identity
+    validate <identity>                 Locally validate an identity
+    sign <identity> <file>              Sign a file with an identity's key
+    verify <identity> <file> <sig>      Verify a signature
+    makeroot <identity> <address> [...] Make a root spec (see docs)
 
 The 'service' command does not exit until the service receives a signal.
 This is typically run from launchd (Mac), systemd or init (Linux), a Windows

+ 5 - 0
go/cmd/zerotier/cli/identity.go

@@ -102,6 +102,11 @@ func Identity(args []string) {
 				}
 			}
 
+		case "makeroot":
+			if len(args) >= 2 {
+				//id := readIdentity(args[1])
+			}
+
 		}
 	}
 	Help()

+ 1 - 1
go/cmd/zerotier/cli/join.go

@@ -28,7 +28,7 @@ func Join(basePath, authToken string, args []string) {
 		os.Exit(1)
 	}
 
-	if len(args[0]) != 16 {
+	if len(args[0]) != zerotier.NetworkIDStringLength {
 		fmt.Printf("ERROR: invalid network ID: %s\n", args[0])
 		os.Exit(1)
 	}

+ 2 - 1
go/cmd/zerotier/cli/leave.go

@@ -17,6 +17,7 @@ import (
 	"fmt"
 	"os"
 	"strconv"
+	"zerotier/pkg/zerotier"
 )
 
 // Leave CLI command
@@ -26,7 +27,7 @@ func Leave(basePath, authToken string, args []string) {
 		os.Exit(1)
 	}
 
-	if len(args[0]) != 16 {
+	if len(args[0]) != zerotier.NetworkIDStringLength {
 		fmt.Printf("ERROR: invalid network ID: %s\n", args[0])
 		os.Exit(1)
 	}

+ 1 - 1
go/cmd/zerotier/cli/network.go

@@ -28,7 +28,7 @@ func Network(basePath, authToken string, args []string, jsonOutput bool) {
 		os.Exit(1)
 	}
 
-	if len(args[0]) != 16 {
+	if len(args[0]) != zerotier.NetworkIDStringLength {
 		fmt.Printf("ERROR: invalid network ID: %s\n", args[0])
 		os.Exit(1)
 	}

+ 0 - 52
go/cmd/zerotier/cli/setroot.go

@@ -1,52 +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"
-)
-
-// SetRoot CLI command, used for addroot and removeroot.
-func SetRoot(basePath, authToken string, args []string, root bool) {
-	if len(args) < 1 || len(args) > 2 {
-		Help()
-		os.Exit(1)
-	}
-
-	id := readIdentity(args[0])
-	if id == nil {
-		fmt.Printf("ERROR: invalid identity '%s' (tried literal or reading as file)\n",args[0])
-		os.Exit(1)
-	}
-
-	var bootstrap *zerotier.InetAddress
-	if len(args) == 2 {
-		bootstrap = zerotier.NewInetAddressFromString(args[1])
-		if bootstrap == nil || bootstrap.Nil() {
-			fmt.Printf("ERROR: invalid bootstrap address '%s'\n",args[1])
-			os.Exit(1)
-		}
-	}
-
-	var peer zerotier.PeerMutableFields
-	peer.Identity = id
-	peer.Bootstrap = bootstrap
-	peer.Root = &root
-	apiPost(basePath, authToken, "/peer/"+id.Address().String(), &peer, nil)
-	fmt.Printf("OK %s", id.String())
-	os.Exit(0)
-}

+ 22 - 21
go/cmd/zerotier/zerotier.go

@@ -74,13 +74,14 @@ func main() {
 	} else {
 		runtime.GOMAXPROCS(1)
 	}
-	debug.SetGCPercent(25)
+	debug.SetGCPercent(20)
 
 	globalOpts := flag.NewFlagSet("global", flag.ContinueOnError)
 	hflag := globalOpts.Bool("h", false, "") // support -h to be canonical with other Unix utilities
 	jflag := globalOpts.Bool("j", false, "")
 	pflag := globalOpts.String("p", "", "")
 	tflag := globalOpts.String("t", "", "")
+	tTflag := globalOpts.String("T", "", "")
 	err := globalOpts.Parse(os.Args[1:])
 	if err != nil {
 		cli.Help()
@@ -98,11 +99,6 @@ func main() {
 		cmdArgs = args[1:]
 	}
 
-	if *hflag {
-		cli.Help()
-		os.Exit(0)
-	}
-
 	basePath := zerotier.PlatformDefaultHomePath
 	if len(*pflag) > 0 {
 		basePath = *pflag
@@ -110,7 +106,14 @@ func main() {
 
 	var authToken string
 	if len(*tflag) > 0 {
-		authToken = *tflag
+		at, err := ioutil.ReadFile(*tflag)
+		if err != nil || len(at) == 0 {
+			fmt.Println("FATAL: unable to read API authorization token from file '" + *tflag + "'")
+			os.Exit(1)
+		}
+		authToken = strings.TrimSpace(string(at))
+	} else if len(*tTflag) > 0 {
+		authToken = strings.TrimSpace(*tTflag)
 	} else {
 		authToken = readAuthToken(basePath)
 	}
@@ -125,38 +128,36 @@ func main() {
 		os.Exit(0)
 	case "service":
 		cli.Service(basePath, authToken, cmdArgs)
-	case "status":
+	case "status", "info":
 		authTokenRequired(authToken)
 		cli.Status(basePath, authToken, cmdArgs, *jflag)
-	case "peers", "listpeers":
+	case "peers", "listpeers", "lspeers":
 		authTokenRequired(authToken)
 		cli.Peers(basePath, authToken, cmdArgs, *jflag, false)
-	case "roots", "listroots":
+	case "roots", "listroots", "lsroots":
 		authTokenRequired(authToken)
 		cli.Peers(basePath, authToken, cmdArgs, *jflag, true)
 	case "addroot":
-		authTokenRequired(authToken)
-		cli.SetRoot(basePath, authToken, cmdArgs, true)
+		// TODO
 	case "removeroot":
+		// TODO
+	case "join":
 		authTokenRequired(authToken)
-		cli.SetRoot(basePath, authToken, cmdArgs, false)
-	case "identity":
-		cli.Identity(cmdArgs)
+		cli.Join(basePath, authToken, cmdArgs)
+	case "leave":
+		authTokenRequired(authToken)
+		cli.Leave(basePath, authToken, cmdArgs)
 	case "networks", "listnetworks":
 		authTokenRequired(authToken)
 		cli.Networks(basePath, authToken, cmdArgs, *jflag)
 	case "network":
 		authTokenRequired(authToken)
 		cli.Network(basePath, authToken, cmdArgs, *jflag)
-	case "join":
-		authTokenRequired(authToken)
-		cli.Join(basePath, authToken, cmdArgs)
-	case "leave":
-		authTokenRequired(authToken)
-		cli.Leave(basePath, authToken, cmdArgs)
 	case "set":
 		authTokenRequired(authToken)
 		cli.Set(basePath, authToken, cmdArgs)
+	case "identity":
+		cli.Identity(cmdArgs)
 	}
 
 	cli.Help()

+ 26 - 0
go/pkg/zerotier/identity.go

@@ -20,6 +20,7 @@ import (
 	"bytes"
 	"encoding/hex"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"runtime"
 	"strings"
@@ -241,6 +242,31 @@ func (id *Identity) Verify(msg, sig []byte) bool {
 	return C.ZT_Identity_verify(id.cid, dataP, C.uint(len(msg)), unsafe.Pointer(&sig[0]), C.uint(len(sig))) != 0
 }
 
+// MakeRoot generates a root spec consisting of a serialized identity and a root locator.
+func (id *Identity) MakeRoot(addresses []InetAddress) ([]byte, error) {
+	if len(addresses) == 0 {
+		return nil, errors.New("at least one static address must be specified for a root")
+	}
+
+	id.cIdentity()
+	if uintptr(id.cid) == 0 {
+		return nil, errors.New("error initializing ZT_Identity")
+	}
+
+	ss := make([]C.sockaddr_storage, len(addresses))
+	for i := range addresses {
+		if !makeSockaddrStorage(addresses[i].IP, addresses[i].Port, &ss[i]) {
+			return nil, errors.New("invalid address in address list")
+		}
+	}
+	var buf [8192]byte
+	rl := C.ZT_Identity_makeRootSpecification(id.cid, C.int64_t(TimeMs()), &ss[0], C.uint(len(ss)), &buf[0], 8192)
+	if rl <= 0 {
+		return nil, errors.New("unable to make root specification (does identity contain a secret key?)")
+	}
+	return buf[0:int(rl)], nil
+}
+
 // Equals performs a deep equality test between this and another identity
 func (id *Identity) Equals(id2 *Identity) bool {
 	if id2 == nil {

+ 8 - 23
go/pkg/zerotier/localconfig.go

@@ -24,9 +24,6 @@ import (
 type LocalConfigPhysicalPathConfiguration struct {
 	// Blacklist flags this path as unusable for ZeroTier traffic
 	Blacklist bool
-
-	// TrustedPathID identifies a path for unencrypted/unauthenticated traffic
-	TrustedPathID uint64
 }
 
 // LocalConfigVirtualAddressConfiguration contains settings for virtual addresses
@@ -35,14 +32,6 @@ type LocalConfigVirtualAddressConfiguration struct {
 	Try []InetAddress `json:"try,omitempty"`
 }
 
-// ExternalAddress is an externally visible address
-type ExternalAddress struct {
-	InetAddress
-
-	// Permanent indicates that this address should be incorporated into this node's Locator
-	Permanent bool `json:"permanent"`
-}
-
 // LocalConfigSettings contains node settings
 type LocalConfigSettings struct {
 	// PrimaryPort is the main UDP port and must be set.
@@ -60,14 +49,14 @@ type LocalConfigSettings struct {
 	// LogSizeMax is the maximum size of the infoLog in kilobytes or 0 for no limit and -1 to disable logging
 	LogSizeMax int `json:"logSizeMax"`
 
-	// IP/port to bind for TCP access to control API (disabled if null)
+	// IP/port to bind for TCP access to control API (TCP API port disabled if null)
 	APITCPBindAddress *InetAddress `json:"apiTCPBindAddress,omitempty"`
 
 	// InterfacePrefixBlacklist are prefixes of physical network interface names that won't be used by ZeroTier (e.g. "lo" or "utun")
 	InterfacePrefixBlacklist []string `json:"interfacePrefixBlacklist,omitempty"`
 
 	// ExplicitAddresses are explicit IP/port addresses to advertise to other nodes, such as externally mapped ports on a router
-	ExplicitAddresses []ExternalAddress `json:"explicitAddresses,omitempty"`
+	ExplicitAddresses []InetAddress `json:"explicitAddresses,omitempty"`
 }
 
 // LocalConfig is the local.conf file and stores local settings for the node.
@@ -97,22 +86,18 @@ func (lc *LocalConfig) Read(p string, saveDefaultsIfNotExist bool, isTotallyNewN
 		lc.Virtual = make(map[Address]LocalConfigVirtualAddressConfiguration)
 		lc.Network = make(map[NetworkID]NetworkLocalSettings)
 
-		if isTotallyNewNode {
-			lc.Settings.PrimaryPort = 793
-		} 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.PortSearch = true
 		lc.Settings.PortMapping = true
 		lc.Settings.LogSizeMax = 128
-		if !isTotallyNewNode {
+
+		if !isTotallyNewNode && runtime.GOOS != "darwin" && runtime.GOOS != "windows" {
+			// If this doesn't look like a new node and it's not a desktop OS, go ahead
+			// and bind the local TCP API port so as not to break scripts.
 			lc.Settings.APITCPBindAddress = NewInetAddressFromString("127.0.0.1/9993")
 		}
+
 		switch runtime.GOOS {
 		case "windows":
 			lc.Settings.InterfacePrefixBlacklist = []string{"loopback"}

+ 3 - 0
go/pkg/zerotier/node.go

@@ -47,6 +47,9 @@ var nullLogger = log.New(ioutil.Discard, "", 0)
 
 // Network status states
 const (
+	NetworkIDStringLength = 16
+	AddressStringLength   = 10
+
 	NetworkStatusRequestConfiguration int = C.ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION
 	NetworkStatusOK                   int = C.ZT_NETWORK_STATUS_OK
 	NetworkStatusAccessDenied         int = C.ZT_NETWORK_STATUS_ACCESS_DENIED

+ 29 - 12
node/AES.hpp

@@ -261,7 +261,15 @@ public:
 	};
 
 	/**
-	 * Encryptor for GMAC-SIV
+	 * Encryptor for AES-GMAC-SIV.
+	 *
+	 * Encryption requires two passes. The first pass starts after init
+	 * with aad (if any) followed by update1() and finish1(). Then the
+	 * update2() and finish2() methods must be used over the same data
+	 * (but NOT AAD) again.
+	 *
+	 * This supports encryption of a maximum of 2^31 bytes of data per
+	 * call to init().
 	 */
 	class GMACSIVEncryptor
 	{
@@ -294,12 +302,12 @@ public:
 		}
 
 		/**
-		 * Process AAD (additional authenticated data) that is not being encrypted
+		 * Process AAD (additional authenticated data) that is not being encrypted.
 		 *
-		 * This must be called prior to update1, finish1, etc. if there is AAD to include
-		 * in the MAC that is not included in the plaintext.
+		 * If such data exists this must be called before update1() and finish1().
 		 *
-		 * This currently only supports one chunk of AAD. Don't call multiple times per message.
+		 * Note: current code only supports one single chunk of AAD. Don't call this
+		 * multiple times per message.
 		 *
 		 * @param aad Additional authenticated data
 		 * @param len Length of AAD in bytes
@@ -336,15 +344,22 @@ public:
 			// Compute 128-bit GMAC tag.
 			_gmac.finish(reinterpret_cast<uint8_t *>(tmp));
 
-			// Truncate to 64 bits, concatenate after 64-bit message IV, and encrypt with AES.
+			// Shorten to 64 bits, concatenate with message IV, and encrypt with AES to
+			// yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV
+			// this get split into the packet ID (64 bits) and the MAC (64 bits) in each
+			// packet and then recombined on receipt for legacy reasons (but with no
+			// cryptographic or performance impact).
 			_tag[1] = tmp[0] ^ tmp[1];
 			_ctr._aes.encrypt(_tag,_tag);
 
-			// Get CTR IV and 32-bit counter. The most significant bit of the 32-bit counter
-			// is masked to zero so the counter will never overflow, but the remaining bits
-			// are taken from the encrypted tag as they can count as additional bits of
-			// entropy for the CTR IV. We don't technically count these in figuring our
-			// worst case scenario bound, but they could be argued to add a little margin.
+			// Initialize CTR with 96-bit CTR nonce and 32-bit counter. The counter
+			// incorporates 31 more bits of entropy which should raise our security margin
+			// a bit, but this is not included in the worst case analysis of GMAC-SIV.
+			// The most significant bit of the counter is masked to zero to allow up to
+			// 2^31 bytes to be encrypted before the counter loops. Some CTR implementations
+			// increment the whole big-endian 128-bit integer in which case this could be
+			// used for more than 2^31 bytes, but ours does not for performance reasons
+			// and so 2^31 should be considered the input limit.
 			tmp[0] = _tag[0];
 			tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
 			_ctr.init(reinterpret_cast<const uint8_t *>(tmp),_output);
@@ -386,7 +401,9 @@ public:
 	};
 
 	/**
-	 * Decryptor for GMAC-SIV
+	 * Decryptor for AES-GMAC-SIV.
+	 *
+	 * GMAC-SIV decryption is single-pass. AAD (if any) must be processed first.
 	 */
 	class GMACSIVDecryptor
 	{

+ 0 - 1
node/CMakeLists.txt

@@ -32,7 +32,6 @@ set(core_headers
 	OS.hpp
 	Path.hpp
 	Peer.hpp
-	PeerList.hpp
 	Poly1305.hpp
 	Protocol.hpp
 	RuntimeEnvironment.hpp

+ 1 - 1
node/Dictionary.hpp

@@ -37,7 +37,7 @@ namespace ZeroTier {
  * compatibility.
  * 
  * Use of the append functions is faster than building and then encoding a
- * dictionary.
+ * dictionary for creating outbound packets.
  */
 class Dictionary
 {

+ 32 - 52
node/FCV.hpp

@@ -19,23 +19,15 @@
 #include <iterator>
 #include <algorithm>
 #include <memory>
-#include <cstring>
-#include <cstdlib>
 
 namespace ZeroTier {
 
 /**
  * FCV is a Fixed Capacity Vector
  *
- * Attempts to resize, push, or access this vector beyond its capacity will
- * silently fail. The [] operator is NOT bounds checked!
- *
  * This doesn't implement everything in std::vector, just what we need. It
  * also adds a few special things for use in ZT core code.
  *
- * Note that an FCV will be TriviallyCopyable IF and only if its contained
- * type is TriviallyCopyable. There's a const static checker for this.
- *
  * @tparam T Type to contain
  * @tparam C Maximum capacity of vector
  */
@@ -46,11 +38,11 @@ public:
 	typedef T * iterator;
 	typedef const T * const_iterator;
 
-	ZT_INLINE FCV() noexcept : _s(0) {} // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
-	ZT_INLINE FCV(const FCV &v) : _s(0) { *this = v; } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
+	ZT_INLINE FCV() noexcept : _s(0) {}
+	ZT_INLINE FCV(const FCV &v) : _s(0) { *this = v; }
 
 	template<typename I>
-	ZT_INLINE FCV(I i,I end) : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
+	ZT_INLINE FCV(I i,I end) :
 		_s(0)
 	{
 		while (i != end) {
@@ -63,7 +55,7 @@ public:
 
 	ZT_INLINE FCV &operator=(const FCV &v)
 	{
-		if (&v != this) {
+		if (likely(&v != this)) {
 			this->clear();
 			const unsigned int s = v._s;
 			_s = s;
@@ -85,25 +77,7 @@ public:
 	}
 
 	/**
-	 * Clear without calling destructors (same as unsafeResize(0))
-	 */
-	ZT_INLINE void unsafeClear() noexcept { _s = 0; }
-
-	/**
-	 * This does a straight copy of one vector's data to another
-	 *
-	 * @tparam C2 Inferred capacity of other vector
-	 * @param v Other vector to copy to this one
-	 */
-	template<unsigned int C2>
-	ZT_INLINE void unsafeAssign(const FCV<T,C2> &v) noexcept
-	{
-		_s = ((C2 > C)&&(v._s > C)) ? C : v._s;
-		Utils::copy(_m,v._m,_s * sizeof(T));
-	}
-
-	/**
-	 * Move contents from this vector to another and clear this vector
+	 * Move contents from this vector to another and clear this vector.
 	 *
 	 * @param v Target vector
 	 */
@@ -114,18 +88,29 @@ public:
 	}
 
 	ZT_INLINE iterator begin() noexcept { return reinterpret_cast<T *>(_m); }
-	ZT_INLINE const_iterator begin() const noexcept { return reinterpret_cast<const T *>(_m); }
 	ZT_INLINE iterator end() noexcept { return reinterpret_cast<T *>(_m) + _s; }
+	ZT_INLINE const_iterator begin() const noexcept { return reinterpret_cast<const T *>(_m); }
 	ZT_INLINE const_iterator end() const noexcept { return reinterpret_cast<const T *>(_m) + _s; }
 
-	ZT_INLINE T &operator[](const unsigned int i) noexcept { return reinterpret_cast<T *>(_m)[i]; }
-	ZT_INLINE const T &operator[](const unsigned int i) const noexcept { return reinterpret_cast<T *>(_m)[i]; }
+	ZT_INLINE T &operator[](const unsigned int i)
+	{
+		if (likely(i < _s))
+			return reinterpret_cast<T *>(_m)[i];
+		throw std::out_of_range("i > capacity");
+	}
+	ZT_INLINE const T &operator[](const unsigned int i) const
+	{
+		if (likely(i < _s))
+			return reinterpret_cast<const T *>(_m)[i];
+		throw std::out_of_range("i > capacity");
+	}
 
+	static constexpr unsigned int capacity() noexcept { return C; }
 	ZT_INLINE unsigned int size() const noexcept { return _s; }
 	ZT_INLINE bool empty() const noexcept { return (_s == 0); }
+
 	ZT_INLINE T *data() noexcept { return reinterpret_cast<T *>(_m); }
 	ZT_INLINE const T *data() const noexcept { return reinterpret_cast<const T *>(_m); }
-	static constexpr unsigned int capacity() noexcept { return C; }
 
 	/**
 	 * Push a value onto the back of this vector
@@ -136,8 +121,9 @@ public:
 	 */
 	ZT_INLINE void push_back(const T &v)
 	{
-		if (_s < C)
+		if (likely(_s < C))
 			new (reinterpret_cast<T *>(_m) + _s++) T(v);
+		else throw std::out_of_range("capacity exceeded");
 	}
 
 	/**
@@ -147,7 +133,7 @@ public:
 	 */
 	ZT_INLINE T &push()
 	{
-		if (_s < C) {
+		if (likely(_s < C)) {
 			return *(new(reinterpret_cast<T *>(_m) + _s++) T());
 		} else {
 			return *(reinterpret_cast<T *>(_m) + (C - 1));
@@ -161,7 +147,7 @@ public:
 	 */
 	ZT_INLINE T &push(const T &v)
 	{
-		if (_s < C) {
+		if (likely(_s < C)) {
 			return *(new(reinterpret_cast<T *>(_m) + _s++) T(v));
 		} else {
 			T &tmp = *(reinterpret_cast<T *>(_m) + (C - 1));
@@ -175,7 +161,7 @@ public:
 	 */
 	ZT_INLINE void pop_back()
 	{
-		if (_s != 0)
+		if (likely(_s != 0))
 			(reinterpret_cast<T *>(_m) + --_s)->~T();
 	}
 
@@ -186,8 +172,8 @@ public:
 	 */
 	ZT_INLINE void resize(unsigned int ns)
 	{
-		if (ns > C)
-			ns = C;
+		if (unlikely(ns > C))
+			throw std::out_of_range("capacity exceeded");
 		unsigned int s = _s;
 		while (s < ns)
 			new(reinterpret_cast<T *>(_m) + s++) T();
@@ -196,16 +182,6 @@ public:
 		_s = s;
 	}
 
-	/**
-	 * Resize without calling any constructors or destructors on T
-	 *
-	 * This must only be called if T is a primitive type or is TriviallyCopyable and
-	 * safe to initialize from undefined contents.
-	 *
-	 * @param ns New size (clipped to C if larger than capacity)
-	 */
-	ZT_INLINE void unsafeResize(const unsigned int ns) noexcept { _s = (ns > C) ? C : ns; }
-
 	/**
 	 * This is a bounds checked auto-resizing variant of the [] operator
 	 *
@@ -267,8 +243,12 @@ public:
 	ZT_INLINE bool operator>=(const FCV &v) const noexcept { return !(*this < v); }
 
 private:
-	unsigned int _s;
+#ifdef _MSC_VER
 	uint8_t _m[sizeof(T) * C];
+#else
+	__attribute__((aligned(16))) uint8_t _m[sizeof(T) * C];
+#endif
+	unsigned int _s;
 };
 
 } // namespace ZeroTier

+ 4 - 2
node/Identity.cpp

@@ -631,11 +631,13 @@ const ZT_Fingerprint *ZT_Identity_fingerprint(const ZT_Identity *id)
 
 int ZT_Identity_makeRootSpecification(ZT_Identity *id,int64_t ts,struct sockaddr_storage *addrs,unsigned int addrcnt,void *rootSpecBuf,unsigned int rootSpecBufSize)
 {
+	if ((!id)||(!addrs)||(!addrcnt)||(!rootSpecBuf))
+		return -1;
 	ZeroTier::Vector<ZeroTier::Endpoint> endpoints;
 	endpoints.reserve(addrcnt);
 	for(unsigned int i=0;i<addrcnt;++i)
-		endpoints.push_back(ZeroTier::Endpoint(ZeroTier::asInetAddress(addrs[i]));
-	return ZeroTier::Locator::makeRootSpecification(reinterpret_cast<const ZeroTier::Identity *>(id),endpoints,rootSpecBuf,rootSpecBufSize);
+		endpoints.push_back(ZeroTier::Endpoint(ZeroTier::asInetAddress(addrs[i])));
+	return ZeroTier::Locator::makeRootSpecification(*reinterpret_cast<const ZeroTier::Identity *>(id),ts,endpoints,rootSpecBuf,rootSpecBufSize);
 }
 
 ZT_SDK_API void ZT_Identity_delete(ZT_Identity *id)

+ 2 - 2
node/InetAddress.hpp

@@ -261,9 +261,9 @@ public:
 	{
 		switch (as.ss.ss_family) {
 			case AF_INET:
-				return Utils::ntoh((uint16_t) as.sa_in.sin_port);
+				return Utils::ntoh((uint16_t)as.sa_in.sin_port);
 			case AF_INET6:
-				return Utils::ntoh((uint16_t) as.sa_in6.sin6_port);
+				return Utils::ntoh((uint16_t)as.sa_in6.sin6_port);
 			default:
 				return 0;
 		}

+ 0 - 2
node/Membership.hpp

@@ -14,8 +14,6 @@
 #ifndef ZT_MEMBERSHIP_HPP
 #define ZT_MEMBERSHIP_HPP
 
-#include <cstdint>
-
 #include "Constants.hpp"
 #include "Credential.hpp"
 #include "Containers.hpp"

+ 1 - 1
node/Meter.hpp

@@ -44,7 +44,7 @@ public:
 	 * @param now Start time
 	 */
 	ZT_INLINE Meter() noexcept
-	{} // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init,hicpp-use-equals-default,modernize-use-equals-default)
+	{}
 
 	/**
 	 * Add a measurement

+ 4 - 7
node/NetworkConfig.hpp

@@ -14,13 +14,6 @@
 #ifndef ZT_NETWORKCONFIG_HPP
 #define ZT_NETWORKCONFIG_HPP
 
-#include <cstdint>
-#include <cstring>
-#include <cstdlib>
-#include <vector>
-#include <stdexcept>
-#include <algorithm>
-
 #include "Constants.hpp"
 #include "InetAddress.hpp"
 #include "MulticastGroup.hpp"
@@ -34,6 +27,10 @@
 #include "Utils.hpp"
 #include "Trace.hpp"
 #include "TriviallyCopyable.hpp"
+#include "Containers.hpp"
+
+#include <stdexcept>
+#include <algorithm>
 
 namespace ZeroTier {
 

+ 0 - 2
node/NetworkController.hpp

@@ -14,8 +14,6 @@
 #ifndef ZT_NETWORKCONFIGMASTER_HPP
 #define ZT_NETWORKCONFIGMASTER_HPP
 
-#include <cstdint>
-
 #include "Constants.hpp"
 #include "Dictionary.hpp"
 #include "NetworkConfig.hpp"

+ 3 - 5
node/Node.cpp

@@ -341,12 +341,10 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u
 
 ZT_ResultCode Node::addRoot(void *tPtr,const void *rdef,unsigned int rdeflen)
 {
+	if ((!rdef)||(rdeflen == 0))
+		return ZT_RESULT_ERROR_BAD_PARAMETER;
 	std::pair<Identity,Locator> r(Locator::parseRootSpecification(rdef,rdeflen));
-	if (r.first) {
-		RR->topology->addRoot(tPtr,r.first,r.second);
-		return ZT_RESULT_OK;
-	}
-	return ZT_RESULT_ERROR_BAD_PARAMETER;
+	return ((r.first)&&(RR->topology->addRoot(tPtr,r.first,r.second))) ? ZT_RESULT_OK : ZT_RESULT_ERROR_BAD_PARAMETER;
 }
 
 ZT_ResultCode Node::removeRoot(void *tPtr,const ZT_Fingerprint *fp)

+ 4 - 4
node/Node.hpp

@@ -130,7 +130,7 @@ public:
 			m_uPtr,
 			tPtr,
 			localSocket,
-			reinterpret_cast<const struct sockaddr_storage *>(&addr),
+			&addr.as.ss,
 			data,
 			len,
 			ttl) == 0);
@@ -306,9 +306,9 @@ public:
 	bool localControllerHasAuthorized(int64_t now,uint64_t nwid,const Address &addr) const;
 
 	// Implementation of NetworkController::Sender interface
-	virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig); // NOLINT(cppcoreguidelines-explicit-virtual-functions,hicpp-use-override,modernize-use-override)
-	virtual void ncSendRevocation(const Address &destination,const Revocation &rev); // NOLINT(cppcoreguidelines-explicit-virtual-functions,hicpp-use-override,modernize-use-override)
-	virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode); // NOLINT(cppcoreguidelines-explicit-virtual-functions,hicpp-use-override,modernize-use-override)
+	virtual void ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig);
+	virtual void ncSendRevocation(const Address &destination,const Revocation &rev);
+	virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode);
 
 private:
 	RuntimeEnvironment m_RR;

+ 1 - 1
node/Path.hpp

@@ -41,7 +41,7 @@ class Path
 	friend class Defragmenter;
 
 public:
-	ZT_INLINE Path(const int64_t l,const InetAddress &r) noexcept : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
+	ZT_INLINE Path(const int64_t l,const InetAddress &r) noexcept :
 		m_localSocket(l),
 		m_lastIn(0),
 		m_lastOut(0),

+ 2 - 2
node/Peer.hpp

@@ -327,10 +327,10 @@ public:
 
 	/**
 	 * Check whether a key is ephemeral
-	 * 
+	 *
 	 * This is used to check whether a packet is received with forward secrecy enabled
 	 * or not.
-	 * 
+	 *
 	 * @param k Key to check
 	 * @return True if this key is ephemeral, false if it's the long-lived identity key
 	 */

+ 4 - 4
node/Protocol.hpp

@@ -250,7 +250,7 @@
 #define ZT_PROTO_PACKET_VERB_INDEX        27
 
 #define ZT_PROTO_HELLO_NODE_META_INSTANCE_ID                "i"
-#define ZT_PROTO_HELLO_NODE_META_PREFERRED_SYMMETRIC        "a"
+#define ZT_PROTO_HELLO_NODE_META_PREFERRED_CIPHER_MODE      "a"
 #define ZT_PROTO_HELLO_NODE_META_LOCATOR                    "l"
 #define ZT_PROTO_HELLO_NODE_META_SOFTWARE_VENDOR            "s"
 #define ZT_PROTO_HELLO_NODE_META_COMPLIANCE                 "c"
@@ -340,7 +340,7 @@ enum Verb
 	 * Dictionary fields (defines start with ZT_PROTO_HELLO_NODE_META_):
 	 * 
 	 *   INSTANCE_ID - a 64-bit unique value generated on each node start
-	 *   PREFERRED_SYMMETRIC - preferred symmetric encryption mode
+	 *   PREFERRED_CIPHER_MODE - preferred symmetric encryption mode
 	 *   LOCATOR - signed record enumerating this node's trusted contact points
 	 *   EPHEMERAL_PUBLIC - Ephemeral public key(s)
 	 * 
@@ -419,10 +419,10 @@ enum Verb
 
 	/**
 	 * Relay-mediated NAT traversal or firewall punching initiation:
-	 *   <[1] flags (unused, currently 0)>
+	 *   <[1] flags>
 	 *   <[5] ZeroTier address of other peer>
 	 *   <[2] 16-bit number of endpoints where peer might be reached>
-	 *   <[...] endpoints to attempt>
+	 *   [<[...] endpoints to attempt>]
 	 *
 	 * Legacy packet format for pre-2.x peers:
 	 *   <[1] flags (unused, currently 0)>

+ 0 - 5
node/Revocation.hpp

@@ -14,11 +14,6 @@
 #ifndef ZT_REVOCATION_HPP
 #define ZT_REVOCATION_HPP
 
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <cstdint>
-
 #include "Constants.hpp"
 #include "Credential.hpp"
 #include "Address.hpp"

+ 0 - 5
node/Tag.hpp

@@ -14,11 +14,6 @@
 #ifndef ZT_TAG_HPP
 #define ZT_TAG_HPP
 
-#include <cstdint>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-
 #include "Constants.hpp"
 #include "Credential.hpp"
 #include "C25519.hpp"

+ 4 - 3
node/Topology.cpp

@@ -71,14 +71,15 @@ struct p_RootSortComparisonOperator
 	}
 };
 
-void Topology::addRoot(void *const tPtr, const Identity &id, const Locator &loc)
+bool Topology::addRoot(void *const tPtr, const Identity &id, const Locator &loc)
 {
-	if (id == RR->identity)
-		return;
+	if ((id == RR->identity) || (!id) || (!loc) || (!loc.verify(id)) || (!id.locallyValidate()))
+		return false;
 	RWMutex::Lock l1(m_peers_l);
 	m_roots[id] = loc;
 	m_updateRootPeers(tPtr);
 	m_writeRootList(tPtr);
+	return true;
 }
 
 bool Topology::removeRoot(void *const tPtr, const Fingerprint &fp)

+ 5 - 1
node/Topology.hpp

@@ -185,11 +185,15 @@ public:
 	/**
 	 * Add or update a root server and its locator
 	 *
+	 * This also validates the identity and checks the locator signature,
+	 * returning false if either of these is not valid.
+	 *
 	 * @param tPtr Thread pointer
 	 * @param id Root identity
 	 * @param loc Root locator
+	 * @return True if identity and locator are valid and root was added / updated
 	 */
-	void addRoot(void *tPtr,const Identity &id,const Locator &loc);
+	bool addRoot(void *tPtr,const Identity &id,const Locator &loc);
 
 	/**
 	 * Remove a root server's identity from the root server set

+ 0 - 56
node/TriviallyCopyable.hpp

@@ -53,62 +53,6 @@ public:
 		Utils::zero<sizeof(T)>(&obj);
 	}
 
-	/**
-	 * Copy a TriviallyCopyable object
-	 *
-	 * @tparam T Automatically inferred type of destination
-	 * @param dest Destination TriviallyCopyable object
-	 * @param src Source TriviallyCopyable object
-	 */
-	template<typename T>
-	static ZT_INLINE void memoryCopy(T *dest,const T *src) noexcept
-	{
-		mustBeTriviallyCopyable(dest);
-		Utils::copy<sizeof(T)>(dest,src);
-	}
-
-	/**
-	 * Copy a TriviallyCopyable object
-	 *
-	 * @tparam T Automatically inferred type of destination
-	 * @param dest Destination TriviallyCopyable object
-	 * @param src Source TriviallyCopyable object
-	 */
-	template<typename T>
-	static ZT_INLINE void memoryCopy(T *dest,const T &src) noexcept
-	{
-		mustBeTriviallyCopyable(src);
-		Utils::copy<sizeof(T)>(dest,&src);
-	}
-
-	/**
-	 * Copy a TriviallyCopyable object
-	 *
-	 * @tparam T Automatically inferred type of destination
-	 * @param dest Destination TriviallyCopyable object
-	 * @param src Source TriviallyCopyable object
-	 */
-	template<typename T>
-	static ZT_INLINE void memoryCopy(T &dest,const T *src) noexcept
-	{
-		mustBeTriviallyCopyable(dest);
-		Utils::copy<sizeof(T)>(&dest,src);
-	}
-
-	/**
-	 * Copy a TriviallyCopyable object
-	 *
-	 * @tparam T Automatically inferred type of destination
-	 * @param dest Destination TriviallyCopyable object
-	 * @param src Source TriviallyCopyable object
-	 */
-	template<typename T>
-	static ZT_INLINE void memoryCopy(T &dest,const T &src) noexcept
-	{
-		mustBeTriviallyCopyable(dest);
-		Utils::copy<sizeof(T)>(&dest,&src);
-	}
-
 private:
 	static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable &) noexcept {}
 	static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable *) noexcept {}