Adam Ierymenko 6 tahun lalu
induk
melakukan
54a1bbd016

+ 3 - 2
controller/EmbeddedNetworkController.cpp

@@ -469,10 +469,11 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule)
 
 } // anonymous namespace
 
-EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPath, int listenPort, MQConfig *mqc) :
+EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc) :
 	_startTime(OSUtils::now()),
 	_listenPort(listenPort),
 	_node(node),
+	_ztPath(ztPath),
 	_path(dbPath),
 	_sender((NetworkController::Sender *)0),
 	_db(this),
@@ -506,7 +507,7 @@ void EmbeddedNetworkController::init(const Identity &signingId,Sender *sender)
 #endif
 
 	std::string lfJSON;
-	OSUtils::readFile((_path + ZT_PATH_SEPARATOR_S ".." ZT_PATH_SEPARATOR_S "local.conf").c_str(),lfJSON);
+	OSUtils::readFile((_ztPath + ZT_PATH_SEPARATOR_S "local.conf").c_str(),lfJSON);
 	if (lfJSON.length() > 0) {
 		nlohmann::json lfConfig(OSUtils::jsonParse(lfJSON));
 		nlohmann::json &settings = lfConfig["settings"];

+ 3 - 1
controller/EmbeddedNetworkController.hpp

@@ -64,9 +64,10 @@ class EmbeddedNetworkController : public NetworkController,public DB::ChangeList
 public:
 	/**
 	 * @param node Parent node
+	 * @param ztPath ZeroTier base path
 	 * @param dbPath Database path (file path or database credentials)
 	 */
-	EmbeddedNetworkController(Node *node,const char *dbPath, int listenPort, MQConfig *mqc = NULL);
+	EmbeddedNetworkController(Node *node,const char *ztPath,const char *dbPath, int listenPort, MQConfig *mqc = NULL);
 	virtual ~EmbeddedNetworkController();
 
 	virtual void init(const Identity &signingId,Sender *sender);
@@ -149,6 +150,7 @@ private:
 	const int64_t _startTime;
 	int _listenPort;
 	Node *const _node;
+	std::string _ztPath;
 	std::string _path;
 	Identity _signingId;
 	std::string _signingIdAddressString;

+ 9 - 16
node/Constants.hpp

@@ -60,8 +60,6 @@
 #endif
 
 #ifdef __APPLE__
-#define likely(x) __builtin_expect((x),1)
-#define unlikely(x) __builtin_expect((x),0)
 #include <TargetConditionals.h>
 #ifndef __UNIX_LIKE__
 #define __UNIX_LIKE__
@@ -79,7 +77,7 @@
 #ifndef __BSD__
 #define __BSD__
 #endif
-#include <machine/endian.h>
+#include <sys/endian.h>
 #ifndef __BYTE_ORDER
 #define __BYTE_ORDER _BYTE_ORDER
 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
@@ -109,14 +107,14 @@
 #endif
 #endif
 
-// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86/x64.
+// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86 and x86_64.
 #if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386)))
 #ifndef ZT_NO_TYPE_PUNNING
 #define ZT_NO_TYPE_PUNNING
 #endif
 #endif
 
-// Assume little endian if not defined
+// Assume little endian if not defined on Mac and Windows as these don't run on any BE architectures.
 #if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
 #undef __BYTE_ORDER
 #undef __LITTLE_ENDIAN
@@ -156,7 +154,7 @@
 #endif
 #endif
 
-#ifdef __WINDOWS__
+#if defined(__WINDOWS__) && !defined(__GNUC__) && !defined (__clang__) && !defined(__INTEL_COMPILER)
 #define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
 #else
 #define ZT_PACKED_STRUCT(D) D __attribute__((packed))
@@ -178,7 +176,7 @@
 #define ZT_ADDRESS_RESERVED_PREFIX 0xff
 
 /**
- * Default MTU used for Ethernet tap device
+ * Default virtual network MTU (not physical)
  */
 #define ZT_DEFAULT_MTU 2800
 
@@ -188,17 +186,17 @@
 #define ZT_MAX_PACKET_FRAGMENTS 7
 
 /**
- * Size of RX queue
+ * Size of RX queue in packets
  */
 #define ZT_RX_QUEUE_SIZE 32
 
 /**
- * Size of TX queue
+ * Size of TX queue in packets
  */
 #define ZT_TX_QUEUE_SIZE 32
 
 /**
- * Length of secret key in bytes -- 256-bit -- do not change
+ * Length of peer shared secrets (256-bit, do not change)
  */
 #define ZT_PEER_SECRET_KEY_LENGTH 32
 
@@ -232,7 +230,7 @@
  *
  * The protocol allows up to 7, but we limit it to something smaller.
  */
-#define ZT_RELAY_MAX_HOPS 3
+#define ZT_RELAY_MAX_HOPS 4
 
 /**
  * Expire time for multicast 'likes' and indirect multicast memberships in ms
@@ -261,11 +259,6 @@
  */
 #define ZT_PING_CHECK_INVERVAL 5000
 
-/**
- * How often the local.conf file is checked for changes (service, should be moved there)
- */
-#define ZT_LOCAL_CONF_FILE_CHECK_INTERVAL 10000
-
 /**
  * How frequently to check for changes to the system's network interfaces. When
  * the service decides to use this constant it's because we want to react more

+ 0 - 67
node/ECC384.cpp

@@ -135,72 +135,6 @@ static uint64_t curve_b[NUM_ECC_DIGITS] = CONCAT(Curve_B_, ECC_CURVE);
 static EccPoint curve_G = CONCAT(Curve_G_, ECC_CURVE);
 static uint64_t curve_n[NUM_ECC_DIGITS] = CONCAT(Curve_N_, ECC_CURVE);
 
-#if 0
-#if (defined(_WIN32) || defined(_WIN64))
-/* Windows */
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <wincrypt.h>
-
-static int getRandomNumber(uint64_t *p_vli)
-{
-	HCRYPTPROV l_prov;
-	if(!CryptAcquireContext(&l_prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
-	{
-		return 0;
-	}
-
-	CryptGenRandom(l_prov, ECC_BYTES, (BYTE *)p_vli);
-	CryptReleaseContext(l_prov, 0);
-	
-	return 1;
-}
-
-#else /* _WIN32 */
-
-/* Assume that we are using a POSIX-like system with /dev/urandom or /dev/random. */
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#ifndef O_CLOEXEC
-	#define O_CLOEXEC 0
-#endif
-
-static int getRandomNumber(uint64_t *p_vli)
-{
-	int l_fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
-	if(l_fd == -1)
-	{
-		l_fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
-		if(l_fd == -1)
-		{
-			return 0;
-		}
-	}
-	
-	char *l_ptr = (char *)p_vli;
-	size_t l_left = ECC_BYTES;
-	while(l_left > 0)
-	{
-		int l_read = read(l_fd, l_ptr, l_left);
-		if(l_read <= 0)
-		{ // read failed
-			close(l_fd);
-			return 0;
-		}
-		l_left -= l_read;
-		l_ptr += l_read;
-	}
-	
-	close(l_fd);
-	return 1;
-}
-
-#endif /* _WIN32 */
-#endif
-
 // Use ZeroTier's secure PRNG
 static inline int getRandomNumber(uint64_t *p_vli)
 {
@@ -515,7 +449,6 @@ static inline void vli_square(uint64_t *p_result, uint64_t *p_left)
 
 #endif /* SUPPORTS_INT128 */
 
-
 /* Computes p_result = (p_left + p_right) % p_mod.
    Assumes that p_left < p_mod and p_right < p_mod, p_result != p_mod. */
 static inline void vli_modAdd(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, uint64_t *p_mod)

+ 2 - 2
node/ECC384.hpp

@@ -26,7 +26,7 @@
 
 // This is glue code to ease the use of the NIST P-384 elliptic curve.
 
-// Note that some of the code inside ECC384.cpp is third party code and
+// Note that most of the code inside ECC384.cpp is third party code and
 // is under the BSD 2-clause license rather than ZeroTier's license.
 
 #ifndef ZT_ECC384_HPP
@@ -55,7 +55,7 @@
 #define ZT_ECC384_SIGNATURE_SIZE 96
 
 /**
- * Size of shared secret generated by ECDH key agreement
+ * Size of raw shared secret generated by ECDH key agreement
  */
 #define ZT_ECC384_SHARED_SECRET_SIZE 48
 

+ 1 - 0
node/Identity.cpp

@@ -122,6 +122,7 @@ void Identity::generate(const Type t)
 		case P384: {
 			do {
 				ECC384GenerateKey(_k.t1.pub,_k.t1.priv);
+				// TODO
 				SHA512::hash(digest,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
 				_address.setTo(digest + 59,ZT_ADDRESS_LENGTH);
 			} while (_address.isReserved());

+ 23 - 2
node/Identity.hpp

@@ -57,8 +57,8 @@ class Identity
 public:
 	enum Type
 	{
-		C25519 = 0, // Curve25519 and Ed25519
-		P384 = 1    // NIST P-384 ECDH and ECDSA
+		C25519 = 0, // Curve25519 and Ed25519 (1.0 and 2.0, default)
+		P384 = 1    // NIST P-384 ECDH and ECDSA (2.0+ only)
 	};
 
 	Identity() { memset(reinterpret_cast<void *>(this),0,sizeof(Identity)); }
@@ -128,6 +128,27 @@ public:
 		return false;
 	}
 
+	/**
+	 * Compute the SHA512 hash of our public key
+	 * 
+	 * @param sha Buffer to receive hash bytes
+	 * @return True on success, false if identity is empty or invalid
+	 */
+	inline bool sha512PublicKey(void *sha) const
+	{
+		if (_hasPrivate) {
+			switch(_type) {
+				case C25519:
+					SHA512::hash(sha,_k.t0.pub.data,ZT_C25519_PUBLIC_KEY_LEN);
+					return true;
+				case P384:
+					SHA512::hash(sha,_k.t1.pub,ZT_ECC384_PUBLIC_KEY_SIZE);
+					return true;
+			}
+		}
+		return false;
+	}
+
 	/**
 	 * Sign a message with this identity (private key required)
 	 *

+ 0 - 68
node/Locator.cpp

@@ -1,68 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2019  ZeroTier, Inc.  https://www.zerotier.com/
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * You can be released from the requirements of the license by purchasing
- * a commercial license. Buying such a license is mandatory as soon as you
- * develop commercial closed-source software that incorporates or links
- * directly against ZeroTier software without disclosing the source code
- * of your own application.
- */
-
-#include "Locator.hpp"
-#include "Utils.hpp"
-
-#include <string.h>
-#include <stdlib.h>
-
-#define ZT_LOCATOR_SIGNING_BUFFER_SIZE (64 + (18 * ZT_LOCATOR_MAX_PHYSICAL_ENDPOINTS) + (256 * ZT_LOCATOR_MAX_VIRTUAL_ENDPOINTS))
-
-namespace ZeroTier {
-
-void Locator::sign(const Identity &id,const Identity &organization,const int64_t timestamp)
-{
-	Buffer<ZT_LOCATOR_SIGNING_BUFFER_SIZE> *const sb = new Buffer<ZT_LOCATOR_SIGNING_BUFFER_SIZE>();
-	_ts = timestamp;
-	_id = id;
-	_organization = organization;
-	serialize(*sb,true);
-	if (id)
-		_signatureLength = id.sign(sb->data(),sb->size(),_signature,sizeof(_signature));
-	if (organization)
-		_orgSignatureLength = organization.sign(sb->data(),sb->size(),_orgSignature,sizeof(_orgSignature));
-	delete sb;
-}
-
-bool Locator::verify() const
-{
-	Buffer<ZT_LOCATOR_SIGNING_BUFFER_SIZE> *const sb = new Buffer<ZT_LOCATOR_SIGNING_BUFFER_SIZE>();
-	serialize(*sb,true);
-	bool ok = _id.verify(sb->data(),sb->size(),_signature,_signatureLength);
-	if ((ok)&&(_organization))
-		ok &= _organization.verify(sb->data(),sb->size(),_orgSignature,_orgSignatureLength);
-	delete sb;
-	return ok;
-}
-
-void Locator::generateDNSRecords(char *buf,unsigned int buflen)
-{
-	Buffer<ZT_LOCATOR_SIGNING_BUFFER_SIZE> *const sb = new Buffer<ZT_LOCATOR_SIGNING_BUFFER_SIZE>();
-	delete sb;
-}
-
-} // namespace ZeroTier

+ 13 - 66
node/Locator.hpp

@@ -30,97 +30,44 @@
 #include "Constants.hpp"
 #include "Identity.hpp"
 #include "InetAddress.hpp"
+#include "Utils.hpp"
 
+#include <algorithm>
 #include <vector>
 
-#define ZT_LOCATOR_MAX_PHYSICAL_ENDPOINTS 32
-#define ZT_LOCATOR_MAX_VIRTUAL_ENDPOINTS 32
-
 namespace ZeroTier {
 
 /**
  * Signed information about a node's location on the network
+ * 
+ * A locator can be stored in DNS as a series of TXT records with a DNS name
+ * that includes a public key that can be used to validate the locator's
+ * signature. That way DNS records can't be spoofed even if no DNSSEC or
+ * anything else is present to secure DNS.
  */
 class Locator
 {
 public:
 	Locator() :
-		_signatureLength(0),
-		_orgSignatureLength(0) {}
-
-	inline void addLocation(const InetAddress &phy) { if (_physical.size() < ZT_LOCATOR_MAX_PHYSICAL_ENDPOINTS) _physical.push_back(phy); }
-	inline void addLocation(const Identity &v) { if (_virtual.size() < ZT_LOCATOR_MAX_VIRTUAL_ENDPOINTS) _virtual.push_back(v); }
+		_signatureLength(0) {}
 
-	inline const std::vector<InetAddress> &physical() const { return _physical; }
+	inline const std::vector<InetAddress> &phy() const { return _physical; }
 	inline const std::vector<Identity> &virt() const { return _virtual; }
 
-	void sign(const Identity &id,const Identity &organization,const int64_t timestamp);
-	bool verify() const;
-
-	void generateDNSRecords(char *buf,unsigned int buflen);
-
-	template<unsigned int C>
-	inline void serialize(Buffer<C> &b,const bool forSign = false) const
+	inline bool sign(const Identity &signingId)
 	{
-		if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
-
-		b.append((uint64_t)_ts);
-		_id.serialize(b,false);
-		_organization.serialize(b,false);
-		b.append((uint16_t)_physical.size());
-		for(std::vector<InetAddress>::const_iterator i(_physical.begin());i!=_physical.end();++i)
-			i->serialize(b);
-		b.append((uint16_t)_virtual.size());
-		for(std::vector<InetAddress>::const_iterator i(_virtual.begin());i!=_virtual.end();++i)
-			i->serialize(b,false);
-		if (!forSign) {
-			b.append((uint16_t)_signatureLength);
-			b.append(_signature,_signatureLength);
-			b.append((uint16_t)_orgSignatureLength);
-			b.append(_orgSignature,_orgSignatureLength);
-		}
-		b.append((uint16_t)0); // length of additional fields, currently 0
-
-		if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
-	}
-
-	template<unsigned int C>
-	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
-	{
-		unsigned int p = startAt;
-
-		_ts = (uint64_t)b.template at<uint64_t>(p); p += 8;
-		p += _id.deserialize(b,p);
-		p += _organization.deserialize(b,p);
-		unsigned int cnt = b.template at<uint16_t>(p); p += 2;
-		if (cnt > ZT_LOCATOR_MAX_PHYSICAL_ENDPOINTS)
-			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
-		_physical.resize(cnt);
-		for(std::vector<InetAddress>::iterator i(_physical.begin());i!=_physical.end();++i)
-			p += i->deserialize(b,p);
-		cnt = b.template at<uint16_t>(p); p += 2;
-		if (cnt > ZT_LOCATOR_MAX_VIRTUAL_ENDPOINTS)
-			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
-		_virtual.resize(cnt);
-		for(std::vector<Identity>::iterator i(_virtual.begin());i!=_virtual.end();++i)
-			p += i->deserialize(b,p);
-		p += 2 + b.template at<uint16_t>(p);
-		if (p > b.size())
-			throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
-
-		return (p - startAt);
+		std::sort(_physical.begin(),_physical.end());
+		std::sort(_virtual.begin(),_virtual.end());
+		_id = signingId;
 	}
 
 private:
 	int64_t _ts;
 	Identity _id;
-	Identity _organization;
 	std::vector<InetAddress> _physical;
 	std::vector<Identity> _virtual;
 	unsigned int _signatureLength;
-	unsigned int _orgSignatureLength;
 	uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
-	uint8_t _orgSignature[ZT_SIGNATURE_BUFFER_SIZE];
 };
 
 } // namespace ZeroTier

+ 24 - 32
node/Membership.hpp

@@ -108,9 +108,9 @@ public:
 	 */
 	inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
 	{
-		if (nconf.isPublic()) return true;
-		if (_com.timestamp() <= _comRevocationThreshold) return false;
-		return nconf.com.agreesWith(_com);
+		if (nconf.isPublic()) return true; // public network
+		if (_com.timestamp() <= _comRevocationThreshold) return false; // COM has been revoked
+		return nconf.com.agreesWith(_com); // check timestamp agreement window
 	}
 
 	inline bool recentlyAssociated(const int64_t now) const
@@ -119,7 +119,7 @@ public:
 	}
 
 	/**
-	 * Check whether the peer represented by this Membership owns a given resource
+	 * Check whether the peer represented by this Membership owns a given address
 	 *
 	 * @tparam Type of resource: InetAddress or MAC
 	 * @param nconf Our network config
@@ -127,8 +127,10 @@ public:
 	 * @return True if this peer has a certificate of ownership for the given resource
 	 */
 	template<typename T>
-	inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const
+	inline bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const
 	{
+		if (_isUnspoofableAddress(nconf,r))
+			return true;
 		uint32_t *k = (uint32_t *)0;
 		CertificateOfOwnership *v = (CertificateOfOwnership *)0;
 		Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
@@ -136,7 +138,7 @@ public:
 			if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r)))
 				return true;
 		}
-		return _isV6NDPEmulated(nconf,r);
+		return false;
 	}
 
 	/**
@@ -152,29 +154,10 @@ public:
 		return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
 	}
 
-	/**
-	 * Validate and add a credential if signature is okay and it's otherwise good
-	 */
 	AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com);
