mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-19 04:57:53 +00:00
(1) Public networks now get COMs even though they do not gate with them since they will need them to push auth for multicast stuff, (2) added a bunch of rate limit circuit breakers for anti-DOS, (3) cleanup.
This commit is contained in:
parent
ef87069957
commit
ab9afbc749
@ -924,13 +924,11 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_jB(network["private"],true)) {
|
CertificateOfMembership com(now,credentialtmd,nwid,identity.address());
|
||||||
CertificateOfMembership com(now,credentialtmd,nwid,identity.address());
|
if (com.sign(signingId)) {
|
||||||
if (com.sign(signingId)) {
|
nc.com = com;
|
||||||
nc.com = com;
|
} else {
|
||||||
} else {
|
return NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
||||||
return NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeJson(memberJP,member);
|
_writeJson(memberJP,member);
|
||||||
|
@ -236,6 +236,11 @@
|
|||||||
*/
|
*/
|
||||||
#define ZT_MULTICAST_EXPLICIT_GATHER_DELAY (ZT_MULTICAST_LIKE_EXPIRE / 10)
|
#define ZT_MULTICAST_EXPLICIT_GATHER_DELAY (ZT_MULTICAST_LIKE_EXPIRE / 10)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expiration for credentials presented for MULTICAST_LIKE or MULTICAST_GATHER (for non-network-members)
|
||||||
|
*/
|
||||||
|
#define ZT_MULTICAST_CREDENTIAL_EXPIRATON ZT_MULTICAST_LIKE_EXPIRE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timeout for outgoing multicasts
|
* Timeout for outgoing multicasts
|
||||||
*
|
*
|
||||||
@ -263,6 +268,11 @@
|
|||||||
*/
|
*/
|
||||||
#define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500
|
#define ZT_PATH_MIN_REACTIVATE_INTERVAL 2500
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not accept HELLOs over a given path more often than this
|
||||||
|
*/
|
||||||
|
#define ZT_PATH_HELLO_RATE_LIMIT 1000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay between full-fledge pings of directly connected peers
|
* Delay between full-fledge pings of directly connected peers
|
||||||
*/
|
*/
|
||||||
@ -283,6 +293,11 @@
|
|||||||
*/
|
*/
|
||||||
#define ZT_PEER_ACTIVITY_TIMEOUT 500000
|
#define ZT_PEER_ACTIVITY_TIMEOUT 500000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General rate limit timeout for multiple packet types (HELLO, etc.)
|
||||||
|
*/
|
||||||
|
#define ZT_PEER_GENERAL_INBOUND_RATE_LIMIT 1000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay between requests for updated network autoconf information
|
* Delay between requests for updated network autoconf information
|
||||||
*
|
*
|
||||||
@ -326,6 +341,11 @@
|
|||||||
*/
|
*/
|
||||||
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000
|
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound
|
||||||
|
*/
|
||||||
|
#define ZT_PEER_GENERAL_RATE_LIMIT 1000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of direct path pushes within cutoff time
|
* Maximum number of direct path pushes within cutoff time
|
||||||
*
|
*
|
||||||
|
@ -62,11 +62,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
|
} else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
|
||||||
// A null pointer for peer to _doHELLO() tells it to run its own
|
// Only HELLO is allowed in the clear, but will still have a MAC
|
||||||
// special internal authentication logic. This is done for unencrypted
|
return _doHELLO(RR,false);
|
||||||
// HELLOs to learn new identities, etc.
|
|
||||||
SharedPtr<Peer> tmp;
|
|
||||||
return _doHELLO(RR,tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
|
SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
|
||||||
@ -91,7 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR)
|
|||||||
peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false);
|
peer->received(_path,hops(),packetId(),v,0,Packet::VERB_NOP,false);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Packet::VERB_HELLO: return _doHELLO(RR,peer);
|
case Packet::VERB_HELLO: return _doHELLO(RR,true);
|
||||||
case Packet::VERB_ERROR: return _doERROR(RR,peer);
|
case Packet::VERB_ERROR: return _doERROR(RR,peer);
|
||||||
case Packet::VERB_OK: return _doOK(RR,peer);
|
case Packet::VERB_OK: return _doOK(RR,peer);
|
||||||
case Packet::VERB_WHOIS: return _doWHOIS(RR,peer);
|
case Packet::VERB_WHOIS: return _doWHOIS(RR,peer);
|
||||||
@ -192,16 +189,16 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer)
|
bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated)
|
||||||
{
|
{
|
||||||
/* Note: this is the only packet ever sent in the clear, and it's also
|
|
||||||
* the only packet that we authenticate via a different path. Authentication
|
|
||||||
* occurs here and is based on the validity of the identity and the
|
|
||||||
* integrity of the packet's MAC, but it must be done after we check
|
|
||||||
* the identity since HELLO is a mechanism for learning new identities
|
|
||||||
* in the first place. */
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const uint64_t now = RR->node->now();
|
||||||
|
|
||||||
|
if (!_path->rateGateHello(now)) {
|
||||||
|
TRACE("dropped HELLO from %s(%s): rate limiting circuit breaker for HELLO on this path tripped",source().toString().c_str(),_path->address().toString().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const uint64_t pid = packetId();
|
const uint64_t pid = packetId();
|
||||||
const Address fromAddress(source());
|
const Address fromAddress(source());
|
||||||
const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
|
const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
|
||||||
@ -228,20 +225,19 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protoVersion < ZT_PROTO_VERSION_MIN) {
|
|
||||||
TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (fromAddress != id.address()) {
|
if (fromAddress != id.address()) {
|
||||||
TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str());
|
TRACE("dropped HELLO from %s(%s): identity not for sending address",fromAddress.toString().c_str(),_path->address().toString().c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (protoVersion < ZT_PROTO_VERSION_MIN) {
|
||||||
|
TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_path->address().toString().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!peer) { // peer == NULL is the normal case here
|
SharedPtr<Peer> peer(RR->topology->getPeer(id.address()));
|
||||||
peer = RR->topology->getPeer(id.address());
|
if (peer) {
|
||||||
if (peer) {
|
// We already have an identity with this address -- check for collisions
|
||||||
// We already have an identity with this address -- check for collisions
|
if (!alreadyAuthenticated) {
|
||||||
|
|
||||||
if (peer->identity() != id) {
|
if (peer->identity() != id) {
|
||||||
// Identity is different from the one we already have -- address collision
|
// Identity is different from the one we already have -- address collision
|
||||||
|
|
||||||
@ -273,31 +269,37 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
|
|||||||
|
|
||||||
// Continue at // VALID
|
// Continue at // VALID
|
||||||
}
|
}
|
||||||
} else {
|
} // else continue at // VALID
|
||||||
// We don't already have an identity with this address -- validate and learn it
|
} else {
|
||||||
|
// We don't already have an identity with this address -- validate and learn it
|
||||||
|
|
||||||
// Check identity proof of work
|
// Sanity check: this basically can't happen
|
||||||
if (!id.locallyValidate()) {
|
if (alreadyAuthenticated) {
|
||||||
TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str());
|
TRACE("dropped HELLO from %s(%s): somehow already authenticated with unknown peer?",id.address().toString().c_str(),_path->address().toString().c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
// Check packet integrity and authentication
|
|
||||||
SharedPtr<Peer> newPeer(new Peer(RR,RR->identity,id));
|
|
||||||
if (!dearmor(newPeer->key())) {
|
|
||||||
TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
peer = RR->topology->addPeer(newPeer);
|
|
||||||
|
|
||||||
// Continue at // VALID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// VALID -- if we made it here, packet passed identity and authenticity checks!
|
// Check identity proof of work
|
||||||
|
if (!id.locallyValidate()) {
|
||||||
|
TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_path->address().toString().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check packet integrity and authentication
|
||||||
|
SharedPtr<Peer> newPeer(new Peer(RR,RR->identity,id));
|
||||||
|
if (!dearmor(newPeer->key())) {
|
||||||
|
TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
peer = RR->topology->addPeer(newPeer);
|
||||||
|
|
||||||
|
// Continue at // VALID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VALID -- if we made it here, packet passed identity and authenticity checks!
|
||||||
|
|
||||||
if ((externalSurfaceAddress)&&(hops() == 0))
|
if ((externalSurfaceAddress)&&(hops() == 0))
|
||||||
RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),RR->node->now());
|
RR->sa->iam(id.address(),_path->localAddress(),_path->address(),externalSurfaceAddress,RR->topology->isUpstream(id),now);
|
||||||
|
|
||||||
Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK);
|
Packet outp(id.address(),RR->identity.address(),Packet::VERB_OK);
|
||||||
outp.append((unsigned char)Packet::VERB_HELLO);
|
outp.append((unsigned char)Packet::VERB_HELLO);
|
||||||
@ -349,7 +351,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
|
|||||||
}
|
}
|
||||||
|
|
||||||
outp.armor(peer->key(),true);
|
outp.armor(peer->key(),true);
|
||||||
_path->send(RR,outp.data(),outp.size(),RR->node->now());
|
_path->send(RR,outp.data(),outp.size(),now);
|
||||||
|
|
||||||
peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
|
peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
|
||||||
peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false);
|
peer->received(_path,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP,false);
|
||||||
@ -443,7 +445,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
|||||||
case Packet::VERB_MULTICAST_GATHER: {
|
case Packet::VERB_MULTICAST_GATHER: {
|
||||||
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID);
|
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID);
|
||||||
SharedPtr<Network> network(RR->node->network(nwid));
|
SharedPtr<Network> network(RR->node->network(nwid));
|
||||||
if ((network)&&(network->gateMulticastGather(peer,verb(),packetId()))) {
|
if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) {
|
||||||
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI));
|
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI));
|
||||||
//TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size());
|
//TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size());
|
||||||
const unsigned int count = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4);
|
const unsigned int count = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4);
|
||||||
@ -469,7 +471,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
|||||||
network->addCredential(com);
|
network->addCredential(com);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (network->gateMulticastGather(peer,verb(),packetId())) {
|
if (network->gateMulticastGatherReply(peer,verb(),packetId())) {
|
||||||
if ((flags & 0x02) != 0) {
|
if ((flags & 0x02) != 0) {
|
||||||
// OK(MULTICAST_FRAME) includes implicit gather results
|
// OK(MULTICAST_FRAME) includes implicit gather results
|
||||||
offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS;
|
offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS;
|
||||||
@ -494,6 +496,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
|
|||||||
bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
if (!peer->rateGateInboundWhoisRequest(RR->node->now())) {
|
||||||
|
TRACE("dropped WHOIS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
||||||
outp.append((unsigned char)Packet::VERB_WHOIS);
|
outp.append((unsigned char)Packet::VERB_WHOIS);
|
||||||
outp.append(packetId());
|
outp.append(packetId());
|
||||||
@ -672,6 +679,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
|
|||||||
bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
if (!peer->rateGateEchoRequest(RR->node->now())) {
|
||||||
|
TRACE("dropped ECHO from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const uint64_t pid = packetId();
|
const uint64_t pid = packetId();
|
||||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
||||||
outp.append((unsigned char)Packet::VERB_ECHO);
|
outp.append((unsigned char)Packet::VERB_ECHO);
|
||||||
@ -680,6 +692,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer>
|
|||||||
outp.append(reinterpret_cast<const unsigned char *>(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
|
outp.append(reinterpret_cast<const unsigned char *>(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
|
||||||
outp.armor(peer->key(),true);
|
outp.armor(peer->key(),true);
|
||||||
_path->send(RR,outp.data(),outp.size(),RR->node->now());
|
_path->send(RR,outp.data(),outp.size(),RR->node->now());
|
||||||
|
|
||||||
peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false);
|
peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false);
|
||||||
} catch ( ... ) {
|
} catch ( ... ) {
|
||||||
TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
|
TRACE("dropped ECHO from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
|
||||||
@ -692,11 +705,35 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared
|
|||||||
try {
|
try {
|
||||||
const uint64_t now = RR->node->now();
|
const uint64_t now = RR->node->now();
|
||||||
|
|
||||||
|
uint64_t authOnNetwork[256];
|
||||||
|
unsigned int authOnNetworkCount = 0;
|
||||||
|
SharedPtr<Network> network;
|
||||||
|
|
||||||
// Iterate through 18-byte network,MAC,ADI tuples
|
// Iterate through 18-byte network,MAC,ADI tuples
|
||||||
for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr<size();ptr+=18) {
|
for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr<size();ptr+=18) {
|
||||||
const uint64_t nwid = at<uint64_t>(ptr);
|
const uint64_t nwid = at<uint64_t>(ptr);
|
||||||
const MulticastGroup group(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14));
|
|
||||||
RR->mc->add(now,nwid,group,peer->address());
|
bool auth = false;
|
||||||
|
for(unsigned int i=0;i<authOnNetworkCount;++i) {
|
||||||
|
if (nwid == authOnNetwork[i]) {
|
||||||
|
auth = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!auth) {
|
||||||
|
if ((!network)||(network->id() != nwid))
|
||||||
|
network = RR->node->network(nwid);
|
||||||
|
if ( ((network)&&(network->gate(peer,verb(),packetId()))) || RR->mc->cacheAuthorized(peer->address(),nwid,now) ) {
|
||||||
|
auth = true;
|
||||||
|
if (authOnNetworkCount < 256) // sanity check, packets can't really be this big
|
||||||
|
authOnNetwork[authOnNetworkCount++] = nwid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auth) {
|
||||||
|
const MulticastGroup group(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14));
|
||||||
|
RR->mc->add(now,nwid,group,peer->address());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false);
|
peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false);
|
||||||
@ -721,7 +758,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
|
|||||||
if (network) {
|
if (network) {
|
||||||
if (network->addCredential(com) == 1)
|
if (network->addCredential(com) == 1)
|
||||||
return false; // wait for WHOIS
|
return false; // wait for WHOIS
|
||||||
}
|
} else RR->mc->addCredential(com,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++p; // skip trailing 0 after COMs if present
|
++p; // skip trailing 0 after COMs if present
|
||||||
@ -759,22 +796,21 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID);
|
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID);
|
||||||
|
|
||||||
const unsigned int metaDataLength = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN);
|
|
||||||
const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength);
|
|
||||||
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData(metaDataBytes,metaDataLength);
|
|
||||||
|
|
||||||
const unsigned int hopCount = hops();
|
const unsigned int hopCount = hops();
|
||||||
const uint64_t requestPacketId = packetId();
|
const uint64_t requestPacketId = packetId();
|
||||||
bool netconfOk = false;
|
bool trustEstablished = false;
|
||||||
|
|
||||||
if (RR->localNetworkController) {
|
if (RR->localNetworkController) {
|
||||||
|
const unsigned int metaDataLength = at<uint16_t>(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN);
|
||||||
|
const char *metaDataBytes = (const char *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength);
|
||||||
|
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData(metaDataBytes,metaDataLength);
|
||||||
|
|
||||||
NetworkConfig *netconf = new NetworkConfig();
|
NetworkConfig *netconf = new NetworkConfig();
|
||||||
try {
|
try {
|
||||||
switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _path->address(),RR->identity,peer->identity(),nwid,metaData,*netconf)) {
|
switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _path->address(),RR->identity,peer->identity(),nwid,metaData,*netconf)) {
|
||||||
|
|
||||||
case NetworkController::NETCONF_QUERY_OK: {
|
case NetworkController::NETCONF_QUERY_OK: {
|
||||||
netconfOk = true;
|
trustEstablished = true;
|
||||||
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dconf = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
|
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *dconf = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
|
||||||
try {
|
try {
|
||||||
if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) {
|
if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) {
|
||||||
@ -846,7 +882,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
|
|||||||
_path->send(RR,outp.data(),outp.size(),RR->node->now());
|
_path->send(RR,outp.data(),outp.size(),RR->node->now());
|
||||||
}
|
}
|
||||||
|
|
||||||
peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,netconfOk);
|
peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,trustEstablished);
|
||||||
} catch (std::exception &exc) {
|
} catch (std::exception &exc) {
|
||||||
fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what());
|
fprintf(stderr,"WARNING: network config request failed with exception: %s" ZT_EOL_S,exc.what());
|
||||||
TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what());
|
TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what());
|
||||||
@ -897,21 +933,23 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar
|
|||||||
|
|
||||||
//TRACE("<<MC %s(%s) GATHER up to %u in %.16llx/%s",source().toString().c_str(),_path->address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str());
|
//TRACE("<<MC %s(%s) GATHER up to %u in %.16llx/%s",source().toString().c_str(),_path->address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str());
|
||||||
|
|
||||||
|
const SharedPtr<Network> network(RR->node->network(nwid));
|
||||||
|
|
||||||
if ((flags & 0x01) != 0) {
|
if ((flags & 0x01) != 0) {
|
||||||
try {
|
try {
|
||||||
CertificateOfMembership com;
|
CertificateOfMembership com;
|
||||||
com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM);
|
com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM);
|
||||||
if (com) {
|
if (com) {
|
||||||
SharedPtr<Network> network(RR->node->network(nwid));
|
|
||||||
if (network)
|
if (network)
|
||||||
network->addCredential(com);
|
network->addCredential(com);
|
||||||
|
else RR->mc->addCredential(com,false);
|
||||||
}
|
}
|
||||||
} catch ( ... ) {
|
} catch ( ... ) {
|
||||||
TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str());
|
TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gatherLimit) {
|
if ( ( ((network)&&(network->gate(peer,verb(),packetId()))) || (RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now())) ) && (gatherLimit > 0) ) {
|
||||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
||||||
outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER);
|
outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER);
|
||||||
outp.append(packetId());
|
outp.append(packetId());
|
||||||
@ -1043,7 +1081,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
|
|||||||
const uint64_t now = RR->node->now();
|
const uint64_t now = RR->node->now();
|
||||||
|
|
||||||
// First, subject this to a rate limit
|
// First, subject this to a rate limit
|
||||||
if (!peer->shouldRespondToDirectPathPush(now)) {
|
if (!peer->rateGatePushDirectPaths(now)) {
|
||||||
TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str());
|
TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str());
|
||||||
peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false);
|
peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false);
|
||||||
return true;
|
return true;
|
||||||
|
@ -136,7 +136,7 @@ private:
|
|||||||
// These are called internally to handle packet contents once it has
|
// These are called internally to handle packet contents once it has
|
||||||
// been authenticated, decrypted, decompressed, and classified.
|
// been authenticated, decrypted, decompressed, and classified.
|
||||||
bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||||
bool _doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer); // can be called with NULL peer, while all others cannot
|
bool _doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated);
|
||||||
bool _doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
bool _doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||||
bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||||
bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer);
|
||||||
|
@ -71,7 +71,7 @@ void Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint
|
|||||||
}
|
}
|
||||||
capsAndTags.setAt<uint16_t>(tagCountPos,(uint16_t)appendedTags);
|
capsAndTags.setAt<uint16_t>(tagCountPos,(uint16_t)appendedTags);
|
||||||
|
|
||||||
const bool needCom = ((nconf.isPrivate())&&(nconf.com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY));
|
const bool needCom = ((nconf.com)&&((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY));
|
||||||
if ( (needCom) || (appendedCaps) || (appendedTags) ) {
|
if ( (needCom) || (appendedCaps) || (appendedTags) ) {
|
||||||
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
||||||
if (needCom) {
|
if (needCom) {
|
||||||
|
@ -34,8 +34,8 @@ namespace ZeroTier {
|
|||||||
|
|
||||||
Multicaster::Multicaster(const RuntimeEnvironment *renv) :
|
Multicaster::Multicaster(const RuntimeEnvironment *renv) :
|
||||||
RR(renv),
|
RR(renv),
|
||||||
_groups(1024),
|
_groups(256),
|
||||||
_groups_m()
|
_gatherAuth(256)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ void Multicaster::send(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(unsigned int k=0;k<numExplicitGatherPeers;++k) {
|
for(unsigned int k=0;k<numExplicitGatherPeers;++k) {
|
||||||
const CertificateOfMembership *com = (network) ? (((network->config())&&(network->config().isPrivate())) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0;
|
const CertificateOfMembership *com = (network) ? ((network->config().com) ? &(network->config().com) : (const CertificateOfMembership *)0) : (const CertificateOfMembership *)0;
|
||||||
Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
|
Packet outp(explicitGatherPeers[k],RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
|
||||||
outp.append(nwid);
|
outp.append(nwid);
|
||||||
outp.append((uint8_t)((com) ? 0x01 : 0x00));
|
outp.append((uint8_t)((com) ? 0x01 : 0x00));
|
||||||
@ -301,42 +301,62 @@ void Multicaster::send(
|
|||||||
|
|
||||||
void Multicaster::clean(uint64_t now)
|
void Multicaster::clean(uint64_t now)
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_groups_m);
|
{
|
||||||
|
Mutex::Lock _l(_groups_m);
|
||||||
|
Multicaster::Key *k = (Multicaster::Key *)0;
|
||||||
|
MulticastGroupStatus *s = (MulticastGroupStatus *)0;
|
||||||
|
Hashtable<Multicaster::Key,MulticastGroupStatus>::Iterator mm(_groups);
|
||||||
|
while (mm.next(k,s)) {
|
||||||
|
for(std::list<OutboundMulticast>::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) {
|
||||||
|
if ((tx->expired(now))||(tx->atLimit()))
|
||||||
|
s->txQueue.erase(tx++);
|
||||||
|
else ++tx;
|
||||||
|
}
|
||||||
|
|
||||||
Multicaster::Key *k = (Multicaster::Key *)0;
|
unsigned long count = 0;
|
||||||
MulticastGroupStatus *s = (MulticastGroupStatus *)0;
|
{
|
||||||
Hashtable<Multicaster::Key,MulticastGroupStatus>::Iterator mm(_groups);
|
std::vector<MulticastGroupMember>::iterator reader(s->members.begin());
|
||||||
while (mm.next(k,s)) {
|
std::vector<MulticastGroupMember>::iterator writer(reader);
|
||||||
for(std::list<OutboundMulticast>::iterator tx(s->txQueue.begin());tx!=s->txQueue.end();) {
|
while (reader != s->members.end()) {
|
||||||
if ((tx->expired(now))||(tx->atLimit()))
|
if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) {
|
||||||
s->txQueue.erase(tx++);
|
*writer = *reader;
|
||||||
else ++tx;
|
++writer;
|
||||||
}
|
++count;
|
||||||
|
}
|
||||||
unsigned long count = 0;
|
++reader;
|
||||||
{
|
|
||||||
std::vector<MulticastGroupMember>::iterator reader(s->members.begin());
|
|
||||||
std::vector<MulticastGroupMember>::iterator writer(reader);
|
|
||||||
while (reader != s->members.end()) {
|
|
||||||
if ((now - reader->timestamp) < ZT_MULTICAST_LIKE_EXPIRE) {
|
|
||||||
*writer = *reader;
|
|
||||||
++writer;
|
|
||||||
++count;
|
|
||||||
}
|
}
|
||||||
++reader;
|
}
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
s->members.resize(count);
|
||||||
|
} else if (s->txQueue.empty()) {
|
||||||
|
_groups.erase(*k);
|
||||||
|
} else {
|
||||||
|
s->members.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (count) {
|
{
|
||||||
s->members.resize(count);
|
Mutex::Lock _l(_gatherAuth_m);
|
||||||
} else if (s->txQueue.empty()) {
|
_GatherAuthKey *k = (_GatherAuthKey *)0;
|
||||||
_groups.erase(*k);
|
uint64_t *ts = (uint64_t *)ts;
|
||||||
} else {
|
Hashtable<_GatherAuthKey,uint64_t>::Iterator i(_gatherAuth);
|
||||||
s->members.clear();
|
while (i.next(k,ts)) {
|
||||||
|
if ((now - *ts) >= ZT_MULTICAST_CREDENTIAL_EXPIRATON)
|
||||||
|
_gatherAuth.erase(*k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Multicaster::addCredential(const CertificateOfMembership &com,bool alreadyValidated)
|
||||||
|
{
|
||||||
|
if ((alreadyValidated)||(com.verify(RR) == 0)) {
|
||||||
|
Mutex::Lock _l(_gatherAuth_m);
|
||||||
|
_gatherAuth[_GatherAuthKey(com.networkId(),com.issuedTo())] = RR->node->now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member)
|
void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member)
|
||||||
{
|
{
|
||||||
// assumes _groups_m is locked
|
// assumes _groups_m is locked
|
||||||
|
@ -179,12 +179,52 @@ public:
|
|||||||
*/
|
*/
|
||||||
void clean(uint64_t now);
|
void clean(uint64_t now);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an authorization credential
|
||||||
|
*
|
||||||
|
* The Multicaster keeps its own track of when valid credentials of network
|
||||||
|
* membership are presented. This allows it to control MULTICAST_LIKE
|
||||||
|
* GATHER authorization for networks this node does not belong to.
|
||||||
|
*
|
||||||
|
* @param com Certificate of membership
|
||||||
|
* @param alreadyValidated If true, COM has already been checked and found to be valid and signed
|
||||||
|
*/
|
||||||
|
void addCredential(const CertificateOfMembership &com,bool alreadyValidated);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check authorization for GATHER and LIKE for non-network-members
|
||||||
|
*
|
||||||
|
* @param a Address of peer
|
||||||
|
* @param nwid Network ID
|
||||||
|
* @param now Current time
|
||||||
|
* @return True if GATHER and LIKE should be allowed
|
||||||
|
*/
|
||||||
|
bool cacheAuthorized(const Address &a,const uint64_t nwid,const uint64_t now) const
|
||||||
|
{
|
||||||
|
Mutex::Lock _l(_gatherAuth_m);
|
||||||
|
const uint64_t *p = _gatherAuth.get(_GatherAuthKey(nwid,a));
|
||||||
|
return ((p)&&((now - *p) < ZT_MULTICAST_CREDENTIAL_EXPIRATON));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member);
|
void _add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member);
|
||||||
|
|
||||||
const RuntimeEnvironment *RR;
|
const RuntimeEnvironment *RR;
|
||||||
|
|
||||||
Hashtable<Multicaster::Key,MulticastGroupStatus> _groups;
|
Hashtable<Multicaster::Key,MulticastGroupStatus> _groups;
|
||||||
Mutex _groups_m;
|
Mutex _groups_m;
|
||||||
|
|
||||||
|
struct _GatherAuthKey
|
||||||
|
{
|
||||||
|
_GatherAuthKey() : member(0),networkId(0) {}
|
||||||
|
_GatherAuthKey(const uint64_t nwid,const Address &a) : member(a.toInt()),networkId(nwid) {}
|
||||||
|
inline unsigned long hashCode() const { return (member ^ networkId); }
|
||||||
|
inline bool operator==(const _GatherAuthKey &k) const { return ((member == k.member)&&(networkId == k.networkId)); }
|
||||||
|
uint64_t member;
|
||||||
|
uint64_t networkId;
|
||||||
|
};
|
||||||
|
Hashtable< _GatherAuthKey,uint64_t > _gatherAuth;
|
||||||
|
Mutex _gatherAuth_m;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
@ -866,31 +866,24 @@ bool Network::subscribedToMulticastGroup(const MulticastGroup &mg,bool includeBr
|
|||||||
return true;
|
return true;
|
||||||
else if (includeBridgedGroups)
|
else if (includeBridgedGroups)
|
||||||
return _multicastGroupsBehindMe.contains(mg);
|
return _multicastGroupsBehindMe.contains(mg);
|
||||||
else return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::multicastSubscribe(const MulticastGroup &mg)
|
void Network::multicastSubscribe(const MulticastGroup &mg)
|
||||||
{
|
{
|
||||||
{
|
Mutex::Lock _l(_lock);
|
||||||
Mutex::Lock _l(_lock);
|
if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
|
||||||
if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
|
_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
|
||||||
return;
|
_sendUpdatesToMembers(&mg);
|
||||||
_myMulticastGroups.push_back(mg);
|
|
||||||
std::sort(_myMulticastGroups.begin(),_myMulticastGroups.end());
|
|
||||||
_pushStateToMembers(&mg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::multicastUnsubscribe(const MulticastGroup &mg)
|
void Network::multicastUnsubscribe(const MulticastGroup &mg)
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_lock);
|
Mutex::Lock _l(_lock);
|
||||||
std::vector<MulticastGroup> nmg;
|
std::vector<MulticastGroup>::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg));
|
||||||
for(std::vector<MulticastGroup>::const_iterator i(_myMulticastGroups.begin());i!=_myMulticastGroups.end();++i) {
|
if ( (i != _myMulticastGroups.end()) && (*i == mg) )
|
||||||
if (*i != mg)
|
_myMulticastGroups.erase(i);
|
||||||
nmg.push_back(*i);
|
|
||||||
}
|
|
||||||
if (nmg.size() != _myMulticastGroups.size())
|
|
||||||
_myMulticastGroups.swap(nmg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Network::applyConfiguration(const NetworkConfig &conf)
|
bool Network::applyConfiguration(const NetworkConfig &conf)
|
||||||
@ -1054,30 +1047,29 @@ void Network::requestConfiguration()
|
|||||||
} else {
|
} else {
|
||||||
outp.append((unsigned char)0,16);
|
outp.append((unsigned char)0,16);
|
||||||
}
|
}
|
||||||
RR->node->expectReplyTo(outp.packetId());
|
|
||||||
|
RR->node->expectReplyTo(_inboundConfigPacketId = outp.packetId());
|
||||||
|
_inboundConfigChunks.clear();
|
||||||
|
|
||||||
outp.compress();
|
outp.compress();
|
||||||
RR->sw->send(outp,true);
|
RR->sw->send(outp,true);
|
||||||
|
|
||||||
// Expect replies with this in-re packet ID
|
|
||||||
_inboundConfigPacketId = outp.packetId();
|
|
||||||
_inboundConfigChunks.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Network::gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId)
|
bool Network::gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId)
|
||||||
{
|
{
|
||||||
|
const uint64_t now = RR->node->now();
|
||||||
Mutex::Lock _l(_lock);
|
Mutex::Lock _l(_lock);
|
||||||
try {
|
try {
|
||||||
if (_config) {
|
if (_config) {
|
||||||
Membership &m = _membership(peer->address());
|
Membership &m = _membership(peer->address());
|
||||||
const bool allow = m.isAllowedOnNetwork(_config);
|
const bool allow = m.isAllowedOnNetwork(_config);
|
||||||
if (allow) {
|
if (allow) {
|
||||||
const uint64_t now = RR->node->now();
|
|
||||||
m.sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0);
|
m.sendCredentialsIfNeeded(RR,now,peer->address(),_config,(const Capability *)0);
|
||||||
if (m.shouldLikeMulticasts(now)) {
|
if (m.shouldLikeMulticasts(now)) {
|
||||||
_announceMulticastGroupsTo(peer->address(),_allMulticastGroups());
|
_announceMulticastGroupsTo(peer->address(),_allMulticastGroups());
|
||||||
m.likingMulticasts(now);
|
m.likingMulticasts(now);
|
||||||
}
|
}
|
||||||
} else if (m.recentlyAllowedOnNetwork(_config)) {
|
} else if (m.recentlyAllowedOnNetwork(_config)&&peer->rateGateRequestCredentials(now)) {
|
||||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
|
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
|
||||||
outp.append((uint8_t)verb);
|
outp.append((uint8_t)verb);
|
||||||
outp.append(packetId);
|
outp.append(packetId);
|
||||||
@ -1093,7 +1085,7 @@ bool Network::gate(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uin
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Network::gateMulticastGather(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId)
|
bool Network::gateMulticastGatherReply(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId)
|
||||||
{
|
{
|
||||||
return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) );
|
return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) );
|
||||||
}
|
}
|
||||||
@ -1180,7 +1172,22 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now)
|
|||||||
const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size();
|
const unsigned long tmp = (unsigned long)_multicastGroupsBehindMe.size();
|
||||||
_multicastGroupsBehindMe.set(mg,now);
|
_multicastGroupsBehindMe.set(mg,now);
|
||||||
if (tmp != _multicastGroupsBehindMe.size())
|
if (tmp != _multicastGroupsBehindMe.size())
|
||||||
_pushStateToMembers(&mg);
|
_sendUpdatesToMembers(&mg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Network::addCredential(const CertificateOfMembership &com)
|
||||||
|
{
|
||||||
|
if (com.networkId() != _id)
|
||||||
|
return -1;
|
||||||
|
const Address a(com.issuedTo());
|
||||||
|
Mutex::Lock _l(_lock);
|
||||||
|
Membership &m = _membership(a);
|
||||||
|
const int result = m.addCredential(RR,com);
|
||||||
|
if (result == 0) {
|
||||||
|
m.sendCredentialsIfNeeded(RR,RR->node->now(),a,_config,(const Capability *)0);
|
||||||
|
RR->mc->addCredential(com,true);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::destroy()
|
void Network::destroy()
|
||||||
@ -1245,7 +1252,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup)
|
void Network::_sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup)
|
||||||
{
|
{
|
||||||
// Assumes _lock is locked
|
// Assumes _lock is locked
|
||||||
const uint64_t now = RR->node->now();
|
const uint64_t now = RR->node->now();
|
||||||
@ -1263,7 +1270,7 @@ void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup)
|
|||||||
// them our COM so that MULTICAST_GATHER can be authenticated properly.
|
// them our COM so that MULTICAST_GATHER can be authenticated properly.
|
||||||
const std::vector<Address> upstreams(RR->topology->upstreamAddresses());
|
const std::vector<Address> upstreams(RR->topology->upstreamAddresses());
|
||||||
for(std::vector<Address>::const_iterator a(upstreams.begin());a!=upstreams.end();++a) {
|
for(std::vector<Address>::const_iterator a(upstreams.begin());a!=upstreams.end();++a) {
|
||||||
if ((_config.isPrivate())&&(_config.com)) {
|
if (_config.com) {
|
||||||
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
||||||
_config.com.serialize(outp);
|
_config.com.serialize(outp);
|
||||||
outp.append((uint8_t)0x00);
|
outp.append((uint8_t)0x00);
|
||||||
@ -1272,12 +1279,17 @@ void Network::_pushStateToMembers(const MulticastGroup *const newMulticastGroup)
|
|||||||
_announceMulticastGroupsTo(*a,groups);
|
_announceMulticastGroupsTo(*a,groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Announce to controller, which does not need our COM since it obviously
|
// Also announce to controller, and send COM to simplify and generalize behavior even though in theory it does not need it
|
||||||
// knows if we are a member. Of course if we already did or are going to
|
|
||||||
// below then we can skip it here.
|
|
||||||
const Address c(controller());
|
const Address c(controller());
|
||||||
if ( (std::find(upstreams.begin(),upstreams.end(),c) == upstreams.end()) && (!_memberships.contains(c)) )
|
if ( (std::find(upstreams.begin(),upstreams.end(),c) == upstreams.end()) && (!_memberships.contains(c)) ) {
|
||||||
|
if (_config.com) {
|
||||||
|
Packet outp(c,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
|
||||||
|
_config.com.serialize(outp);
|
||||||
|
outp.append((uint8_t)0x00);
|
||||||
|
RR->sw->send(outp,true);
|
||||||
|
}
|
||||||
_announceMulticastGroupsTo(c,groups);
|
_announceMulticastGroupsTo(c,groups);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that all "network anchors" have Membership records so we will
|
// Make sure that all "network anchors" have Membership records so we will
|
||||||
|
@ -260,7 +260,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Check whether this peer is allowed to provide multicast info for this network
|
* Check whether this peer is allowed to provide multicast info for this network
|
||||||
*/
|
*/
|
||||||
bool gateMulticastGather(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId);
|
bool gateMulticastGatherReply(const SharedPtr<Peer> &peer,const Packet::Verb verb,const uint64_t packetId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param peer Peer to check
|
* @param peer Peer to check
|
||||||
@ -276,10 +276,10 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Push state to members such as multicast group memberships and latest COM (if needed)
|
* Push state to members such as multicast group memberships and latest COM (if needed)
|
||||||
*/
|
*/
|
||||||
inline void pushStateToMembers()
|
inline void sendUpdatesToMembers()
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_lock);
|
Mutex::Lock _l(_lock);
|
||||||
_pushStateToMembers((const MulticastGroup *)0);
|
_sendUpdatesToMembers((const MulticastGroup *)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -332,9 +332,7 @@ public:
|
|||||||
{
|
{
|
||||||
Mutex::Lock _l(_lock);
|
Mutex::Lock _l(_lock);
|
||||||
const Address *const br = _remoteBridgeRoutes.get(mac);
|
const Address *const br = _remoteBridgeRoutes.get(mac);
|
||||||
if (br)
|
return ((br) ? *br : Address());
|
||||||
return *br;
|
|
||||||
return Address();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -357,13 +355,7 @@ public:
|
|||||||
* @param com Certificate of membership
|
* @param com Certificate of membership
|
||||||
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
|
* @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
|
||||||
*/
|
*/
|
||||||
inline int addCredential(const CertificateOfMembership &com)
|
int addCredential(const CertificateOfMembership &com);
|
||||||
{
|
|
||||||
if (com.networkId() != _id)
|
|
||||||
return -1;
|
|
||||||
Mutex::Lock _l(_lock);
|
|
||||||
return _membership(com.issuedTo()).addCredential(RR,com);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param cap Capability
|
* @param cap Capability
|
||||||
@ -418,7 +410,7 @@ private:
|
|||||||
ZT_VirtualNetworkStatus _status() const;
|
ZT_VirtualNetworkStatus _status() const;
|
||||||
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
|
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
|
||||||
bool _gate(const SharedPtr<Peer> &peer);
|
bool _gate(const SharedPtr<Peer> &peer);
|
||||||
void _pushStateToMembers(const MulticastGroup *const newMulticastGroup);
|
void _sendUpdatesToMembers(const MulticastGroup *const newMulticastGroup);
|
||||||
void _announceMulticastGroupsTo(const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
|
void _announceMulticastGroupsTo(const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
|
||||||
std::vector<MulticastGroup> _allMulticastGroups() const;
|
std::vector<MulticastGroup> _allMulticastGroups() const;
|
||||||
Membership &_membership(const Address &a);
|
Membership &_membership(const Address &a);
|
||||||
|
@ -266,7 +266,7 @@ ZT_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextB
|
|||||||
for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
|
for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
|
||||||
if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig()))
|
if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!n->second->hasConfig()))
|
||||||
needConfig.push_back(n->second);
|
needConfig.push_back(n->second);
|
||||||
n->second->pushStateToMembers();
|
n->second->sendUpdatesToMembers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(std::vector< SharedPtr<Network> >::const_iterator n(needConfig.begin());n!=needConfig.end();++n)
|
for(std::vector< SharedPtr<Network> >::const_iterator n(needConfig.begin());n!=needConfig.end();++n)
|
||||||
|
@ -104,6 +104,7 @@ public:
|
|||||||
Path() :
|
Path() :
|
||||||
_lastOut(0),
|
_lastOut(0),
|
||||||
_lastIn(0),
|
_lastIn(0),
|
||||||
|
_lastHello(0),
|
||||||
_addr(),
|
_addr(),
|
||||||
_localAddress(),
|
_localAddress(),
|
||||||
_ipScope(InetAddress::IP_SCOPE_NONE)
|
_ipScope(InetAddress::IP_SCOPE_NONE)
|
||||||
@ -113,6 +114,7 @@ public:
|
|||||||
Path(const InetAddress &localAddress,const InetAddress &addr) :
|
Path(const InetAddress &localAddress,const InetAddress &addr) :
|
||||||
_lastOut(0),
|
_lastOut(0),
|
||||||
_lastIn(0),
|
_lastIn(0),
|
||||||
|
_lastHello(0),
|
||||||
_addr(addr),
|
_addr(addr),
|
||||||
_localAddress(localAddress),
|
_localAddress(localAddress),
|
||||||
_ipScope(addr.ipScope())
|
_ipScope(addr.ipScope())
|
||||||
@ -229,9 +231,22 @@ public:
|
|||||||
*/
|
*/
|
||||||
inline uint64_t lastIn() const { return _lastIn; }
|
inline uint64_t lastIn() const { return _lastIn; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if we should allow HELLO via this path
|
||||||
|
*/
|
||||||
|
inline bool rateGateHello(const uint64_t now)
|
||||||
|
{
|
||||||
|
if ((now - _lastHello) >= ZT_PATH_HELLO_RATE_LIMIT) {
|
||||||
|
_lastHello = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t _lastOut;
|
uint64_t _lastOut;
|
||||||
uint64_t _lastIn;
|
uint64_t _lastIn;
|
||||||
|
uint64_t _lastHello;
|
||||||
InetAddress _addr;
|
InetAddress _addr;
|
||||||
InetAddress _localAddress;
|
InetAddress _localAddress;
|
||||||
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
|
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
|
||||||
|
160
node/Peer.cpp
160
node/Peer.cpp
@ -47,6 +47,9 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
|
|||||||
_lastMulticastFrame(0),
|
_lastMulticastFrame(0),
|
||||||
_lastDirectPathPushSent(0),
|
_lastDirectPathPushSent(0),
|
||||||
_lastDirectPathPushReceive(0),
|
_lastDirectPathPushReceive(0),
|
||||||
|
_lastCredentialRequestSent(0),
|
||||||
|
_lastWhoisRequestReceived(0),
|
||||||
|
_lastEchoRequestReceived(0),
|
||||||
RR(renv),
|
RR(renv),
|
||||||
_remoteClusterOptimal4(0),
|
_remoteClusterOptimal4(0),
|
||||||
_vProto(0),
|
_vProto(0),
|
||||||
@ -194,7 +197,80 @@ void Peer::received(
|
|||||||
}
|
}
|
||||||
} else if (trustEstablished) {
|
} else if (trustEstablished) {
|
||||||
// Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership)
|
// Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership)
|
||||||
_pushDirectPaths(path,now);
|
#ifdef ZT_ENABLE_CLUSTER
|
||||||
|
// Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection
|
||||||
|
const bool haveCluster = (RR->cluster);
|
||||||
|
#else
|
||||||
|
const bool haveCluster = false;
|
||||||
|
#endif
|
||||||
|
if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) {
|
||||||
|
_lastDirectPathPushSent = now;
|
||||||
|
|
||||||
|
std::vector<InetAddress> pathsToPush;
|
||||||
|
|
||||||
|
std::vector<InetAddress> dps(RR->node->directPaths());
|
||||||
|
for(std::vector<InetAddress>::const_iterator i(dps.begin());i!=dps.end();++i)
|
||||||
|
pathsToPush.push_back(*i);
|
||||||
|
|
||||||
|
std::vector<InetAddress> sym(RR->sa->getSymmetricNatPredictions());
|
||||||
|
for(unsigned long i=0,added=0;i<sym.size();++i) {
|
||||||
|
InetAddress tmp(sym[(unsigned long)RR->node->prng() % sym.size()]);
|
||||||
|
if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) {
|
||||||
|
pathsToPush.push_back(tmp);
|
||||||
|
if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathsToPush.size() > 0) {
|
||||||
|
#ifdef ZT_TRACE
|
||||||
|
std::string ps;
|
||||||
|
for(std::vector<InetAddress>::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) {
|
||||||
|
if (ps.length() > 0)
|
||||||
|
ps.push_back(',');
|
||||||
|
ps.append(p->toString());
|
||||||
|
}
|
||||||
|
TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
|
||||||
|
while (p != pathsToPush.end()) {
|
||||||
|
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
|
||||||
|
outp.addSize(2); // leave room for count
|
||||||
|
|
||||||
|
unsigned int count = 0;
|
||||||
|
while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) {
|
||||||
|
uint8_t addressType = 4;
|
||||||
|
switch(p->ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
addressType = 6;
|
||||||
|
break;
|
||||||
|
default: // we currently only push IP addresses
|
||||||
|
++p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
outp.append((uint8_t)0); // no flags
|
||||||
|
outp.append((uint16_t)0); // no extensions
|
||||||
|
outp.append(addressType);
|
||||||
|
outp.append((uint8_t)((addressType == 4) ? 6 : 18));
|
||||||
|
outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16));
|
||||||
|
outp.append((uint16_t)p->port());
|
||||||
|
|
||||||
|
++count;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
|
||||||
|
outp.armor(_key,true);
|
||||||
|
path->send(RR,outp.data(),outp.size(),now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,86 +444,4 @@ void Peer::getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6)
|
|||||||
v6 = _paths[bestp6].path->address();
|
v6 = _paths[bestp6].path->address();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Peer::_pushDirectPaths(const SharedPtr<Path> &path,uint64_t now)
|
|
||||||
{
|
|
||||||
#ifdef ZT_ENABLE_CLUSTER
|
|
||||||
// Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection
|
|
||||||
if (RR->cluster)
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((now - _lastDirectPathPushSent) < ZT_DIRECT_PATH_PUSH_INTERVAL)
|
|
||||||
return false;
|
|
||||||
else _lastDirectPathPushSent = now;
|
|
||||||
|
|
||||||
std::vector<InetAddress> pathsToPush;
|
|
||||||
|
|
||||||
std::vector<InetAddress> dps(RR->node->directPaths());
|
|
||||||
for(std::vector<InetAddress>::const_iterator i(dps.begin());i!=dps.end();++i)
|
|
||||||
pathsToPush.push_back(*i);
|
|
||||||
|
|
||||||
std::vector<InetAddress> sym(RR->sa->getSymmetricNatPredictions());
|
|
||||||
for(unsigned long i=0,added=0;i<sym.size();++i) {
|
|
||||||
InetAddress tmp(sym[(unsigned long)RR->node->prng() % sym.size()]);
|
|
||||||
if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) {
|
|
||||||
pathsToPush.push_back(tmp);
|
|
||||||
if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pathsToPush.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
#ifdef ZT_TRACE
|
|
||||||
{
|
|
||||||
std::string ps;
|
|
||||||
for(std::vector<InetAddress>::const_iterator p(pathsToPush.begin());p!=pathsToPush.end();++p) {
|
|
||||||
if (ps.length() > 0)
|
|
||||||
ps.push_back(',');
|
|
||||||
ps.append(p->toString());
|
|
||||||
}
|
|
||||||
TRACE("pushing %u direct paths to %s: %s",(unsigned int)pathsToPush.size(),_id.address().toString().c_str(),ps.c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
|
|
||||||
while (p != pathsToPush.end()) {
|
|
||||||
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
|
|
||||||
outp.addSize(2); // leave room for count
|
|
||||||
|
|
||||||
unsigned int count = 0;
|
|
||||||
while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) {
|
|
||||||
uint8_t addressType = 4;
|
|
||||||
switch(p->ss_family) {
|
|
||||||
case AF_INET:
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
addressType = 6;
|
|
||||||
break;
|
|
||||||
default: // we currently only push IP addresses
|
|
||||||
++p;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
outp.append((uint8_t)0); // no flags
|
|
||||||
outp.append((uint16_t)0); // no extensions
|
|
||||||
outp.append(addressType);
|
|
||||||
outp.append((uint8_t)((addressType == 4) ? 6 : 18));
|
|
||||||
outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16));
|
|
||||||
outp.append((uint16_t)p->port());
|
|
||||||
|
|
||||||
++count;
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count) {
|
|
||||||
outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
|
|
||||||
outp.armor(_key,true);
|
|
||||||
path->send(RR,outp.data(),outp.size(),now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
@ -348,7 +348,7 @@ public:
|
|||||||
* @param now Current time
|
* @param now Current time
|
||||||
* @return True if we should respond
|
* @return True if we should respond
|
||||||
*/
|
*/
|
||||||
inline bool shouldRespondToDirectPathPush(const uint64_t now)
|
inline bool rateGatePushDirectPaths(const uint64_t now)
|
||||||
{
|
{
|
||||||
if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME)
|
if ((now - _lastDirectPathPushReceive) <= ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME)
|
||||||
++_directPathPushCutoffCount;
|
++_directPathPushCutoffCount;
|
||||||
@ -357,6 +357,42 @@ public:
|
|||||||
return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT);
|
return (_directPathPushCutoffCount < ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rate limit gate for sending of ERROR_NEED_MEMBERSHIP_CERTIFICATE
|
||||||
|
*/
|
||||||
|
inline bool rateGateRequestCredentials(const uint64_t now)
|
||||||
|
{
|
||||||
|
if ((now - _lastCredentialRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) {
|
||||||
|
_lastCredentialRequestSent = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rate limit gate for inbound WHOIS requests
|
||||||
|
*/
|
||||||
|
inline bool rateGateInboundWhoisRequest(const uint64_t now)
|
||||||
|
{
|
||||||
|
if ((now - _lastWhoisRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) {
|
||||||
|
_lastWhoisRequestReceived = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rate limit gate for inbound ECHO requests
|
||||||
|
*/
|
||||||
|
inline bool rateGateEchoRequest(const uint64_t now)
|
||||||
|
{
|
||||||
|
if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) {
|
||||||
|
_lastEchoRequestReceived = now;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a common set of addresses by which two peers can link, if any
|
* Find a common set of addresses by which two peers can link, if any
|
||||||
*
|
*
|
||||||
@ -378,8 +414,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _pushDirectPaths(const SharedPtr<Path> &path,uint64_t now);
|
|
||||||
|
|
||||||
inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const
|
inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const
|
||||||
{
|
{
|
||||||
uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK));
|
uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK));
|
||||||
@ -415,6 +449,9 @@ private:
|
|||||||
uint64_t _lastMulticastFrame;
|
uint64_t _lastMulticastFrame;
|
||||||
uint64_t _lastDirectPathPushSent;
|
uint64_t _lastDirectPathPushSent;
|
||||||
uint64_t _lastDirectPathPushReceive;
|
uint64_t _lastDirectPathPushReceive;
|
||||||
|
uint64_t _lastCredentialRequestSent;
|
||||||
|
uint64_t _lastWhoisRequestReceived;
|
||||||
|
uint64_t _lastEchoRequestReceived;
|
||||||
const RuntimeEnvironment *RR;
|
const RuntimeEnvironment *RR;
|
||||||
uint32_t _remoteClusterOptimal4;
|
uint32_t _remoteClusterOptimal4;
|
||||||
uint16_t _vProto;
|
uint16_t _vProto;
|
||||||
|
Loading…
Reference in New Issue
Block a user