summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2013-07-29 13:56:20 -0400
committerAdam Ierymenko <adam.ierymenko@gmail.com>2013-07-29 13:56:20 -0400
commita53cfc909638ea9eeb2bd477cee20d106f79bf6d (patch)
treecbac1b06e6cbf1a88868cb6da06c347bb8561880
parente7b515c86c34e2805e136152a2719bc6ad86e46f (diff)
downloadinfinitytier-a53cfc909638ea9eeb2bd477cee20d106f79bf6d.tar.gz
infinitytier-a53cfc909638ea9eeb2bd477cee20d106f79bf6d.zip
Network membership certificate work in progress... does not build yet.
-rw-r--r--Makefile.linux2
-rw-r--r--Makefile.mac2
-rw-r--r--node/Address.hpp34
-rw-r--r--node/Dictionary.hpp73
-rw-r--r--node/Identity.cpp6
-rw-r--r--node/Network.cpp87
-rw-r--r--node/Network.hpp262
-rw-r--r--node/NodeConfig.cpp2
-rw-r--r--node/Packet.cpp3
-rw-r--r--node/Packet.hpp49
-rw-r--r--node/PacketDecoder.cpp18
-rw-r--r--node/PacketDecoder.hpp3
12 files changed, 467 insertions, 74 deletions
diff --git a/Makefile.linux b/Makefile.linux
index 9cb86305..bc77db4e 100644
--- a/Makefile.linux
+++ b/Makefile.linux
@@ -20,7 +20,7 @@ CXXFLAGS=$(CFLAGS) -fno-rtti
# separate binaries for the RedHat and Debian universes to distribute via
# auto-update. This way we get one Linux binary for all systems of a given
# architecture.
-LIBS=ext/bin/libcrypto/linux-$(ARCH)/libcrypto.a -ldl
+LIBS=ext/bin/libcrypto/linux-$(ARCH)/libcrypto.a -lm
include objects.mk
diff --git a/Makefile.mac b/Makefile.mac
index d3e3c27a..d47d18cc 100644
--- a/Makefile.mac
+++ b/Makefile.mac
@@ -13,7 +13,7 @@ STRIP=strip
#STRIP=echo
CXXFLAGS=$(CFLAGS) -fno-rtti
-LIBS=-lcrypto -ldl
+LIBS=-lcrypto -lm
include objects.mk
diff --git a/node/Address.hpp b/node/Address.hpp
index 0e3f7b8e..8573a268 100644
--- a/node/Address.hpp
+++ b/node/Address.hpp
@@ -64,13 +64,28 @@ public:
{
}
+ Address(const char *s)
+ throw()
+ {
+ unsigned char foo[ZT_ADDRESS_LENGTH];
+ setTo(foo,Utils::unhex(s,foo,ZT_ADDRESS_LENGTH));
+ }
+
+ Address(const std::string &s)
+ throw()
+ {
+ unsigned char foo[ZT_ADDRESS_LENGTH];
+ setTo(foo,Utils::unhex(s.c_str(),foo,ZT_ADDRESS_LENGTH));
+ }
+
/**
* @param bits Raw address -- 5 bytes, big-endian byte order
+ * @param len Length of array
*/
- Address(const void *bits)
+ Address(const void *bits,unsigned int len)
throw()
{
- setTo(bits);
+ setTo(bits,len);
}
inline Address &operator=(const Address &a)
@@ -89,10 +104,15 @@ public:
/**
* @param bits Raw address -- 5 bytes, big-endian byte order
+ * @param len Length of array
*/
- inline void setTo(const void *bits)
+ inline void setTo(const void *bits,unsigned int len)
throw()
{
+ if (len < ZT_ADDRESS_LENGTH) {
+ _a = 0;
+ return;
+ }
const unsigned char *b = (const unsigned char *)bits;
uint64_t a = ((uint64_t)*b++) << 32;
a |= ((uint64_t)*b++) << 24;
@@ -104,10 +124,13 @@ public:
/**
* @param bits Buffer to hold 5-byte address in big-endian byte order
+ * @param len Length of array
*/
- inline void copyTo(void *bits) const
+ inline void copyTo(void *bits,unsigned int len) const
throw()
{
+ if (len < ZT_ADDRESS_LENGTH)
+ return;
unsigned char *b = (unsigned char *)bits;
*(b++) = (unsigned char)((_a >> 32) & 0xff);
*(b++) = (unsigned char)((_a >> 24) & 0xff);
@@ -164,7 +187,8 @@ public:
throw()
{
MAC m;
- copyTo(m.data);
+ m.data[0] = ZT_MAC_FIRST_OCTET;
+ copyTo(m.data + 1,ZT_ADDRESS_LENGTH);
return m;
}
diff --git a/node/Dictionary.hpp b/node/Dictionary.hpp
index fff600eb..f706168f 100644
--- a/node/Dictionary.hpp
+++ b/node/Dictionary.hpp
@@ -30,6 +30,7 @@
#include <string>
#include <map>
+#include <stdexcept>
#include "Constants.hpp"
namespace ZeroTier {
@@ -38,11 +39,76 @@ namespace ZeroTier {
* Simple key/value dictionary with string serialization
*
* The serialization format is a flat key=value with backslash escape.
- * It does not support comments or other syntactic complexities.
+ * It does not support comments or other syntactic complexities. It is
+ * human-readable if the keys and values in the dictionary are also
+ * human-readable. Otherwise it might contain unprintable characters.
*/
class Dictionary : public std::map<std::string,std::string>
{
public:
+ Dictionary()
+ {
+ }
+
+ /**
+ * @param s String-serialized dictionary
+ */
+ Dictionary(const char *s)
+ {
+ fromString(s);
+ }
+
+ /**
+ * @param s String-serialized dictionary
+ */
+ Dictionary(const std::string &s)
+ {
+ fromString(s.c_str());
+ }
+
+ /**
+ * Get a key, throwing an exception if it is not present
+ *
+ * @param key Key to look up
+ * @return Reference to value
+ * @throws std::invalid_argument Key not found
+ */
+ inline const std::string &get(const std::string &key) const
+ throw(std::invalid_argument)
+ {
+ const_iterator e(find(key));
+ if (e == end())
+ throw std::invalid_argument(std::string("missing required field: ")+key);
+ return e->second;
+ }
+
+ /**
+ * Get a key, returning a default if not present
+ *
+ * @param key Key to look up
+ * @param dfl Default if not present
+ * @return Value or default
+ */
+ inline const std::string &get(const std::string &key,const std::string &dfl) const
+ {
+ const_iterator e(find(key));
+ if (e == end())
+ return dfl;
+ return e->second;
+ }
+
+ /**
+ * @param key Key to check
+ * @return True if dictionary contains key
+ */
+ inline bool contains(const std::string &key) const
+ {
+ return (find(key) != end());
+ }
+
+ /**
+ * @return String-serialized dictionary
+ */
inline std::string toString() const
{
std::string s;
@@ -57,6 +123,11 @@ public:
return s;
}
+ /**
+ * Clear and initialize from a string
+ *
+ * @param s String-serialized dictionary
+ */
inline void fromString(const char *s)
{
clear();
diff --git a/node/Identity.cpp b/node/Identity.cpp
index a7ef403d..fdfdcd99 100644
--- a/node/Identity.cpp
+++ b/node/Identity.cpp
@@ -58,7 +58,7 @@ void Identity::generate()
// invalid. Of course, deep verification of address/key relationship is
// required to cover the more elaborate address claim jump attempt case.
unsigned char atmp[ZT_ADDRESS_LENGTH];
- _address.copyTo(atmp);
+ _address.copyTo(atmp,ZT_ADDRESS_LENGTH);
SHA256_CTX sha;
unsigned char dig[32];
unsigned char idtype = IDENTITY_TYPE_NIST_P_521,zero = 0;
@@ -76,7 +76,7 @@ void Identity::generate()
bool Identity::locallyValidate(bool doAddressDerivationCheck) const
{
unsigned char atmp[ZT_ADDRESS_LENGTH];
- _address.copyTo(atmp);
+ _address.copyTo(atmp,ZT_ADDRESS_LENGTH);
SHA256_CTX sha;
unsigned char dig[32];
unsigned char idtype = IDENTITY_TYPE_NIST_P_521,zero = 0;
@@ -222,7 +222,7 @@ Address Identity::deriveAddress(const void *keyBytes,unsigned int keyLen)
delete [] ram;
- return Address(dig); // first 5 bytes of dig[]
+ return Address(dig,ZT_ADDRESS_LENGTH); // first 5 bytes of dig[]
}
std::string Identity::encrypt(const Identity &to,const void *data,unsigned int len) const
diff --git a/node/Network.cpp b/node/Network.cpp
index f34e07e0..34a9a85b 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -25,19 +25,90 @@
* LLC. Start here: http://www.zerotier.com/
*/
+#include <stdlib.h>
+#include <math.h>
+
+#include <openssl/sha.h>
+
+#include "RuntimeEnvironment.hpp"
+#include "NodeConfig.hpp"
#include "Network.hpp"
#include "Switch.hpp"
namespace ZeroTier {
+void Network::Certificate::sign(const Identity &with)
+{
+ unsigned char dig[32];
+ SHA256_CTX sha;
+ SHA256_Init(&sha);
+ unsigned char zero = 0;
+ for(const_iterator i(begin());i!=end();++i) {
+ if (i->first != "sig") {
+ SHA256_Update(&sha,&zero,1);
+ SHA256_Update(&sha,(const unsigned char *)i->first.data(),i->first.length());
+ SHA256_Update(&sha,&zero,1);
+ SHA256_Update(&sha,(const unsigned char *)i->second.data(),i->second.length());
+ SHA256_Update(&sha,&zero,1);
+ }
+ }
+ SHA256_Final(dig,&sha);
+ (*this)["sig"] = with.sign(dig);
+}
+
+static const std::string _DELTA_PREFIX("~");
+bool Network::Certificate::qualifyMembership(const Network::Certificate &mc) const
+{
+ // Note: optimization probably needed here, probably via some kind of
+ // memoization / dynamic programming.
+
+ for(const_iterator myField(begin());myField!=end();++myField) {
+ if (!((myField->first.length() > 1)&&(myField->first[0] == '~'))) { // ~fields are max delta range specs
+ // If they lack the same field, comparison fails.
+ const_iterator theirField(mc.find(myField->first));
+ if (theirField == mc.end())
+ return false;
+
+ const_iterator deltaField(find(_DELTA_PREFIX + myField->first));
+ if (deltaField == end()) {
+ // If there is no delta, compare for equality (e.g. node, nwid)
+ if (myField->second != theirField->second)
+ return false;
+ } else {
+ // Otherwise compare range with max delta. Presence of a dot in delta
+ // indicates a floating point comparison. Otherwise an integer
+ // comparison occurs.
+ if (deltaField->second.find('.') != std::string::npos) {
+ double my = strtod(myField->second.c_str(),(char **)0);
+ double their = strtod(theirField->second.c_str(),(char **)0);
+ double delta = strtod(deltaField->second.c_str(),(char **)0);
+ if (fabs(my - their) > delta)
+ return false;
+ } else {
+ int64_t my = strtoll(myField->second.c_str(),(char **)0,10);
+ int64_t their = strtoll(theirField->second.c_str(),(char **)0,10);
+ int64_t delta = strtoll(deltaField->second.c_str(),(char **)0,10);
+ if (my > their) {
+ if ((my - their) > delta)
+ return false;
+ } else {
+ if ((their - my) > delta)
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
Network::Network(const RuntimeEnvironment *renv,uint64_t id)
throw(std::runtime_error) :
_r(renv),
- _id(id),
_tap(renv,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,this),
- _members(),
- _open(false),
- _lock()
+ _id(id),
+ _isOpen(false)
{
}
@@ -45,6 +116,14 @@ Network::~Network()
{
}
+void Network::setConfiguration(const Network::Config &conf)
+{
+}
+
+void Network::requestConfiguration()
+{
+}
+
void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data)
{
const RuntimeEnvironment *_r = ((Network *)arg)->_r;
diff --git a/node/Network.hpp b/node/Network.hpp
index 6263aa9b..359e2ce5 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -30,28 +30,37 @@
#include <string>
#include <set>
+#include <map>
#include <vector>
#include <stdexcept>
+
+#include "Constants.hpp"
+#include "Utils.hpp"
#include "EthernetTap.hpp"
#include "Address.hpp"
#include "Mutex.hpp"
-#include "InetAddress.hpp"
-#include "Constants.hpp"
#include "SharedPtr.hpp"
#include "AtomicCounter.hpp"
-#include "RuntimeEnvironment.hpp"
#include "MulticastGroup.hpp"
#include "NonCopyable.hpp"
#include "MAC.hpp"
+#include "Dictionary.hpp"
+#include "Identity.hpp"
+#include "InetAddress.hpp"
namespace ZeroTier {
+class RuntimeEnvironment;
class NodeConfig;
/**
* A virtual LAN
*
- * Networks can be open or closed.
+ * Networks can be open or closed. Each network has an ID whose most
+ * significant 40 bits are the ZeroTier address of the node that should
+ * be contacted for network configuration. The least significant 24
+ * bits are arbitrary, allowing up to 2^24 networks per managing
+ * node.
*
* Open networks do not track membership. Anyone is allowed to communicate
* over them.
@@ -69,7 +78,183 @@ class Network : NonCopyable
friend class SharedPtr<Network>;
friend class NodeConfig;
+public:
+ /**
+ * A certificate of network membership
+ */
+ class Certificate : private Dictionary
+ {
+ public:
+ Certificate()
+ {
+ }
+
+ Certificate(const char *s) :
+ Dictionary(s)
+ {
+ }
+
+ Certificate(const std::string &s) :
+ Dictionary(s)
+ {
+ }
+
+ /**
+ * @return Read-only underlying dictionary
+ */
+ inline const Dictionary &dictionary() const { return *this; }
+
+ inline void setNetworkId(uint64_t id)
+ {
+ char buf[32];
+ sprintf(buf,"%llu",id);
+ (*this)["nwid"] = buf;
+ }
+
+ inline uint64_t networkId() const
+ throw(std::invalid_argument)
+ {
+ return strtoull(get("nwid").c_str(),(char **)0,10);
+ }
+
+ inline void setPeerAddress(Address &a)
+ {
+ (*this)["peer"] = a.toString();
+ }
+
+ inline Address peerAddress() const
+ throw(std::invalid_argument)
+ {
+ return Address(get("peer"));
+ }
+
+ /**
+ * Set the timestamp and max-delta
+ *
+ * @param ts Timestamp in ms since epoch
+ * @param maxDelta Maximum difference between two peers on the same network
+ */
+ inline void setTimestamp(uint64_t ts,uint64_t maxDelta)
+ {
+ char foo[32];
+ sprintf(foo,"%llu",ts);
+ (*this)["ts"] = foo;
+ sprintf(foo,"%llu",maxDelta);
+ (*this)["~ts"] = foo;
+ }
+
+ /**
+ * Set or update the sig field to contain a signature
+ *
+ * @param with Signing identity -- the identity of this network's controller
+ */
+ void sign(const Identity &with);
+
+ /**
+ * Check if another peer is indeed a current member of this network
+ *
+ * Fields with companion ~fields are compared with the defined maximum
+ * delta in this certificate. Fields without ~fields are compared for
+ * equality.
+ *
+ * This does not verify the certificate's signature! The signature
+ * must be verified first.
+ *
+ * @param mc Peer membership certificate
+ * @return True if mc's membership in this network is current
+ */
+ bool qualifyMembership(const Certificate &mc) const;
+ };
+
+ /**
+ * A network configuration for a given node
+ */
+ class Config : private Dictionary
+ {
+ public:
+ Config()
+ {
+ }
+
+ Config(const char *s) :
+ Dictionary(s)
+ {
+ }
+
+ Config(const std::string &s) :
+ Dictionary(s)
+ {
+ }
+
+ /**
+ * @return Certificate of membership for this network, or empty cert if none
+ */
+ inline Certificate certificateOfMembership() const
+ {
+ return Certificate(get("com",""));
+ }
+
+ /**
+ * @return True if this is an open non-access-controlled network
+ */
+ inline bool isOpen() const
+ {
+ return (get("isOpen","0") == "1");
+ }
+
+ /**
+ * @return All static addresses / netmasks, IPv4 or IPv6
+ */
+ inline std::set<InetAddress> staticAddresses() const
+ {
+ std::set<InetAddress> sa;
+ std::vector<std::string> ips(Utils::split(get("ipv4Static","").c_str(),",","",""));
+ for(std::vector<std::string>::const_iterator i(ips.begin());i!=ips.end();++i)
+ sa.insert(InetAddress(*i));
+ ips = Utils::split(get("ipv6Static","").c_str(),",","","");
+ for(std::vector<std::string>::const_iterator i(ips.begin());i!=ips.end();++i)
+ sa.insert(InetAddress(*i));
+ return sa;
+ }
+
+ /**
+ * Set static IPv4 and IPv6 addresses
+ *
+ * This sets the ipv4Static and ipv6Static fields to comma-delimited
+ * lists of assignments. The port field in InetAddress must be the
+ * number of bits in the netmask.
+ *
+ * @param begin Start of container or array of addresses (InetAddress)
+ * @param end End of container or array of addresses (InetAddress)
+ * @tparam I Type of container or array
+ */
+ template<typename I>
+ inline void setStaticInetAddresses(const I &begin,const I &end)
+ {
+ std::string v4;
+ std::string v6;
+ for(I i(begin);i!=end;++i) {
+ if (i->isV4()) {
+ if (v4.length())
+ v4.push_back(',');
+ v4.append(i->toString());
+ } else if (i->isV6()) {
+ if (v6.length())
+ v6.push_back(',');
+ v6.append(i->toString());
+ }
+ }
+ if (v4.length())
+ (*this)["ipv4Static"] = v4;
+ else erase("ipv4Static");
+ if (v6.length())
+ (*this)["ipv6Static"] = v6;
+ else erase("ipv6Static");
+ }
+ };
+
private:
+ // Only NodeConfig can create, only SharedPtr can delete
Network(const RuntimeEnvironment *renv,uint64_t id)
throw(std::runtime_error);
@@ -87,56 +272,22 @@ public:
inline EthernetTap &tap() throw() { return _tap; }
/**
- * Get this network's members
- *
- * If this is an open network, membership isn't relevant and this doesn't
- * mean much. If it's a closed network, frames will only be exchanged to/from
- * members.
- *
- * @return Members of this network
+ * @return Address of network's controlling node
*/
- inline std::set<Address> members() const
- {
- Mutex::Lock _l(_lock);
- return _members;
- }
-
- /**
- * @param addr Address to check
- * @return True if address is a member
- */
- inline bool isMember(const Address &addr) const
- throw()
- {
- Mutex::Lock _l(_lock);
- return (_members.count(addr) > 0);
- }
-
- /**
- * Shortcut to check open() and then isMember()
- *
- * @param addr Address to check
- * @return True if network is open or if address is a member
- */
- inline bool isAllowed(const Address &addr) const
- throw()
- {
- Mutex::Lock _l(_lock);
- return ((_open)||(_members.count(addr) > 0));
- }
+ inline Address controller() throw() { return Address(_id >> 24); }
/**
* @return True if network is open (no membership required)
*/
- inline bool open() const
+ inline bool isOpen() const
throw()
{
Mutex::Lock _l(_lock);
- return _open;
+ return _isOpen;
}
/**
- * Update internal multicast group set and return true if changed
+ * Update multicast groups for this network's tap
*
* @return True if internal multicast group set has changed
*/
@@ -147,7 +298,7 @@ public:
}
/**
- * @return Latest set of multicast groups
+ * @return Latest set of multicast groups for this network's tap
*/
inline std::set<MulticastGroup> multicastGroups() const
{
@@ -155,15 +306,32 @@ public:
return _multicastGroups;
}
+ /**
+ * Set or update this network's configuration
+ *
+ * This is called by PacketDecoder when an update comes over the wire, or
+ * internally when an old config is reloaded from disk.
+ *
+ * @param conf Configuration in key/value dictionary form
+ */
+ void setConfiguration(const Config &conf);
+
+ /**
+ * Causes this network to request an updated configuration from its master node now
+ */
+ void requestConfiguration();
+
private:
static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
const RuntimeEnvironment *_r;
- uint64_t _id;
+
EthernetTap _tap;
- std::set<Address> _members;
std::set<MulticastGroup> _multicastGroups;
- bool _open;
+
+ uint64_t _id;
+ bool _isOpen;
+
Mutex _lock;
AtomicCounter __refCount;
diff --git a/node/NodeConfig.cpp b/node/NodeConfig.cpp
index 1a84b6b7..214c06b7 100644
--- a/node/NodeConfig.cpp
+++ b/node/NodeConfig.cpp
@@ -126,7 +126,7 @@ std::vector<std::string> NodeConfig::execute(const char *command)
_P("200 listnetworks %llu %s %s",
nw->first,
nw->second->tap().deviceName().c_str(),
- (nw->second->open() ? "public" : "private"));
+ (nw->second->isOpen() ? "public" : "private"));
}
} else if (cmd[0] == "join") {
_P("404 join Not implemented yet.");
diff --git a/node/Packet.cpp b/node/Packet.cpp
index 4728609d..d3c0a3af 100644
--- a/node/Packet.cpp
+++ b/node/Packet.cpp
@@ -43,6 +43,8 @@ const char *Packet::verbString(Verb v)
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
case VERB_NETWORK_PERMISSION_CERTIFICATE: return "NETWORK_PERMISSION_CERTIFICATE";
+ case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST";
+ case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH";
}
return "(unknown)";
}
@@ -59,7 +61,6 @@ const char *Packet::errorString(ErrorCode e)
case ERROR_IDENTITY_INVALID: return "IDENTITY_INVALID";
case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION";
case ERROR_NO_NETWORK_CERTIFICATE_ON_FILE: return "NO_NETWORK_CERTIFICATE_ON_FILE";
- case ERROR_OBJECT_EXPIRED: return "OBJECT_EXPIRED";
}
return "(unknown)";
}
diff --git a/node/Packet.hpp b/node/Packet.hpp
index 86d94e1d..2f88ac37 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -287,7 +287,7 @@ public:
*
* @return Destination ZT address
*/
- inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH)); }
+ inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
/**
* @return True if fragment is of a valid length
@@ -468,8 +468,9 @@ public:
/* Network permission certificate:
* <[8] 64-bit network ID>
* <[1] flags (currently unused, must be 0)>
- * <[8] certificate timestamp>
- * <[8] 16-bit length of signature>
+ * <[2] 16-bit length of qualifying fields>
+ * <[...] string-serialized dictionary of qualifying fields>
+ * <[2] 16-bit length of signature>
* <[...] ECDSA signature of my binary serialized identity and timestamp>
*
* This message is used to send ahead of time a certificate proving
@@ -478,7 +479,38 @@ public:
* OK is generated on acceptance. ERROR is returned on failure. In both
* cases the payload is the network ID.
*/
- VERB_NETWORK_PERMISSION_CERTIFICATE = 10
+ VERB_NETWORK_PERMISSION_CERTIFICATE = 10,
+
+ /* Network configuration request:
+ * <[8] 64-bit network ID>
+ *
+ * This message requests network configuration from a node capable of
+ * providing it. Such nodes run the netconf service, which must be
+ * installed into the ZeroTier home directory.
+ *
+ * OK response payload:
+ * <[8] 64-bit network ID>
+ * <[...] network configuration dictionary>
+ *
+ * OK returns a Dictionary (string serialized) containing the network's
+ * configuration and IP address assignment information for the querying
+ * node.
+ *
+ * ERROR may be NOT_FOUND if no such network is known, or
+ * UNSUPPORTED_OPERATION if the netconf service isn't available. The
+ * payload will be the network ID.
+ */
+ VERB_NETWORK_CONFIG_REQUEST = 11,
+
+ /* Network configuration refresh request:
+ * <[8] 64-bit network ID>
+ *
+ * This message can be sent by the network configuration master node
+ * to request that nodes refresh their network configuration.
+ *
+ * It is only a hint and does not presently elicit a response.
+ */
+ VERB_NETWORK_CONFIG_REFRESH = 12
};
/**
@@ -508,10 +540,7 @@ public:
ERROR_UNSUPPORTED_OPERATION = 6,
/* Message to private network rejected -- no unexpired certificate on file */
- ERROR_NO_NETWORK_CERTIFICATE_ON_FILE = 7,
-
- /* Object is expired (e.g. network certificate) */
- ERROR_OBJECT_EXPIRED = 8
+ ERROR_NO_NETWORK_CERTIFICATE_ON_FILE = 7
};
/**
@@ -624,14 +653,14 @@ public:
*
* @return Destination ZT address
*/
- inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH)); }
+ inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
/**
* Get this packet's source
*
* @return Source ZT address
*/
- inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH)); }
+ inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
/**
* @return True if packet is of valid length
diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp
index 810e30a7..cd9985c3 100644
--- a/node/PacketDecoder.cpp
+++ b/node/PacketDecoder.cpp
@@ -102,6 +102,12 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
return _doMULTICAST_LIKE(_r,peer);
case Packet::VERB_MULTICAST_FRAME:
return _doMULTICAST_FRAME(_r,peer);
+ case Packet::VERB_NETWORK_PERMISSION_CERTIFICATE:
+ return _doNETWORK_PERMISSION_CERTIFICATE(_r,peer);
+ case Packet::VERB_NETWORK_CONFIG_REQUEST:
+ return _doNETWORK_CONFIG_REQUEST(_r,peer);
+ case Packet::VERB_NETWORK_CONFIG_REFRESH:
+ return _doNETWORK_CONFIG_REFRESH(_r,peer);
default:
// This might be something from a new or old version of the protocol.
// Technically it passed HMAC so the packet is still valid, but we
@@ -538,4 +544,16 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
return true;
}
+bool PacketDecoder::_doNETWORK_PERMISSION_CERTIFICATE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
+{
+}
+
+bool PacketDecoder::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
+{
+}
+
+bool PacketDecoder::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
+{
+}
+
} // namespace ZeroTier
diff --git a/node/PacketDecoder.hpp b/node/PacketDecoder.hpp
index e595d326..1cd1dca7 100644
--- a/node/PacketDecoder.hpp
+++ b/node/PacketDecoder.hpp
@@ -122,6 +122,9 @@ private:
bool _doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
+ bool _doNETWORK_PERMISSION_CERTIFICATE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
+ bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
+ bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
uint64_t _receiveTime;
Demarc::Port _localPort;