-
-	/**
-	 * Validate and add a credential if signature is okay and it's otherwise good
-	 */
 	AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag);
-
-	/**
-	 * Validate and add a credential if signature is okay and it's otherwise good
-	 */
 	AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap);
-
-	/**
-	 * Validate and add a credential if signature is okay and it's otherwise good
-	 */
 	AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
-
-	/**
-	 * Validate and add a credential if signature is okay and it's otherwise good
-	 */
 	AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev);
 
 	/**
@@ -186,20 +169,29 @@ public:
 	void clean(const int64_t now,const NetworkConfig &nconf);
 
 	/**
-	 * Generates a key for the internal use in indexing credentials by type and credential ID
+	 * Generates a key for internal use in indexing credentials by type and credential ID
 	 */
 	static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); }
 
 private:
-	inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const MAC &m) const { return false; }
-	inline bool _isV6NDPEmulated(const NetworkConfig &nconf,const InetAddress &ip) const
+	// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT
+	// address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
+	// always return true for them. A certificate is not required for these.
+	inline bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
+	inline bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
 	{
-		if ((ip.isV6())&&(nconf.ndpEmulation())&&((InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip))||(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip)))) {
-			return true;
-		}
-		return false;
+		return (
+			(ip.ss_family == AF_INET6)&&
+			(nconf.ndpEmulation())&&
+			(
+				(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip))||
+				(InetAddress::makeIpv6rfc4193(nconf.networkId,nconf.issuedTo.toInt()).ipsEqual(ip))
+			)
+		);
 	}
 
