Add Bonds, Slaves, and Flows
This commit is contained in:
parent
de9cfbe9b0
commit
a50e8e9878
31 changed files with 4898 additions and 1966 deletions
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Copyright (c)2019 ZeroTier, Inc.
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2023-01-01
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
|
@ -35,10 +35,12 @@
|
|||
#include "Tag.hpp"
|
||||
#include "Revocation.hpp"
|
||||
#include "Trace.hpp"
|
||||
#include "Path.hpp"
|
||||
#include "Bond.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
||||
bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t flowId)
|
||||
{
|
||||
const Address sourceAddress(source());
|
||||
|
||||
|
@ -67,7 +69,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
|||
if (!trusted) {
|
||||
if (!dearmor(peer->key())) {
|
||||
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC");
|
||||
_path->recordInvalidPacket();
|
||||
peer->recordIncomingInvalidPacket(_path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -78,11 +80,12 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
|||
}
|
||||
|
||||
const Packet::Verb v = verb();
|
||||
|
||||
bool r = true;
|
||||
switch(v) {
|
||||
//case Packet::VERB_NOP:
|
||||
default: // ignore unknown verbs, but if they pass auth check they are "received"
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
break;
|
||||
case Packet::VERB_HELLO: r = _doHELLO(RR,tPtr,true); break;
|
||||
case Packet::VERB_ACK: r = _doACK(RR,tPtr,peer); break;
|
||||
|
@ -91,8 +94,8 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
|||
case Packet::VERB_OK: r = _doOK(RR,tPtr,peer); break;
|
||||
case Packet::VERB_WHOIS: r = _doWHOIS(RR,tPtr,peer); break;
|
||||
case Packet::VERB_RENDEZVOUS: r = _doRENDEZVOUS(RR,tPtr,peer); break;
|
||||
case Packet::VERB_FRAME: r = _doFRAME(RR,tPtr,peer); break;
|
||||
case Packet::VERB_EXT_FRAME: r = _doEXT_FRAME(RR,tPtr,peer); break;
|
||||
case Packet::VERB_FRAME: r = _doFRAME(RR,tPtr,peer,flowId); break;
|
||||
case Packet::VERB_EXT_FRAME: r = _doEXT_FRAME(RR,tPtr,peer,flowId); break;
|
||||
case Packet::VERB_ECHO: r = _doECHO(RR,tPtr,peer); break;
|
||||
case Packet::VERB_MULTICAST_LIKE: r = _doMULTICAST_LIKE(RR,tPtr,peer); break;
|
||||
case Packet::VERB_NETWORK_CREDENTIALS: r = _doNETWORK_CREDENTIALS(RR,tPtr,peer); break;
|
||||
|
@ -103,6 +106,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
|||
case Packet::VERB_PUSH_DIRECT_PATHS: r = _doPUSH_DIRECT_PATHS(RR,tPtr,peer); break;
|
||||
case Packet::VERB_USER_MESSAGE: r = _doUSER_MESSAGE(RR,tPtr,peer); break;
|
||||
case Packet::VERB_REMOTE_TRACE: r = _doREMOTE_TRACE(RR,tPtr,peer); break;
|
||||
case Packet::VERB_PATH_NEGOTIATION_REQUEST: r = _doPATH_NEGOTIATION_REQUEST(RR,tPtr,peer); break;
|
||||
}
|
||||
if (r) {
|
||||
RR->node->statsLogVerb((unsigned int)v,(unsigned int)size());
|
||||
|
@ -113,9 +117,6 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
|
|||
RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress);
|
||||
return false;
|
||||
}
|
||||
} catch (int ztExcCode) {
|
||||
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()");
|
||||
return true;
|
||||
} catch ( ... ) {
|
||||
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),sourceAddress,hops(),verb(),"unexpected exception in tryDecode()");
|
||||
return true;
|
||||
|
@ -193,59 +194,59 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
|
|||
default: break;
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,networkId);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_ERROR,inRePacketId,inReVerb,false,networkId,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (!peer->rateGateACK(RR->node->now()))
|
||||
SharedPtr<Bond> bond = peer->bond();
|
||||
if (!bond || !bond->rateGateACK(RR->node->now())) {
|
||||
return true;
|
||||
}
|
||||
/* Dissect incoming ACK packet. From this we can estimate current throughput of the path, establish known
|
||||
* maximums and detect packet loss. */
|
||||
if (peer->localMultipathSupport()) {
|
||||
int32_t ackedBytes;
|
||||
if (payloadLength() != sizeof(ackedBytes)) {
|
||||
return true; // ignore
|
||||
}
|
||||
memcpy(&ackedBytes, payload(), sizeof(ackedBytes));
|
||||
_path->receivedAck(RR->node->now(), Utils::ntoh(ackedBytes));
|
||||
peer->inferRemoteMultipathEnabled();
|
||||
int32_t ackedBytes;
|
||||
if (payloadLength() != sizeof(ackedBytes)) {
|
||||
return true; // ignore
|
||||
}
|
||||
memcpy(&ackedBytes, payload(), sizeof(ackedBytes));
|
||||
if (bond) {
|
||||
bond->receivedAck(_path, RR->node->now(), Utils::ntoh(ackedBytes));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (!peer->rateGateQoS(RR->node->now()))
|
||||
SharedPtr<Bond> bond = peer->bond();
|
||||
if (!bond || !bond->rateGateQoS(RR->node->now())) {
|
||||
return true;
|
||||
}
|
||||
/* Dissect incoming QoS packet. From this we can compute latency values and their variance.
|
||||
* The latency variance is used as a measure of "jitter". */
|
||||
if (peer->localMultipathSupport()) {
|
||||
if (payloadLength() > ZT_PATH_MAX_QOS_PACKET_SZ || payloadLength() < ZT_PATH_MIN_QOS_PACKET_SZ) {
|
||||
return true; // ignore
|
||||
}
|
||||
const int64_t now = RR->node->now();
|
||||
uint64_t rx_id[ZT_PATH_QOS_TABLE_SIZE];
|
||||
uint16_t rx_ts[ZT_PATH_QOS_TABLE_SIZE];
|
||||
char *begin = (char *)payload();
|
||||
char *ptr = begin;
|
||||
int count = 0;
|
||||
int len = payloadLength();
|
||||
// Read packet IDs and latency compensation intervals for each packet tracked by this QoS packet
|
||||
while (ptr < (begin + len) && (count < ZT_PATH_QOS_TABLE_SIZE)) {
|
||||
memcpy((void*)&rx_id[count], ptr, sizeof(uint64_t));
|
||||
ptr+=sizeof(uint64_t);
|
||||
memcpy((void*)&rx_ts[count], ptr, sizeof(uint16_t));
|
||||
ptr+=sizeof(uint16_t);
|
||||
count++;
|
||||
}
|
||||
_path->receivedQoS(now, count, rx_id, rx_ts);
|
||||
peer->inferRemoteMultipathEnabled();
|
||||
if (payloadLength() > ZT_QOS_MAX_PACKET_SIZE || payloadLength() < ZT_QOS_MIN_PACKET_SIZE) {
|
||||
return true; // ignore
|
||||
}
|
||||
const int64_t now = RR->node->now();
|
||||
uint64_t rx_id[ZT_QOS_TABLE_SIZE];
|
||||
uint16_t rx_ts[ZT_QOS_TABLE_SIZE];
|
||||
char *begin = (char *)payload();
|
||||
char *ptr = begin;
|
||||
int count = 0;
|
||||
unsigned int len = payloadLength();
|
||||
// Read packet IDs and latency compensation intervals for each packet tracked by this QoS packet
|
||||
while (ptr < (begin + len) && (count < ZT_QOS_TABLE_SIZE)) {
|
||||
memcpy((void*)&rx_id[count], ptr, sizeof(uint64_t));
|
||||
ptr+=sizeof(uint64_t);
|
||||
memcpy((void*)&rx_ts[count], ptr, sizeof(uint16_t));
|
||||
ptr+=sizeof(uint16_t);
|
||||
count++;
|
||||
}
|
||||
if (bond) {
|
||||
bond->receivedQoS(_path, now, count, rx_id, rx_ts);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -441,11 +442,12 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
|||
}
|
||||
outp.setAt<uint16_t>(worldUpdateSizeAt,(uint16_t)(outp.size() - (worldUpdateSizeAt + 2)));
|
||||
|
||||
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
|
||||
peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
|
||||
peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_HELLO,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_HELLO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -493,7 +495,10 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
|
|||
}
|
||||
|
||||
if (!hops()) {
|
||||
_path->updateLatency((unsigned int)latency,RR->node->now());
|
||||
SharedPtr<Bond> bond = peer->bond();
|
||||
if (!bond) {
|
||||
_path->updateLatency((unsigned int)latency,RR->node->now());
|
||||
}
|
||||
}
|
||||
|
||||
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
|
||||
|
@ -522,8 +527,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
|
|||
if (network) {
|
||||
const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI));
|
||||
const unsigned int count = at<uint16_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4);
|
||||
if (((ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6) + (count * 5)) <= size())
|
||||
RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS));
|
||||
RR->mc->addMultiple(tPtr,RR->node->now(),networkId,mg,field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 6,count * 5),count,at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS));
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -556,7 +560,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
|
|||
default: break;
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_OK,inRePacketId,inReVerb,false,networkId);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_OK,inRePacketId,inReVerb,false,networkId,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -591,7 +595,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar
|
|||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -615,13 +619,108 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const
|
|||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
// Returns true if packet appears valid; pos and proto will be set
|
||||
static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsigned int &pos,unsigned int &proto)
|
||||
{
|
||||
if (frameLen < 40)
|
||||
return false;
|
||||
pos = 40;
|
||||
proto = frameData[6];
|
||||
while (pos <= frameLen) {
|
||||
switch(proto) {
|
||||
case 0: // hop-by-hop options
|
||||
case 43: // routing
|
||||
case 60: // destination options
|
||||
case 135: // mobility options
|
||||
if ((pos + 8) > frameLen)
|
||||
return false; // invalid!
|
||||
proto = frameData[pos];
|
||||
pos += ((unsigned int)frameData[pos + 1] * 8) + 8;
|
||||
break;
|
||||
|
||||
//case 44: // fragment -- we currently can't parse these and they are deprecated in IPv6 anyway
|
||||
//case 50:
|
||||
//case 51: // IPSec ESP and AH -- we have to stop here since this is encrypted stuff
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // overflow == invalid
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId)
|
||||
{
|
||||
int32_t _flowId = ZT_QOS_NO_FLOW;
|
||||
SharedPtr<Bond> bond = peer->bond();
|
||||
if (bond && bond->flowHashingEnabled()) {
|
||||
if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
|
||||
const unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
|
||||
const unsigned int frameLen = size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
|
||||
const uint8_t *const frameData = reinterpret_cast<const uint8_t *>(data()) + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD;
|
||||
|
||||
if (etherType == ZT_ETHERTYPE_IPV4 && (frameLen >= 20)) {
|
||||
uint16_t srcPort = 0;
|
||||
uint16_t dstPort = 0;
|
||||
uint8_t proto = (reinterpret_cast<const uint8_t *>(frameData)[9]);
|
||||
const unsigned int headerLen = 4 * (reinterpret_cast<const uint8_t *>(frameData)[0] & 0xf);
|
||||
switch(proto) {
|
||||
case 0x01: // ICMP
|
||||
//flowId = 0x01;
|
||||
break;
|
||||
// All these start with 16-bit source and destination port in that order
|
||||
case 0x06: // TCP
|
||||
case 0x11: // UDP
|
||||
case 0x84: // SCTP
|
||||
case 0x88: // UDPLite
|
||||
if (frameLen > (headerLen + 4)) {
|
||||
unsigned int pos = headerLen + 0;
|
||||
srcPort = (reinterpret_cast<const uint8_t *>(frameData)[pos++]) << 8;
|
||||
srcPort |= (reinterpret_cast<const uint8_t *>(frameData)[pos]);
|
||||
pos++;
|
||||
dstPort = (reinterpret_cast<const uint8_t *>(frameData)[pos++]) << 8;
|
||||
dstPort |= (reinterpret_cast<const uint8_t *>(frameData)[pos]);
|
||||
_flowId = dstPort ^ srcPort ^ proto;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (etherType == ZT_ETHERTYPE_IPV6 && (frameLen >= 40)) {
|
||||
uint16_t srcPort = 0;
|
||||
uint16_t dstPort = 0;
|
||||
unsigned int pos;
|
||||
unsigned int proto;
|
||||
_ipv6GetPayload((const uint8_t *)frameData, frameLen, pos, proto);
|
||||
switch(proto) {
|
||||
case 0x3A: // ICMPv6
|
||||
//flowId = 0x3A;
|
||||
break;
|
||||
// All these start with 16-bit source and destination port in that order
|
||||
case 0x06: // TCP
|
||||
case 0x11: // UDP
|
||||
case 0x84: // SCTP
|
||||
case 0x88: // UDPLite
|
||||
if (frameLen > (pos + 4)) {
|
||||
srcPort = (reinterpret_cast<const uint8_t *>(frameData)[pos++]) << 8;
|
||||
srcPort |= (reinterpret_cast<const uint8_t *>(frameData)[pos]);
|
||||
pos++;
|
||||
dstPort = (reinterpret_cast<const uint8_t *>(frameData)[pos++]) << 8;
|
||||
dstPort |= (reinterpret_cast<const uint8_t *>(frameData)[pos]);
|
||||
_flowId = dstPort ^ srcPort ^ proto;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID);
|
||||
const SharedPtr<Network> network(RR->node->network(nwid));
|
||||
bool trustEstablished = false;
|
||||
|
@ -641,13 +740,12 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished,nwid);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished,nwid,_flowId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,int32_t flowId)
|
||||
{
|
||||
const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID);
|
||||
const SharedPtr<Network> network(RR->node->network(nwid));
|
||||
|
@ -676,7 +774,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
|
|||
const uint8_t *const frameData = (const uint8_t *)field(comLen + ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD,frameLen);
|
||||
|
||||
if ((!from)||(from == network->mac())) {
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); // trustEstablished because COM is okay
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -687,19 +785,19 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
|
|||
network->learnBridgeRoute(from,peer->address());
|
||||
} else {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (remote)");
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); // trustEstablished because COM is okay
|
||||
return true;
|
||||
}
|
||||
} else if (to != network->mac()) {
|
||||
if (to.isMulticast()) {
|
||||
if (network->config().multicastLimit == 0) {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"multicast disabled");
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); // trustEstablished because COM is okay
|
||||
return true;
|
||||
}
|
||||
} else if (!network->config().permitsBridging(RR->identity.address())) {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,from,to,"bridging not allowed (local)");
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId); // trustEstablished because COM is okay
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -715,13 +813,15 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
|
|||
outp.append((uint8_t)Packet::VERB_EXT_FRAME);
|
||||
outp.append((uint64_t)packetId());
|
||||
outp.append((uint64_t)nwid);
|
||||
const int64_t now = RR->node->now();
|
||||
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true,nwid,flowId);
|
||||
} else {
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid,flowId);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -729,8 +829,10 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
|
|||
|
||||
bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
if (!peer->rateGateEchoRequest(RR->node->now()))
|
||||
uint64_t now = RR->node->now();
|
||||
if (!peer->rateGateEchoRequest(now)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint64_t pid = packetId();
|
||||
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
|
||||
|
@ -738,10 +840,11 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share
|
|||
outp.append((uint64_t)pid);
|
||||
if (size() > ZT_PACKET_IDX_PAYLOAD)
|
||||
outp.append(reinterpret_cast<const unsigned char *>(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
|
||||
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
|
||||
peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -767,7 +870,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,c
|
|||
RR->mc->add(tPtr,now,nwid,MulticastGroup(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14)),peer->address());
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -889,7 +992,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t
|
|||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_NETWORK_CREDENTIALS,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -915,7 +1018,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void
|
|||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hopCount,requestPacketId,payloadLength(),Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false,nwid);
|
||||
peer->received(tPtr,_path,hopCount,requestPacketId,payloadLength(),Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,false,nwid,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -931,12 +1034,14 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c
|
|||
outp.append((uint64_t)packetId());
|
||||
outp.append((uint64_t)network->id());
|
||||
outp.append((uint64_t)configUpdateId);
|
||||
const int64_t now = RR->node->now();
|
||||
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false,(network) ? network->id() : 0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false,(network) ? network->id() : 0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -979,12 +1084,13 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
|
|||
outp.append((uint32_t)mg.adi());
|
||||
const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit);
|
||||
if (gatheredLocally > 0) {
|
||||
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished,nwid);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_GATHER,0,Packet::VERB_NOP,trustEstablished,nwid,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1032,19 +1138,19 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
|
|||
|
||||
if (network->config().multicastLimit == 0) {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"multicast disabled");
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid,ZT_QOS_NO_FLOW);
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) {
|
||||
if (!to.mac().isMulticast()) {
|
||||
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"destination not multicast");
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW); // trustEstablished because COM is okay
|
||||
return true;
|
||||
}
|
||||
if ((!from)||(from.isMulticast())||(from == network->mac())) {
|
||||
RR->t->incomingPacketInvalid(tPtr,_path,packetId(),source(),hops(),Packet::VERB_MULTICAST_FRAME,"invalid source MAC");
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW); // trustEstablished because COM is okay
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1058,7 +1164,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
|
|||
network->learnBridgeRoute(from,peer->address());
|
||||
} else {
|
||||
RR->t->incomingNetworkFrameDropped(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,from,to.mac(),"bridging not allowed (remote)");
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid); // trustEstablished because COM is okay
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW); // trustEstablished because COM is okay
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1076,12 +1182,14 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
|
|||
outp.append((uint32_t)to.adi());
|
||||
outp.append((unsigned char)0x02); // flag 0x02 = contains gather results
|
||||
if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) {
|
||||
const int64_t now = RR->node->now();
|
||||
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
|
||||
outp.armor(peer->key(),true);
|
||||
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
|
||||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW);
|
||||
} else {
|
||||
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
|
||||
return false;
|
||||
|
@ -1094,9 +1202,8 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
|||
{
|
||||
const int64_t now = RR->node->now();
|
||||
|
||||
// First, subject this to a rate limit
|
||||
if (!peer->rateGatePushDirectPaths(now)) {
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1108,8 +1215,6 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
|||
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2;
|
||||
|
||||
while (count--) { // if ptr overflows Buffer will throw
|
||||
// TODO: some flags are not yet implemented
|
||||
|
||||
unsigned int flags = (*this)[ptr++];
|
||||
unsigned int extLen = at<uint16_t>(ptr); ptr += 2;
|
||||
ptr += extLen; // unused right now
|
||||
|
@ -1132,6 +1237,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
|||
}
|
||||
} break;
|
||||
case 6: {
|
||||
|
||||
const InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
|
||||
if (
|
||||
((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget
|
||||
|
@ -1149,7 +1255,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
|||
ptr += addrLen;
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1165,7 +1271,7 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con
|
|||
RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast<const void *>(&um));
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1189,11 +1295,29 @@ bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,con
|
|||
}
|
||||
}
|
||||
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_REMOTE_TRACE,0,Packet::VERB_NOP,false,0);
|
||||
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_REMOTE_TRACE,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IncomingPacket::_doPATH_NEGOTIATION_REQUEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
|
||||
{
|
||||
uint64_t now = RR->node->now();
|
||||
SharedPtr<Bond> bond = peer->bond();
|
||||
if (!bond || !bond->rateGatePathNegotiation(now)) {
|
||||
return true;
|
||||
}
|
||||
if (payloadLength() != sizeof(int16_t)) {
|
||||
return true;
|
||||
}
|
||||
int16_t remoteUtility = 0;
|
||||
memcpy(&remoteUtility, payload(), sizeof(int16_t));
|
||||
if (peer->bond()) {
|
||||
peer->bond()->processIncomingPathNegotiationRequest(now, _path, Utils::ntoh(remoteUtility));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid)
|
||||
{
|
||||
Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue