
Prueba de concepto de red mesh IoT/Radioaficionado con enrutamiento global a través de Internet.

Sistema de enrutamiento de malla que soporta el uso de un proxy OpenDHT como backend, para que los nodos puedan comunicarse directamente a través de internet. Muy temprano pre alfa, prueba de concepto, podría no funcionar realmente, etc.
Está pensado tanto para casos de uso de hobby/HAM, como para trabajo IoT más típico de consumo/comercial, pero específicamente no intenta reemplazar internet, ni cubrir grandes áreas de alto tráfico con antenas omnidireccionales.
No tiene enrutamiento de siguiente salto al estilo Meshtastic, de ahí el nombre LazyMesh. Si quieres usarlo para aplicaciones de tipo fuera de la red en un área densa, probablemente necesitarás antenas direccionales e IDs de ruta coordinados manualmente.
Ahora mismo esta es la única aplicación real. Abre el sketch de ejemplo de Arduino, modifícalo con tu nombre de usuario y una clave de canal secreta que debe ser una contraseña segura.
Escribe tu mensaje en el monitor serial de Arduino, y deberías poder chatear con todos los demás dispositivos.
Los mensajes deberían llegar siempre que los nodos estén en la misma red, o ambos tengan acceso a internet.
Visita el Cliente Web para chatear con el nodo a través de MQTT desde internet. Solo establece un nombre de usuario, añade un canal e ingresa la contraseña del canal. El nombre del canal puede ser cualquier cosa y solo afecta el etiquetado en la interfaz.
También puedes probar el sketch de ejemplo de lectura/escritura de datos. Este expone el ID de datos 195 como legible, y el ID de datos 196 como legible y escribible. Ve al sitio, ingresa los detalles de tu canal y usa el diálogo de solicitud de datos para solicitar el ID 196 de todos los dispositivos.
Luego haz clic en "set" y establécela en otro valor, e intenta leerla de nuevo.
El Cliente Web actualmente está hardcodeado para usar test.mosquitto.org, esto cambiará en el futuro.
Los nodos necesitan alguna forma de sincronizar la hora para comunicarse. Actualmente, si nunca han recibido la hora de una fuente confiable, establecerán su hora a partir de cualquier paquete aleatorio que vean.
Esto podría ser un riesgo de seguridad que permite ataques de repetición, por lo que los dispositivos que necesitan seguridad deben tener una fuente de tiempo confiable.
Una vez que se ha establecido la hora inicialmente, el código ajustará su hora del sistema hasta 1 segundo por día para mantenerse sincronizado con otros nodos, por lo que la desviación de la sincronización no debería ser un problema importante.
En Lazymesh, todo es un canal, no hay mensajes directos. Si los quieres, solo crea un canal privado dedicado.
Los canales se definen por una contraseña, conocer la contraseña permite acceso de lectura y escritura.
Hay 256 números de ruta. Cada paquete tiene uno, y los repetidores solo repiten si tienen habilitado un número de ruta coincidente. Por defecto, todo se envía con el número de ruta 0, que está habilitado por defecto.
Esto solo afecta a los repetidores, los nodos escucharán cualquier número de ruta de malla si está directamente dirigido a ellos.
Los payloads de los paquetes son arrays de MessagePack. Alternan IDs de datos enteros y elementos de datos. 192-256 están reservados para mensajes específicos de la aplicación.
El ID 32 es para mensajes de texto, que pueden tener un prefijo con un nombre de usuario y dos puntos.
El ID 2 se usa para un ID único, que debe ser un entero. Muchas aplicaciones podrían no necesitarlo en absoluto.
Añadir un byte de longitud de metadatos y N bytes de metadatos.
Para crear el IV, toma 12 bytes aleatorios para el IV. Luego cifra todo. Antepón el IV y añade 4 bytes de etiqueta de autenticación.
Luego toma los primeros 8 bytes del hash del ID de ruta y conviértelos a hexadecimal.
El tópico MQTT será lazymesh_route_HEX
Nota que usamos un tópico de nivel superior. Esto es para que no puedas usar comodines para suscribirte a todos los canales lazymesh a la vez en brokers públicos, lo que te permitiría hacer DoS a todos con bastante facilidad.
Solo los paquetes sin procesar transmitidos en 224.0.0.251:2221
¡¡¡Nada de esto está finalizado!!!
All numbers are little-endian.
1 byte header:
2 bit packet type(Either 1 or 2, depending on if we want ACK)
3 bits TTL hops remaining
1 bit allow slow transport(LoRa etc)
1 bit allow global routing
1 bit was already global routed
1 byte header 2:
1 bit first send attempt:
Whenever we create a or recieve a packet, set this bit. After trying to send it,
clear it. This way, as long as we assume packet loss is low-ish, we can count the repeaters in the area
without extra overhead.
1 bit repeater bit:
Marks that this packet should be included when counting repeaters.
Set it if you would repeat the packet or one like it, even if you originated it.
1 bit interest bit:
If this is set, the node who sent it is directly interested in the channel,
not purely just a repeater. If first send is also set, it is treated as an
implicit ack
1 bit location enabled
If this bit is set, repeaters may add location metadata to the packets forwarded to the internet. This metadata must be encrypted with the routing ID as the key,
meaning nearby people could track you for 1 hour after you get out of range.
Not implemented anywhere at the moment.
5 reserved 0 bits
1 byte mesh route number
1 byte path loss accumulated:
5 bits total
3 bits last hop
Every hop is a point of path loss,
plus whatever extra cost heuristic the transport applies.
1 extra point of loss should be roughly the same "badness" as
10dbm extra loss on wifi.
16 bytes routing ID:
Changes every hour, derived from the channel PSK by a hash.
The PSK is just the 16 byte SHA256 of the password.
The routing ID changes hourly, and is the SHA256 of:
The letter 'cr'
The count of hours since 1970 as a 32 bit unsigned int
the PSK
8 Bytes random entropy:
Used as part of the IV for the cipher
4 bytes timestamp:
Also part of the IV, also prevents replay attacks
N bytes ciphertext:
AES-GCM encrypted.
The encryption key changes hourly, and is the SHA256 of:
The letter 'c'
The count of hours since 1970 as a 32 bit unsigned int
the PSK
6 bytes auth tag:
The last 6 bytes are the GCM tag
Algunas implementaciones pueden optar por ignorar esto por completo.
Los ACK son puramente por salto a menos que una capa de protocolo superior quiera hacer ACK de extremo a extremo.
Los paquetes ACK no se repiten ni se enrutan ni nada, tampoco están autenticados. Cada paso de la repetición en malla tiene su propio reconocimiento, desde la perspectiva del remitente original, es 'disparar y olvidar'.
Como Meshtastic y la mayoría de otros, el protocolo es "semi-confiable", hay, como en todas las redes, casos límite que causan fallos.
La confiabilidad real debe hacerse a un nivel superior.
Por cada paquete, cada oyente interesado en ese canal específico envía un reconocimiento de canal exactamente una vez, a menos que detecte que más de 8 ACK ya han sido enviados por otros nodos.
Este paquete debe enviarse en todos los transportes, no solo en el que vino el paquete, de lo contrario otros nodos podrían tener una idea equivocada de cuántos oyentes hay.
Cuando un paquete tiene tanto el bit de primer intento de envío como el indicador de interés, es como un ACK implícito. Si estamos enviando una copia del paquete, no necesitamos enviar también un ACK para agregarnos al conteo de interés.
Los repetidores reconocen simplemente enviando una copia del paquete, cuando está marcado con el indicador de primera copia, lo contamos. Por esta razón, los transportes como WiFi deben repetir aunque realmente no tenga sentido.
Esto NO aplica a los transportes de enrutamiento global, el enrutamiento global se maneja por separado y no está sujeto a ningún tipo de ACK o repeticiones o nada, asumimos que el servidor MQTT maneja todo.
Los nodos pueden reenviar un mensaje unas cuantas veces si obtienen menos respuestas de las esperadas.
Los nodos nunca deben esperar más de 6 repetidores y 6 oyentes de canal, incluso si obtienen más respuestas, ya que el esquema simple de ACK se vuelve inexacto más allá de eso si la pérdida de paquetes es moderada.
1 byte header:
Always 0, packet type is control, and these are not routable or repeatable
1 byte header 2:
Same as on the data packets. Not really used at the moment
1 byte subtype:
CONTROL_TYPE_CHANNEL_ACKNOWLEDGE
You can acknowlege as a channel listener
so the sender knows how many there are.
4 byte message ID:
just the first 4 bytes of the random IV from the packet we are ACKing
Cada hora, unos minutos antes de la hora, los nodos deben enviar un anuncio de los canales en los que están interesados.
Esto debe enviarse con los códigos rotatorios para la próxima hora en lugar de la hora actual, para que las conexiones puedan establecerse con anticipación y todo funcione incluso cuando las horas están desincronizadas.
Los nodos se conectan en malla a través de bluetooth usando un paquete de publicidad extendida con UUID de servicio d1a77e11-420f-9f11-1a00-10a6beef0001, y el payload es solo el formato de paquete anterior.
Los paquetes BLE nunca deben tener el indicador de "primera copia" establecido, y no contamos repetidores a través de BLE. La pérdida de paquetes es demasiado alta para cualquier esquema simple y escalable que pueda pensar.
Por lo tanto, simplemente lo tratamos como un canal inherentemente con pérdidas, que mitigamos algo repitiendo paquetes hasta 4 veces, o hasta que necesitemos dejar de hacerlo para poder enviar algún otro paquete.
Siempre que el nodo no intente enviar más de uno o dos paquetes por segundo, el esquema de repetición pura proporcionará cierta confiabilidad, y si superamos eso, entonces retrocederá para no bloquear todo.
También dejamos de enviar si vemos demasiados otros nodos en la misma área enviando demasiadas copias del paquete.