summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Network.cpp31
-rw-r--r--node/Network.hpp59
-rw-r--r--node/Packet.hpp110
-rw-r--r--node/Peer.cpp2
-rw-r--r--node/Peer.hpp29
5 files changed, 95 insertions, 136 deletions
diff --git a/node/Network.cpp b/node/Network.cpp
index 455820d9..2d43e383 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -147,6 +147,7 @@ Network::~Network()
SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t id)
throw(std::runtime_error)
{
+ // Tag to identify tap device -- used on some OSes like Windows
char tag[32];
Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)id);
@@ -159,8 +160,7 @@ SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t
nw->_ready = false; // disable handling of Ethernet frames during construct
nw->_r = renv;
nw->_tap = new EthernetTap(renv,tag,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());
- nw->_multicastPropagationBreadth = 0;
- nw->_multicastPropagationDepth = 0;
+ nw->_isOpen = false;
memset(nw->_etWhitelist,0,sizeof(nw->_etWhitelist));
nw->_id = id;
nw->_lastConfigUpdate = 0;
@@ -179,28 +179,39 @@ void Network::setConfiguration(const Network::Config &conf)
try {
if (conf.networkId() == _id) { // sanity check
_configuration = conf;
+
+ // Grab some things from conf for faster lookup and memoize them
_myCertificate = conf.certificateOfMembership();
_mcRates = conf.multicastRates();
- _multicastPropagationBreadth = conf.multicastPropagationBreadth();
- _multicastPropagationDepth = conf.multicastPropagationDepth();
+ _staticAddresses = conf.staticAddresses();
+ _isOpen = conf.isOpen();
+
_lastConfigUpdate = Utils::now();
- _tap->setIps(conf.staticAddresses());
+ _tap->setIps(_staticAddresses);
_tap->setDisplayName((std::string("ZeroTier One [") + conf.name() + "]").c_str());
+ // Expand ethertype whitelist into fast-lookup bit field
memset(_etWhitelist,0,sizeof(_etWhitelist));
std::set<unsigned int> wl(conf.etherTypes());
for(std::set<unsigned int>::const_iterator t(wl.begin());t!=wl.end();++t)
_etWhitelist[*t / 8] |= (unsigned char)(1 << (*t % 8));
+ // Save most recent configuration to disk in networks.d
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".conf");
if (!Utils::writeFile(confPath.c_str(),conf.toString())) {
LOG("error: unable to write network configuration file at: %s",confPath.c_str());
}
}
} catch ( ... ) {
+ // If conf is invalid, reset everything
_configuration = Config();
+
_myCertificate = CertificateOfMembership();
+ _mcRates = MulticastRates();
+ _staticAddresses.clear();
+ _isOpen = false;
+
_lastConfigUpdate = 0;
LOG("unexpected exception handling config for network %.16llx, retrying fetch...",(unsigned long long)_id);
}
@@ -209,9 +220,11 @@ void Network::setConfiguration(const Network::Config &conf)
void Network::requestConfiguration()
{
if (controller() == _r->identity.address()) {
+ // FIXME: Right now the netconf master cannot be a member of its own nets
LOG("unable to request network configuration for network %.16llx: I am the network master, cannot query self",(unsigned long long)_id);
return;
}
+
TRACE("requesting netconf for network %.16llx from netconf master %s",(unsigned long long)_id,controller().toString().c_str());
Packet outp(controller(),_r->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST);
outp.append((uint64_t)_id);
@@ -222,7 +235,7 @@ void Network::requestConfiguration()
void Network::addMembershipCertificate(const Address &peer,const CertificateOfMembership &cert)
{
Mutex::Lock _l(_lock);
- if (!_configuration.isOpen())
+ if (!_isOpen)
_membershipCertificates[peer] = cert;
}
@@ -231,7 +244,7 @@ bool Network::isAllowed(const Address &peer) const
// Exceptions can occur if we do not yet have *our* configuration.
try {
Mutex::Lock _l(_lock);
- if (_configuration.isOpen())
+ if (_isOpen)
return true;
std::map<Address,CertificateOfMembership>::const_iterator pc(_membershipCertificates.find(peer));
if (pc == _membershipCertificates.end())
@@ -249,9 +262,11 @@ void Network::clean()
{
std::string mcdbPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".mcerts");
+ _multicaster.clean(Utils::now());
+
Mutex::Lock _l(_lock);
- if ((!_id)||(_configuration.isOpen())) {
+ if ((!_id)||(_isOpen)) {
_membershipCertificates.clear();
Utils::rm(mcdbPath);
} else {
diff --git a/node/Network.hpp b/node/Network.hpp
index dd6c5254..9663b982 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -319,34 +319,6 @@ public:
}
/**
- * @return Breadth for multicast propagation
- */
- inline unsigned int multicastPropagationBreadth() const
- {
- const_iterator mcb(find("mcb"));
- if (mcb == end())
- return ZT_MULTICAST_DEFAULT_PROPAGATION_BREADTH;
- unsigned int mcb2 = Utils::hexStrToUInt(mcb->second.c_str());
- if (mcb2)
- return mcb2;
- return ZT_MULTICAST_DEFAULT_PROPAGATION_BREADTH;
- }
-
- /**
- * @return Depth for multicast propagation
- */
- inline unsigned int multicastPropagationDepth() const
- {
- const_iterator mcd(find("mcd"));
- if (mcd == end())
- return ZT_MULTICAST_DEFAULT_PROPAGATION_DEPTH;
- unsigned int mcd2 = Utils::hexStrToUInt(mcd->second.c_str());
- if (mcd2)
- return mcd2;
- return ZT_MULTICAST_DEFAULT_PROPAGATION_DEPTH;
- }
-
- /**
* @return Certificate of membership for this network, or empty cert if none
*/
inline CertificateOfMembership certificateOfMembership() const
@@ -462,6 +434,7 @@ private:
* Causes all persistent disk presence to be erased on delete
*/
inline void destroyOnDelete()
+ throw()
{
_destroyOnDelete = true;
}
@@ -498,12 +471,8 @@ public:
inline bool isOpen() const
throw()
{
- try {
- Mutex::Lock _l(_lock);
- return _configuration.isOpen();
- } catch ( ... ) {
- return false;
- }
+ Mutex::Lock _l(_lock);
+ return _isOpen;
}
/**
@@ -616,21 +585,12 @@ public:
}
/**
- * @return Breadth for multicast rumor mill propagation
- */
- inline unsigned int multicastPropagationBreadth() const
- throw()
- {
- return _multicastPropagationBreadth;
- }
-
- /**
- * @return Depth for multicast rumor mill propagation
+ * @return Multicaster for this network
*/
- inline unsigned int multicastPropagationDepth() const
+ inline Multicaster &multicaster()
throw()
{
- return _multicastPropagationDepth;
+ return _multicaster;
}
private:
@@ -653,12 +613,15 @@ private:
Config _configuration;
CertificateOfMembership _myCertificate; // memoized from _configuration
MulticastRates _mcRates; // memoized from _configuration
- unsigned int _multicastPropagationBreadth; // memoized from _configuration
- unsigned int _multicastPropagationDepth; // memoized from _configuration
+ std::set<InetAddress> _staticAddresses; // memoized from _configuration
+ bool _isOpen; // memoized from _configuration
// Ethertype whitelist bit field, set from config, for really fast lookup
unsigned char _etWhitelist[65536 / 8];
+ // Multicast propagation database
+ Multicaster _multicaster;
+
uint64_t _id;
volatile uint64_t _lastConfigUpdate;
volatile bool _destroyOnDelete;
diff --git a/node/Packet.hpp b/node/Packet.hpp
index a52c3409..cde381dd 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -814,75 +814,68 @@ public:
}
/**
- * Generate a message authenticationc code and set MAC field of packet
- *
- * For encrypted packets, this must be called after encryption.
+ * Armor packet for transport
*
- * @param key 256-bit (32 byte) key
+ * @param key 32-byte key
+ * @param encryptPayload If true, encrypt packet payload, else just MAC
*/
- inline void macSet(const void *key)
+ inline void armor(const void *key,bool encryptPayload)
{
+ unsigned char mangledKey[32];
+ unsigned char macKey[32];
unsigned char mac[16];
- unsigned char key2[32];
- _mangleKey((const unsigned char *)key,key2);
- unsigned int macLen = (size() >= ZT_PACKET_IDX_VERB) ? (size() - ZT_PACKET_IDX_VERB) : 0;
- Poly1305::compute(mac,field(ZT_PACKET_IDX_VERB,macLen),macLen,key2);
+ const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
+ unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen);
+
+ // Set flag now, since it affects key mangle function
+ if (encryptPayload)
+ (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_ENCRYPTED;
+ else (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
+
+ _mangleKey((const unsigned char *)key,mangledKey);
+ Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8));
+
+ // MAC key is always the first 32 bytes of the Salsa20 key stream
+ // This is the same technique DJB's NaCl library uses to use poly1305
+ memset(macKey,0,sizeof(macKey));
+ s20.encrypt(macKey,macKey,sizeof(macKey));
+
+ if (encryptPayload)
+ s20.encrypt(payload,payload,payloadLen);
+
+ Poly1305::compute(mac,payload,payloadLen,macKey);
memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8);
}
/**
- * Check the MAC of this packet's payload
- *
- * For encrypted packets, this must be checked before decryption.
+ * Verify and (if encrypted) decrypt packet
*
- * @param key 256-bit (32 byte) key
+ * @param key 32-byte key
+ * @return False if packet is invalid or failed MAC authenticity check
*/
- inline bool macVerify(const void *key) const
+ inline bool dearmor(const void *key)
{
+ unsigned char mangledKey[32];
+ unsigned char macKey[32];
unsigned char mac[16];
- unsigned char key2[32];
- if (size() < ZT_PACKET_IDX_VERB)
- return false; // incomplete packets fail
- _mangleKey((const unsigned char *)key,key2);
- unsigned int macLen = size() - ZT_PACKET_IDX_VERB;
- Poly1305::compute(mac,field(ZT_PACKET_IDX_VERB,macLen),macLen,key2);
- return Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8);
- }
+ const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
+ unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen);
- /**
- * Encrypt this packet
- *
- * @param key 256-bit (32 byte) key
- */
- inline void encrypt(const void *key)
- {
- (*this)[ZT_PACKET_IDX_FLAGS] |= ZT_PROTO_FLAG_ENCRYPTED;
- unsigned char key2[32];
- if (size() >= ZT_PACKET_IDX_VERB) {
- _mangleKey((const unsigned char *)key,key2);
- Salsa20 s20(key2,256,field(ZT_PACKET_IDX_IV,8));
- unsigned int encLen = size() - ZT_PACKET_IDX_VERB;
- unsigned char *const encBuf = field(ZT_PACKET_IDX_VERB,encLen);
- s20.encrypt(encBuf,encBuf,encLen);
- }
- }
+ _mangleKey((const unsigned char *)key,mangledKey);
+ Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8));
- /**
- * Decrypt this packet
- *
- * @param key 256-bit (32 byte) key
- */
- inline void decrypt(const void *key)
- {
- unsigned char key2[32];
- if (size() >= ZT_PACKET_IDX_VERB) {
- _mangleKey((const unsigned char *)key,key2);
- Salsa20 s20(key2,256,field(ZT_PACKET_IDX_IV,8));
- unsigned int decLen = size() - ZT_PACKET_IDX_VERB;
- unsigned char *const decBuf = field(ZT_PACKET_IDX_VERB,decLen);
- s20.decrypt(decBuf,decBuf,decLen);
+ memset(macKey,0,sizeof(macKey));
+ s20.encrypt(macKey,macKey,sizeof(macKey));
+ Poly1305::compute(mac,payload,payloadLen,macKey);
+ if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8))
+ return false;
+
+ if (((*this)[ZT_PACKET_IDX_FLAGS] & (char)ZT_PROTO_FLAG_ENCRYPTED)) {
+ s20.decrypt(payload,payload,payloadLen);
+ (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
}
- (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
+
+ return true;
}
/**
@@ -932,7 +925,7 @@ public:
memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)ucl),buf,ucl);
} else return false;
}
- (*this)[ZT_PACKET_IDX_VERB] &= ~ZT_PROTO_VERB_FLAG_COMPRESSED;
+ (*this)[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED);
}
return true;
}
@@ -946,11 +939,8 @@ private:
*/
inline void _mangleKey(const unsigned char *in,unsigned char *out) const
{
- // IV and source/destination addresses. Salsa uses the IV natively
- // so this is redundant there, but not harmful. But Poly1305 depends
- // on the key being mangled with the IV. Using the source and
- // destination addresses bifurcates the key space into a different
- // key space for each direction of the conversation.
+ // IV and source/destination addresses. Using the addresses divides the
+ // key space into two halves-- A->B and B->A (since order will change).
for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
out[i] = in[i] ^ (unsigned char)(*this)[i];
diff --git a/node/Peer.cpp b/node/Peer.cpp
index 7fd33ce9..1d22fd1f 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -54,7 +54,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
_vRevision(0),
_dirty(true)
{
- if (!myIdentity.agree(peerIdentity,_keys,sizeof(_keys)))
+ if (!myIdentity.agree(peerIdentity,_key,sizeof(_key)))
throw std::runtime_error("new peer identity key agreement failed");
}
diff --git a/node/Peer.hpp b/node/Peer.hpp
index cab9319b..38b93a32 100644
--- a/node/Peer.hpp
+++ b/node/Peer.hpp
@@ -52,7 +52,7 @@
* Max length of serialized peer record
*/
#define ZT_PEER_MAX_SERIALIZED_LENGTH ( \
- 64 + \
+ 32 + \
ZT_IDENTITY_MAX_BINARY_SERIALIZED_LENGTH + \
( ( \
(sizeof(uint64_t) * 4) + \
@@ -187,7 +187,7 @@ public:
}
/**
- * @return Time of most recent unicast frame (actual data transferred)
+ * @return Time of most recent unicast frame received
*/
uint64_t lastUnicastFrame() const
throw()
@@ -196,7 +196,7 @@ public:
}
/**
- * @return Time of most recent multicast frame
+ * @return Time of most recent multicast frame received
*/
uint64_t lastMulticastFrame() const
throw()
@@ -305,19 +305,10 @@ public:
/**
* @return 256-bit encryption key
*/
- inline const unsigned char *cryptKey() const
+ inline const unsigned char *key() const
throw()
{
- return _keys; // crypt key is first 32-byte key
- }
-
- /**
- * @return 256-bit MAC (message authentication code) key
- */
- inline const unsigned char *macKey() const
- throw()
- {
- return (_keys + 32); // mac key is second 32-byte key
+ return _key;
}
/**
@@ -369,8 +360,8 @@ public:
inline void serialize(Buffer<C> &b)
throw(std::out_of_range)
{
- b.append((unsigned char)2); // version
- b.append(_keys,sizeof(_keys));
+ b.append((unsigned char)3); // version
+ b.append(_key,sizeof(_key));
_id.serialize(b,false);
_ipv4p.serialize(b);
_ipv6p.serialize(b);
@@ -384,10 +375,10 @@ public:
{
unsigned int p = startAt;
- if (b[p++] != 2)
+ if (b[p++] != 3)
throw std::invalid_argument("Peer: deserialize(): version mismatch");
- memcpy(_keys,b.field(p,sizeof(_keys)),sizeof(_keys)); p += sizeof(_keys);
+ memcpy(_key,b.field(p,sizeof(_key)),sizeof(_key)); p += sizeof(_key);
p += _id.deserialize(b,p);
p += _ipv4p.deserialize(b,p);
p += _ipv6p.deserialize(b,p);
@@ -517,7 +508,7 @@ private:
bool fixed; // do not learn address from received packets
};
- unsigned char _keys[32 * 2]; // crypt key[32], mac key[32]
+ unsigned char _key[32]; // shared secret key agreed upon between identities
Identity _id;
WanPath _ipv4p;