summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ZeroTierOne.h28
-rw-r--r--node/IncomingPacket.cpp26
-rw-r--r--node/Node.cpp12
-rw-r--r--node/Node.hpp13
-rw-r--r--node/Packet.hpp50
-rw-r--r--node/Switch.cpp7
-rw-r--r--node/Topology.hpp53
-rw-r--r--version.h2
8 files changed, 164 insertions, 27 deletions
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index d46c64b8..f5523461 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -117,6 +117,11 @@ extern "C" {
#define ZT_MAX_PEER_NETWORK_PATHS 4
/**
+ * Maximum number of trusted physical network paths
+ */
+#define ZT_MAX_TRUSTED_PATHS 16
+
+/**
* Maximum number of hops in a ZeroTier circuit test
*
* This is more or less the max that can be fit in a given packet (with
@@ -1838,6 +1843,29 @@ void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned
void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs);
/**
+ * Set trusted paths
+ *
+ * A trusted path is a physical network (network/bits) over which both
+ * encryption and authentication can be skipped to improve performance.
+ * Each trusted path must have a non-zero unique ID that is the same across
+ * all participating nodes.
+ *
+ * We don't recommend using trusted paths at all unless you really *need*
+ * near-bare-metal performance. Even on a LAN authentication and encryption
+ * are never a bad thing, and anything that introduces an "escape hatch"
+ * for encryption should be treated with the utmost care.
+ *
+ * Calling with NULL pointers for networks and ids and a count of zero clears
+ * all trusted paths.
+ *
+ * @param node Node instance
+ * @param networks Array of [count] networks
+ * @param ids Array of [count] corresponding non-zero path IDs (zero path IDs are ignored)
+ * @param count Number of trusted paths-- values greater than ZT_MAX_TRUSTED_PATHS are clipped
+ */
+void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count);
+
+/**
* Do things in the background until Node dies
*
* This function can be called from one or more background threads to process
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp
index 871297f7..fb4562ab 100644
--- a/node/IncomingPacket.cpp
+++ b/node/IncomingPacket.cpp
@@ -42,9 +42,21 @@ namespace ZeroTier {
bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred)
{
- const Address sourceAddress(source());
try {
- if ((cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
+ // Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear)
+ const unsigned int c = cipher();
+ bool trusted = false;
+ if (c == ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH) {
+ // If this is marked as a packet via a trusted path, check source address and path ID.
+ // Obviously if no trusted paths are configured this always returns false and such
+ // packets are dropped on the floor.
+ if (RR->topology->shouldInboundPathBeTrusted(_remoteAddress,trustedPathId())) {
+ trusted = true;
+ } else {
+ TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %.16llx@%s is not trusted!",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),trustedPathId(),_remoteAddress.toString().c_str());
+ return true;
+ }
+ } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
// Unencrypted HELLOs require some potentially expensive verification, so
// do this in the background if background processing is enabled.
if ((RR->dpEnabled > 0)&&(!deferred)) {
@@ -59,12 +71,16 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred)
}
}
+ const Address sourceAddress(source());
SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
if (peer) {
- if (!dearmor(peer->key())) {
- TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),size());
- return true;
+ if (!trusted) {
+ if (!dearmor(peer->key())) {
+ TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),size());
+ return true;
+ }
}
+
if (!uncompress()) {
TRACE("dropped packet from %s(%s), compressed data invalid",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
return true;
diff --git a/node/Node.cpp b/node/Node.cpp
index bedbba94..058df32d 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -745,6 +745,11 @@ void Node::postCircuitTestReport(const ZT_CircuitTestReport *report)
(reinterpret_cast<void (*)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)>((*i)->_internalPtr))(reinterpret_cast<ZT_Node *>(this),*i,report);
}
+void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count)
+{
+ RR->topology->setTrustedPaths(reinterpret_cast<const InetAddress *>(networks),ids,count);
+}
+
} // namespace ZeroTier
/****************************************************************************/
@@ -1014,6 +1019,13 @@ void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs)
} catch ( ... ) {}
}
+void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count)
+{
+ try {
+ reinterpret_cast<ZeroTier::Node *>(node)->setTrustedPaths(networks,ids,count);
+ } catch ( ... ) {}
+}
+
void ZT_Node_backgroundThreadMain(ZT_Node *node)
{
try {
diff --git a/node/Node.hpp b/node/Node.hpp
index 6ac23ca0..0a39d1ee 100644
--- a/node/Node.hpp
+++ b/node/Node.hpp
@@ -248,26 +248,15 @@ public:
*/
inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,nwid,nuptr,op,nc); }
- /**
- * @return True if we appear to be online
- */
inline bool online() const throw() { return _online; }
#ifdef ZT_TRACE
void postTrace(const char *module,unsigned int line,const char *fmt,...);
#endif
- /**
- * @return Next 64-bit random number (not for cryptographic use)
- */
uint64_t prng();
-
- /**
- * Post a circuit test report to any listeners for a given test ID
- *
- * @param report Report (includes test ID)
- */
void postCircuitTestReport(const ZT_CircuitTestReport *report);
+ void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count);
private:
inline SharedPtr<Network> _network(uint64_t nwid) const
diff --git a/node/Packet.hpp b/node/Packet.hpp
index 79fff344..3d95b0ba 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -57,11 +57,13 @@
* + Supports in-band world (root server definition) updates
* + Clustering! (Though this will work with protocol v4 clients.)
* + Otherwise backward compatible with protocol v4
- * 6 - 1.1.5 ... CURRENT
+ * 6 - 1.1.5 ... 1.1.10
* + Deprecate old dictionary-based network config format
* + Introduce new binary serialized network config and meta-data
+ * 7 - 1.1.10 -- CURRENT
+ * + Introduce trusted paths for local SDN use
*/
-#define ZT_PROTO_VERSION 6
+#define ZT_PROTO_VERSION 7
/**
* Minimum supported protocol version
@@ -100,10 +102,21 @@
#define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 1
/**
- * DEPRECATED payload encrypted flag, will be removed for re-use soon.
+ * Cipher suite: NONE
*
- * This has been replaced by the three-bit cipher suite selection field where
- * a value of 0 indicates unencrypted (but authenticated) messages.
+ * This differs from POLY1305/NONE in that *no* crypto is done, not even
+ * authentication. This is for trusted local LAN interconnects for internal
+ * SDN use within a data center.
+ *
+ * For this mode the MAC field becomes a trusted path ID and must match the
+ * configured ID of a trusted path or the packet is discarded.
+ */
+#define ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH 2
+
+/**
+ * DEPRECATED payload encrypted flag, may be re-used in the future.
+ *
+ * This has been replaced by the three-bit cipher suite selection field.
*/
#define ZT_PROTO_FLAG_ENCRYPTED 0x80
@@ -337,7 +350,7 @@ namespace ZeroTier {
* <[5] destination ZT address>
* <[5] source ZT address>
* <[1] flags/cipher/hops>
- * <[8] 64-bit MAC>
+ * <[8] 64-bit MAC (or trusted path ID in trusted path mode)>
* [... -- begin encryption envelope -- ...]
* <[1] encrypted flags (MS 3 bits) and verb (LS 5 bits)>
* [... verb-specific payload ...]
@@ -1218,7 +1231,6 @@ public:
*/
inline unsigned int cipher() const
{
- // Note: this uses the new cipher spec field, which is incompatible with <1.0.0 peers
return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3);
}
@@ -1229,13 +1241,31 @@ public:
{
unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
- // DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers
+ // Set DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers
if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
b |= ZT_PROTO_FLAG_ENCRYPTED;
else b &= (~ZT_PROTO_FLAG_ENCRYPTED);
}
/**
+ * Get the trusted path ID for this packet (only meaningful if cipher is trusted path)
+ *
+ * @return Trusted path ID (from MAC field)
+ */
+ inline uint64_t trustedPathId() const { return at<uint64_t>(ZT_PACKET_IDX_MAC); }
+
+ /**
+ * Set this packet's trusted path ID and set the cipher spec to trusted path
+ *
+ * @param tpid Trusted path ID
+ */
+ inline void setTrusted(const uint64_t tpid)
+ {
+ setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH);
+ setAt(ZT_PACKET_IDX_MAC,tpid);
+ }
+
+ /**
* Get this packet's unique ID (the IV field interpreted as uint64_t)
*
* @return Packet ID
@@ -1278,6 +1308,10 @@ public:
/**
* Verify and (if encrypted) decrypt packet
*
+ * This does not handle trusted path mode packets and will return false
+ * for these. These are handled in IncomingPacket if the sending physical
+ * address and MAC field match a trusted path.
+ *
* @param key 32-byte key
* @return False if packet is invalid or failed MAC authenticity check
*/
diff --git a/node/Switch.cpp b/node/Switch.cpp
index b134cc69..bf3afe33 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -849,7 +849,12 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
unsigned int chunkSize = std::min(tmp.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU);
tmp.setFragmented(chunkSize < tmp.size());
- tmp.armor(peer->key(),encrypt);
+ const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address());
+ if (trustedPathId) {
+ tmp.setTrusted(trustedPathId);
+ } else {
+ tmp.armor(peer->key(),encrypt);
+ }
if (viaPath->send(RR,tmp.data(),chunkSize,now)) {
if (chunkSize < tmp.size()) {
diff --git a/node/Topology.hpp b/node/Topology.hpp
index 86fbb011..03c491e5 100644
--- a/node/Topology.hpp
+++ b/node/Topology.hpp
@@ -28,6 +28,7 @@
#include <utility>
#include "Constants.hpp"
+#include "../include/ZeroTierOne.h"
#include "Address.hpp"
#include "Identity.hpp"
@@ -252,12 +253,64 @@ public:
*/
inline bool amRoot() const throw() { return _amRoot; }
+ /**
+ * Get the outbound trusted path ID for a physical address, or 0 if none
+ *
+ * @param physicalAddress Physical address to which we are sending the packet
+ * @return Trusted path ID or 0 if none (0 is not a valid trusted path ID)
+ */
+ inline uint64_t getOutboundPathTrust(const InetAddress &physicalAddress)
+ {
+ for(unsigned int i=0;i<_trustedPathCount;++i) {
+ if (_trustedPathNetworks[i].containsAddress(physicalAddress))
+ return _trustedPathIds[i];
+ }
+ return 0;
+ }
+
+ /**
+ * Check whether in incoming trusted path marked packet is valid
+ *
+ * @param physicalAddress Originating physical address
+ * @param trustedPathId Trusted path ID from packet (from MAC field)
+ */
+ inline bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId)
+ {
+ for(unsigned int i=0;i<_trustedPathCount;++i) {
+ if ((_trustedPathIds[i] == trustedPathId)&&(_trustedPathNetworks[i].containsAddress(physicalAddress)))
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Set trusted paths in this topology
+ *
+ * @param networks Array of networks (prefix/netmask bits)
+ * @param ids Array of trusted path IDs
+ * @param count Number of trusted paths (if larger than ZT_MAX_TRUSTED_PATHS overflow is ignored)
+ */
+ inline void setTrustedPaths(const InetAddress *networks,const uint64_t *ids,unsigned int count)
+ {
+ if (count > ZT_MAX_TRUSTED_PATHS)
+ count = ZT_MAX_TRUSTED_PATHS;
+ Mutex::Lock _l(_lock);
+ for(unsigned int i=0;i<count;++i) {
+ _trustedPathIds[i] = ids[i];
+ _trustedPathNetworks[i] = networks[i];
+ }
+ _trustedPathCount = count;
+ }
+
private:
Identity _getIdentity(const Address &zta);
void _setWorld(const World &newWorld);
const RuntimeEnvironment *const RR;
+ uint64_t _trustedPathIds[ZT_MAX_TRUSTED_PATHS];
+ InetAddress _trustedPathNetworks[ZT_MAX_TRUSTED_PATHS];
+ unsigned int _trustedPathCount;
World _world;
Hashtable< Address,SharedPtr<Peer> > _peers;
std::vector< Address > _rootAddresses;
diff --git a/version.h b/version.h
index 012660dd..b0df04f8 100644
--- a/version.h
+++ b/version.h
@@ -32,6 +32,6 @@
/**
* Revision
*/
-#define ZEROTIER_ONE_VERSION_REVISION 8
+#define ZEROTIER_ONE_VERSION_REVISION 9
#endif