* separated PAYLOAD_TYPE_ANON_REQ, to new createAnonDatagram(), with extra 'sender' param. So, caller can use 'self_id' or ephemeral key

This commit is contained in:
Scott Powell
2025-01-13 15:01:15 +11:00
parent 6c7efdd0f6
commit 2faff914f6
5 changed files with 51 additions and 24 deletions

View File

@@ -95,7 +95,7 @@ public:
if (!got_adv) return; // have not received Advert yet
uint32_t now = getRTCClock()->getCurrentTime(); // important, need timestamp in packet, so that packet_hash will be unique
mesh::Packet* ping = createDatagram(PAYLOAD_TYPE_ANON_REQ, server_id, server_secret, (uint8_t *) &now, sizeof(now));
mesh::Packet* ping = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, server_id, server_secret, (uint8_t *) &now, sizeof(now));
if (ping) {
if (server_path_len < 0) {

View File

@@ -28,8 +28,9 @@
#error "need to provide a 'board' object"
#endif
#define FLOOD_SEND_TIMEOUT_MILLIS 4000
#define DIRECT_SEND_TIMEOUT_MILLIS 2000
#define FLOOD_SEND_TIMEOUT_MILLIS 6000
#define DIRECT_TIMEOUT_BASE 1000
#define DIRECT_TIMEOUT_FACTOR 400 // per hop millis
/* -------------------------------------------------------------------------------------- */
@@ -108,6 +109,9 @@ protected:
void onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_idx, uint8_t* data, size_t len) override {
if (type == PAYLOAD_TYPE_TXT_MSG) {
// NOTE: this is a 'first packet wins' impl. When receiving from multiple paths, the first to arrive wins.
// For flood mode, the path may not be the 'best' in terms of hops.
// FUTURE: could send back multiple paths, using createPathReturn(), and let sender choose which to use(?)
if (_table->hasSeenPacket(packet)) return;
int i = matching_peer_indexes[sender_idx];
@@ -124,10 +128,8 @@ protected:
// 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
Serial.print("MSG -> from ");
Serial.print(from.name);
Serial.print(": ");
Serial.println((const char *) &data[4]);
Serial.printf("MSG -> from %s\n", from.name);
Serial.printf(" %s\n", (const char *) &data[4]);
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, len, from.id.pub_key, PUB_KEY_SIZE);
@@ -162,6 +164,8 @@ protected:
ContactInfo& from = contacts[i];
Serial.printf("PATH to: %s, path_len=%d\n", from.name, (uint32_t) path_len);
// NOTE: for this impl, we just replace the current 'out_path' regardless, whenever sender sends us a new out_path.
// FUTURE: could store multiple out_paths per contact, and try to find which is the 'best'(?)
memcpy(from.out_path, path, from.out_path_len = path_len); // store a copy of path, for sendDirect()
if (packet->isRouteFlood()) {
@@ -213,10 +217,10 @@ public:
return createDatagram(PAYLOAD_TYPE_TXT_MSG, recipient.id, recipient.shared_secret, temp, 4 + text_len);
}
void sendSelfAnnounce() {
mesh::Packet* announce = createAdvert(self_id);
if (announce) {
sendFlood(announce);
void sendSelfAdvert() {
mesh::Packet* adv = createAdvert(self_id);
if (adv) {
sendFlood(adv);
Serial.println(" (advert sent).");
} else {
Serial.println(" ERROR: unable to create packet.");
@@ -260,7 +264,7 @@ void setup() {
the_mesh.addContact("Alice", mesh::Identity(alice_public));
#endif
Serial.println("Help:");
Serial.println(" enter 'ann' to announce presence to mesh");
Serial.println(" enter 'adv' to advertise presence to mesh");
Serial.println(" enter 'send {message text}' to send a message");
the_mesh.begin();
@@ -268,8 +272,8 @@ void setup() {
command[0] = 0;
txt_send_timeout = 0;
// send out initial Announce to the mesh
the_mesh.sendSelfAnnounce();
// send out initial Advertisement to the mesh
the_mesh.sendSelfAdvert();
}
void loop() {
@@ -301,14 +305,14 @@ void loop() {
txt_send_timeout = the_mesh.futureMillis(FLOOD_SEND_TIMEOUT_MILLIS);
} else {
the_mesh.sendDirect(pkt, recipient.out_path, recipient.out_path_len);
txt_send_timeout = the_mesh.futureMillis(DIRECT_SEND_TIMEOUT_MILLIS);
txt_send_timeout = the_mesh.futureMillis(DIRECT_TIMEOUT_FACTOR*recipient.out_path_len + DIRECT_TIMEOUT_BASE);
}
Serial.println(" (message sent)");
} else {
Serial.println(" ERROR: unable to create packet.");
}
} else if (strcmp(command, "ann") == 0) {
the_mesh.sendSelfAnnounce();
} else if (strcmp(command, "adv") == 0) {
the_mesh.sendSelfAdvert();
} else if (strcmp(command, "key") == 0) {
mesh::LocalIdentity new_id(the_mesh.getRNG());
new_id.printTo(Serial);

View File

@@ -75,7 +75,7 @@ protected:
memcpy(temp, &now, 4);
memcpy(&temp[4], ADMIN_PASSWORD, 8);
mesh::Packet* login = createDatagram(PAYLOAD_TYPE_ANON_REQ, server_id, server_secret, temp, sizeof(temp));
mesh::Packet* login = createAnonDatagram(PAYLOAD_TYPE_ANON_REQ, self_id, server_id, server_secret, temp, sizeof(temp));
if (login) sendFlood(login); // server_path won't be known yet
}
}

View File

@@ -283,9 +283,7 @@ Packet* Mesh::createPathReturn(const Identity& dest, const uint8_t* secret, cons
}
Packet* Mesh::createDatagram(uint8_t type, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len) {
if (type == PAYLOAD_TYPE_ANON_REQ) {
if (data_len + 1 + PUB_KEY_SIZE + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL;
} else if (type == PAYLOAD_TYPE_TXT_MSG || type == PAYLOAD_TYPE_REQ || type == PAYLOAD_TYPE_RESPONSE) {
if (type == PAYLOAD_TYPE_TXT_MSG || type == PAYLOAD_TYPE_REQ || type == PAYLOAD_TYPE_RESPONSE) {
if (data_len + 2 + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL;
} else {
return NULL; // invalid type
@@ -299,13 +297,37 @@ Packet* Mesh::createDatagram(uint8_t type, const Identity& dest, const uint8_t*
packet->header = (type << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later
packet->path_len = 0;
int len = 0;
len += dest.copyHashTo(&packet->payload[len]); // dest hash
len += self_id.copyHashTo(&packet->payload[len]); // src hash
len += Utils::encryptThenMAC(secret, &packet->payload[len], data, data_len);
packet->payload_len = len;
return packet;
}
Packet* Mesh::createAnonDatagram(uint8_t type, const LocalIdentity& sender, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len) {
if (type == PAYLOAD_TYPE_ANON_REQ) {
if (data_len + 1 + PUB_KEY_SIZE + CIPHER_BLOCK_SIZE-1 > MAX_PACKET_PAYLOAD) return NULL;
} else {
return NULL; // invalid type
}
Packet* packet = obtainNewPacket();
if (packet == NULL) {
MESH_DEBUG_PRINTLN("Mesh::createAnonDatagram(): error, packet pool empty");
return NULL;
}
packet->header = (type << PH_TYPE_SHIFT); // ROUTE_TYPE_* set later
packet->path_len = 0;
int len = 0;
if (type == PAYLOAD_TYPE_ANON_REQ) {
len += dest.copyHashTo(&packet->payload[len]); // dest hash
memcpy(&packet->payload[len], self_id.pub_key, PUB_KEY_SIZE); len += PUB_KEY_SIZE; // sender pub_key
memcpy(&packet->payload[len], sender.pub_key, PUB_KEY_SIZE); len += PUB_KEY_SIZE; // sender pub_key
} else {
len += dest.copyHashTo(&packet->payload[len]); // dest hash
len += self_id.copyHashTo(&packet->payload[len]); // src hash
// FUTURE:
}
len += Utils::encryptThenMAC(secret, &packet->payload[len], data, data_len);

View File

@@ -128,6 +128,7 @@ public:
Packet* createAdvert(const LocalIdentity& id, const uint8_t* app_data=NULL, size_t app_data_len=0);
Packet* createDatagram(uint8_t type, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t len);
Packet* createAnonDatagram(uint8_t type, const LocalIdentity& sender, const Identity& dest, const uint8_t* secret, const uint8_t* data, size_t data_len);
Packet* createGroupDatagram(uint8_t type, const GroupChannel& channel, const uint8_t* data, size_t data_len);
Packet* createAck(uint32_t ack_crc);
Packet* createPathReturn(const Identity& dest, const uint8_t* secret, const uint8_t* path, uint8_t path_len, uint8_t extra_type, const uint8_t*extra, size_t extra_len);