Merge pull request #2306 from zerotier/fix-flows-for-bridge-mode-mp
Some checks are pending
/ build_macos (push) Waiting to run
/ build_windows (push) Waiting to run
/ build_ubuntu (push) Waiting to run

Fix flow assignment for bridged EXT_FRAME packets
This commit is contained in:
Adam Ierymenko 2025-07-10 15:52:03 -04:00 committed by GitHub
commit 5fb8d2aa37
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -774,64 +774,66 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment* RR, void* tPtr, const Sh
Metrics::pkt_frame_in++;
int32_t _flowId = ZT_QOS_NO_FLOW;
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 (peer->flowHashingSupported()) {
if (size() > ZT_PROTO_VERB_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_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;
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;
}
}
}
}
@ -865,6 +867,72 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment* RR, void* tPtr, const Sh
bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer, int32_t flowId)
{
Metrics::pkt_ext_frame_in++;
int32_t _flowId = ZT_QOS_NO_FLOW;
if (peer->flowHashingSupported()) {
if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
const unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE);
const unsigned int frameLen = size() - ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD;
const uint8_t* const frameData = reinterpret_cast<const uint8_t*>(data()) + ZT_PROTO_VERB_EXT_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_EXT_FRAME_IDX_NETWORK_ID);
const SharedPtr<Network> network(RR->node->network(nwid));
if (network) {
@ -893,7 +961,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, cons
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, flowId); // 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;
}
@ -905,7 +973,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, cons
}
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, flowId); // 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;
}
}
@ -913,19 +981,19 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, cons
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, flowId); // 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, flowId); // 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;
}
}
// fall through -- 2 means accept regardless of bridging checks or other restrictions
case 2:
RR->pm->putFrame(tPtr, nwid, network->userPtr(), from, to, etherType, 0, (const void*)frameData, frameLen, flowId);
RR->pm->putFrame(tPtr, nwid, network->userPtr(), from, to, etherType, 0, (const void*)frameData, frameLen, _flowId);
break;
}
}
@ -942,10 +1010,10 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment* RR, void* tPtr, cons
_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, flowId);
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, flowId);
peer->received(tPtr, _path, hops(), packetId(), payloadLength(), Packet::VERB_EXT_FRAME, 0, Packet::VERB_NOP, false, nwid, _flowId);
}
return true;