diff options
Diffstat (limited to 'node/PacketDecoder.cpp')
-rw-r--r-- | node/PacketDecoder.cpp | 159 |
1 files changed, 42 insertions, 117 deletions
diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index c024532b..9ae7270d 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -124,73 +124,6 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r) } } -void PacketDecoder::_CBaddPeerFromHello(void *arg,const SharedPtr<Peer> &p,Topology::PeerVerifyResult result) -{ - _CBaddPeerFromHello_Data *req = (_CBaddPeerFromHello_Data *)arg; - const RuntimeEnvironment *_r = req->renv; - - try { - switch(result) { - case Topology::PEER_VERIFY_ACCEPTED_NEW: - case Topology::PEER_VERIFY_ACCEPTED_ALREADY_HAVE: - case Topology::PEER_VERIFY_ACCEPTED_DISPLACED_INVALID_ADDRESS: { - _r->sw->doAnythingWaitingForPeer(p); - Packet outp(req->source,_r->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_HELLO); - outp.append(req->helloPacketId); - outp.append(req->helloTimestamp); - outp.append((unsigned char)ZT_PROTO_VERSION); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - outp.armor(p->key(),true); - _r->demarc->send(req->localPort,req->remoteAddress,outp.data(),outp.size(),-1); - } break; - - case Topology::PEER_VERIFY_REJECTED_INVALID_IDENTITY: { - Packet outp(req->source,_r->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_HELLO); - outp.append(req->helloPacketId); - outp.append((unsigned char)Packet::ERROR_IDENTITY_INVALID); - outp.armor(p->key(),true); - _r->demarc->send(req->localPort,req->remoteAddress,outp.data(),outp.size(),-1); - } break; - - case Topology::PEER_VERIFY_REJECTED_DUPLICATE: - case Topology::PEER_VERIFY_REJECTED_DUPLICATE_TRIAGED: { - Packet outp(req->source,_r->identity.address(),Packet::VERB_ERROR); - outp.append((unsigned char)Packet::VERB_HELLO); - outp.append(req->helloPacketId); - outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION); - outp.armor(p->key(),true); - _r->demarc->send(req->localPort,req->remoteAddress,outp.data(),outp.size(),-1); - } break; - } - } catch ( ... ) { - TRACE("unexpected exception in addPeer() result callback for peer received via HELLO"); - } - - delete req; -} - -void PacketDecoder::_CBaddPeerFromWhois(void *arg,const SharedPtr<Peer> &p,Topology::PeerVerifyResult result) -{ - const RuntimeEnvironment *_r = (const RuntimeEnvironment *)arg; - try { - switch(result) { - case Topology::PEER_VERIFY_ACCEPTED_NEW: - case Topology::PEER_VERIFY_ACCEPTED_ALREADY_HAVE: - case Topology::PEER_VERIFY_ACCEPTED_DISPLACED_INVALID_ADDRESS: - _r->sw->doAnythingWaitingForPeer(p); - break; - default: - break; - } - } catch ( ... ) { - TRACE("unexpected exception in addPeer() result callback for peer received via OK(WHOIS)"); - } -} - bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer) { try { @@ -205,7 +138,6 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr<Peer> } break; case Packet::ERROR_IDENTITY_COLLISION: - case Packet::ERROR_IDENTITY_INVALID: // TODO: if it comes from a supernode, regenerate a new identity break; case Packet::ERROR_NO_MEMBER_CERTIFICATE: @@ -225,67 +157,59 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr<Peer> bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r) { try { - //unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; + unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION); uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); Identity id(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); - // Initial sniff test for valid addressing and that this is indeed the - // submitter's identity. - if ((id.address().isReserved())||(id.address() != source())) { -#ifdef ZT_TRACE - if (id.address().isReserved()) { - TRACE("dropped HELLO from %s(%s): identity has reserved address",source().toString().c_str(),_remoteAddress.toString().c_str()); - } else { - TRACE("dropped HELLO from %s(%s): identity is not for sender of packet (HELLO is a self-announcement)",source().toString().c_str(),_remoteAddress.toString().c_str()); - } -#endif + if (protoVersion != ZT_PROTO_VERSION) { + TRACE("dropped HELLO from %s(%s): protocol version mismatch (%u, expected %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),protoVersion,(unsigned int)ZT_PROTO_VERSION); return true; } - // Is this a HELLO for a peer we already know? If so just update its - // packet receive stats and send an OK. - SharedPtr<Peer> existingPeer(_r->topology->getPeer(id.address())); - if ((existingPeer)&&(existingPeer->identity() == id)) { - existingPeer->onReceive(_r,_localPort,_remoteAddress,hops(),Packet::VERB_HELLO,Utils::now()); - existingPeer->setRemoteVersion(vMajor,vMinor,vRevision); - - Packet outp(source(),_r->identity.address(),Packet::VERB_OK); - outp.append((unsigned char)Packet::VERB_HELLO); - outp.append(packetId()); - outp.append(timestamp); - outp.append((unsigned char)ZT_PROTO_VERSION); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); - outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); - outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); - outp.armor(existingPeer->key(),true); - _r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1); + if (!id.locallyValidate()) { + TRACE("dropped HELLO from %s(%s): identity invalid",source().toString().c_str(),_remoteAddress.toString().c_str()); return true; } - SharedPtr<Peer> candidate(new Peer(_r->identity,id)); - candidate->setPathAddress(_remoteAddress,false); - candidate->setRemoteVersion(vMajor,vMinor,vRevision); - - _CBaddPeerFromHello_Data *arg = new _CBaddPeerFromHello_Data; - arg->renv = _r; - arg->source = source(); - arg->remoteAddress = _remoteAddress; - arg->localPort = _localPort; - arg->vMajor = vMajor; - arg->vMinor = vMinor; - arg->vRevision = vRevision; - arg->helloPacketId = packetId(); - arg->helloTimestamp = timestamp; - _r->topology->addPeer(candidate,&PacketDecoder::_CBaddPeerFromHello,arg); + SharedPtr<Peer> peer(_r->topology->getPeer(id.address())); + if (peer) { + if (peer->identity() != id) { + unsigned char key[ZT_PEER_SECRET_KEY_LENGTH]; + if (_r->identity.agree(id,key,ZT_PEER_SECRET_KEY_LENGTH)) { + TRACE("rejected HELLO from %s(%s): address already claimed",source().toString().c_str(),_remoteAddress.toString().c_str()); + + Packet outp(source(),_r->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); + _r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1); + } + return true; + } + } else peer = _r->topology->addPeer(SharedPtr<Peer>(new Peer(_r->identity,id))); + + peer->onReceive(_r,_localPort,_remoteAddress,hops(),Packet::VERB_HELLO,Utils::now()); + peer->setRemoteVersion(vMajor,vMinor,vRevision); + + Packet outp(source(),_r->identity.address(),Packet::VERB_OK); + outp.append((unsigned char)Packet::VERB_HELLO); + outp.append(packetId()); + outp.append(timestamp); + outp.append((unsigned char)ZT_PROTO_VERSION); + outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); + outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR); + outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); + outp.armor(peer->key(),true); + _r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1); } catch (std::exception &ex) { TRACE("dropped HELLO from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); } catch ( ... ) { TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str()); } - return true; } @@ -305,12 +229,13 @@ bool PacketDecoder::_doOK(const RuntimeEnvironment *_r,const SharedPtr<Peer> &pe peer->setRemoteVersion(vMajor,vMinor,vRevision); } break; case Packet::VERB_WHOIS: { - TRACE("%s(%s): OK(%s)",source().toString().c_str(),_remoteAddress.toString().c_str(),Packet::verbString(inReVerb)); + // Right now only supernodes are allowed to send OK(WHOIS) to prevent + // poisoning attacks. Further decentralization will require some other + // kind of trust mechanism. if (_r->topology->isSupernode(source())) { - // Right now, only supernodes are queried for WHOIS so we only - // accept OK(WHOIS) from supernodes. Otherwise peers could - // potentially cache-poison. - _r->topology->addPeer(SharedPtr<Peer>(new Peer(_r->identity,Identity(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY))),&PacketDecoder::_CBaddPeerFromWhois,const_cast<void *>((const void *)_r)); + Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); + if (id.locallyValidate()) + _r->sw->doAnythingWaitingForPeer(_r->topology->addPeer(SharedPtr<Peer>(new Peer(_r->identity,id)))); } } break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { |