diff --git a/node/Buffer.hpp b/node/Buffer.hpp
index c5d625deb..0b1715925 100644
--- a/node/Buffer.hpp
+++ b/node/Buffer.hpp
@@ -300,6 +300,23 @@ public:
 		append(s.data(),(unsigned int)s.length());
 	}
 
+	/**
+	 * Append a C string including null termination byte
+	 *
+	 * @param s C string
+	 * @throws std::out_of_range Attempt to append beyond capacity
+	 */
+	inline void appendCString(const char *s)
+		throw(std::out_of_range)
+	{
+		for(;;) {
+			if (_l >= C)
+				throw std::out_of_range("Buffer: append beyond capacity");
+			if (!(_b[_l++] = *(s++)))
+				break;
+		}
+	}
+
 	/**
 	 * Append a buffer
 	 *
diff --git a/node/Network.cpp b/node/Network.cpp
index e7b996618..00ae795a2 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -181,12 +181,23 @@ bool Network::applyConfiguration(const NetworkConfig &conf)
 int Network::setConfiguration(const void *confBytes,unsigned int confLen,bool saveToDisk)
 {
 	try {
-		if (!confLen)
+		if (confLen <= 1)
 			return 0;
 
 		NetworkConfig newConfig;
-		if (reinterpret_cast<const uint8_t *>(confBytes)[0] == ZT_NETWORKCONFIG_V2_MARKER_BYTE) {
-			Buffer<8194> tmp(confBytes,confLen);
+
+		// Find the length of any string-serialized old-style Dictionary,
+		// including its terminating NULL (if any). If this is before
+		// the end of the config, that tells us there is a new-style
+		// binary config which is preferred.
+		unsigned int dictLen = 0;
+		while (dictLen < confLen) {
+			if (!(reinterpret_cast<const uint8_t *>(confBytes)[dictLen++]))
+				break;
+		}
+
+		if (dictLen < (confLen - 2)) {
+			Buffer<8194> tmp(reinterpret_cast<const uint8_t *>(confBytes) + dictLen,confLen - dictLen);
 			newConfig.deserialize(tmp,0);
 		} else {
 #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
@@ -422,15 +433,15 @@ public:
 		_now(renv->node->now()),
 		_controller(nw->controller()),
 		_network(nw),
+		_anchors(nw->config().anchors()),
 		_rootAddresses(renv->topology->rootAddresses())
 	{}
 	inline void operator()(Topology &t,const SharedPtr<Peer> &p)
 	{
-		if (
-		    (_network->_isAllowed(p)) ||
-		    (p->address() == _controller) ||
-		    (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end())
-		   ) {
+		if ( (_network->_isAllowed(p)) || // FIXME: this causes multicast LIKEs for public networks to get spammed
+		     (p->address() == _controller) ||
+		     (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) ||
+				 (std::find(_anchors.begin(),_anchors.end(),p->address()) != _anchors.end()) ) {
 			peers.push_back(p);
 		}
 	}
@@ -439,14 +450,15 @@ private:
 	const uint64_t _now;
 	const Address _controller;
 	Network *const _network;
+	const std::vector<Address> _anchors;
 	const std::vector<Address> _rootAddresses;
 };
 void Network::_announceMulticastGroups()
 {
 	// Assumes _lock is locked
+	std::vector<MulticastGroup> allMulticastGroups(_allMulticastGroups());
 	_MulticastAnnounceAll gpfunc(RR,this);
 	RR->topology->eachPeer<_MulticastAnnounceAll &>(gpfunc);
-	std::vector<MulticastGroup> allMulticastGroups(_allMulticastGroups());
 	for(std::vector< SharedPtr<Peer> >::const_iterator i(gpfunc.peers.begin());i!=gpfunc.peers.end();++i)
 		_announceMulticastGroupsTo(*i,allMulticastGroups);
 }
diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp
index 15778aede..a03c1faf9 100644
--- a/node/NetworkConfig.hpp
+++ b/node/NetworkConfig.hpp
@@ -25,6 +25,7 @@
 
 #include <vector>
 #include <stdexcept>
+#include <algorithm>
 
 #include "../include/ZeroTierOne.h"
 
@@ -40,13 +41,6 @@
 #include <string>
 #endif
 
-/**
- * First byte of V2 binary-serialized network configs
- *
- * This will never begin a Dictionary, so it serves to distinguish.
- */
-#define ZT_NETWORKCONFIG_V2_MARKER_BYTE 0x00
-
 /**
  * Flag: allow passive bridging (experimental)
  */
