Handling of CIRCUIT_TEST, should be ready to test.

This commit is contained in:
Adam Ierymenko 2015-10-06 11:47:16 -07:00
parent 57c857e89a
commit 5341afcdcd
3 changed files with 162 additions and 51 deletions

View File

@ -391,6 +391,23 @@ public:
::memmove(_b,_b + at,_l -= at); ::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 * Set buffer data length to zero
*/ */

View File

@ -933,38 +933,146 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
const uint64_t timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 7); const uint64_t timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 7);
const uint64_t testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 15); const uint64_t testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 15);
unsigned int vlf = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 23); // variable length field length // Tracks total length of variable length fields, initialized to originator credential length below
switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) { unsigned int vlf;
case 0x01: { // 64-bit network ID, originator must be controller
} break; // Originator credentials
default: break; const unsigned int originatorCredentialLength = vlf = at<uint16_t>(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<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 26);
} break;
default: break;
}
} }
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 26 + vlf); // length of additional fields, currently unused // Add length of "additional fields," which are currently unused
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 25 + vlf);
const unsigned int signatureLength = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 28 + vlf); // Verify signature -- only tests signed by their originators are allowed
if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,28 + vlf),28 + vlf,field(30 + vlf,signatureLength),signatureLength)) { const unsigned int signatureLength = at<uint16_t>(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()); 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; return true;
} }
vlf += signatureLength; vlf += signatureLength;
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 30 + vlf); // Save this length so we can copy the immutable parts of this test
switch((*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf]) { // into the one we send along to next hops.
case 0x01: { // network certificate of membership for previous hop const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf;
} break;
default: break; // Get previous hop's credential, if any
const unsigned int previousHopCredentialLength = at<uint16_t>(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<NetworkConfig> originatorCredentialNetworkConfig;
if (originatorCredentialNetworkId) {
if (Network::controllerFor(originatorCredentialNetworkId) == originatorAddress) {
SharedPtr<Network> 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;
} }
if ((ZT_PACKET_IDX_PAYLOAD + 33 + vlf) < size()) { const uint64_t now = RR->node->now();
const unsigned int breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 33 + vlf];
Address nextHops[255]; unsigned int breadth = 0;
SharedPtr<Peer> nextHopPeers[255]; Address nextHop[256]; // breadth is a uin8_t, so this is the max
unsigned int hptr = ZT_PACKET_IDX_PAYLOAD + 34 + vlf; InetAddress nextHopBestPathAddress[256];
for(unsigned int h=0;((h<breadth)&&(h<255));++h) { // breadth can't actually be >256 but be safe anyway unsigned int remainingHopsPtr = ZT_PACKET_IDX_PAYLOAD + 33 + vlf;
nextHops[h].setTo(field(hptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); if ((ZT_PACKET_IDX_PAYLOAD + 31 + vlf) < size()) {
hptr += ZT_ADDRESS_LENGTH; // unsigned int nextHopFlags = (*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf]
nextHopPeers[h] = RR->topology->getPeer(nextHops[h]); breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf];
for(unsigned int h=0;h<breadth;++h) {
nextHop[h].setTo(field(remainingHopsPtr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
remainingHopsPtr += ZT_ADDRESS_LENGTH;
SharedPtr<Peer> 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;h<breadth;++h) {
nextHop[h].appendTo(outp);
nextHopBestPathAddress[h].serialize(outp); // appends 0 if null InetAddress
}
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);
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<uint16_t>(previousHopCredentialPos,(uint16_t)(size() - previousHopCredentialPos));
}
if (remainingHopsPtr < size())
outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr);
for(unsigned int h=0;h<breadth;++h) {
outp.newInitializationVector();
outp.setDestination(nextHop[h]);
RR->sw->send(outp,true,originatorCredentialNetworkId);
} }
} }
} catch (std::exception &exc) { } catch (std::exception &exc) {

View File

@ -911,39 +911,34 @@ public:
* <[2] 16-bit flags> * <[2] 16-bit flags>
* <[8] 64-bit timestamp> * <[8] 64-bit timestamp>
* <[8] 64-bit test ID (arbitrary, set by tester)> * <[8] 64-bit test ID (arbitrary, set by tester)>
* <[2] 16-bit originator credential length> * <[2] 16-bit originator credential length (includes type)>
* <[1] originator credential type (for authorizing test)> * [[1] originator credential type (for authorizing test)]
* <[...] credential> * [[...] originator credential]
* <[2] 16-bit length of additional fields> * <[2] 16-bit length of additional fields>
* <[...] additional fields> * [[...] additional fields]
* [ ... end of signed portion of request ... ] * [ ... end of signed portion of request ... ]
* <[2] 16-bit length of signature of request> * <[2] 16-bit length of signature of request>
* <[...] signature of request by originator> * <[...] signature of request by originator>
* <[2] 16-bit previous hop credential length> * <[2] 16-bit previous hop credential length (including type)>
* <[1] previous hop credential type> * [[1] previous hop credential type]
* <[...] previous hop credential> * [[...] previous hop credential]
* <[...] next hop(s) in path> * <[...] next hop(s) in path>
* *
* Flags: * 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 * 0x02 - Report back to originator at last hop
* *
* Originator credential types: * Originator credential types:
* 0x00 - No credentials included
* 0x01 - 64-bit network ID for which originator is controller * 0x01 - 64-bit network ID for which originator is controller
* *
* Previous hop credential types: * Previous hop credential types:
* 0x00 - No credentials included
* 0x01 - Certificate of network membership * 0x01 - Certificate of network membership
* *
* Path record format: * Path record format:
* <[1] 8-bit flags> * <[1] 8-bit flags (unused, must be zero)>
* <[1] 8-bit breadth (number of next hops)> * <[1] 8-bit breadth (number of next hops)>
* <[...] one or more ZeroTier addresses 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 circuit test allows a device to send a message that will traverse
* the network along a specified path, with each hop optionally reporting * the network along a specified path, with each hop optionally reporting
* back to the tester via VERB_CIRCUIT_TEST_REPORT. * back to the tester via VERB_CIRCUIT_TEST_REPORT.
@ -1001,28 +996,19 @@ public:
* <[2] 16-bit reporter OS/platform> * <[2] 16-bit reporter OS/platform>
* <[2] 16-bit reporter architecture> * <[2] 16-bit reporter architecture>
* <[2] 16-bit error code (set to 0, currently unused)> * <[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> * <[8] 64-bit source packet ID>
* <[1] 8-bit source packet hop count> * <[1] 8-bit source packet hop count (ZeroTier hop count)>
* <[1] 8-bit source address type> * <[...] local wire address on which packet was received>
* [<[...] source address>] * <[...] remote wire address from which packet was received>
* <[2] 16-bit length of network information>
* <[...] network information>
* <[2] 16-bit length of additional fields> * <[2] 16-bit length of additional fields>
* <[...] 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> * <[...] next hop information>
* *
* Circuit test report flags:
* (currently none, must be zero)
*
* Next hop information record format: * Next hop information record format:
* <[5] ZeroTier address of next hop> * <[5] ZeroTier address of next hop>
* <[1] 8-bit destination wire address type> * <[...] current best direct path address, if any, 0 if none>
* <[...] destination wire address>
*
* See enums below for OS/platform and architecture. Source address format
* is the same as specified in HELLO.
* *
* Circuit test reports can be sent by hops in a circuit test to report * 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 * back results. They should include information about the sender as well