diff options
Diffstat (limited to 'node/Network.cpp')
| -rw-r--r-- | node/Network.cpp | 99 |
1 files changed, 63 insertions, 36 deletions
diff --git a/node/Network.cpp b/node/Network.cpp index 3fd0e428..13086a8e 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -41,50 +41,77 @@ namespace ZeroTier { -void Network::Certificate::_shaForSignature(unsigned char *dig) const +void Network::CertificateOfMembership::addParameter(uint64_t id,uint64_t value,uint64_t maxDelta) { - SHA256_CTX sha; - SHA256_Init(&sha); - unsigned char zero = 0; - for(const_iterator i(begin());i!=end();++i) { - SHA256_Update(&sha,&zero,1); - SHA256_Update(&sha,(const unsigned char *)i->first.data(),i->first.length()); - SHA256_Update(&sha,&zero,1); - SHA256_Update(&sha,(const unsigned char *)i->second.data(),i->second.length()); - SHA256_Update(&sha,&zero,1); + _params.push_back(_Parameter(id,value,maxDelta)); + std::sort(_params.begin(),_params.end(),_SortByIdComparison()); +} + +std::string Network::CertificateOfMembership::toString() const +{ + uint64_t tmp[3000]; + unsigned long n = 0; + for(std::vector<_Parameter>::const_iterator p(_params.begin());p!=_params.end();++p) { + tmp[n++] = Utils::hton(p->id); + tmp[n++] = Utils::hton(p->value); + tmp[n++] = Utils::hton(p->maxDelta); + if (n >= 3000) + break; // sanity check -- certificates will never even approach this size } - SHA256_Final(dig,&sha); + return Utils::hex(tmp,sizeof(uint64_t) * n); } -static const std::string _DELTA_PREFIX("~"); -bool Network::Certificate::qualifyMembership(const Network::Certificate &mc) const +void Network::CertificateOfMembership::fromString(const char *s) { - // Note: optimization probably needed here, probably via some kind of - // memoization / dynamic programming. But make it work first, then make - // it fast. - - for(const_iterator myField(begin());myField!=end();++myField) { - if (!((myField->first.length() > 1)&&(myField->first[0] == '~'))) { // ~fields are max delta range specs - // If they lack the same field, comparison fails. - const_iterator theirField(mc.find(myField->first)); - if (theirField == mc.end()) + std::string tmp(Utils::unhex(s)); + _params.clear(); + const char *ptr = tmp.data(); + unsigned long remaining = tmp.length(); + while (remaining >= 24) { + _Parameter p; + p.id = Utils::ntoh(*((const uint64_t *)(ptr))); + p.value = Utils::ntoh(*((const uint64_t *)(ptr + 8))); + p.maxDelta = Utils::ntoh(*((const uint64_t *)(ptr + 16))); + _params.push_back(p); + ptr += 24; + remaining -= 24; + } +} + +bool Network::CertificateOfMembership::compare(const CertificateOfMembership &other) const + throw() +{ + unsigned long myidx = 0; + unsigned long otheridx = 0; + + while (myidx < _params.size()) { + // Fail if we're at the end of other, since this means the field is + // missing. + if (otheridx >= other._params.size()) + return false; + + // Seek to corresponding tuple in other, ignoring tuples that + // we may not have. If we run off the end of other, the tuple is + // missing. This works because tuples are sorted by ID. + while (other._params[otheridx].id != _params[myidx].id) { + ++otheridx; + if (otheridx >= other._params.size()) return false; + } - const_iterator deltaField(find(_DELTA_PREFIX + myField->first)); - if (deltaField == end()) { - // If there is no delta, compare on simple equality - if (myField->second != theirField->second) - return false; - } else { - // Otherwise compare the absolute value of the difference between - // the two values against the max delta. - int64_t my = Utils::hexStrTo64(myField->second.c_str()); - int64_t their = Utils::hexStrTo64(theirField->second.c_str()); - int64_t delta = Utils::hexStrTo64(deltaField->second.c_str()); - if (llabs((long long)(my - their)) > delta) - return false; - } + // Compare to determine if the absolute value of the difference + // between these two parameters is within our maxDelta. + uint64_t a = _params[myidx].value; + uint64_t b = other._params[myidx].value; + if (a >= b) { + if ((a - b) > _params[myidx].maxDelta) + return false; + } else { + if ((b - a) > _params[myidx].maxDelta) + return false; } + + ++myidx; } return true; |
