@@ -613,6 +613,23 @@ void SensorMesh::getPeerSharedSecret(uint8_t* dest_secret, int peer_idx) {
613613 }
614614}
615615
616+ void SensorMesh::sendAckTo (const ContactInfo& dest, uint32_t ack_hash) {
617+ if (dest.out_path_len < 0 ) {
618+ mesh::Packet* ack = createAck (ack_hash);
619+ if (ack) sendFlood (ack, TXT_ACK_DELAY);
620+ } else {
621+ uint32_t d = TXT_ACK_DELAY;
622+ if (getExtraAckTransmitCount () > 0 ) {
623+ mesh::Packet* a1 = createMultiAck (ack_hash, 1 );
624+ if (a1) sendDirect (a1, dest.out_path , dest.out_path_len , d);
625+ d += 300 ;
626+ }
627+
628+ mesh::Packet* a2 = createAck (ack_hash);
629+ if (a2) sendDirect (a2, dest.out_path , dest.out_path_len , d);
630+ }
631+ }
632+
616633void SensorMesh::onPeerDataRecv (mesh::Packet* packet, uint8_t type, int sender_idx, const uint8_t * secret, uint8_t * data, size_t len) {
617634 int i = matching_peer_indexes[sender_idx];
618635 if (i < 0 || i >= num_contacts) {
@@ -656,45 +673,71 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i
656673 memcpy (&sender_timestamp, data, 4 ); // timestamp (by sender's RTC clock - which could be wrong)
657674 uint flags = (data[4 ] >> 2 ); // message attempt number, and other flags
658675
659- if (!(flags == TXT_TYPE_CLI_DATA)) {
660- MESH_DEBUG_PRINTLN (" onPeerDataRecv: unsupported text type received: flags=%02x" , (uint32_t )flags);
661- } else if (sender_timestamp > from.last_timestamp ) { // prevent replay attacks
662- from.last_timestamp = sender_timestamp;
663- from.last_activity = getRTCClock ()->getCurrentTime ();
664-
665- // len can be > original length, but 'text' will be padded with zeroes
666- data[len] = 0 ; // need to make a C string again, with null terminator
667-
668- uint8_t temp[166 ];
669- char *command = (char *) &data[5 ];
670- char *reply = (char *) &temp[5 ];
671- handleCommand (sender_timestamp, command, reply);
672-
673- int text_len = strlen (reply);
674- if (text_len > 0 ) {
675- uint32_t timestamp = getRTCClock ()->getCurrentTimeUnique ();
676- if (timestamp == sender_timestamp) {
677- // WORKAROUND: the two timestamps need to be different, in the CLI view
678- timestamp++;
679- }
680- memcpy (temp, ×tamp, 4 ); // mostly an extra blob to help make packet_hash unique
681- temp[4 ] = (TXT_TYPE_CLI_DATA << 2 );
682-
683- auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG, from.id , secret, temp, 5 + text_len);
684- if (reply) {
685- if (from.out_path_len < 0 ) {
686- sendFlood (reply, CLI_REPLY_DELAY_MILLIS);
676+ if (sender_timestamp > from.last_timestamp ) { // prevent replay attacks
677+ if (flags == TXT_TYPE_PLAIN) {
678+ bool handled = handleIncomingMsg (from, sender_timestamp, &data[5 ], flags, len - 5 );
679+ if (handled) { // if msg was handled then send an ack
680+ uint32_t ack_hash; // calc truncated hash of the message timestamp + text + sender pub_key, to prove to sender that we got it
681+ mesh::Utils::sha256 ((uint8_t *) &ack_hash, 4 , data, 5 + strlen ((char *)&data[5 ]), from.id .pub_key , PUB_KEY_SIZE);
682+
683+ if (packet->isRouteFlood ()) {
684+ // let this sender know path TO here, so they can use sendDirect(), and ALSO encode the ACK
685+ mesh::Packet* path = createPathReturn (from.id , secret, packet->path , packet->path_len ,
686+ PAYLOAD_TYPE_ACK, (uint8_t *) &ack_hash, 4 );
687+ if (path) sendFlood (path, TXT_ACK_DELAY);
687688 } else {
688- sendDirect (reply, from.out_path , from.out_path_len , CLI_REPLY_DELAY_MILLIS);
689+ sendAckTo (from, ack_hash);
690+ }
691+ }
692+ } else if (flags == TXT_TYPE_CLI_DATA) {
693+ from.last_timestamp = sender_timestamp;
694+ from.last_activity = getRTCClock ()->getCurrentTime ();
695+
696+ // len can be > original length, but 'text' will be padded with zeroes
697+ data[len] = 0 ; // need to make a C string again, with null terminator
698+
699+ uint8_t temp[166 ];
700+ char *command = (char *) &data[5 ];
701+ char *reply = (char *) &temp[5 ];
702+ handleCommand (sender_timestamp, command, reply);
703+
704+ int text_len = strlen (reply);
705+ if (text_len > 0 ) {
706+ uint32_t timestamp = getRTCClock ()->getCurrentTimeUnique ();
707+ if (timestamp == sender_timestamp) {
708+ // WORKAROUND: the two timestamps need to be different, in the CLI view
709+ timestamp++;
710+ }
711+ memcpy (temp, ×tamp, 4 ); // mostly an extra blob to help make packet_hash unique
712+ temp[4 ] = (TXT_TYPE_CLI_DATA << 2 );
713+
714+ auto reply = createDatagram (PAYLOAD_TYPE_TXT_MSG, from.id , secret, temp, 5 + text_len);
715+ if (reply) {
716+ if (from.out_path_len < 0 ) {
717+ sendFlood (reply, CLI_REPLY_DELAY_MILLIS);
718+ } else {
719+ sendDirect (reply, from.out_path , from.out_path_len , CLI_REPLY_DELAY_MILLIS);
720+ }
689721 }
690722 }
723+ } else {
724+ MESH_DEBUG_PRINTLN (" onPeerDataRecv: unsupported text type received: flags=%02x" , (uint32_t )flags);
691725 }
692726 } else {
693727 MESH_DEBUG_PRINTLN (" onPeerDataRecv: possible replay attack detected" );
694728 }
695729 }
696730}
697731
732+ bool SensorMesh::handleIncomingMsg (ContactInfo& from, uint32_t timestamp, uint8_t * data, uint flags, size_t len) {
733+ MESH_DEBUG_PRINT (" handleIncomingMsg: unhandled msg from " );
734+ #ifdef MESH_DEBUG
735+ mesh::Utils::printHex (Serial, from.id .pub_key , PUB_KEY_SIZE);
736+ Serial.printf (" : %s\n " , data);
737+ #endif
738+ return false ;
739+ }
740+
698741bool SensorMesh::onPeerPathRecv (mesh::Packet* packet, int sender_idx, const uint8_t * secret, uint8_t * path, uint8_t path_len, uint8_t extra_type, uint8_t * extra, uint8_t extra_len) {
699742 int i = matching_peer_indexes[sender_idx];
700743 if (i < 0 || i >= num_contacts) {
0 commit comments