From 72653e54f951b2a47686d420186f59f533542940 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 23 Feb 2017 12:34:17 -0800 Subject: [PATCH] Finish wiring up ipauth and macauth to Network filter. --- include/ZeroTierOne.h | 10 ++++++++++ node/CertificateOfOwnership.cpp | 17 ++++++++++++++++ node/CertificateOfOwnership.hpp | 29 +++++++-------------------- node/Membership.cpp | 20 +++++++------------ node/Membership.hpp | 35 +++++++++++++++++++++++---------- node/Network.cpp | 25 +++++++++++++++++++++++ rule-compiler/package.json | 2 +- rule-compiler/rule-compiler.js | 2 ++ 8 files changed, 94 insertions(+), 46 deletions(-) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index c1dbd8f8d..ddd0b4044 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -194,6 +194,16 @@ extern "C" { */ #define ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST 0x2000000000000000ULL +/** + * Packet characteristics flag: sending IP address has a certificate of ownership + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED 0x1000000000000000ULL + +/** + * Packet characteristics flag: sending MAC address has a certificate of ownership + */ +#define ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED 0x0800000000000000ULL + /** * Packet characteristics flag: TCP left-most reserved bit */ diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index 8305c489f..6fc59ad1c 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -43,4 +43,21 @@ int CertificateOfOwnership::verify(const RuntimeEnvironment *RR) const } } +bool CertificateOfOwnership::_owns(const CertificateOfOwnership::Thing &t,const void *v,unsigned int l) const +{ + for(unsigned int i=0,j=_thingCount;i(v)[k] != _thingValues[i][k]) + break; + ++k; + } + if (k == l) + return true; + } + } + return false; +} + } // namespace ZeroTier diff --git a/node/CertificateOfOwnership.hpp b/node/CertificateOfOwnership.hpp index 69b26aec3..7e71c9b26 100644 --- a/node/CertificateOfOwnership.hpp +++ b/node/CertificateOfOwnership.hpp @@ -84,37 +84,20 @@ public: inline const Address &issuedTo() const { return _issuedTo; } - inline bool owns(const Thing &t,const void *v,unsigned int l) - { - for(unsigned int i=0,j=_thingCount;i(v)[k] != _thingValues[i][k]) - break; - ++k; - } - if (k == l) - return true; - } - } - return false; - } - - inline bool owns(const InetAddress &ip) + inline bool owns(const InetAddress &ip) const { if (ip.ss_family == AF_INET) - return this->owns(THING_IPV4_ADDRESS,&(reinterpret_cast(&ip)->sin_addr.s_addr),4); + return this->_owns(THING_IPV4_ADDRESS,&(reinterpret_cast(&ip)->sin_addr.s_addr),4); if (ip.ss_family == AF_INET6) - return this->owns(THING_IPV6_ADDRESS,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); + return this->_owns(THING_IPV6_ADDRESS,reinterpret_cast(&ip)->sin6_addr.s6_addr,16); return false; } - inline bool owns(const MAC &mac) + inline bool owns(const MAC &mac) const { uint8_t tmp[6]; mac.copyTo(tmp,6); - return this->owns(THING_MAC_ADDRESS,tmp,6); + return this->_owns(THING_MAC_ADDRESS,tmp,6); } inline void addThing(const InetAddress &ip) @@ -234,6 +217,8 @@ public: inline bool operator!=(const CertificateOfOwnership &coo) const { return (memcmp(this,&coo,sizeof(CertificateOfOwnership)) != 0); } private: + bool _owns(const Thing &t,const void *v,unsigned int l) const; + uint64_t _networkId; uint64_t _ts; uint64_t _flags; diff --git a/node/Membership.cpp b/node/Membership.cpp index 1eacb93d1..5facbe24b 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -117,16 +117,10 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,const uint64_t now } } -const Capability *Membership::getCapability(const NetworkConfig &nconf,const uint32_t id) const -{ - const _RemoteCredential *const *c = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)id,_RemoteCredentialComp()); - return ( ((c != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*c)->id == (uint64_t)id)) ? ((((*c)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*c)->credential,**c))) ? &((*c)->credential) : (const Capability *)0) : (const Capability *)0); -} - const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) const { const _RemoteCredential *const *t = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)id,_RemoteCredentialComp()); - return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,(*t)->credential,**t))) ? &((*t)->credential) : (const Tag *)0) : (const Tag *)0); + return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,**t))) ? &((*t)->credential) : (const Tag *)0) : (const Tag *)0); } Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,const NetworkConfig &nconf,const CertificateOfMembership &com) @@ -165,7 +159,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme _RemoteCredential *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteCredential *)0; if (have) { - if ( (!_isCredentialTimestampValid(nconf,tag,*have)) || (have->credential.timestamp() > tag.timestamp()) ) { + if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > tag.timestamp()) ) { TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId()); return ADD_REJECTED; } @@ -195,7 +189,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCredential *)0; if (have) { - if ( (!_isCredentialTimestampValid(nconf,cap,*have)) || (have->credential.timestamp() > cap.timestamp()) ) { + if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > cap.timestamp()) ) { TRACE("addCredential(Capability) for %s on %.16llx REJECTED (revoked or too old)",cap.issuedTo().toString().c_str(),cap.networkId()); return ADD_REJECTED; } @@ -252,7 +246,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme _RemoteCredential *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)coo.id(),_RemoteCredentialComp()); _RemoteCredential *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)coo.id())) ? *htmp : (_RemoteCredential *)0; if (have) { - if ( (!_isCredentialTimestampValid(nconf,coo,*have)) || (have->credential.timestamp() > coo.timestamp()) ) { + if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > coo.timestamp()) ) { TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (revoked or too old)",cap.issuedTo().toString().c_str(),cap.networkId()); return ADD_REJECTED; } @@ -298,7 +292,7 @@ Membership::_RemoteCredential *Membership::_newTag(const uint64_t id) t->credential = Tag(); } - std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS])); + std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialComp()); return t; } @@ -323,7 +317,7 @@ Membership::_RemoteCredential *Membership::_newCapability(const uint c->credential = Capability(); } - std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES])); + std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialComp()); return c; } @@ -348,7 +342,7 @@ Membership::_RemoteCredential *Membership::_newCoo(const c->credential = CertificateOfOwnership(); } - std::sort(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP])); + std::sort(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),_RemoteCredentialComp()); return c; } diff --git a/node/Membership.hpp b/node/Membership.hpp index 4e9d77692..a77943288 100644 --- a/node/Membership.hpp +++ b/node/Membership.hpp @@ -99,7 +99,7 @@ public: for(;;) { if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) { const Capability *tmp = &((*_i)->credential); - if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) { + if (_m->_isCredentialTimestampValid(*_c,**_i)) { ++_i; return tmp; } else ++_i; @@ -132,7 +132,7 @@ public: for(;;) { if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) { const Tag *tmp = &((*_i)->credential); - if (_m->_isCredentialTimestampValid(*_c,*tmp,**_i)) { + if (_m->_isCredentialTimestampValid(*_c,**_i)) { ++_i; return tmp; } else ++_i; @@ -197,11 +197,24 @@ public: } /** - * @param nconf Network configuration - * @param id Capablity ID - * @return Pointer to capability or NULL if not found + * Check whether the peer represented by this Membership owns a given resource + * + * @tparam Type of resource: InetAddress or MAC + * @param nconf Our network config + * @param r Resource to check + * @return True if this peer has a certificate of ownership for the given resource */ - const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const; + template + inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const + { + for(unsigned int i=0;iid == ZT_MEMBERSHIP_CRED_ID_UNUSED) + break; + if ((_isCredentialTimestampValid(nconf,*_remoteCoos[i]))&&(_remoteCoos[i]->credential.owns(r))) + return true; + } + return false; + } /** * @param nconf Network configuration @@ -244,11 +257,13 @@ private: bool _revokeTag(const Revocation &rev,const uint64_t now); bool _revokeCoo(const Revocation &rev,const uint64_t now); - template - inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &cred,const CS &state) const + template + inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const _RemoteCredential &remoteCredential) const { - const uint64_t ts = cred.timestamp(); - return ( (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) && (ts > state.revocationThreshold) ); + if (!remoteCredential.lastReceived) + return false; + const uint64_t ts = remoteCredential.credential.timestamp(); + return ( (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) && (ts > remoteCredential.revocationThreshold) ); } // Last time we pushed MULTICAST_LIKE(s) diff --git a/node/Network.cpp b/node/Network.cpp index 290ceaf95..50df58bb5 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -299,6 +299,7 @@ static _doZtFilterResult _doZtFilter( // If this was not an ACTION evaluate next MATCH and update thisSetMatches with (AND [result]) uint8_t thisRuleMatches = 0; + uint64_t ownershipVerificationMask = 1; // this magic value means it hasn't been computed yet -- this is done lazily the first time it's needed switch(rt) { case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt()); @@ -507,6 +508,30 @@ static _doZtFilterResult _doZtFilter( uint64_t cf = (inbound) ? ZT_RULE_PACKET_CHARACTERISTICS_INBOUND : 0ULL; if (macDest.isMulticast()) cf |= ZT_RULE_PACKET_CHARACTERISTICS_MULTICAST; if (macDest.isBroadcast()) cf |= ZT_RULE_PACKET_CHARACTERISTICS_BROADCAST; + if (ownershipVerificationMask == 1) { + ownershipVerificationMask = 0; + InetAddress src; + if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) { + src.set((const void *)(frameData + 12),4,0); + } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) { + src.set((const void *)(frameData + 8),16,0); + } + if (inbound) { + if (membership) { + if ((src)&&(membership->hasCertificateOfOwnershipFor(nconf,src))) + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED; + if (membership->hasCertificateOfOwnershipFor(nconf,macSource)) + ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED; + } + } else { + for(unsigned int i=0;i= 20)&&(frameData[9] == 0x06)) { const unsigned int headerLen = 4 * (frameData[0] & 0xf); cf |= (uint64_t)frameData[headerLen + 13]; diff --git a/rule-compiler/package.json b/rule-compiler/package.json index 16f7a23fa..f0e747a23 100644 --- a/rule-compiler/package.json +++ b/rule-compiler/package.json @@ -1,6 +1,6 @@ { "name": "zerotier-rule-compiler", - "version": "1.1.17-1", + "version": "1.1.17-2", "description": "ZeroTier Rule Script Compiler", "main": "cli.js", "scripts": { diff --git a/rule-compiler/rule-compiler.js b/rule-compiler/rule-compiler.js index d927e512d..be4e5c640 100644 --- a/rule-compiler/rule-compiler.js +++ b/rule-compiler/rule-compiler.js @@ -5,6 +5,8 @@ const CHARACTERISTIC_BITS = { 'inbound': 63, 'multicast': 62, 'broadcast': 61, + 'ipauth': 60, + 'macauth': 59, 'tcp_fin': 0, 'tcp_syn': 1, 'tcp_rst': 2,