summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/CertificateOfMembership.hpp6
-rw-r--r--node/Network.cpp56
-rw-r--r--node/Packet.cpp2
-rw-r--r--node/Packet.hpp23
-rw-r--r--node/PacketDecoder.cpp61
-rw-r--r--node/PacketDecoder.hpp2
-rw-r--r--node/Switch.cpp2
7 files changed, 84 insertions, 68 deletions
diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp
index 8f73f9e2..4cc2015b 100644
--- a/node/CertificateOfMembership.hpp
+++ b/node/CertificateOfMembership.hpp
@@ -198,14 +198,14 @@ public:
/**
* @return Timestamp for this cert in ms since epoch (according to netconf's clock)
*/
- inline Address timestamp() const
+ inline uint64_t timestamp() const
throw()
{
for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
if (q->id == COM_RESERVED_ID_TIMESTAMP)
- return Address(q->value);
+ return q->value;
}
- return Address();
+ return 0ULL;
}
/**
diff --git a/node/Network.cpp b/node/Network.cpp
index 68847749..db84ada0 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -178,10 +178,14 @@ void Network::requestConfiguration()
void Network::addMembershipCertificate(const CertificateOfMembership &cert)
{
Mutex::Lock _l(_lock);
+
// We go ahead and accept certs provisionally even if _isOpen is true, since
// that might be changed in short order if the user is fiddling in the UI.
// These will be purged on clean() for open networks eventually.
- _membershipCertificates[cert.issuedTo()] = cert;
+
+ CertificateOfMembership &old = _membershipCertificates[cert.issuedTo()];
+ if (cert.timestamp() >= old.timestamp())
+ old = cert;
}
bool Network::isAllowed(const Address &peer) const
@@ -299,30 +303,38 @@ void Network::_restoreState()
_membershipCertificates.clear();
- try {
- FILE *mcdb = fopen(mcdbPath.c_str(),"rb");
- if (mcdb) {
- for(;;) {
- long rlen = (long)fread(buf.data() + buf.size(),1,ZT_NETWORK_CERT_WRITE_BUF_SIZE - buf.size(),mcdb);
- if (rlen <= 0)
- break;
- buf.setSize(buf.size() + (unsigned int)rlen);
- unsigned int ptr = 0;
- while ((ptr < (ZT_NETWORK_CERT_WRITE_BUF_SIZE / 2))&&(ptr < buf.size())) {
- ptr += com.deserialize(buf,ptr);
- if (com.issuedTo())
- _membershipCertificates[com.issuedTo()] = com;
- }
- if (ptr) {
- memmove(buf.data(),buf.data() + ptr,buf.size() - ptr);
- buf.setSize(buf.size() - ptr);
+ FILE *mcdb = fopen(mcdbPath.c_str(),"rb");
+ if (mcdb) {
+ try {
+ char magic[6];
+ if ((fread(magic,6,1,mcdb) == 1)&&(!memcmp("ZTMCD0",magic,6))) {
+ for(;;) {
+ long rlen = (long)fread(buf.data() + buf.size(),1,ZT_NETWORK_CERT_WRITE_BUF_SIZE - buf.size(),mcdb);
+ if (rlen <= 0)
+ break;
+ buf.setSize(buf.size() + (unsigned int)rlen);
+ unsigned int ptr = 0;
+ while ((ptr < (ZT_NETWORK_CERT_WRITE_BUF_SIZE / 2))&&(ptr < buf.size())) {
+ ptr += com.deserialize(buf,ptr);
+ if (com.issuedTo())
+ _membershipCertificates[com.issuedTo()] = com;
+ }
+ if (ptr) {
+ memmove(buf.data(),buf.data() + ptr,buf.size() - ptr);
+ buf.setSize(buf.size() - ptr);
+ }
}
+ fclose(mcdb);
+ } else {
+ fclose(mcdb);
+ Utils::rm(mcdbPath);
}
+ } catch ( ... ) {
+ // Membership cert dump file invalid. We'll re-learn them off the net.
+ _membershipCertificates.clear();
+ fclose(mcdb);
+ Utils::rm(mcdbPath);
}
- } catch ( ... ) {
- // Membership cert dump file invalid. We'll re-learn them off the net.
- _membershipCertificates.clear();
- Utils::rm(mcdbPath);
}
}
}
diff --git a/node/Packet.cpp b/node/Packet.cpp
index 99cf3979..d809d402 100644
--- a/node/Packet.cpp
+++ b/node/Packet.cpp
@@ -42,7 +42,7 @@ const char *Packet::verbString(Verb v)
case VERB_WHOIS: return "WHOIS";
case VERB_RENDEZVOUS: return "RENDEZVOUS";
case VERB_FRAME: return "FRAME";
- case VERB_PROXY_FRAME: return "PROXY_FRAME";
+ case VERB_BRIDGED_FRAME: return "BRIDGED_FRAME";
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE";
diff --git a/node/Packet.hpp b/node/Packet.hpp
index 4f139de8..486faebb 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -155,7 +155,8 @@
#define ZT_PROTO_VERB_WHOIS_IDX_ZTADDRESS (ZT_PACKET_IDX_PAYLOAD)
-#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS + 1)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT (ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS + 5)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN (ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT + 2)
#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN + 1)
@@ -199,8 +200,6 @@
#define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_FRAME_LEN 2
#define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME_LEN + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_FRAME_LEN)
-#define ZT_PROTO_VERB_NETWORK_MEMBERSHIP_CERTIFICATE_IDX_CERTIFICATE (ZT_PACKET_IDX_PAYLOAD)
-
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8)
#define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2)
@@ -434,11 +433,13 @@ public:
* OK response payload:
* <[...] binary serialized identity>
*
- * Error payload will be address queried.
+ * ERROR response payload:
+ * <[5] address>
*/
VERB_WHOIS = 4,
/* Meet another node at a given protocol address:
+ * <[1] flags (unused, currently 0)>
* <[5] ZeroTier address of peer that might be found at this address>
* <[2] 16-bit protocol address port>
* <[1] protocol address length (4 for IPv4, 16 for IPv6)>
@@ -470,8 +471,7 @@ public:
* <[...] ethernet payload>
*
* MAC addresses are derived from the packet's source and destination
- * ZeroTier addresses. ZeroTier does not support VLANs or other extensions
- * beyond core Ethernet.
+ * ZeroTier addresses.
*
* ERROR may be generated if a membership certificate is needed for a
* closed network. Payload will be network ID.
@@ -479,7 +479,7 @@ public:
VERB_FRAME = 6,
/* TODO: not implemented yet */
- VERB_PROXY_FRAME = 7,
+ VERB_BRIDGED_FRAME = 7,
/* A multicast frame:
* <[2] 16-bit propagation depth or 0xffff for "do not forward">
@@ -556,6 +556,7 @@ public:
/* Network member certificate:
* <[...] serialized certificate of membership>
+ * [ ... additional certificates may follow ...]
*
* Certificate contains network ID, peer it was issued for, etc.
*
@@ -583,9 +584,8 @@ public:
* node can push to other peers to demonstrate its right to speak on
* a given network.
*
- * 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.
+ * ERROR response payload:
+ * <[8] 64-bit network ID>
*/
VERB_NETWORK_CONFIG_REQUEST = 11,
@@ -594,7 +594,8 @@ public:
*
* This message can be sent by the network configuration master node
* to request that nodes refresh their network configuration. It can
- * thus be used to "push" updates.
+ * thus be used to "push" updates so that network config changes will
+ * take effect quickly.
*
* It does not generate an OK or ERROR message, and is treated only as
* a hint to refresh now.
diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp
index a8a55602..f4100029 100644
--- a/node/PacketDecoder.cpp
+++ b/node/PacketDecoder.cpp
@@ -102,8 +102,8 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
return _doRENDEZVOUS(_r,peer);
case Packet::VERB_FRAME:
return _doFRAME(_r,peer);
- case Packet::VERB_PROXY_FRAME:
- return _doPROXY_FRAME(_r,peer);
+ case Packet::VERB_BRIDGED_FRAME:
+ return _doBRIDGED_FRAME(_r,peer);
case Packet::VERB_MULTICAST_FRAME:
return _doMULTICAST_FRAME(_r,peer);
case Packet::VERB_MULTICAST_LIKE:
@@ -151,9 +151,6 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr<Peer>
// if (_r->topology->isSupernode(source())) {}
break;
case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
- // TODO: this allows anyone to request a membership cert, which is
- // harmless until these contain possibly privacy-sensitive info.
- // Then we'll need to be more careful.
SharedPtr<Network> network(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
if (network)
network->pushMembershipCertificate(source(),true,Utils::now());
@@ -399,7 +396,7 @@ bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer>
return true;
}
-bool PacketDecoder::_doPROXY_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
+bool PacketDecoder::_doBRIDGED_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
{
// TODO: bridging is not implemented yet
return true;
@@ -654,40 +651,44 @@ bool PacketDecoder::_doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedP
bool PacketDecoder::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
{
try {
- CertificateOfMembership com(*this,ZT_PROTO_VERB_NETWORK_MEMBERSHIP_CERTIFICATE_IDX_CERTIFICATE);
- if (!com.hasRequiredFields()) {
- TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): invalid cert: at least one required field is missing",source().toString().c_str(),_remoteAddress.toString().c_str());
- return true;
- } else if (com.signedBy()) {
- SharedPtr<Peer> signer(_r->topology->getPeer(com.signedBy()));
- if (signer) {
- if (com.verify(signer->identity())) {
- uint64_t nwid = com.networkId();
- SharedPtr<Network> network(_r->nc->network(nwid));
- if (network) {
- if (network->controller() == signer) {
- network->addMembershipCertificate(com);
- return true;
+ CertificateOfMembership com;
+ unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
+ while (ptr < size()) {
+ ptr += com.deserialize(*this,ptr);
+ if (!com.hasRequiredFields()) {
+ TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): invalid cert: at least one required field is missing",source().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
+ } else if (com.signedBy()) {
+ SharedPtr<Peer> signer(_r->topology->getPeer(com.signedBy()));
+ if (signer) {
+ if (com.verify(signer->identity())) {
+ uint64_t nwid = com.networkId();
+ SharedPtr<Network> network(_r->nc->network(nwid));
+ if (network) {
+ if (network->controller() == signer) {
+ network->addMembershipCertificate(com);
+ return true;
+ } else {
+ TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): signer %s is not the controller for network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),signer->address().toString().c_str(),(unsigned long long)nwid);
+ return true;
+ }
} else {
- TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): signer %s is not the controller for network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),signer->address().toString().c_str(),(unsigned long long)nwid);
+ TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): not a member of network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)nwid);
return true;
}
} else {
- TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): not a member of network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)nwid);
+ TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): failed signature verification for signer %s",source().toString().c_str(),_remoteAddress.toString().c_str(),signer->address().toString().c_str());
return true;
}
} else {
- TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): failed signature verification for signer %s",source().toString().c_str(),_remoteAddress.toString().c_str(),signer->address().toString().c_str());
- return true;
+ _r->sw->requestWhois(com.signedBy());
+ _step = DECODE_WAITING_FOR_NETWORK_MEMBERSHIP_CERTIFICATE_SIGNER_LOOKUP;
+ return false;
}
} else {
- _r->sw->requestWhois(com.signedBy());
- _step = DECODE_WAITING_FOR_NETWORK_MEMBERSHIP_CERTIFICATE_SIGNER_LOOKUP;
- return false;
+ TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): invalid cert: no signature",source().toString().c_str(),_remoteAddress.toString().c_str());
+ return true;
}
- } else {
- TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): invalid cert: no signature",source().toString().c_str(),_remoteAddress.toString().c_str());
- return true;
}
} catch (std::exception &ex) {
TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
diff --git a/node/PacketDecoder.hpp b/node/PacketDecoder.hpp
index 7a8aaca3..e5035317 100644
--- a/node/PacketDecoder.hpp
+++ b/node/PacketDecoder.hpp
@@ -117,7 +117,7 @@ private:
bool _doWHOIS(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
- bool _doPROXY_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
+ bool _doBRIDGED_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
diff --git a/node/Switch.cpp b/node/Switch.cpp
index f6fe4e3a..c6cd7987 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -265,6 +265,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
{ // tell p1 where to find p2
Packet outp(p1,_r->identity.address(),Packet::VERB_RENDEZVOUS);
+ outp.append((unsigned char)0);
p2.appendTo(outp);
outp.append((uint16_t)cg.first.port());
if (cg.first.isV6()) {
@@ -279,6 +280,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
}
{ // tell p2 where to find p1
Packet outp(p2,_r->identity.address(),Packet::VERB_RENDEZVOUS);
+ outp.append((unsigned char)0);
p1.appendTo(outp);
outp.append((uint16_t)cg.second.port());
if (cg.second.isV6()) {