diff --git a/protobufs b/protobufs index 7654db2e2d1..88b846c9b6d 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 7654db2e2d1834aebde40090a9b74162ad1048ae +Subproject commit 88b846c9b6d9ca65bdd47212406ade5c861bd5ac diff --git a/src/main.cpp b/src/main.cpp index c654822927f..6332aed46da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -218,6 +218,8 @@ bool eink_found = true; uint32_t serialSinceMsec; bool pauseBluetoothLogging = false; +// Global control flag for encrypted-only promiscuous forwarding to FromRadio +bool serialPromiscuousEnabled = false; bool pmu_found; diff --git a/src/main.h b/src/main.h index 414752b5c6c..7d9c1e8551d 100644 --- a/src/main.h +++ b/src/main.h @@ -90,6 +90,10 @@ extern bool runASAP; extern bool pauseBluetoothLogging; +// When true, forward all received LoRa packets to FromRadio as encrypted MeshPacket payloads +// and avoid sending decrypted duplicates to FromRadio. Reset to false on serial connect/disconnect. +extern bool serialPromiscuousEnabled; + void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(), enterDfuMode(); meshtastic_DeviceMetadata getDeviceMetadata(); diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 1b2af082d87..2bf82e61a08 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -109,7 +109,10 @@ int MeshService::handleFromRadio(const meshtastic_MeshPacket *mp) } printPacket("Forwarding to phone", mp); - sendToPhone(packetPool.allocCopy(*mp)); + // If promiscuous mode is enabled, suppress duplicate to phone. + if (!serialPromiscuousEnabled) { + sendToPhone(packetPool.allocCopy(*mp)); + } return 0; } @@ -184,7 +187,10 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p) return; } #endif - p.from = 0; // We don't let clients assign nodenums to their sent messages + // Allow any encrypted packet as-is in promiscuous mode + if (!(serialPromiscuousEnabled && p.which_payload_variant == meshtastic_MeshPacket_encrypted_tag)) { + p.from = 0; // We don't let clients assign nodenums to their sent messages + } p.next_hop = NO_NEXT_HOP_PREFERENCE; // We don't let clients assign next_hop to their sent messages p.relay_node = NO_RELAY_NODE; // We don't let clients assign relay_node to their sent messages @@ -292,7 +298,10 @@ bool MeshService::trySendPosition(NodeNum dest, bool wantReplies) void MeshService::sendToPhone(meshtastic_MeshPacket *p) { - perhapsDecode(p); + // In promiscuous mode, prefer to forward encrypted packets as-is and avoid decoding duplicates + if (!serialPromiscuousEnabled) { + perhapsDecode(p); + } #ifdef ARCH_ESP32 #if !MESHTASTIC_EXCLUDE_STOREFORWARD @@ -306,8 +315,9 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p) #endif if (toPhoneQueue.numFree() == 0) { - if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP || - p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) { + if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag && + (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP || + p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP)) { LOG_WARN("ToPhone queue is full, discard oldest"); meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0); if (d) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 9050ee89d71..355f1626eba 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -127,6 +127,7 @@ void PhoneAPI::close() config_state = 0; pauseBluetoothLogging = false; heartbeatReceived = false; + serialPromiscuousEnabled = false; } } @@ -165,6 +166,10 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength) LOG_INFO("Disconnect from phone"); close(); break; + case meshtastic_ToRadio_set_promiscuous_tag: + LOG_INFO("Set serial promiscuous: %s", toRadioScratch.set_promiscuous ? "true" : "false"); + serialPromiscuousEnabled = toRadioScratch.set_promiscuous; + break; case meshtastic_ToRadio_xmodemPacket_tag: LOG_INFO("Got xmodem packet"); #ifdef FSCom diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 05f47d7f4b8..5cd8ff49e0f 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -758,6 +758,13 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src) void Router::perhapsHandleReceived(meshtastic_MeshPacket *p) { + if (serialPromiscuousEnabled) { + // If serial promiscuous mode is enabled, forward the encrypted form to the phone now + service->sendToPhone(packetPool.allocCopy(*p)); + } + LOG_DEBUG("serialPromiscuousEnabled: %d Encrypted: %d", serialPromiscuousEnabled, + p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag); + #if ENABLE_JSON_LOGGING // Even ignored packets get logged in the trace p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp index 20026767e30..a8e8242f403 100644 --- a/src/mesh/StreamAPI.cpp +++ b/src/mesh/StreamAPI.cpp @@ -3,6 +3,7 @@ #include "RTC.h" #include "Throttle.h" #include "configuration.h" +#include "main.h" #define START1 0x94 #define START2 0xc3 @@ -219,9 +220,13 @@ void StreamAPI::onConnectionChanged(bool connected) if (connected) { // To prevent user confusion, turn off bluetooth while using the serial port api powerFSM.trigger(EVENT_SERIAL_CONNECTED); + // Reset promiscuous mode on connect + serialPromiscuousEnabled = false; } else { // FIXME, we get no notice of serial going away, we should instead automatically generate this event if we haven't // received a packet in a while powerFSM.trigger(EVENT_SERIAL_DISCONNECTED); + // Reset promiscuous mode on disconnect + serialPromiscuousEnabled = false; } } \ No newline at end of file diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 0da44cce075..cec543e8124 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -1218,6 +1218,10 @@ typedef struct _meshtastic_ToRadio { meshtastic_MqttClientProxyMessage mqttClientProxyMessage; /* Heartbeat message (used to keep the device connection awake on serial) */ meshtastic_Heartbeat heartbeat; + /* Set or clear promiscuous capture mode for LoRa RX. + If true, the device will forward all received LoRa packets to FromRadio as encrypted MeshPacket payloads, + and will avoid additionally sending the decrypted copies. This is primarily intended for serial sniffing. */ + bool set_promiscuous; }; } meshtastic_ToRadio; @@ -1605,6 +1609,7 @@ extern "C" { #define meshtastic_ToRadio_xmodemPacket_tag 5 #define meshtastic_ToRadio_mqttClientProxyMessage_tag 6 #define meshtastic_ToRadio_heartbeat_tag 7 +#define meshtastic_ToRadio_set_promiscuous_tag 8 #define meshtastic_NodeRemoteHardwarePin_node_num_tag 1 #define meshtastic_NodeRemoteHardwarePin_pin_tag 2 #define meshtastic_ChunkedPayload_payload_id_tag 1 @@ -1883,7 +1888,8 @@ X(a, STATIC, ONEOF, UINT32, (payload_variant,want_config_id,want_config_i X(a, STATIC, ONEOF, BOOL, (payload_variant,disconnect,disconnect), 4) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,xmodemPacket,xmodemPacket), 5) \ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,mqttClientProxyMessage,mqttClientProxyMessage), 6) \ -X(a, STATIC, ONEOF, MESSAGE, (payload_variant,heartbeat,heartbeat), 7) +X(a, STATIC, ONEOF, MESSAGE, (payload_variant,heartbeat,heartbeat), 7) \ +X(a, STATIC, ONEOF, BOOL, (payload_variant,set_promiscuous,set_promiscuous), 8) #define meshtastic_ToRadio_CALLBACK NULL #define meshtastic_ToRadio_DEFAULT NULL #define meshtastic_ToRadio_payload_variant_packet_MSGTYPE meshtastic_MeshPacket