From 71812d220b0968737d401566ddd5038a8aa4adbc Mon Sep 17 00:00:00 2001 From: ViezeVingertjes Date: Tue, 26 Aug 2025 16:57:01 +0200 Subject: [PATCH] Added compatibility between nodes on different Presets through `Mesh via UDP` --- src/mesh/Channels.cpp | 23 +++++++++++++++++++++++ src/mesh/Channels.h | 2 ++ src/mesh/FloodingRouter.cpp | 7 +++++++ src/mesh/Router.cpp | 21 +++++++++++++++++++++ src/mesh/udp/UdpMulticastHandler.h | 1 + 5 files changed, 54 insertions(+) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 70e4127d8..433727301 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -422,6 +422,29 @@ bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash) } } +bool Channels::setDefaultPresetCryptoForHash(ChannelHash channelHash) +{ + // Iterate all known presets + for (int preset = _meshtastic_Config_LoRaConfig_ModemPreset_MIN; preset <= _meshtastic_Config_LoRaConfig_ModemPreset_MAX; ++preset) { + const char *name = DisplayFormatters::getModemPresetDisplayName((meshtastic_Config_LoRaConfig_ModemPreset)preset, false); + if (!name) continue; + if (strcmp(name, "Invalid") == 0) continue; // skip invalid placeholder + uint8_t h = xorHash((const uint8_t *)name, strlen(name)); + // Expand default PSK alias 1 to actual bytes and xor into hash + uint8_t tmp = h ^ xorHash(defaultpsk, sizeof(defaultpsk)); + if (tmp == channelHash) { + // Set crypto to defaultpsk and report success + CryptoKey k; + memcpy(k.bytes, defaultpsk, sizeof(defaultpsk)); + k.length = sizeof(defaultpsk); + crypto->setKey(k); + LOG_INFO("Matched default preset '%s' for hash 0x%x; set default PSK", name, channelHash); + return true; + } + } + return false; +} + /** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured) * * This method is called before encoding outbound packets diff --git a/src/mesh/Channels.h b/src/mesh/Channels.h index 7873a306a..b53f552fa 100644 --- a/src/mesh/Channels.h +++ b/src/mesh/Channels.h @@ -94,6 +94,8 @@ class Channels bool ensureLicensedOperation(); + bool setDefaultPresetCryptoForHash(ChannelHash channelHash); + private: /** Given a channel index, change to use the crypto key specified by that index * diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index dbd458b61..b19966e6b 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -68,6 +68,13 @@ bool FloodingRouter::isRebroadcaster() void FloodingRouter::perhapsRebroadcast(const meshtastic_MeshPacket *p) { if (!isToUs(p) && (p->hop_limit > 0) && !isFromUs(p)) { + // If this packet arrived via UDP and is still encrypted, skip rebroadcast. + // We expect the router to decode and then re-encode to our local preset before sending. + if (p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MULTICAST_UDP && + p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag) { + LOG_DEBUG("Skip rebroadcast of UDP-encrypted packet; awaiting local decode/re-encode"); + return; + } if (p->id != 0) { if (isRebroadcaster()) { meshtastic_MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 1f835bca7..bf6a66a1e 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -416,6 +416,27 @@ DecodeState perhapsDecode(meshtastic_MeshPacket *p) } } } + + // Fallback: for UDP multicast, try default preset names with default PSK if normal channel match failed + if (!decrypted && p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MULTICAST_UDP) { + if (channels.setDefaultPresetCryptoForHash(p->channel)) { + memcpy(bytes, p->encrypted.bytes, rawSize); + crypto->decrypt(p->from, p->id, rawSize, bytes); + + meshtastic_Data decodedtmp; + memset(&decodedtmp, 0, sizeof(decodedtmp)); + if (pb_decode_from_bytes(bytes, rawSize, &meshtastic_Data_msg, &decodedtmp) && + decodedtmp.portnum != meshtastic_PortNum_UNKNOWN_APP) { + p->decoded = decodedtmp; + p->which_payload_variant = meshtastic_MeshPacket_decoded_tag; + // Map to our primary channel index so subsequent processing and re-encoding use local preset + chIndex = channels.getPrimaryIndex(); + decrypted = true; + } else { + LOG_WARN("UDP fallback decode attempted but failed for hash 0x%x", p->channel); + } + } + } if (decrypted) { // parsing was successful p->channel = chIndex; // change to store the index instead of the hash diff --git a/src/mesh/udp/UdpMulticastHandler.h b/src/mesh/udp/UdpMulticastHandler.h index 9650668a8..104e1a711 100644 --- a/src/mesh/udp/UdpMulticastHandler.h +++ b/src/mesh/udp/UdpMulticastHandler.h @@ -54,6 +54,7 @@ class UdpMulticastHandler final LOG_DEBUG("Decoding MeshPacket from UDP len=%u", packetLength); bool isPacketDecoded = pb_decode_from_bytes(packet.data(), packetLength, &meshtastic_MeshPacket_msg, &mp); if (isPacketDecoded && router && mp.which_payload_variant == meshtastic_MeshPacket_encrypted_tag) { + mp.transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MULTICAST_UDP; mp.pki_encrypted = false; mp.public_key.size = 0; memset(mp.public_key.bytes, 0, sizeof(mp.public_key.bytes));