mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +02:00
Cleanup, remove legacy accessors, formatting.
This commit is contained in:
parent
a117c92a1e
commit
a19bc1e826
17 changed files with 630 additions and 615 deletions
|
@ -13,5 +13,5 @@
|
|||
|
||||
package cli
|
||||
|
||||
func Controller(basePath, authToken string, args []string, jsonOutput bool) {
|
||||
func Cert(basePath, authToken string, args []string, jsonOutput bool) {
|
||||
}
|
|
@ -79,7 +79,7 @@ Commands:
|
|||
validate <identity> Locally validate an identity
|
||||
sign <identity> <file> Sign a file with an identity's key
|
||||
verify <identity> <file> <sig> Verify a signature
|
||||
certificate <command> [args] - Certificate commands
|
||||
cert <command> [args] - Certificate commands
|
||||
newid Create a new unique subject ID
|
||||
newcsr <subject json path> Create a new CSR (signing request)
|
||||
sign <csr path> <identity path> Sign a CSR to create a certificate
|
||||
|
|
|
@ -139,12 +139,13 @@ func main() {
|
|||
cli.Peers(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag, true)
|
||||
case "root":
|
||||
cli.Root(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag)
|
||||
case "controller":
|
||||
case "set":
|
||||
cli.Set(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs)
|
||||
case "controller":
|
||||
cli.Controller(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag)
|
||||
case "identity":
|
||||
cli.Identity(cmdArgs)
|
||||
case "cert":
|
||||
cli.Cert(basePath, authTokenRequired(basePath, *tflag, *tTflag), cmdArgs, *jflag)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
|
@ -41,35 +41,18 @@ struct intl_MapHasher
|
|||
std::size_t operator()(const O &obj) const noexcept
|
||||
{ return (std::size_t)obj.hashCode(); }
|
||||
std::size_t operator()(const uint64_t i) const noexcept
|
||||
{ return (std::size_t)Utils::hash64(i + Utils::s_mapNonce); }
|
||||
{ return (std::size_t)Utils::hash64(i ^ Utils::s_mapNonce); }
|
||||
std::size_t operator()(const int64_t i) const noexcept
|
||||
{ return (std::size_t)Utils::hash64((uint64_t)i + Utils::s_mapNonce); }
|
||||
{ return (std::size_t)Utils::hash64((uint64_t)i ^ Utils::s_mapNonce); }
|
||||
std::size_t operator()(const uint32_t i) const noexcept
|
||||
{ return (std::size_t)Utils::hash32(i + (uint32_t)Utils::s_mapNonce); }
|
||||
{ return (std::size_t)Utils::hash32(i ^ (uint32_t)Utils::s_mapNonce); }
|
||||
std::size_t operator()(const int32_t i) const noexcept
|
||||
{ return (std::size_t)Utils::hash32((uint32_t)i + (uint32_t)Utils::s_mapNonce); }
|
||||
{ return (std::size_t)Utils::hash32((uint32_t)i ^ (uint32_t)Utils::s_mapNonce); }
|
||||
};
|
||||
|
||||
template< typename K, typename V >
|
||||
class Map : public std::unordered_map< K, V, intl_MapHasher >
|
||||
{
|
||||
public:
|
||||
ZT_INLINE V *get(const K &key) noexcept
|
||||
{
|
||||
typename Map::iterator i(this->find(key));
|
||||
if (i == this->end())
|
||||
return nullptr;
|
||||
return &(i->second);
|
||||
}
|
||||
ZT_INLINE const V *get(const K &key) const noexcept
|
||||
{
|
||||
typename Map::const_iterator i(this->find(key));
|
||||
if (i == this->end())
|
||||
return nullptr;
|
||||
return &(i->second);
|
||||
}
|
||||
ZT_INLINE void set(const K &key, const V &value) { this->emplace(key, value); }
|
||||
};
|
||||
{};
|
||||
|
||||
template< typename K, typename V >
|
||||
class MultiMap : public std::unordered_multimap< K, V, intl_MapHasher, std::equal_to< K > >
|
||||
|
@ -77,34 +60,13 @@ class MultiMap : public std::unordered_multimap< K, V, intl_MapHasher, std::equa
|
|||
|
||||
#else
|
||||
|
||||
template<typename K,typename V>
|
||||
class Map : public std::map< K,V,std::less<K> >
|
||||
{
|
||||
public:
|
||||
ZT_INLINE V *get(const K &key) noexcept
|
||||
{
|
||||
typename Map::iterator i(this->find(key));
|
||||
if (i == this->end())
|
||||
return nullptr;
|
||||
return &(i->second);
|
||||
}
|
||||
template<typename K, typename V>
|
||||
class Map : public std::map< K, V >
|
||||
{};
|
||||
|
||||
ZT_INLINE const V *get(const K &key) const noexcept
|
||||
{
|
||||
typename Map::const_iterator i(this->find(key));
|
||||
if (i == this->end())
|
||||
return nullptr;
|
||||
return &(i->second);
|
||||
}
|
||||
|
||||
ZT_INLINE void set(const K &key,const V &value)
|
||||
{ (*this)[key] = value; }
|
||||
};
|
||||
|
||||
template<typename K,typename V>
|
||||
class MultiMap : public std::multimap< K,V,std::less<K>,Utils::Mallocator< std::pair<const K,V> > >
|
||||
{
|
||||
};
|
||||
template<typename K, typename V>
|
||||
class MultiMap : public std::multimap< K, V >
|
||||
{};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -167,15 +167,15 @@ public:
|
|||
// under the target size. This tries to minimize the amount of time the write
|
||||
// lock is held since many threads can hold the read lock but all threads must
|
||||
// wait if someone holds the write lock.
|
||||
std::vector<std::pair<int64_t, uint64_t> > messagesByLastUsedTime;
|
||||
std::vector< std::pair< int64_t, uint64_t > > messagesByLastUsedTime;
|
||||
messagesByLastUsedTime.reserve(m_messages.size());
|
||||
|
||||
for (typename Map<uint64_t, p_E>::const_iterator i(m_messages.begin());i != m_messages.end();++i)
|
||||
messagesByLastUsedTime.push_back(std::pair<int64_t, uint64_t>(i->second.lastUsed, i->first));
|
||||
for (typename Map< uint64_t, p_E >::const_iterator i(m_messages.begin()); i != m_messages.end(); ++i)
|
||||
messagesByLastUsedTime.push_back(std::pair< int64_t, uint64_t >(i->second.lastUsed, i->first));
|
||||
std::sort(messagesByLastUsedTime.begin(), messagesByLastUsedTime.end());
|
||||
|
||||
ml.writing(); // acquire write lock on _messages
|
||||
for (unsigned long x = 0, y = (messagesByLastUsedTime.size() - GCS);x <= y;++x)
|
||||
for (unsigned long x = 0, y = (messagesByLastUsedTime.size() - GCS); x <= y; ++x)
|
||||
m_messages.erase(messagesByLastUsedTime[x].second);
|
||||
} catch (...) {
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
|
@ -183,15 +183,20 @@ public:
|
|||
}
|
||||
|
||||
// Get or create message fragment.
|
||||
p_E *e = m_messages.get(messageId);
|
||||
if (!e) {
|
||||
ml.writing(); // acquire write lock on _messages if not already
|
||||
try {
|
||||
e = &(m_messages[messageId]);
|
||||
} catch (...) {
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
Defragmenter< MF, MFP, GCS, GCT, P >::p_E *e;
|
||||
{
|
||||
typename Map< uint64_t, Defragmenter< MF, MFP, GCS, GCT, P >::p_E >::iterator ee(m_messages.find(messageId));
|
||||
if (ee == m_messages.end()) {
|
||||
ml.writing(); // acquire write lock on _messages if not already
|
||||
try {
|
||||
e = &(m_messages[messageId]);
|
||||
} catch (...) {
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
e->id = messageId;
|
||||
} else {
|
||||
e = &(ee->second);
|
||||
}
|
||||
e->id = messageId;
|
||||
}
|
||||
|
||||
// Switch back to holding only the read lock on _messages if we have locked for write
|
||||
|
@ -343,7 +348,7 @@ private:
|
|||
Mutex lock;
|
||||
};
|
||||
|
||||
Map <uint64_t, Defragmenter<MF, MFP, GCS, GCT, P>::p_E> m_messages;
|
||||
Map <uint64_t, Defragmenter< MF, MFP, GCS, GCT, P >::p_E> m_messages;
|
||||
RWMutex m_messages_l;
|
||||
};
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ void Member::pushCredentials(const RuntimeEnvironment *RR, void *tPtr, const int
|
|||
m_lastPushedCredentials = now;
|
||||
}
|
||||
|
||||
void Member::clean(const int64_t now, const NetworkConfig &nconf)
|
||||
void Member::clean(const NetworkConfig &nconf)
|
||||
{
|
||||
m_cleanCredImpl< TagCredential >(nconf, m_remoteTags);
|
||||
m_cleanCredImpl< CapabilityCredential >(nconf, m_remoteCaps);
|
||||
|
@ -164,18 +164,18 @@ static ZT_INLINE Member::AddCredentialResult _addCredImpl(
|
|||
const NetworkConfig &nconf,
|
||||
const C &cred)
|
||||
{
|
||||
C *rc = remoteCreds.get(cred.id());
|
||||
if (rc) {
|
||||
if (rc->timestamp() > cred.timestamp()) {
|
||||
typename Map< uint32_t, C >::const_iterator rc(remoteCreds.find(cred.id()));
|
||||
if (rc != remoteCreds.end()) {
|
||||
if (rc->second.timestamp() > cred.timestamp()) {
|
||||
RR->t->credentialRejected(tPtr, 0x40000001, nconf.networkId, sourcePeerIdentity, cred.id(), cred.timestamp(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
|
||||
return Member::ADD_REJECTED;
|
||||
}
|
||||
if (*rc == cred)
|
||||
if (rc->second == cred)
|
||||
return Member::ADD_ACCEPTED_REDUNDANT;
|
||||
}
|
||||
|
||||
const int64_t *const rt = revocations.get(Member::credentialKey(C::credentialType(), cred.id()));
|
||||
if ((rt) && (*rt >= cred.timestamp())) {
|
||||
typename Map< uint64_t, int64_t >::const_iterator rt(revocations.find(Member::credentialKey(C::credentialType(), cred.id())));
|
||||
if ((rt != revocations.end()) && (rt->second >= cred.timestamp())) {
|
||||
RR->t->credentialRejected(tPtr, 0x24248124, nconf.networkId, sourcePeerIdentity, cred.id(), cred.timestamp(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
|
||||
return Member::ADD_REJECTED;
|
||||
}
|
||||
|
@ -185,9 +185,8 @@ static ZT_INLINE Member::AddCredentialResult _addCredImpl(
|
|||
RR->t->credentialRejected(tPtr, 0x01feba012, nconf.networkId, sourcePeerIdentity, cred.id(), cred.timestamp(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
|
||||
return Member::ADD_REJECTED;
|
||||
case 0:
|
||||
if (!rc)
|
||||
rc = &(remoteCreds[cred.id()]);
|
||||
*rc = cred;
|
||||
if (rc == remoteCreds.end())
|
||||
remoteCreds[cred.id()] = cred;
|
||||
return Member::ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return Member::ADD_DEFERRED_FOR_WHOIS;
|
||||
|
|
|
@ -73,17 +73,16 @@ public:
|
|||
*/
|
||||
ZT_INLINE const TagCredential *getTag(const NetworkConfig &nconf, const uint32_t id) const noexcept
|
||||
{
|
||||
const TagCredential *const t = m_remoteTags.get(id);
|
||||
return (((t)&&(m_isCredentialTimestampValid(nconf, *t))) ? t : (TagCredential *)0);
|
||||
Map< uint32_t, TagCredential >::const_iterator t(m_remoteTags.find(id));
|
||||
return (((t != m_remoteTags.end())&&(m_isCredentialTimestampValid(nconf, t->second))) ? &(t->second) : (TagCredential *)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean internal databases of stale entries
|
||||
*
|
||||
* @param now Current time
|
||||
* @param nconf Current network configuration
|
||||
*/
|
||||
void clean(int64_t now,const NetworkConfig &nconf);
|
||||
void clean(const NetworkConfig &nconf);
|
||||
|
||||
/**
|
||||
* Generates a key for internal use in indexing credentials by type and credential ID
|
||||
|
@ -166,8 +165,8 @@ private:
|
|||
{
|
||||
const int64_t ts = remoteCredential.timestamp();
|
||||
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
|
||||
const int64_t *threshold = m_revocations.get(credentialKey(C::credentialType(), remoteCredential.id()));
|
||||
return ((!threshold)||(ts > *threshold));
|
||||
Map< uint64_t, int64_t >::const_iterator threshold(m_revocations.find(credentialKey(C::credentialType(), remoteCredential.id())));
|
||||
return ((threshold == m_revocations.end())||(ts > threshold->second));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
362
core/Network.cpp
362
core/Network.cpp
|
@ -33,14 +33,14 @@ namespace ZeroTier {
|
|||
namespace {
|
||||
|
||||
// Returns true if packet appears valid; pos and proto will be set
|
||||
bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto) noexcept
|
||||
bool _ipv6GetPayload(const uint8_t *frameData, unsigned int frameLen, unsigned int &pos, unsigned int &proto) noexcept
|
||||
{
|
||||
if (frameLen < 40)
|
||||
return false;
|
||||
pos = 40;
|
||||
proto = frameData[6];
|
||||
while (pos <= frameLen) {
|
||||
switch(proto) {
|
||||
switch (proto) {
|
||||
case 0: // hop-by-hop options
|
||||
case 43: // routing
|
||||
case 60: // destination options
|
||||
|
@ -51,9 +51,9 @@ bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int
|
|||
pos += ((unsigned int)frameData[pos + 1] * 8) + 8;
|
||||
break;
|
||||
|
||||
//case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway
|
||||
//case 50:
|
||||
//case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff
|
||||
//case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway
|
||||
//case 50:
|
||||
//case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -100,13 +100,13 @@ _doZtFilterResult _doZtFilter(
|
|||
|
||||
rrl.clear();
|
||||
|
||||
for(unsigned int rn=0;rn<ruleCount;++rn) {
|
||||
for (unsigned int rn = 0; rn < ruleCount; ++rn) {
|
||||
const ZT_VirtualNetworkRuleType rt = (ZT_VirtualNetworkRuleType)(rules[rn].t & 0x3fU);
|
||||
|
||||
// First check if this is an ACTION
|
||||
if ((unsigned int)rt <= (unsigned int)ZT_NETWORK_RULE_ACTION__MAX_ID) {
|
||||
if (thisSetMatches) {
|
||||
switch(rt) {
|
||||
switch (rt) {
|
||||
case ZT_NETWORK_RULE_ACTION_PRIORITY:
|
||||
qosBucket = (rules[rn].v.qosBucket >= 0 && rules[rn].v.qosBucket <= 8) ? rules[rn].v.qosBucket : 4; // 4 = default bucket (no priority)
|
||||
return DOZTFILTER_ACCEPT;
|
||||
|
@ -117,10 +117,10 @@ _doZtFilterResult _doZtFilter(
|
|||
case ZT_NETWORK_RULE_ACTION_ACCEPT:
|
||||
return (superAccept ? DOZTFILTER_SUPER_ACCEPT : DOZTFILTER_ACCEPT); // match, accept packet
|
||||
|
||||
// These are initially handled together since preliminary logic is common
|
||||
// These are initially handled together since preliminary logic is common
|
||||
case ZT_NETWORK_RULE_ACTION_TEE:
|
||||
case ZT_NETWORK_RULE_ACTION_WATCH:
|
||||
case ZT_NETWORK_RULE_ACTION_REDIRECT: {
|
||||
case ZT_NETWORK_RULE_ACTION_REDIRECT: {
|
||||
const Address fwdAddr(rules[rn].v.fwd.address);
|
||||
if (fwdAddr == ztSource) {
|
||||
// Skip as no-op since source is target
|
||||
|
@ -140,12 +140,13 @@ _doZtFilterResult _doZtFilter(
|
|||
ccWatch = (rt == ZT_NETWORK_RULE_ACTION_WATCH);
|
||||
}
|
||||
}
|
||||
} continue;
|
||||
}
|
||||
continue;
|
||||
|
||||
case ZT_NETWORK_RULE_ACTION_BREAK:
|
||||
return DOZTFILTER_NO_MATCH;
|
||||
|
||||
// Unrecognized ACTIONs are ignored as no-ops
|
||||
// Unrecognized ACTIONs are ignored as no-ops
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
@ -154,7 +155,7 @@ _doZtFilterResult _doZtFilter(
|
|||
// super-accept if we accept at all. This will cause us to accept redirected or
|
||||
// tee'd packets in spite of MAC and ZT addressing checks.
|
||||
if (inbound) {
|
||||
switch(rt) {
|
||||
switch (rt) {
|
||||
case ZT_NETWORK_RULE_ACTION_TEE:
|
||||
case ZT_NETWORK_RULE_ACTION_WATCH:
|
||||
case ZT_NETWORK_RULE_ACTION_REDIRECT:
|
||||
|
@ -173,15 +174,15 @@ _doZtFilterResult _doZtFilter(
|
|||
|
||||
// Circuit breaker: no need to evaluate an AND if the set's match state
|
||||
// is currently false since anything AND false is false.
|
||||
if ((!thisSetMatches)&&(!(rules[rn].t & 0x40U))) {
|
||||
rrl.logSkipped(rn,thisSetMatches);
|
||||
if ((!thisSetMatches) && (!(rules[rn].t & 0x40U))) {
|
||||
rrl.logSkipped(rn, thisSetMatches);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
switch (rt) {
|
||||
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
|
||||
thisRuleMatches = (uint8_t)(rules[rn].v.zt == ztSource.toInt());
|
||||
break;
|
||||
|
@ -206,50 +207,50 @@ _doZtFilterResult _doZtFilter(
|
|||
thisRuleMatches = (uint8_t)(MAC(rules[rn].v.mac) == macDest);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
||||
thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12),4,0)));
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) {
|
||||
thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip), 4, rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 12), 4, 0)));
|
||||
} else {
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
||||
thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip),4,rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16),4,0)));
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) {
|
||||
thisRuleMatches = (uint8_t)(InetAddress((const void *)&(rules[rn].v.ipv4.ip), 4, rules[rn].v.ipv4.mask).containsAddress(InetAddress((const void *)(frameData + 16), 4, 0)));
|
||||
} else {
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
|
||||
if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
|
||||
thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8),16,0)));
|
||||
if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) {
|
||||
thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip, 16, rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 8), 16, 0)));
|
||||
} else {
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
|
||||
if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
|
||||
thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip,16,rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24),16,0)));
|
||||
if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) {
|
||||
thisRuleMatches = (uint8_t)(InetAddress((const void *)rules[rn].v.ipv6.ip, 16, rules[rn].v.ipv6.mask).containsAddress(InetAddress((const void *)(frameData + 24), 16, 0)));
|
||||
} else {
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_TOS:
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) {
|
||||
const uint8_t tosMasked = frameData[1] & rules[rn].v.ipTos.mask;
|
||||
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
|
||||
} else if ((etherType == ZT_ETHERTYPE_IPV6)&&(frameLen >= 40)) {
|
||||
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0]) && (tosMasked <= rules[rn].v.ipTos.value[1]));
|
||||
} else if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) {
|
||||
const uint8_t tosMasked = (((frameData[0] << 4U) & 0xf0U) | ((frameData[1] >> 4U) & 0x0fU)) & rules[rn].v.ipTos.mask;
|
||||
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0])&&(tosMasked <= rules[rn].v.ipTos.value[1]));
|
||||
thisRuleMatches = (uint8_t)((tosMasked >= rules[rn].v.ipTos.value[0]) && (tosMasked <= rules[rn].v.ipTos.value[1]));
|
||||
} else {
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) {
|
||||
thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == frameData[9]);
|
||||
} else if (etherType == ZT_ETHERTYPE_IPV6) {
|
||||
unsigned int pos = 0,proto = 0;
|
||||
if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
|
||||
unsigned int pos = 0, proto = 0;
|
||||
if (_ipv6GetPayload(frameData, frameLen, pos, proto)) {
|
||||
thisRuleMatches = (uint8_t)(rules[rn].v.ipProtocol == (uint8_t)proto);
|
||||
} else {
|
||||
thisRuleMatches = 0;
|
||||
|
@ -262,13 +263,13 @@ _doZtFilterResult _doZtFilter(
|
|||
thisRuleMatches = (uint8_t)(rules[rn].v.etherType == (uint16_t)etherType);
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_ICMP:
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) {
|
||||
if (frameData[9] == 0x01) { // IP protocol == ICMP
|
||||
const unsigned int ihl = (frameData[0] & 0xfU) * 4;
|
||||
if (frameLen >= (ihl + 2)) {
|
||||
if (rules[rn].v.icmp.type == frameData[ihl]) {
|
||||
if ((rules[rn].v.icmp.flags & 0x01) != 0) {
|
||||
thisRuleMatches = (uint8_t)(frameData[ihl+1] == rules[rn].v.icmp.code);
|
||||
thisRuleMatches = (uint8_t)(frameData[ihl + 1] == rules[rn].v.icmp.code);
|
||||
} else {
|
||||
thisRuleMatches = 1;
|
||||
}
|
||||
|
@ -282,12 +283,12 @@ _doZtFilterResult _doZtFilter(
|
|||
thisRuleMatches = 0;
|
||||
}
|
||||
} else if (etherType == ZT_ETHERTYPE_IPV6) {
|
||||
unsigned int pos = 0,proto = 0;
|
||||
if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
|
||||
if ((proto == 0x3a)&&(frameLen >= (pos+2))) {
|
||||
unsigned int pos = 0, proto = 0;
|
||||
if (_ipv6GetPayload(frameData, frameLen, pos, proto)) {
|
||||
if ((proto == 0x3a) && (frameLen >= (pos + 2))) {
|
||||
if (rules[rn].v.icmp.type == frameData[pos]) {
|
||||
if ((rules[rn].v.icmp.flags & 0x01) != 0) {
|
||||
thisRuleMatches = (uint8_t)(frameData[pos+1] == rules[rn].v.icmp.code);
|
||||
thisRuleMatches = (uint8_t)(frameData[pos + 1] == rules[rn].v.icmp.code);
|
||||
} else {
|
||||
thisRuleMatches = 1;
|
||||
}
|
||||
|
@ -306,10 +307,10 @@ _doZtFilterResult _doZtFilter(
|
|||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
|
||||
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)) {
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) {
|
||||
const unsigned int headerLen = 4 * (frameData[0] & 0xfU);
|
||||
int p = -1;
|
||||
switch(frameData[9]) { // IP protocol number
|
||||
switch (frameData[9]) { // IP protocol number
|
||||
// All these start with 16-bit source and destination port in that order
|
||||
case 0x06: // TCP
|
||||
case 0x11: // UDP
|
||||
|
@ -323,12 +324,12 @@ _doZtFilterResult _doZtFilter(
|
|||
break;
|
||||
}
|
||||
|
||||
thisRuleMatches = (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0;
|
||||
thisRuleMatches = (p >= 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0]) && (p <= (int)rules[rn].v.port[1])) : (uint8_t)0;
|
||||
} else if (etherType == ZT_ETHERTYPE_IPV6) {
|
||||
unsigned int pos = 0,proto = 0;
|
||||
if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
|
||||
unsigned int pos = 0, proto = 0;
|
||||
if (_ipv6GetPayload(frameData, frameLen, pos, proto)) {
|
||||
int p = -1;
|
||||
switch(proto) { // IP protocol number
|
||||
switch (proto) { // IP protocol number
|
||||
// All these start with 16-bit source and destination port in that order
|
||||
case 0x06: // TCP
|
||||
case 0x11: // UDP
|
||||
|
@ -341,7 +342,7 @@ _doZtFilterResult _doZtFilter(
|
|||
}
|
||||
break;
|
||||
}
|
||||
thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0])&&(p <= (int)rules[rn].v.port[1])) : (uint8_t)0;
|
||||
thisRuleMatches = (p > 0) ? (uint8_t)((p >= (int)rules[rn].v.port[0]) && (p <= (int)rules[rn].v.port[1])) : (uint8_t)0;
|
||||
} else {
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
|
@ -356,11 +357,11 @@ _doZtFilterResult _doZtFilter(
|
|||
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)) {
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20)) {
|
||||
src.set((const void *)(frameData + 12), 4, 0);
|
||||
} else if ((etherType == ZT_ETHERTYPE_IPV6) && (frameLen >= 40)) {
|
||||
// IPv6 NDP requires special handling, since the src and dest IPs in the packet are empty or link-local.
|
||||
if ( (frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) && ((frameData[40] == 0x87)||(frameData[40] == 0x88)) ) {
|
||||
if ((frameLen >= (40 + 8 + 16)) && (frameData[6] == 0x3a) && ((frameData[40] == 0x87) || (frameData[40] == 0x88))) {
|
||||
if (frameData[40] == 0x87) {
|
||||
// Neighbor solicitations contain no reliable source address, so we implement a small
|
||||
// hack by considering them authenticated. Otherwise you would pretty much have to do
|
||||
|
@ -368,25 +369,25 @@ _doZtFilterResult _doZtFilter(
|
|||
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED;
|
||||
} else {
|
||||
// Neighbor advertisements on the other hand can absolutely be authenticated.
|
||||
src.set((const void *)(frameData + 40 + 8),16,0);
|
||||
src.set((const void *)(frameData + 40 + 8), 16, 0);
|
||||
}
|
||||
} else {
|
||||
// Other IPv6 packets can be handled normally
|
||||
src.set((const void *)(frameData + 8),16,0);
|
||||
src.set((const void *)(frameData + 8), 16, 0);
|
||||
}
|
||||
} else if ((etherType == ZT_ETHERTYPE_ARP)&&(frameLen >= 28)) {
|
||||
src.set((const void *)(frameData + 14),4,0);
|
||||
} else if ((etherType == ZT_ETHERTYPE_ARP) && (frameLen >= 28)) {
|
||||
src.set((const void *)(frameData + 14), 4, 0);
|
||||
}
|
||||
if (inbound) {
|
||||
if (membership) {
|
||||
if ((src)&&(membership->peerOwnsAddress<InetAddress>(nconf,src)))
|
||||
if ((src) && (membership->peerOwnsAddress< InetAddress >(nconf, src)))
|
||||
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED;
|
||||
if (membership->peerOwnsAddress<MAC>(nconf,macSource))
|
||||
if (membership->peerOwnsAddress< MAC >(nconf, macSource))
|
||||
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED;
|
||||
}
|
||||
} else {
|
||||
for(unsigned int i=0;i<nconf.certificateOfOwnershipCount;++i) {
|
||||
if ((src)&&(nconf.certificatesOfOwnership[i].owns(src)))
|
||||
for (unsigned int i = 0; i < nconf.certificateOfOwnershipCount; ++i) {
|
||||
if ((src) && (nconf.certificatesOfOwnership[i].owns(src)))
|
||||
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED;
|
||||
if (nconf.certificatesOfOwnership[i].owns(macSource))
|
||||
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED;
|
||||
|
@ -394,23 +395,24 @@ _doZtFilterResult _doZtFilter(
|
|||
}
|
||||
}
|
||||
cf |= ownershipVerificationMask;
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4)&&(frameLen >= 20)&&(frameData[9] == 0x06)) {
|
||||
if ((etherType == ZT_ETHERTYPE_IPV4) && (frameLen >= 20) && (frameData[9] == 0x06)) {
|
||||
const unsigned int headerLen = 4 * (frameData[0] & 0xfU);
|
||||
cf |= (uint64_t)frameData[headerLen + 13];
|
||||
cf |= (((uint64_t)(frameData[headerLen + 12] & 0x0fU)) << 8U);
|
||||
} else if (etherType == ZT_ETHERTYPE_IPV6) {
|
||||
unsigned int pos = 0,proto = 0;
|
||||
if (_ipv6GetPayload(frameData,frameLen,pos,proto)) {
|
||||
if ((proto == 0x06)&&(frameLen > (pos + 14))) {
|
||||
unsigned int pos = 0, proto = 0;
|
||||
if (_ipv6GetPayload(frameData, frameLen, pos, proto)) {
|
||||
if ((proto == 0x06) && (frameLen > (pos + 14))) {
|
||||
cf |= (uint64_t)frameData[pos + 13];
|
||||
cf |= (((uint64_t)(frameData[pos + 12] & 0x0fU)) << 8U);
|
||||
}
|
||||
}
|
||||
}
|
||||
thisRuleMatches = (uint8_t)((cf & rules[rn].v.characteristics) != 0);
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
|
||||
thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0])&&(frameLen <= (unsigned int)rules[rn].v.frameSize[1]));
|
||||
thisRuleMatches = (uint8_t)((frameLen >= (unsigned int)rules[rn].v.frameSize[0]) && (frameLen <= (unsigned int)rules[rn].v.frameSize[1]));
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_RANDOM:
|
||||
thisRuleMatches = (uint8_t)((uint32_t)(Utils::random() & 0xffffffffULL) <= rules[rn].v.randomProbability);
|
||||
|
@ -421,7 +423,7 @@ _doZtFilterResult _doZtFilter(
|
|||
case ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR:
|
||||
case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: {
|
||||
const TagCredential *const localTag = std::lower_bound(&(nconf.tags[0]), &(nconf.tags[nconf.tagCount]), rules[rn].v.tag.id, TagCredential::IdComparePredicate());
|
||||
if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) {
|
||||
if ((localTag != &(nconf.tags[nconf.tagCount])) && (localTag->id() == rules[rn].v.tag.id)) {
|
||||
const TagCredential *const remoteTag = ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const TagCredential *)0);
|
||||
if (remoteTag) {
|
||||
const uint32_t ltv = localTag->value();
|
||||
|
@ -436,12 +438,12 @@ _doZtFilterResult _doZtFilter(
|
|||
} else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_BITWISE_XOR) {
|
||||
thisRuleMatches = (uint8_t)((ltv ^ rtv) == rules[rn].v.tag.value);
|
||||
} else if (rt == ZT_NETWORK_RULE_MATCH_TAGS_EQUAL) {
|
||||
thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value)&&(rtv == rules[rn].v.tag.value));
|
||||
thisRuleMatches = (uint8_t)((ltv == rules[rn].v.tag.value) && (rtv == rules[rn].v.tag.value));
|
||||
} else { // sanity check, can't really happen
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
} else {
|
||||
if ((inbound)&&(!superAccept)) {
|
||||
if ((inbound) && (!superAccept)) {
|
||||
thisRuleMatches = 0;
|
||||
} else {
|
||||
// Outbound side is not strict since if we have to match both tags and
|
||||
|
@ -455,12 +457,13 @@ _doZtFilterResult _doZtFilter(
|
|||
} else {
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
|
||||
case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: {
|
||||
if (superAccept) {
|
||||
thisRuleMatches = 1;
|
||||
} else if ( ((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER)&&(inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER)&&(!inbound)) ) {
|
||||
} else if (((rt == ZT_NETWORK_RULE_MATCH_TAG_SENDER) && (inbound)) || ((rt == ZT_NETWORK_RULE_MATCH_TAG_RECEIVER) && (!inbound))) {
|
||||
const TagCredential *const remoteTag = ((membership) ? membership->getTag(nconf, rules[rn].v.tag.id) : (const TagCredential *)0);
|
||||
if (remoteTag) {
|
||||
thisRuleMatches = (uint8_t)(remoteTag->value() == rules[rn].v.tag.value);
|
||||
|
@ -475,13 +478,14 @@ _doZtFilterResult _doZtFilter(
|
|||
}
|
||||
} else { // sender and outbound or receiver and inbound
|
||||
const TagCredential *const localTag = std::lower_bound(&(nconf.tags[0]), &(nconf.tags[nconf.tagCount]), rules[rn].v.tag.id, TagCredential::IdComparePredicate());
|
||||
if ((localTag != &(nconf.tags[nconf.tagCount]))&&(localTag->id() == rules[rn].v.tag.id)) {
|
||||
if ((localTag != &(nconf.tags[nconf.tagCount])) && (localTag->id() == rules[rn].v.tag.id)) {
|
||||
thisRuleMatches = (uint8_t)(localTag->value() == rules[rn].v.tag.value);
|
||||
} else {
|
||||
thisRuleMatches = 0;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: {
|
||||
uint64_t integer = 0;
|
||||
const unsigned int bits = (rules[rn].v.intRange.format & 63U) + 1;
|
||||
|
@ -509,17 +513,18 @@ _doZtFilterResult _doZtFilter(
|
|||
}
|
||||
integer >>= (64 - bits);
|
||||
}
|
||||
thisRuleMatches = (uint8_t)((integer >= rules[rn].v.intRange.start)&&(integer <= (rules[rn].v.intRange.start + (uint64_t)rules[rn].v.intRange.end)));
|
||||
} break;
|
||||
thisRuleMatches = (uint8_t)((integer >= rules[rn].v.intRange.start) && (integer <= (rules[rn].v.intRange.start + (uint64_t)rules[rn].v.intRange.end)));
|
||||
}
|
||||
break;
|
||||
|
||||
// The result of an unsupported MATCH is configurable at the network
|
||||
// level via a flag.
|
||||
// The result of an unsupported MATCH is configurable at the network
|
||||
// level via a flag.
|
||||
default:
|
||||
thisRuleMatches = (uint8_t)((nconf.flags & ZT_NETWORKCONFIG_FLAG_RULES_RESULT_OF_UNSUPPORTED_MATCH) != 0);
|
||||
break;
|
||||
}
|
||||
|
||||
rrl.log(rn,thisRuleMatches,thisSetMatches);
|
||||
rrl.log(rn, thisRuleMatches, thisSetMatches);
|
||||
|
||||
if ((rules[rn].t & 0x40U))
|
||||
thisSetMatches |= (thisRuleMatches ^ ((rules[rn].t >> 7U) & 1U));
|
||||
|
@ -531,9 +536,9 @@ _doZtFilterResult _doZtFilter(
|
|||
|
||||
} // anonymous namespace
|
||||
|
||||
const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL),0);
|
||||
const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffULL), 0);
|
||||
|
||||
Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,const Fingerprint &controllerFingerprint,void *uptr,const NetworkConfig *nconf) :
|
||||
Network::Network(const RuntimeEnvironment *renv, void *tPtr, uint64_t nwid, const Fingerprint &controllerFingerprint, void *uptr, const NetworkConfig *nconf) :
|
||||
RR(renv),
|
||||
m_uPtr(uptr),
|
||||
m_id(nwid),
|
||||
|
@ -547,33 +552,34 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,const F
|
|||
m_controllerFingerprint = controllerFingerprint;
|
||||
|
||||
if (nconf) {
|
||||
this->setConfiguration(tPtr,*nconf,false);
|
||||
this->setConfiguration(tPtr, *nconf, false);
|
||||
m_lastConfigUpdate = 0; // still want to re-request since it's likely outdated
|
||||
} else {
|
||||
uint64_t tmp[2];
|
||||
tmp[0] = nwid; tmp[1] = 0;
|
||||
tmp[0] = nwid;
|
||||
tmp[1] = 0;
|
||||
|
||||
bool got = false;
|
||||
try {
|
||||
Dictionary dict;
|
||||
Vector<uint8_t> nconfData(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp));
|
||||
Vector< uint8_t > nconfData(RR->node->stateObjectGet(tPtr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp));
|
||||
if (nconfData.size() > 2) {
|
||||
nconfData.push_back(0);
|
||||
if (dict.decode(nconfData.data(),(unsigned int)nconfData.size())) {
|
||||
if (dict.decode(nconfData.data(), (unsigned int)nconfData.size())) {
|
||||
try {
|
||||
ScopedPtr<NetworkConfig> nconf2(new NetworkConfig());
|
||||
ScopedPtr< NetworkConfig > nconf2(new NetworkConfig());
|
||||
if (nconf2->fromDictionary(dict)) {
|
||||
this->setConfiguration(tPtr,*nconf2,false);
|
||||
this->setConfiguration(tPtr, *nconf2, false);
|
||||
m_lastConfigUpdate = 0; // still want to re-request an update since it's likely outdated
|
||||
got = true;
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
} catch (...) {}
|
||||
|
||||
if (!got)
|
||||
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,"\n",1);
|
||||
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, "\n", 1);
|
||||
}
|
||||
|
||||
if (!m_portInitialized) {
|
||||
|
@ -615,7 +621,7 @@ bool Network::filterOutgoingPacket(
|
|||
const unsigned int vlanId,
|
||||
uint8_t &qosBucket)
|
||||
{
|
||||
Trace::RuleResultLog rrl,crrl;
|
||||
Trace::RuleResultLog rrl, crrl;
|
||||
Address ztFinalDest(ztDest);
|
||||
int localCapabilityIndex = -1;
|
||||
int accept = 0;
|
||||
|
@ -626,12 +632,19 @@ bool Network::filterOutgoingPacket(
|
|||
Mutex::Lock l1(m_memberships_l);
|
||||
Mutex::Lock l2(m_config_l);
|
||||
|
||||
Member *const membership = (ztDest) ? m_memberships.get(ztDest) : nullptr;
|
||||
Member *membership;
|
||||
if (ztDest) {
|
||||
Map<Address, Member>::iterator mm(m_memberships.find(ztDest));
|
||||
if (mm != m_memberships.end())
|
||||
membership = &(mm->second);
|
||||
} else {
|
||||
membership = nullptr;
|
||||
}
|
||||
|
||||
switch(_doZtFilter(RR, rrl, m_config, membership, false, ztSource, ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.rules, m_config.ruleCount, cc, ccLength, ccWatch, qosBucket)) {
|
||||
switch (_doZtFilter(RR, rrl, m_config, membership, false, ztSource, ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.rules, m_config.ruleCount, cc, ccLength, ccWatch, qosBucket)) {
|
||||
|
||||
case DOZTFILTER_NO_MATCH: {
|
||||
for(unsigned int c=0;c < m_config.capabilityCount;++c) {
|
||||
for (unsigned int c = 0; c < m_config.capabilityCount; ++c) {
|
||||
ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match
|
||||
Address cc2;
|
||||
unsigned int ccLength2 = 0;
|
||||
|
@ -647,7 +660,7 @@ bool Network::filterOutgoingPacket(
|
|||
localCapabilityIndex = (int)c;
|
||||
accept = 1;
|
||||
|
||||
if ((!noTee)&&(cc2)) {
|
||||
if ((!noTee) && (cc2)) {
|
||||
// TODO
|
||||
/*
|
||||
Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||
|
@ -667,7 +680,8 @@ bool Network::filterOutgoingPacket(
|
|||
if (accept)
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOZTFILTER_DROP:
|
||||
RR->t->networkFilter(tPtr, 0xadea5a2a, m_id, rrl.l, nullptr, 0, 0, ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, 0);
|
||||
|
@ -684,7 +698,7 @@ bool Network::filterOutgoingPacket(
|
|||
}
|
||||
|
||||
if (accept != 0) {
|
||||
if ((!noTee)&&(cc)) {
|
||||
if ((!noTee) && (cc)) {
|
||||
// TODO
|
||||
/*
|
||||
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||
|
@ -699,7 +713,7 @@ bool Network::filterOutgoingPacket(
|
|||
*/
|
||||
}
|
||||
|
||||
if ((ztDest != ztFinalDest)&&(ztFinalDest)) {
|
||||
if ((ztDest != ztFinalDest) && (ztFinalDest)) {
|
||||
// TODO
|
||||
/*
|
||||
Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||
|
@ -730,7 +744,7 @@ bool Network::filterOutgoingPacket(
|
|||
|
||||
int Network::filterIncomingPacket(
|
||||
void *tPtr,
|
||||
const SharedPtr<Peer> &sourcePeer,
|
||||
const SharedPtr< Peer > &sourcePeer,
|
||||
const Address &ztDest,
|
||||
const MAC &macSource,
|
||||
const MAC &macDest,
|
||||
|
@ -740,7 +754,7 @@ int Network::filterIncomingPacket(
|
|||
const unsigned int vlanId)
|
||||
{
|
||||
Address ztFinalDest(ztDest);
|
||||
Trace::RuleResultLog rrl,crrl;
|
||||
Trace::RuleResultLog rrl, crrl;
|
||||
int accept = 0;
|
||||
Address cc;
|
||||
unsigned int ccLength = 0;
|
||||
|
@ -763,7 +777,7 @@ int Network::filterIncomingPacket(
|
|||
Address cc2;
|
||||
unsigned int ccLength2 = 0;
|
||||
bool ccWatch2 = false;
|
||||
switch(_doZtFilter(RR, crrl, m_config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, c->rules(), c->ruleCount(), cc2, ccLength2, ccWatch2, qosBucket)) {
|
||||
switch (_doZtFilter(RR, crrl, m_config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, c->rules(), c->ruleCount(), cc2, ccLength2, ccWatch2, qosBucket)) {
|
||||
case DOZTFILTER_NO_MATCH:
|
||||
case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern
|
||||
break;
|
||||
|
@ -794,7 +808,8 @@ int Network::filterIncomingPacket(
|
|||
break;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
|
||||
case DOZTFILTER_DROP:
|
||||
//if (_config.remoteTraceTarget)
|
||||
|
@ -826,7 +841,7 @@ int Network::filterIncomingPacket(
|
|||
*/
|
||||
}
|
||||
|
||||
if ((ztDest != ztFinalDest)&&(ztFinalDest)) {
|
||||
if ((ztDest != ztFinalDest) && (ztFinalDest)) {
|
||||
// TODO
|
||||
/*
|
||||
Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME);
|
||||
|
@ -851,7 +866,7 @@ int Network::filterIncomingPacket(
|
|||
return accept;
|
||||
}
|
||||
|
||||
void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg)
|
||||
void Network::multicastSubscribe(void *tPtr, const MulticastGroup &mg)
|
||||
{
|
||||
Mutex::Lock l(m_myMulticastGroups_l);
|
||||
if (!std::binary_search(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg)) {
|
||||
|
@ -864,12 +879,12 @@ void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg)
|
|||
void Network::multicastUnsubscribe(const MulticastGroup &mg)
|
||||
{
|
||||
Mutex::Lock l(m_myMulticastGroups_l);
|
||||
Vector<MulticastGroup>::iterator i(std::lower_bound(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg));
|
||||
if ((i != m_myMulticastGroups.end()) && (*i == mg) )
|
||||
Vector< MulticastGroup >::iterator i(std::lower_bound(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg));
|
||||
if ((i != m_myMulticastGroups.end()) && (*i == mg))
|
||||
m_myMulticastGroups.erase(i);
|
||||
}
|
||||
|
||||
uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr<Peer> &source,const Buf &chunk,int ptr,int size)
|
||||
uint64_t Network::handleConfigChunk(void *tPtr, uint64_t packetId, const SharedPtr< Peer > &source, const Buf &chunk, int ptr, int size)
|
||||
{
|
||||
// If the controller's full fingerprint is known or was explicitly specified on join(),
|
||||
// require that the controller's identity match. Otherwise learn it.
|
||||
|
@ -1013,16 +1028,16 @@ uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr
|
|||
#endif
|
||||
}
|
||||
|
||||
int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk)
|
||||
int Network::setConfiguration(void *tPtr, const NetworkConfig &nconf, bool saveToDisk)
|
||||
{
|
||||
if (m_destroyed)
|
||||
return 0;
|
||||
|
||||
// _lock is NOT locked when this is called
|
||||
try {
|
||||
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != m_id))
|
||||
if ((nconf.issuedTo != RR->identity.address()) || (nconf.networkId != m_id))
|
||||
return 0; // invalid config that is not for us or not for this network
|
||||
if ((!Utils::allZero(nconf.issuedToFingerprintHash,ZT_FINGERPRINT_HASH_SIZE)) && (memcmp(nconf.issuedToFingerprintHash,RR->identity.fingerprint().hash,ZT_FINGERPRINT_HASH_SIZE) != 0))
|
||||
if ((!Utils::allZero(nconf.issuedToFingerprintHash, ZT_FINGERPRINT_HASH_SIZE)) && (memcmp(nconf.issuedToFingerprintHash, RR->identity.fingerprint().hash, ZT_FINGERPRINT_HASH_SIZE) != 0))
|
||||
return 0; // full identity hash is present and does not match
|
||||
|
||||
if (m_config == nconf)
|
||||
|
@ -1030,7 +1045,7 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
|
|||
|
||||
ZT_VirtualNetworkConfig ctmp;
|
||||
bool oldPortInitialized;
|
||||
{ // do things that require lock here, but unlock before calling callbacks
|
||||
{ // do things that require lock here, but unlock before calling callbacks
|
||||
Mutex::Lock l1(m_config_l);
|
||||
|
||||
m_config = nconf;
|
||||
|
@ -1050,20 +1065,21 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
|
|||
Dictionary d;
|
||||
if (nconf.toDictionary(d)) {
|
||||
uint64_t tmp[2];
|
||||
tmp[0] = m_id; tmp[1] = 0;
|
||||
Vector<uint8_t> d2;
|
||||
tmp[0] = m_id;
|
||||
tmp[1] = 0;
|
||||
Vector< uint8_t > d2;
|
||||
d.encode(d2);
|
||||
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,d2.data(),(unsigned int)d2.size());
|
||||
RR->node->stateObjectPut(tPtr, ZT_STATE_OBJECT_NETWORK_CONFIG, tmp, d2.data(), (unsigned int)d2.size());
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
return 2; // OK and configuration has changed
|
||||
} catch ( ... ) {} // ignore invalid configs
|
||||
} catch (...) {} // ignore invalid configs
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer) noexcept
|
||||
bool Network::gate(void *tPtr, const SharedPtr< Peer > &peer) noexcept
|
||||
{
|
||||
Mutex::Lock lc(m_config_l);
|
||||
|
||||
|
@ -1074,21 +1090,13 @@ bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer) noexcept
|
|||
|
||||
try {
|
||||
Mutex::Lock l(m_memberships_l);
|
||||
Member *m = m_memberships.get(peer->address());
|
||||
if (m) {
|
||||
// SECURITY: this method in CertificateOfMembership does a full fingerprint check as well as
|
||||
// checking certificate agreement. See Membership.hpp.
|
||||
return m->certificateOfMembershipAgress(m_config.com, peer->identity());
|
||||
} else {
|
||||
m = &(m_memberships[peer->address()]);
|
||||
return false;
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
return m_memberships[peer->address()].certificateOfMembershipAgress(m_config.com, peer->identity());
|
||||
} catch (...) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Network::doPeriodicTasks(void *tPtr,const int64_t now)
|
||||
void Network::doPeriodicTasks(void *tPtr, const int64_t now)
|
||||
{
|
||||
if (m_destroyed)
|
||||
return;
|
||||
|
@ -1099,8 +1107,8 @@ void Network::doPeriodicTasks(void *tPtr,const int64_t now)
|
|||
{
|
||||
Mutex::Lock l1(m_memberships_l);
|
||||
|
||||
for(Map<Address,Member>::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i)
|
||||
i->second.clean(now, m_config);
|
||||
for (Map< Address, Member >::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i)
|
||||
i->second.clean(m_config);
|
||||
|
||||
{
|
||||
Mutex::Lock l2(m_myMulticastGroups_l);
|
||||
|
@ -1121,19 +1129,19 @@ void Network::doPeriodicTasks(void *tPtr,const int64_t now)
|
|||
}
|
||||
}
|
||||
|
||||
void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
|
||||
void Network::learnBridgeRoute(const MAC &mac, const Address &addr)
|
||||
{
|
||||
Mutex::Lock _l(m_remoteBridgeRoutes_l);
|
||||
m_remoteBridgeRoutes[mac] = addr;
|
||||
|
||||
// Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes
|
||||
while (m_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) {
|
||||
Map< Address,unsigned long > counts;
|
||||
Map< Address, unsigned long > counts;
|
||||
Address maxAddr;
|
||||
unsigned long maxCount = 0;
|
||||
|
||||
// Find the address responsible for the most entries
|
||||
for(Map<MAC,Address>::iterator i(m_remoteBridgeRoutes.begin());i != m_remoteBridgeRoutes.end();++i) {
|
||||
for (Map< MAC, Address >::iterator i(m_remoteBridgeRoutes.begin()); i != m_remoteBridgeRoutes.end(); ++i) {
|
||||
const unsigned long c = ++counts[i->second];
|
||||
if (c > maxCount) {
|
||||
maxCount = c;
|
||||
|
@ -1142,7 +1150,7 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
|
|||
}
|
||||
|
||||
// Kill this address from our table, since it's most likely spamming us
|
||||
for(Map<MAC,Address>::iterator i(m_remoteBridgeRoutes.begin());i != m_remoteBridgeRoutes.end();) {
|
||||
for (Map< MAC, Address >::iterator i(m_remoteBridgeRoutes.begin()); i != m_remoteBridgeRoutes.end();) {
|
||||
if (i->second == maxAddr)
|
||||
m_remoteBridgeRoutes.erase(i++);
|
||||
else ++i;
|
||||
|
@ -1216,7 +1224,7 @@ Member::AddCredentialResult Network::addCredential(void *tPtr, const Identity &s
|
|||
return m_memberships[coo.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, coo);
|
||||
}
|
||||
|
||||
void Network::pushCredentials(void *tPtr,const SharedPtr<Peer> &to,const int64_t now)
|
||||
void Network::pushCredentials(void *tPtr, const SharedPtr< Peer > &to, const int64_t now)
|
||||
{
|
||||
const int64_t tout = std::min(m_config.credentialTimeMaxDelta, m_config.com.timestampMaxDelta());
|
||||
Mutex::Lock _l(m_memberships_l);
|
||||
|
@ -1251,7 +1259,7 @@ void Network::m_requestConfiguration(void *tPtr)
|
|||
const uint16_t startPortRange = (uint16_t)((m_id >> 40U) & 0xffff);
|
||||
const uint16_t endPortRange = (uint16_t)((m_id >> 24U) & 0xffff);
|
||||
if (endPortRange >= startPortRange) {
|
||||
ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
|
||||
ScopedPtr< NetworkConfig > nconf(new NetworkConfig());
|
||||
|
||||
nconf->networkId = m_id;
|
||||
nconf->timestamp = RR->node->now();
|
||||
|
@ -1307,12 +1315,12 @@ void Network::m_requestConfiguration(void *tPtr)
|
|||
nconf->name[3] = 'o';
|
||||
nconf->name[4] = 'c';
|
||||
nconf->name[5] = '-';
|
||||
Utils::hex((uint16_t)startPortRange,nconf->name + 6);
|
||||
Utils::hex((uint16_t)startPortRange, nconf->name + 6);
|
||||
nconf->name[10] = '-';
|
||||
Utils::hex((uint16_t)endPortRange,nconf->name + 11);
|
||||
Utils::hex((uint16_t)endPortRange, nconf->name + 11);
|
||||
nconf->name[15] = (char)0;
|
||||
|
||||
this->setConfiguration(tPtr,*nconf,false);
|
||||
this->setConfiguration(tPtr, *nconf, false);
|
||||
} else {
|
||||
this->setNotFound();
|
||||
}
|
||||
|
@ -1328,9 +1336,9 @@ void Network::m_requestConfiguration(void *tPtr)
|
|||
ipv4[3] = (uint8_t)myAddress;
|
||||
|
||||
char v4ascii[24];
|
||||
Utils::decimal(ipv4[0],v4ascii);
|
||||
Utils::decimal(ipv4[0], v4ascii);
|
||||
|
||||
ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
|
||||
ScopedPtr< NetworkConfig > nconf(new NetworkConfig());
|
||||
|
||||
nconf->networkId = m_id;
|
||||
nconf->timestamp = RR->node->now();
|
||||
|
@ -1348,7 +1356,7 @@ void Network::m_requestConfiguration(void *tPtr)
|
|||
nconf->specialists[0] = networkHub;
|
||||
|
||||
nconf->staticIps[0] = InetAddress::makeIpv66plane(m_id, myAddress);
|
||||
nconf->staticIps[1].set(ipv4,4,8);
|
||||
nconf->staticIps[1].set(ipv4, 4, 8);
|
||||
|
||||
nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
|
||||
|
||||
|
@ -1370,7 +1378,7 @@ void Network::m_requestConfiguration(void *tPtr)
|
|||
nconf->name[nn++] = '0';
|
||||
nconf->name[nn] = (char)0;
|
||||
|
||||
this->setConfiguration(tPtr,*nconf,false);
|
||||
this->setConfiguration(tPtr, *nconf, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1378,17 +1386,17 @@ void Network::m_requestConfiguration(void *tPtr)
|
|||
const Address ctrl(controller());
|
||||
|
||||
Dictionary rmd;
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR,(uint64_t)1); // 1 == ZeroTier, no other vendors at the moment
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,(uint64_t)ZT_PROTO_VERSION);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,(uint64_t)ZEROTIER_VERSION_MAJOR);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,(uint64_t)ZEROTIER_VERSION_MINOR);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,(uint64_t)ZEROTIER_VERSION_REVISION);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES,(uint64_t)ZT_MAX_NETWORK_RULES);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES,(uint64_t)ZT_MAX_NETWORK_CAPABILITIES);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES,(uint64_t)ZT_MAX_CAPABILITY_RULES);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS,(uint64_t)ZT_MAX_NETWORK_TAGS);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_VENDOR, (uint64_t)1); // 1 == ZeroTier, no other vendors at the moment
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION, (uint64_t)ZT_PROTO_VERSION);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION, (uint64_t)ZEROTIER_VERSION_MAJOR);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION, (uint64_t)ZEROTIER_VERSION_MINOR);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION, (uint64_t)ZEROTIER_VERSION_REVISION);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_RULES, (uint64_t)ZT_MAX_NETWORK_RULES);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_CAPABILITIES, (uint64_t)ZT_MAX_NETWORK_CAPABILITIES);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_CAPABILITY_RULES, (uint64_t)ZT_MAX_CAPABILITY_RULES);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_MAX_NETWORK_TAGS, (uint64_t)ZT_MAX_NETWORK_TAGS);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS, (uint64_t)0);
|
||||
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV, (uint64_t)ZT_RULES_ENGINE_REVISION);
|
||||
|
||||
RR->t->networkConfigRequestSent(tPtr, 0x335bb1a2, m_id);
|
||||
|
||||
|
@ -1422,7 +1430,7 @@ void Network::m_requestConfiguration(void *tPtr)
|
|||
|
||||
ZT_VirtualNetworkStatus Network::m_status() const
|
||||
{
|
||||
switch(_netconfFailure) {
|
||||
switch (_netconfFailure) {
|
||||
case NETCONF_FAILURE_ACCESS_DENIED:
|
||||
return ZT_NETWORK_STATUS_ACCESS_DENIED;
|
||||
case NETCONF_FAILURE_NOT_FOUND:
|
||||
|
@ -1445,32 +1453,32 @@ void Network::m_externalConfig(ZT_VirtualNetworkConfig *ec) const
|
|||
ec->status = m_status();
|
||||
ec->type = (m_config) ? (m_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE;
|
||||
ec->mtu = (m_config) ? m_config.mtu : ZT_DEFAULT_MTU;
|
||||
Vector<Address> ab;
|
||||
for(unsigned int i=0;i < m_config.specialistCount;++i) {
|
||||
Vector< Address > ab;
|
||||
for (unsigned int i = 0; i < m_config.specialistCount; ++i) {
|
||||
if ((m_config.specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)
|
||||
ab.push_back(Address(m_config.specialists[i]));
|
||||
}
|
||||
ec->bridge = (std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end()) ? 1 : 0;
|
||||
ec->bridge = (std::find(ab.begin(), ab.end(), RR->identity.address()) != ab.end()) ? 1 : 0;
|
||||
ec->broadcastEnabled = (m_config) ? (m_config.enableBroadcast() ? 1 : 0) : 0;
|
||||
ec->netconfRevision = (m_config) ? (unsigned long)m_config.revision : 0;
|
||||
|
||||
ec->assignedAddressCount = 0;
|
||||
for(unsigned int i=0;i<ZT_MAX_ZT_ASSIGNED_ADDRESSES;++i) {
|
||||
for (unsigned int i = 0; i < ZT_MAX_ZT_ASSIGNED_ADDRESSES; ++i) {
|
||||
if (i < m_config.staticIpCount) {
|
||||
Utils::copy<sizeof(struct sockaddr_storage)>(&(ec->assignedAddresses[i]),&(m_config.staticIps[i]));
|
||||
Utils::copy< sizeof(struct sockaddr_storage) >(&(ec->assignedAddresses[i]), &(m_config.staticIps[i]));
|
||||
++ec->assignedAddressCount;
|
||||
} else {
|
||||
Utils::zero<sizeof(struct sockaddr_storage)>(&(ec->assignedAddresses[i]));
|
||||
Utils::zero< sizeof(struct sockaddr_storage) >(&(ec->assignedAddresses[i]));
|
||||
}
|
||||
}
|
||||
|
||||
ec->routeCount = 0;
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_ROUTES;++i) {
|
||||
for (unsigned int i = 0; i < ZT_MAX_NETWORK_ROUTES; ++i) {
|
||||
if (i < m_config.routeCount) {
|
||||
Utils::copy<sizeof(ZT_VirtualNetworkRoute)>(&(ec->routes[i]),&(m_config.routes[i]));
|
||||
Utils::copy< sizeof(ZT_VirtualNetworkRoute) >(&(ec->routes[i]), &(m_config.routes[i]));
|
||||
++ec->routeCount;
|
||||
} else {
|
||||
Utils::zero<sizeof(ZT_VirtualNetworkRoute)>(&(ec->routes[i]));
|
||||
Utils::zero< sizeof(ZT_VirtualNetworkRoute) >(&(ec->routes[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1478,26 +1486,26 @@ void Network::m_externalConfig(ZT_VirtualNetworkConfig *ec) const
|
|||
void Network::m_announceMulticastGroups(void *tPtr, bool force)
|
||||
{
|
||||
// Assumes _myMulticastGroups_l and _memberships_l are locked
|
||||
const Vector<MulticastGroup> groups(m_allMulticastGroups());
|
||||
const Vector< MulticastGroup > groups(m_allMulticastGroups());
|
||||
m_announceMulticastGroupsTo(tPtr, controller(), groups);
|
||||
|
||||
// TODO
|
||||
/*
|
||||
Address *a = nullptr;
|
||||
Membership *m = nullptr;
|
||||
Hashtable<Address,Membership>::Iterator i(_memberships);
|
||||
while (i.next(a,m)) {
|
||||
bool announce = m->multicastLikeGate(now); // force this to be called even if 'force' is true since it updates last push time
|
||||
if ((!announce)&&(force))
|
||||
announce = true;
|
||||
if ((announce)&&(m->isAllowedOnNetwork(_config)))
|
||||
_announceMulticastGroupsTo(tPtr,*a,groups);
|
||||
}
|
||||
*/
|
||||
// TODO
|
||||
/*
|
||||
Address *a = nullptr;
|
||||
Membership *m = nullptr;
|
||||
Hashtable<Address,Membership>::Iterator i(_memberships);
|
||||
while (i.next(a,m)) {
|
||||
bool announce = m->multicastLikeGate(now); // force this to be called even if 'force' is true since it updates last push time
|
||||
if ((!announce)&&(force))
|
||||
announce = true;
|
||||
if ((announce)&&(m->isAllowedOnNetwork(_config)))
|
||||
_announceMulticastGroupsTo(tPtr,*a,groups);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
void Network::m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector<MulticastGroup> &allMulticastGroups)
|
||||
void Network::m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector< MulticastGroup > &allMulticastGroups)
|
||||
{
|
||||
#if 0
|
||||
// Assumes _myMulticastGroups_l and _memberships_l are locked
|
||||
|
@ -1523,18 +1531,18 @@ void Network::m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const
|
|||
#endif
|
||||
}
|
||||
|
||||
Vector<MulticastGroup> Network::m_allMulticastGroups() const
|
||||
Vector< MulticastGroup > Network::m_allMulticastGroups() const
|
||||
{
|
||||
// Assumes _myMulticastGroups_l is locked
|
||||
Vector<MulticastGroup> mgs;
|
||||
Vector< MulticastGroup > mgs;
|
||||
mgs.reserve(m_myMulticastGroups.size() + m_multicastGroupsBehindMe.size() + 1);
|
||||
mgs.insert(mgs.end(), m_myMulticastGroups.begin(), m_myMulticastGroups.end());
|
||||
for(Map<MulticastGroup,int64_t>::const_iterator i(m_multicastGroupsBehindMe.begin());i != m_multicastGroupsBehindMe.end();++i)
|
||||
for (Map< MulticastGroup, int64_t >::const_iterator i(m_multicastGroupsBehindMe.begin()); i != m_multicastGroupsBehindMe.end(); ++i)
|
||||
mgs.push_back(i->first);
|
||||
if ((m_config) && (m_config.enableBroadcast()))
|
||||
mgs.push_back(Network::BROADCAST);
|
||||
std::sort(mgs.begin(),mgs.end());
|
||||
mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end());
|
||||
std::sort(mgs.begin(), mgs.end());
|
||||
mgs.erase(std::unique(mgs.begin(), mgs.end()), mgs.end());
|
||||
return mgs;
|
||||
}
|
||||
|
||||
|
|
105
core/Network.hpp
105
core/Network.hpp
|
@ -32,6 +32,7 @@
|
|||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
|
||||
class Peer;
|
||||
|
||||
/**
|
||||
|
@ -39,7 +40,7 @@ class Peer;
|
|||
*/
|
||||
class Network
|
||||
{
|
||||
friend class SharedPtr<Network>;
|
||||
friend class SharedPtr< Network >;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -50,7 +51,8 @@ public:
|
|||
/**
|
||||
* Compute primary controller device ID from network ID
|
||||
*/
|
||||
static ZT_INLINE Address controllerFor(uint64_t nwid) noexcept { return Address(nwid >> 24U); }
|
||||
static ZT_INLINE Address controllerFor(uint64_t nwid) noexcept
|
||||
{ return Address(nwid >> 24U); }
|
||||
|
||||
/**
|
||||
* Construct a new network
|
||||
|
@ -65,18 +67,33 @@ public:
|
|||
* @param uptr Arbitrary pointer used by externally-facing API (for user use)
|
||||
* @param nconf Network config, if known
|
||||
*/
|
||||
Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,const Fingerprint &controllerFingerprint,void *uptr,const NetworkConfig *nconf);
|
||||
Network(const RuntimeEnvironment *renv, void *tPtr, uint64_t nwid, const Fingerprint &controllerFingerprint, void *uptr, const NetworkConfig *nconf);
|
||||
|
||||
~Network();
|
||||
|
||||
ZT_INLINE uint64_t id() const noexcept { return m_id; }
|
||||
ZT_INLINE Address controller() const noexcept { return Address(m_id >> 24U); }
|
||||
ZT_INLINE bool multicastEnabled() const noexcept { return (m_config.multicastLimit > 0); }
|
||||
ZT_INLINE bool hasConfig() const noexcept { return (m_config); }
|
||||
ZT_INLINE uint64_t lastConfigUpdate() const noexcept { return m_lastConfigUpdate; }
|
||||
ZT_INLINE ZT_VirtualNetworkStatus status() const noexcept { return m_status(); }
|
||||
ZT_INLINE const NetworkConfig &config() const noexcept { return m_config; }
|
||||
ZT_INLINE const MAC &mac() const noexcept { return m_mac; }
|
||||
ZT_INLINE uint64_t id() const noexcept
|
||||
{ return m_id; }
|
||||
|
||||
ZT_INLINE Address controller() const noexcept
|
||||
{ return Address(m_id >> 24U); }
|
||||
|
||||
ZT_INLINE bool multicastEnabled() const noexcept
|
||||
{ return (m_config.multicastLimit > 0); }
|
||||
|
||||
ZT_INLINE bool hasConfig() const noexcept
|
||||
{ return (m_config); }
|
||||
|
||||
ZT_INLINE uint64_t lastConfigUpdate() const noexcept
|
||||
{ return m_lastConfigUpdate; }
|
||||
|
||||
ZT_INLINE ZT_VirtualNetworkStatus status() const noexcept
|
||||
{ return m_status(); }
|
||||
|
||||
ZT_INLINE const NetworkConfig &config() const noexcept
|
||||
{ return m_config; }
|
||||
|
||||
ZT_INLINE const MAC &mac() const noexcept
|
||||
{ return m_mac; }
|
||||
|
||||
/**
|
||||
* Apply filters to an outgoing packet
|
||||
|
@ -132,7 +149,7 @@ public:
|
|||
*/
|
||||
int filterIncomingPacket(
|
||||
void *tPtr,
|
||||
const SharedPtr<Peer> &sourcePeer,
|
||||
const SharedPtr< Peer > &sourcePeer,
|
||||
const Address &ztDest,
|
||||
const MAC &macSource,
|
||||
const MAC &macDest,
|
||||
|
@ -148,7 +165,7 @@ public:
|
|||
* @param includeBridgedGroups If true, also check groups we've learned via bridging
|
||||
* @return True if this network endpoint / peer is a member
|
||||
*/
|
||||
ZT_INLINE bool subscribedToMulticastGroup(const MulticastGroup &mg,const bool includeBridgedGroups) const
|
||||
ZT_INLINE bool subscribedToMulticastGroup(const MulticastGroup &mg, const bool includeBridgedGroups) const
|
||||
{
|
||||
Mutex::Lock l(m_myMulticastGroups_l);
|
||||
if (std::binary_search(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg))
|
||||
|
@ -164,7 +181,7 @@ public:
|
|||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param mg New multicast group
|
||||
*/
|
||||
void multicastSubscribe(void *tPtr,const MulticastGroup &mg);
|
||||
void multicastSubscribe(void *tPtr, const MulticastGroup &mg);
|
||||
|
||||
/**
|
||||
* Unsubscribe from a multicast group
|
||||
|
@ -189,7 +206,7 @@ public:
|
|||
* @param size Size of data in chunk buffer (total, not relative to ptr)
|
||||
* @return Update ID if update was fully assembled and accepted or 0 otherwise
|
||||
*/
|
||||
uint64_t handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr<Peer> &source,const Buf &chunk,int ptr,int size);
|
||||
uint64_t handleConfigChunk(void *tPtr, uint64_t packetId, const SharedPtr< Peer > &source, const Buf &chunk, int ptr, int size);
|
||||
|
||||
/**
|
||||
* Set network configuration
|
||||
|
@ -203,17 +220,19 @@ public:
|
|||
* @param saveToDisk Save to disk? Used during loading, should usually be true otherwise.
|
||||
* @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new
|
||||
*/
|
||||
int setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk);
|
||||
int setConfiguration(void *tPtr, const NetworkConfig &nconf, bool saveToDisk);
|
||||
|
||||
/**
|
||||
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
|
||||
*/
|
||||
ZT_INLINE void setAccessDenied() noexcept { _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; }
|
||||
ZT_INLINE void setAccessDenied() noexcept
|
||||
{ _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; }
|
||||
|
||||
/**
|
||||
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this
|
||||
*/
|
||||
ZT_INLINE void setNotFound() noexcept { _netconfFailure = NETCONF_FAILURE_NOT_FOUND; }
|
||||
ZT_INLINE void setNotFound() noexcept
|
||||
{ _netconfFailure = NETCONF_FAILURE_NOT_FOUND; }
|
||||
|
||||
/**
|
||||
* Determine whether this peer is permitted to communicate on this network
|
||||
|
@ -221,12 +240,12 @@ public:
|
|||
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
|
||||
* @param peer Peer to check
|
||||
*/
|
||||
bool gate(void *tPtr,const SharedPtr<Peer> &peer) noexcept;
|
||||
bool gate(void *tPtr, const SharedPtr< Peer > &peer) noexcept;
|
||||
|
||||
/**
|
||||
* Do periodic cleanup and housekeeping tasks
|
||||
*/
|
||||
void doPeriodicTasks(void *tPtr,int64_t now);
|
||||
void doPeriodicTasks(void *tPtr, int64_t now);
|
||||
|
||||
/**
|
||||
* Find the node on this network that has this MAC behind it (if any)
|
||||
|
@ -237,8 +256,8 @@ public:
|
|||
ZT_INLINE Address findBridgeTo(const MAC &mac) const
|
||||
{
|
||||
Mutex::Lock _l(m_remoteBridgeRoutes_l);
|
||||
const Address *const br = m_remoteBridgeRoutes.get(mac);
|
||||
return ((br) ? *br : Address());
|
||||
Map< MAC, Address >::const_iterator br(m_remoteBridgeRoutes.find(mac));
|
||||
return ((br == m_remoteBridgeRoutes.end()) ? Address() : br->second);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -247,7 +266,7 @@ public:
|
|||
* @param mac MAC address of destination
|
||||
* @param addr Bridge this MAC is reachable behind
|
||||
*/
|
||||
void learnBridgeRoute(const MAC &mac,const Address &addr);
|
||||
void learnBridgeRoute(const MAC &mac, const Address &addr);
|
||||
|
||||
/**
|
||||
* Learn a multicast group that is bridged to our tap device
|
||||
|
@ -256,10 +275,10 @@ public:
|
|||
* @param mg Multicast group
|
||||
* @param now Current time
|
||||
*/
|
||||
ZT_INLINE void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now)
|
||||
ZT_INLINE void learnBridgedMulticastGroup(void *tPtr, const MulticastGroup &mg, int64_t now)
|
||||
{
|
||||
Mutex::Lock l(m_myMulticastGroups_l);
|
||||
m_multicastGroupsBehindMe.set(mg, now);
|
||||
m_multicastGroupsBehindMe[mg] = now;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,7 +313,7 @@ public:
|
|||
* @param to Destination peer
|
||||
* @param now Current time
|
||||
*/
|
||||
void pushCredentials(void *tPtr,const SharedPtr<Peer> &to,int64_t now);
|
||||
void pushCredentials(void *tPtr, const SharedPtr< Peer > &to, int64_t now);
|
||||
|
||||
/**
|
||||
* Destroy this network
|
||||
|
@ -316,12 +335,12 @@ public:
|
|||
*
|
||||
* @param f Function of (const Address,const Membership)
|
||||
*/
|
||||
template<typename F>
|
||||
template< typename F >
|
||||
ZT_INLINE void eachMember(F f)
|
||||
{
|
||||
Mutex::Lock ml(m_memberships_l);
|
||||
for(Map<Address,Member>::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
|
||||
if (!f(i->first,i->second))
|
||||
for (Map< Address, Member >::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
|
||||
if (!f(i->first, i->second))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -329,15 +348,20 @@ public:
|
|||
/**
|
||||
* @return Externally usable pointer-to-pointer exported via the core API
|
||||
*/
|
||||
ZT_INLINE void **userPtr() noexcept { return &m_uPtr; }
|
||||
ZT_INLINE void **userPtr() noexcept
|
||||
{ return &m_uPtr; }
|
||||
|
||||
private:
|
||||
void m_requestConfiguration(void *tPtr);
|
||||
|
||||
ZT_VirtualNetworkStatus m_status() const;
|
||||
|
||||
void m_externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
|
||||
void m_announceMulticastGroups(void *tPtr, bool force);
|
||||
void m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector<MulticastGroup> &allMulticastGroups);
|
||||
Vector<MulticastGroup> m_allMulticastGroups() const;
|
||||
|
||||
void m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector< MulticastGroup > &allMulticastGroups);
|
||||
|
||||
Vector< MulticastGroup > m_allMulticastGroups() const;
|
||||
|
||||
const RuntimeEnvironment *const RR;
|
||||
void *m_uPtr;
|
||||
|
@ -345,30 +369,31 @@ private:
|
|||
Fingerprint m_controllerFingerprint;
|
||||
MAC m_mac; // local MAC address
|
||||
bool m_portInitialized;
|
||||
std::atomic<bool> m_destroyed;
|
||||
std::atomic< bool > m_destroyed;
|
||||
|
||||
Vector<MulticastGroup> m_myMulticastGroups; // multicast groups that we belong to (according to tap)
|
||||
Map<MulticastGroup,int64_t> m_multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
|
||||
Map<MAC,Address> m_remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
|
||||
Vector< MulticastGroup > m_myMulticastGroups; // multicast groups that we belong to (according to tap)
|
||||
Map< MulticastGroup, int64_t > m_multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
|
||||
Map< MAC, Address > m_remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
|
||||
|
||||
NetworkConfig m_config;
|
||||
std::atomic<int64_t> m_lastConfigUpdate;
|
||||
std::atomic< int64_t > m_lastConfigUpdate;
|
||||
|
||||
volatile enum {
|
||||
volatile enum
|
||||
{
|
||||
NETCONF_FAILURE_NONE,
|
||||
NETCONF_FAILURE_ACCESS_DENIED,
|
||||
NETCONF_FAILURE_NOT_FOUND,
|
||||
NETCONF_FAILURE_INIT_FAILED
|
||||
} _netconfFailure;
|
||||
|
||||
Map<Address,Member> m_memberships;
|
||||
Map< Address, Member > m_memberships;
|
||||
|
||||
Mutex m_myMulticastGroups_l;
|
||||
Mutex m_remoteBridgeRoutes_l;
|
||||
Mutex m_config_l;
|
||||
Mutex m_memberships_l;
|
||||
|
||||
std::atomic<int> __refCount;
|
||||
std::atomic< int > __refCount;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -678,10 +678,11 @@ bool Node::externalPathLookup(void *tPtr, const Identity &id, int family, InetAd
|
|||
bool Node::localControllerHasAuthorized(const int64_t now, const uint64_t nwid, const Address &addr) const
|
||||
{
|
||||
m_localControllerAuthorizations_l.lock();
|
||||
const int64_t *const at = m_localControllerAuthorizations.get(p_LocalControllerAuth(nwid, addr));
|
||||
Map<Node::p_LocalControllerAuth, int64_t>::const_iterator i(m_localControllerAuthorizations.find(p_LocalControllerAuth(nwid, addr)));
|
||||
const int64_t at = (i == m_localControllerAuthorizations.end()) ? -1LL : i->second;
|
||||
m_localControllerAuthorizations_l.unlock();
|
||||
if (at)
|
||||
return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3));
|
||||
if (at > 0)
|
||||
return ((now - at) < (ZT_NETWORK_AUTOCONF_DELAY * 3));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
int64_t now,
|
||||
int64_t localSocket,
|
||||
const struct sockaddr_storage *remoteAddress,
|
||||
SharedPtr<Buf> &packetData,
|
||||
SharedPtr< Buf > &packetData,
|
||||
unsigned int packetLength,
|
||||
volatile int64_t *nextBackgroundTaskDeadline);
|
||||
|
||||
|
@ -67,7 +67,7 @@ public:
|
|||
uint64_t destMac,
|
||||
unsigned int etherType,
|
||||
unsigned int vlanId,
|
||||
SharedPtr<Buf> &frameData,
|
||||
SharedPtr< Buf > &frameData,
|
||||
unsigned int frameLength,
|
||||
volatile int64_t *nextBackgroundTaskDeadline);
|
||||
|
||||
|
@ -222,19 +222,19 @@ public:
|
|||
* @param nwid Network ID
|
||||
* @return Network associated with ID
|
||||
*/
|
||||
ZT_INLINE SharedPtr<Network> network(const uint64_t nwid) const noexcept
|
||||
ZT_INLINE SharedPtr< Network > network(const uint64_t nwid) const noexcept
|
||||
{
|
||||
RWMutex::RLock l(m_networks_l);
|
||||
const SharedPtr<Network> *const n = m_networks.get(nwid);
|
||||
if (n)
|
||||
return *n;
|
||||
return SharedPtr<Network>();
|
||||
Map< uint64_t, SharedPtr< Network > >::const_iterator n(m_networks.find(nwid));
|
||||
if (likely(n != m_networks.end()))
|
||||
return n->second;
|
||||
return SharedPtr< Network >();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Known local interface addresses for this node
|
||||
*/
|
||||
ZT_INLINE Vector<ZT_InterfaceAddress> localInterfaceAddresses() const
|
||||
ZT_INLINE Vector< ZT_InterfaceAddress > localInterfaceAddresses() const
|
||||
{
|
||||
Mutex::Lock _l(m_localInterfaceAddresses_m);
|
||||
return m_localInterfaceAddresses;
|
||||
|
@ -280,7 +280,7 @@ public:
|
|||
* @param id Object ID or NULL if this type does not use one
|
||||
* @return Vector containing data or empty vector if not found or empty
|
||||
*/
|
||||
Vector<uint8_t> stateObjectGet(void *tPtr, ZT_StateObjectType type, const uint64_t *id);
|
||||
Vector< uint8_t > stateObjectGet(void *tPtr, ZT_StateObjectType type, const uint64_t *id);
|
||||
|
||||
/**
|
||||
* Store a state object
|
||||
|
@ -398,16 +398,16 @@ private:
|
|||
{ return ((a.nwid < nwid) || ((a.nwid == nwid) && (a.address < address))); }
|
||||
};
|
||||
|
||||
Map<p_LocalControllerAuth, int64_t> m_localControllerAuthorizations;
|
||||
Map< p_LocalControllerAuth, int64_t > m_localControllerAuthorizations;
|
||||
Mutex m_localControllerAuthorizations_l;
|
||||
|
||||
// Locally joined networks by network ID.
|
||||
Map<uint64_t, SharedPtr<Network> > m_networks;
|
||||
Map< uint64_t, SharedPtr< Network > > m_networks;
|
||||
RWMutex m_networks_l;
|
||||
|
||||
// These are local interface addresses that have been configured via the API
|
||||
// and can be pushed to other nodes.
|
||||
Vector<ZT_InterfaceAddress> m_localInterfaceAddresses;
|
||||
Vector< ZT_InterfaceAddress > m_localInterfaceAddresses;
|
||||
Mutex m_localInterfaceAddresses_m;
|
||||
|
||||
// This is locked while running processBackgroundTasks().
|
||||
|
@ -419,10 +419,10 @@ private:
|
|||
int64_t m_lastNetworkHousekeepingRun;
|
||||
|
||||
// This is the most recent value for time passed in via any of the core API methods.
|
||||
std::atomic<int64_t> m_now;
|
||||
std::atomic< int64_t > m_now;
|
||||
|
||||
// True if at least one root appears reachable.
|
||||
std::atomic<bool> m_online;
|
||||
std::atomic< bool > m_online;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -416,6 +416,20 @@ void Topology::m_loadCached(void *tPtr, const Address &zta, SharedPtr< Peer > &p
|
|||
}
|
||||
}
|
||||
|
||||
SharedPtr< Peer > Topology::m_peerFromCached(void *tPtr, const Address &zta)
|
||||
{
|
||||
SharedPtr< Peer > p;
|
||||
m_loadCached(tPtr, zta, p);
|
||||
if (p) {
|
||||
RWMutex::Lock l(m_peers_l);
|
||||
SharedPtr< Peer > &hp = m_peers[zta];
|
||||
if (hp)
|
||||
return hp;
|
||||
hp = p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void Topology::m_updateRootPeers_l_roots_certs(void *tPtr)
|
||||
{
|
||||
// assumes m_roots_l and m_certs_l are locked for write
|
||||
|
|
|
@ -65,24 +65,13 @@ public:
|
|||
{
|
||||
{
|
||||
RWMutex::RLock l(m_peers_l);
|
||||
const SharedPtr< Peer > *const ap = m_peers.get(zta);
|
||||
if (likely(ap != nullptr))
|
||||
return *ap;
|
||||
}
|
||||
{
|
||||
SharedPtr< Peer > p;
|
||||
if (loadFromCached) {
|
||||
m_loadCached(tPtr, zta, p);
|
||||
if (p) {
|
||||
RWMutex::Lock l(m_peers_l);
|
||||
SharedPtr< Peer > &hp = m_peers[zta];
|
||||
if (hp)
|
||||
return hp;
|
||||
hp = p;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
Map< Address, SharedPtr< Peer > >::const_iterator ap(m_peers.find(zta));
|
||||
if (likely(ap != m_peers.end()))
|
||||
return ap->second;
|
||||
}
|
||||
if (loadFromCached)
|
||||
return m_peerFromCached(tPtr, zta);
|
||||
return SharedPtr< Peer >();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -97,9 +86,9 @@ public:
|
|||
const UniqueID k(r.key());
|
||||
{
|
||||
RWMutex::RLock lck(m_paths_l);
|
||||
SharedPtr< Path > *const p = m_paths.get(k);
|
||||
if (likely(p != nullptr))
|
||||
return *p;
|
||||
Map< UniqueID, SharedPtr< Path > >::const_iterator p(m_paths.find(k));
|
||||
if (likely(p != m_paths.end()))
|
||||
return p->second;
|
||||
}
|
||||
{
|
||||
SharedPtr< Path > p(new Path(l, r));
|
||||
|
@ -231,11 +220,19 @@ public:
|
|||
|
||||
private:
|
||||
void m_eraseCertificate_l_certs(const SharedPtr< const Certificate > &cert);
|
||||
|
||||
bool m_cleanCertificates_l_certs(int64_t now);
|
||||
|
||||
bool m_verifyCertificateChain_l_certs(const Certificate *current, const int64_t now) const;
|
||||
|
||||
ZT_CertificateError m_verifyCertificate_l_certs(const Certificate &cert, const int64_t now, unsigned int localTrust, bool skipSignatureCheck) const;
|
||||
|
||||
void m_loadCached(void *tPtr, const Address &zta, SharedPtr< Peer > &peer);
|
||||
|
||||
SharedPtr< Peer > m_peerFromCached(void *tPtr, const Address &zta);
|
||||
|
||||
void m_updateRootPeers_l_roots_certs(void *tPtr);
|
||||
|
||||
void m_writeTrustStore_l_roots_certs(void *tPtr) const;
|
||||
|
||||
const RuntimeEnvironment *const RR;
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
|
||||
namespace ZeroTier {
|
||||
|
||||
static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x01 };
|
||||
static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x02 };
|
||||
static const uint8_t ARP_REQUEST_HEADER[8] = {0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01};
|
||||
static const uint8_t ARP_RESPONSE_HEADER[8] = {0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02};
|
||||
|
||||
Arp::Arp() :
|
||||
_cache(),
|
||||
|
@ -28,7 +28,7 @@ Arp::Arp() :
|
|||
{
|
||||
}
|
||||
|
||||
void Arp::addLocal(uint32_t ip,const MAC &mac)
|
||||
void Arp::addLocal(uint32_t ip, const MAC &mac)
|
||||
{
|
||||
_ArpEntry &e = _cache[ip];
|
||||
e.lastQuerySent = 0; // local IP
|
||||
|
@ -42,7 +42,7 @@ void Arp::remove(uint32_t ip)
|
|||
_cache.erase(ip);
|
||||
}
|
||||
|
||||
uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest)
|
||||
uint32_t Arp::processIncomingArp(const void *arp, unsigned int len, void *response, unsigned int &responseLen, MAC &responseDest)
|
||||
{
|
||||
const uint64_t now = OSUtils::now();
|
||||
uint32_t ip = 0;
|
||||
|
@ -51,25 +51,25 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
|
|||
responseDest.zero();
|
||||
|
||||
if (len >= 28) {
|
||||
if (!memcmp(arp,ARP_REQUEST_HEADER,8)) {
|
||||
if (!memcmp(arp, ARP_REQUEST_HEADER, 8)) {
|
||||
// Respond to ARP requests for locally-known IPs
|
||||
_ArpEntry *targetEntry = _cache.get(reinterpret_cast<const uint32_t *>(arp)[6]);
|
||||
if ((targetEntry)&&(targetEntry->local)) {
|
||||
memcpy(response,ARP_RESPONSE_HEADER,8);
|
||||
targetEntry->mac.copyTo(reinterpret_cast<uint8_t *>(response) + 8);
|
||||
memcpy(reinterpret_cast<uint8_t *>(response) + 14,reinterpret_cast<const uint8_t *>(arp) + 24,4);
|
||||
memcpy(reinterpret_cast<uint8_t *>(response) + 18,reinterpret_cast<const uint8_t *>(arp) + 8,10);
|
||||
Map< uint32_t, Arp::_ArpEntry >::const_iterator targetEntry(_cache.find(reinterpret_cast<const uint32_t *>(arp)[6]));
|
||||
if ((targetEntry != _cache.end()) && (targetEntry->second.local)) {
|
||||
memcpy(response, ARP_RESPONSE_HEADER, 8);
|
||||
targetEntry->second.mac.copyTo(reinterpret_cast<uint8_t *>(response) + 8);
|
||||
memcpy(reinterpret_cast<uint8_t *>(response) + 14, reinterpret_cast<const uint8_t *>(arp) + 24, 4);
|
||||
memcpy(reinterpret_cast<uint8_t *>(response) + 18, reinterpret_cast<const uint8_t *>(arp) + 8, 10);
|
||||
responseLen = 28;
|
||||
responseDest.setTo(reinterpret_cast<const uint8_t *>(arp) + 8);
|
||||
}
|
||||
} else if (!memcmp(arp,ARP_RESPONSE_HEADER,8)) {
|
||||
} else if (!memcmp(arp, ARP_RESPONSE_HEADER, 8)) {
|
||||
// Learn cache entries for remote IPs from relevant ARP replies
|
||||
uint32_t responseIp = 0;
|
||||
memcpy(&responseIp,reinterpret_cast<const uint8_t *>(arp) + 14,4);
|
||||
_ArpEntry *queryEntry = _cache.get(responseIp);
|
||||
if ((queryEntry)&&(!queryEntry->local)&&((now - queryEntry->lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) {
|
||||
queryEntry->lastResponseReceived = now;
|
||||
queryEntry->mac.setTo(reinterpret_cast<const uint8_t *>(arp) + 8);
|
||||
memcpy(&responseIp, reinterpret_cast<const uint8_t *>(arp) + 14, 4);
|
||||
Map< uint32_t, Arp::_ArpEntry >::iterator queryEntry(_cache.find(responseIp));
|
||||
if ((queryEntry != _cache.end()) && (!queryEntry->second.local) && ((now - queryEntry->second.lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) {
|
||||
queryEntry->second.lastResponseReceived = now;
|
||||
queryEntry->second.mac.setTo(reinterpret_cast<const uint8_t *>(arp) + 8);
|
||||
ip = responseIp;
|
||||
}
|
||||
}
|
||||
|
@ -77,8 +77,8 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
|
|||
|
||||
if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) {
|
||||
_lastCleaned = now;
|
||||
for(Map< uint32_t,_ArpEntry >::iterator i(_cache.begin());i!=_cache.end();) {
|
||||
if ((!i->second.local)&&((now - i->second.lastResponseReceived) >= ZT_ARP_EXPIRE))
|
||||
for (Map< uint32_t, _ArpEntry >::iterator i(_cache.begin()); i != _cache.end();) {
|
||||
if ((!i->second.local) && ((now - i->second.lastResponseReceived) >= ZT_ARP_EXPIRE))
|
||||
_cache.erase(i++);
|
||||
else ++i;
|
||||
}
|
||||
|
@ -87,22 +87,26 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
|
|||
return ip;
|
||||
}
|
||||
|
||||
MAC Arp::query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest)
|
||||
MAC Arp::query(const MAC &localMac, uint32_t localIp, uint32_t targetIp, void *query, unsigned int &queryLen, MAC &queryDest)
|
||||
{
|
||||
const uint64_t now = OSUtils::now();
|
||||
|
||||
_ArpEntry &e = _cache[targetIp];
|
||||
|
||||
if ( ((e.mac)&&((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) ||
|
||||
((!e.mac)&&((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL)) ) {
|
||||
if (((e.mac) && ((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) ||
|
||||
((!e.mac) && ((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL))) {
|
||||
e.lastQuerySent = now;
|
||||
|
||||
uint8_t *q = reinterpret_cast<uint8_t *>(query);
|
||||
memcpy(q,ARP_REQUEST_HEADER,8); q += 8; // ARP request header information, always the same
|
||||
localMac.copyTo(q); q += 6; // sending host MAC address
|
||||
memcpy(q,&localIp,4); q += 4; // sending host IP (IP already in big-endian byte order)
|
||||
memset(q,0,6); q += 6; // sending zeros for target MAC address as thats what we want to find
|
||||
memcpy(q,&targetIp,4); // target IP address for resolution (IP already in big-endian byte order)
|
||||
memcpy(q, ARP_REQUEST_HEADER, 8);
|
||||
q += 8; // ARP request header information, always the same
|
||||
localMac.copyTo(q);
|
||||
q += 6; // sending host MAC address
|
||||
memcpy(q, &localIp, 4);
|
||||
q += 4; // sending host IP (IP already in big-endian byte order)
|
||||
memset(q, 0, 6);
|
||||
q += 6; // sending zeros for target MAC address as thats what we want to find
|
||||
memcpy(q, &targetIp, 4); // target IP address for resolution (IP already in big-endian byte order)
|
||||
queryLen = 28;
|
||||
if (e.mac)
|
||||
queryDest = e.mac; // confirmation query, send directly to address holder
|
||||
|
|
|
@ -47,70 +47,71 @@ typedef std::vector<route_entry> RouteList;
|
|||
class LinuxNetLink
|
||||
{
|
||||
private:
|
||||
LinuxNetLink();
|
||||
~LinuxNetLink();
|
||||
LinuxNetLink();
|
||||
~LinuxNetLink();
|
||||
|
||||
public:
|
||||
static LinuxNetLink& getInstance()
|
||||
{
|
||||
static LinuxNetLink instance;
|
||||
return instance;
|
||||
}
|
||||
static LinuxNetLink& getInstance()
|
||||
{
|
||||
static LinuxNetLink instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
LinuxNetLink(LinuxNetLink const&) = delete;
|
||||
void operator=(LinuxNetLink const&) = delete;
|
||||
LinuxNetLink(LinuxNetLink const&) = delete;
|
||||
void operator=(LinuxNetLink const&) = delete;
|
||||
|
||||
void addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName);
|
||||
void delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName);
|
||||
RouteList getIPV4Routes() const;
|
||||
RouteList getIPV6Routes() const;
|
||||
void addRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName);
|
||||
void delRoute(const InetAddress &target, const InetAddress &via, const InetAddress &src, const char *ifaceName);
|
||||
RouteList getIPV4Routes() const;
|
||||
RouteList getIPV6Routes() const;
|
||||
|
||||
void addAddress(const InetAddress &addr, const char *iface);
|
||||
void removeAddress(const InetAddress &addr, const char *iface);
|
||||
void addAddress(const InetAddress &addr, const char *iface);
|
||||
void removeAddress(const InetAddress &addr, const char *iface);
|
||||
|
||||
void threadMain() throw();
|
||||
|
||||
void threadMain() throw();
|
||||
private:
|
||||
int _doRecv(int fd);
|
||||
int _doRecv(int fd);
|
||||
|
||||
void _processMessage(struct nlmsghdr *nlp, int nll);
|
||||
void _routeAdded(struct nlmsghdr *nlp);
|
||||
void _routeDeleted(struct nlmsghdr *nlp);
|
||||
void _linkAdded(struct nlmsghdr *nlp);
|
||||
void _linkDeleted(struct nlmsghdr *nlp);
|
||||
void _ipAddressAdded(struct nlmsghdr *nlp);
|
||||
void _ipAddressDeleted(struct nlmsghdr *nlp);
|
||||
void _processMessage(struct nlmsghdr *nlp, int nll);
|
||||
void _routeAdded(struct nlmsghdr *nlp);
|
||||
void _routeDeleted(struct nlmsghdr *nlp);
|
||||
void _linkAdded(struct nlmsghdr *nlp);
|
||||
void _linkDeleted(struct nlmsghdr *nlp);
|
||||
void _ipAddressAdded(struct nlmsghdr *nlp);
|
||||
void _ipAddressDeleted(struct nlmsghdr *nlp);
|
||||
|
||||
void _requestInterfaceList();
|
||||
void _requestIPv4Routes();
|
||||
void _requestIPv6Routes();
|
||||
void _requestInterfaceList();
|
||||
void _requestIPv4Routes();
|
||||
void _requestIPv6Routes();
|
||||
|
||||
int _indexForInterface(const char *iface);
|
||||
int _indexForInterface(const char *iface);
|
||||
|
||||
void _setSocketTimeout(int fd, int seconds = 1);
|
||||
void _setSocketTimeout(int fd, int seconds = 1);
|
||||
|
||||
Thread _t;
|
||||
bool _running;
|
||||
Thread _t;
|
||||
bool _running;
|
||||
|
||||
RouteList _routes_ipv4;
|
||||
Mutex _rv4_m;
|
||||
RouteList _routes_ipv6;
|
||||
Mutex _rv6_m;
|
||||
RouteList _routes_ipv4;
|
||||
Mutex _rv4_m;
|
||||
RouteList _routes_ipv6;
|
||||
Mutex _rv6_m;
|
||||
|
||||
uint32_t _seq;
|
||||
uint32_t _seq;
|
||||
|
||||
struct iface_entry {
|
||||
int index;
|
||||
char ifacename[IFNAMSIZ];
|
||||
char mac[18];
|
||||
char mac_bin[6];
|
||||
unsigned int mtu;
|
||||
};
|
||||
std::map<int, iface_entry> _interfaces;
|
||||
Mutex _if_m;
|
||||
struct iface_entry {
|
||||
int index;
|
||||
char ifacename[IFNAMSIZ];
|
||||
char mac[18];
|
||||
char mac_bin[6];
|
||||
unsigned int mtu;
|
||||
};
|
||||
std::map<int, iface_entry> _interfaces;
|
||||
Mutex _if_m;
|
||||
|
||||
// socket communication vars;
|
||||
int _fd;
|
||||
struct sockaddr_nl _la;
|
||||
// socket communication vars;
|
||||
int _fd;
|
||||
struct sockaddr_nl _la;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -20,239 +20,236 @@
|
|||
|
||||
namespace ZeroTier {
|
||||
|
||||
uint16_t calc_checksum (uint16_t *addr, int len)
|
||||
uint16_t calc_checksum(uint16_t *addr, int len)
|
||||
{
|
||||
int count = len;
|
||||
uint32_t sum = 0;
|
||||
uint16_t answer = 0;
|
||||
int count = len;
|
||||
uint32_t sum = 0;
|
||||
uint16_t answer = 0;
|
||||
|
||||
// Sum up 2-byte values until none or only one byte left.
|
||||
while (count > 1) {
|
||||
sum += *(addr++);
|
||||
count -= 2;
|
||||
}
|
||||
// Sum up 2-byte values until none or only one byte left.
|
||||
while (count > 1) {
|
||||
sum += *(addr++);
|
||||
count -= 2;
|
||||
}
|
||||
|
||||
// Add left-over byte, if any.
|
||||
if (count > 0) {
|
||||
sum += *(uint8_t *) addr;
|
||||
}
|
||||
// Add left-over byte, if any.
|
||||
if (count > 0) {
|
||||
sum += *(uint8_t *)addr;
|
||||
}
|
||||
|
||||
// Fold 32-bit sum into 16 bits; we lose information by doing this,
|
||||
// increasing the chances of a collision.
|
||||
// sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
|
||||
while (sum >> 16) {
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
// Fold 32-bit sum into 16 bits; we lose information by doing this,
|
||||
// increasing the chances of a collision.
|
||||
// sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
|
||||
while (sum >> 16) {
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
}
|
||||
|
||||
// Checksum is one's compliment of sum.
|
||||
answer = ~sum;
|
||||
// Checksum is one's compliment of sum.
|
||||
answer = ~sum;
|
||||
|
||||
return (answer);
|
||||
return (answer);
|
||||
}
|
||||
|
||||
struct _pseudo_header {
|
||||
uint8_t sourceAddr[16];
|
||||
uint8_t targetAddr[16];
|
||||
uint32_t length;
|
||||
uint8_t zeros[3];
|
||||
uint8_t next; // 58
|
||||
struct _pseudo_header
|
||||
{
|
||||
uint8_t sourceAddr[16];
|
||||
uint8_t targetAddr[16];
|
||||
uint32_t length;
|
||||
uint8_t zeros[3];
|
||||
uint8_t next; // 58
|
||||
};
|
||||
|
||||
struct _option {
|
||||
_option(int optionType)
|
||||
: type(optionType)
|
||||
, length(8)
|
||||
{
|
||||
memset(mac, 0, sizeof(mac));
|
||||
}
|
||||
struct _option
|
||||
{
|
||||
_option(int optionType)
|
||||
: type(optionType), length(8)
|
||||
{
|
||||
memset(mac, 0, sizeof(mac));
|
||||
}
|
||||
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint8_t mac[6];
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint8_t mac[6];
|
||||
};
|
||||
|
||||
struct _neighbor_solicitation {
|
||||
_neighbor_solicitation()
|
||||
: type(135)
|
||||
, code(0)
|
||||
, checksum(0)
|
||||
, option(1)
|
||||
{
|
||||
memset(&reserved, 0, sizeof(reserved));
|
||||
memset(target, 0, sizeof(target));
|
||||
}
|
||||
struct _neighbor_solicitation
|
||||
{
|
||||
_neighbor_solicitation()
|
||||
: type(135), code(0), checksum(0), option(1)
|
||||
{
|
||||
memset(&reserved, 0, sizeof(reserved));
|
||||
memset(target, 0, sizeof(target));
|
||||
}
|
||||
|
||||
void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) {
|
||||
_pseudo_header ph;
|
||||
memset(&ph, 0, sizeof(_pseudo_header));
|
||||
const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp;
|
||||
const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp;
|
||||
void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp)
|
||||
{
|
||||
_pseudo_header ph;
|
||||
memset(&ph, 0, sizeof(_pseudo_header));
|
||||
const sockaddr_in6 *src = (const sockaddr_in6 *)&sourceIp;
|
||||
const sockaddr_in6 *dest = (const sockaddr_in6 *)&destIp;
|
||||
|
||||
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
|
||||
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
|
||||
ph.next = 58;
|
||||
ph.length = htonl(sizeof(_neighbor_solicitation));
|
||||
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
|
||||
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
|
||||
ph.next = 58;
|
||||
ph.length = htonl(sizeof(_neighbor_solicitation));
|
||||
|
||||
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation);
|
||||
uint8_t *tmp = (uint8_t*)malloc(len);
|
||||
memcpy(tmp, &ph, sizeof(_pseudo_header));
|
||||
memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation));
|
||||
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation);
|
||||
uint8_t *tmp = (uint8_t *)malloc(len);
|
||||
memcpy(tmp, &ph, sizeof(_pseudo_header));
|
||||
memcpy(tmp + sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation));
|
||||
|
||||
checksum = calc_checksum((uint16_t*)tmp, (int)len);
|
||||
checksum = calc_checksum((uint16_t *)tmp, (int)len);
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
uint8_t type; // 135
|
||||
uint8_t code; // 0
|
||||
uint16_t checksum;
|
||||
uint32_t reserved;
|
||||
uint8_t target[16];
|
||||
_option option;
|
||||
uint8_t type; // 135
|
||||
uint8_t code; // 0
|
||||
uint16_t checksum;
|
||||
uint32_t reserved;
|
||||
uint8_t target[16];
|
||||
_option option;
|
||||
};
|
||||
|
||||
struct _neighbor_advertisement {
|
||||
_neighbor_advertisement()
|
||||
: type(136)
|
||||
, code(0)
|
||||
, checksum(0)
|
||||
, rso(0x40)
|
||||
, option(2)
|
||||
{
|
||||
memset(padding, 0, sizeof(padding));
|
||||
memset(target, 0, sizeof(target));
|
||||
}
|
||||
struct _neighbor_advertisement
|
||||
{
|
||||
_neighbor_advertisement()
|
||||
: type(136), code(0), checksum(0), rso(0x40), option(2)
|
||||
{
|
||||
memset(padding, 0, sizeof(padding));
|
||||
memset(target, 0, sizeof(target));
|
||||
}
|
||||
|
||||
void calculateChecksum(const sockaddr_storage &sourceIp, const InetAddress &destIp) {
|
||||
_pseudo_header ph;
|
||||
memset(&ph, 0, sizeof(_pseudo_header));
|
||||
const sockaddr_in6 *src = (const sockaddr_in6*)&sourceIp;
|
||||
const sockaddr_in6 *dest = (const sockaddr_in6*)&destIp;
|
||||
void calculateChecksum(const sockaddr_storage &sourceIp, const InetAddress &destIp)
|
||||
{
|
||||
_pseudo_header ph;
|
||||
memset(&ph, 0, sizeof(_pseudo_header));
|
||||
const sockaddr_in6 *src = (const sockaddr_in6 *)&sourceIp;
|
||||
const sockaddr_in6 *dest = (const sockaddr_in6 *)&destIp;
|
||||
|
||||
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
|
||||
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
|
||||
ph.next = 58;
|
||||
ph.length = htonl(sizeof(_neighbor_advertisement));
|
||||
memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr));
|
||||
memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr));
|
||||
ph.next = 58;
|
||||
ph.length = htonl(sizeof(_neighbor_advertisement));
|
||||
|
||||
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement);
|
||||
uint8_t *tmp = (uint8_t*)malloc(len);
|
||||
memcpy(tmp, &ph, sizeof(_pseudo_header));
|
||||
memcpy(tmp+sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement));
|
||||
size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement);
|
||||
uint8_t *tmp = (uint8_t *)malloc(len);
|
||||
memcpy(tmp, &ph, sizeof(_pseudo_header));
|
||||
memcpy(tmp + sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement));
|
||||
|
||||
checksum = calc_checksum((uint16_t*)tmp, (int)len);
|
||||
checksum = calc_checksum((uint16_t *)tmp, (int)len);
|
||||
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
free(tmp);
|
||||
tmp = NULL;
|
||||
}
|
||||
|
||||
uint8_t type; // 136
|
||||
uint8_t code; // 0
|
||||
uint16_t checksum;
|
||||
uint8_t rso;
|
||||
uint8_t padding[3];
|
||||
uint8_t target[16];
|
||||
_option option;
|
||||
uint8_t type; // 136
|
||||
uint8_t code; // 0
|
||||
uint16_t checksum;
|
||||
uint8_t rso;
|
||||
uint8_t padding[3];
|
||||
uint8_t target[16];
|
||||
_option option;
|
||||
};
|
||||
|
||||
NeighborDiscovery::NeighborDiscovery()
|
||||
: _cache()
|
||||
, _lastCleaned(OSUtils::now())
|
||||
: _cache(), _lastCleaned(OSUtils::now())
|
||||
{}
|
||||
|
||||
void NeighborDiscovery::addLocal(const sockaddr_storage &address, const MAC &mac)
|
||||
{
|
||||
_NDEntry &e = _cache[InetAddress(address)];
|
||||
e.lastQuerySent = 0;
|
||||
e.lastResponseReceived = 0;
|
||||
e.mac = mac;
|
||||
e.local = true;
|
||||
_NDEntry &e = _cache[InetAddress(address)];
|
||||
e.lastQuerySent = 0;
|
||||
e.lastResponseReceived = 0;
|
||||
e.mac = mac;
|
||||
e.local = true;
|
||||
}
|
||||
|
||||
void NeighborDiscovery::remove(const sockaddr_storage &address)
|
||||
{
|
||||
_cache.erase(InetAddress(address));
|
||||
_cache.erase(InetAddress(address));
|
||||
}
|
||||
|
||||
sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest)
|
||||
{
|
||||
// assert(sizeof(_neighbor_solicitation) == 28);
|
||||
// assert(sizeof(_neighbor_advertisement) == 32);
|
||||
// assert(sizeof(_neighbor_solicitation) == 28);
|
||||
// assert(sizeof(_neighbor_advertisement) == 32);
|
||||
|
||||
const uint64_t now = OSUtils::now();
|
||||
InetAddress ip;
|
||||
const uint64_t now = OSUtils::now();
|
||||
InetAddress ip;
|
||||
|
||||
if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) {
|
||||
// respond to Neighbor Solicitation request for local address
|
||||
_neighbor_solicitation solicitation;
|
||||
memcpy(&solicitation, nd, len);
|
||||
InetAddress targetAddress(solicitation.target, 16, 0);
|
||||
_NDEntry *targetEntry = _cache.get(targetAddress);
|
||||
if (targetEntry && targetEntry->local) {
|
||||
_neighbor_advertisement adv;
|
||||
targetEntry->mac.copyTo(adv.option.mac);
|
||||
memcpy(adv.target, solicitation.target, 16);
|
||||
adv.calculateChecksum(localIp, targetAddress);
|
||||
memcpy(response, &adv, sizeof(_neighbor_advertisement));
|
||||
responseLen = sizeof(_neighbor_advertisement);
|
||||
responseDest.setTo(solicitation.option.mac);
|
||||
}
|
||||
} else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) {
|
||||
_neighbor_advertisement adv;
|
||||
memcpy(&adv, nd, len);
|
||||
InetAddress responseAddress(adv.target, 16, 0);
|
||||
_NDEntry *queryEntry = _cache.get(responseAddress);
|
||||
if(queryEntry && !queryEntry->local && (now - queryEntry->lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) {
|
||||
queryEntry->lastResponseReceived = now;
|
||||
queryEntry->mac.setTo(adv.option.mac);
|
||||
ip = responseAddress;
|
||||
}
|
||||
}
|
||||
if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) {
|
||||
// respond to Neighbor Solicitation request for local address
|
||||
_neighbor_solicitation solicitation;
|
||||
memcpy(&solicitation, nd, len);
|
||||
InetAddress targetAddress(solicitation.target, 16, 0);
|
||||
Map<InetAddress, NeighborDiscovery::_NDEntry>::const_iterator targetEntry(_cache.find(targetAddress));
|
||||
if ((targetEntry != _cache.end()) && targetEntry->second.local) {
|
||||
_neighbor_advertisement adv;
|
||||
targetEntry->second.mac.copyTo(adv.option.mac);
|
||||
memcpy(adv.target, solicitation.target, 16);
|
||||
adv.calculateChecksum(localIp, targetAddress);
|
||||
memcpy(response, &adv, sizeof(_neighbor_advertisement));
|
||||
responseLen = sizeof(_neighbor_advertisement);
|
||||
responseDest.setTo(solicitation.option.mac);
|
||||
}
|
||||
} else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) {
|
||||
_neighbor_advertisement adv;
|
||||
memcpy(&adv, nd, len);
|
||||
InetAddress responseAddress(adv.target, 16, 0);
|
||||
Map<InetAddress, NeighborDiscovery::_NDEntry>::iterator queryEntry(_cache.find(responseAddress));
|
||||
if ((queryEntry != _cache.end()) && !queryEntry->second.local && (now - queryEntry->second.lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) {
|
||||
queryEntry->second.lastResponseReceived = now;
|
||||
queryEntry->second.mac.setTo(adv.option.mac);
|
||||
ip = responseAddress;
|
||||
}
|
||||
}
|
||||
|
||||
if ((now - _lastCleaned) >= ZT_ND_EXPIRE) {
|
||||
_lastCleaned = now;
|
||||
for(Map<InetAddress,_NDEntry>::iterator i(_cache.begin());i!=_cache.end();) {
|
||||
if(!i->second.local && (now - i->second.lastResponseReceived) >= ZT_ND_EXPIRE) {
|
||||
_cache.erase(i++);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((now - _lastCleaned) >= ZT_ND_EXPIRE) {
|
||||
_lastCleaned = now;
|
||||
for (Map< InetAddress, _NDEntry >::iterator i(_cache.begin()); i != _cache.end();) {
|
||||
if (!i->second.local && (now - i->second.lastResponseReceived) >= ZT_ND_EXPIRE) {
|
||||
_cache.erase(i++);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *reinterpret_cast<sockaddr_storage *>(&ip);
|
||||
return *reinterpret_cast<sockaddr_storage *>(&ip);
|
||||
}
|
||||
|
||||
MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest)
|
||||
{
|
||||
const uint64_t now = OSUtils::now();
|
||||
const uint64_t now = OSUtils::now();
|
||||
|
||||
InetAddress localAddress(localIp);
|
||||
localAddress.setPort(0);
|
||||
InetAddress targetAddress(targetIp);
|
||||
targetAddress.setPort(0);
|
||||
InetAddress localAddress(localIp);
|
||||
localAddress.setPort(0);
|
||||
InetAddress targetAddress(targetIp);
|
||||
targetAddress.setPort(0);
|
||||
|
||||
_NDEntry &e = _cache[targetAddress];
|
||||
_NDEntry &e = _cache[targetAddress];
|
||||
|
||||
if ( (e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) ||
|
||||
(!e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) {
|
||||
e.lastQuerySent = now;
|
||||
if ((e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) ||
|
||||
(!e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) {
|
||||
e.lastQuerySent = now;
|
||||
|
||||
_neighbor_solicitation ns;
|
||||
memcpy(ns.target, targetAddress.rawIpData(), 16);
|
||||
localMac.copyTo(ns.option.mac);
|
||||
ns.calculateChecksum(localIp, targetIp);
|
||||
if (e.mac) {
|
||||
queryDest = e.mac;
|
||||
} else {
|
||||
queryDest = (uint64_t)0xffffffffffffULL;
|
||||
}
|
||||
} else {
|
||||
queryLen = 0;
|
||||
queryDest.zero();
|
||||
}
|
||||
_neighbor_solicitation ns;
|
||||
memcpy(ns.target, targetAddress.rawIpData(), 16);
|
||||
localMac.copyTo(ns.option.mac);
|
||||
ns.calculateChecksum(localIp, targetIp);
|
||||
if (e.mac) {
|
||||
queryDest = e.mac;
|
||||
} else {
|
||||
queryDest = (uint64_t)0xffffffffffffULL;
|
||||
}
|
||||
} else {
|
||||
queryLen = 0;
|
||||
queryDest.zero();
|
||||
}
|
||||
|
||||
return e.mac;
|
||||
return e.mac;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,39 +27,41 @@ namespace ZeroTier {
|
|||
class NeighborDiscovery
|
||||
{
|
||||
public:
|
||||
NeighborDiscovery();
|
||||
NeighborDiscovery();
|
||||
|
||||
/**
|
||||
* Set a local IP entry that we should respond to Neighbor Requests withPrefix64k
|
||||
*
|
||||
* @param mac Our local MAC address
|
||||
* @param ip Our IPv6 address
|
||||
*/
|
||||
void addLocal(const sockaddr_storage &address, const MAC &mac);
|
||||
/**
|
||||
* Set a local IP entry that we should respond to Neighbor Requests withPrefix64k
|
||||
*
|
||||
* @param mac Our local MAC address
|
||||
* @param ip Our IPv6 address
|
||||
*/
|
||||
void addLocal(const sockaddr_storage &address, const MAC &mac);
|
||||
|
||||
/**
|
||||
* Delete a local IP entry or cached Neighbor entry
|
||||
*
|
||||
* @param address IPv6 address to remove
|
||||
*/
|
||||
void remove(const sockaddr_storage &address);
|
||||
/**
|
||||
* Delete a local IP entry or cached Neighbor entry
|
||||
*
|
||||
* @param address IPv6 address to remove
|
||||
*/
|
||||
void remove(const sockaddr_storage &address);
|
||||
|
||||
sockaddr_storage processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest);
|
||||
sockaddr_storage processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest);
|
||||
|
||||
MAC query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest);
|
||||
MAC query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest);
|
||||
|
||||
private:
|
||||
struct _NDEntry
|
||||
{
|
||||
_NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false) {}
|
||||
uint64_t lastQuerySent;
|
||||
uint64_t lastResponseReceived;
|
||||
MAC mac;
|
||||
bool local;
|
||||
};
|
||||
struct _NDEntry
|
||||
{
|
||||
_NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false)
|
||||
{}
|
||||
|
||||
Map< InetAddress,_NDEntry > _cache;
|
||||
uint64_t _lastCleaned;
|
||||
uint64_t lastQuerySent;
|
||||
uint64_t lastResponseReceived;
|
||||
MAC mac;
|
||||
bool local;
|
||||
};
|
||||
|
||||
Map< InetAddress, _NDEntry > _cache;
|
||||
uint64_t _lastCleaned;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
Loading…
Add table
Reference in a new issue