cleanup packet encrypt/descrypt

This commit is contained in:
Kevin Hester 2021-04-05 09:24:00 +08:00
parent 8ef36bcc9c
commit a845406a19
6 changed files with 92 additions and 69 deletions

View File

@ -12,10 +12,8 @@ typedef uint32_t PacketId; // A packet sequence number
#define NODENUM_BROADCAST UINT32_MAX #define NODENUM_BROADCAST UINT32_MAX
#define ERRNO_OK 0 #define ERRNO_OK 0
#define ERRNO_NO_INTERFACES 33 #define ERRNO_NO_INTERFACES 33
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER #define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
#define ERRNO_DISABLED 34 // the itnerface is disabled #define ERRNO_DISABLED 34 // the itnerface is disabled
#define ERRNO_TOO_LARGE 35
#define ERRNO_NO_CHANNEL 36
/** /**
* the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket. * the max number of hops a message can pass through, used as the default max for hop_limit in MeshPacket.
@ -35,7 +33,7 @@ typedef int ErrorCode;
extern Allocator<MeshPacket> &packetPool; extern Allocator<MeshPacket> &packetPool;
/** /**
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node. * Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on
* If from is zero this function returns our node number instead * the local node. If from is zero this function returns our node number instead
*/ */
NodeNum getFrom(const MeshPacket *p); NodeNum getFrom(const MeshPacket *p);

View File

