summaryrefslogtreecommitdiff
path: root/node/IncomingPacket.cpp
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2015-10-06 11:47:16 -0700
committerAdam Ierymenko <adam.ierymenko@gmail.com>2015-10-06 11:47:16 -0700
commit5341afcdcd7d2d1ae5546ae44024d039b03ccad3 (patch)
treeee2ccf4dcea1e4925c50af6b3bbedad4e57da65a /node/IncomingPacket.cpp
parent57c857e89a1b4616ffb091b9d834c68b4b8d93d0 (diff)
downloadinfinitytier-5341afcdcd7d2d1ae5546ae44024d039b03ccad3.tar.gz
infinitytier-5341afcdcd7d2d1ae5546ae44024d039b03ccad3.zip
Handling of CIRCUIT_TEST, should be ready to test.
Diffstat (limited to 'node/IncomingPacket.cpp')
-rw-r--r--node/IncomingPacket.cpp152
1 files changed, 130 insertions, 22 deletions
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<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 7);
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
- 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<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);
- 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<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());
return true;
}
vlf += signatureLength;
- vlf += at<uint16_t>(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<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;
+ }
+
+ 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<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);
- if ((ZT_PACKET_IDX_PAYLOAD + 33 + vlf) < size()) {
- const unsigned int breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 33 + vlf];
- Address nextHops[255];
- SharedPtr<Peer> nextHopPeers[255];
- unsigned int hptr = ZT_PACKET_IDX_PAYLOAD + 34 + vlf;
- for(unsigned int h=0;((h<breadth)&&(h<255));++h) { // breadth can't actually be >256 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;h<breadth;++h) {
+ outp.newInitializationVector();
+ outp.setDestination(nextHop[h]);
+ RR->sw->send(outp,true,originatorCredentialNetworkId);
}
}
} catch (std::exception &exc) {