Category
Other
Hardware
Not Applicable
Is this bug report about any UI component firmware like InkHUD or Meshtatic UI (MUI)?
Firmware Version
2.7.19
Description
Issue description and repro
If we use a MQTT server with "encryption" enabled, a node that receives a traceroute packet should add itself to the route and then send that packet to the MQTT server.
Instead it adds itself to the route, sends the altered packet through RF and sends the original received packet to the MQTT server.
This means that any traceroute transversing the MQTT server will miss the node that uplinked the packet to the MQTT server.
This can be easily reproduced with two RF nodes, an MQTT server and a meshtasticD node without RF. Steps to reproduce:
1- Configure one node (DomusOnlineHT-CL-8 in this example) with RF, without MQTT server
2- Configure one node (DomusOnlineT2 in this example) with RF, with MQTT server (encrypted)
3- Configure one node (DomusOnlineD-CL-8 in this example) without RF, with MQTT server (encrypted)
4- Send a traceroute from DomusOnlineHT-CL-8 to DomusOnlineD-CL-8. This can only reach the destination through DomusOnlineT2 which will upload it to MQTT server. The destination will download it and respond. The effect:

5- Now remove the Encryption of the MQTT server on both nodes. Resend the traceroute. The effect:

Explanation
On src/Router.cpp we can see the following lines of code:
void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
{
bool skipHandle = false;
// Also, we should set the time from the ISR and it should have msec level resolution
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
// Store a copy of encrypted packet for MQTT
DEBUG_HEAP_BEFORE;
p_encrypted = packetPool.allocCopy(*p);
DEBUG_HEAP_AFTER("Router::handleReceived", p_encrypted);
So, the original received packet is saved as "p_encrypted".
later in the same method we can see:
// call modules here
// If this could be a spoofed packet, don't let the modules see it.
if (!skipHandle) {
MeshModule::callModules(*p, src);
#if !MESHTASTIC_EXCLUDE_MQTT
if (p_encrypted == nullptr) {
LOG_WARN("p_encrypted is null, skipping MQTT publish");
} else {
// Mark as pki_encrypted if it is not yet decoded and MQTT encryption is also enabled, hash matches and it's a DM not
// to us (because we would be able to decrypt it)
if (decodedState == DecodeState::DECODE_FAILURE && moduleConfig.mqtt.encryption_enabled && p->channel == 0x00 &&
!isBroadcast(p->to) && !isToUs(p))
p_encrypted->pki_encrypted = true;
// After potentially altering it, publish received message to MQTT if we're not the original transmitter of the packet
if ((decodedState == DecodeState::DECODE_SUCCESS || p_encrypted->pki_encrypted) && moduleConfig.mqtt.enabled &&
!isFromUs(p) && mqtt)
mqtt->onSend(*p_encrypted, *p, p->channel);
}
#endif
So, the modules are called AFTER saving the encrypted packet. TraceRoute is one of the modules. So the change in the packet, where the node adds itself to the route is called after.
Later the mqtt->onSend() method is called, sending both the encrypted and the decrypted packets.
In that method we have:
void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_MeshPacket &mp_decoded, ChannelIndex chIndex)
{
[...]
LOG_DEBUG("MQTT onSend - Publish ");
const meshtastic_MeshPacket *p;
if (moduleConfig.mqtt.encryption_enabled) {
p = &mp_encrypted;
LOG_DEBUG("encrypted message");
} else if (mp_decoded.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
p = &mp_decoded;
LOG_DEBUG("portnum %i message", mp_decoded.decoded.portnum);
} else {
LOG_DEBUG("nothing, pkt not decrypted");
return; // Don't upload a still-encrypted PKI packet if not encryption_enabled
}
// Generate node ID from nodenum for service envelope
std::string nodeId = nodeDB->getNodeId();
const meshtastic_ServiceEnvelope env = {.packet = const_cast<meshtastic_MeshPacket *>(p),
.channel_id = const_cast<char *>(channelId),
.gateway_id = const_cast<char *>(nodeId.c_str())};
So, if the option to encrypt is set, we use the original packet, and not the one that was changed.
Relevant log output
For the wrong behavior:
Feb 22 02:27:24 DOH2_9468 RadioIf [1117]: Lora RX (id=0x99c71b9f fr=0xdb2aca70 to=0xccddeeff, transport = 0, WantAck=1, HopLim=5 Ch=0x8 encrypted len=22 rxSNR=7 rxRSSI=-66 hopStart=5 nextHop=0xff relay=0x70)
Feb 22 02:27:24 DOH2_9468 RadioIf [1117]: Packet RX: 395ms
Feb 22 02:27:24 DOH2_9468 Router [1117]: Packet History - insert: Using new slot @uptime 1117.462s TRACE NEW
Feb 22 02:27:24 DOH2_9468 Router [1117]: Use channel 0 (hash 0x8)
Feb 22 02:27:24 DOH2_9468 Router [1117]: Expand short PSK #1
Feb 22 02:27:24 DOH2_9468 Router [1117]: Use AES128 key!
Feb 22 02:27:24 DOH2_9468 Router [1117]: decoded message (id=0x99c71b9f fr=0xdb2aca70 to=0xccddeeff, transport = 1, WantAck=1, HopLim=5 Ch=0x0 Portnum=70 WANTRESP rxtime=1771727319 rxSNR=7 rxRSSI=-66 hopStart=5 nextHop=0xff relay=0x70)
Feb 22 02:27:24 DOH2_9468 Router [1117]: handleReceived(REMOTE) (id=0x99c71b9f fr=0xdb2aca70 to=0xccddeeff, transport = 1, WantAck=1, HopLim=5 Ch=0x0 Portnum=70 WANTRESP rxtime=1771727319 rxSNR=7 rxRSSI=-66 hopStart=5 nextHop=0xff relay=0x70)
Feb 22 02:27:24 DOH2_9468 Router [1117]: Module 'traceroute' wantsPacket=1
Feb 22 02:27:24 DOH2_9468 Router [1117]: Received traceroute from=0xdb2aca70, id=0x99c71b9f, portnum=70, payloadlen=0
Feb 22 02:27:24 DOH2_9468 Router [1117]: Route traced:#0120xdb2aca70 --> 0x433c9468 (7.00dB) --> ...
Feb 22 02:27:24 DOH2_9468 Router [1117]: Module 'traceroute' considered
Feb 22 02:27:24 DOH2_9468 Router [1117]: Module 'routing' wantsPacket=1
Feb 22 02:27:24 DOH2_9468 Router [1117]: Received routing from=0xdb2aca70, id=0x99c71b9f, portnum=70, payloadlen=9
Feb 22 02:27:24 DOH2_9468 Router [1117]: Routing sniffing (id=0x99c71b9f fr=0xdb2aca70 to=0xccddeeff, transport = 1, WantAck=1, HopLim=5 Ch=0x0 Portnum=70 WANTRESP rxtime=1771727319 rxSNR=7 rxRSSI=-66 hopStart=5 nextHop=0xff relay=0x70)
Feb 22 02:27:24 DOH2_9468 Router [1117]: Module 'routing' considered
Feb 22 02:27:24 DOH2_9468 Router [1117]: MQTT onSend - Publish
Feb 22 02:27:24 DOH2_9468 Router [1117]: encrypted message
Feb 22 02:27:24 DOH2_9468 Router [1117]: MQTT Publish msh/2/e/LongFast/!433c9468, 85 bytes
The correct behavior when MQTT encryption is disabled:
Feb 22 21:56:27 DOH2_9468 RadioIf [13]: Lora RX (id=0xaa523ef5 fr=0xdb2aca70 to=0xccddeeff, transport = 0, WantAck=1, HopLim=5 Ch=0x8 encrypted len=22 rxSNR=7.25 rxRSSI=-64 hopStart=5 nextHop=0xff relay=0x70)
Feb 22 21:56:27 DOH2_9468 RadioIf [13]: Packet RX: 395ms
Feb 22 21:56:27 DOH2_9468 Router [13]: Packet History - insert: Using new slot @uptime 13.367s TRACE NEW
Feb 22 21:56:27 DOH2_9468 Router [13]: Use channel 0 (hash 0x8)
Feb 22 21:56:27 DOH2_9468 Router [13]: Expand short PSK #1
Feb 22 21:56:27 DOH2_9468 Router [13]: Use AES128 key!
Feb 22 21:56:27 DOH2_9468 Router [13]: decoded message (id=0xaa523ef5 fr=0xdb2aca70 to=0xccddeeff, transport = 1, WantAck=1, HopLim=5 Ch=0x0 Portnum=70 WANTRESP rxtime=1771797465 rxSNR=7.25 rxRSSI=-64 hopStart=5 nextHop=0xff relay=0x70)
Feb 22 21:56:27 DOH2_9468 Router [13]: handleReceived(REMOTE) (id=0xaa523ef5 fr=0xdb2aca70 to=0xccddeeff, transport = 1, WantAck=1, HopLim=5 Ch=0x0 Portnum=70 WANTRESP rxtime=1771797465 rxSNR=7.25 rxRSSI=-64 hopStart=5 nextHop=0xff relay=0x70)
Feb 22 21:56:27 DOH2_9468 Router [13]: Module 'traceroute' wantsPacket=1
Feb 22 21:56:27 DOH2_9468 Router [13]: Received traceroute from=0xdb2aca70, id=0xaa523ef5, portnum=70, payloadlen=0
Feb 22 21:56:27 DOH2_9468 Router [13]: Route traced:#0120xdb2aca70 --> 0x433c9468 (7.25dB) --> ...
Feb 22 21:56:27 DOH2_9468 Router [13]: Module 'traceroute' considered
Feb 22 21:56:27 DOH2_9468 Router [13]: Module 'routing' wantsPacket=1
Feb 22 21:56:27 DOH2_9468 Router [13]: Received routing from=0xdb2aca70, id=0xaa523ef5, portnum=70, payloadlen=9
Feb 22 21:56:27 DOH2_9468 Router [13]: Routing sniffing (id=0xaa523ef5 fr=0xdb2aca70 to=0xccddeeff, transport = 1, WantAck=1, HopLim=5 Ch=0x0 Portnum=70 WANTRESP rxtime=1771797465 rxSNR=7.25 rxRSSI=-64 hopStart=5 nextHop=0xff relay=0x70)
Feb 22 21:56:27 DOH2_9468 Router [13]: Module 'routing' considered
Feb 22 21:56:27 DOH2_9468 Router [13]: MQTT onSend - Publish
Feb 22 21:56:27 DOH2_9468 Router [13]: portnum 70 message
Feb 22 21:56:27 DOH2_9468 Router [13]: MQTT Publish msh/2/e/LongFast/!433c9468, 94 bytes
Category
Other
Hardware
Not Applicable
Is this bug report about any UI component firmware like InkHUD or Meshtatic UI (MUI)?
Firmware Version
2.7.19
Description
Issue description and repro
If we use a MQTT server with "encryption" enabled, a node that receives a traceroute packet should add itself to the route and then send that packet to the MQTT server.
Instead it adds itself to the route, sends the altered packet through RF and sends the original received packet to the MQTT server.
This means that any traceroute transversing the MQTT server will miss the node that uplinked the packet to the MQTT server.
This can be easily reproduced with two RF nodes, an MQTT server and a meshtasticD node without RF. Steps to reproduce:
1- Configure one node (DomusOnlineHT-CL-8 in this example) with RF, without MQTT server
2- Configure one node (DomusOnlineT2 in this example) with RF, with MQTT server (encrypted)
3- Configure one node (DomusOnlineD-CL-8 in this example) without RF, with MQTT server (encrypted)
4- Send a traceroute from DomusOnlineHT-CL-8 to DomusOnlineD-CL-8. This can only reach the destination through DomusOnlineT2 which will upload it to MQTT server. The destination will download it and respond. The effect:
5- Now remove the Encryption of the MQTT server on both nodes. Resend the traceroute. The effect:
Explanation
On src/Router.cpp we can see the following lines of code:
So, the original received packet is saved as "p_encrypted".
later in the same method we can see:
So, the modules are called AFTER saving the encrypted packet. TraceRoute is one of the modules. So the change in the packet, where the node adds itself to the route is called after.
Later the mqtt->onSend() method is called, sending both the encrypted and the decrypted packets.
In that method we have:
So, if the option to encrypt is set, we use the original packet, and not the one that was changed.
Relevant log output