This commit is contained in:
Adam Ierymenko 2019-08-07 11:20:12 -05:00
parent 455cd5551b
commit 54a1bbd016
No known key found for this signature in database
GPG Key ID: 1657198823E52A61
14 changed files with 94 additions and 268 deletions

View File

@ -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"];

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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());

View File

@ -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)
*

View File

@ -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

View File

@ -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) {}
_signatureLength(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); }
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

View File

@ -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
{

View File

@ -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 {

View File

@ -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

View File

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

View File

@ -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