Skip to content

Commit 3dacaa4

Browse files
committed
v1.0.48: TCP server whitelist parity, LAN announce WL#1 fix
- Add explicit trusted-local interface classification (is_local_client) - register_local_client_interface() now marks interfaces as trusted - Both LoRa and LocalTcpInterface registered as trusted local - is_trusted_local_interface() predicate for WL seeding decisions - WL#1 announce registration moved before replay/path dedup so duplicate valid LAN announces still establish local reachability - WL#2 seeding uses trusted-local check for TCP server packets matching identical LoRa behavior
1 parent be9beb8 commit 3dacaa4

6 files changed

Lines changed: 32 additions & 43 deletions

File tree

Config.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
#define CONFIG_H
2121

2222
#define MAJ_VERS 0x01
23-
#define MIN_VERS 0x2F
24-
#define FW_RELEASE_TAG "1.0.47"
23+
#define MIN_VERS 0x30
24+
#define FW_RELEASE_TAG "1.0.48"
25+
2526
#define MODE_HOST 0x11
2627
#define MODE_TNC 0x12
2728

RNode_Firmware.ino

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,7 @@ void setup() {
992992
HEAD("Registering LoRA Interface...", RNS::LOG_TRACE);
993993
lora_interface = new LoRaInterface();
994994
RNS::Transport::register_interface(lora_interface);
995+
RNS::Transport::register_local_client_interface(lora_interface);
995996

996997
#ifdef FIREWALL_MODE
997998
// ── Firewall Mode: Load config and optionally set up WiFi + TCP ──

lib/microReticulum/src/Interface.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ namespace RNS {
9090
bool _is_connected_to_shared_instance = false;
9191
bool _is_local_shared_instance = false;
9292
bool _is_backbone = false;
93+
bool _is_local_client = false;
9394
//Bytes _hash;
9495
HInterface _parent_interface;
9596
//Transport& _owner;
@@ -212,6 +213,8 @@ namespace RNS {
212213
inline bool is_local_shared_instance() const { assert(_impl); return _impl->_is_local_shared_instance; }
213214
inline bool is_backbone() const { assert(_impl); return _impl->_is_backbone; }
214215
inline void is_backbone(bool val) { assert(_impl); _impl->_is_backbone = val; }
216+
inline bool is_local_client() const { assert(_impl); return _impl->_is_local_client; }
217+
inline void is_local_client(bool val) { assert(_impl); _impl->_is_local_client = val; }
215218
inline bool isConnected() const { assert(_impl); return _impl->isConnected(); }
216219
inline HInterface parent_interface() const { assert(_impl); return _impl->_parent_interface; }
217220

lib/microReticulum/src/Transport.cpp

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ using namespace RNS;
2020
using namespace RNS::Type::Transport;
2121
using namespace RNS::Utilities;
2222

23-
// ── Firewall-mode extern: set by RTNode firmware before Transport::start() ──
24-
#ifdef FIREWALL_MODE
25-
extern bool firewall_probe_enabled;
26-
#endif
27-
2823
// ── Flat-map helpers (vector<pair<Bytes,T>> replaces std::map<Bytes,T>) ────
2924
// Eliminates per-element tree-node allocation. Linear search is fine
3025
// for N ≤ ~1000 on ESP32.
@@ -254,6 +249,9 @@ static std::string short_hash(const Bytes& h) {
254249
static bool is_backbone_interface(const Interface& iface) {
255250
return iface.is_backbone();
256251
}
252+
static bool is_trusted_local_interface(const Interface& iface) {
253+
return iface.is_local_client();
254+
}
257255
// Human-readable packet type abbreviations
258256
static const char* pkt_type_name(uint8_t t) {
259257
switch (t) {
@@ -369,24 +367,6 @@ static inline bool is_resource_ctx(uint8_t ctx) {
369367
_control_hashes.insert(tunnel_synthesize_destination.hash());
370368
DEBUG("Created transport-specific tunnel synthesize destination " + tunnel_synthesize_destination.hash().toHex());
371369

372-
// Create transport-specific destination for rnprobe responder.
373-
// rnprobe sends a random DATA packet and measures RTT from the
374-
// delivery proof. PROVE_ALL makes Transport send that proof
375-
// automatically — no custom packet handler needed.
376-
// The destination hash is well-known: identity.hash + hash("rnstransport", "probe").
377-
// In firewall mode, gated by the captive-portal toggle.
378-
#ifdef FIREWALL_MODE
379-
if (firewall_probe_enabled)
380-
#endif
381-
{
382-
Destination probe_destination(Transport::identity(), Type::Destination::IN, Type::Destination::SINGLE, APP_NAME, "probe");
383-
probe_destination.accepts_links(false);
384-
probe_destination.set_proof_strategy(Type::Destination::PROVE_ALL);
385-
_control_destinations.insert(probe_destination);
386-
_control_hashes.insert(probe_destination.hash());
387-
NOTICE("PROBE-DST: " + probe_destination.hash().toHex().substr(0,8) + " — responding to rnprobe requests");
388-
}
389-
390370
_jobs_running = false;
391371

392372
// CBA Threading
@@ -1624,6 +1604,7 @@ static inline bool is_resource_ctx(uint8_t ctx) {
16241604
#ifdef FIREWALL_MODE
16251605
{
16261606
bool is_backbone = is_backbone_interface(packet.receiving_interface());
1607+
bool is_trusted_local = is_trusted_local_interface(packet.receiving_interface());
16271608

16281609
// ── Extract all addresses from this packet ──────────
16291610
// Two tiers:
@@ -1727,10 +1708,10 @@ static inline bool is_resource_ctx(uint8_t ctx) {
17271708
for (auto& a : addrs) { wl_add(a, "backbone"); }
17281709
WLOG(packet, "TO: " + short_hash(packet.destination_hash()) + " (" + dest_zone(packet.destination_hash()) + ") - WL-PASS hops=" + std::to_string(packet.hops()) + " sz=" + std::to_string(packet.raw().size()));
17291710
}
1730-
else {
1711+
else if (is_trusted_local) {
17311712
// === LOCAL DEVICE PACKET ===
17321713
// Always whitelist ALL addresses from local packets.
1733-
// Local devices are trusted; their traffic seeds the
1714+
// LoRa and registered TCP server clients are trusted; their traffic seeds the
17341715
// secondary whitelist for return traffic from WAN.
17351716
for (auto& a : addrs) { wl_add(a, "local"); }
17361717
WLOG(packet, "TO: " + short_hash(packet.destination_hash()) + " (" + dest_zone(packet.destination_hash()) + ") - WL-PASS hops=" + std::to_string(packet.hops()) + " sz=" + std::to_string(packet.raw().size()));
@@ -2360,6 +2341,15 @@ static inline bool is_resource_ctx(uint8_t ctx) {
23602341
if (iter == _destinations.end() && Identity::validate_announce(packet)) {
23612342
#endif
23622343
TRACE("Transport::inbound: Packet is announce for non-local destination, processing...");
2344+
#ifdef FIREWALL_MODE
2345+
// A valid announce received from LoRa or the local TCP server proves
2346+
// that destination is locally reachable. Record it before replay/path
2347+
// dedup, since the same announce may already have arrived via WAN.
2348+
if (is_trusted_local_interface(packet.receiving_interface())) {
2349+
wl1_push(packet.destination_hash());
2350+
NOTICE("WL#1 ADD - " + packet.destination_hash().toHex().substr(0,8) + " (from LAN)");
2351+
}
2352+
#endif
23632353
if (packet.transport_id()) {
23642354
received_from = packet.transport_id();
23652355

@@ -2537,16 +2527,6 @@ static inline bool is_resource_ctx(uint8_t ctx) {
25372527
DEBUG("Destination " + packet.destination_hash().toHex() + " is now " + std::to_string(announce_hops) + " hops away via " + received_from.toHex() + " on " + packet.receiving_interface().toString());
25382528
DEBUG("DIAG: STORED path " + packet.destination_hash().toHex().substr(0,8) + " hops=" + std::to_string(announce_hops) + " iface=" + packet.receiving_interface().toString());
25392529

2540-
// FIREWALL MODE: Register destinations seen via non-backbone interfaces (Whitelist 1)
2541-
#ifdef FIREWALL_MODE
2542-
{
2543-
bool is_backbone = is_backbone_interface(packet.receiving_interface());
2544-
if (!is_backbone) {
2545-
wl1_push(packet.destination_hash());
2546-
NOTICE("WL#1 ADD - " + packet.destination_hash().toHex().substr(0,8) + " (from LAN)");
2547-
}
2548-
}
2549-
#endif
25502530
//TRACE("Transport::inbound: Destination " + packet.destination_hash().toHex() + " has data: " + packet.data().toHex());
25512531
//TRACE("Transport::inbound: Destination " + packet.destination_hash().toHex() + " has text: " + packet.data().toString());
25522532

@@ -2948,6 +2928,12 @@ static inline bool is_resource_ctx(uint8_t ctx) {
29482928
// CBA TODO set or add transport as listener on interface to receive incoming packets?
29492929
}
29502930

2931+
/*static*/ void Transport::register_local_client_interface(Interface& interface) {
2932+
interface.is_local_client(true);
2933+
interface.is_backbone(false);
2934+
TRACE("Transport: Registered trusted local client interface " + interface.toString());
2935+
}
2936+
29512937
/*static*/ void Transport::deregister_interface(const Interface& interface) {
29522938
TRACE("Transport: Deregistering interface " + interface.toString());
29532939
#if defined(INTERFACES_SET)

lib/microReticulum/src/Transport.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ namespace RNS {
367367
static void handle_tunnel(const Bytes& tunnel_id, const Interface& interface);
368368
static void register_interface(Interface& interface);
369369
static void deregister_interface(const Interface& interface);
370-
static void register_local_client_interface(const Interface&) { /* no-op in firewall mode */ }
370+
static void register_local_client_interface(Interface& interface);
371371
inline static const std::map<Bytes, Interface&> get_interfaces() { return _interfaces; }
372372
static void register_destination(Destination& destination);
373373
static void deregister_destination(const Destination& destination);

versions.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[
2-
{
3-
"tag": "v1.0.47",
4-
"name": "v1.0.47 — LoRa repeater audit: atomic queue, same-interface announce propagation",
2+
{ "tag": "v1.0.48",
3+
"name": "v1.0.48 — TCP server whitelist parity, LAN announce WL#1 fix",
54
"stability": "beta",
65
"prerelease": false,
76
"published_at": "2026-07-27T00:00:00Z",
@@ -12,8 +11,7 @@
1211
"rtnode_heltec_v4_merged.bin"
1312
]
1413
},
15-
{
16-
"tag": "v1.0.46",
14+
{ "tag": "v1.0.46",
1715
"name": "v1.0.46 — Proof timeout fix: extra_link_proof_timeout for LoRa interfaces",
1816
"stability": "beta",
1917
"prerelease": false,

0 commit comments

Comments
 (0)