From 123bdc9200a80910bd253660bf1a32f0ef475fd1 Mon Sep 17 00:00:00 2001 From: torlando-tech Date: Fri, 31 Oct 2025 21:06:58 -0400 Subject: [PATCH] fix: Use identity-based keying for fragmenters/reassemblers (MAC rotation immunity) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Critical fix for message delivery and Android MAC rotation support. **Problem:** - Fragmenters keyed by MAC address - Failed with "dev:" prefix mismatch - Would break on Android MAC rotation **Solution:** Use identity_hash for fragmenter/reassembler keys (with Protocol v1 MAC fallback). **Changes:** 1. Added _get_fragmenter_key() helper - returns identity_hash or normalized MAC 2. Updated _connect_to_peer() - creates fragmenters with identity keys 3. Updated BLEPeerInterface.processOutgoing() - looks up fragmenters with identity keys **Benefits:** - ✅ Fixes immediate "No fragmenter" bug - ✅ Survives Android MAC address rotation - ✅ Consistent with unified interface architecture - ✅ One fragmenter per peer identity (not per ephemeral MAC) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/RNS/Interfaces/BLEInterface.py | 38 +++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/RNS/Interfaces/BLEInterface.py b/src/RNS/Interfaces/BLEInterface.py index 007844b..1643139 100644 --- a/src/RNS/Interfaces/BLEInterface.py +++ b/src/RNS/Interfaces/BLEInterface.py @@ -1517,9 +1517,12 @@ class BLEInterface(Interface): self.peers[peer.address] = (client, time.time(), mtu) # Create fragmenter for this peer's MTU + # KEY CHANGE: Use identity_hash for keying (survives MAC rotation, fixes dev: prefix issue) + frag_key = self._get_fragmenter_key(peer_identity, peer.address) with self.frag_lock: - self.fragmenters[peer.address] = BLEFragmenter(mtu=mtu) - self.reassemblers[peer.address] = BLEReassembler(timeout=self.connection_timeout) + self.fragmenters[frag_key] = BLEFragmenter(mtu=mtu) + self.reassemblers[frag_key] = BLEReassembler(timeout=self.connection_timeout) + RNS.log(f"{self} created fragmenter/reassembler for peer (key: {frag_key[:16]})", RNS.LOG_DEBUG) # Create or update unified peer interface with central connection self._spawn_or_update_peer_interface( @@ -1633,6 +1636,27 @@ class BLEInterface(Interface): RNS.log(f"{self} failed to connect to {peer.name} ({peer.address}): " f"{error_type}: {e}, failures={peer.failed_connections}", RNS.LOG_WARNING) + def _get_fragmenter_key(self, peer_identity, peer_address): + """ + Compute fragmenter/reassembler dictionary key. + + Uses identity_hash for Protocol v2 devices (survives MAC rotation), + falls back to normalized MAC for Protocol v1 legacy devices. + + Args: + peer_identity: 16-byte peer identity (None for Protocol v1) + peer_address: BLE MAC address (may have "dev:" prefix) + + Returns: + str: Identity hash (16 hex chars) or normalized MAC address + """ + if peer_identity: + # Protocol v2: Use identity hash (immune to MAC rotation) + return RNS.Identity.full_hash(peer_identity)[:16].hex()[:16] + else: + # Protocol v1 fallback: Use normalized MAC address + return peer_address.replace("dev:", "") + def _spawn_or_update_peer_interface(self, address, name, peer_identity=None, client=None, mtu=None, connection_type="central"): """ Create or update a unified peer interface that can handle both central and peripheral connections. @@ -2314,13 +2338,15 @@ class BLEPeerInterface(Interface): # Log packet transmission RNS.log(f"{self} TX: {len(data)} bytes to {self.peer_name}", RNS.LOG_DEBUG) - # Get fragmenter for this peer + # Get fragmenter for this peer (using identity-based key for MAC rotation immunity) + frag_key = self.parent_interface._get_fragmenter_key(self.peer_identity, self.peer_address) + with self.parent_interface.frag_lock: - if self.peer_address not in self.parent_interface.fragmenters: - RNS.log(f"No fragmenter for peer {self.peer_address}", RNS.LOG_WARNING) + if frag_key not in self.parent_interface.fragmenters: + RNS.log(f"No fragmenter for peer {self.peer_name} (key: {frag_key})", RNS.LOG_WARNING) return - fragmenter = self.parent_interface.fragmenters[self.peer_address] + fragmenter = self.parent_interface.fragmenters[frag_key] # Fragment the data try: