Add Peer method for getting preferred cipher, various cleanup in VL1

This commit is contained in:
Adam Ierymenko 2020-02-18 12:38:48 -08:00
parent 0dc476518b
commit 9ad8dd3700
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
7 changed files with 121 additions and 90 deletions

View file

@ -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)) if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return -1; return -1;
Utils::storeBigEndian<int64_t>(data,_ts); data[0] = 0xff; // version byte, currently 0xff to never be the same as byte 0 of an identity for legacy compatibility reasons
int p = 8; Utils::storeBigEndian<int64_t>(data + 1,_ts);
int p = 9;
if (_ts > 0) { if (_ts > 0) {
Utils::storeBigEndian(data + p,(uint16_t)_endpointCount); 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 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; return -1;
_ts = Utils::loadBigEndian<int64_t>(data); if (data[0] != 0xff)
int p = 8; return -1;
_ts = Utils::loadBigEndian<int64_t>(data + 1);
int p = 9;
if (_ts > 0) { if (_ts > 0) {
const unsigned int ec = Utils::loadBigEndian<uint16_t>(data + p); const unsigned int ec = Utils::loadBigEndian<uint16_t>(data + p);

View file

@ -24,7 +24,7 @@
#include "TriviallyCopyable.hpp" #include "TriviallyCopyable.hpp"
#define ZT_LOCATOR_MAX_ENDPOINTS 8 #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 { namespace ZeroTier {

View file

@ -72,7 +72,8 @@ void Peer::received(
const unsigned int hops, const unsigned int hops,
const uint64_t packetId, const uint64_t packetId,
const unsigned int payloadLength, const unsigned int payloadLength,
const Protocol::Verb verb) const Protocol::Verb verb,
const Protocol::Verb inReVerb)
{ {
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
_lastReceive = 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); RR->identity.address().copyTo(ph.source);
ph.flags = 0; ph.flags = 0;
ph.verb = Protocol::VERB_NOP; 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)); RR->node->putPacket(tPtr,localSocket,atAddress,outp.b,sizeof(Protocol::Header));
} }
@ -354,7 +355,7 @@ void Peer::save(void *tPtr) const
free(buf); 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; static uint8_t junk = 0;

View file

@ -101,6 +101,7 @@ public:
* @param hops ZeroTier (not IP) hops * @param hops ZeroTier (not IP) hops
* @param packetId Packet ID * @param packetId Packet ID
* @param verb Packet verb * @param verb Packet verb
* @param inReVerb In-reply verb for OK or ERROR verbs
*/ */
void received( void received(
void *tPtr, void *tPtr,
@ -108,7 +109,8 @@ public:
unsigned int hops, unsigned int hops,
uint64_t packetId, uint64_t packetId,
unsigned int payloadLength, unsigned int payloadLength,
Protocol::Verb verb); Protocol::Verb verb,
Protocol::Verb inReVerb);
/** /**
* Send a HELLO to this peer at a specified physical address * 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; } 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) * @return Incoming probe packet (in big-endian byte order)
0 */ 0 */

View file

@ -305,43 +305,42 @@ enum Verb
* <[...] meta-data dictionary> * <[...] meta-data dictionary>
* <[2] 16-bit length of any additional fields> * <[2] 16-bit length of any additional fields>
* [... end encrypted region ...] * [... 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 * HELLO is sent using the POLY1305_NONE cipher setting (MAC but
* that peers can exchange identities. * 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 * The physical desgination address is the raw InetAddress to which the
* was sent. See InetAddress::serialize() for format. * packet was sent, regardless of any relaying used.
* *
* Starting at "begin encrypted section" the reset of the packet is * HELLO packets have an encrypted section that is encrypted with
* encrypted with Salsa20/12. This is not the normal packet encryption * Salsa20/12 using the two peers' long-term negotiated keys and with
* and is technically not necessary as nothing in HELLO is secret. It * the packet ID (with least significant 3 bits masked to 0 for legacy
* exists merely to shield meta-data info from passive listeners to * reasons) as the Salsa20/12 IV. This encryption is technically not
* slightly improve privacy, and for backward compatibility with older * necessary but serves to protect the privacy of locators and other
* nodes that required it. * 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 * A valid and successfully authenticated HELLO will generate the following
* identity exchanges to be authenticated with additional strength beyond * OK response which contains much of the same information about the
* ordinary packet authentication. * responding peer.
* *
* OK payload: * OK payload:
* [... HMAC-384 starts here ...] * <[8] timestamp echoed from original HELLO packet>
* <[8] HELLO timestamp field echo>
* <[1] protocol version> * <[1] protocol version>
* <[1] software major version> * <[1] software major version>
* <[1] software minor version> * <[1] software minor version>
* <[2] software revision> * <[2] software revision>
* <[...] physical destination address of packet> * <[...] 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> * <[2] 16-bit length of meta-data dictionary>
* <[...] meta-data dictionary> * <[...] meta-data dictionary>
* <[2] 16-bit length of any additional fields> * <[2] 16-bit length of any additional fields>
* <[48] HMAC-SHA384 of all fields to this point (as plaintext)> * <[48] HMAC-SHA384 of plaintext packet (with hops masked to 0)>
*
* 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.
*/ */
VERB_HELLO = 0x01, VERB_HELLO = 0x01,
@ -350,10 +349,10 @@ enum Verb
* <[1] in-re verb> * <[1] in-re verb>
* <[8] in-re packet ID> * <[8] in-re packet ID>
* <[1] error code> * <[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 * An ERROR that does not pertain to a specific packet will have its verb
* NOP and packet ID can be zero. * set to VERB_NOP and its packet ID set to zero.
*/ */
VERB_ERROR = 0x02, VERB_ERROR = 0x02,
@ -380,8 +379,7 @@ enum Verb
* be performed. * be performed.
* *
* It is possible for an identity but a null/empty locator to be returned * 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 * if no locator is known for a node. Older versions may omit the locator.
* locator field at all.
*/ */
VERB_WHOIS = 0x04, VERB_WHOIS = 0x04,
@ -390,13 +388,19 @@ enum Verb
* <[1] flags (unused, currently 0)> * <[1] flags (unused, currently 0)>
* <[5] ZeroTier address of peer that might be found at this address> * <[5] ZeroTier address of peer that might be found at this address>
* <[2] 16-bit protocol address port> * <[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)> * <[...] protocol address (network byte order)>
* *
* An upstream node can send this to inform both sides of a relay of * This is sent by a third party node to inform a node of where another
* information they might use to establish a direct connection. * 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. * No OK or ERROR is generated.
*/ */

View file

@ -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); 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)) { 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); RR->t->incomingPacketDropped(tPtr,0x5b001099,ph->packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
return; 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. * 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) { switch(verb) {
case Protocol::VERB_NOP: break; case Protocol::VERB_NOP: break;
case Protocol::VERB_HELLO: ok = _HELLO(tPtr,path,peer,*pkt.b,(int)packetSize,authenticated); 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_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); 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_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_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; 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; break;
} }
if (ok) 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 ( ... ) { } catch ( ... ) {
RR->t->unexpectedError(tPtr,0xea1b6dea,"unexpected exception in onRemotePacket() parsing packet from %s",Trace::str(path->address()).s); 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)) { 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); RR->expect->sending(ph.packetId,now);
rootPath->send(RR,tPtr,outp.b,outl,now); rootPath->send(RR,tPtr,outp.b,outl,now);
} }
} }
} }
bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated) bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,const bool authenticated)
{ {
if (packetSize < sizeof(Protocol::HELLO)) { 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); 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> &path,SharedPtr<Peer> &peer,Bu
// Packet is basically valid and identity unmarshaled successfully -------------------------------------------------- // Packet is basically valid and identity unmarshaled successfully --------------------------------------------------
// Get long-term static key for this node.
uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t key[ZT_PEER_SECRET_KEY_LENGTH];
if ((peer) && (id == peer->identity())) { if ((peer) && (id == peer->identity())) {
memcpy(key,peer->key(),ZT_PEER_SECRET_KEY_LENGTH); memcpy(key,peer->key(),ZT_PEER_SECRET_KEY_LENGTH);
@ -516,8 +517,7 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
} }
} }
// Verify packet using Poly1305 MAC if ((!peer)||(!authenticated)) {
{
uint8_t perPacketKey[ZT_PEER_SECRET_KEY_LENGTH]; uint8_t perPacketKey[ZT_PEER_SECRET_KEY_LENGTH];
uint8_t macKey[ZT_POLY1305_KEY_LEN]; uint8_t macKey[ZT_POLY1305_KEY_LEN];
Protocol::salsa2012DeriveKey(peer->key(),perPacketKey,pkt,packetSize); Protocol::salsa2012DeriveKey(peer->key(),perPacketKey,pkt,packetSize);
@ -538,15 +538,16 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &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); 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; 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) 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); HMACSHA384(hmacKey,pkt.b,packetSize,hmac);
if (!Utils::secureEq(pkt.b + (packetSize - ZT_HMACSHA384_LEN),hmac,ZT_HMACSHA384_LEN)) { 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); 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; return false;
} }
} }
// Packet has passed HMAC-SHA384 (if present and/or forced) --------------------------------------------------------- // Packet has passed HMAC-SHA384 (if present) -----------------------------------------------------------------------
InetAddress externalSurfaceAddress; InetAddress externalSurfaceAddress;
Dictionary nodeMetaData; Dictionary nodeMetaData;
@ -559,43 +560,39 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &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 // 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 // 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, // can't even get ephemeral public keys without first knowing the long term secret key,
// adding a little defense in depth. // adding a little defense in depth.
uint8_t iv[8]; uint8_t iv[8];
for (int i = 0; i < 8; ++i) iv[i] = pkt.b[i]; 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); 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+ ptr += pkt.rI16(ptr); // skip length field which currently is always zero in v2.0+
if (ptr < packetSize) { if (ptr < packetSize) {
const unsigned int dictionarySize = pkt.rI16(ptr); const unsigned int dictionarySize = pkt.rI16(ptr);
const void *const dictionaryBytes = pkt.b + ptr; const void *const dictionaryBytes = pkt.rBnc(ptr,dictionarySize);
if ((ptr += (int)dictionarySize) > packetSize) { 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_INVALID_OBJECT); 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; 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 (dictionarySize) {
if (!nodeMetaData.decode(dictionaryBytes,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); 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; return false;
} }
} }
ptr += pkt.rI16(ptr); // skip any additional fields, currently always 0
} }
} }
if (Buf::readOverflow(ptr,packetSize)) { // sanity check, should be impossible 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; return false;
} }
@ -620,6 +617,10 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
if ((hops == 0) && (externalSurfaceAddress)) if ((hops == 0) && (externalSurfaceAddress))
RR->sa->iam(tPtr,id,path->localSocket(),path->address(),externalSurfaceAddress,RR->topology->isRoot(id),now); 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<uint8_t> myNodeMetaDataBin; std::vector<uint8_t> myNodeMetaDataBin;
{ {
Dictionary myNodeMetaData; Dictionary myNodeMetaData;
@ -651,8 +652,9 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
int outl = sizeof(Protocol::OK::HELLO); int outl = sizeof(Protocol::OK::HELLO);
outp.wO(outl,path->address()); outp.wO(outl,path->address());
outp.wI(outl,(uint16_t)0); // legacy field, always 0
if (p.versionProtocol >= 11) { if (p.versionProtocol >= 11) {
outp.wI(outl,(uint16_t)0); // legacy field, always 0
outp.wI(outl,(uint16_t)myNodeMetaDataBin.size()); outp.wI(outl,(uint16_t)myNodeMetaDataBin.size());
outp.wB(outl,myNodeMetaDataBin.data(),(unsigned int)myNodeMetaDataBin.size()); outp.wB(outl,myNodeMetaDataBin.data(),(unsigned int)myNodeMetaDataBin.size());
outp.wI(outl,(uint16_t)0); // length of additional fields, currently 0 outp.wI(outl,(uint16_t)0); // length of additional fields, currently 0
@ -665,21 +667,20 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
outl += ZT_HMACSHA384_LEN; 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); path->send(RR,tPtr,outp.b,outl,now);
peer->setRemoteVersion(p.versionProtocol,p.versionMajor,p.versionMinor,Utils::ntoh(p.versionRev));
return true; return true;
} }
bool VL1::_ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize) bool VL1::_ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,Protocol::Verb &inReVerb)
{ {
if (packetSize < sizeof(Protocol::ERROR::Header)) { 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); RR->t->incomingPacketDropped(tPtr,0x3beb1947,0,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_ERROR,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
return false; return false;
} }
Protocol::ERROR::Header &eh = pkt.as<Protocol::ERROR::Header>(); Protocol::ERROR::Header &eh = pkt.as<Protocol::ERROR::Header>();
inReVerb = (Protocol::Verb)eh.inReVerb;
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
if (!RR->expect->expecting(eh.inRePacketId,now)) { if (!RR->expect->expecting(eh.inRePacketId,now)) {
@ -717,13 +718,14 @@ bool VL1::_ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &p
return true; return true;
} }
bool VL1::_OK(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize) bool VL1::_OK(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,Protocol::Verb &inReVerb)
{ {
if (packetSize < sizeof(Protocol::OK::Header)) { 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); RR->t->incomingPacketDropped(tPtr,0x4c1f1ff7,0,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_OK,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
return false; return false;
} }
Protocol::OK::Header &oh = pkt.as<Protocol::OK::Header>(); Protocol::OK::Header &oh = pkt.as<Protocol::OK::Header>();
inReVerb = (Protocol::Verb)oh.inReVerb;
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
if (!RR->expect->expecting(oh.inRePacketId,now)) { if (!RR->expect->expecting(oh.inRePacketId,now)) {
@ -793,7 +795,7 @@ bool VL1::_WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &p
} }
if (outl > sizeof(Protocol::OK::WHOIS)) { 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()); path->send(RR,tPtr,outp.b,outl,RR->node->now());
} }
} }
@ -803,7 +805,6 @@ bool VL1::_WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &p
bool VL1::_RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize) bool VL1::_RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize)
{ {
static uint16_t junk = 0;
if (RR->topology->isRoot(peer->identity())) { if (RR->topology->isRoot(peer->identity())) {
if (packetSize < sizeof(Protocol::RENDEZVOUS)) { 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); 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> &path,const SharedPtr<Pee
const SharedPtr<Peer> with(RR->topology->peer(tPtr,Address(rdv.peerAddress))); const SharedPtr<Peer> with(RR->topology->peer(tPtr,Address(rdv.peerAddress)));
if (with) { if (with) {
const int64_t now = RR->node->now();
const unsigned int port = Utils::ntoh(rdv.port); const unsigned int port = Utils::ntoh(rdv.port);
if (port != 0) { if (port != 0) {
switch(rdv.addressLength) { switch(rdv.addressLength) {
case 4: case 4:
if ((sizeof(Protocol::RENDEZVOUS) + 4) <= packetSize) { case 16:
InetAddress atAddr(pkt.b + sizeof(Protocol::RENDEZVOUS),4,port); if ((sizeof(Protocol::RENDEZVOUS) + rdv.addressLength) <= packetSize) {
++junk; const InetAddress atAddr(pkt.b + sizeof(Protocol::RENDEZVOUS),rdv.addressLength,port);
RR->node->putPacket(tPtr,path->localSocket(),atAddr,(const void *)&junk,2,2); // IPv4 "firewall opener" hack peer->contact(tPtr,Endpoint(atAddr),now,false,false);
with->sendHELLO(tPtr,path->localSocket(),atAddr,RR->node->now());
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); 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; break;
case 16: case 255:
if ((sizeof(Protocol::RENDEZVOUS) + 16) <= packetSize) { if ((sizeof(Protocol::RENDEZVOUS) + 1) <= packetSize) {
InetAddress atAddr(pkt.b + sizeof(Protocol::RENDEZVOUS),16,port); Endpoint ep;
with->sendHELLO(tPtr,path->localSocket(),atAddr,RR->node->now()); int epl = ep.unmarshal(pkt.b + sizeof(Protocol::RENDEZVOUS),packetSize - (int)sizeof(Protocol::RENDEZVOUS));
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); 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; break;
} }
@ -847,6 +858,7 @@ bool VL1::_ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &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); 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; return false;
} }
if (peer->rateGateEchoRequest(now)) { if (peer->rateGateEchoRequest(now)) {
Buf outp; Buf outp;
Protocol::OK::ECHO &outh = outp.as<Protocol::OK::ECHO>(); Protocol::OK::ECHO &outh = outp.as<Protocol::OK::ECHO>();
@ -865,11 +877,12 @@ bool VL1::_ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &pe
return false; 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); path->send(RR,tPtr,outp.b,outl,now);
} else { } 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); 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; return true;
} }

View file

@ -70,8 +70,8 @@ private:
// Handlers for VL1 verbs -- for clarity's sake VL2 verbs are in the VL2 class. // Handlers for VL1 verbs -- for clarity's sake VL2 verbs are in the VL2 class.
bool _HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated); bool _HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Buf &pkt,int packetSize,bool authenticated);
bool _ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize); bool _ERROR(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,Protocol::Verb &inReVerb);
bool _OK(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize); bool _OK(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize,Protocol::Verb &inReVerb);
bool _WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize); bool _WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize);
bool _RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize); bool _RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize);
bool _ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize); bool _ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &peer,Buf &pkt,int packetSize);