diff options
author | Grant Limberg <glimberg@gmail.com> | 2015-07-07 19:24:02 -0700 |
---|---|---|
committer | Grant Limberg <glimberg@gmail.com> | 2015-07-07 19:24:02 -0700 |
commit | 1ad2cfeedfa2a9f4fc1f512e1009e5bb1b0630cb (patch) | |
tree | d8264c9bd4f6b9dce3f5237b94fe1f2fc521cf19 /node/IncomingPacket.cpp | |
parent | 6d398beefddb48d91f27e5f41bf39f40eb77222f (diff) | |
parent | 412389ec755528108e0254e75a9cf43fc53e331a (diff) | |
download | infinitytier-1ad2cfeedfa2a9f4fc1f512e1009e5bb1b0630cb.tar.gz infinitytier-1ad2cfeedfa2a9f4fc1f512e1009e5bb1b0630cb.zip |
Merge branch 'adamierymenko-dev' into android-jni
Diffstat (limited to 'node/IncomingPacket.cpp')
-rw-r--r-- | node/IncomingPacket.cpp | 94 |
1 files changed, 74 insertions, 20 deletions
diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 7e2bcdaa..6c3a0932 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -84,6 +84,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR) case Packet::VERB_NETWORK_CONFIG_REFRESH: return _doNETWORK_CONFIG_REFRESH(RR,peer); 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); } } else { RR->sw->requestWhois(source()); @@ -133,6 +134,9 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer> break; case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: { + /* Note: certificates are public so it's safe to push them to anyone + * who asks. We won't communicate unless we also get a certificate + * from the remote that agrees. */ SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); if (network) { SharedPtr<NetworkConfig> nconf(network->config2()); @@ -152,7 +156,10 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer> } break; case Packet::ERROR_UNWANTED_MULTICAST: { - // TODO: unsubscribe + uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD); + MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at<uint32_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); + TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",nwid,peer->address().toString().c_str(),mg.toString().c_str()); + RR->mc->remove(nwid,mg,peer->address()); } break; default: break; @@ -169,8 +176,20 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer> bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) { + /* Note: this is the only packet ever sent in the clear, and it's also + * the only packet that we authenticate via a different path. Authentication + * occurs here and is based on the validity of the identity and the + * integrity of the packet's MAC, but it must be done after we check + * the identity since HELLO is a mechanism for learning new identities + * in the first place. */ + try { const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; + if (protoVersion < ZT_PROTO_VERSION_MIN) { + TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str()); + return true; + } + const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION); @@ -178,6 +197,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) Identity id; unsigned int destAddrPtr = id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY) + ZT_PROTO_VERB_HELLO_IDX_IDENTITY; + if (source() != id.address()) { + TRACE("dropped HELLO from %s(%s): identity not for sending address",source().toString().c_str(),_remoteAddress.toString().c_str()); + return true; + } InetAddress destAddr; if (destAddrPtr < size()) { // ZeroTier One < 1.0.3 did not include this field @@ -192,16 +215,6 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) } } - if (source() != id.address()) { - TRACE("dropped HELLO from %s(%s): identity not for sending address",source().toString().c_str(),_remoteAddress.toString().c_str()); - return true; - } - - if (protoVersion < ZT_PROTO_VERSION_MIN) { - TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str()); - return true; - } - SharedPtr<Peer> peer(RR->topology->getPeer(id.address())); if (peer) { // We already have an identity with this address -- check for collisions @@ -244,12 +257,14 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR) } else { // We don't already have an identity with this address -- validate and learn it + // Check identity proof of work if (!id.locallyValidate()) { RR->node->postEvent(ZT1_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; } + // Check packet integrity and authentication SharedPtr<Peer> newPeer(new Peer(RR->identity,id)); if (!dearmor(newPeer->key())) { RR->node->postEvent(ZT1_EVENT_AUTHENTICATION_FAILURE,(const void *)&_remoteAddress); @@ -428,7 +443,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS); SharedPtr<Network> network(RR->node->network(nwid)); if ((network)&&(com.hasRequiredFields())) - network->addMembershipCertificate(com,false); + network->validateAndAddMembershipCertificate(com); } if ((flags & 0x02) != 0) { @@ -553,14 +568,17 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P const unsigned int flags = (*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS]; unsigned int comLen = 0; + bool comFailed = false; if ((flags & 0x01) != 0) { CertificateOfMembership com; comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM); - if (com.hasRequiredFields()) - network->addMembershipCertificate(com,false); + if (com.hasRequiredFields()) { + if (!network->validateAndAddMembershipCertificate(com)) + comFailed = true; // technically this check is redundant to isAllowed(), but do it anyway for thoroughness + } } - if (!network->isAllowed(peer->address())) { + if ((comFailed)||(!network->isAllowed(peer->address()))) { 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; @@ -595,9 +613,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: sender not allowed to bridge into %.16llx",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); return true; } - } - - if (to != network->mac()) { + } else if (to != network->mac()) { if (!network->permitsBridging(RR->identity.address())) { TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: I cannot bridge to %.16llx or bridging disabled on network",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str(),network->id()); return true; @@ -649,7 +665,7 @@ bool IncomingPacket::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment if (com.hasRequiredFields()) { SharedPtr<Network> network(RR->node->network(com.networkId())); if (network) - network->addMembershipCertificate(com,false); + network->validateAndAddMembershipCertificate(com); } } @@ -807,7 +823,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share CertificateOfMembership com; offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM); if (com.hasRequiredFields()) - network->addMembershipCertificate(com,false); + network->validateAndAddMembershipCertificate(com); } // Check membership after we've read any included COM, since @@ -884,6 +900,44 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share return true; } +bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer) +{ + try { + unsigned int count = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD); + unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; + + while (count) { // if ptr overflows Buffer will throw + // TODO: properly handle blacklisting, support other features... see Packet.hpp. + + unsigned int flags = (*this)[ptr++]; + /*int metric = (*this)[ptr++];*/ ++ptr; + unsigned int extLen = at<uint16_t>(ptr); ptr += 2; + ptr += extLen; // unused right now + unsigned int addrType = (*this)[ptr++]; + + unsigned int addrLen = (*this)[ptr++]; + switch(addrType) { + case 4: { + InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4)); + if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) + peer->attemptToContactAt(RR,a,RR->node->now()); + } break; + case 6: { + InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16)); + if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) + peer->attemptToContactAt(RR,a,RR->node->now()); + } break; + } + ptr += addrLen; + } + } catch (std::exception &exc) { + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what()); + } catch ( ... ) { + TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): unexpected exception: (unknown)",source().toString().c_str(),_remoteAddress.toString().c_str()); + } + return true; +} + void IncomingPacket::_sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer,uint64_t nwid) { Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); |