mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-03-21 03:25:16 +00:00
Auto-pushing of membership certs on: MULTICAST_FRAME,FRAME,MULTICAST_LIKE and on receipt of MULTICAST_LIKE.
This commit is contained in:
parent
4d594b24bc
commit
58fa6cab43
@ -169,30 +169,6 @@ void Network::addMembershipCertificate(const Address &peer,const CertificateOfMe
|
||||
_membershipCertificates[peer] = cert;
|
||||
}
|
||||
|
||||
void Network::pushMembershipCertificate(const Address &peer,bool force,uint64_t now)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
if (_isOpen)
|
||||
return;
|
||||
|
||||
uint64_t timestampMaxDelta = _myCertificate.timestampMaxDelta();
|
||||
if (!timestampMaxDelta) {
|
||||
LOG("unable to push my certificate to %s for network %.16llx: certificate invalid, missing required timestamp field",peer.toString().c_str(),_id);
|
||||
return; // required field missing!
|
||||
}
|
||||
|
||||
uint64_t &lastPushed = _lastPushedMembershipCertificate[peer];
|
||||
if ((force)||((now - lastPushed) > (timestampMaxDelta / 2))) {
|
||||
lastPushed = now;
|
||||
|
||||
Packet outp(peer,_r->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
|
||||
outp.append((uint64_t)_id);
|
||||
_myCertificate.serialize(outp);
|
||||
_r->sw->send(outp,true);
|
||||
}
|
||||
}
|
||||
|
||||
bool Network::isAllowed(const Address &peer) const
|
||||
{
|
||||
// Exceptions can occur if we do not yet have *our* configuration.
|
||||
@ -282,6 +258,25 @@ void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned
|
||||
}
|
||||
}
|
||||
|
||||
void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t now)
|
||||
{
|
||||
uint64_t timestampMaxDelta = _myCertificate.timestampMaxDelta();
|
||||
if (!timestampMaxDelta) {
|
||||
LOG("unable to push my certificate to %s for network %.16llx: certificate invalid, missing required timestamp field",peer.toString().c_str(),_id);
|
||||
return; // required field missing!
|
||||
}
|
||||
|
||||
uint64_t &lastPushed = _lastPushedMembershipCertificate[peer];
|
||||
if ((force)||((now - lastPushed) > (timestampMaxDelta / 2))) {
|
||||
lastPushed = now;
|
||||
|
||||
Packet outp(peer,_r->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
|
||||
outp.append((uint64_t)_id);
|
||||
_myCertificate.serialize(outp);
|
||||
_r->sw->send(outp,true);
|
||||
}
|
||||
}
|
||||
|
||||
void Network::_restoreState()
|
||||
{
|
||||
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".conf");
|
||||
|
@ -476,7 +476,36 @@ public:
|
||||
* @param force If true, push even if we've already done so within required time frame
|
||||
* @param now Current time
|
||||
*/
|
||||
void pushMembershipCertificate(const Address &peer,bool force,uint64_t now);
|
||||
inline void pushMembershipCertificate(const Address &peer,bool force,uint64_t now)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
if (!_isOpen)
|
||||
_pushMembershipCertificate(peer,force,now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push membership certificate to a packed zero-terminated array of addresses
|
||||
*
|
||||
* This pushes to all peers in peers[] (length must be a multiple of 5) until
|
||||
* len is reached or a null address is encountered.
|
||||
*
|
||||
* @param peers Packed array of 5-byte big-endian addresses
|
||||
* @param len Length of peers[] in total, MUST be a multiple of 5
|
||||
* @param force If true, push even if we've already done so within required time frame
|
||||
* @param now Current time
|
||||
*/
|
||||
inline void pushMembershipCertificate(const void *peers,unsigned int len,bool force,uint64_t now)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
if (!_isOpen) {
|
||||
for(unsigned int i=0;i<len;i+=ZT_ADDRESS_LENGTH) {
|
||||
Address a((char *)peers + i,ZT_ADDRESS_LENGTH);
|
||||
if (a)
|
||||
_pushMembershipCertificate(a,force,now);
|
||||
else break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param peer Peer address to check
|
||||
@ -558,6 +587,7 @@ public:
|
||||
|
||||
private:
|
||||
static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
|
||||
void _pushMembershipCertificate(const Address &peer,bool force,uint64_t now);
|
||||
void _restoreState();
|
||||
|
||||
const RuntimeEnvironment *_r;
|
||||
|
@ -438,6 +438,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
|
||||
|
||||
bool rateLimitsExceeded = false;
|
||||
unsigned int maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH;
|
||||
SharedPtr<Network> network(_r->nc->network(nwid));
|
||||
|
||||
if ((origin == _r->identity.address())||(_r->mc->deduplicate(nwid,guid))) {
|
||||
// Ordinary frames will drop duplicates. Supernodes keep propagating
|
||||
@ -457,7 +458,6 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
|
||||
// true -- we don't want to see a ton of copies of the same frame on
|
||||
// its tap device. Also double or triple counting bandwidth metrics
|
||||
// for the same frame would not be fair.
|
||||
SharedPtr<Network> network(_r->nc->network(nwid));
|
||||
if (network) {
|
||||
maxDepth = std::min((unsigned int)ZT_MULTICAST_GLOBAL_MAX_DEPTH,network->multicastDepth());
|
||||
if (!network->isAllowed(origin)) {
|
||||
@ -549,6 +549,11 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
|
||||
while (newFifoPtr != newFifoEnd)
|
||||
*(newFifoPtr++) = (unsigned char)0;
|
||||
|
||||
// If we're forwarding a packet within a private network that we are
|
||||
// a member of, also propagate our cert forward if needed.
|
||||
if (network)
|
||||
network->pushMembershipCertificate(newFifo,sizeof(newFifo),false,Utils::now());
|
||||
|
||||
// First element in newFifo[] is next hop
|
||||
Address nextHop(newFifo,ZT_ADDRESS_LENGTH);
|
||||
if ((!nextHop)&&(!_r->topology->amSupernode())) {
|
||||
@ -593,17 +598,18 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
|
||||
bool PacketDecoder::_doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
try {
|
||||
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
|
||||
if (ptr >= size())
|
||||
return true;
|
||||
uint64_t now = Utils::now();
|
||||
Address src(source());
|
||||
uint64_t now = Utils::now();
|
||||
|
||||
// Iterate through 18-byte network,MAC,ADI tuples
|
||||
for(;;) {
|
||||
_r->mc->likesGroup(at<uint64_t>(ptr),src,MulticastGroup(MAC(field(ptr + 8,6)),at<uint32_t>(ptr + 14)),now);
|
||||
if ((ptr += 18) >= size())
|
||||
break;
|
||||
for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr<size();ptr+=18) {
|
||||
uint64_t nwid = at<uint64_t>(ptr);
|
||||
SharedPtr<Network> network(_r->nc->network(nwid));
|
||||
if ((_r->topology->amSupernode())||((network)&&(network->isAllowed(peer->address())))) {
|
||||
_r->mc->likesGroup(nwid,src,MulticastGroup(MAC(field(ptr + 8,6)),at<uint32_t>(ptr + 14)),now);
|
||||
if (network)
|
||||
network->pushMembershipCertificate(peer->address(),false,now);
|
||||
}
|
||||
}
|
||||
} catch (std::exception &ex) {
|
||||
TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
|
||||
|
@ -114,6 +114,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
|
||||
unsigned char *const fifoEnd = fifo + sizeof(fifo);
|
||||
const unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION) + data.size();
|
||||
const SharedPtr<Peer> supernode(_r->topology->getBestSupernode());
|
||||
uint64_t now = Utils::now();
|
||||
|
||||
for(unsigned int prefix=0,np=((unsigned int)2 << (network->multicastPrefixBits() - 1));prefix<np;++prefix) {
|
||||
memset(bloom,0,sizeof(bloom));
|
||||
@ -130,6 +131,12 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
|
||||
else continue;
|
||||
}
|
||||
|
||||
// If network is not open, make sure all recipients have our membership
|
||||
// certificate if we haven't sent it recently. As the multicast goes
|
||||
// further down the line, peers beyond the first batch will ask us for
|
||||
// our membership certificate if they need it.
|
||||
network->pushMembershipCertificate(fifo,sizeof(fifo),false,now);
|
||||
|
||||
Packet outp(firstHop,_r->identity.address(),Packet::VERB_MULTICAST_FRAME);
|
||||
outp.append((uint16_t)0);
|
||||
outp.append(fifo + ZT_ADDRESS_LENGTH,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO); // remainder of fifo is loaded into packet
|
||||
@ -161,6 +168,8 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
|
||||
// Simple unicast frame from us to another node
|
||||
Address toZT(to.data + 1,ZT_ADDRESS_LENGTH);
|
||||
if (network->isAllowed(toZT)) {
|
||||
network->pushMembershipCertificate(toZT,false,Utils::now());
|
||||
|
||||
Packet outp(toZT,_r->identity.address(),Packet::VERB_FRAME);
|
||||
outp.append(network->id());
|
||||
outp.append((uint16_t)etherType);
|
||||
@ -388,10 +397,13 @@ void Switch::announceMulticastGroups(const std::map< SharedPtr<Network>,std::set
|
||||
TRACE("announcing %u multicast groups for %u networks to %u peers",totalMulticastGroups,(unsigned int)allMemberships.size(),(unsigned int)directPeers.size());
|
||||
#endif
|
||||
|
||||
uint64_t now = Utils::now();
|
||||
for(std::vector< SharedPtr<Peer> >::iterator p(directPeers.begin());p!=directPeers.end();++p) {
|
||||
Packet outp((*p)->address(),_r->identity.address(),Packet::VERB_MULTICAST_LIKE);
|
||||
|
||||
for(std::map< SharedPtr<Network>,std::set<MulticastGroup> >::const_iterator nwmgs(allMemberships.begin());nwmgs!=allMemberships.end();++nwmgs) {
|
||||
nwmgs->first->pushMembershipCertificate((*p)->address(),false,now);
|
||||
|
||||
if ((_r->topology->isSupernode((*p)->address()))||(nwmgs->first->isAllowed((*p)->address()))) {
|
||||
for(std::set<MulticastGroup>::iterator mg(nwmgs->second.begin());mg!=nwmgs->second.end();++mg) {
|
||||
if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
|
||||
@ -416,8 +428,11 @@ void Switch::announceMulticastGroups(const SharedPtr<Peer> &peer)
|
||||
{
|
||||
Packet outp(peer->address(),_r->identity.address(),Packet::VERB_MULTICAST_LIKE);
|
||||
std::vector< SharedPtr<Network> > networks(_r->nc->networks());
|
||||
uint64_t now = Utils::now();
|
||||
for(std::vector< SharedPtr<Network> >::iterator n(networks.begin());n!=networks.end();++n) {
|
||||
if (((*n)->isAllowed(peer->address()))||(_r->topology->isSupernode(peer->address()))) {
|
||||
(*n)->pushMembershipCertificate(peer->address(),false,now);
|
||||
|
||||
std::set<MulticastGroup> mgs((*n)->multicastGroups());
|
||||
for(std::set<MulticastGroup>::iterator mg(mgs.begin());mg!=mgs.end();++mg) {
|
||||
if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user