From fcfee673a57a95bc367f38cee16599515867519d Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Sun, 20 Sep 2026 14:21:25 +0200 Subject: [PATCH] out_path_len fixes --- zephcore/helpers/ClientACL.cpp | 15 +++++++++++++++ zephcore/helpers/ClientACL.h | 8 +++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/zephcore/helpers/ClientACL.cpp b/zephcore/helpers/ClientACL.cpp index c8b58b3..a529478 100644 --- a/zephcore/helpers/ClientACL.cpp +++ b/zephcore/helpers/ClientACL.cpp @@ -39,6 +39,21 @@ void ClientACL::load(const char* path, const mesh::LocalIdentity& self_id) { if (!success) break; // EOF + /* out_path_len is the one byte in this file that steers routing, and + * it is used without a later bounds check: anything that is not + * OUT_PATH_UNKNOWN is taken as a usable path. A value with the + * reserved hash size 4 (0xC0-0xFE) passes that test, then copyPath() + * rejects the encoding inside sendDirect() and the reply leaves as a + * zero-hop direct -- undeliverable, and never retried, because the + * repeater considers the request answered. Fall back to "unknown", + * which costs one flooded reply and re-learns the real path. */ + if (c.out_path_len != OUT_PATH_UNKNOWN && + !mesh::Packet::isValidPathLen(c.out_path_len)) { + LOG_WRN("load: client %d has invalid out_path_len 0x%02x, discarding path", + num_clients, c.out_path_len); + c.out_path_len = OUT_PATH_UNKNOWN; + } + c.id = mesh::Identity(pub_key); self_id.calcSharedSecret(c.shared_secret, pub_key); // recalculate in case key changed diff --git a/zephcore/helpers/ClientACL.h b/zephcore/helpers/ClientACL.h index 9af5e55..ac01e0e 100644 --- a/zephcore/helpers/ClientACL.h +++ b/zephcore/helpers/ClientACL.h @@ -40,7 +40,13 @@ struct ClientInfo { void clear() { id = mesh::Identity(); permissions = 0; - out_path_len = 0; + /* NOT 0 -- that is a valid path_len meaning "zero-hop direct", so a + * cleared slot would claim a usable route and every reply to that + * client would go out DIRECT with an empty path, reaching only its + * immediate neighbours. Silent: the sender believes it answered. + * putClient() happens to overwrite this today, so nothing currently + * observes the 0; the correct default belongs here regardless. */ + out_path_len = OUT_PATH_UNKNOWN; memset(out_path, 0, sizeof(out_path)); memset(shared_secret, 0, sizeof(shared_secret)); last_timestamp = 0;