(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID));
}
} catch ( ... ) {
- TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped EXT_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -691,11 +621,6 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer)
{
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();
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_ECHO);
@@ -703,11 +628,10 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr
if (size() > ZT_PACKET_IDX_PAYLOAD)
outp.append(reinterpret_cast(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
-
- peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP);
} 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(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -717,145 +641,34 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared
try {
const uint64_t now = RR->node->now();
- uint64_t authOnNetwork[256]; // cache for approved network IDs
- unsigned int authOnNetworkCount = 0;
- SharedPtr network;
- bool trustEstablished = false;
-
// Iterate through 18-byte network,MAC,ADI tuples
for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr);
-
- bool auth = false;
- for(unsigned int i=0;iid() != nwid))
- network = RR->node->network(nwid);
- const bool authOnNet = ((network)&&(network->gate(peer)));
- if (!authOnNet)
- _sendErrorNeedCredentials(RR,peer,nwid);
- trustEstablished |= authOnNet;
- if (authOnNet||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(ptr + 14));
- RR->mc->add(now,nwid,group,peer->address());
- }
+ const MulticastGroup group(MAC(field(ptr + 8,6),6),at(ptr + 14));
+ RR->mc->add(now,nwid,group,peer->address());
}
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished);
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
-bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer)
+bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr &peer)
{
try {
- if (!peer->rateGateCredentialsReceived(RR->node->now())) {
- TRACE("dropped NETWORK_CREDENTIALS from %s(%s): rate limit circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str());
- return true;
- }
-
CertificateOfMembership com;
- Capability cap;
- Tag tag;
- Revocation revocation;
- bool trustEstablished = false;
- unsigned int p = ZT_PACKET_IDX_PAYLOAD;
- while ((p < size())&&((*this)[p])) {
- p += com.deserialize(*this,p);
- if (com) {
- const SharedPtr network(RR->node->network(com.networkId()));
- if (network) {
- switch (network->addCredential(com)) {
- case Membership::ADD_REJECTED:
- break;
- case Membership::ADD_ACCEPTED_NEW:
- case Membership::ADD_ACCEPTED_REDUNDANT:
- trustEstablished = true;
- break;
- case Membership::ADD_DEFERRED_FOR_WHOIS:
- return false;
- }
- } else RR->mc->addCredential(com,false);
- }
- }
- ++p; // skip trailing 0 after COMs if present
-
- if (p < size()) { // older ZeroTier versions do not send capabilities, tags, or revocations
- const unsigned int numCapabilities = at(p); p += 2;
- for(unsigned int i=0;i network(RR->node->network(cap.networkId()));
- if (network) {
- switch (network->addCredential(cap)) {
- case Membership::ADD_REJECTED:
- break;
- case Membership::ADD_ACCEPTED_NEW:
- case Membership::ADD_ACCEPTED_REDUNDANT:
- trustEstablished = true;
- break;
- case Membership::ADD_DEFERRED_FOR_WHOIS:
- return false;
- }
- }
- }
-
- const unsigned int numTags = at(p); p += 2;
- for(unsigned int i=0;i network(RR->node->network(tag.networkId()));
- if (network) {
- switch (network->addCredential(tag)) {
- case Membership::ADD_REJECTED:
- break;
- case Membership::ADD_ACCEPTED_NEW:
- case Membership::ADD_ACCEPTED_REDUNDANT:
- trustEstablished = true;
- break;
- case Membership::ADD_DEFERRED_FOR_WHOIS:
- return false;
- }
- }
- }
-
- const unsigned int numRevocations = at(p); p += 2;
- for(unsigned int i=0;i network(RR->node->network(revocation.networkId()));
- if (network) {
- switch(network->addCredential(peer->address(),revocation)) {
- case Membership::ADD_REJECTED:
- break;
- case Membership::ADD_ACCEPTED_NEW:
- case Membership::ADD_ACCEPTED_REDUNDANT:
- trustEstablished = true;
- break;
- case Membership::ADD_DEFERRED_FOR_WHOIS:
- return false;
- }
- }
- }
+ unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
+ while (ptr < size()) {
+ ptr += com.deserialize(*this,ptr);
+ peer->validateAndSetNetworkMembershipCertificate(com.networkId(),com);
}
- peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished);
- } catch (std::exception &exc) {
- TRACE("dropped NETWORK_CREDENTIALS from %s(%s): %s",source().toString().c_str(),_path->address().toString().c_str(),exc.what());
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped NETWORK_CREDENTIALS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -864,134 +677,117 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
{
try {
const uint64_t nwid = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID);
- const unsigned int hopCount = hops();
- const uint64_t requestPacketId = packetId();
- bool trustEstablished = false;
+
+ const unsigned int metaDataLength = at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN);
+ const uint8_t *metaDataBytes = (const uint8_t *)field(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT,metaDataLength);
+
+ NetworkConfigRequestMetaData metaData;
+ bool haveNewStyleMetaData = false;
+ for(unsigned int i=0;i md(metaDataBytes,metaDataLength);
+ metaData.deserialize(md,0); // the meta-data deserializer automatically skips old-style meta-data
+ } else {
+#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
+ const Dictionary oldStyleMetaData((const char *)metaDataBytes,metaDataLength);
+ metaData.majorVersion = (unsigned int)oldStyleMetaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0);
+ metaData.minorVersion = (unsigned int)oldStyleMetaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0);
+ metaData.revision = (unsigned int)oldStyleMetaData.getHexUInt(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0);
+#endif
+ }
+
+ //const uint64_t haveRevision = ((ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength + 8) <= size()) ? at(ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT + metaDataLength) : 0ULL;
+
+ const unsigned int h = hops();
+ const uint64_t pid = packetId();
+ peer->received(_localAddress,_remoteAddress,h,pid,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP);
if (RR->localNetworkController) {
- const unsigned int metaDataLength = at(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 metaData(metaDataBytes,metaDataLength);
+ Buffer<8194> netconf;
+ switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,netconf)) {
- NetworkConfig *netconf = new NetworkConfig();
- try {
- switch(RR->localNetworkController->doNetworkConfigRequest((hopCount > 0) ? InetAddress() : _path->address(),RR->identity,peer->identity(),nwid,metaData,*netconf)) {
+ case NetworkController::NETCONF_QUERY_OK: {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
+ outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append(pid);
+ outp.append(nwid);
+ outp.append((uint16_t)netconf.size());
+ outp.append(netconf.data(),(unsigned int)netconf.size());
+ outp.compress();
+ outp.armor(peer->key(),true);
+ if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { // sanity check
+ //TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length());
+ } else {
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ }
+ } break;
- case NetworkController::NETCONF_QUERY_OK: {
- trustEstablished = true;
- Dictionary *dconf = new Dictionary();
- try {
- if (netconf->toDictionary(*dconf,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6)) {
- uint64_t configUpdateId = RR->node->prng();
- if (!configUpdateId) ++configUpdateId;
- const unsigned int totalSize = dconf->sizeBytes();
- unsigned int chunkIndex = 0;
- while (chunkIndex < totalSize) {
- const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 256)));
- Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
- outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
- outp.append(requestPacketId);
+ case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append(pid);
+ outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
+ outp.append(nwid);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } break;
- const unsigned int sigStart = outp.size();
- outp.append(nwid);
- outp.append((uint16_t)chunkLen);
- outp.append((const void *)(dconf->data() + chunkIndex),chunkLen);
+ case NetworkController::NETCONF_QUERY_ACCESS_DENIED: {
+ Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
+ outp.append(pid);
+ outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_);
+ outp.append(nwid);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+ } break;
- outp.append((uint8_t)0); // no flags
- outp.append((uint64_t)configUpdateId);
- outp.append((uint32_t)totalSize);
- outp.append((uint32_t)chunkIndex);
+ case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR:
+ // TRACE("NETWORK_CONFIG_REQUEST failed: internal error: %s",netconf.get("error","(unknown)").c_str());
+ break;
- C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + sigStart,outp.size() - sigStart));
- outp.append((uint8_t)1);
- outp.append((uint16_t)ZT_C25519_SIGNATURE_LEN);
- outp.append(sig.data,ZT_C25519_SIGNATURE_LEN);
+ case NetworkController::NETCONF_QUERY_IGNORE:
+ break;
- outp.compress();
- RR->sw->send(outp,true);
- chunkIndex += chunkLen;
- }
- }
- delete dconf;
- } catch ( ... ) {
- delete dconf;
- throw;
- }
- } break;
+ default:
+ TRACE("NETWORK_CONFIG_REQUEST failed: invalid return value from NetworkController::doNetworkConfigRequest()");
+ break;
- case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: {
- Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
- outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
- outp.append(requestPacketId);
- outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
- outp.append(nwid);
- outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
- } break;
-
- case NetworkController::NETCONF_QUERY_ACCESS_DENIED: {
- Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
- outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
- outp.append(requestPacketId);
- outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_);
- outp.append(nwid);
- outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
- } break;
-
- case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR:
- break;
- case NetworkController::NETCONF_QUERY_IGNORE:
- break;
- default:
- TRACE("NETWORK_CONFIG_REQUEST failed: invalid return value from NetworkController::doNetworkConfigRequest()");
- break;
- }
- delete netconf;
- } catch ( ... ) {
- delete netconf;
- throw;
}
} else {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST);
- outp.append(requestPacketId);
+ outp.append(pid);
outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
outp.append(nwid);
outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
-
- peer->received(_path,hopCount,requestPacketId,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,trustEstablished);
- } catch (std::exception &exc) {
- 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());
} catch ( ... ) {
- fprintf(stderr,"WARNING: network config request failed with exception: unknown exception" ZT_EOL_S);
- TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unknown exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
-bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer)
+bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer)
{
try {
- const SharedPtr network(RR->node->network(at(ZT_PACKET_IDX_PAYLOAD)));
- if (network) {
- const uint64_t configUpdateId = network->handleConfigChunk(*this,ZT_PACKET_IDX_PAYLOAD);
- if (configUpdateId) {
- Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
- outp.append((uint8_t)Packet::VERB_ECHO);
- outp.append((uint64_t)packetId());
- outp.append((uint64_t)network->id());
- outp.append((uint64_t)configUpdateId);
- outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
- }
+ unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
+ while ((ptr + 8) <= size()) {
+ uint64_t nwid = at(ptr);
+ SharedPtr nw(RR->node->network(nwid));
+ if ((nw)&&(peer->address() == nw->controller()))
+ nw->requestConfiguration();
+ ptr += 8;
}
- peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false);
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -1000,32 +796,12 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar
{
try {
const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID);
- const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS];
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI));
const unsigned int gatherLimit = at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT);
- //TRACE("<address().toString().c_str(),gatherLimit,nwid,mg.toString().c_str());
+ //TRACE("< network(RR->node->network(nwid));
-
- if ((flags & 0x01) != 0) {
- try {
- CertificateOfMembership com;
- com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM);
- if (com) {
- if (network)
- network->addCredential(com);
- else RR->mc->addCredential(com,false);
- }
- } catch ( ... ) {
- TRACE("MULTICAST_GATHER from %s(%s): discarded invalid COM",peer->address().toString().c_str(),_path->address().toString().c_str());
- }
- }
-
- const bool trustEstablished = ((network)&&(network->gate(peer)));
- if (!trustEstablished)
- _sendErrorNeedCredentials(RR,peer,nwid);
- if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) {
+ if (gatherLimit) {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER);
outp.append(packetId());
@@ -1033,21 +809,20 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar
mg.mac().appendTo(outp);
outp.append((uint32_t)mg.adi());
const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit);
- if (gatheredLocally > 0) {
+ if (gatheredLocally) {
outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
- // If we are a member of a cluster, distribute this GATHER across it
#ifdef ZT_ENABLE_CLUSTER
if ((RR->cluster)&&(gatheredLocally < gatherLimit))
RR->cluster->sendDistributedQuery(*this);
#endif
}
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished);
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -1064,23 +839,16 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
unsigned int offset = 0;
if ((flags & 0x01) != 0) {
- // This is deprecated but may still be sent by old peers
CertificateOfMembership com;
offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM);
- if (com)
- network->addCredential(com);
+ peer->validateAndSetNetworkMembershipCertificate(nwid,com);
}
- if (!network->gate(peer)) {
- TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id());
- _sendErrorNeedCredentials(RR,peer,nwid);
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false);
- return true;
- }
-
- if (network->config().multicastLimit == 0) {
- TRACE("dropped MULTICAST_FRAME from %s(%s): network %.16llx does not allow multicast",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id());
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false);
+ // Check membership after we've read any included COM, since
+ // that cert might be what we needed.
+ if (!network->isAllowed(peer)) {
+ TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)network->id());
+ _sendErrorNeedCertificate(RR,peer,network->id());
return true;
}
@@ -1100,36 +868,30 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
const MulticastGroup to(MAC(field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_MAC,6),6),at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_DEST_ADI));
const unsigned int etherType = at(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_ETHERTYPE);
- const unsigned int frameLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME);
+ const unsigned int payloadLen = size() - (offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME);
- //TRACE("<address().toString().c_str(),flags,frameLen);
+ //TRACE("<address().toString().c_str(),flags,payloadLen);
- if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) {
+ if ((payloadLen > 0)&&(payloadLen <= ZT_IF_MTU)) {
if (!to.mac().isMulticast()) {
- TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str());
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
+ TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
return true;
}
if ((!from)||(from.isMulticast())||(from == network->mac())) {
- TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str());
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
+ TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: invalid source MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
return true;
}
- if (from != MAC(peer->address(),nwid)) {
+ if (from != MAC(peer->address(),network->id())) {
if (network->config().permitsBridging(peer->address())) {
network->learnBridgeRoute(from,peer->address());
} else {
- TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str(),network->id());
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
+ TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id());
return true;
}
}
- const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen);
- if (network->filterIncomingPacket(peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) {
- RR->node->putFrame(nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen);
- }
+ RR->node->putFrame(network->id(),network->userPtr(),from,to.mac(),etherType,0,field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,payloadLen),payloadLen);
}
if (gatherLimit) {
@@ -1142,17 +904,14 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
outp.append((unsigned char)0x02); // flag 0x02 = contains gather results
if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) {
outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
}
+ } // else ignore -- not a member of this network
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true);
- } else {
- _sendErrorNeedCredentials(RR,peer,nwid);
- peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false);
- }
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -1163,9 +922,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
const uint64_t now = RR->node->now();
// First, subject this to a rate limit
- if (!peer->rateGatePushDirectPaths(now)) {
- 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);
+ if (!peer->shouldRespondToDirectPathPush(now)) {
+ TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
@@ -1191,15 +949,15 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
bool redundant = false;
if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) {
- peer->setClusterOptimal(a);
+ peer->setClusterOptimalPathForAddressFamily(a);
} else {
redundant = peer->hasActivePathTo(now,a);
}
- if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) {
+ if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) {
if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
- peer->attemptToContactAt(InetAddress(),a,now);
+ peer->sendHELLO(InetAddress(),a,now);
} else {
TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
}
@@ -1210,15 +968,15 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
bool redundant = false;
if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) {
- peer->setClusterOptimal(a);
+ peer->setClusterOptimalPathForAddressFamily(a);
} else {
redundant = peer->hasActivePathTo(now,a);
}
- if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_path->localAddress(),a)) ) {
+ if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(_localAddress,a)) ) {
if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
- peer->attemptToContactAt(InetAddress(),a,now);
+ peer->sendHELLO(InetAddress(),a,now);
} else {
TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
}
@@ -1228,9 +986,9 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
ptr += addrLen;
}
- peer->received(_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false);
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -1252,7 +1010,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
// Tracks total length of variable length fields, initialized to originator credential length below
unsigned int vlf;
- // Originator credentials -- right now only a network ID for which the originator is controller or is authorized by controller is allowed
+ // Originator credentials
const unsigned int originatorCredentialLength = vlf = at(ZT_PACKET_IDX_PAYLOAD + 23);
uint64_t originatorCredentialNetworkId = 0;
if (originatorCredentialLength >= 1) {
@@ -1271,8 +1029,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
// Verify signature -- only tests signed by their originators are allowed
const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 27 + vlf);
if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) {
- TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str());
- peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
+ TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str());
return true;
}
vlf += signatureLength;
@@ -1281,24 +1038,46 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
// into the one we send along to next hops.
const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf;
- // Add length of second "additional fields" section.
- vlf += at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
-
- uint64_t reportFlags = 0;
+ // Get previous hop's credential, if any
+ const unsigned int previousHopCredentialLength = at(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
+ CertificateOfMembership previousHopCom;
+ if (previousHopCredentialLength >= 1) {
+ switch((*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf]) {
+ case 0x01: { // network certificate of membership for previous hop
+ const unsigned int phcl = previousHopCom.deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 32 + vlf);
+ if (phcl != (previousHopCredentialLength - 1)) {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): previous hop COM invalid (%u != %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),phcl,(previousHopCredentialLength - 1));
+ return true;
+ }
+ } break;
+ default: break;
+ }
+ }
+ vlf += previousHopCredentialLength;
// Check credentials (signature already verified)
+ NetworkConfig originatorCredentialNetworkConfig;
if (originatorCredentialNetworkId) {
- SharedPtr network(RR->node->network(originatorCredentialNetworkId));
- if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) {
- TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
- peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
+ if (Network::controllerFor(originatorCredentialNetworkId) == originatorAddress) {
+ SharedPtr nw(RR->node->network(originatorCredentialNetworkId));
+ if ((nw)&&(nw->hasConfig())) {
+ originatorCredentialNetworkConfig = nw->config();
+ if ( ( (originatorCredentialNetworkConfig.isPublic()) || (peer->address() == originatorAddress) || ((originatorCredentialNetworkConfig.com)&&(previousHopCom)&&(originatorCredentialNetworkConfig.com.agreesWith(previousHopCom))) ) ) {
+ TRACE("CIRCUIT_TEST %.16llx received from hop %s(%s) and originator %s with valid network ID credential %.16llx (verified from originator and next hop)",testId,source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
+ } else {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and previous hop %s did not supply a valid COM",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId,peer->address().toString().c_str());
+ return true;
+ }
+ } else {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
+ return true;
+ }
+ } else {
+ TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID as credential, is not controller for %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
return true;
}
- if (network->gate(peer))
- reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH;
} else {
- TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str());
- peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
+ TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str());
return true;
}
@@ -1316,9 +1095,9 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
remainingHopsPtr += ZT_ADDRESS_LENGTH;
SharedPtr nhp(RR->topology->getPeer(nextHop[h]));
if (nhp) {
- SharedPtr nhbp(nhp->getBestPath(now,false));
- if ((nhbp)&&(nhbp->alive(now)))
- nextHopBestPathAddress[h] = nhbp->address();
+ Path *const rp = nhp->getBestPath(now);
+ if (rp)
+ nextHopBestPathAddress[h] = rp->address();
}
}
}
@@ -1337,26 +1116,32 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED);
outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED);
outp.append((uint16_t)0); // error code, currently unused
- outp.append((uint64_t)reportFlags);
+ outp.append((uint64_t)0); // flags, currently unused
outp.append((uint64_t)packetId());
peer->address().appendTo(outp);
outp.append((uint8_t)hops());
- _path->localAddress().serialize(outp);
- _path->address().serialize(outp);
+ _localAddress.serialize(outp);
+ _remoteAddress.serialize(outp);
outp.append((uint16_t)0); // no additional fields
outp.append((uint8_t)breadth);
for(unsigned int h=0;hsw->send(outp,true);
+ RR->sw->send(outp,true,0);
}
// If there are next hops, forward the test along through the graph
if (breadth > 0) {
Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST);
outp.append(field(ZT_PACKET_IDX_PAYLOAD,lengthOfSignedPortionAndSignature),lengthOfSignedPortionAndSignature);
- outp.append((uint16_t)0); // no additional fields
+ const unsigned int previousHopCredentialPos = outp.size();
+ outp.append((uint16_t)0); // no previous hop credentials: default
+ if ((originatorCredentialNetworkConfig)&&(!originatorCredentialNetworkConfig.isPublic())&&(originatorCredentialNetworkConfig.com)) {
+ outp.append((uint8_t)0x01); // COM
+ originatorCredentialNetworkConfig.com.serialize(outp);
+ outp.setAt(previousHopCredentialPos,(uint16_t)(outp.size() - (previousHopCredentialPos + 2)));
+ }
if (remainingHopsPtr < size())
outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr);
@@ -1364,14 +1149,14 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid
outp.newInitializationVector();
outp.setDestination(nextHop[h]);
- RR->sw->send(outp,true);
+ RR->sw->send(outp,true,originatorCredentialNetworkId);
}
}
}
- peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
+ peer->received(_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP);
} catch ( ... ) {
- TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -1386,6 +1171,7 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S
report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
report.testId = at(ZT_PACKET_IDX_PAYLOAD + 8);
report.timestamp = at(ZT_PACKET_IDX_PAYLOAD);
+ report.remoteTimestamp = at(ZT_PACKET_IDX_PAYLOAD + 16);
report.sourcePacketId = at(ZT_PACKET_IDX_PAYLOAD + 44);
report.flags = at(ZT_PACKET_IDX_PAYLOAD + 36);
report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58
@@ -1413,10 +1199,8 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S
}
RR->node->postCircuitTestReport(&report);
-
- peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false);
} catch ( ... ) {
- TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
@@ -1424,20 +1208,8 @@ bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const S
bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &peer)
{
try {
- // If this were allowed from anyone, it would itself be a DOS vector. Right
- // now we only allow it from roots and controllers of networks you have joined.
- bool allowed = RR->topology->isUpstream(peer->identity());
- if (!allowed) {
- std::vector< SharedPtr > allNetworks(RR->node->allNetworks());
- for(std::vector< SharedPtr >::const_iterator n(allNetworks.begin());n!=allNetworks.end();++n) {
- if (peer->address() == (*n)->controller()) {
- allowed = true;
- break;
- }
- }
- }
-
- if (allowed) {
+ // Right now this is only allowed from root servers -- may be allowed from controllers and relays later.
+ if (RR->topology->isRoot(peer->identity())) {
const uint64_t pid = packetId();
const unsigned int difficulty = (*this)[ZT_PACKET_IDX_PAYLOAD + 1];
const unsigned int challengeLength = at(ZT_PACKET_IDX_PAYLOAD + 2);
@@ -1459,46 +1231,32 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const
outp.append((uint16_t)sizeof(result));
outp.append(result,sizeof(result));
outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
} else {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR);
outp.append((unsigned char)Packet::VERB_REQUEST_PROOF_OF_WORK);
outp.append(pid);
outp.append((unsigned char)Packet::ERROR_INVALID_REQUEST);
outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),RR->node->now());
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
}
} break;
default:
- TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unrecognized proof of work type",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
break;
}
- peer->received(_path,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP,false);
+ peer->received(_localAddress,_remoteAddress,hops(),pid,Packet::VERB_REQUEST_PROOF_OF_WORK,0,Packet::VERB_NOP);
} else {
- TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): not trusted enough",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
}
} catch ( ... ) {
- TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_path->address().toString().c_str());
+ TRACE("dropped REQUEST_PROOF_OF_WORK from %s(%s): unexpected exception",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
}
return true;
}
-void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid)
-{
- const uint64_t now = RR->node->now();
- if (peer->rateGateOutgoingComRequest(now)) {
- Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
- outp.append((uint8_t)verb());
- outp.append(packetId());
- outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
- outp.append(nwid);
- outp.armor(peer->key(),true);
- _path->send(RR,outp.data(),outp.size(),now);
- }
-}
-
void IncomingPacket::computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16])
{
unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function
@@ -1577,4 +1335,15 @@ bool IncomingPacket::testSalsa2012Sha512ProofOfWorkResult(unsigned int difficult
return true;
}
+void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid)
+{
+ Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
+ outp.append((unsigned char)verb());
+ outp.append(packetId());
+ outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
+ outp.append(nwid);
+ outp.armor(peer->key(),true);
+ RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
+}
+
} // namespace ZeroTier
diff --git a/zerotierone/node/IncomingPacket.hpp b/zerotierone/node/IncomingPacket.hpp
index c363221..96e46c0 100644
--- a/zerotierone/node/IncomingPacket.hpp
+++ b/zerotierone/node/IncomingPacket.hpp
@@ -22,7 +22,7 @@
#include
#include "Packet.hpp"
-#include "Path.hpp"
+#include "InetAddress.hpp"
#include "Utils.hpp"
#include "MulticastGroup.hpp"
#include "Peer.hpp"
@@ -56,40 +56,59 @@ class IncomingPacket : public Packet
public:
IncomingPacket() :
Packet(),
- _receiveTime(0)
+ _receiveTime(0),
+ _localAddress(),
+ _remoteAddress()
{
}
+ IncomingPacket(const IncomingPacket &p)
+ {
+ // All fields including InetAddress are memcpy'able
+ memcpy(this,&p,sizeof(IncomingPacket));
+ }
+
/**
* Create a new packet-in-decode
*
* @param data Packet data
* @param len Packet length
- * @param path Path over which packet arrived
+ * @param localAddress Local interface address
+ * @param remoteAddress Address from which packet came
* @param now Current time
* @throws std::out_of_range Range error processing packet
*/
- IncomingPacket(const void *data,unsigned int len,const SharedPtr &path,uint64_t now) :
- Packet(data,len),
- _receiveTime(now),
- _path(path)
+ IncomingPacket(const void *data,unsigned int len,const InetAddress &localAddress,const InetAddress &remoteAddress,uint64_t now) :
+ Packet(data,len),
+ _receiveTime(now),
+ _localAddress(localAddress),
+ _remoteAddress(remoteAddress)
{
}
+ inline IncomingPacket &operator=(const IncomingPacket &p)
+ {
+ // All fields including InetAddress are memcpy'able
+ memcpy(this,&p,sizeof(IncomingPacket));
+ return *this;
+ }
+
/**
* Init packet-in-decode in place
*
* @param data Packet data
* @param len Packet length
- * @param path Path over which packet arrived
+ * @param localAddress Local interface address
+ * @param remoteAddress Address from which packet came
* @param now Current time
* @throws std::out_of_range Range error processing packet
*/
- inline void init(const void *data,unsigned int len,const SharedPtr &path,uint64_t now)
+ inline void init(const void *data,unsigned int len,const InetAddress &localAddress,const InetAddress &remoteAddress,uint64_t now)
{
copyFrom(data,len);
_receiveTime = now;
- _path = path;
+ _localAddress = localAddress;
+ _remoteAddress = remoteAddress;
}
/**
@@ -99,12 +118,21 @@ public:
* about whether the packet was valid. A rejection is 'complete.'
*
* Once true is returned, this must not be called again. The packet's state
- * may no longer be valid.
+ * may no longer be valid. The only exception is deferred decoding. In this
+ * case true is returned to indicate to the normal decode path that it is
+ * finished with the packet. The packet will have added itself to the
+ * deferred queue and will expect tryDecode() to be called one more time
+ * with deferred set to true.
+ *
+ * Deferred decoding is performed by DeferredPackets.cpp and should not be
+ * done elsewhere. Under deferred decoding packets only get one shot and
+ * so the return value of tryDecode() is ignored.
*
* @param RR Runtime environment
+ * @param deferred If true, this is a deferred decode and the return is ignored
* @return True if decoding and processing is complete, false if caller should try again
*/
- bool tryDecode(const RuntimeEnvironment *RR);
+ bool tryDecode(const RuntimeEnvironment *RR,bool deferred);
/**
* @return Time of packet receipt / start of decode
@@ -136,7 +164,7 @@ private:
// These are called internally to handle packet contents once it has
// been authenticated, decrypted, decompressed, and classified.
bool _doERROR(const RuntimeEnvironment *RR,const SharedPtr &peer);
- bool _doHELLO(const RuntimeEnvironment *RR,const bool alreadyAuthenticated);
+ bool _doHELLO(const RuntimeEnvironment *RR,SharedPtr &peer); // can be called with NULL peer, while all others cannot
bool _doOK(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doWHOIS(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr &peer);
@@ -144,9 +172,9 @@ private:
bool _doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doECHO(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doMULTICAST_LIKE(const RuntimeEnvironment *RR,const SharedPtr &peer);
- bool _doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr &peer);
+ bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer);
- bool _doNETWORK_CONFIG(const RuntimeEnvironment *RR,const SharedPtr &peer);
+ bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr &peer);
@@ -154,10 +182,12 @@ private:
bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer);
bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &peer);
- void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid);
+ // Send an ERROR_NEED_MEMBERSHIP_CERTIFICATE to a peer indicating that an updated cert is needed to communicate
+ void _sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid);
uint64_t _receiveTime;
- SharedPtr _path;
+ InetAddress _localAddress;
+ InetAddress _remoteAddress;
};
} // namespace ZeroTier
diff --git a/zerotierone/node/InetAddress.cpp b/zerotierone/node/InetAddress.cpp
index 1244690..dca772e 100644
--- a/zerotierone/node/InetAddress.cpp
+++ b/zerotierone/node/InetAddress.cpp
@@ -113,7 +113,7 @@ void InetAddress::set(const std::string &ip,unsigned int port)
sin6->sin6_port = Utils::hton((uint16_t)port);
if (inet_pton(AF_INET6,ip.c_str(),(void *)&(sin6->sin6_addr.s6_addr)) <= 0)
memset(this,0,sizeof(InetAddress));
- } else if (ip.find('.') != std::string::npos) {
+ } else {
struct sockaddr_in *sin = reinterpret_cast(this);
ss_family = AF_INET;
sin->sin_port = Utils::hton((uint16_t)port);
@@ -279,8 +279,6 @@ bool InetAddress::containsAddress(const InetAddress &addr) const
switch(ss_family) {
case AF_INET: {
const unsigned int bits = netmaskBits();
- if (bits == 0)
- return true;
return ( (Utils::ntoh((uint32_t)reinterpret_cast(&addr)->sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)reinterpret_cast(this)->sin_addr.s_addr) >> (32 - bits)) );
}
case AF_INET6: {
@@ -395,6 +393,7 @@ bool InetAddress::operator<(const InetAddress &a) const
}
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
+ throw()
{
struct sockaddr_in6 sin6;
sin6.sin6_family = AF_INET6;
@@ -419,6 +418,7 @@ InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
}
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
+ throw()
{
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast(&r);
@@ -443,25 +443,4 @@ InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
return r;
}
-InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress)
-{
- nwid ^= (nwid >> 32);
- InetAddress r;
- struct sockaddr_in6 *const sin6 = reinterpret_cast