|
@@ -83,40 +83,43 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
const SharedPtr<Path> path(RR->topology->path(localSocket,fromAddr));
|
|
|
const int64_t now = RR->node->now();
|
|
|
|
|
|
- // Update path's last receive time (this is updated when anything is received at all, even if invalid or a keepalive)
|
|
|
+ ZT_SPEW("%u bytes from %s (local socket %lld)",len,fromAddr.toString().c_str(),localSocket);
|
|
|
path->received(now,len);
|
|
|
|
|
|
+ // NOTE: likely/unlikely are used here to highlight the most common code path
|
|
|
+ // for valid data packets. This may allow the compiler to generate very slightly
|
|
|
+ // faster code for that path.
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Packet format:
|
|
|
+ * <[8] 64-bit packet ID / crypto IV>
|
|
|
+ * <[5] destination ZT address>
|
|
|
+ * <[5] source ZT address>
|
|
|
+ * <[1] outer visible flags, cipher, and hop count (bits: FFCCHHH)>
|
|
|
+ * <[8] 64-bit MAC (or trusted path ID in trusted path mode)>
|
|
|
+ * [... -- begin encryption envelope -- ...]
|
|
|
+ * <[1] inner envelope flags (MS 3 bits) and verb (LS 5 bits)>
|
|
|
+ * [... verb-specific payload ...]
|
|
|
+ */
|
|
|
+
|
|
|
try {
|
|
|
- // Handle short probes, which are used as a low-bandwidth way to initiate a real handshake.
|
|
|
- // These are subjected to a significant rate limit to prevent DOS or amplification attacks.
|
|
|
- // The probe itself is a token passed via HELLO, so these are only used with peers we've
|
|
|
- // already started communicating with.
|
|
|
- if (unlikely(len == ZT_PROTO_PROBE_LENGTH)) {
|
|
|
- PeerList peers(RR->topology->peersByProbeToken(data->lI32(0)));
|
|
|
- for(unsigned int pi=0;pi<peers.size();++pi) {
|
|
|
- if (peers[pi]->rateGateProbeRequest(now))
|
|
|
- peers[pi]->hello(tPtr,localSocket,fromAddr,now);
|
|
|
+ // If this is too short to be a packet or fragment, check if it's a probe and
|
|
|
+ // if not simply drop it.
|
|
|
+ if (unlikely(len < ZT_PROTO_MIN_FRAGMENT_LENGTH)) {
|
|
|
+ if (len == ZT_PROTO_PROBE_LENGTH) {
|
|
|
+ const uint32_t probeToken = data->lI32(0);
|
|
|
+ PeerList peers(RR->topology->peersByProbeToken(probeToken));
|
|
|
+ ZT_SPEW("probe %.8x matches %u peers",(unsigned long)probeToken,peers.size());
|
|
|
+ for(unsigned int pi=0;pi<peers.size();++pi) {
|
|
|
+ if (peers[pi]->rateGateProbeRequest(now)) {
|
|
|
+ ZT_SPEW("HELLO -> %s(%s)",peers[pi]->address().toString().c_str(),fromAddr.toString().c_str());
|
|
|
+ peers[pi]->hello(tPtr,localSocket,fromAddr,now);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- // Any other "runt" packets are discarded, though they still count toward a path's
|
|
|
- // last receive time as they may be keepalives.
|
|
|
- if (unlikely(len < ZT_PROTO_MIN_FRAGMENT_LENGTH))
|
|
|
- return;
|
|
|
-
|
|
|
- /*
|
|
|
- * Packet format:
|
|
|
- * <[8] 64-bit packet ID / crypto IV>
|
|
|
- * <[5] destination ZT address>
|
|
|
- * <[5] source ZT address>
|
|
|
- * <[1] outer visible flags, cipher, and hop count (bits: FFCCHHH)>
|
|
|
- * <[8] 64-bit MAC (or trusted path ID in trusted path mode)>
|
|
|
- * [... -- begin encryption envelope -- ...]
|
|
|
- * <[1] inner envelope flags (MS 3 bits) and verb (LS 5 bits)>
|
|
|
- * [... verb-specific payload ...]
|
|
|
- */
|
|
|
-
|
|
|
static_assert((ZT_PROTO_PACKET_DESTINATION_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_FRAGMENT_LENGTH,"overflow");
|
|
|
Address destination(data->unsafeData + ZT_PROTO_PACKET_DESTINATION_INDEX);
|
|
|
if (destination != RR->identity.address()) {
|
|
@@ -187,7 +190,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
}
|
|
|
} else {
|
|
|
// This is a single whole packet with no fragments.
|
|
|
- Buf::Slice &s = pktv.push();
|
|
|
+ Buf::Slice s = pktv.push();
|
|
|
s.b.swap(data);
|
|
|
s.s = 0;
|
|
|
s.e = len;
|
|
@@ -199,23 +202,21 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
const uint8_t *const hdr = pktv[0].b->unsafeData + pktv[0].s;
|
|
|
-
|
|
|
static_assert((ZT_PROTO_PACKET_SOURCE_INDEX + ZT_ADDRESS_LENGTH) < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
|
|
|
const Address source(hdr + ZT_PROTO_PACKET_SOURCE_INDEX);
|
|
|
static_assert(ZT_PROTO_PACKET_FLAGS_INDEX < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
|
|
|
const uint8_t hops = hdr[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK;
|
|
|
const uint8_t cipher = (hdr[ZT_PROTO_PACKET_FLAGS_INDEX] >> 3U) & 3U;
|
|
|
|
|
|
- const SharedPtr<Buf> pkt(new Buf());
|
|
|
+ SharedPtr<Buf> pkt(new Buf());
|
|
|
int pktSize = 0;
|
|
|
- bool authenticated = false;
|
|
|
|
|
|
static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
|
|
|
- if ( ((cipher == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)||(cipher == ZT_PROTO_CIPHER_SUITE__NONE)) && ((hdr[ZT_PROTO_PACKET_VERB_INDEX] & ZT_PROTO_VERB_MASK) == Protocol::VERB_HELLO) ) {
|
|
|
+ if (unlikely( ((cipher == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)||(cipher == ZT_PROTO_CIPHER_SUITE__NONE)) && ((hdr[ZT_PROTO_PACKET_VERB_INDEX] & ZT_PROTO_VERB_MASK) == Protocol::VERB_HELLO) )) {
|
|
|
// Handle unencrypted HELLO packets.
|
|
|
pktSize = pktv.mergeCopy(*pkt);
|
|
|
if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) {
|
|
|
- ZT_SPEW("discarding packet %.16llx from %s: assembled packet size: %d",packetId,fromAddr.toString().c_str(),pktSize);
|
|
|
+ ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
|
|
|
return;
|
|
|
}
|
|
|
const SharedPtr<Peer> peer(m_HELLO(tPtr, path, *pkt, pktSize));
|
|
@@ -228,6 +229,11 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
// Making it this far means the packet is not a plaintext HELLO, so do normal AEAD decrypt and packet handling.
|
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
+ // This remains zero if authentication fails. Otherwise it gets set to a bit mask
|
|
|
+ // indicating authentication and other security flags like encryption and forward
|
|
|
+ // secrecy status.
|
|
|
+ unsigned int auth = 0;
|
|
|
+
|
|
|
SharedPtr<Peer> peer(RR->topology->peer(tPtr,source));
|
|
|
if (peer) {
|
|
|
switch(cipher) {
|
|
@@ -239,7 +245,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
|
|
|
pktSize = pktv.mergeMap<p_PolyCopyFunction &>(*pkt,ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,s20cf);
|
|
|
if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) {
|
|
|
- ZT_SPEW("discarding packet %.16llx from %s: assembled packet size: %d",packetId,fromAddr.toString().c_str(),pktSize);
|
|
|
+ ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -247,11 +253,12 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
s20cf.poly1305.finish(mac);
|
|
|
static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
|
|
|
if (unlikely(Utils::loadAsIsEndian<uint64_t>(hdr + ZT_PROTO_PACKET_MAC_INDEX) != mac[0])) {
|
|
|
+ ZT_SPEW("discarding packet %.16llx from %s(%s): packet MAC failed (none/poly1305)",packetId,source.toString().c_str(),fromAddr.toString().c_str());
|
|
|
RR->t->incomingPacketDropped(tPtr,0xcc89c812,packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- authenticated = true;
|
|
|
+ auth = ZT_VL1_AUTH_RESULT_FLAG_AUTHENTICATED;
|
|
|
} break;
|
|
|
|
|
|
case ZT_PROTO_CIPHER_SUITE__POLY1305_SALSA2012: {
|
|
@@ -261,7 +268,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
|
|
|
pktSize = pktv.mergeMap<p_SalsaPolyCopyFunction &>(*pkt,ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,s20cf);
|
|
|
if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) {
|
|
|
- ZT_SPEW("discarding packet %.16llx from %s: assembled packet size: %d",packetId,fromAddr.toString().c_str(),pktSize);
|
|
|
+ ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -269,11 +276,12 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
s20cf.poly1305.finish(mac);
|
|
|
static_assert((ZT_PROTO_PACKET_MAC_INDEX + 8) < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
|
|
|
if (unlikely(Utils::loadAsIsEndian<uint64_t>(hdr + ZT_PROTO_PACKET_MAC_INDEX) != mac[0])) {
|
|
|
+ ZT_SPEW("discarding packet %.16llx from %s(%s): packet MAC failed (salsa/poly1305)",packetId,source.toString().c_str(),fromAddr.toString().c_str());
|
|
|
RR->t->incomingPacketDropped(tPtr,0xcc89c812,packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- authenticated = true;
|
|
|
+ auth = ZT_VL1_AUTH_RESULT_FLAG_AUTHENTICATED | ZT_VL1_AUTH_RESULT_FLAG_ENCRYPTED;
|
|
|
} break;
|
|
|
|
|
|
case ZT_PROTO_CIPHER_SUITE__NONE: {
|
|
@@ -290,90 +298,80 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (likely(authenticated)) {
|
|
|
+ if (likely(auth != 0)) {
|
|
|
// If authentication was successful go on and process the packet.
|
|
|
-#if 0
|
|
|
- const Protocol::Verb verb = (Protocol::Verb)(ph->verb & ZT_PROTO_VERB_MASK);
|
|
|
|
|
|
- // 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);
|
|
|
+ if (unlikely(pktSize < ZT_PROTO_MIN_PACKET_LENGTH)) {
|
|
|
+ ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size: %d",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize);
|
|
|
return;
|
|
|
}
|
|
|
+ static_assert(ZT_PROTO_PACKET_VERB_INDEX < ZT_PROTO_MIN_PACKET_LENGTH,"overflow");
|
|
|
+ const uint8_t verbFlags = pkt->unsafeData[ZT_PROTO_PACKET_VERB_INDEX];
|
|
|
+ const Protocol::Verb verb = (Protocol::Verb)(verbFlags & ZT_PROTO_VERB_MASK);
|
|
|
|
|
|
// Decompress packet payload if compressed. For additional safety decompression is
|
|
|
// only performed on packets whose MACs have already been validated. (Only HELLO is
|
|
|
// sent without this, and HELLO doesn't benefit from compression.)
|
|
|
- if ((ph->verb & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0) {
|
|
|
- if (!authenticated) {
|
|
|
- RR->t->incomingPacketDropped(tPtr,0x390bcd0a,ph->packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- SharedPtr<Buf> nb(new Buf());
|
|
|
+ if (((verbFlags & ZT_PROTO_VERB_FLAG_COMPRESSED) != 0)&&(pktSize > ZT_PROTO_PACKET_PAYLOAD_START)) {
|
|
|
+ SharedPtr<Buf> dec(new Buf());
|
|
|
+ Utils::copy<ZT_PROTO_PACKET_PAYLOAD_START>(dec->unsafeData,pkt->unsafeData);
|
|
|
const int uncompressedLen = LZ4_decompress_safe(
|
|
|
- reinterpret_cast<const char *>(pkt.b->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),
|
|
|
- reinterpret_cast<char *>(nb->unsafeData),
|
|
|
- (int)(packetSize - ZT_PROTO_PACKET_PAYLOAD_START),
|
|
|
+ reinterpret_cast<const char *>(pkt->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),
|
|
|
+ reinterpret_cast<char *>(dec->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),
|
|
|
+ pktSize - ZT_PROTO_PACKET_PAYLOAD_START,
|
|
|
ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
|
|
|
|
|
|
- if ((uncompressedLen > 0)&&(uncompressedLen <= (ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START))) {
|
|
|
- pkt.b.swap(nb);
|
|
|
- pkt.e = packetSize = (unsigned int)uncompressedLen;
|
|
|
+ if (likely((uncompressedLen > 0)&&(uncompressedLen <= (ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START)))) {
|
|
|
+ pkt.swap(dec);
|
|
|
+ ZT_SPEW("decompressed packet: %d -> %d",pktSize,ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen);
|
|
|
+ pktSize = ZT_PROTO_PACKET_PAYLOAD_START + uncompressedLen;
|
|
|
} else {
|
|
|
- RR->t->incomingPacketDropped(tPtr,0xee9e4392,ph->packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA);
|
|
|
+ RR->t->incomingPacketDropped(tPtr,0xee9e4392,packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_INVALID_COMPRESSED_DATA);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- * Important notes:
|
|
|
- *
|
|
|
- * All verbs except HELLO assume that authenticated is true and peer is non-NULL.
|
|
|
- * This is checked above. HELLO will accept either case and always performs its
|
|
|
- * own secondary validation. The path argument is never NULL.
|
|
|
- *
|
|
|
- * VL1 and VL2 are conceptually separate layers of the ZeroTier protocol. In the
|
|
|
- * code they are almost entirely logically separate. To make the code easier to
|
|
|
- * understand the handlers for VL2 data paths have been moved to a VL2 class.
|
|
|
- */
|
|
|
-
|
|
|
- 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
|
|
|
+ // NOTE: HELLO is normally sent in the clear (in terms of our usual AEAD modes) and is handled
|
|
|
+ // above. We will try to process it here, but if so it'll still get re-authenticated via HELLO's
|
|
|
+ // own internal authentication logic as usual. It would be abnormal to make it here with HELLO
|
|
|
+ // but not invalid.
|
|
|
+
|
|
|
+ bool ok = true;
|
|
|
+ Protocol::Verb inReVerb = Protocol::VERB_NOP;
|
|
|
switch(verb) {
|
|
|
case Protocol::VERB_NOP: break;
|
|
|
- case Protocol::VERB_HELLO: ok = (bool)(m_HELLO(tPtr, path, *pkt.b, (int) packetSize)); break;
|
|
|
- case Protocol::VERB_ERROR: ok = m_ERROR(tPtr, path, peer, *pkt.b, (int) packetSize, inReVerb); break;
|
|
|
- case Protocol::VERB_OK: ok = m_OK(tPtr, path, peer, *pkt.b, (int) packetSize, inReVerb); break;
|
|
|
- case Protocol::VERB_WHOIS: ok = m_WHOIS(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_RENDEZVOUS: ok = m_RENDEZVOUS(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_FRAME: ok = RR->vl2->m_FRAME(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_EXT_FRAME: ok = RR->vl2->m_EXT_FRAME(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_ECHO: ok = m_ECHO(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_MULTICAST_LIKE: ok = RR->vl2->m_MULTICAST_LIKE(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_NETWORK_CREDENTIALS: ok = RR->vl2->m_NETWORK_CREDENTIALS(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_NETWORK_CONFIG_REQUEST: ok = RR->vl2->m_NETWORK_CONFIG_REQUEST(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_NETWORK_CONFIG: ok = RR->vl2->m_NETWORK_CONFIG(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_MULTICAST_GATHER: ok = RR->vl2->m_MULTICAST_GATHER(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_MULTICAST_FRAME_deprecated: ok = RR->vl2->m_MULTICAST_FRAME_deprecated(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_PUSH_DIRECT_PATHS: ok = m_PUSH_DIRECT_PATHS(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_USER_MESSAGE: ok = m_USER_MESSAGE(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_MULTICAST: ok = RR->vl2->m_MULTICAST(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
- case Protocol::VERB_ENCAP: ok = m_ENCAP(tPtr, path, peer, *pkt.b, (int) packetSize); break;
|
|
|
+ case Protocol::VERB_HELLO: ok = (bool)(m_HELLO(tPtr, path, *pkt, pktSize)); break;
|
|
|
+ case Protocol::VERB_ERROR: ok = m_ERROR(tPtr, auth, path, peer, *pkt, pktSize, inReVerb); break;
|
|
|
+ case Protocol::VERB_OK: ok = m_OK(tPtr, auth, path, peer, *pkt, pktSize, inReVerb); break;
|
|
|
+ case Protocol::VERB_WHOIS: ok = m_WHOIS(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_RENDEZVOUS: ok = m_RENDEZVOUS(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_FRAME: ok = RR->vl2->m_FRAME(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_EXT_FRAME: ok = RR->vl2->m_EXT_FRAME(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_ECHO: ok = m_ECHO(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_MULTICAST_LIKE: ok = RR->vl2->m_MULTICAST_LIKE(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_NETWORK_CREDENTIALS: ok = RR->vl2->m_NETWORK_CREDENTIALS(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_NETWORK_CONFIG_REQUEST: ok = RR->vl2->m_NETWORK_CONFIG_REQUEST(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_NETWORK_CONFIG: ok = RR->vl2->m_NETWORK_CONFIG(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_MULTICAST_GATHER: ok = RR->vl2->m_MULTICAST_GATHER(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_MULTICAST_FRAME_deprecated: ok = RR->vl2->m_MULTICAST_FRAME_deprecated(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_PUSH_DIRECT_PATHS: ok = m_PUSH_DIRECT_PATHS(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_USER_MESSAGE: ok = m_USER_MESSAGE(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_MULTICAST: ok = RR->vl2->m_MULTICAST(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+ case Protocol::VERB_ENCAP: ok = m_ENCAP(tPtr, auth, path, peer, *pkt, pktSize); break;
|
|
|
+
|
|
|
default:
|
|
|
- RR->t->incomingPacketDropped(tPtr,0xeeeeeff0,ph->packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB);
|
|
|
+ RR->t->incomingPacketDropped(tPtr,0xeeeeeff0,packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB);
|
|
|
break;
|
|
|
}
|
|
|
- if (ok)
|
|
|
- peer->received(tPtr,path,hops,ph->packetId,packetSize - ZT_PROTO_PACKET_PAYLOAD_START,verb,inReVerb);
|
|
|
-#endif
|
|
|
+ if (likely(ok))
|
|
|
+ peer->received(tPtr,path,hops,packetId,pktSize - ZT_PROTO_PACKET_PAYLOAD_START,verb,inReVerb);
|
|
|
} else {
|
|
|
// If decryption and authentication were not successful, try to look up identities.
|
|
|
// This is rate limited by virtue of the retry rate limit timer.
|
|
|
if (pktSize <= 0)
|
|
|
pktSize = pktv.mergeCopy(*pkt);
|
|
|
if (pktSize >= ZT_PROTO_MIN_PACKET_LENGTH) {
|
|
|
+ ZT_SPEW("authentication failed or no peers match, queueing WHOIS for %s",source.toString().c_str());
|
|
|
bool sendPending;
|
|
|
{
|
|
|
Mutex::Lock wl(m_whoisQueue_l);
|
|
@@ -392,7 +390,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void VL1::m_relay(void *tPtr, const SharedPtr<Path> &path, const Address &destination, SharedPtr<Buf> &data, unsigned int len)
|
|
|
+void VL1::m_relay(void *tPtr, const SharedPtr<Path> &path, Address destination, SharedPtr<Buf> &pkt, int pktSize)
|
|
|
{
|
|
|
}
|
|
|
|
|
@@ -444,19 +442,16 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
|
|
|
|
|
|
const uint64_t packetId = Utils::loadAsIsEndian<uint64_t>(pkt.unsafeData + ZT_PROTO_PACKET_ID_INDEX);
|
|
|
const uint64_t mac = Utils::loadAsIsEndian<uint64_t>(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX);
|
|
|
-
|
|
|
- // Get hops field and then mask hops to zero for MAC checking.
|
|
|
const uint8_t hops = pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK;
|
|
|
- pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] &= ~ZT_PROTO_FLAG_FIELD_HOPS_MASK;
|
|
|
|
|
|
- const uint8_t protoVersion = pkt.lI8<ZT_PROTO_PACKET_PAYLOAD_START>;
|
|
|
+ const uint8_t protoVersion = pkt.lI8<ZT_PROTO_PACKET_PAYLOAD_START>();
|
|
|
unsigned int versionMajor = pkt.lI8<ZT_PROTO_PACKET_PAYLOAD_START + 1>(); // LEGACY
|
|
|
unsigned int versionMinor = pkt.lI8<ZT_PROTO_PACKET_PAYLOAD_START + 2>(); // LEGACY
|
|
|
unsigned int versionRev = pkt.lI16<ZT_PROTO_PACKET_PAYLOAD_START + 3>(); // LEGACY
|
|
|
const uint64_t timestamp = pkt.lI64<ZT_PROTO_PACKET_PAYLOAD_START + 5>();
|
|
|
-
|
|
|
int p = ZT_PROTO_PACKET_PAYLOAD_START + 13;
|
|
|
|
|
|
+ // Get identity and verify that it matches the sending address in the packet.
|
|
|
Identity id;
|
|
|
if (unlikely(pkt.rO(p,id) < 0)) {
|
|
|
RR->t->incomingPacketDropped(tPtr,0x707a9810,packetId,0,Identity::NIL,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
|
@@ -467,6 +462,7 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
|
|
|
return SharedPtr<Peer>();
|
|
|
}
|
|
|
|
|
|
+ // Get the peer that matches this identity, or learn a new one if we don't know it.
|
|
|
SharedPtr<Peer> peer(RR->topology->peer(tPtr,id.address(),true));
|
|
|
if (peer) {
|
|
|
if (peer->identity() != id) {
|
|
@@ -492,14 +488,21 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
|
|
|
|
|
|
if (protoVersion >= 11) {
|
|
|
// V2.x and newer use HMAC-SHA384 for HELLO, which offers a larger security margin
|
|
|
- // to guard key exchange and connection setup than typical AEAD.
|
|
|
+ // to guard key exchange and connection setup than typical AEAD. The packet MAC
|
|
|
+ // field is ignored, and eventually it'll be undefined.
|
|
|
uint8_t hmac[ZT_HMACSHA384_LEN];
|
|
|
+ if (unlikely(packetSize < ZT_HMACSHA384_LEN)) {
|
|
|
+ RR->t->incomingPacketDropped(tPtr,0xab9c9891,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
|
|
+ return SharedPtr<Peer>();
|
|
|
+ }
|
|
|
+ packetSize -= ZT_HMACSHA384_LEN;
|
|
|
+ pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] &= ~ZT_PROTO_FLAG_FIELD_HOPS_MASK; // mask hops to 0
|
|
|
+ Utils::storeAsIsEndian<uint64_t>(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX,0); // set MAC field to 0
|
|
|
HMACSHA384(peer->identityHelloHmacKey(),pkt.unsafeData,packetSize,hmac);
|
|
|
- if (unlikely((packetSize < ZT_HMACSHA384_LEN)||(!Utils::secureEq(hmac,(pkt.unsafeData + packetSize) - ZT_HMACSHA384_LEN,ZT_HMACSHA384_LEN)))) {
|
|
|
+ if (unlikely(!Utils::secureEq(hmac,pkt.unsafeData + packetSize,ZT_HMACSHA384_LEN))) {
|
|
|
RR->t->incomingPacketDropped(tPtr,0x707a9891,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
|
|
return SharedPtr<Peer>();
|
|
|
}
|
|
|
- packetSize -= ZT_HMACSHA384_LEN; // trim this off the end since we're done with it
|
|
|
} else {
|
|
|
// Older versions use Poly1305 MAC (but no whole packet encryption) for HELLO.
|
|
|
if (likely(packetSize > ZT_PROTO_PACKET_ENCRYPTED_SECTION_START)) {
|
|
@@ -532,53 +535,78 @@ SharedPtr<Peer> VL1::m_HELLO(void *tPtr, const SharedPtr<Path> &path, Buf &pkt,
|
|
|
return SharedPtr<Peer>();
|
|
|
}
|
|
|
|
|
|
- if ((protoVersion >= 11)&&((p + 12) < packetSize)) {
|
|
|
- uint64_t ctrNonce[2];
|
|
|
- ctrNonce[0] = Utils::loadAsIsEndian<uint64_t>(pkt.unsafeData + p);
|
|
|
- #if __BYTE_ORDER == __BIG_ENDIAN
|
|
|
- ctrNonce[1] = ((uint64_t)Utils::loadAsIsEndian<uint32_t>(pkt.unsafeData + p + 8)) << 32U;
|
|
|
- #else
|
|
|
- ctrNonce[1] = Utils::loadAsIsEndian<uint32_t>(pkt.unsafeData + p + 8);
|
|
|
- #endif
|
|
|
- p += 12;
|
|
|
-
|
|
|
- AES::CTR ctr(peer->identityHelloDictionaryEncryptionCipher());
|
|
|
- ctr.init(reinterpret_cast<uint8_t *>(ctrNonce),pkt.unsafeData + p);
|
|
|
- ctr.crypt(pkt.unsafeData + p,(packetSize - p) - ZT_HMACSHA384_LEN);
|
|
|
- ctr.finish();
|
|
|
-
|
|
|
- const unsigned int dictSize = pkt.rI16(p);
|
|
|
- if (unlikely((p + dictSize) > packetSize)) {
|
|
|
- RR->t->incomingPacketDropped(tPtr,0x707a9815,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
|
|
- return peer;
|
|
|
- }
|
|
|
- Dictionary md;
|
|
|
- if (!md.decode(pkt.unsafeData + p,dictSize)) {
|
|
|
- RR->t->incomingPacketDropped(tPtr,0x707a9816,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
|
|
- return peer;
|
|
|
- }
|
|
|
+ const SharedPtr<SymmetricKey> key(peer->identityKey());
|
|
|
+
|
|
|
+ if (protoVersion >= 11) {
|
|
|
+ // V2.x and newer supports an encrypted section and has a new OK format.
|
|
|
+ if ((p + 12) < packetSize) {
|
|
|
+ uint64_t ctrNonce[2];
|
|
|
+ ctrNonce[0] = Utils::loadAsIsEndian<uint64_t>(pkt.unsafeData + p);
|
|
|
+#if __BYTE_ORDER == __BIG_ENDIAN
|
|
|
+ ctrNonce[1] = ((uint64_t)Utils::loadAsIsEndian<uint32_t>(pkt.unsafeData + p + 8)) << 32U;
|
|
|
+#else
|
|
|
+ ctrNonce[1] = Utils::loadAsIsEndian<uint32_t>(pkt.unsafeData + p + 8);
|
|
|
+#endif
|
|
|
+ p += 12;
|
|
|
+ AES::CTR ctr(peer->identityHelloDictionaryEncryptionCipher());
|
|
|
+ ctr.init(reinterpret_cast<uint8_t *>(ctrNonce),pkt.unsafeData + p);
|
|
|
+ ctr.crypt(pkt.unsafeData + p,packetSize - p);
|
|
|
+ ctr.finish();
|
|
|
+
|
|
|
+ const unsigned int dictSize = pkt.rI16(p);
|
|
|
+ if (unlikely((p + dictSize) > packetSize)) {
|
|
|
+ RR->t->incomingPacketDropped(tPtr,0x707a9815,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
|
|
+ return peer;
|
|
|
+ }
|
|
|
+ Dictionary md;
|
|
|
+ if (!md.decode(pkt.unsafeData + p,dictSize)) {
|
|
|
+ RR->t->incomingPacketDropped(tPtr,0x707a9816,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT);
|
|
|
+ return peer;
|
|
|
+ }
|
|
|
|
|
|
- if (!md.empty()) {
|
|
|
- InetAddress sentTo2;
|
|
|
- if (md.getO(ZT_PROTO_HELLO_NODE_META_PHYSICAL_DEST,sentTo2))
|
|
|
- sentTo = sentTo2;
|
|
|
- const uint64_t packedVer = md.getUI(ZT_PROTO_HELLO_NODE_META_SOFTWARE_VERSION);
|
|
|
- if (packedVer != 0) {
|
|
|
- versionMajor = (unsigned int)(packedVer >> 48U) & 0xffffU;
|
|
|
- versionMinor = (unsigned int)(packedVer >> 32U) & 0xffffU;
|
|
|
- versionRev = (unsigned int)(packedVer >> 16U) & 0xffffU;
|
|
|
+ if (!md.empty()) {
|
|
|
+ InetAddress sentTo2;
|
|
|
+ if (md.getO(ZT_PROTO_HELLO_NODE_META_PHYSICAL_DEST,sentTo2))
|
|
|
+ sentTo = sentTo2;
|
|
|
+ const uint64_t packedVer = md.getUI(ZT_PROTO_HELLO_NODE_META_SOFTWARE_VERSION);
|
|
|
+ if (packedVer != 0) {
|
|
|
+ versionMajor = (unsigned int)(packedVer >> 48U) & 0xffffU;
|
|
|
+ versionMinor = (unsigned int)(packedVer >> 32U) & 0xffffU;
|
|
|
+ versionRev = (unsigned int)(packedVer >> 16U) & 0xffffU;
|
|
|
+ }
|
|
|
+ const uint32_t probeToken = (uint32_t)md.getUI(ZT_PROTO_HELLO_NODE_META_PROBE_TOKEN);
|
|
|
+ if (probeToken != 0)
|
|
|
+ peer->setProbeToken(probeToken);
|
|
|
}
|
|
|
- const uint32_t probeToken = (uint32_t)md.getUI(ZT_PROTO_HELLO_NODE_META_PROBE_TOKEN);
|
|
|
- if (probeToken != 0)
|
|
|
- peer->setProbeToken(probeToken);
|
|
|
}
|
|
|
+
|
|
|
+ Protocol::newPacket(pkt,key->nextMessage(RR->identity.address(),peer->address()),peer->address(),RR->identity.address(),Protocol::VERB_OK);
|
|
|
+ p = ZT_PROTO_PACKET_PAYLOAD_START;
|
|
|
+ pkt.wI8(p,Protocol::VERB_HELLO);
|
|
|
+ pkt.wI64(p,packetId);
|
|
|
+ pkt.wI64(p,timestamp);
|
|
|
+ pkt.wI8(p,(uint8_t)protoVersion);
|
|
|
+ } else {
|
|
|
+ // V1.x has nothing more for this version to parse, and has an older OK format.
|
|
|
+ Protocol::newPacket(pkt,key->nextMessage(RR->identity.address(),peer->address()),peer->address(),RR->identity.address(),Protocol::VERB_OK);
|
|
|
+ p = ZT_PROTO_PACKET_PAYLOAD_START;
|
|
|
+ pkt.wI8(p,Protocol::VERB_HELLO);
|
|
|
+ pkt.wI64(p,packetId);
|
|
|
+ pkt.wI64(p,timestamp);
|
|
|
+ pkt.wI8(p,(uint8_t)protoVersion);
|
|
|
+ pkt.wI8(p,(uint8_t)versionMajor);
|
|
|
+ pkt.wI8(p,(uint8_t)versionMinor);
|
|
|
+ pkt.wI16(p,(uint16_t)versionRev);
|
|
|
+ pkt.wO(p,path->address());
|
|
|
+ pkt.wI16(p,0);
|
|
|
}
|
|
|
|
|
|
peer->setRemoteVersion(protoVersion,versionMajor,versionMinor,versionRev);
|
|
|
}
|
|
|
|
|
|
-bool VL1::m_ERROR(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb)
|
|
|
+bool VL1::m_ERROR(void *tPtr,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb)
|
|
|
{
|
|
|
+#if 0
|
|
|
if (packetSize < (int)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;
|
|
@@ -622,7 +650,7 @@ bool VL1::m_ERROR(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer>
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-bool VL1::m_OK(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb)
|
|
|
+bool VL1::m_OK(void *tPtr,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb)
|
|
|
{
|
|
|
if (packetSize < (int)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);
|
|
@@ -653,10 +681,12 @@ bool VL1::m_OK(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &p
|
|
|
|
|
|
}
|
|
|
return true;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
-bool VL1::m_WHOIS(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
+bool VL1::m_WHOIS(void *tPtr,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
{
|
|
|
+#if 0
|
|
|
if (packetSize < (int)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;
|
|
@@ -705,10 +735,12 @@ bool VL1::m_WHOIS(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer>
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
-bool VL1::m_RENDEZVOUS(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
+bool VL1::m_RENDEZVOUS(void *tPtr,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
{
|
|
|
+#if 0
|
|
|
if (RR->topology->isRoot(peer->identity())) {
|
|
|
if (packetSize < (int)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);
|
|
@@ -751,10 +783,12 @@ bool VL1::m_RENDEZVOUS(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
-bool VL1::m_ECHO(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
+bool VL1::m_ECHO(void *tPtr,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
{
|
|
|
+#if 0
|
|
|
const uint64_t packetId = Protocol::packetId(pkt,packetSize);
|
|
|
const uint64_t now = RR->node->now();
|
|
|
if (packetSize < (int)sizeof(Protocol::Header)) {
|
|
@@ -787,10 +821,12 @@ bool VL1::m_ECHO(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer>
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
-bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
+bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
{
|
|
|
+#if 0
|
|
|
if (packetSize < (int)sizeof(Protocol::PUSH_DIRECT_PATHS)) {
|
|
|
RR->t->incomingPacketDropped(tPtr,0x1bb1bbb1,Protocol::packetId(pkt,packetSize),0,peer->identity(),path->address(),Protocol::packetHops(pkt,packetSize),Protocol::VERB_PUSH_DIRECT_PATHS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
|
|
return false;
|
|
@@ -876,15 +912,16 @@ bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr, const SharedPtr<Path> &path, const Sha
|
|
|
// TODO: add to a peer try-queue
|
|
|
|
|
|
return true;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
-bool VL1::m_USER_MESSAGE(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
+bool VL1::m_USER_MESSAGE(void *tPtr,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
{
|
|
|
// TODO
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-bool VL1::m_ENCAP(void *tPtr, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
+bool VL1::m_ENCAP(void *tPtr,const unsigned int auth, const SharedPtr<Path> &path, const SharedPtr<Peer> &peer, Buf &pkt, int packetSize)
|
|
|
{
|
|
|
// TODO: not implemented yet
|
|
|
return true;
|