diff --git a/node/Locator.cpp b/node/Locator.cpp index 94ad49b8c..76a9cc0ca 100644 --- a/node/Locator.cpp +++ b/node/Locator.cpp @@ -42,8 +42,9 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE)) return -1; - Utils::storeBigEndian(data,_ts); - int p = 8; + data[0] = 0xff; // version byte, currently 0xff to never be the same as byte 0 of an identity for legacy compatibility reasons + Utils::storeBigEndian(data + 1,_ts); + int p = 9; if (_ts > 0) { Utils::storeBigEndian(data + p,(uint16_t)_endpointCount); @@ -71,11 +72,13 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool exclud int Locator::unmarshal(const uint8_t *restrict data,const int len) noexcept { - if (len <= (8 + 2 + 48)) + if (len <= (1 + 8 + 2 + 48)) return -1; - _ts = Utils::loadBigEndian(data); - int p = 8; + if (data[0] != 0xff) + return -1; + _ts = Utils::loadBigEndian(data + 1); + int p = 9; if (_ts > 0) { const unsigned int ec = Utils::loadBigEndian(data + p); diff --git a/node/Locator.hpp b/node/Locator.hpp index 8041a3338..f4db23804 100644 --- a/node/Locator.hpp +++ b/node/Locator.hpp @@ -24,7 +24,7 @@ #include "TriviallyCopyable.hpp" #define ZT_LOCATOR_MAX_ENDPOINTS 8 -#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE) +#define ZT_LOCATOR_MARSHAL_SIZE_MAX (1 + 8 + 2 + (ZT_ENDPOINT_MARSHAL_SIZE_MAX * ZT_LOCATOR_MAX_ENDPOINTS) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE) namespace ZeroTier { diff --git a/node/Peer.cpp b/node/Peer.cpp index c14421947..04f8354f7 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -72,7 +72,8 @@ void Peer::received( const unsigned int hops, const uint64_t packetId, const unsigned int payloadLength, - const Protocol::Verb verb) + const Protocol::Verb verb, + const Protocol::Verb inReVerb) { const int64_t now = RR->node->now(); _lastReceive = now; @@ -240,7 +241,7 @@ void Peer::sendNOP(void *tPtr,const int64_t localSocket,const InetAddress &atAdd RR->identity.address().copyTo(ph.source); ph.flags = 0; ph.verb = Protocol::VERB_NOP; - Protocol::armor(outp,sizeof(Protocol::Header),_key,ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); + Protocol::armor(outp,sizeof(Protocol::Header),_key,this->cipher()); RR->node->putPacket(tPtr,localSocket,atAddress,outp.b,sizeof(Protocol::Header)); } @@ -354,7 +355,7 @@ void Peer::save(void *tPtr) const free(buf); } -void Peer::contact(void *tPtr,const Endpoint &ep,const int64_t now,bool behindSymmetric,bool bfg1024) +void Peer::contact(void *tPtr,const Endpoint &ep,const int64_t now,const bool behindSymmetric,const bool bfg1024) { static uint8_t junk = 0; diff --git a/node/Peer.hpp b/node/Peer.hpp index 697307c14..9692b23a1 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -101,6 +101,7 @@ public: * @param hops ZeroTier (not IP) hops * @param packetId Packet ID * @param verb Packet verb + * @param inReVerb In-reply verb for OK or ERROR verbs */ void received( void *tPtr, @@ -108,7 +109,8 @@ public: unsigned int hops, uint64_t packetId, unsigned int payloadLength, - Protocol::Verb verb); + Protocol::Verb verb, + Protocol::Verb inReVerb); /** * Send a HELLO to this peer at a specified physical address @@ -207,6 +209,14 @@ public: */ ZT_ALWAYS_INLINE const unsigned char *key() const noexcept { return _key; } + /** + * @return Preferred cipher suite for normal encrypted P2P communication + */ + ZT_ALWAYS_INLINE uint8_t cipher() const noexcept + { + return ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012; + } + /** * @return Incoming probe packet (in big-endian byte order) 0 */ diff --git a/node/Protocol.hpp b/node/Protocol.hpp index ec1a729d4..3cbbe8346 100644 --- a/node/Protocol.hpp +++ b/node/Protocol.hpp @@ -305,43 +305,42 @@ enum Verb * <[...] meta-data dictionary> * <[2] 16-bit length of any additional fields> * [... end encrypted region ...] - * <[48] HMAC-SHA384 of full plaintext payload> + * <[48] HMAC-SHA384 of packet (with hops field masked to 0)> * - * HELLO is sent with authentication but without the usual encryption so - * that peers can exchange identities. + * HELLO is sent using the POLY1305_NONE cipher setting (MAC but + * no encryption) and as of protocol version 11 contains an extra + * HMAC-SHA384 MAC for additional authentication hardening. * - * Destination address is the actual wire address to which the packet - * was sent. See InetAddress::serialize() for format. + * The physical desgination address is the raw InetAddress to which the + * packet was sent, regardless of any relaying used. * - * Starting at "begin encrypted section" the reset of the packet is - * encrypted with Salsa20/12. This is not the normal packet encryption - * and is technically not necessary as nothing in HELLO is secret. It - * exists merely to shield meta-data info from passive listeners to - * slightly improve privacy, and for backward compatibility with older - * nodes that required it. + * HELLO packets have an encrypted section that is encrypted with + * Salsa20/12 using the two peers' long-term negotiated keys and with + * the packet ID (with least significant 3 bits masked to 0 for legacy + * reasons) as the Salsa20/12 IV. This encryption is technically not + * necessary but serves to protect the privacy of locators and other + * fields for a little added defense in depth. Note to auditors: for FIPS + * or other auditing purposes this crypto can be ignored as its + * compromise poses no risk to peer or network authentication or transport + * data privacy. HMAC is computed after this encryption is performed and + * is verified before decryption is performed. * - * HELLO (and its OK response) ends with a large 384-bit HMAC to allow - * identity exchanges to be authenticated with additional strength beyond - * ordinary packet authentication. + * A valid and successfully authenticated HELLO will generate the following + * OK response which contains much of the same information about the + * responding peer. * * OK payload: - * [... HMAC-384 starts here ...] - * <[8] HELLO timestamp field echo> + * <[8] timestamp echoed from original HELLO packet> * <[1] protocol version> * <[1] software major version> * <[1] software minor version> * <[2] software revision> * <[...] physical destination address of packet> - * <[2] 16-bit reserved (legacy) field, always 0> + * <[2] 16-bit reserved (legacy) field, currently must be 0> * <[2] 16-bit length of meta-data dictionary> * <[...] meta-data dictionary> * <[2] 16-bit length of any additional fields> - * <[48] HMAC-SHA384 of all fields to this point (as plaintext)> - * - * With the exception of the timestamp, the other fields pertain to the - * respondent who is sending OK and are not echoes. - * - * ERROR has no payload. + * <[48] HMAC-SHA384 of plaintext packet (with hops masked to 0)> */ VERB_HELLO = 0x01, @@ -350,10 +349,10 @@ enum Verb * <[1] in-re verb> * <[8] in-re packet ID> * <[1] error code> - * <[...] error-dependent payload> + * <[...] error-dependent payload, may be empty> * - * If this is not in response to a single packet then verb can be - * NOP and packet ID can be zero. + * An ERROR that does not pertain to a specific packet will have its verb + * set to VERB_NOP and its packet ID set to zero. */ VERB_ERROR = 0x02, @@ -380,8 +379,7 @@ enum Verb * be performed. * * It is possible for an identity but a null/empty locator to be returned - * if no locator is known for a node. Older versions will also send no - * locator field at all. + * if no locator is known for a node. Older versions may omit the locator. */ VERB_WHOIS = 0x04, @@ -390,13 +388,19 @@ enum Verb * <[1] flags (unused, currently 0)> * <[5] ZeroTier address of peer that might be found at this address> * <[2] 16-bit protocol address port> - * <[1] protocol address length (4 for IPv4, 16 for IPv6)> + * <[1] protocol address length / type> * <[...] protocol address (network byte order)> * - * An upstream node can send this to inform both sides of a relay of - * information they might use to establish a direct connection. + * This is sent by a third party node to inform a node of where another + * may be located. These are currently only allowed from roots. * - * Upon receipt a peer sends HELLO to establish a direct link. + * The protocol address format differs from the standard InetAddress + * encoding for legacy reasons, but it's not hard to decode. The following + * values are valid for the protocol address length (type) field: + * + * 4 - IPv4 IP address + * 16 - IPv6 IP address + * 255 - Endpoint object, unmarshaled in place (port ignored) * * No OK or ERROR is generated. */ diff --git a/node/VL1.cpp b/node/VL1.cpp index b4c2eda3b..e10a7cdf3 100644 --- a/node/VL1.cpp +++ b/node/VL1.cpp @@ -335,7 +335,8 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd const Protocol::Verb verb = (Protocol::Verb)(ph->verb & ZT_PROTO_VERB_MASK); - // Note that all verbs except HELLO require MAC. + // All verbs except HELLO require authentication before being handled. The HELLO + // handler does its own authentication. if (((!authenticated)||(!peer))&&(verb != Protocol::VERB_HELLO)) { RR->t->incomingPacketDropped(tPtr,0x5b001099,ph->packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return; @@ -376,12 +377,13 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd * understand the handlers for VL2 data paths have been moved to a VL2 class. */ - bool ok = true; + bool ok = true; // set to false if a packet turns out to be invalid + Protocol::Verb inReVerb = Protocol::VERB_NOP; // set via result parameter to _ERROR and _OK switch(verb) { case Protocol::VERB_NOP: break; case Protocol::VERB_HELLO: ok = _HELLO(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); break; - case Protocol::VERB_ERROR: ok = _ERROR(tPtr,path,peer,*pkt.b,(int)packetSize); break; - case Protocol::VERB_OK: ok = _OK(tPtr,path,peer,*pkt.b,(int)packetSize); break; + case Protocol::VERB_ERROR: ok = _ERROR(tPtr,path,peer,*pkt.b,(int)packetSize,inReVerb); break; + case Protocol::VERB_OK: ok = _OK(tPtr,path,peer,*pkt.b,(int)packetSize,inReVerb); break; case Protocol::VERB_WHOIS: ok = _WHOIS(tPtr,path,peer,*pkt.b,(int)packetSize); break; case Protocol::VERB_RENDEZVOUS: ok = _RENDEZVOUS(tPtr,path,peer,*pkt.b,(int)packetSize); break; case Protocol::VERB_FRAME: ok = RR->vl2->_FRAME(tPtr,path,peer,*pkt.b,(int)packetSize); break; @@ -402,7 +404,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd break; } if (ok) - peer->received(tPtr,path,hops,ph->packetId,packetSize - ZT_PROTO_PACKET_PAYLOAD_START,verb); + peer->received(tPtr,path,hops,ph->packetId,packetSize - ZT_PROTO_PACKET_PAYLOAD_START,verb,inReVerb); } catch ( ... ) { RR->t->unexpectedError(tPtr,0xea1b6dea,"unexpected exception in onRemotePacket() parsing packet from %s",Trace::str(path->address()).s); } @@ -469,14 +471,14 @@ void VL1::_sendPendingWhois(void *const tPtr,const int64_t now) } if (outl > sizeof(Protocol::Header)) { - Protocol::armor(outp,outl,root->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); + Protocol::armor(outp,outl,root->key(),peer->cipher()); RR->expect->sending(ph.packetId,now); rootPath->send(RR,tPtr,outp.b,outl,now); } } } -bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Buf &pkt,int packetSize,bool authenticated) +bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Buf &pkt,int packetSize,const bool authenticated) { if (packetSize < sizeof(Protocol::HELLO)) { RR->t->incomingPacketDropped(tPtr,0x2bdb0001,0,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); @@ -504,7 +506,6 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu // Packet is basically valid and identity unmarshaled successfully -------------------------------------------------- - // Get long-term static key for this node. uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; if ((peer) && (id == peer->identity())) { memcpy(key,peer->key(),ZT_PEER_SECRET_KEY_LENGTH); @@ -516,8 +517,7 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu } } - // Verify packet using Poly1305 MAC - { + if ((!peer)||(!authenticated)) { uint8_t perPacketKey[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t macKey[ZT_POLY1305_KEY_LEN]; Protocol::salsa2012DeriveKey(peer->key(),perPacketKey,pkt,packetSize); @@ -538,15 +538,16 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu RR->t->incomingPacketDropped(tPtr,0x1000662a,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return false; } + packetSize -= ZT_HMACSHA384_LEN; KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,0,hmacKey); // iter == 0 for HELLO, 1 for OK(HELLO) - HMACSHA384(hmacKey,pkt.b,packetSize - ZT_HMACSHA384_LEN,hmac); - if (!Utils::secureEq(pkt.b + (packetSize - ZT_HMACSHA384_LEN),hmac,ZT_HMACSHA384_LEN)) { + HMACSHA384(hmacKey,pkt.b,packetSize,hmac); + if (!Utils::secureEq(pkt.b + packetSize,hmac,ZT_HMACSHA384_LEN)) { RR->t->incomingPacketDropped(tPtr,0x1000662a,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return false; } } - // Packet has passed HMAC-SHA384 (if present and/or forced) --------------------------------------------------------- + // Packet has passed HMAC-SHA384 (if present) ----------------------------------------------------------------------- InetAddress externalSurfaceAddress; Dictionary nodeMetaData; @@ -559,43 +560,39 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu } } - if (((ptr + ZT_HMACSHA384_LEN) < packetSize)&&(peer->remoteVersionProtocol() >= 11)) { + if ((ptr < packetSize)&&(peer->remoteVersionProtocol() >= 11)) { // Everything after this point is encrypted with Salsa20/12. This is only a privacy measure // since there's nothing truly secret in a HELLO packet. It also means that an observer // can't even get ephemeral public keys without first knowing the long term secret key, // adding a little defense in depth. uint8_t iv[8]; for (int i = 0; i < 8; ++i) iv[i] = pkt.b[i]; - iv[7] &= 0xf8U; + iv[7] &= 0xf8U; // this exists for pure legacy reasons, meh... Salsa20 s20(key,iv); - s20.crypt12(pkt.b + ptr,pkt.b + ptr,(packetSize - ZT_HMACSHA384_LEN) - ptr); + s20.crypt12(pkt.b + ptr,pkt.b + ptr,packetSize - ptr); ptr += pkt.rI16(ptr); // skip length field which currently is always zero in v2.0+ + if (ptr < packetSize) { const unsigned int dictionarySize = pkt.rI16(ptr); - const void *const dictionaryBytes = pkt.b + ptr; - if ((ptr += (int)dictionarySize) > packetSize) { - RR->t->incomingPacketDropped(tPtr,0x0d0f0112,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); + const void *const dictionaryBytes = pkt.rBnc(ptr,dictionarySize); + if (Buf::readOverflow(ptr,packetSize)) { + RR->t->incomingPacketDropped(tPtr,0x0d0f0112,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return false; } - - ptr += pkt.rI16(ptr); // skip any additional fields, currently always 0 - if (ptr > packetSize) { - RR->t->incomingPacketDropped(tPtr,0x451f2341,0,p.h.packetId,id,path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); - return false; - } - if (dictionarySize) { if (!nodeMetaData.decode(dictionaryBytes,dictionarySize)) { RR->t->incomingPacketDropped(tPtr,0x67192344,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return false; } } + + ptr += pkt.rI16(ptr); // skip any additional fields, currently always 0 } } if (Buf::readOverflow(ptr,packetSize)) { // sanity check, should be impossible - RR->t->incomingPacketDropped(tPtr,0x457f2347,0,p.h.packetId,id,path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); + RR->t->incomingPacketDropped(tPtr,0x50003470,0,p.h.packetId,id,path->address(),0,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return false; } @@ -620,6 +617,10 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu if ((hops == 0) && (externalSurfaceAddress)) RR->sa->iam(tPtr,id,path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now); + peer->setRemoteVersion(p.versionProtocol,p.versionMajor,p.versionMinor,Utils::ntoh(p.versionRev)); + + // Compose and send OK(HELLO) --------------------------------------------------------------------------------------- + std::vector myNodeMetaDataBin; { Dictionary myNodeMetaData; @@ -651,8 +652,9 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu int outl = sizeof(Protocol::OK::HELLO); outp.wO(outl,path->address()); + outp.wI(outl,(uint16_t)0); // legacy field, always 0 + if (p.versionProtocol >= 11) { - outp.wI(outl,(uint16_t)0); // legacy field, always 0 outp.wI(outl,(uint16_t)myNodeMetaDataBin.size()); outp.wB(outl,myNodeMetaDataBin.data(),(unsigned int)myNodeMetaDataBin.size()); outp.wI(outl,(uint16_t)0); // length of additional fields, currently 0 @@ -665,21 +667,20 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Bu outl += ZT_HMACSHA384_LEN; } - Protocol::armor(outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); + Protocol::armor(outp,outl,peer->key(),peer->cipher()); path->send(RR,tPtr,outp.b,outl,now); - peer->setRemoteVersion(p.versionProtocol,p.versionMajor,p.versionMinor,Utils::ntoh(p.versionRev)); - return true; } -bool VL1::_ERROR(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize) +bool VL1::_ERROR(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize,Protocol::Verb &inReVerb) { if (packetSize < sizeof(Protocol::ERROR::Header)) { RR->t->incomingPacketDropped(tPtr,0x3beb1947,0,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_ERROR,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return false; } Protocol::ERROR::Header &eh = pkt.as(); + inReVerb = (Protocol::Verb)eh.inReVerb; const int64_t now = RR->node->now(); if (!RR->expect->expecting(eh.inRePacketId,now)) { @@ -717,13 +718,14 @@ bool VL1::_ERROR(void *tPtr,const SharedPtr &path,const SharedPtr &p return true; } -bool VL1::_OK(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize) +bool VL1::_OK(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize,Protocol::Verb &inReVerb) { if (packetSize < sizeof(Protocol::OK::Header)) { RR->t->incomingPacketDropped(tPtr,0x4c1f1ff7,0,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_OK,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return false; } Protocol::OK::Header &oh = pkt.as(); + inReVerb = (Protocol::Verb)oh.inReVerb; const int64_t now = RR->node->now(); if (!RR->expect->expecting(oh.inRePacketId,now)) { @@ -793,7 +795,7 @@ bool VL1::_WHOIS(void *tPtr,const SharedPtr &path,const SharedPtr &p } if (outl > sizeof(Protocol::OK::WHOIS)) { - Protocol::armor(outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); + Protocol::armor(outp,outl,peer->key(),peer->cipher()); path->send(RR,tPtr,outp.b,outl,RR->node->now()); } } @@ -803,7 +805,6 @@ bool VL1::_WHOIS(void *tPtr,const SharedPtr &path,const SharedPtr &p bool VL1::_RENDEZVOUS(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize) { - static uint16_t junk = 0; if (RR->topology->isRoot(peer->identity())) { if (packetSize < sizeof(Protocol::RENDEZVOUS)) { RR->t->incomingPacketDropped(tPtr,0x43e90ab3,Protocol::packetId(pkt,packetSize),0,peer->identity(),path->address(),Protocol::packetHops(pkt,packetSize),Protocol::VERB_RENDEZVOUS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); @@ -813,23 +814,33 @@ bool VL1::_RENDEZVOUS(void *tPtr,const SharedPtr &path,const SharedPtr with(RR->topology->peer(tPtr,Address(rdv.peerAddress))); if (with) { + const int64_t now = RR->node->now(); const unsigned int port = Utils::ntoh(rdv.port); if (port != 0) { switch(rdv.addressLength) { case 4: - if ((sizeof(Protocol::RENDEZVOUS) + 4) <= packetSize) { - InetAddress atAddr(pkt.b + sizeof(Protocol::RENDEZVOUS),4,port); - ++junk; - RR->node->putPacket(tPtr,path->localSocket(),atAddr,(const void *)&junk,2,2); // IPv4 "firewall opener" hack - with->sendHELLO(tPtr,path->localSocket(),atAddr,RR->node->now()); + case 16: + if ((sizeof(Protocol::RENDEZVOUS) + rdv.addressLength) <= packetSize) { + const InetAddress atAddr(pkt.b + sizeof(Protocol::RENDEZVOUS),rdv.addressLength,port); + peer->contact(tPtr,Endpoint(atAddr),now,false,false); RR->t->tryingNewPath(tPtr,0x55a19aaa,with->identity(),atAddr,path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS); } break; - case 16: - if ((sizeof(Protocol::RENDEZVOUS) + 16) <= packetSize) { - InetAddress atAddr(pkt.b + sizeof(Protocol::RENDEZVOUS),16,port); - with->sendHELLO(tPtr,path->localSocket(),atAddr,RR->node->now()); - RR->t->tryingNewPath(tPtr,0x54bada09,with->identity(),atAddr,path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS); + case 255: + if ((sizeof(Protocol::RENDEZVOUS) + 1) <= packetSize) { + Endpoint ep; + int epl = ep.unmarshal(pkt.b + sizeof(Protocol::RENDEZVOUS),packetSize - (int)sizeof(Protocol::RENDEZVOUS)); + if ((epl > 0) && (ep)) { + switch (ep.type()) { + case Endpoint::INETADDR_V4: + case Endpoint::INETADDR_V6: + peer->contact(tPtr,ep,now,false,false); + RR->t->tryingNewPath(tPtr,0x55a19aab,with->identity(),ep.inetAddr(),path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS); + break; + default: + break; + } + } } break; } @@ -847,6 +858,7 @@ bool VL1::_ECHO(void *tPtr,const SharedPtr &path,const SharedPtr &pe RR->t->incomingPacketDropped(tPtr,0x14d70bb0,packetId,0,peer->identity(),path->address(),Protocol::packetHops(pkt,packetSize),Protocol::VERB_ECHO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET); return false; } + if (peer->rateGateEchoRequest(now)) { Buf outp; Protocol::OK::ECHO &outh = outp.as(); @@ -865,11 +877,12 @@ bool VL1::_ECHO(void *tPtr,const SharedPtr &path,const SharedPtr &pe return false; } - Protocol::armor(outp,outl,peer->key(),ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012); + Protocol::armor(outp,outl,peer->key(),peer->cipher()); path->send(RR,tPtr,outp.b,outl,now); } else { RR->t->incomingPacketDropped(tPtr,0x27878bc1,packetId,0,peer->identity(),path->address(),Protocol::packetHops(pkt,packetSize),Protocol::VERB_ECHO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED); } + return true; } diff --git a/node/VL1.hpp b/node/VL1.hpp index c95cccfb5..bc6ab4349 100644 --- a/node/VL1.hpp +++ b/node/VL1.hpp @@ -70,8 +70,8 @@ private: // Handlers for VL1 verbs -- for clarity's sake VL2 verbs are in the VL2 class. bool _HELLO(void *tPtr,const SharedPtr &path,SharedPtr &peer,Buf &pkt,int packetSize,bool authenticated); - bool _ERROR(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize); - bool _OK(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize); + bool _ERROR(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize,Protocol::Verb &inReVerb); + bool _OK(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize,Protocol::Verb &inReVerb); bool _WHOIS(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize); bool _RENDEZVOUS(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize); bool _ECHO(void *tPtr,const SharedPtr &path,const SharedPtr &peer,Buf &pkt,int packetSize);