From f69454ec9879a0b0a424f743ca144d1123ef7e99 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 24 Sep 2015 16:21:36 -0700 Subject: (1) Make ZT_ naming convention consistent (get rid of ZT1_), (2) Make local interface a full sockaddr_storage instead of an int identifier, which turns out to be better for multi-homing and other uses. --- node/IncomingPacket.cpp | 72 ++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e4861af7..c94ffe2e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -69,7 +69,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) switch(verb()) { //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),verb(),0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),verb(),0,Packet::VERB_NOP); return true; case Packet::VERB_HELLO: return _doHELLO(RR); case Packet::VERB_ERROR: return _doERROR(RR,peer); @@ -130,7 +130,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr case Packet::ERROR_IDENTITY_COLLISION: if (RR->topology->isRoot(peer->identity())) - RR->node->postEvent(ZT1_EVENT_FATAL_ERROR_IDENTITY_COLLISION); + RR->node->postEvent(ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION); break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { @@ -144,7 +144,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); nconf->com().serialize(outp); outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } } break; @@ -165,7 +165,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr default: break; } - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb); } catch (std::exception &ex) { TRACE("dropped ERROR from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -224,20 +224,20 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; if (RR->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { if (dearmor(key)) { // ensure packet is authentic, otherwise drop - RR->node->postEvent(ZT1_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); + RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): address already claimed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); Packet outp(id.address(),RR->identity.address(),Packet::VERB_ERROR); outp.append((unsigned char)Packet::VERB_HELLO); outp.append(packetId()); outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION); outp.armor(key,true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } else { - RR->node->postEvent(ZT1_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); + RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); } } else { - RR->node->postEvent(ZT1_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); + RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): key agreement failed",id.address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -246,7 +246,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - RR->node->postEvent(ZT1_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); + RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } @@ -258,7 +258,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Check identity proof of work if (!id.locallyValidate()) { - RR->node->postEvent(ZT1_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); + RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("dropped HELLO from %s(%s): identity invalid",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } @@ -266,7 +266,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // Check packet integrity and authentication SharedPtr newPeer(new Peer(RR->identity,id)); if (!dearmor(newPeer->key())) { - RR->node->postEvent(ZT1_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); + RR->node->postEvent(ZT_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_remoteAddress.toString().c_str()); return true; } @@ -278,7 +278,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) // VALID -- continues here - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); bool trusted = false; @@ -316,7 +316,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) } outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } catch (std::exception &ex) { TRACE("dropped HELLO from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -436,7 +436,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb); } catch (std::exception &ex) { TRACE("dropped OK from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -456,7 +456,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr outp.append(packetId()); queried->identity().serialize(outp,false); outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + 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_WHOIS); @@ -464,12 +464,12 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(payload(),ZT_ADDRESS_LENGTH); outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } else { TRACE("dropped WHOIS from %s(%s): missing or invalid address",source().toString().c_str(),_remoteAddress.toString().c_str()); } - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP); } catch ( ... ) { TRACE("dropped WHOIS from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -487,8 +487,8 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr< if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) { InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port); TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str()); - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); - RR->sw->rendezvous(withPeer,_localInterfaceId,atAddr); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP); + RR->sw->rendezvous(withPeer,_localAddress,atAddr); } else { TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",peer->address().toString().c_str(),_remoteAddress.toString().c_str()); } @@ -525,7 +525,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr RR->node->putFrame(network->id(),MAC(peer->address(),network->id()),network->mac(),etherType,0,field(ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,payloadLen),payloadLen); } - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP); } else { TRACE("dropped FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } @@ -602,7 +602,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

node->putFrame(network->id(),from,to,etherType,0,field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,payloadLen),payloadLen); } - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP); } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); } @@ -623,7 +623,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptrmc->add(now,at(ptr),MulticastGroup(MAC(field(ptr + 8,6),6),at(ptr + 14)),peer->address()); - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP); } catch (std::exception &ex) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -647,7 +647,7 @@ bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment } } - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP); } catch (std::exception &ex) { TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { @@ -666,7 +666,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons const unsigned int h = hops(); const uint64_t pid = packetId(); - peer->received(RR,_localInterfaceId,_remoteAddress,h,pid,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,h,pid,Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP); if (RR->localNetworkController) { Dictionary netconf; @@ -688,7 +688,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) { TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length()); } else { - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } } break; @@ -700,7 +700,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND); outp.append(nwid); outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } break; case NetworkController::NETCONF_QUERY_ACCESS_DENIED: { @@ -710,7 +710,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_NETWORK_ACCESS_DENIED_); outp.append(nwid); outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } break; case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: @@ -732,7 +732,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION); outp.append(nwid); outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } catch (std::exception &exc) { TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); @@ -753,7 +753,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,cons nw->requestConfiguration(); ptr += 8; } - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP); } catch (std::exception &exc) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { @@ -780,11 +780,11 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar outp.append((uint32_t)mg.adi()); if (RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit)) { outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP); } catch (std::exception &exc) { TRACE("dropped MULTICAST_GATHER from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { @@ -871,12 +871,12 @@ 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); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } } // else ignore -- not a member of this network - peer->received(RR,_localInterfaceId,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP); + peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP); } catch (std::exception &exc) { TRACE("dropped MULTICAST_FRAME from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); } catch ( ... ) { @@ -905,14 +905,14 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha InetAddress a(field(ptr,4),4,at(ptr + 4)); if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(RR,_localInterfaceId,a,RR->node->now()); + peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); } } break; case 6: { InetAddress a(field(ptr,16),16,at(ptr + 16)); if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) { TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); - peer->attemptToContactAt(RR,_localInterfaceId,a,RR->node->now()); + peer->attemptToContactAt(RR,_localAddress,a,RR->node->now()); } } break; } @@ -934,7 +934,7 @@ void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,cons outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); outp.append(nwid); outp.armor(peer->key(),true); - RR->node->putPacket(_localInterfaceId,_remoteAddress,outp.data(),outp.size()); + RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size()); } } // namespace ZeroTier -- cgit v1.2.3 From 1a4f16e0ed1b62ebf3bdbb539858a3874c689fa4 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 30 Sep 2015 13:59:05 -0700 Subject: More work on circuit testing... --- node/IncomingPacket.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ node/IncomingPacket.hpp | 4 +++- node/Packet.hpp | 5 +++- 3 files changed, 70 insertions(+), 2 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c94ffe2e..3866abf1 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -85,6 +85,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,peer); case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,peer); case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,peer); + case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,peer); + case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,peer); } } else { RR->sw->requestWhois(source()); @@ -926,6 +928,67 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha return true; } +bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer) +{ + try { + const Address originatorAddress(field(ZT_PACKET_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + SharedPtr originator(RR->topology->getPeer(originatorAddress)); + if (!originator) { + RR->sw->requestWhois(originatorAddress); + return false; + } + + const unsigned int flags = at(ZT_PACKET_IDX_PAYLOAD + 5); + const uint64_t timestamp = at(ZT_PACKET_IDX_PAYLOAD + 7); + const uint64_t testId = at(ZT_PACKET_IDX_PAYLOAD + 15); + + unsigned int vlf = at(ZT_PACKET_IDX_PAYLOAD + 23); // variable length field length + switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) { + case 0x01: { // 64-bit network ID, originator must be controller + } break; + default: break; + } + + vlf += at(ZT_PACKET_IDX_PAYLOAD + 26 + vlf); // length of additional fields, currently unused + + const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 28 + vlf); + if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,28 + vlf),28 + vlf,field(30 + vlf,signatureLength),signatureLength)) { + 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; + + vlf += at(ZT_PACKET_IDX_PAYLOAD + 30 + vlf); + switch((*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf]) { + case 0x01: { // network certificate of membership for previous hop + } break; + default: break; + } + + if ((ZT_PACKET_IDX_PAYLOAD + 33 + vlf) < size()) { + const unsigned int breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 33 + vlf]; + Address nextHops[255]; + SharedPtr nextHopPeers[255]; + unsigned int hptr = ZT_PACKET_IDX_PAYLOAD + 34 + vlf; + for(unsigned int h=0;((h256 but be safe anyway + nextHops[h].setTo(field(hptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); + hptr += ZT_ADDRESS_LENGTH; + nextHopPeers[h] = RR->topology->getPeer(nextHops[h]); + } + } + } catch (std::exception &exc) { + TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); + } catch ( ... ) { + TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str()); + } + return true; +} + +bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer) +{ + return true; +} + void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid) { Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index d19eb5c6..06220c4b 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -124,8 +124,10 @@ private: 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); + bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); - // Send an ERROR_NEED_MEMBERSHIP_CERTIFICATE to a peer indicating that an updated cert is needed to join + // 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; diff --git a/node/Packet.hpp b/node/Packet.hpp index 2d439b11..2a1a39af 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -911,12 +911,15 @@ public: * <[2] 16-bit flags> * <[8] 64-bit timestamp> * <[8] 64-bit test ID (arbitrary, set by tester)> + * <[2] 16-bit originator credential length> * <[1] originator credential type (for authorizing test)> * <[...] credential> * <[2] 16-bit length of additional fields> * <[...] additional fields> + * [ ... end of signed portion of request ... ] * <[2] 16-bit length of signature of request> * <[...] signature of request by originator> + * <[2] 16-bit previous hop credential length> * <[1] previous hop credential type> * <[...] previous hop credential> * <[...] next hop(s) in path> @@ -939,7 +942,7 @@ public: * <[...] one or more ZeroTier addresses of next hops> * * Path record flags (in each path record): - * 0x80 - End of path (should be set on last entry) + * (unused, must be zero) * * The circuit test allows a device to send a message that will traverse * the network along a specified path, with each hop optionally reporting -- cgit v1.2.3 From a3db7d0728c1bc5181b8a70e8c379632125ee376 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 1 Oct 2015 11:11:52 -0700 Subject: Refactor: move network COMs out of Network and into Peer in prep for tightening up multicast lookup and other things. --- node/Constants.hpp | 7 ++ node/IncomingPacket.cpp | 25 ++---- node/Network.cpp | 132 ++---------------------------- node/Network.hpp | 45 +++------- node/Node.hpp | 10 +++ node/OutboundMulticast.cpp | 6 +- node/Path.hpp | 8 -- node/Peer.cpp | 199 +++++++++++++++++++++++++++++++++++++++++---- node/Peer.hpp | 57 ++++++++++++- node/Switch.cpp | 8 +- node/Topology.cpp | 7 +- 11 files changed, 289 insertions(+), 215 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Constants.hpp b/node/Constants.hpp index 4f783550..27c43aa7 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -324,6 +324,13 @@ */ #define ZT_DIRECT_PATH_PUSH_INTERVAL 300000 +/** + * How long (max) to remember network certificates of membership? + * + * This only applies to networks we don't belong to. + */ +#define ZT_PEER_NETWORK_COM_EXPIRATION 3600000 + /** * Sanity limit on maximum bridge routes * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 3866abf1..e892edc2 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -421,9 +421,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p // OK(MULTICAST_FRAME) includes certificate of membership update CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); - SharedPtr network(RR->node->network(nwid)); - if ((network)&&(com.hasRequiredFields())) - network->validateAndAddMembershipCertificate(com); + peer->validateAndSetNetworkMembershipCertificate(RR,nwid,com); } if ((flags & 0x02) != 0) { @@ -511,7 +509,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID))); if (network) { if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { - if (!network->isAllowed(peer->address())) { + if (!network->isAllowed(peer)) { TRACE("dropped 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; @@ -552,13 +550,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

validateAndAddMembershipCertificate(com)) - comFailed = true; // technically this check is redundant to isAllowed(), but do it anyway for thoroughness - } + if (!peer->validateAndSetNetworkMembershipCertificate(RR,network->id(),com)) + comFailed = true; } - if ((comFailed)||(!network->isAllowed(peer->address()))) { + if ((comFailed)||(!network->isAllowed(peer))) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),network->id()); _sendErrorNeedCertificate(RR,peer,network->id()); return true; @@ -642,11 +638,7 @@ bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; while (ptr < size()) { ptr += com.deserialize(*this,ptr); - if (com.hasRequiredFields()) { - SharedPtr network(RR->node->network(com.networkId())); - if (network) - network->validateAndAddMembershipCertificate(com); - } + peer->validateAndSetNetworkMembershipCertificate(RR,com.networkId(),com); } peer->received(RR,_localAddress,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP); @@ -809,13 +801,12 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share if ((flags & 0x01) != 0) { CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); - if (com.hasRequiredFields()) - network->validateAndAddMembershipCertificate(com); + peer->validateAndSetNetworkMembershipCertificate(RR,nwid,com); } // Check membership after we've read any included COM, since // that cert might be what we needed. - if (!network->isAllowed(peer->address())) { + 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; diff --git a/node/Network.cpp b/node/Network.cpp index 2b24d5f9..9c8aabfa 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -59,6 +59,9 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid) : Utils::snprintf(confn,sizeof(confn),"networks.d/%.16llx.conf",_id); Utils::snprintf(mcdbn,sizeof(mcdbn),"networks.d/%.16llx.mcerts",_id); + // These files are no longer used, so clean them. + RR->node->dataStoreDelete(mcdbn); + if (_id == ZT_TEST_NETWORK_ID) { applyConfiguration(NetworkConfig::createTestNetworkConfig(RR->identity.address())); @@ -79,24 +82,6 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid) : // Save a one-byte CR to persist membership while we request a real netconf RR->node->dataStorePut(confn,"\n",1,false); } - - try { - std::string mcdb(RR->node->dataStoreGet(mcdbn)); - if (mcdb.length() > 6) { - const char *p = mcdb.data(); - const char *e = p + mcdb.length(); - if (!memcmp("ZTMCD0",p,6)) { - p += 6; - while (p != e) { - CertificateOfMembership com; - com.deserialize2(p,e); - if (!com) - break; - _certInfo[com.issuedTo()].com = com; - } - } - } - } catch ( ... ) {} // ignore invalid MCDB, we'll re-learn from peers } if (!_portInitialized) { @@ -115,32 +100,10 @@ Network::~Network() char n[128]; if (_destroyed) { RR->node->configureVirtualNetworkPort(_id,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp); - Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id); RR->node->dataStoreDelete(n); - Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.mcerts",_id); - RR->node->dataStoreDelete(n); } else { RR->node->configureVirtualNetworkPort(_id,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp); - - clean(); - - Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.mcerts",_id); - - Mutex::Lock _l(_lock); - if ((!_config)||(_config->isPublic())||(_certInfo.empty())) { - RR->node->dataStoreDelete(n); - } else { - std::string buf("ZTMCD0"); - Hashtable< Address,_RemoteMemberCertificateInfo >::Iterator i(_certInfo); - Address *a = (Address *)0; - _RemoteMemberCertificateInfo *ci = (_RemoteMemberCertificateInfo *)0; - while (i.next(a,ci)) { - if (ci->com) - ci->com.serialize2(buf); - } - RR->node->dataStorePut(n,buf,true); - } } } @@ -281,70 +244,6 @@ void Network::requestConfiguration() RR->sw->send(outp,true,0); } -bool Network::validateAndAddMembershipCertificate(const CertificateOfMembership &cert) -{ - if (!cert) // sanity check - return false; - - Mutex::Lock _l(_lock); - - { - const _RemoteMemberCertificateInfo *ci = _certInfo.get(cert.issuedTo()); - if ((ci)&&(ci->com == cert)) - return true; // we already have it - } - - // Check signature, log and return if cert is invalid - if (cert.signedBy() != controller()) { - TRACE("rejected network membership certificate for %.16llx signed by %s: signer not a controller of this network",(unsigned long long)_id,cert.signedBy().toString().c_str()); - return false; // invalid signer - } - - if (cert.signedBy() == RR->identity.address()) { - - // We are the controller: RR->identity.address() == controller() == cert.signedBy() - // So, verify that we signed th cert ourself - if (!cert.verify(RR->identity)) { - TRACE("rejected network membership certificate for %.16llx self signed by %s: signature check failed",(unsigned long long)_id,cert.signedBy().toString().c_str()); - return false; // invalid signature - } - - } else { - - SharedPtr signer(RR->topology->getPeer(cert.signedBy())); - - if (!signer) { - // This would be rather odd, since this is our controller... could happen - // if we get packets before we've gotten config. - RR->sw->requestWhois(cert.signedBy()); - return false; // signer unknown - } - - if (!cert.verify(signer->identity())) { - TRACE("rejected network membership certificate for %.16llx signed by %s: signature check failed",(unsigned long long)_id,cert.signedBy().toString().c_str()); - return false; // invalid signature - } - } - - // If we made it past authentication, add or update cert in our cert info store - _certInfo[cert.issuedTo()].com = cert; - - return true; -} - -bool Network::peerNeedsOurMembershipCertificate(const Address &to,uint64_t now) -{ - Mutex::Lock _l(_lock); - if ((_config)&&(!_config->isPublic())&&(_config->com())) { - _RemoteMemberCertificateInfo &ci = _certInfo[to]; - if ((now - ci.lastPushed) > (ZT_NETWORK_AUTOCONF_DELAY / 2)) { - ci.lastPushed = now; - return true; - } - } - return false; -} - void Network::clean() { const uint64_t now = RR->node->now(); @@ -353,22 +252,6 @@ void Network::clean() if (_destroyed) return; - if ((_config)&&(_config->isPublic())) { - // Open (public) networks do not track certs or cert pushes at all. - _certInfo.clear(); - } else if (_config) { - // Clean obsolete entries from private network cert info table - Hashtable< Address,_RemoteMemberCertificateInfo >::Iterator i(_certInfo); - Address *a = (Address *)0; - _RemoteMemberCertificateInfo *ci = (_RemoteMemberCertificateInfo *)0; - const uint64_t forgetIfBefore = now - (ZT_PEER_ACTIVITY_TIMEOUT * 16); // arbitrary reasonable cutoff - while (i.next(a,ci)) { - if ((ci->lastPushed < forgetIfBefore)&&(!ci->com.agreesWith(_config->com()))) - _certInfo.erase(*a); - } - } - - // Clean learned multicast groups if we haven't heard from them in a while { Hashtable< MulticastGroup,uint64_t >::Iterator i(_multicastGroupsBehindMe); MulticastGroup *mg = (MulticastGroup *)0; @@ -494,7 +377,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const } else ec->assignedAddressCount = 0; } -bool Network::_isAllowed(const Address &peer) const +bool Network::_isAllowed(const SharedPtr &peer) const { // Assumes _lock is locked try { @@ -502,10 +385,7 @@ bool Network::_isAllowed(const Address &peer) const return false; if (_config->isPublic()) return true; - const _RemoteMemberCertificateInfo *ci = _certInfo.get(peer); - if (!ci) - return false; - return _config->com().agreesWith(ci->com); + return ((_config->com())&&(peer->networkMembershipCertificatesAgree(_id,_config->com()))); } catch (std::exception &exc) { TRACE("isAllowed() check failed for peer %s: unexpected exception: %s",peer.toString().c_str(),exc.what()); } catch ( ... ) { @@ -542,7 +422,7 @@ public: inline void operator()(Topology &t,const SharedPtr &p) { - if ( ( (p->hasActiveDirectPath(_now)) && ( (_network->_isAllowed(p->address())) || (p->address() == _network->controller()) ) ) || (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) ) { + if ( ( (p->hasActiveDirectPath(_now)) && ( (_network->_isAllowed(p)) || (p->address() == _network->controller()) ) ) || (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) ) { Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE); for(std::vector::iterator mg(_allMulticastGroups.begin());mg!=_allMulticastGroups.end();++mg) { diff --git a/node/Network.hpp b/node/Network.hpp index ad9f18de..37077650 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -56,6 +56,7 @@ namespace ZeroTier { class RuntimeEnvironment; class _AnnounceMulticastGroupsToPeersWithActiveDirectPaths; +class Peer; /** * A virtual LAN @@ -94,6 +95,12 @@ public: */ inline Address controller() throw() { return Address(_id >> 24); } + /** + * @param nwid Network ID + * @return Address of network's controller + */ + static inline Address controllerFor(uint64_t nwid) throw() { return Address(nwid >> 24); } + /** * @return Multicast group memberships for this network's port (local, not learned via bridging) */ @@ -177,33 +184,10 @@ public: void requestConfiguration(); /** - * Add or update a membership certificate - * - * @param cert Certificate of membership - * @return True if certificate was accepted as valid - */ - bool validateAndAddMembershipCertificate(const CertificateOfMembership &cert); - - /** - * Check if we should push membership certificate to a peer, AND update last pushed - * - * If we haven't pushed a cert to this peer in a long enough time, this returns - * true and updates the last pushed time. Otherwise it returns false. - * - * This doesn't actually send anything, since COMs can hitch a ride with several - * different kinds of packets. - * - * @param to Destination peer - * @param now Current time - * @return True if we should include a COM with whatever we're currently sending - */ - bool peerNeedsOurMembershipCertificate(const Address &to,uint64_t now); - - /** - * @param peer Peer address to check + * @param peer Peer to check * @return True if peer is allowed to communicate on this network */ - inline bool isAllowed(const Address &peer) const + inline bool isAllowed(const SharedPtr &peer) const { Mutex::Lock _l(_lock); return _isAllowed(peer); @@ -347,16 +331,9 @@ public: inline bool operator>=(const Network &n) const throw() { return (_id >= n._id); } private: - struct _RemoteMemberCertificateInfo - { - _RemoteMemberCertificateInfo() : com(),lastPushed(0) {} - CertificateOfMembership com; // remote member's COM - uint64_t lastPushed; // when did we last push ours to them? - }; - ZT_VirtualNetworkStatus _status() const; void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked - bool _isAllowed(const Address &peer) const; + bool _isAllowed(const SharedPtr &peer) const; void _announceMulticastGroups(); std::vector _allMulticastGroups() const; @@ -370,8 +347,6 @@ private: Hashtable< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge) Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) - Hashtable< Address,_RemoteMemberCertificateInfo > _certInfo; - SharedPtr _config; // Most recent network configuration, which is an immutable value-object volatile uint64_t _lastConfigUpdate; diff --git a/node/Node.hpp b/node/Node.hpp index b81c1943..0f659f47 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -168,6 +168,16 @@ public: return _network(nwid); } + inline bool belongsToNetwork(uint64_t nwid) const + { + Mutex::Lock _l(_networks_m); + for(std::vector< std::pair< uint64_t, SharedPtr > >::const_iterator i=_networks.begin();i!=_networks.end();++i) { + if (i->first == nwid) + return true; + } + return false; + } + inline std::vector< SharedPtr > allNetworks() const { std::vector< SharedPtr > nw; diff --git a/node/OutboundMulticast.cpp b/node/OutboundMulticast.cpp index 46116c07..c26372cb 100644 --- a/node/OutboundMulticast.cpp +++ b/node/OutboundMulticast.cpp @@ -103,11 +103,11 @@ void OutboundMulticast::init( void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,const Address &toAddr) { if (_haveCom) { - SharedPtr network(RR->node->network(_nwid)); - if ((network)&&(network->peerNeedsOurMembershipCertificate(toAddr,RR->node->now()))) { + SharedPtr peer(RR->topology->getPeer(toAddr)); + if ( (!peer) || (peer->needsOurNetworkMembershipCertificate(_nwid,RR->node->now(),true)) ) { + //TRACE(">>MC %.16llx -> %s (with COM)",(unsigned long long)this,toAddr.toString().c_str()); _packetWithCom.newInitializationVector(); _packetWithCom.setDestination(toAddr); - //TRACE(">>MC %.16llx -> %s (with COM)",(unsigned long long)this,toAddr.toString().c_str()); RR->sw->send(_packetWithCom,true,_nwid); return; } diff --git a/node/Path.hpp b/node/Path.hpp index 9d97d2df..8d662ff7 100644 --- a/node/Path.hpp +++ b/node/Path.hpp @@ -122,14 +122,6 @@ public: */ inline operator bool() const throw() { return (_addr); } - // Comparisons are by address only - inline bool operator==(const Path &p) const throw() { return (_addr == p._addr); } - inline bool operator!=(const Path &p) const throw() { return (_addr != p._addr); } - inline bool operator<(const Path &p) const throw() { return (_addr < p._addr); } - inline bool operator>(const Path &p) const throw() { return (_addr > p._addr); } - inline bool operator<=(const Path &p) const throw() { return (_addr <= p._addr); } - inline bool operator>=(const Path &p) const throw() { return (_addr >= p._addr); } - /** * Check whether this address is valid for a ZeroTier path * diff --git a/node/Peer.cpp b/node/Peer.cpp index 48b77c85..6203d0b4 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -37,6 +37,8 @@ #include +#define ZT_PEER_PATH_SORT_INTERVAL 5000 + namespace ZeroTier { // Used to send varying values for NAT keepalive @@ -51,17 +53,38 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity) _lastAnnouncedTo(0), _lastPathConfirmationSent(0), _lastDirectPathPush(0), + _lastPathSort(0), _vMajor(0), _vMinor(0), _vRevision(0), _id(peerIdentity), _numPaths(0), - _latency(0) + _latency(0), + _networkComs(4), + _lastPushedComs(4) { if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH)) throw std::runtime_error("new peer identity key agreement failed"); } +struct _SortPathsByQuality +{ + uint64_t _now; + _SortPathsByQuality(const uint64_t now) : _now(now) {} + inline bool operator()(const RemotePath &a,const RemotePath &b) const + { + const uint64_t qa = ( + ((uint64_t)a.active(_now) << 63) | + (((uint64_t)(a.preferenceRank() & 0xfff)) << 51) | + ((uint64_t)a.lastReceived() & 0x7ffffffffffffULL) ); + const uint64_t qb = ( + ((uint64_t)b.active(_now) << 63) | + (((uint64_t)(b.preferenceRank() & 0xfff)) << 51) | + ((uint64_t)b.lastReceived() & 0x7ffffffffffffULL) ); + return (qb < qa); // invert sense to sort in descending order + } +}; + void Peer::received( const RuntimeEnvironment *RR, const InetAddress &localAddr, @@ -73,6 +96,8 @@ void Peer::received( Packet::Verb inReVerb) { const uint64_t now = RR->node->now(); + Mutex::Lock _l(_lock); + _lastReceive = now; if (!hops) { @@ -91,6 +116,7 @@ void Peer::received( if (!pathIsConfirmed) { if ((verb == Packet::VERB_OK)&&(inReVerb == Packet::VERB_HELLO)) { + // Learn paths if they've been confirmed via a HELLO RemotePath *slot = (RemotePath *)0; if (np < ZT_MAX_PEER_NETWORK_PATHS) { @@ -111,8 +137,11 @@ void Peer::received( slot->received(now); _numPaths = np; pathIsConfirmed = true; + _sortPaths(now); } + } else { + /* If this path is not known, send a HELLO. We don't learn * paths without confirming that a bidirectional link is in * fact present, but any packet that decodes and authenticates @@ -122,6 +151,7 @@ void Peer::received( TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str()); attemptToContactAt(RR,localAddr,remoteAddr,now); } + } } } @@ -129,6 +159,7 @@ void Peer::received( /* Announce multicast groups of interest to direct peers if they are * considered authorized members of a given network. Also announce to * root servers and network controllers. */ + /* if ((pathIsConfirmed)&&((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000))) { _lastAnnouncedTo = now; @@ -158,6 +189,7 @@ void Peer::received( RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size()); } } + */ } if ((verb == Packet::VERB_FRAME)||(verb == Packet::VERB_EXT_FRAME)) @@ -166,23 +198,10 @@ void Peer::received( _lastMulticastFrame = now; } -RemotePath *Peer::getBestPath(uint64_t now) -{ - RemotePath *bestPath = (RemotePath *)0; - uint64_t lrMax = 0; - int rank = 0; - for(unsigned int p=0,np=_numPaths;p= lrMax)||(_paths[p].preferenceRank() >= rank)) ) { - lrMax = _paths[p].lastReceived(); - rank = _paths[p].preferenceRank(); - bestPath = &(_paths[p]); - } - } - return bestPath; -} - void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now) { + // _lock not required here since _id is immutable and nothing else is accessed + Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); outp.append((unsigned char)ZT_PROTO_VERSION); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); @@ -214,7 +233,8 @@ void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &lo void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) { - RemotePath *const bestPath = getBestPath(now); + Mutex::Lock _l(_lock); + RemotePath *const bestPath = _getBestPath(now); if (bestPath) { if ((now - bestPath->lastReceived()) >= ZT_PEER_DIRECT_PING_DELAY) { TRACE("PING %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str()); @@ -231,6 +251,8 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now) void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_t now,bool force) { + Mutex::Lock _l(_lock); + if (((now - _lastDirectPathPush) >= ZT_DIRECT_PATH_PUSH_INTERVAL)||(force)) { _lastDirectPathPush = now; @@ -299,13 +321,16 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_ } } -void Peer::addPath(const RemotePath &newp) +void Peer::addPath(const RemotePath &newp,uint64_t now) { + Mutex::Lock _l(_lock); + unsigned int np = _numPaths; for(unsigned int p=0;pcom.agreesWith(com); + return false; +} + +bool Peer::validateAndSetNetworkMembershipCertificate(const RuntimeEnvironment *RR,uint64_t nwid,const CertificateOfMembership &com) +{ + // Sanity checks + if ((!com)||(com.issuedTo() != _id.address())) + return false; + + // Return true if we already have this *exact* COM + { + Mutex::Lock _l(_lock); + _NetworkCom *ourCom = _networkComs.get(nwid); + if ((ourCom)&&(ourCom->com == com)) + return true; + } + + // Check signature, log and return if cert is invalid + if (com.signedBy() != Network::controllerFor(nwid)) { + TRACE("rejected network membership certificate for %.16llx signed by %s: signer not a controller of this network",(unsigned long long)_id,cert.signedBy().toString().c_str()); + return false; // invalid signer + } + + if (com.signedBy() == RR->identity.address()) { + + // We are the controller: RR->identity.address() == controller() == cert.signedBy() + // So, verify that we signed th cert ourself + if (!com.verify(RR->identity)) { + TRACE("rejected network membership certificate for %.16llx self signed by %s: signature check failed",(unsigned long long)_id,cert.signedBy().toString().c_str()); + return false; // invalid signature + } + + } else { + + SharedPtr signer(RR->topology->getPeer(com.signedBy())); + + if (!signer) { + // This would be rather odd, since this is our controller... could happen + // if we get packets before we've gotten config. + RR->sw->requestWhois(com.signedBy()); + return false; // signer unknown + } + + if (!com.verify(signer->identity())) { + TRACE("rejected network membership certificate for %.16llx signed by %s: signature check failed",(unsigned long long)_id,cert.signedBy().toString().c_str()); + return false; // invalid signature + } + } + + // If we made it past all those checks, add or update cert in our cert info store + { + Mutex::Lock _l(_lock); + _networkComs.set(nwid,_NetworkCom(RR->node->now(),com)); + } + + return true; +} + +bool Peer::needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime) +{ + Mutex::Lock _l(_lock); + uint64_t &lastPushed = _lastPushedComs[nwid]; + const uint64_t tmp = lastPushed; + if (updateLastPushedTime) + lastPushed = now; + return ((now - tmp) < (ZT_NETWORK_AUTOCONF_DELAY / 2)); +} + +void Peer::clean(const RuntimeEnvironment *RR,uint64_t now) +{ + Mutex::Lock _l(_lock); + + { + unsigned int np = _numPaths; + unsigned int x = 0; + unsigned int y = 0; + while (x < np) { + if (_paths[x].active(now)) + _paths[y++] = _paths[x]; + ++x; + } + _numPaths = y; + } + + { + uint64_t *k = (uint64_t *)0; + _NetworkCom *v = (_NetworkCom *)0; + Hashtable< uint64_t,_NetworkCom >::Iterator i(_networkComs); + while (i.next(k,v)) { + if ( (!RR->node->belongsToNetwork(*k)) && ((now - v->ts) >= ZT_PEER_NETWORK_COM_EXPIRATION) ) + _networkComs.erase(*k); + } + } + + { + uint64_t *k = (uint64_t *)0; + uint64_t *v = (uint64_t *)0; + Hashtable< uint64_t,uint64_t >::Iterator i(_lastPushedComs); + while (i.next(k,v)) { + if ((now - *v) > (ZT_NETWORK_AUTOCONF_DELAY * 2)) + _lastPushedComs.erase(*k); + } + } +} + +void Peer::_sortPaths(const uint64_t now) +{ + // assumes _lock is locked + _lastPathSort = now; + std::sort(&(_paths[0]),&(_paths[_numPaths]),_SortPathsByQuality(now)); +} + +RemotePath *Peer::_getBestPath(const uint64_t now) +{ + // assumes _lock is locked + if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL) + _sortPaths(now); + if (_paths[0].active(now)) { + return &(_paths[0]); + } else { + _sortPaths(now); + if (_paths[0].active(now)) + return &(_paths[0]); + } + return (RemotePath *)0; +} + } // namespace ZeroTier diff --git a/node/Peer.hpp b/node/Peer.hpp index 4d1031b8..c1692846 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -49,6 +49,8 @@ #include "Packet.hpp" #include "SharedPtr.hpp" #include "AtomicCounter.hpp" +#include "Hashtable.hpp" +#include "Mutex.hpp" #include "NonCopyable.hpp" namespace ZeroTier { @@ -129,7 +131,11 @@ public: * @param now Current time * @return Best path or NULL if there are no active (or fixed) direct paths */ - RemotePath *getBestPath(uint64_t now); + inline RemotePath *getBestPath(uint64_t now) + { + Mutex::Lock _l(_lock); + return _getBestPath(now); + } /** * Send via best path @@ -293,8 +299,9 @@ public: * Add a path (if we don't already have it) * * @param p New path to add + * @param now Current time */ - void addPath(const RemotePath &newp); + void addPath(const RemotePath &newp,uint64_t now); /** * Clear paths @@ -381,6 +388,37 @@ public: */ void getBestActiveAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const; + /** + * Check network COM agreement with this peer + * + * @param nwid Network ID + * @param com Another certificate of membership + * @return True if supplied COM agrees with ours, false if not or if we don't have one + */ + bool networkMembershipCertificatesAgree(uint64_t nwid,const CertificateOfMembership &com) const; + + /** + * Check the validity of the COM and add/update if valid and new + * + * @param RR Runtime Environment + * @param nwid Network ID + * @param com Externally supplied COM + */ + bool validateAndSetNetworkMembershipCertificate(const RuntimeEnvironment *RR,uint64_t nwid,const CertificateOfMembership &com); + + /** + * @param nwid Network ID + * @param now Current time + * @param updateLastPushedTime If true, go ahead and update the last pushed time regardless of return value + * @return Whether or not this peer needs another COM push from us + */ + bool needsOurNetworkMembershipCertificate(uint64_t nwid,uint64_t now,bool updateLastPushedTime); + + /** + * Perform periodic cleaning operations + */ + void clean(const RuntimeEnvironment *RR,uint64_t now); + /** * Find a common set of addresses by which two peers can link, if any * @@ -402,7 +440,8 @@ public: } private: - void _announceMulticastGroups(const RuntimeEnvironment *RR,uint64_t now); + void _sortPaths(const uint64_t now); + RemotePath *_getBestPath(const uint64_t now); unsigned char _key[ZT_PEER_SECRET_KEY_LENGTH]; uint64_t _lastUsed; @@ -412,6 +451,7 @@ private: uint64_t _lastAnnouncedTo; uint64_t _lastPathConfirmationSent; uint64_t _lastDirectPathPush; + uint64_t _lastPathSort; uint16_t _vProto; uint16_t _vMajor; uint16_t _vMinor; @@ -421,6 +461,17 @@ private: unsigned int _numPaths; unsigned int _latency; + struct _NetworkCom + { + _NetworkCom() {} + _NetworkCom(uint64_t t,const CertificateOfMembership &c) : ts(t),com(c) {} + uint64_t ts; + CertificateOfMembership com; + }; + Hashtable _networkComs; + Hashtable _lastPushedComs; + + Mutex _lock; AtomicCounter __refCount; }; diff --git a/node/Switch.cpp b/node/Switch.cpp index ecae9b76..9ea8ac49 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -202,7 +202,8 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c // Destination is another ZeroTier peer on the same network Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this - const bool includeCom = network->peerNeedsOurMembershipCertificate(toZT,RR->node->now()); + SharedPtr toPeer(RR->topology->getPeer(toZT)); + const bool includeCom = ((!toPeer)||(toPeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true)));; if ((fromBridged)||(includeCom)) { Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); @@ -267,9 +268,10 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c } for(unsigned int b=0;b bridgePeer(RR->topology->getPeer(bridges[b])); Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME); outp.append(network->id()); - if (network->peerNeedsOurMembershipCertificate(bridges[b],RR->node->now())) { + if ((!bridgePeer)||(bridgePeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) { outp.append((unsigned char)0x01); // 0x01 -- COM included nconf->com().serialize(outp); } else { @@ -747,7 +749,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid) return false; // no paths, no root servers? } - if ((network)&&(relay)&&(network->isAllowed(peer->address()))) { + if ((network)&&(relay)&&(network->isAllowed(peer))) { // Push hints for direct connectivity to this peer if we are relaying peer->pushDirectPaths(RR,viaPath,now,false); } diff --git a/node/Topology.cpp b/node/Topology.cpp index e931df1e..b2b4ebbd 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -62,7 +62,7 @@ void Topology::setRootServers(const std::map< Identity,std::vector if (!p) p = SharedPtr(new Peer(RR->identity,i->first)); for(std::vector::const_iterator j(i->second.begin());j!=i->second.end();++j) - p->addPath(RemotePath(InetAddress(),*j,true)); + p->addPath(RemotePath(InetAddress(),*j,true),now); p->use(now); _rootPeers.push_back(p); } @@ -252,9 +252,12 @@ void Topology::clean(uint64_t now) Hashtable< Address,SharedPtr >::Iterator i(_activePeers); Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; - while (i.next(a,p)) + while (i.next(a,p)) { if (((now - (*p)->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end())) { _activePeers.erase(*a); + } else { + (*p)->clean(RR,now); + } } } -- cgit v1.2.3 From 5341afcdcd7d2d1ae5546ae44024d039b03ccad3 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Oct 2015 11:47:16 -0700 Subject: Handling of CIRCUIT_TEST, should be ready to test. --- node/Buffer.hpp | 17 ++++++ node/IncomingPacket.cpp | 152 +++++++++++++++++++++++++++++++++++++++++------- node/Packet.hpp | 44 +++++--------- 3 files changed, 162 insertions(+), 51 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 789b835a..46924c14 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -391,6 +391,23 @@ public: ::memmove(_b,_b + at,_l -= at); } + /** + * Erase something from the middle of the buffer + * + * @param start Starting position + * @param length Length of block to erase + * @throw std::out_of_range Position plus length is beyond size of buffer + */ + inline void erase(const unsigned int at,const unsigned int length) + throw(std::out_of_range) + { + const unsigned int endr = at + length; + if (endr > _l) + throw std::out_of_range("Buffer: erase() range beyond end of buffer"); + ::memmove(_b + at,_b + endr,_l - endr); + _l -= length; + } + /** * Set buffer data length to zero */ diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e892edc2..49a5981b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -933,38 +933,146 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt const uint64_t timestamp = at(ZT_PACKET_IDX_PAYLOAD + 7); const uint64_t testId = at(ZT_PACKET_IDX_PAYLOAD + 15); - unsigned int vlf = at(ZT_PACKET_IDX_PAYLOAD + 23); // variable length field length - switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) { - case 0x01: { // 64-bit network ID, originator must be controller - } break; - default: break; + // Tracks total length of variable length fields, initialized to originator credential length below + unsigned int vlf; + + // Originator credentials + const unsigned int originatorCredentialLength = vlf = at(ZT_PACKET_IDX_PAYLOAD + 23); + uint64_t originatorCredentialNetworkId = 0; + if (originatorCredentialLength >= 1) { + switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) { + case 0x01: { // 64-bit network ID, originator must be controller + if (originatorCredentialLength >= 9) + originatorCredentialNetworkId = at(ZT_PACKET_IDX_PAYLOAD + 26); + } break; + default: break; + } } - vlf += at(ZT_PACKET_IDX_PAYLOAD + 26 + vlf); // length of additional fields, currently unused + // Add length of "additional fields," which are currently unused + vlf += at(ZT_PACKET_IDX_PAYLOAD + 25 + vlf); - const unsigned int signatureLength = at(ZT_PACKET_IDX_PAYLOAD + 28 + vlf); - if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,28 + vlf),28 + vlf,field(30 + vlf,signatureLength),signatureLength)) { + // 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(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str()); return true; } vlf += signatureLength; - vlf += at(ZT_PACKET_IDX_PAYLOAD + 30 + vlf); - switch((*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf]) { - case 0x01: { // network certificate of membership for previous hop - } break; - default: break; + // Save this length so we can copy the immutable parts of this test + // into the one we send along to next hops. + const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf; + + // 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 + if (previousHopCom.deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 32 + vlf) != (previousHopCredentialLength - 1)) { + TRACE("dropped CIRCUIT_TEST from %s(%s): previous hop COM invalid",source().toString().c_str(),_remoteAddress.toString().c_str()); + return true; + } + } break; + default: break; + } } + vlf += previousHopCredentialLength; + + // Check credentials (signature already verified) + SharedPtr originatorCredentialNetworkConfig; + if (originatorCredentialNetworkId) { + if (Network::controllerFor(originatorCredentialNetworkId) == originatorAddress) { + SharedPtr nw(RR->node->network(originatorCredentialNetworkId)); + if (nw) { + originatorCredentialNetworkConfig = nw->config2(); + if ( (originatorCredentialNetworkConfig) && (originatorCredentialNetworkConfig->isPublic()||((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; + } + } else { + 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; + } + + const uint64_t now = RR->node->now(); + + unsigned int breadth = 0; + Address nextHop[256]; // breadth is a uin8_t, so this is the max + InetAddress nextHopBestPathAddress[256]; + unsigned int remainingHopsPtr = ZT_PACKET_IDX_PAYLOAD + 33 + vlf; + if ((ZT_PACKET_IDX_PAYLOAD + 31 + vlf) < size()) { + // unsigned int nextHopFlags = (*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf] + breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf]; + for(unsigned int h=0;h nhp(RR->topology->getPeer(nextHop[h])); + if (nhp) { + RemotePath *const rp = nhp->getBestPath(now); + if (rp) + nextHopBestPathAddress[h] = rp->address(); + } + } + } + + // Report back to originator, depending on flags and whether we are last hop + if ( ((flags & 0x01) != 0) || ((breadth == 0)&&((flags & 0x02) != 0)) ) { + Packet outp(originatorAddress,RR->identity.address(),Packet::VERB_CIRCUIT_TEST_REPORT); + outp.append((uint64_t)timestamp); + outp.append((uint64_t)testId); + outp.append((uint64_t)now); + outp.append((uint8_t)0); // vendor ID, currently unused + outp.append((uint8_t)ZT_PROTO_VERSION); + outp.append((uint8_t)ZEROTIER_ONE_VERSION_MAJOR); + outp.append((uint8_t)ZEROTIER_ONE_VERSION_MINOR); + outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + outp.append((uint16_t)CIRCUIT_TEST_REPORT_PLATFORM_UNSPECIFIED); + outp.append((uint16_t)CIRCUIT_TEST_REPORT_ARCH_UNSPECIFIED); + outp.append((uint16_t)0); // error code, currently unused + outp.append((uint64_t)0); // flags, currently unused + outp.append((uint64_t)packetId()); + outp.append((uint8_t)hops()); + _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,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); + 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)(size() - previousHopCredentialPos)); + } + if (remainingHopsPtr < size()) + outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr); - if ((ZT_PACKET_IDX_PAYLOAD + 33 + vlf) < size()) { - const unsigned int breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 33 + vlf]; - Address nextHops[255]; - SharedPtr nextHopPeers[255]; - unsigned int hptr = ZT_PACKET_IDX_PAYLOAD + 34 + vlf; - for(unsigned int h=0;((h256 but be safe anyway - nextHops[h].setTo(field(hptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); - hptr += ZT_ADDRESS_LENGTH; - nextHopPeers[h] = RR->topology->getPeer(nextHops[h]); + for(unsigned int h=0;hsw->send(outp,true,originatorCredentialNetworkId); } } } catch (std::exception &exc) { diff --git a/node/Packet.hpp b/node/Packet.hpp index 71fa6e56..eaffb922 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -911,39 +911,34 @@ public: * <[2] 16-bit flags> * <[8] 64-bit timestamp> * <[8] 64-bit test ID (arbitrary, set by tester)> - * <[2] 16-bit originator credential length> - * <[1] originator credential type (for authorizing test)> - * <[...] credential> + * <[2] 16-bit originator credential length (includes type)> + * [[1] originator credential type (for authorizing test)] + * [[...] originator credential] * <[2] 16-bit length of additional fields> - * <[...] additional fields> + * [[...] additional fields] * [ ... end of signed portion of request ... ] * <[2] 16-bit length of signature of request> * <[...] signature of request by originator> - * <[2] 16-bit previous hop credential length> - * <[1] previous hop credential type> - * <[...] previous hop credential> + * <[2] 16-bit previous hop credential length (including type)> + * [[1] previous hop credential type] + * [[...] previous hop credential] * <[...] next hop(s) in path> * * Flags: - * 0x01 - Report back to originator at each hop + * 0x01 - Report back to originator at middle hops * 0x02 - Report back to originator at last hop * * Originator credential types: - * 0x00 - No credentials included * 0x01 - 64-bit network ID for which originator is controller * * Previous hop credential types: - * 0x00 - No credentials included * 0x01 - Certificate of network membership * * Path record format: - * <[1] 8-bit flags> + * <[1] 8-bit flags (unused, must be zero)> * <[1] 8-bit breadth (number of next hops)> * <[...] one or more ZeroTier addresses of next hops> * - * Path record flags (in each path record): - * (unused, must be zero) - * * The circuit test allows a device to send a message that will traverse * the network along a specified path, with each hop optionally reporting * back to the tester via VERB_CIRCUIT_TEST_REPORT. @@ -1001,28 +996,19 @@ public: * <[2] 16-bit reporter OS/platform> * <[2] 16-bit reporter architecture> * <[2] 16-bit error code (set to 0, currently unused)> - * <[8] 64-bit report flags> + * <[8] 64-bit report flags (set to 0, currently unused)> * <[8] 64-bit source packet ID> - * <[1] 8-bit source packet hop count> - * <[1] 8-bit source address type> - * [<[...] source address>] - * <[2] 16-bit length of network information> - * <[...] network information> + * <[1] 8-bit source packet hop count (ZeroTier hop count)> + * <[...] local wire address on which packet was received> + * <[...] remote wire address from which packet was received> * <[2] 16-bit length of additional fields> * <[...] additional fields> - * <[2] 16-bit number of next hops to which something is being sent> + * <[1] 8-bit number of next hops (breadth)> * <[...] next hop information> * - * Circuit test report flags: - * (currently none, must be zero) - * * Next hop information record format: * <[5] ZeroTier address of next hop> - * <[1] 8-bit destination wire address type> - * <[...] destination wire address> - * - * See enums below for OS/platform and architecture. Source address format - * is the same as specified in HELLO. + * <[...] current best direct path address, if any, 0 if none> * * Circuit test reports can be sent by hops in a circuit test to report * back results. They should include information about the sender as well -- cgit v1.2.3 From d3f29d09e8eb7fdbbbed682b383da73bc44928d6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Oct 2015 14:42:51 -0700 Subject: Plumbing through circuit test stuff. --- include/ZeroTierOne.h | 271 ++++++++++++++++++++++++++++++++++++++++++++++++ node/IncomingPacket.cpp | 7 +- node/Node.cpp | 52 ++++++++++ node/Node.hpp | 12 +++ node/Packet.hpp | 38 ------- 5 files changed, 339 insertions(+), 41 deletions(-) (limited to 'node/IncomingPacket.cpp') diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 8eacc993..43c8fc0b 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -115,6 +115,19 @@ extern "C" { */ #define ZT_FEATURE_FLAG_FIPS 0x00000002 +/** + * Maximum number of hops in a ZeroTier circuit test + * + * This is more or less the max that can be fit in a given packet (with + * fragmentation) and only one address per hop. + */ +#define ZT_CIRCUIT_TEST_MAX_HOPS 512 + +/** + * Maximum number of addresses per hop in a circuit test + */ +#define ZT_CIRCUIT_TEST_MAX_HOP_BREADTH 256 + /** * A null/empty sockaddr (all zero) to signify an unspecified socket address */ @@ -631,6 +644,231 @@ typedef enum { ZT_LOCAL_INTERFACE_ADDRESS_TRUST_ULTIMATE = 20 } ZT_LocalInterfaceAddressTrust; +/** + * Vendor ID + */ +typedef enum { + ZT_VENDOR_UNSPECIFIED = 0, + ZT_VENDOR_ZEROTIER = 1 +} ZT_Vendor; + +/** + * Platform type + */ +typedef enum { + ZT_PLATFORM_UNSPECIFIED = 0, + ZT_PLATFORM_LINUX = 1, + ZT_PLATFORM_WINDOWS = 2, + ZT_PLATFORM_MACOS = 3, + ZT_PLATFORM_ANDROID = 4, + ZT_PLATFORM_IOS = 5, + ZT_PLATFORM_SOLARIS_SMARTOS = 6, + ZT_PLATFORM_FREEBSD = 7, + ZT_PLATFORM_NETBSD = 8, + ZT_PLATFORM_OPENBSD = 9, + ZT_PLATFORM_RISCOS = 10, + ZT_PLATFORM_VXWORKS = 11, + ZT_PLATFORM_FREERTOS = 12, + ZT_PLATFORM_SYSBIOS = 13, + ZT_PLATFORM_HURD = 14 +} ZT_Platform; + +/** + * Architecture type + */ +typedef enum { + ZT_ARCHITECTURE_UNSPECIFIED = 0, + ZT_ARCHITECTURE_X86 = 1, + ZT_ARCHITECTURE_X64 = 2, + ZT_ARCHITECTURE_ARM32 = 3, + ZT_ARCHITECTURE_ARM64 = 4, + ZT_ARCHITECTURE_MIPS32 = 5, + ZT_ARCHITECTURE_MIPS64 = 6, + ZT_ARCHITECTURE_POWER32 = 7, + ZT_ARCHITECTURE_POWER64 = 8 +} ZT_Architecture; + +/** + * ZeroTier circuit test configuration and path + */ +typedef struct { + /** + * Test ID -- an arbitrary 64-bit identifier + */ + uint64_t testId; + + /** + * Timestamp -- sent with test and echoed back by each reporter + */ + uint64_t timestamp; + + /** + * Originator credential: network ID + * + * If this is nonzero, a network ID will be set for this test and + * the originator must be its primary network controller. This is + * currently the only authorization method available, so it must + * be set to run a test. + */ + uint64_t credentialNetworkId; + + /** + * Hops in circuit test (a.k.a. FIFO for graph traversal) + */ + struct { + /** + * Hop flags (currently unused, must be zero) + */ + unsigned int flags; + + /** + * Number of addresses in this hop (max: ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) + */ + unsigned int breadth; + + /** + * 40-bit ZeroTier addresses (most significant 24 bits ignored) + */ + uint64_t addresses[ZT_CIRCUIT_TEST_MAX_HOP_BREADTH]; + } hops[ZT_CIRCUIT_TEST_MAX_HOPS]; + + /** + * Number of hops (max: ZT_CIRCUIT_TEST_MAX_HOPS) + */ + unsigned int hopCount; + + /** + * If non-zero, circuit test will report back at every hop + */ + int reportAtEveryHop; + + /** + * An arbitrary user-settable pointer + */ + void *ptr; + + /** + * Pointer for internal use -- initialize to zero and do not modify + */ + void *_internalPtr; +} ZT_CircuitTest; + +/** + * Circuit test result report + */ +typedef struct { + /** + * 64-bit test ID + */ + uint64_t testId; + + /** + * Timestamp from original test (echoed back at each hop) + */ + uint64_t timestamp; + + /** + * Timestamp on remote device + */ + uint64_t remoteTimestamp; + + /** + * 64-bit packet ID of packet received by the reporting device + */ + uint64_t sourcePacketId; + + /** + * Flags (currently unused, will be zero) + */ + uint64_t flags; + + /** + * ZeroTier protocol-level hop count of packet received by reporting device (>0 indicates relayed) + */ + unsigned int sourcePacketHopCount; + + /** + * Error code (currently unused, will be zero) + */ + unsigned int errorCode; + + /** + * Remote device vendor ID + */ + ZT_Vendor vendor; + + /** + * Remote device protocol compliance version + */ + unsigned int protocolVersion; + + /** + * Software major version + */ + unsigned int majorVersion; + + /** + * Software minor version + */ + unsigned int minorVersion; + + /** + * Software revision + */ + unsigned int revision; + + /** + * Platform / OS + */ + ZT_Platform platform; + + /** + * System architecture + */ + ZT_Architecture architecture; + + /** + * Local device address on which packet was received by reporting device + * + * This may have ss_family equal to zero (null address) if unspecified. + */ + struct sockaddr_storage receivedOnLocalAddress; + + /** + * Remote address from which reporter received the test packet + * + * This may have ss_family set to zero (null address) if unspecified. + */ + struct sockaddr_storage receivedFromAddress; + + /** + * Next hops to which packets are being or will be sent by the reporter + * + * In addition to reporting back, the reporter may send the test on if + * there are more recipients in the FIFO. If it does this, it can report + * back the address(es) that make up the next hop and the physical address + * for each if it has one. The physical address being null/unspecified + * typically indicates that no direct path exists and the next packet + * will be relayed. + */ + struct { + /** + * 40-bit ZeroTier address + */ + uint64_t address; + + /** + * Physical address or null address (ss_family == 0) if unspecified or unknown + */ + struct sockaddr_storage physicalAddress; + } nextHops[ZT_CIRCUIT_TEST_MAX_HOP_BREADTH]; + + /** + * Number of next hops reported in nextHops[] + */ + unsigned int nextHopCount; +} ZT_CircuitTestReport; + /** * An instance of a ZeroTier One node (opaque) */ @@ -1061,6 +1299,39 @@ void ZT_Node_clearLocalInterfaceAddresses(ZT_Node *node); */ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); +/** + * Initiate a VL1 circuit test + * + * This sends an initial VERB_CIRCUIT_TEST and reports results back to the + * supplied callback until circuitTestEnd() is called. The supplied + * ZT_CircuitTest structure should be initially zeroed and then filled + * in with settings and hops. + * + * It is the caller's responsibility to call circuitTestEnd() and then + * to dispose of the test structure. Otherwise this node will listen + * for results forever. + * + * @param node Node instance + * @param test Test configuration + * @param reportCallback Function to call each time a report is received + * @return OK or error if, for example, test is too big for a packet or support isn't compiled in + */ +ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); + +/** + * Stop listening for results to a given circuit test + * + * This does not free the 'test' structure. The caller may do that + * after calling this method to unregister it. + * + * Any reports that are received for a given test ID after it is + * terminated are ignored. + * + * @param node Node instance + * @param test Test configuration to unregister + */ +void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test); + /** * Get ZeroTier One version * diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 49a5981b..c8e4cf5f 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -30,6 +30,7 @@ #include #include "../version.h" +#include "../include/ZeroTierOne.h" #include "Constants.hpp" #include "Defaults.hpp" @@ -1033,13 +1034,13 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt outp.append((uint64_t)timestamp); outp.append((uint64_t)testId); outp.append((uint64_t)now); - outp.append((uint8_t)0); // vendor ID, currently unused + outp.append((uint8_t)ZT_VENDOR_ZEROTIER); outp.append((uint8_t)ZT_PROTO_VERSION); outp.append((uint8_t)ZEROTIER_ONE_VERSION_MAJOR); outp.append((uint8_t)ZEROTIER_ONE_VERSION_MINOR); outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - outp.append((uint16_t)CIRCUIT_TEST_REPORT_PLATFORM_UNSPECIFIED); - outp.append((uint16_t)CIRCUIT_TEST_REPORT_ARCH_UNSPECIFIED); + 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)0); // flags, currently unused outp.append((uint64_t)packetId()); diff --git a/node/Node.cpp b/node/Node.cpp index 6dc83d4e..cd20972b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -464,6 +464,28 @@ void Node::setNetconfMaster(void *networkControllerInstance) RR->localNetworkController = reinterpret_cast(networkControllerInstance); } +ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +{ + { + test->_internalPtr = reinterpret_cast(reportCallback); + Mutex::Lock _l(_circuitTests_m); + if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end()) + _circuitTests.push_back(test); + } + return ZT_RESULT_OK; +} + +void Node::circuitTestEnd(ZT_CircuitTest *test) +{ + Mutex::Lock _l(_circuitTests_m); + for(;;) { + std::vector< ZT_CircuitTest * >::iterator ct(std::find(_circuitTests.begin(),_circuitTests.end(),test)); + if (ct == _circuitTests.end()) + break; + else _circuitTests.erase(ct); + } +} + /****************************************************************************/ /* Node methods used only within node/ */ /****************************************************************************/ @@ -533,6 +555,20 @@ uint64_t Node::prng() return _prngStream[p]; } +void Node::postCircuitTestReport(const ZT_CircuitTestReport *report) +{ + std::vector< ZT_CircuitTest * > toNotify; + { + Mutex::Lock _l(_circuitTests_m); + for(std::vector< ZT_CircuitTest * >::iterator i(_circuitTests.begin());i!=_circuitTests.end();++i) { + if ((*i)->testId == report->testId) + toNotify.push_back(*i); + } + } + for(std::vector< ZT_CircuitTest * >::iterator i(toNotify.begin());i!=toNotify.end();++i) + (reinterpret_cast((*i)->_internalPtr))(reinterpret_cast(this),*i,report); +} + } // namespace ZeroTier /****************************************************************************/ @@ -721,6 +757,22 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) } catch ( ... ) {} } +ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) +{ + try { + return reinterpret_cast(node)->circuitTestBegin(test,reportCallback); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } +} + +void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test) +{ + try { + reinterpret_cast(node)->circuitTestEnd(test); + } catch ( ... ) {} +} + int ZT_Node_addLocalInterfaceAddress(ZT_Node *node,const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust) { try { diff --git a/node/Node.hpp b/node/Node.hpp index 0f659f47..20c54471 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -109,6 +109,8 @@ public: int addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT_LocalInterfaceAddressTrust trust); void clearLocalInterfaceAddresses(); void setNetconfMaster(void *networkControllerInstance); + ZT_ResultCode circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)); + void circuitTestEnd(ZT_CircuitTest *test); // Internal functions ------------------------------------------------------ @@ -238,6 +240,13 @@ public: */ uint64_t prng(); + /** + * Post a circuit test report to any listeners for a given test ID + * + * @param report Report (includes test ID) + */ + void postCircuitTestReport(const ZT_CircuitTestReport *report); + private: inline SharedPtr _network(uint64_t nwid) const { @@ -264,6 +273,9 @@ private: std::vector< std::pair< uint64_t, SharedPtr > > _networks; Mutex _networks_m; + std::vector< ZT_CircuitTest * > _circuitTests; + Mutex _circuitTests_m; + std::vector _directPaths; Mutex _directPaths_m; diff --git a/node/Packet.hpp b/node/Packet.hpp index eaffb922..409762c7 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -1020,44 +1020,6 @@ public: VERB_CIRCUIT_TEST_REPORT = 18 }; - /** - * Platforms reported in circuit tests - */ - enum CircuitTestReportPlatform - { - CIRCUIT_TEST_REPORT_PLATFORM_UNSPECIFIED = 0, - CIRCUIT_TEST_REPORT_PLATFORM_LINUX = 1, - CIRCUIT_TEST_REPORT_PLATFORM_WINDOWS = 2, - CIRCUIT_TEST_REPORT_PLATFORM_MACOS = 3, - CIRCUIT_TEST_REPORT_PLATFORM_ANDROID = 4, - CIRCUIT_TEST_REPORT_PLATFORM_IOS = 5, - CIRCUIT_TEST_REPORT_PLATFORM_SOLARIS_SMARTOS = 6, - CIRCUIT_TEST_REPORT_PLATFORM_FREEBSD = 7, - CIRCUIT_TEST_REPORT_PLATFORM_NETBSD = 8, - CIRCUIT_TEST_REPORT_PLATFORM_OPENBSD = 9, - CIRCUIT_TEST_REPORT_PLATFORM_RISCOS = 10, - CIRCUIT_TEST_REPORT_PLATFORM_VXWORKS = 11, - CIRCUIT_TEST_REPORT_PLATFORM_FREERTOS = 12, - CIRCUIT_TEST_REPORT_PLATFORM_SYSBIOS = 13, - CIRCUIT_TEST_REPORT_PLATFORM_HURD = 14 - }; - - /** - * Architectures reported in circuit tests - */ - enum CircuitTestReportArchitecture - { - CIRCUIT_TEST_REPORT_ARCH_UNSPECIFIED = 0, - CIRCUIT_TEST_REPORT_ARCH_X86 = 1, - CIRCUIT_TEST_REPORT_ARCH_X64 = 2, - CIRCUIT_TEST_REPORT_ARCH_ARM32 = 3, - CIRCUIT_TEST_REPORT_ARCH_ARM64 = 4, - CIRCUIT_TEST_REPORT_ARCH_MIPS32 = 5, - CIRCUIT_TEST_REPORT_ARCH_MIPS64 = 6, - CIRCUIT_TEST_REPORT_ARCH_POWER32 = 7, - CIRCUIT_TEST_REPORT_ARCH_POWER64 = 8 - }; - /** * Error codes for VERB_ERROR */ -- cgit v1.2.3 From 3593fb3462f277cca9241563ac0b97ade1582c91 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Tue, 6 Oct 2015 15:16:41 -0700 Subject: Send initial CIRCUIT_TEST packet. --- node/IncomingPacket.cpp | 2 +- node/Node.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) (limited to 'node/IncomingPacket.cpp') diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index c8e4cf5f..305232ee 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -988,7 +988,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt SharedPtr nw(RR->node->network(originatorCredentialNetworkId)); if (nw) { originatorCredentialNetworkConfig = nw->config2(); - if ( (originatorCredentialNetworkConfig) && (originatorCredentialNetworkConfig->isPublic()||((originatorCredentialNetworkConfig->com())&&(previousHopCom)&&(originatorCredentialNetworkConfig->com().agreesWith(previousHopCom)))) ) { + if ( (originatorCredentialNetworkConfig) && ((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()); diff --git a/node/Node.cpp b/node/Node.cpp index cd20972b..d5cc50b9 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -466,12 +466,48 @@ void Node::setNetconfMaster(void *networkControllerInstance) ZT_ResultCode Node::circuitTestBegin(ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)) { + if (test->hopCount > 0) { + try { + Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST); + RR->identity.address().appendTo(outp); + outp.append((uint16_t)((test->reportAtEveryHop != 0) ? 0x03 : 0x02)); + outp.append((uint64_t)test->timestamp); + outp.append((uint64_t)test->testId); + outp.append((uint16_t)0); // originator credential length, updated later + if (test->credentialNetworkId) { + outp.append((uint8_t)0x01); + outp.append((uint64_t)test->credentialNetworkId); + outp.setAt(ZT_PACKET_IDX_PAYLOAD + 23,(uint16_t)9); + } + outp.append((uint16_t)0); + C25519::Signature sig(RR->identity.sign(reinterpret_cast(outp.data()) + ZT_PACKET_IDX_PAYLOAD,outp.size() - ZT_PACKET_IDX_PAYLOAD)); + outp.append((uint16_t)sig.size()); + outp.append(sig.data,sig.size()); + outp.append((uint16_t)0); // originator doesn't need an extra credential, since it's the originator + for(unsigned int h=1;hhopCount;++h) { + outp.append((uint8_t)0); + outp.append((uint8_t)(test->hops[h].breadth & 0xff)); + for(unsigned int a=0;ahops[h].breadth;++a) + Address(test->hops[h].addresses[a]).appendTo(outp); + } + + for(unsigned int a=0;ahops[0].breadth;++a) { + outp.newInitializationVector(); + outp.setDestination(Address(test->hops[0].addresses[a])); + RR->sw->send(outp,true,test->credentialNetworkId); + } + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet + } + } + { test->_internalPtr = reinterpret_cast(reportCallback); Mutex::Lock _l(_circuitTests_m); if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end()) _circuitTests.push_back(test); } + return ZT_RESULT_OK; } -- cgit v1.2.3