@ -361,12 +361,8 @@ ErrorCode SimRadio::send(MeshPacket *p)
void RadioInterface::deliverToReceiver(MeshPacket *p) void RadioInterface::deliverToReceiver(MeshPacket *p)
{ {
assert(rxDest);
assert(rxDest->enqueue(p, 0)); // NOWAIT - fixme, if queue is full, delete older messages
// Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME
if (router) if (router)
router->setReceivedMessage(); router->enqueueReceivedMessage(p);
} }
/*** /***

View File

@ -42,7 +42,6 @@ typedef struct {
class RadioInterface class RadioInterface
{ {
friend class MeshRadio; // for debugging we let that class touch pool friend class MeshRadio; // for debugging we let that class touch pool
PointerQueue<MeshPacket> *rxDest = NULL;
CallbackObserver<RadioInterface, void *> configChangedObserver = CallbackObserver<RadioInterface, void *> configChangedObserver =
CallbackObserver<RadioInterface, void *>(this, &RadioInterface::reloadConfig); CallbackObserver<RadioInterface, void *>(this, &RadioInterface::reloadConfig);
@ -82,17 +81,11 @@ class RadioInterface
float freq = 915.0; float freq = 915.0;
/** pool is the pool we will alloc our rx packets from /** pool is the pool we will alloc our rx packets from
* rxDest is where we will send any rx packets, it becomes receivers responsibility to return packet to the pool
*/ */
RadioInterface(); RadioInterface();
virtual ~RadioInterface() {} virtual ~RadioInterface() {}
/**
* Set where to deliver received packets. This method should only be used by the Router class
*/
void setReceiver(PointerQueue<MeshPacket> *_rxDest) { rxDest = _rxDest; }
/** /**
* Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving) * Return true if we think the board can go to sleep (i.e. our tx queue is empty, we are not sending or receiving)
* *

View File

@ -65,6 +65,22 @@ int32_t Router::runOnce()
return INT32_MAX; // Wait a long time - until we get woken for the message queue return INT32_MAX; // Wait a long time - until we get woken for the message queue
} }
/**
* RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for
* freeing the packet
*/
void Router::enqueueReceivedMessage(MeshPacket *p)
{
if (fromRadioQueue.enqueue(p, 0)) { // NOWAIT - fixme, if queue is full, delete older messages
// Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME
setReceivedMessage();
} else {
printPacket("BUG! fromRadioQueue is full! Discarding!", p);
packetPool.release(p);
}
}
/// Generate a unique packet id /// Generate a unique packet id
// FIXME, move this someplace better // FIXME, move this someplace better
PacketId generatePacketId() PacketId generatePacketId()
@ -130,13 +146,8 @@ ErrorCode Router::sendLocal(MeshPacket *p)
{ {
// No need to deliver externally if the destination is the local node // No need to deliver externally if the destination is the local node
if (p->to == nodeDB.getNodeNum()) { if (p->to == nodeDB.getNodeNum()) {
if (fromRadioQueue.enqueue(p, 0)) { printPacket("Enqueued local", p);
printPacket("Enqueued local", p); enqueueReceivedMessage(p);
setReceivedMessage();
} else {
printPacket("BUG! fromRadioQueue is full! Discarding!", p);
packetPool.release(p);
}
return ERRNO_OK; return ERRNO_OK;
} else if (!iface) { } else if (!iface) {
// We must be sending to remote nodes also, fail if no interface found // We must be sending to remote nodes also, fail if no interface found
@ -190,36 +201,14 @@ ErrorCode Router::send(MeshPacket *p)
// If the packet is not yet encrypted, do so now // If the packet is not yet encrypted, do so now
if (p->which_payloadVariant == MeshPacket_decoded_tag) { if (p->which_payloadVariant == MeshPacket_decoded_tag) {
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
// printPacket("pre encrypt", p); // portnum valid here
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
if (numbytes > MAX_RHPACKETLEN) {
abortSendAndNak(Routing_Error_TOO_LARGE, p);
return ERRNO_TOO_LARGE;
}
// printBytes("plaintext", bytes, numbytes);
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
auto hash = channels.setActiveByIndex(chIndex);
if (hash < 0) { auto encodeResult = perhapsEncode(p);
// No suitable channel could be found for sending if (encodeResult != Routing_Error_NONE) {
abortSendAndNak(Routing_Error_NO_CHANNEL, p); abortSendAndNak(encodeResult, p);
return ERRNO_NO_CHANNEL; return encodeResult; // FIXME - this isn't a valid ErrorCode
} }
// Now that we are encrypting the packet channel should be the hash (no longer the index)
p->channel = hash;
crypto->encrypt(getFrom(p), p->id, numbytes, bytes);
// Copy back into the packet and set the variant type
memcpy(p->encrypted.bytes, bytes, numbytes);
p->encrypted.size = numbytes;
p->which_payloadVariant = MeshPacket_encrypted_tag;
if (mqtt) if (mqtt)
mqtt->onSend(*p, chIndex); mqtt->onSend(*p, chIndex);
} }
@ -244,7 +233,7 @@ void Router::sniffReceived(const MeshPacket *p, const Routing *c)
// FIXME, update nodedb here for any packet that passes through us // FIXME, update nodedb here for any packet that passes through us
} }
bool Router::perhapsDecode(MeshPacket *p) bool perhapsDecode(MeshPacket *p)
{ {
if (p->which_payloadVariant == MeshPacket_decoded_tag) if (p->which_payloadVariant == MeshPacket_decoded_tag)
return true; // If packet was already decoded just return return true; // If packet was already decoded just return
@ -285,6 +274,42 @@ bool Router::perhapsDecode(MeshPacket *p)
return false; return false;
} }
/** Return 0 for success or a Routing_Errror code for failure
*/
Routing_Error perhapsEncode(MeshPacket *p)
{
// If the packet is not yet encrypted, do so now
if (p->which_payloadVariant == MeshPacket_decoded_tag) {
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
// printPacket("pre encrypt", p); // portnum valid here
size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
if (numbytes > MAX_RHPACKETLEN)
return Routing_Error_TOO_LARGE;
// printBytes("plaintext", bytes, numbytes);
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
auto hash = channels.setActiveByIndex(chIndex);
if (hash < 0)
// No suitable channel could be found for sending
return Routing_Error_NO_CHANNEL;
// Now that we are encrypting the packet channel should be the hash (no longer the index)
p->channel = hash;
crypto->encrypt(getFrom(p), p->id, numbytes, bytes);
// Copy back into the packet and set the variant type
memcpy(p->encrypted.bytes, bytes, numbytes);
p->encrypted.size = numbytes;
p->which_payloadVariant = MeshPacket_encrypted_tag;
}
return Routing_Error_NONE;
}
NodeNum Router::getNodeNum() NodeNum Router::getNodeNum()
{ {
return nodeDB.getNodeNum(); return nodeDB.getNodeNum();

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include "Channels.h"
#include "MemoryPool.h" #include "MemoryPool.h"
#include "MeshTypes.h" #include "MeshTypes.h"
#include "Observer.h" #include "Observer.h"
#include "PointerQueue.h" #include "PointerQueue.h"
#include "RadioInterface.h" #include "RadioInterface.h"
#include "concurrency/OSThread.h" #include "concurrency/OSThread.h"
#include "Channels.h"
/** /**
* A mesh aware router that supports multiple interfaces. * A mesh aware router that supports multiple interfaces.
@ -22,7 +22,6 @@ class Router : protected concurrency::OSThread
RadioInterface *iface = NULL; RadioInterface *iface = NULL;
public: public:
/** /**
* Constructor * Constructor
* *
@ -32,11 +31,7 @@ class Router : protected concurrency::OSThread
/** /**
* Currently we only allow one interface, that may change in the future * Currently we only allow one interface, that may change in the future
*/ */
void addInterface(RadioInterface *_iface) void addInterface(RadioInterface *_iface) { iface = _iface; }
{
iface = _iface;
iface->setReceiver(&fromRadioQueue);
}
/** /**
* do idle processing * do idle processing
@ -53,7 +48,7 @@ class Router : protected concurrency::OSThread
ErrorCode sendLocal(MeshPacket *p); ErrorCode sendLocal(MeshPacket *p);
/** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */
bool cancelSending(NodeNum from, PacketId id); bool cancelSending(NodeNum from, PacketId id);
/** Allocate and return a meshpacket which defaults as send to broadcast from the current node. /** Allocate and return a meshpacket which defaults as send to broadcast from the current node.
* The returned packet is guaranteed to have a unique packet ID already assigned * The returned packet is guaranteed to have a unique packet ID already assigned
@ -69,6 +64,12 @@ class Router : protected concurrency::OSThread
*/ */
void setReceivedMessage(); void setReceivedMessage();
/**
* RadioInterface calls this to queue up packets that have been received from the radio. The router is now responsible for
* freeing the packet
*/
void enqueueReceivedMessage(MeshPacket *p);
protected: protected:
friend class RoutingPlugin; friend class RoutingPlugin;
@ -83,7 +84,7 @@ class Router : protected concurrency::OSThread
/** /**
* Should this incoming filter be dropped? * Should this incoming filter be dropped?
* *
* FIXME, move this into the new RoutingPlugin and do the filtering there using the regular plugin logic * FIXME, move this into the new RoutingPlugin and do the filtering there using the regular plugin logic
* *
* Called immedately on receiption, before any further processing. * Called immedately on receiption, before any further processing.
@ -97,18 +98,11 @@ class Router : protected concurrency::OSThread
*/ */
virtual void sniffReceived(const MeshPacket *p, const Routing *c); virtual void sniffReceived(const MeshPacket *p, const Routing *c);
/**
* Remove any encryption and decode the protobufs inside this packet (if necessary).
*
* @return true for success, false for corrupt packet.
*/
bool perhapsDecode(MeshPacket *p);
/** /**
* Send an ack or a nak packet back towards whoever sent idFrom * Send an ack or a nak packet back towards whoever sent idFrom
*/ */
void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex); void sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex);
private: private:
/** /**
* Called from loop() * Called from loop()
@ -134,6 +128,17 @@ class Router : protected concurrency::OSThread
void abortSendAndNak(Routing_Error err, MeshPacket *p); void abortSendAndNak(Routing_Error err, MeshPacket *p);
}; };
/** FIXME - move this into a mesh packet class
* Remove any encryption and decode the protobufs inside this packet (if necessary).
*
* @return true for success, false for corrupt packet.
*/
bool perhapsDecode(MeshPacket *p);
/** Return 0 for success or a Routing_Errror code for failure
*/
Routing_Error perhapsEncode(MeshPacket *p);
extern Router *router; extern Router *router;
/// Generate a unique packet id /// Generate a unique packet id

View File

@ -2,6 +2,7 @@
#include "NodeDB.h" #include "NodeDB.h"
#include "main.h" #include "main.h"
#include "mesh/Channels.h" #include "mesh/Channels.h"
#include "mesh/Router.h"
#include "mesh/generated/mqtt.pb.h" #include "mesh/generated/mqtt.pb.h"
#include <WiFi.h> #include <WiFi.h>
#include <assert.h> #include <assert.h>
@ -26,6 +27,11 @@ void MQTT::onPublish(char *topic, byte *payload, unsigned int length)
DEBUG_MSG("Received MQTT topic %s, len=%u\n", topic, length); DEBUG_MSG("Received MQTT topic %s, len=%u\n", topic, length);
// FIXME, ignore messages sent by us (requires decryption) or if we don't have the channel key // FIXME, ignore messages sent by us (requires decryption) or if we don't have the channel key
if (e.packet) {
MeshPacket *p = packetPool.allocCopy(*e.packet);
if (router)
router->enqueueReceivedMessage(p);
}
// make sure to free both strings and the MeshPacket (passing in NULL is acceptable) // make sure to free both strings and the MeshPacket (passing in NULL is acceptable)
free(e.channel_id); free(e.channel_id);