
Прототип mesh-сети IoT/любительского радио с глобальной маршрутизацией через интернет

Система mesh-маршрутизации, которая поддерживает использование прокси OpenDHT в качестве бэкенда, благодаря чему узлы могут связываться напрямую через интернет. Очень ранняя пре-альфа, концепт-прототип, может не работать на деле и т. д.
Она предназначена как для любительских/HAM-сценариев, так и для более типичных потребительских/коммерческих задач Интернета вещей (IoT), но при этом специально не пытается заменить интернет или покрывать большие территории с высокой нагрузкой всенаправленными антеннами.
В ней нет маршрутизации следующего прыжка в стиле Meshtastic, отсюда и название LazyMesh. Если вы хотите использовать её для автономных (offgrid) приложений в плотно застроенной местности, вам, вероятно, понадобятся направленные антенны и вручную согласованные номера маршрутов.
Пока это единственное реальное приложение. Откройте пример скетча Arduino, измените его, указав ваше имя пользователя и секретный ключ канала — это должен быть надёжный пароль.
Введите сообщение в последовательный монитор Arduino — вы сможете общаться со всеми другими устройствами.
Сообщения должны доходить, если узлы находятся в одной сети или у обоих есть доступ в интернет.
Посетите Веб-клиент, чтобы общаться с узлом через MQTT из интернета. Просто укажите имя пользователя, добавьте канал и введите пароль канала. Имя канала может быть любым и влияет только на подписи в интерфейсе.
Вы также можете попробовать пример скетча чтения/записи данных. Он открывает ID данных 195 для чтения, а ID данных 196 — для чтения и записи. Зайдите на сайт, введите данные канала и используйте диалог запроса данных, чтобы запросить ID 196 у всех устройств.
Затем нажмите «set» и установите другое значение, после чего попробуйте прочитать его снова.
Веб-клиент в настоящее время жёстко привязан к test.mosquitto.org, в будущем это изменится.
Узлам нужен способ синхронизировать время для связи. Сейчас, если они никогда не получали время из доверенного источника, они устанавливают своё время на основе любого случайного пакета.
Это может быть риском для безопасности, допускающим атаки повторного воспроизведения, поэтому устройствам, которым нужна безопасность, следует иметь доверенный источник времени.
После первичной установки времени код будет корректировать системное время до 1 секунды в день, чтобы оставаться синхронизированным с другими узлами, так что рассинхронизация не должна быть серьёзной проблемой.
В LazyMesh всё является каналом, прямых сообщений нет. Если вам нужны прямые сообщения, просто создайте выделенный приватный канал.
Каналы определяются паролем: знание пароля даёт доступ на чтение и запись.
Всего существует 256 номеров маршрутов. Каждый пакет имеет один из них, и повторители повторяют пакет только в том случае, если у них включён соответствующий номер маршрута. По умолчанию всё отправляется с номером маршрута 0, который включён по умолчанию.
Это влияет только на повторители: узлы будут слушать любой номер mesh-маршрута, если пакет предназначен непосредственно им.
Полезная нагрузка пакетов — это массивы MessagePack. В них чередуются целочисленные ID данных и элементы данных. ID 192–256 зарезервированы для прикладных сообщений.
ID 32 используется для текстовых сообщений, которые могут иметь префикс с именем пользователя и двоеточием.
ID 2 используется для уникального идентификатора, который должен быть целым числом. Многим приложениям он может вообще не понадобиться.
Добавьте байт длины метаданных и N байт метаданных.
Чтобы создать IV, возьмите 12 случайных байтов для IV. Затем зашифруйте всё целиком. Добавьте IV в начало и 4 байта тега аутентификации в конец.
Затем возьмите первые 8 байтов хеша маршрутного ID и преобразуйте их в hex.
Тема MQTT будет lazymesh_route_HEX
Обратите внимание, что мы используем тему верхнего уровня. Это сделано для того, чтобы вы не могли с помощью подстановочных знаков подписаться сразу на все каналы lazymesh на публичных брокерах, что позволило бы довольно легко устроить DoS для всех.
Просто необработанные пакеты, отправляемые широковещательно на 224.0.0.251:2221
Ничто из этого не является окончательным!!!
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
Некоторые реализации могут вообще игнорировать это.
ACK являются чисто посегментными (per hop), если только вышестоящий протокольный уровень не захочет сквозных ACK.
ACK-пакеты не повторяются, не маршрутизируются и никак не аутентифицируются. Каждый шаг mesh-повторения имеет собственное подтверждение; с точки зрения исходного отправителя это работает по принципу «отправил и забыл».