From ea9a4dcd3af187bb56d5ced63c4cc506d77dc68f Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Mon, 3 Mar 2025 15:30:50 +1100 Subject: [PATCH] * room server: adding post, was not sending Acks on retries. * room server and repeater: now does NOT send Acks for TXT_TYPE_CLI_DATA commands --- examples/simple_repeater/main.cpp | 30 ++++++++++++++++------------ examples/simple_room_server/main.cpp | 25 ++++++++++++++++------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index 2c35106c..d47a6e02 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -407,27 +407,34 @@ protected: if (!(flags == TXT_TYPE_PLAIN || flags == TXT_TYPE_CLI_DATA)) { MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported text type received: flags=%02x", (uint32_t)flags); - } else if (sender_timestamp > client->last_timestamp) { // prevent replay attacks + } else if (sender_timestamp >= client->last_timestamp) { // prevent replay attacks + bool is_retry = (sender_timestamp == client->last_timestamp); client->last_timestamp = sender_timestamp; client->last_activity = getRTCClock()->getCurrentTime(); // len can be > original length, but 'text' will be padded with zeroes data[len] = 0; // need to make a C string again, with null terminator - uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it - mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 5 + strlen((char *)&data[5]), client->id.pub_key, PUB_KEY_SIZE); + if (flags == TXT_TYPE_PLAIN) { // for legacy CLI, send Acks + uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it + mesh::Utils::sha256((uint8_t *) &ack_hash, 4, data, 5 + strlen((char *)&data[5]), client->id.pub_key, PUB_KEY_SIZE); - mesh::Packet* ack = createAck(ack_hash); - if (ack) { - if (client->out_path_len < 0) { - sendFlood(ack); - } else { - sendDirect(ack, client->out_path, client->out_path_len); + mesh::Packet* ack = createAck(ack_hash); + if (ack) { + if (client->out_path_len < 0) { + sendFlood(ack); + } else { + sendDirect(ack, client->out_path, client->out_path_len); + } } } uint8_t temp[166]; - _cli.handleCommand(sender_timestamp, (const char *) &data[5], (char *) &temp[5]); + if (is_retry) { + temp[0] = 0; + } else { + _cli.handleCommand(sender_timestamp, (const char *) &data[5], (char *) &temp[5]); + } int text_len = strlen((char *) &temp[5]); if (text_len > 0) { uint32_t timestamp = getRTCClock()->getCurrentTimeUnique(); @@ -438,9 +445,6 @@ protected: memcpy(temp, ×tamp, 4); // mostly an extra blob to help make packet_hash unique temp[4] = (TXT_TYPE_CLI_DATA << 2); // NOTE: legacy was: TXT_TYPE_PLAIN - // calc expected ACK reply - //mesh::Utils::sha256((uint8_t *)&expected_ack_crc, 4, temp, 5 + text_len, self_id.pub_key, PUB_KEY_SIZE); - auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len); if (reply) { if (client->out_path_len < 0) { diff --git a/examples/simple_room_server/main.cpp b/examples/simple_room_server/main.cpp index 4ef72e16..cce7e3d4 100644 --- a/examples/simple_room_server/main.cpp +++ b/examples/simple_room_server/main.cpp @@ -372,7 +372,8 @@ protected: if (!(flags == TXT_TYPE_PLAIN || flags == TXT_TYPE_CLI_DATA)) { MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported command flags received: flags=%02x", (uint32_t)flags); - } else if (sender_timestamp > client->last_timestamp) { // prevent replay attacks + } else if (sender_timestamp >= client->last_timestamp) { // prevent replay attacks, but send Acks for retries + bool is_retry = (sender_timestamp == client->last_timestamp); client->last_timestamp = sender_timestamp; uint32_t now = getRTCClock()->getCurrentTimeUnique(); @@ -389,19 +390,26 @@ protected: bool send_ack; if (flags == TXT_TYPE_CLI_DATA) { if (client->is_admin) { - _cli.handleCommand(sender_timestamp, (const char *) &data[5], (char *) &temp[5]); - temp[4] = (TXT_TYPE_CLI_DATA << 2); // attempt and flags, (NOTE: legacy was: TXT_TYPE_PLAIN) - send_ack = true; + if (is_retry) { + temp[5] = 0; // no reply + } else { + _cli.handleCommand(sender_timestamp, (const char *) &data[5], (char *) &temp[5]); + temp[4] = (TXT_TYPE_CLI_DATA << 2); // attempt and flags, (NOTE: legacy was: TXT_TYPE_PLAIN) + } + send_ack = false; } else { temp[5] = 0; // no reply send_ack = false; // and no ACK... user shoudn't be sending these } } else { // TXT_TYPE_PLAIN - addPost(client, (const char *) &data[5]); + if (!is_retry) { + addPost(client, (const char *) &data[5]); + } temp[5] = 0; // no reply (ACK is enough) send_ack = true; } + uint32_t delay_millis; if (send_ack) { mesh::Packet* ack = createAck(ack_hash); if (ack) { @@ -411,6 +419,9 @@ protected: sendDirect(ack, client->out_path, client->out_path_len); } } + delay_millis = REPLY_DELAY_MILLIS; + } else { + delay_millis = 0; } int text_len = strlen((char *) &temp[5]); @@ -427,9 +438,9 @@ protected: auto reply = createDatagram(PAYLOAD_TYPE_TXT_MSG, client->id, secret, temp, 5 + text_len); if (reply) { if (client->out_path_len < 0) { - sendFlood(reply, REPLY_DELAY_MILLIS); + sendFlood(reply, delay_millis); } else { - sendDirect(reply, client->out_path, client->out_path_len, REPLY_DELAY_MILLIS); + sendDirect(reply, client->out_path, client->out_path_len, delay_millis); } } }