diff --git a/go/native/GoGlue.cpp b/go/native/GoGlue.cpp index 4f065c1fe..84ffb7a92 100644 --- a/go/native/GoGlue.cpp +++ b/go/native/GoGlue.cpp @@ -13,16 +13,13 @@ #include "GoGlue.h" -#include -#include -#include - #include "../../node/Constants.hpp" #include "../../node/InetAddress.hpp" #include "../../node/Node.hpp" #include "../../node/Utils.hpp" #include "../../node/MAC.hpp" #include "../../node/Address.hpp" +#include "../../node/Containers.hpp" #include "../../osdep/OSUtils.hpp" #include "../../osdep/EthernetTap.hpp" @@ -32,6 +29,7 @@ #include #include #include +#include #ifdef __BSD__ #include #endif @@ -81,13 +79,13 @@ struct ZT_GoNode_Impl Node *node; volatile int64_t nextBackgroundTaskDeadline; - std::string path; + String path; std::atomic run; - std::map< ZT_SOCKET,ZT_GoNodeThread > threads; - std::mutex threads_l; + Map< ZT_SOCKET,ZT_GoNodeThread > threads; + Map< uint64_t,std::shared_ptr > taps; - std::map< uint64_t,std::shared_ptr > taps; + std::mutex threads_l; std::mutex taps_l; std::thread backgroundTaskThread; @@ -96,9 +94,7 @@ struct ZT_GoNode_Impl static const std::string defaultHomePath(OSUtils::platformDefaultHomePath()); const char *ZT_PLATFORM_DEFAULT_HOMEPATH = defaultHomePath.c_str(); -// -------------------------------------------------------------------------------------------------------------------- - -/* These functions are implemented in Go in pkg/zerotier/node.go */ +// These are implemented in Go code. extern "C" int goPathCheckFunc(void *,const ZT_Identity *,int,const void *,int); extern "C" int goPathLookupFunc(void *,uint64_t,int,const ZT_Identity *,int *,uint8_t [16],int *); extern "C" void goStateObjectPutFunc(void *,int,const uint64_t [2],const void *,int); @@ -300,8 +296,6 @@ static int ZT_GoNode_PathLookupFunction( return 0; } -// -------------------------------------------------------------------------------------------------------------------- - extern "C" ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr) { try { @@ -388,7 +382,6 @@ extern "C" ZT_Node *ZT_GoNode_getNode(ZT_GoNode *gn) return gn->node; } -// Sets flags and socket options common to both IPv4 and IPv6 UDP sockets static void setCommonUdpSocketSettings(ZT_SOCKET udpSock,const char *dev) { int bufSize = 1048576; @@ -623,8 +616,6 @@ extern "C" void ZT_GoNode_leave(ZT_GoNode *gn,uint64_t nwid) } } -/****************************************************************************/ - extern "C" void ZT_GoTap_setEnabled(ZT_GoTap *tap,int enabled) { reinterpret_cast(tap)->setEnabled(enabled != 0); diff --git a/go/native/GoGlue.h b/go/native/GoGlue.h index a5554b7cc..810f41a93 100644 --- a/go/native/GoGlue.h +++ b/go/native/GoGlue.h @@ -14,15 +14,9 @@ #ifndef ZT_GONODE_H #define ZT_GONODE_H -#ifdef __cplusplus -#include -#include -#include -#else #include #include #include -#endif #include "../../include/ZeroTierCore.h" #include "../../node/Constants.hpp" @@ -31,56 +25,28 @@ extern "C" { #endif -/* A pointer to an instance of EthernetTap */ typedef void ZT_GoTap; - -/* ZT_GoNode is a C struct and functions that wraps ZT_Node for use via cgo. It - * performs UDP and other direct I/O in C for performance but otherwise lets - * the Go code control the node's behavior. */ struct ZT_GoNode_Impl; typedef struct ZT_GoNode_Impl ZT_GoNode; extern const char *ZT_PLATFORM_DEFAULT_HOMEPATH; ZT_GoNode *ZT_GoNode_new(const char *workingPath,uintptr_t userPtr); - void ZT_GoNode_delete(ZT_GoNode *gn); - ZT_Node *ZT_GoNode_getNode(ZT_GoNode *gn); - -/* This can be called more than once to start multiple listener threads */ int ZT_GoNode_phyStartListen(ZT_GoNode *gn,const char *dev,const char *ip,int port,int primary); - -/* Close all listener threads for a given local IP and port */ int ZT_GoNode_phyStopListen(ZT_GoNode *gn,const char *dev,const char *ip,int port); - ZT_GoTap *ZT_GoNode_join(ZT_GoNode *gn,uint64_t nwid,const ZT_Fingerprint *controllerFingerprint); - void ZT_GoNode_leave(ZT_GoNode *gn,uint64_t nwid); void ZT_GoTap_setEnabled(ZT_GoTap *tap,int enabled); - int ZT_GoTap_addIp(ZT_GoTap *tap,int af,const void *ip,int netmaskBits); - int ZT_GoTap_removeIp(ZT_GoTap *tap,int af,const void *ip,int netmaskBits); - -/* The buf buffer is filled with tuplies of: - * uint8_t family - * uint8_t ip[4 or 16] - * uint8_t netmask bits (up to 32 for ipv4, 128 for ipv6) - * - * This function returns the number of such tuples in the result. - * If the buffer isn't big enough results are incomplete. - */ int ZT_GoTap_ips(ZT_GoTap *tap,void *buf,unsigned int bufSize); - void ZT_GoTap_deviceName(ZT_GoTap *tap,char nbuf[256]); - void ZT_GoTap_setFriendlyName(ZT_GoTap *tap,const char *friendlyName); - void ZT_GoTap_setMtu(ZT_GoTap *tap,unsigned int mtu); -/* Core self-tests that output results to stdout and return non-zero on failure. */ int ZT_TestCrypto(); int ZT_TestIdentity(); int ZT_TestOther(); diff --git a/node/Containers.hpp b/node/Containers.hpp index f74ce9922..27aa059cf 100644 --- a/node/Containers.hpp +++ b/node/Containers.hpp @@ -152,7 +152,9 @@ class Set : public std::set< V,std::less,Utils::Mallocator > class String : public std::basic_string< char,std::char_traits,Utils::Mallocator > { public: + ZT_INLINE String() {} explicit ZT_INLINE String(const char *const s) { assign(s); } + ZT_INLINE &operator=(const char *const s) { assign(s); } }; } // ZeroTier diff --git a/node/OS.hpp b/node/OS.hpp index 388835329..5bc611e0c 100644 --- a/node/OS.hpp +++ b/node/OS.hpp @@ -195,6 +195,11 @@ typedef unsigned uint128_t __attribute__((mode(TI))); #endif // Macro to print very verbose tracing information to standard error. +#define ZT_DEBUG_SPEW +#ifdef ZT_DEBUG_SPEW #define ZT_SPEW(f,...) fprintf(stderr,"%s:%d(%s): " f ZT_EOL_S,__FILE__,__LINE__,__FUNCTION__,__VA_ARGS__) +#else +#define ZT_SPEW(f,...) +#endif #endif diff --git a/node/Peer.hpp b/node/Peer.hpp index 77adcb30e..993954d0a 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -32,9 +32,11 @@ #include "SymmetricKey.hpp" #include "Containers.hpp" -// version, identity, locator, bootstrap, version info, length of any additional fields #define ZT_PEER_MARSHAL_SIZE_MAX (1 + ZT_ADDRESS_LENGTH + ZT_SYMMETRIC_KEY_SIZE + ZT_IDENTITY_MARSHAL_SIZE_MAX + ZT_LOCATOR_MARSHAL_SIZE_MAX + 1 + (ZT_MAX_PEER_NETWORK_PATHS * ZT_ENDPOINT_MARSHAL_SIZE_MAX) + (2*4) + 2) +#define ZT_PEER_DEDUP_BUFFER_SIZE 1024 +#define ZT_PEER_DEDUP_BUFFER_MASK 1023U + namespace ZeroTier { class Topology; @@ -444,6 +446,21 @@ public: return false; } + /** + * Packet deduplication filter for incoming packets + * + * This flags a packet ID and returns true if the same packet ID was already + * flagged. This is done in an atomic operation if supported. + * + * @param packetId Packet ID to check/flag + * @return True if this is a duplicate + */ + ZT_INLINE bool deduplicateIncomingPacket(const uint64_t packetId) noexcept + { + // TODO: should take instance ID into account too, but this isn't fully wired. + return m_dedup[Utils::hash32((uint32_t)packetId) & ZT_PEER_DEDUP_BUFFER_MASK].exchange(packetId) == packetId; + } + private: void m_prioritizePaths(int64_t now); unsigned int m_sendProbe(void *tPtr,int64_t localSocket,const InetAddress &atAddress,int64_t now); @@ -498,6 +515,9 @@ private: // The last time we got a probe from this peer. std::atomic m_lastProbeReceived; + // Deduplication buffer + std::atomic m_dedup[ZT_PEER_DEDUP_BUFFER_SIZE]; + // Meters measuring actual bandwidth in, out, and relayed via this peer (mostly if this is a root). Meter<> m_inMeter; Meter<> m_outMeter; diff --git a/node/Protocol.hpp b/node/Protocol.hpp index a09424b60..fbfc6a085 100644 --- a/node/Protocol.hpp +++ b/node/Protocol.hpp @@ -693,6 +693,34 @@ enum Verb // protocol max: 0x1f }; +#ifdef ZT_DEBUG_SPEW +static ZT_INLINE const char *verbName(const Verb v) noexcept +{ + switch(v) { + case VERB_NOP: return "NOP"; + case VERB_HELLO: return "HELLO"; + case VERB_ERROR: return "ERROR"; + case VERB_OK: return "OK"; + case VERB_WHOIS: return "WHOIS"; + case VERB_RENDEZVOUS: return "RENDEZVOUS"; + case VERB_FRAME: return "FRAME"; + case VERB_EXT_FRAME: return "EXT_FRAME"; + case VERB_ECHO: return "ECHO"; + case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE"; + case VERB_NETWORK_CREDENTIALS: return "NETWORK_CREDENTIALS"; + case VERB_NETWORK_CONFIG_REQUEST: return "NETWORK_CONFIG_REQUEST"; + case VERB_NETWORK_CONFIG: return "NETWORK_CONFIG"; + case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; + case VERB_MULTICAST_FRAME_deprecated: return "MULTICAST_FRAME_deprecated"; + case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; + case VERB_USER_MESSAGE: return "USER_MESSAGE"; + case VERB_MULTICAST: return "MULTICAST"; + case VERB_ENCAP: return "ENCAP"; + default: return "(unknown)"; + } +} +#endif + /** * Error codes used in ERROR packets. */ @@ -825,7 +853,7 @@ static ZT_INLINE int newPacket(uint8_t pkt[28],const uint64_t packetId,const Add destination.copyTo(pkt + ZT_PROTO_PACKET_DESTINATION_INDEX); source.copyTo(pkt + ZT_PROTO_PACKET_SOURCE_INDEX); pkt[ZT_PROTO_PACKET_FLAGS_INDEX] = 0; - // mac is left undefined as it's filled out by armor() + Utils::storeAsIsEndian(pkt + ZT_PROTO_PACKET_MAC_INDEX,0); pkt[ZT_PROTO_PACKET_VERB_INDEX] = (uint8_t)verb; return ZT_PROTO_PACKET_VERB_INDEX + 1; } diff --git a/node/Topology.cpp b/node/Topology.cpp index 7e1c582e6..1b9e26e61 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -31,7 +31,7 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : m_roots.insert(id); dptr += l; drem -= l; - ZT_SPEW("recalled root %s",id.address().toString().c_str()); + ZT_SPEW("loaded root %s",id.address().toString().c_str()); } } } diff --git a/node/Topology.hpp b/node/Topology.hpp index 72c45a11e..2c9ad36f3 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -297,7 +297,7 @@ private: void m_writeRootList(void *tPtr); // This gets an integer key from an InetAddress for looking up paths. - static ZT_INLINE uint64_t s_getPathKey(const int64_t l,const InetAddress &r) + static ZT_INLINE uint64_t s_getPathKey(const int64_t l,const InetAddress &r) noexcept { if (r.family() == AF_INET) { return ((uint64_t)(reinterpret_cast(&r)->sin_addr.s_addr) << 24U) + diff --git a/node/VL1.cpp b/node/VL1.cpp index 0fff5e1f0..8c5f7173e 100644 --- a/node/VL1.cpp +++ b/node/VL1.cpp @@ -103,13 +103,12 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd */ try { - // If this is too short to be a packet or fragment, check if it's a probe and - // if not simply drop it. + // 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()); + ZT_SPEW("probe %.8lx matches %u peers",(unsigned long)probeToken,peers.size()); for(unsigned int pi=0;pirateGateProbeRequest(now)) { ZT_SPEW("HELLO -> %s(%s)",peers[pi]->address().toString().c_str(),fromAddr.toString().c_str()); @@ -120,6 +119,9 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd return; } + static_assert((ZT_PROTO_PACKET_ID_INDEX + sizeof(uint64_t)) < ZT_PROTO_MIN_FRAGMENT_LENGTH,"overflow"); + const uint64_t packetId = Utils::loadAsIsEndian(data->unsafeData + ZT_PROTO_PACKET_ID_INDEX); + 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()) { @@ -131,9 +133,6 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd // If we made it this far, the packet is at least MIN_FRAGMENT_LENGTH and is addressed to this node's ZT address // ---------------------------------------------------------------------------------------------------------------- - static_assert((ZT_PROTO_PACKET_ID_INDEX + sizeof(uint64_t)) < ZT_PROTO_MIN_FRAGMENT_LENGTH,"overflow"); - const uint64_t packetId = Utils::loadAsIsEndian(data->unsafeData + ZT_PROTO_PACKET_ID_INDEX); - Buf::PacketVector pktv; static_assert(ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX <= ZT_PROTO_MIN_FRAGMENT_LENGTH,"overflow"); @@ -225,10 +224,6 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd return; } - // ---------------------------------------------------------------------------------------------------------------- - // 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. @@ -302,9 +297,16 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd // If authentication was successful go on and process the packet. 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); + ZT_SPEW("discarding packet %.16llx from %s(%s): assembled packet size %d is smaller than minimum packet length",packetId,source.toString().c_str(),fromAddr.toString().c_str(),pktSize); return; } + + // TODO: should take instance ID into account here once that is fully implemented. + if (unlikely(peer->deduplicateIncomingPacket(packetId))) { + ZT_SPEW("discarding packet %.16llx from %s(%s): duplicate!",packetId,source.toString().c_str(),fromAddr.toString().c_str()); + 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); @@ -320,8 +322,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd reinterpret_cast(dec->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START), pktSize - ZT_PROTO_PACKET_PAYLOAD_START, ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START); - - if (likely((uncompressedLen > 0)&&(uncompressedLen <= (ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START)))) { + 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; @@ -331,6 +332,8 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd } } + ZT_SPEW("%s from %s(%s) (%d bytes)",Protocol::verbName(verb),source.toString().c_str(),fromAddr.toString().c_str(),pktSize); + // 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 @@ -341,23 +344,23 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd switch(verb) { case Protocol::VERB_NOP: 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; + case Protocol::VERB_ERROR: ok = m_ERROR(tPtr, packetId, auth, path, peer, *pkt, pktSize, inReVerb); break; + case Protocol::VERB_OK: ok = m_OK(tPtr, packetId, auth, path, peer, *pkt, pktSize, inReVerb); break; + case Protocol::VERB_WHOIS: ok = m_WHOIS(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_RENDEZVOUS: ok = m_RENDEZVOUS(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_FRAME: ok = RR->vl2->m_FRAME(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_EXT_FRAME: ok = RR->vl2->m_EXT_FRAME(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_ECHO: ok = m_ECHO(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_MULTICAST_LIKE: ok = RR->vl2->m_MULTICAST_LIKE(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_NETWORK_CREDENTIALS: ok = RR->vl2->m_NETWORK_CREDENTIALS(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_NETWORK_CONFIG_REQUEST: ok = RR->vl2->m_NETWORK_CONFIG_REQUEST(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_NETWORK_CONFIG: ok = RR->vl2->m_NETWORK_CONFIG(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_MULTICAST_GATHER: ok = RR->vl2->m_MULTICAST_GATHER(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_MULTICAST_FRAME_deprecated: ok = RR->vl2->m_MULTICAST_FRAME_deprecated(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_PUSH_DIRECT_PATHS: ok = m_PUSH_DIRECT_PATHS(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_USER_MESSAGE: ok = m_USER_MESSAGE(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_MULTICAST: ok = RR->vl2->m_MULTICAST(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; + case Protocol::VERB_ENCAP: ok = m_ENCAP(tPtr, packetId, auth, path, peer, *pkt, pktSize); break; default: RR->t->incomingPacketDropped(tPtr,0xeeeeeff0,packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB); @@ -437,9 +440,6 @@ void VL1::m_sendPendingWhois(void *tPtr, int64_t now) SharedPtr VL1::m_HELLO(void *tPtr, const SharedPtr &path, Buf &pkt, int packetSize) { - // SECURITY: we know if we made it this far the packet's header is valid and - // packetSize is at least the size of a header. - const uint64_t packetId = Utils::loadAsIsEndian(pkt.unsafeData + ZT_PROTO_PACKET_ID_INDEX); const uint64_t mac = Utils::loadAsIsEndian(pkt.unsafeData + ZT_PROTO_PACKET_MAC_INDEX); const uint8_t hops = pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK; @@ -449,11 +449,12 @@ SharedPtr VL1::m_HELLO(void *tPtr, const SharedPtr &path, Buf &pkt, unsigned int versionMinor = pkt.lI8(); // LEGACY unsigned int versionRev = pkt.lI16(); // LEGACY const uint64_t timestamp = pkt.lI64(); - int p = ZT_PROTO_PACKET_PAYLOAD_START + 13; + + int ii = 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)) { + if (unlikely(pkt.rO(ii,id) < 0)) { RR->t->incomingPacketDropped(tPtr,0x707a9810,packetId,0,Identity::NIL,path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return SharedPtr(); } @@ -469,6 +470,10 @@ SharedPtr VL1::m_HELLO(void *tPtr, const SharedPtr &path, Buf &pkt, RR->t->incomingPacketDropped(tPtr,0x707a9891,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED); return SharedPtr(); } + if (peer->deduplicateIncomingPacket(packetId)) { + ZT_SPEW("discarding packet %.16llx from %s(%s): duplicate!",packetId,id.address().toString().c_str(),path->address().toString().c_str()); + return SharedPtr(); + } } else { if (unlikely(!id.locallyValidate())) { RR->t->incomingPacketDropped(tPtr,0x707a9892,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); @@ -530,7 +535,7 @@ SharedPtr VL1::m_HELLO(void *tPtr, const SharedPtr &path, Buf &pkt, // LEGACY: this is superseded by the sent-to field in the meta-data dictionary if present. InetAddress sentTo; - if (unlikely(pkt.rO(p,sentTo) < 0)) { + if (unlikely(pkt.rO(ii,sentTo) < 0)) { RR->t->incomingPacketDropped(tPtr,0x707a9811,packetId,0,identityFromPeerPtr(peer),path->address(),hops,Protocol::VERB_HELLO,ZT_TRACE_PACKET_DROP_REASON_INVALID_OBJECT); return SharedPtr(); } @@ -539,27 +544,27 @@ SharedPtr VL1::m_HELLO(void *tPtr, const SharedPtr &path, Buf &pkt, if (protoVersion >= 11) { // V2.x and newer supports an encrypted section and has a new OK format. - if ((p + 12) < packetSize) { + if (likely((ii + 12) < packetSize)) { uint64_t ctrNonce[2]; - ctrNonce[0] = Utils::loadAsIsEndian(pkt.unsafeData + p); + ctrNonce[0] = Utils::loadAsIsEndian(pkt.unsafeData + ii); #if __BYTE_ORDER == __BIG_ENDIAN - ctrNonce[1] = ((uint64_t)Utils::loadAsIsEndian(pkt.unsafeData + p + 8)) << 32U; + ctrNonce[1] = ((uint64_t)Utils::loadAsIsEndian(pkt.unsafeData + ii + 8)) << 32U; #else - ctrNonce[1] = Utils::loadAsIsEndian(pkt.unsafeData + p + 8); + ctrNonce[1] = Utils::loadAsIsEndian(pkt.unsafeData + ii + 8); #endif - p += 12; + ii += 12; AES::CTR ctr(peer->identityHelloDictionaryEncryptionCipher()); - ctr.init(reinterpret_cast(ctrNonce),pkt.unsafeData + p); - ctr.crypt(pkt.unsafeData + p,packetSize - p); + ctr.init(reinterpret_cast(ctrNonce),pkt.unsafeData + ii); + ctr.crypt(pkt.unsafeData + ii,packetSize - ii); ctr.finish(); - const unsigned int dictSize = pkt.rI16(p); - if (unlikely((p + dictSize) > packetSize)) { + const unsigned int dictSize = pkt.rI16(ii); + if (unlikely((ii + 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)) { + if (!md.decode(pkt.unsafeData + ii,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; } @@ -581,30 +586,35 @@ SharedPtr VL1::m_HELLO(void *tPtr, const SharedPtr &path, Buf &pkt, } 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); + ii = ZT_PROTO_PACKET_PAYLOAD_START; + pkt.wI8(ii,Protocol::VERB_HELLO); + pkt.wI64(ii,packetId); + pkt.wI64(ii,timestamp); + pkt.wI8(ii,(uint8_t)protoVersion); + + FCV okmd; + pkt.wI16(ii,(uint16_t)okmd.size()); + pkt.wB(ii,okmd.data(),okmd.size()); } 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); + ii = ZT_PROTO_PACKET_PAYLOAD_START; + pkt.wI8(ii,Protocol::VERB_HELLO); + pkt.wI64(ii,packetId); + pkt.wI64(ii,timestamp); + pkt.wI8(ii,(uint8_t)protoVersion); + pkt.wI8(ii,(uint8_t)versionMajor); + pkt.wI8(ii,(uint8_t)versionMinor); + pkt.wI16(ii,(uint16_t)versionRev); + pkt.wO(ii,path->address()); + pkt.wI16(ii,0); } peer->setRemoteVersion(protoVersion,versionMajor,versionMinor,versionRev); + peer->send(tPtr,RR->node->now(),pkt.unsafeData,ii,path); } -bool VL1::m_ERROR(void *tPtr,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb) +bool VL1::m_ERROR(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb) { #if 0 if (packetSize < (int)sizeof(Protocol::ERROR::Header)) { @@ -648,24 +658,29 @@ bool VL1::m_ERROR(void *tPtr,const unsigned int auth, const SharedPtr &pat } return true; +#endif } -bool VL1::m_OK(void *tPtr,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb) +bool VL1::m_OK(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, const SharedPtr &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); + int ii = ZT_PROTO_PACKET_PAYLOAD_START + 13; + + inReVerb = (Protocol::Verb)pkt.rI8(ii); + const uint64_t inRePacketId = pkt.rI64(ii); + if (unlikely(Buf::readOverflow(ii,packetSize))) { + RR->t->incomingPacketDropped(tPtr,0x4c1f1ff7,packetId,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)) { - RR->t->incomingPacketDropped(tPtr,0x4c1f1ff7,0,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_OK,ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED); + if (!RR->expect->expecting(inRePacketId,now)) { + RR->t->incomingPacketDropped(tPtr,0x4c1f1ff8,packetId,0,identityFromPeerPtr(peer),path->address(),0,Protocol::VERB_OK,ZT_TRACE_PACKET_DROP_REASON_REPLY_NOT_EXPECTED); return false; } - switch(oh.inReVerb) { + ZT_SPEW("got OK in-re %s (packet ID %.16llx) from %s(%s)",Protocol::verbName(inReVerb),inRePacketId,peer->address().toString().c_str(),path->address().toString().c_str()); + + switch(inReVerb) { case Protocol::VERB_HELLO: break; @@ -680,11 +695,11 @@ bool VL1::m_OK(void *tPtr,const unsigned int auth, const SharedPtr &path, break; } + return true; -#endif } -bool VL1::m_WHOIS(void *tPtr,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) +bool VL1::m_WHOIS(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) { #if 0 if (packetSize < (int)sizeof(Protocol::OK::Header)) { @@ -738,7 +753,7 @@ bool VL1::m_WHOIS(void *tPtr,const unsigned int auth, const SharedPtr &pat #endif } -bool VL1::m_RENDEZVOUS(void *tPtr,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) +bool VL1::m_RENDEZVOUS(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) { #if 0 if (RR->topology->isRoot(peer->identity())) { @@ -786,7 +801,7 @@ bool VL1::m_RENDEZVOUS(void *tPtr,const unsigned int auth, const SharedPtr #endif } -bool VL1::m_ECHO(void *tPtr,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) +bool VL1::m_ECHO(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) { #if 0 const uint64_t packetId = Protocol::packetId(pkt,packetSize); @@ -824,7 +839,7 @@ bool VL1::m_ECHO(void *tPtr,const unsigned int auth, const SharedPtr &path #endif } -bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) +bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) { #if 0 if (packetSize < (int)sizeof(Protocol::PUSH_DIRECT_PATHS)) { @@ -915,13 +930,13 @@ bool VL1::m_PUSH_DIRECT_PATHS(void *tPtr,const unsigned int auth, const SharedPt #endif } -bool VL1::m_USER_MESSAGE(void *tPtr,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) +bool VL1::m_USER_MESSAGE(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) { // TODO return true; } -bool VL1::m_ENCAP(void *tPtr,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) +bool VL1::m_ENCAP(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize) { // TODO: not implemented yet return true; diff --git a/node/VL1.hpp b/node/VL1.hpp index e36ff4634..6242e8000 100644 --- a/node/VL1.hpp +++ b/node/VL1.hpp @@ -70,17 +70,19 @@ private: SharedPtr m_HELLO(void *tPtr, const SharedPtr &path, Buf &pkt, int packetSize); - bool m_ERROR(void *tPtr, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb); - bool m_OK(void *tPtr, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb); - bool m_WHOIS(void *tPtr, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); - bool m_RENDEZVOUS(void *tPtr, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); - bool m_ECHO(void *tPtr, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); - bool m_PUSH_DIRECT_PATHS(void *tPtr, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); - bool m_USER_MESSAGE(void *tPtr, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); - bool m_ENCAP(void *tPtr, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); + bool m_ERROR(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb); + bool m_OK(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb); + bool m_WHOIS(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); + bool m_RENDEZVOUS(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); + bool m_ECHO(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); + bool m_PUSH_DIRECT_PATHS(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); + bool m_USER_MESSAGE(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); + bool m_ENCAP(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, const SharedPtr &peer, Buf &pkt, int packetSize); + // Defragmentation engine for handling inbound packets with more than one fragment. Defragmenter m_inputPacketAssembler; + // Queue of outbound WHOIS reqeusts and packets waiting on them. struct p_WhoisQueueItem { ZT_INLINE p_WhoisQueueItem() : lastRetry(0),retries(0),waitingPacketCount(0) {} diff --git a/node/VL2.cpp b/node/VL2.cpp index cea77982c..72c69cfa9 100644 --- a/node/VL2.cpp +++ b/node/VL2.cpp @@ -27,43 +27,43 @@ VL2::VL2(const RuntimeEnvironment *renv) { } -void VL2::onLocalEthernet(void *const tPtr,const unsigned int auth,const SharedPtr &network,const MAC &from,const MAC &to,const unsigned int etherType,unsigned int vlanId,SharedPtr &data,unsigned int len) +void VL2::onLocalEthernet(void *const tPtr,const uint64_t packetId,const unsigned int auth,const SharedPtr &network,const MAC &from,const MAC &to,const unsigned int etherType,unsigned int vlanId,SharedPtr &data,unsigned int len) { } -bool VL2::m_FRAME(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_FRAME(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } -bool VL2::m_EXT_FRAME(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_EXT_FRAME(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } -bool VL2::m_MULTICAST_LIKE(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_MULTICAST_LIKE(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } -bool VL2::m_NETWORK_CREDENTIALS(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_NETWORK_CREDENTIALS(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } -bool VL2::m_NETWORK_CONFIG_REQUEST(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_NETWORK_CONFIG_REQUEST(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } -bool VL2::m_NETWORK_CONFIG(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_NETWORK_CONFIG(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } -bool VL2::m_MULTICAST_GATHER(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_MULTICAST_GATHER(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } -bool VL2::m_MULTICAST_FRAME_deprecated(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_MULTICAST_FRAME_deprecated(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } -bool VL2::m_MULTICAST(void *tPtr,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) +bool VL2::m_MULTICAST(void *tPtr,const uint64_t packetId,const unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize) { } diff --git a/node/VL2.hpp b/node/VL2.hpp index 31c7a4e58..bff719f2f 100644 --- a/node/VL2.hpp +++ b/node/VL2.hpp @@ -53,15 +53,15 @@ public: void onLocalEthernet(void *tPtr,const SharedPtr &network,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,SharedPtr &data,unsigned int len); protected: - bool m_FRAME(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); - bool m_EXT_FRAME(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); - bool m_MULTICAST_LIKE(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); - bool m_NETWORK_CREDENTIALS(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); - bool m_NETWORK_CONFIG_REQUEST(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); - bool m_NETWORK_CONFIG(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); - bool m_MULTICAST_GATHER(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); - bool m_MULTICAST_FRAME_deprecated(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); - bool m_MULTICAST(void *tPtr, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_FRAME(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_EXT_FRAME(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_MULTICAST_LIKE(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_NETWORK_CREDENTIALS(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_NETWORK_CONFIG_REQUEST(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_NETWORK_CONFIG(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_MULTICAST_GATHER(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_MULTICAST_FRAME_deprecated(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); + bool m_MULTICAST(void *tPtr, uint64_t packetId, unsigned int auth, const SharedPtr &path, SharedPtr &peer, Buf &pkt, int packetSize); private: };