+	// This compares the remote credential's timestamp to the timestamp in our network config
+	// plus or minus the permitted maximum timestamp delta.
 	template<typename C>
 	inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
 	{

+ 2 - 2
node/Network.cpp

@@ -399,9 +399,9 @@ static _doZtFilterResult _doZtFilter(
 					}
 					if (inbound) {
 						if (membership) {
-							if ((src)&&(membership->hasCertificateOfOwnershipFor<InetAddress>(nconf,src)))
+							if ((src)&&(membership->peerOwnsAddress<InetAddress>(nconf,src)))
 								ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED;
-							if (membership->hasCertificateOfOwnershipFor<MAC>(nconf,macSource))
+							if (membership->peerOwnsAddress<MAC>(nconf,macSource))
 								ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED;
 						}
 					} else {

+ 10 - 5
node/Utils.cpp

@@ -213,9 +213,11 @@ int Utils::b32d(const char *encoded, uint8_t *result, int bufSize)
 
 int Utils::b32e(const uint8_t *data,int length,char *result,int bufSize)
 {
-  if (length < 0 || length > (1 << 28))
+  if (length < 0 || length > (1 << 28)) {
+		result[0] = (char)0;
     return -1;
-  int count = 0;
+	}
+	int count = 0;
   if (length > 0) {
     int buffer = data[0];
     int next = 1;
@@ -237,9 +239,12 @@ int Utils::b32e(const uint8_t *data,int length,char *result,int bufSize)
       result[count++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"[index];
     }
   }
-  if (count < bufSize)
-    result[count] = (char)0;
-  return count;
+  if (count < bufSize) {
+		result[count] = (char)0;
+		return count;
+	}
+	result[0] = (char)0;
+	return -1;
 }
 
 } // namespace ZeroTier

+ 0 - 4
node/Utils.hpp

@@ -38,10 +38,6 @@
 #include <vector>
 #include <map>
 
-#if defined(__FreeBSD__)
-#include <sys/endian.h>
-#endif
-
 #include "Constants.hpp"
 
 namespace ZeroTier {

+ 4 - 1
service/OneService.cpp

@@ -181,6 +181,9 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; }
 // TCP activity timeout
 #define ZT_TCP_ACTIVITY_TIMEOUT 60000
 
+// How often local.conf is checked for changes
+#define ZT_LOCAL_CONF_FILE_CHECK_INTERVAL 10000
+
 #if ZT_VAULT_SUPPORT
 size_t curlResponseWrite(void *ptr, size_t size, size_t nmemb, std::string *data)
 {
@@ -753,7 +756,7 @@ public:
 			OSUtils::rmDashRf((_homePath + ZT_PATH_SEPARATOR_S "iddb.d").c_str());
 
 			// Network controller is now enabled by default for desktop and server
-			_controller = new EmbeddedNetworkController(_node,_controllerDbPath.c_str(),_ports[0], _mqc);
+			_controller = new EmbeddedNetworkController(_node,_homePath.c_str(),_controllerDbPath.c_str(),_ports[0], _mqc);
 			_node->setNetconfMaster((void *)_controller);
 
 			// Join existing networks in networks.d