@@ -68,9 +62,9 @@
 #define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE 0x0000020000000000ULL
 
 /**
- * This device is allowed to send packets from any Ethernet MAC, including ZeroTier-reserved ones
+ * An anchor is a device that is willing to be one and has been online/stable for a long time on this network
  */
-#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_IMPOSTOR 0x0000040000000000ULL
+#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR 0x0000040000000000ULL
 
 namespace ZeroTier {
 
@@ -302,6 +296,19 @@ public:
 		return r;
 	}
 
+	/**
+	 * @return ZeroTier addresses of "anchor" devices on this network
+	 */
+	inline std::vector<Address> anchors() const
+	{
+		std::vector<Address> r;
+		for(unsigned int i=0;i<_specialistCount;++i) {
+			if ((_specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR) != 0)
+				r.push_back(Address(_specialists[i]));
+		}
+		return r;
+	}
+
 	/**
 	 * Look up a static physical address for a given ZeroTier address
 	 *
@@ -321,6 +328,8 @@ public:
 	}
 
 	/**
+	 * This gets network preferred relays with their static physical address if one is defined
+	 *
 	 * @return Network-preferred relays for this network (if none, only roots will be used)
 	 */
 	inline std::vector<Relay> relays() const
@@ -393,9 +402,7 @@ public:
 	template<unsigned int C>
 	inline void serialize(Buffer<C> &b) const
 	{
-		b.append((uint8_t)ZT_NETWORKCONFIG_V2_MARKER_BYTE);
-
-		b.append((uint16_t)0); // version
+		b.append((uint16_t)1); // version
 
 		b.append((uint64_t)_nwid);
 		b.append((uint64_t)_timestamp);
@@ -517,9 +524,7 @@ public:
 
 		unsigned int p = startAt;
 
-		if (b[p++] != ZT_NETWORKCONFIG_V2_MARKER_BYTE)
-			throw std::invalid_argument("unrecognized format");
-		if (b.template at<uint16_t>(p) != 0)
+		if (b.template at<uint16_t>(p) != 1)
 			throw std::invalid_argument("unrecognized version");
 		p += 2;
 
@@ -532,9 +537,8 @@ public:
 		_type = (ZT_VirtualNetworkType)b[p++];
 
 		unsigned int nl = (unsigned int)b[p++];
-		if (nl > ZT_MAX_NETWORK_SHORT_NAME_LENGTH)
-			nl = ZT_MAX_NETWORK_SHORT_NAME_LENGTH;
-		memcpy(_name,b.field(p,nl),nl);
+		memcpy(_name,b.field(p,nl),std::max(nl,(unsigned int)ZT_MAX_NETWORK_SHORT_NAME_LENGTH));
+		p += nl;
 		// _name will always be null terminated since field size is ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1
 
 		_specialistCount = (unsigned int)b.template at<uint16_t>(p); p += 2;
diff --git a/node/NetworkConfigRequestMetaData.hpp b/node/NetworkConfigRequestMetaData.hpp
index 5bf8bac4f..3756d0d86 100644
--- a/node/NetworkConfigRequestMetaData.hpp
+++ b/node/NetworkConfigRequestMetaData.hpp
@@ -25,6 +25,9 @@
 
 #include "Constants.hpp"
 #include "NetworkConfig.hpp"
+#include "Buffer.hpp"
+
+#include "../version.h"
 
 #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
 #include <string>
@@ -33,27 +36,122 @@
 
 namespace ZeroTier {
 
+/**
+ * Network configuration request meta data
+ */
 class NetworkConfigRequestMetaData
 {
 public:
-	NetworkConfigRequestMetaData() :
-		_vendor(0),
-		_majorVersion(0),
-		_minorVersion(0),
-		_revision(0),
-		_buildNo(0),
-		_flags(0)
+	NetworkConfigRequestMetaData()
 	{
+		memset(this,0,sizeof(NetworkConfigRequestMetaData));
 	}
 
-protected:
-	unsigned int _vendor;
-	unsigned int _majorVersion;
-	unsigned int _minorVersion;
-	unsigned int _revision;
-	unsigned int _buildNo;
-	unsigned int _flags;
-	char _passcode[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1];
+	template<unsigned int C>
+	inline void serialize(Buffer<C> &b) const
+	{
+		// Unlike network config we always send the old fields. Newer network
+		// controllers will detect the presence of the new serialized data by
+		// detecting extra data after the terminating NULL. But always sending
+		// these maintains backward compatibility with old controllers.
+		b.appendCString("majv="ZEROTIER_ONE_VERSION_MAJOR_S"\nminv="ZEROTIER_ONE_VERSION_MINOR_S"\nrevv="ZEROTIER_ONE_VERSION_REVISION_S"\n");
+
+		b.append((uint16_t)1); // version
+
+		b.append((uint64_t)buildId);
+		b.append((uint64_t)flags);
+		b.append((uint16_t)vendor);
+		b.append((uint16_t)platform);
+		b.append((uint16_t)architecture);
+		b.append((uint16_t)majorVersion);
+		b.append((uint16_t)minorVersion);
+		b.append((uint16_t)revision);
+
+		unsigned int tl = (unsigned int)strlen(_auth);
+		if (tl > 255) tl = 255; // sanity check
+		b.append((uint8_t)tl);
+		b.append((const void *)auth,tl);
+
+		b.append((uint16_t)0); // extended bytes, currently 0 since unused
+	}
+
+	template<unsigned int C>
+	inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
+	{
+		memset(this,0,sizeof(NetworkConfigRequestMetaData));
+
+		unsigned int p = startAt;
+
+		// Seek past old style meta-data
+		while (b[p]) ++p;
+
+		if (b.template at<uint16_t>(p) != 1)
+			throw std::invalid_argument("unrecognized version");
+		p += 2;
+
+		buildId = b.template at<uint64_t>(p); p += 8;
+		flags = b.template at<uint64_t>(p); p += 8;
+		vendor = (ZT_Vendor)b.template at<uint16_t>(p); p += 2;
+		platform = (ZT_Platform)b.template at<uint16_t>(p); p += 2;
+		architecture = (ZT_Architecture)b.template at<uint16_t>(p); p += 2;
+		majorVersion = b.template at<uint16_t>(p); p += 2;
+		minorVersion = b.template at<uint16_t>(p); p += 2;
+		revision = b.template at<uint16_t>(p); p += 2;
+
+		unsigned int tl = (unsigned int)b[p++];
+		memcpy(auth,b.field(p,tl),std::max(tl,(unsigned int)ZT_MAX_NETWORK_SHORT_NAME_LENGTH));
+		// auth[] is ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1 and so will always end up null-terminated since we zeroed the structure
+		p += tl;
+
+		p += b.template at<uint16_t>(p) + 2;
+
+		return (p - startAt);
+	}
+
+	/**
+	 * Build ID (currently unused, must be 0)
+	 */
+	uint64_t buildId;
+
+	/**
+	 * Flags (currently unused, must be 0)
+	 */
+	uint64_t flags;
+
+	/**
+	 * ZeroTier vendor or 0 for unspecified
+	 */
+	ZT_Vendor vendor;
+
+	/**
+	 * ZeroTier platform or 0 for unspecified
+	 */
+	ZT_Platform platform;
+
+	/**
+	 * ZeroTier architecture or 0 for unspecified
+	 */
+	ZT_Architecture architecture;
+
+	/**
+	 * ZeroTier software major version
+	 */
+	unsigned int majorVersion;
+
+	/**
+	 * ZeroTier software minor version
+	 */
+	unsigned int minorVersion;
+
+	/**
+	 * ZeroTier software revision
+	 */
+	unsigned int revision;
+
+	/**
+	 * Authentication data (e.g. bearer=<token>)
+	 */
+	char auth[ZT_MAX_NETWORK_SHORT_NAME_LENGTH + 1];
 };
 
 } // namespace ZeroTier
diff --git a/version.h b/version.h
index 62045ed81..70815daf2 100644
--- a/version.h
+++ b/version.h
@@ -23,15 +23,18 @@
  * Major version
  */
 #define ZEROTIER_ONE_VERSION_MAJOR 1
+#define ZEROTIER_ONE_VERSION_MAJOR_S "1"
 
 /**
  * Minor version
  */
 #define ZEROTIER_ONE_VERSION_MINOR 1
+#define ZEROTIER_ONE_VERSION_MINOR_S "1"
 
 /**
  * Revision
  */
 #define ZEROTIER_ONE_VERSION_REVISION 5
+#define ZEROTIER_ONE_VERSION_REVISION_S "5"
 
 #endif