summaryrefslogtreecommitdiff
path: root/node/IncomingPacket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'node/IncomingPacket.cpp')
-rw-r--r--node/IncomingPacket.cpp94
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);