mirror of
https://github.com/markqvist/Reticulum.git
synced 2026-05-13 13:58:11 +00:00
Added markdown manual build
This commit is contained in:
parent
4d6e164d62
commit
ec27d8bfde
18 changed files with 1025 additions and 166 deletions
|
|
@ -39,5 +39,6 @@ help:
|
|||
@if [ $@ = "markdown" ]; then \
|
||||
rm -rf markdown; \
|
||||
cp -r build/markdown ./; \
|
||||
./clean_md.py ./markdown \
|
||||
echo "Markdown Manual Generated"; \
|
||||
fi
|
||||
|
|
|
|||
136
docs/clean_md.py
Executable file
136
docs/clean_md.py
Executable file
|
|
@ -0,0 +1,136 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
LINE_START_PATTERNS = [
|
||||
r'<a\s+', # HTML anchor tags: <a id="..."></a>
|
||||
r'\\\\newpage', # LaTeX newpage commands
|
||||
]
|
||||
|
||||
LINE_ANY_PATTERNS = [
|
||||
# r'<div[^>]*>',
|
||||
# r'</div>',
|
||||
]
|
||||
|
||||
def compile_patterns():
|
||||
"""Compile regex patterns for matching lines to remove."""
|
||||
start_patterns = [re.compile(p) for p in LINE_START_PATTERNS]
|
||||
any_patterns = [re.compile(p) for p in LINE_ANY_PATTERNS]
|
||||
return start_patterns, any_patterns
|
||||
|
||||
|
||||
def should_remove_line(line, start_patterns, any_patterns):
|
||||
"""Check if a line should be removed based on configured patterns."""
|
||||
stripped = line.strip()
|
||||
|
||||
# Check start-of-line patterns
|
||||
for pattern in start_patterns:
|
||||
if pattern.match(stripped):
|
||||
return True
|
||||
|
||||
# Check anywhere-in-line patterns
|
||||
for pattern in any_patterns:
|
||||
if pattern.search(stripped):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def clean_markdown_content(content, start_patterns, any_patterns):
|
||||
"""
|
||||
Remove matching lines and collapse trailing empty lines.
|
||||
|
||||
When a line is removed, any immediately following empty lines
|
||||
are also removed to avoid leaving gaps in the document.
|
||||
"""
|
||||
lines = content.split('\n')
|
||||
result = []
|
||||
skip_next_empty = False
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
if should_remove_line(line, start_patterns, any_patterns):
|
||||
# Mark that we should skip trailing empty lines
|
||||
skip_next_empty = True
|
||||
continue
|
||||
|
||||
if skip_next_empty:
|
||||
if line.strip() == '':
|
||||
# Skip this empty line (trailing from removed line)
|
||||
continue
|
||||
else:
|
||||
# Non-empty line, resume normal processing
|
||||
skip_next_empty = False
|
||||
|
||||
result.append(line)
|
||||
|
||||
# Remove trailing empty lines from end of file
|
||||
while result and result[-1].strip() == '':
|
||||
result.pop()
|
||||
|
||||
return '\n'.join(result)
|
||||
|
||||
|
||||
def process_file(filepath, start_patterns, any_patterns):
|
||||
"""Process a single markdown file."""
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
original_content = f.read()
|
||||
|
||||
cleaned_content = clean_markdown_content(
|
||||
original_content, start_patterns, any_patterns
|
||||
)
|
||||
|
||||
# Only write if changes were made
|
||||
if cleaned_content != original_content:
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(cleaned_content)
|
||||
return True
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error processing {filepath}: {e}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
|
||||
def find_markdown_files(directory):
|
||||
"""Recursively find all .md files in directory."""
|
||||
md_files = []
|
||||
for root, _, files in os.walk(directory):
|
||||
for filename in files:
|
||||
if filename.endswith('.md'):
|
||||
md_files.append(Path(root) / filename)
|
||||
return md_files
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python clean_markdown.py <directory_path>", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
directory = sys.argv[1]
|
||||
|
||||
if not os.path.isdir(directory):
|
||||
print(f"Error: '{directory}' is not a valid directory", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
start_patterns, any_patterns = compile_patterns()
|
||||
md_files = find_markdown_files(directory)
|
||||
|
||||
if not md_files:
|
||||
print(f"No markdown files found in '{directory}'")
|
||||
return
|
||||
|
||||
modified_count = 0
|
||||
for filepath in md_files:
|
||||
if process_file(filepath, start_patterns, any_patterns):
|
||||
print(f"Cleaned: {filepath}")
|
||||
modified_count += 1
|
||||
|
||||
print(f"\nProcessed {len(md_files)} file(s), modified {modified_count}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
<a id="examples-main"></a>
|
||||
|
||||
# Code Examples
|
||||
|
||||
A number of examples are included in the source distribution of Reticulum.
|
||||
You can use these examples to learn how to write your own programs.
|
||||
|
||||
<a id="example-minimal"></a>
|
||||
|
||||
## Minimal
|
||||
|
||||
The *Minimal* example demonstrates the bare-minimum setup required to connect to
|
||||
|
|
@ -121,8 +117,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Minimal.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Minimal.py).
|
||||
|
||||
<a id="example-announce"></a>
|
||||
|
||||
## Announce
|
||||
|
||||
The *Announce* example builds upon the previous example by exploring how to
|
||||
|
|
@ -306,8 +300,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Announce.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Announce.py).
|
||||
|
||||
<a id="example-broadcast"></a>
|
||||
|
||||
## Broadcast
|
||||
|
||||
The *Broadcast* example explores how to transmit plaintext broadcast messages
|
||||
|
|
@ -439,8 +431,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Broadcast.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Broadcast.py).
|
||||
|
||||
<a id="example-echo"></a>
|
||||
|
||||
## Echo
|
||||
|
||||
The *Echo* example demonstrates communication between two destinations using
|
||||
|
|
@ -783,8 +773,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Echo.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Echo.py).
|
||||
|
||||
<a id="example-link"></a>
|
||||
|
||||
## Link
|
||||
|
||||
The *Link* example explores establishing an encrypted link to a remote
|
||||
|
|
@ -1085,8 +1073,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py).
|
||||
|
||||
<a id="example-identify"></a>
|
||||
|
||||
## Identification
|
||||
|
||||
The *Identify* example explores identifying an intiator of a link, once
|
||||
|
|
@ -1410,8 +1396,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py).
|
||||
|
||||
<a id="example-request"></a>
|
||||
|
||||
## Requests & Responses
|
||||
|
||||
The *Request* example explores sending requests and receiving responses.
|
||||
|
|
@ -1707,8 +1691,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py).
|
||||
|
||||
<a id="example-channel"></a>
|
||||
|
||||
## Channel
|
||||
|
||||
The *Channel* example explores using a `Channel` to send structured
|
||||
|
|
@ -2440,8 +2422,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Buffer.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Buffer.py).
|
||||
|
||||
<a id="example-filetransfer"></a>
|
||||
|
||||
## Filetransfer
|
||||
|
||||
The *Filetransfer* example implements a basic file-server program that
|
||||
|
|
@ -3056,8 +3036,6 @@ if __name__ == "__main__":
|
|||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/Filetransfer.py](https://github.com/markqvist/Reticulum/blob/master/Examples/Filetransfer.py).
|
||||
|
||||
<a id="example-custominterface"></a>
|
||||
|
||||
## Custom Interfaces
|
||||
|
||||
The *ExampleInterface* demonstrates creating custom interfaces for Reticulum.
|
||||
|
|
@ -3365,4 +3343,4 @@ class ExampleInterface(Interface):
|
|||
interface_class = ExampleInterface
|
||||
```
|
||||
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/ExampleInterface.py](https://github.com/markqvist/Reticulum/blob/master/Examples/ExampleInterface.py).
|
||||
This example can also be found at [https://github.com/markqvist/Reticulum/blob/master/Examples/ExampleInterface.py](https://github.com/markqvist/Reticulum/blob/master/Examples/ExampleInterface.py).
|
||||
|
|
@ -1 +1 @@
|
|||
# An Explanation of Reticulum for Human Beings
|
||||
# An Explanation of Reticulum for Human Beings
|
||||
|
|
@ -117,8 +117,6 @@ start with reading the next section, [Bootstrapping Connectivity](#bootstrapping
|
|||
as this provides the most essential understanding of how to ensure reliable
|
||||
connectivity with a minimum of maintenance.
|
||||
|
||||
<a id="bootstrapping-connectivity"></a>
|
||||
|
||||
## Bootstrapping Connectivity
|
||||
|
||||
Reticulum is not a service you subscribe to, nor is it a single global network you “join”. It is a *networking stack*; a toolkit for building communications systems that align with your specific values, requirements, and operational environment. The way you choose to connect to other Reticulum peers is entirely your own choice.
|
||||
|
|
@ -186,8 +184,6 @@ A global, distributed backbone of Reticulum Transport Nodes is being run by volu
|
|||
|
||||
As a good starting point, you can find interface definitions for connecting your own networks to this backbone on websites such as [directory.rns.recipes](https://directory.rns.recipes/) and [rmap.world](https://rmap.world/).
|
||||
|
||||
<a id="hosting-entrypoints"></a>
|
||||
|
||||
## Hosting Public Entrypoints
|
||||
|
||||
If you want to help build a strong global interconnection backbone, you can host a public (or private) entry-point to a Reticulum network over the
|
||||
|
|
@ -339,8 +335,6 @@ The entire Reticulum API is documented in the [API Reference](reference.md#api-m
|
|||
chapter of this manual. Before diving in, it’s probably a good idea to read
|
||||
this manual in full, but at least start with the [Understanding Reticulum](understanding.md#understanding-main) chapter.
|
||||
|
||||
<a id="install-guides"></a>
|
||||
|
||||
## Platform-Specific Install Notes
|
||||
|
||||
Some platforms require a slightly different installation procedure, or have
|
||||
|
|
@ -687,4 +681,4 @@ No matter how Reticulum is installed and started, it will load external dependen
|
|||
only if they are *needed* and *available*. If for example you want to use Reticulum
|
||||
on a system that cannot support `pyserial`, it is perfectly possible to do so using
|
||||
the rnspure package, but Reticulum will not be able to use serial-based interfaces.
|
||||
All other available modules will still be loaded when needed.
|
||||
All other available modules will still be loaded when needed.
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="git-main"></a>
|
||||
|
||||
# Git Over Reticulum
|
||||
|
||||
A set of utilities for distributed collaborative software development and publishing is included in RNS.
|
||||
|
|
@ -558,4 +556,4 @@ options:
|
|||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
```
|
||||
```
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="hardware-main"></a>
|
||||
|
||||
# Communications Hardware
|
||||
|
||||
One of the truly valuable aspects of Reticulum is the ability to use it over
|
||||
|
|
@ -38,8 +36,6 @@ links based on WiFi or millimeter-wave radios (with high-gain directional antenn
|
|||
for the network backbone, and using LoRa-based RNodes for covering large areas with
|
||||
connectivity for client devices.
|
||||
|
||||
<a id="rnode-main"></a>
|
||||
|
||||
## RNode
|
||||
|
||||
Reliable and general-purpose long-range digital radio transceiver systems are
|
||||
|
|
@ -62,8 +58,6 @@ used for centrally controlled IoT devices. RNodes use *raw LoRa modulation*, wit
|
|||
any additional protocol overhead. All high-level protocol functionality is handled
|
||||
directly by Reticulum.
|
||||
|
||||
<a id="rnode-creating"></a>
|
||||
|
||||
### Creating RNodes
|
||||
|
||||
RNode has been designed as a system that is easy to replicate across time and
|
||||
|
|
@ -81,8 +75,6 @@ is ready to use with any software that supports RNodes, including Reticulum.
|
|||
The device can be used with Reticulum by adding an [RNodeInterface](interfaces.md#interfaces-rnode)
|
||||
to the configuration.
|
||||
|
||||
<a id="rnode-supported"></a>
|
||||
|
||||
### Supported Boards and Devices
|
||||
|
||||
To create one or more RNodes, you will need to obtain supported development
|
||||
|
|
@ -226,8 +218,6 @@ by the auto-installer.
|
|||
|
||||
---
|
||||
|
||||
<a id="rnode-installation"></a>
|
||||
|
||||
### Installation
|
||||
|
||||
Once you have obtained compatible boards, you can install the [RNode Firmware](https://github.com/markqvist/RNode_Firmware)
|
||||
|
|
@ -251,8 +241,6 @@ The utility will guide you through the installation process by asking a series o
|
|||
questions about your hardware. Simply follow the guide, and the utility will
|
||||
auto-install and configure your devices.
|
||||
|
||||
<a id="rnode-usage"></a>
|
||||
|
||||
### Usage with Reticulum
|
||||
|
||||
When the devices have been installed and provisioned, you can use them with Reticulum
|
||||
|
|
@ -308,4 +296,4 @@ using Reticulum over communications hardware that provides a serial port interfa
|
|||
|
||||
Any packet radio modem that provides a standard KISS interface over USB, serial or TCP
|
||||
can be used with Reticulum. This includes virtual software modems such as
|
||||
[FreeDV TNC](https://github.com/xssfox/freedv-tnc) and [Dire Wolf](https://github.com/wb2osz/direwolf).
|
||||
[FreeDV TNC](https://github.com/xssfox/freedv-tnc) and [Dire Wolf](https://github.com/wb2osz/direwolf).
|
||||
|
|
@ -229,4 +229,4 @@ to participate in the development of Reticulum itself.
|
|||
* [`Buffer`](reference.md#RNS.Buffer)
|
||||
* [`RawChannelReader`](reference.md#RNS.RawChannelReader)
|
||||
* [`RawChannelWriter`](reference.md#RNS.RawChannelWriter)
|
||||
* [`Transport`](reference.md#RNS.Transport)
|
||||
* [`Transport`](reference.md#RNS.Transport)
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="interfaces-main"></a>
|
||||
|
||||
# Configuring Interfaces
|
||||
|
||||
Reticulum supports using many kinds of devices as networking interfaces, and
|
||||
|
|
@ -15,8 +13,6 @@ For a high-level overview of how networks can be formed over different interface
|
|||
types, have a look at the [Building Networks](networks.md#networks-main) chapter of this
|
||||
manual.
|
||||
|
||||
<a id="interfaces-custom"></a>
|
||||
|
||||
## Custom Interfaces
|
||||
|
||||
In addition to the built-in interface types, Reticulum is **fully extensible** with
|
||||
|
|
@ -24,8 +20,6 @@ custom, user- or community-supplied interfaces, and creating custom interface
|
|||
modules is straightforward. Please see the [custom interface](examples.md#example-custominterface)
|
||||
example for basic interface code to build upon.
|
||||
|
||||
<a id="interfaces-auto"></a>
|
||||
|
||||
## Auto Interface
|
||||
|
||||
The `AutoInterface` enables communication with other discoverable Reticulum
|
||||
|
|
@ -113,8 +107,6 @@ the discovery scope by setting it to one of `link`, `admin`, `site`,
|
|||
data_port = 49555
|
||||
```
|
||||
|
||||
<a id="interfaces-backbone"></a>
|
||||
|
||||
## Backbone Interface
|
||||
|
||||
The Backbone interface is a very fast and resource efficient interface type, primarily
|
||||
|
|
@ -220,8 +212,6 @@ specify the target Yggdrasil IPv6 address and port, like so:
|
|||
target_port = 4343
|
||||
```
|
||||
|
||||
<a id="interfaces-tcps"></a>
|
||||
|
||||
## TCP Server Interface
|
||||
|
||||
The TCP Server interface is suitable for allowing other peers to connect over
|
||||
|
|
@ -296,8 +286,6 @@ you must use the i2p_tunneled option:
|
|||
In almost all cases, it is easier to use the dedicated `I2PInterface`, but for complete
|
||||
control, and using I2P routers running on external systems, this option also exists.
|
||||
|
||||
<a id="interfaces-tcpc"></a>
|
||||
|
||||
## TCP Client Interface
|
||||
|
||||
To connect to a TCP server interface, you can use the TCP client
|
||||
|
|
@ -369,8 +357,6 @@ you must use the i2p_tunneled option:
|
|||
i2p_tunneled = yes
|
||||
```
|
||||
|
||||
<a id="interfaces-udp"></a>
|
||||
|
||||
## UDP Interface
|
||||
|
||||
A UDP interface can be useful for communicating over IP networks, both
|
||||
|
|
@ -429,8 +415,6 @@ easier to use.
|
|||
# forward_port = 4242
|
||||
```
|
||||
|
||||
<a id="interfaces-i2p"></a>
|
||||
|
||||
## I2P Interface
|
||||
|
||||
The I2P interface lets you connect Reticulum instances over the
|
||||
|
|
@ -495,8 +479,6 @@ was manually tunneled over I2P, for example. This offers a high degree
|
|||
of flexibility in network setup, while retaining ease of use in simpler
|
||||
use-cases.
|
||||
|
||||
<a id="interfaces-rnode"></a>
|
||||
|
||||
## RNode LoRa Interface
|
||||
|
||||
To use Reticulum over LoRa, the [RNode](https://unsigned.io/rnode/) interface
|
||||
|
|
@ -594,8 +576,6 @@ relevant regulation for your location, and to make decisions accordingly.
|
|||
# airtime_limit_short = 33
|
||||
```
|
||||
|
||||
<a id="interfaces-rnode-multi"></a>
|
||||
|
||||
## RNode Multi Interface
|
||||
|
||||
For RNodes that support multiple LoRa transceivers, the RNode
|
||||
|
|
@ -713,8 +693,6 @@ port = /dev/ttyACM0
|
|||
# airtime_limit_short = 100
|
||||
```
|
||||
|
||||
<a id="interfaces-serial"></a>
|
||||
|
||||
## Serial Interface
|
||||
|
||||
Reticulum can be used over serial ports directly, or over any device with a
|
||||
|
|
@ -737,8 +715,6 @@ directly over a wire-pair, or for using devices such as data radios and lasers.
|
|||
stopbits = 1
|
||||
```
|
||||
|
||||
<a id="interfaces-pipe"></a>
|
||||
|
||||
## Pipe Interface
|
||||
|
||||
Using this interface, Reticulum can use any program as an interface via stdin and
|
||||
|
|
@ -761,8 +737,6 @@ Reticulum will write all packets to stdin of the `command` option, and will
|
|||
continuously read and scan its stdout for Reticulum packets. If `EOF` is reached,
|
||||
Reticulum will try to respawn the program after waiting for `respawn_interval` seconds.
|
||||
|
||||
<a id="interfaces-kiss"></a>
|
||||
|
||||
## KISS Interface
|
||||
|
||||
With the KISS interface, you can use Reticulum over a variety of packet
|
||||
|
|
@ -821,8 +795,6 @@ relevant regulation for your location, and to make decisions accordingly.
|
|||
flow_control = false
|
||||
```
|
||||
|
||||
<a id="interfaces-ax25"></a>
|
||||
|
||||
## AX.25 KISS Interface
|
||||
|
||||
If you’re using Reticulum on amateur radio spectrum, you might want to
|
||||
|
|
@ -887,8 +859,6 @@ relevant regulation for your location, and to make decisions accordingly.
|
|||
flow_control = false
|
||||
```
|
||||
|
||||
<a id="interfaces-discoverable"></a>
|
||||
|
||||
## Discoverable Interfaces
|
||||
|
||||
Reticulum includes a powerful system for publishing your local interfaces to the wider network, allowing other peers to [discover, validate, and automatically connect to them](using.md#using-interface-discovery). This feature is particularly useful for creating decentralized networks where peers can dynamically find entrypoints, such as public Internet gateways or local radio access points, without relying on static configuration files or centralized directories.
|
||||
|
|
@ -1085,8 +1055,6 @@ With these configuration options applied, your Reticulum instance will actively
|
|||
|
||||
For information on how to use these discovered interfaces and configure your system to auto-connect to them, refer to the [Discovering Interfaces](using.md#using-interface-discovery) chapter.
|
||||
|
||||
<a id="interfaces-options"></a>
|
||||
|
||||
## Common Interface Options
|
||||
|
||||
A number of general configuration options are available on most interfaces.
|
||||
|
|
@ -1169,8 +1137,6 @@ These can be used to control various aspects of interface behaviour.
|
|||
> infrastructure, which then supersedes the bootstrap interface.
|
||||
> <br/>
|
||||
|
||||
<a id="interfaces-modes"></a>
|
||||
|
||||
## Interface Modes
|
||||
|
||||
The optional `mode` setting is available on all interfaces, and allows
|
||||
|
|
@ -1249,8 +1215,6 @@ the default mode.
|
|||
For a table describing the impact of all modes on announce propagation,
|
||||
please see the [Announce Propagation Rules](understanding.md#understanding-announcepropagation) section.
|
||||
|
||||
<a id="interfaces-announcerates"></a>
|
||||
|
||||
## Announce Rate Control
|
||||
|
||||
The built-in announce control mechanisms and the default `announce_cap`
|
||||
|
|
@ -1313,8 +1277,6 @@ conserve bandwidth, while very fast networks can support applications that
|
|||
need more frequent announces. Reticulum implements these mechanisms to ensure
|
||||
that a large span of network types can seamlessly *co-exist* and interconnect.
|
||||
|
||||
<a id="interfaces-ingress-control"></a>
|
||||
|
||||
## New Destination Rate Limiting
|
||||
|
||||
On public interfaces, where anyone may connect and announce new destinations,
|
||||
|
|
@ -1381,4 +1343,4 @@ but all the parameters are exposed for configuration if needed.
|
|||
> * The `ic_held_release_interval` option sets how much time (in seconds)
|
||||
> must pass between releasing each held announce from the queue. Defaults
|
||||
> to `30` seconds.
|
||||
> <br/>
|
||||
> <br/>
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="license"></a>
|
||||
|
||||
# Reticulum License
|
||||
|
||||
```text
|
||||
|
|
@ -32,4 +30,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
```
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="networks-main"></a>
|
||||
|
||||
# Building Networks
|
||||
|
||||
This chapter will provide you with the high-level knowledge needed to build networks with
|
||||
|
|
@ -319,4 +317,4 @@ The key design consideration is not whether different mediums can work together
|
|||
with multiple interfaces spanning heterogeneous mediums needs to be configured
|
||||
with appropriate interface modes so that traffic flows efficiently. A gateway
|
||||
connecting a slow LoRa segment to a fast Internet backbone should be configured
|
||||
differently than a mobile device roaming between radio cells.
|
||||
differently than a mobile device roaming between radio cells.
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
<a id="api-main"></a>
|
||||
|
||||
# API Reference
|
||||
|
||||
Communication over Reticulum networks is achieved by using a simple set of classes exposed by the RNS API.
|
||||
This chapter lists and explains all classes exposed by the Reticulum Network Stack API, along with their method signatures and usage. It can be used as a reference while writing applications that utilise Reticulum, or it can be read in entirity to gain an understanding of the complete functionality of RNS from a developers perspective.
|
||||
|
||||
<a id="api-reticulum"></a>
|
||||
|
||||
### *class* RNS.Reticulum(configdir=None, loglevel=None, logdest=None, verbosity=None, require_shared_instance=False, shared_instance_type=None)
|
||||
|
||||
This class is used to initialise access to Reticulum within a
|
||||
|
|
@ -162,8 +158,6 @@ interfaces are discovered.
|
|||
* **Returns:**
|
||||
A list of identity hashes.
|
||||
|
||||
<a id="api-identity"></a>
|
||||
|
||||
### *class* RNS.Identity(create_keys=True)
|
||||
|
||||
This class is used to manage identities in Reticulum. It provides methods
|
||||
|
|
@ -360,8 +354,6 @@ Validates the signature of a signed message.
|
|||
* **Raises:**
|
||||
*KeyError* if the instance does not hold a public key.
|
||||
|
||||
<a id="api-destination"></a>
|
||||
|
||||
### *class* RNS.Destination(identity, direction, type, app_name, \*aspects)
|
||||
|
||||
A class used to describe endpoints in a Reticulum Network. Destination
|
||||
|
|
@ -584,8 +576,6 @@ unless other app_data is specified in the *announce* method.
|
|||
|
||||
Clears default app_data previously set for the destination.
|
||||
|
||||
<a id="api-packet"></a>
|
||||
|
||||
### *class* RNS.Packet(destination, data, create_receipt=True)
|
||||
|
||||
The Packet class is used to create packet instances that can be sent
|
||||
|
|
@ -645,8 +635,6 @@ Re-sends the packet.
|
|||
* **Returns:**
|
||||
The physical layer *Link Quality* if available, otherwise `None`.
|
||||
|
||||
<a id="api-packetreceipt"></a>
|
||||
|
||||
### *class* RNS.PacketReceipt
|
||||
|
||||
The PacketReceipt class is used to receive notifications about
|
||||
|
|
@ -685,8 +673,6 @@ Sets a function that gets called if the delivery times out.
|
|||
* **Parameters:**
|
||||
**callback** – A *callable* with the signature *callback(packet_receipt)*
|
||||
|
||||
<a id="api-link"></a>
|
||||
|
||||
### *class* RNS.Link(destination, established_callback=None, closed_callback=None)
|
||||
|
||||
This class is used to establish and manage links to other peers. When a
|
||||
|
|
@ -900,8 +886,6 @@ Sets the resource strategy for the link.
|
|||
* **Raises:**
|
||||
*TypeError* if the resource strategy is unsupported.
|
||||
|
||||
<a id="api-requestreceipt"></a>
|
||||
|
||||
### *class* RNS.RequestReceipt
|
||||
|
||||
An instance of this class is returned by the `request` method of `RNS.Link`
|
||||
|
|
@ -938,8 +922,6 @@ check status, response time and response data when the request concludes.
|
|||
* **Returns:**
|
||||
True if the associated request has concluded (successfully or with a failure), otherwise False.
|
||||
|
||||
<a id="api-resource"></a>
|
||||
|
||||
### *class* RNS.Resource(data, link, advertise=True, auto_compress=True, callback=None, progress_callback=None, timeout=None)
|
||||
|
||||
The Resource class allows transferring arbitrary amounts
|
||||
|
|
@ -998,8 +980,6 @@ Cancels transferring the resource.
|
|||
* **Returns:**
|
||||
Whether the resource is compressed.
|
||||
|
||||
<a id="api-channel"></a>
|
||||
|
||||
### *class* RNS.Channel.Channel
|
||||
|
||||
Provides reliable delivery of messages over
|
||||
|
|
@ -1084,8 +1064,6 @@ message header information.
|
|||
* **Returns:**
|
||||
number of bytes available
|
||||
|
||||
<a id="api-messsagebase"></a>
|
||||
|
||||
### *class* RNS.MessageBase
|
||||
|
||||
Base type for any messages sent or received on a Channel.
|
||||
|
|
@ -1113,8 +1091,6 @@ Populate message from binary representation
|
|||
* **Parameters:**
|
||||
**raw** – binary representation
|
||||
|
||||
<a id="api-buffer"></a>
|
||||
|
||||
### *class* RNS.Buffer
|
||||
|
||||
Static functions for creating buffered streams that send
|
||||
|
|
@ -1178,8 +1154,6 @@ of this object, see the Python documentation for
|
|||
* **Returns:**
|
||||
a BufferedRWPair object
|
||||
|
||||
<a id="api-rawchannelreader"></a>
|
||||
|
||||
### *class* RNS.RawChannelReader(stream_id: int, channel: [Channel](#RNS.Channel.Channel))
|
||||
|
||||
An implementation of RawIOBase that receives
|
||||
|
|
@ -1218,8 +1192,6 @@ Remove a function added with [`RNS.RawChannelReader.add_ready_callback()`](#RNS.
|
|||
* **Parameters:**
|
||||
**cb** – function to remove
|
||||
|
||||
<a id="api-rawchannelwriter"></a>
|
||||
|
||||
### *class* RNS.RawChannelWriter(stream_id: int, channel: [Channel](#RNS.Channel.Channel))
|
||||
|
||||
An implementation of RawIOBase that receives
|
||||
|
|
@ -1243,8 +1215,6 @@ Create a raw channel writer.
|
|||
* **stream_id** – remote stream id to sent do
|
||||
* **channel** – `Channel` object to send on
|
||||
|
||||
<a id="api-transport"></a>
|
||||
|
||||
### *class* RNS.Transport
|
||||
|
||||
Through static methods of this class you can interact with the
|
||||
|
|
@ -1320,4 +1290,4 @@ will announce it.
|
|||
|
||||
* **Parameters:**
|
||||
* **destination_hash** – A destination hash as *bytes*.
|
||||
* **on_interface** – If specified, the path request will only be sent on this interface. In normal use, Reticulum handles this automatically, and this parameter should not be used.
|
||||
* **on_interface** – If specified, the path request will only be sent on this interface. In normal use, Reticulum handles this automatically, and this parameter should not be used.
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="software-main"></a>
|
||||
|
||||
# Programs Using Reticulum
|
||||
|
||||
This chapter provides a non-exhaustive list of notable programs, systems and application-layer
|
||||
|
|
@ -36,8 +34,6 @@ In addition to the default, fully interactive terminal mode,
|
|||
for extremely limited links, `rnsh` offers line-interactive mode, allowing you to interact
|
||||
with remote systems, even when link throughput is counted in a few hundreds of bits per second.
|
||||
|
||||
\\newpage
|
||||
|
||||
### Nomad Network
|
||||
|
||||
The terminal-based program [Nomad Network](https://github.com/markqvist/nomadnet)
|
||||
|
|
@ -59,8 +55,6 @@ for the messaging and information-sharing protocol LXMF.
|
|||
|
||||
You can host the entirity of Wikipedia (or any `.zim`) file to other Nomad Network clients using [Retipedia](https://github.com/RFnexus/Retipedia).
|
||||
|
||||
\\newpage
|
||||
|
||||
### Sideband
|
||||
|
||||
If you would rather use an LXMF client with a graphical user interface, you can take
|
||||
|
|
@ -76,16 +70,12 @@ It also interoperates with all other LXMF clients, and provides advanced feature
|
|||
real-time voice calls, file attachments, private telemetry sharing, and a full
|
||||
plugin system for expandability.
|
||||
|
||||
\\newpage
|
||||
|
||||
### MeshChatX
|
||||
|
||||
A [Reticulum MeshChat fork from the future](https://git.quad4.io/RNS-Things/MeshChatX), with the goal of providing everything you need for Reticulum, LXMF, and LXST in one beautiful and feature-rich application. This project is separate from the original Reticulum MeshChat project, and is not affiliated with the original project.
|
||||
|
||||
Features include full LXST support, custom voicemail, phonebook, contact sharing, and ringtone support, multi-identity handling, modern UI/UX, offline documentation, expanded tools, page archiving, integrated maps, telemetry and improved application security.
|
||||
|
||||
\\newpage
|
||||
|
||||
### MeshChat
|
||||
|
||||
The [Reticulum MeshChat](https://github.com/liamcottle/reticulum-meshchat) application
|
||||
|
|
@ -104,8 +94,6 @@ While still in early and very active development, it is of course also compatibl
|
|||
with all other LXMF clients, and allows you to message seamlessly with anyone else
|
||||
using LXMF.
|
||||
|
||||
\\newpage
|
||||
|
||||
### Reticulum Relay Chat
|
||||
|
||||
[Reticulum Relay Chat](https://rrc.kc1awv.net/) is a live chat system built on top of the Reticulum Network Stack. It exists to let people talk to each other in real time over Reticulum without dragging in message databases, synchronization engines, or architectural commitments they did not ask for.
|
||||
|
|
@ -120,32 +108,24 @@ RRC is closer in spirit to IRC than to modern “everything platforms.” You co
|
|||
|
||||
RetiBBS allows users to communicate through message boards in a secure manner.
|
||||
|
||||
\\newpage
|
||||
|
||||
### RBrowser
|
||||
|
||||
The [rBrowser](https://github.com/fr33n0w/rBrowser) program is a cross-platform, standalone, web-based browser for exploring NomadNetwork Nodes over Reticulum Network. It automatically discovers NomadNet nodes through network announces and provides a user-friendly interface for browsing distributed content with Micron markup support.
|
||||
|
||||
Includes useful features like automatic listening for announce, adding nodes to favorites, browsing and rendering any kind of NomadNet links, downloading files from remote nodes, a unique local NomadNet Search Engine and more.
|
||||
|
||||
\\newpage
|
||||
|
||||
### Reticulum Network Telephone
|
||||
|
||||
The `rnphone` program, included as part of the [LXST](https://github.com/markqvist/LXST) package is a command-line Reticulum telephone utility and daemon, that allows building physical, hardware telephones for LXST and Reticulum, as well as simply performing calls via the command line.
|
||||
|
||||
It supports interfacing directly with hardware peripherals such as GPIO keypads and LCD displays, providing a modular system for building secure hardware telephones.
|
||||
|
||||
\\newpage
|
||||
|
||||
### LXST Phone
|
||||
|
||||
The [LXST Phone](https://github.com/kc1awv/lxst_phone) program is a cross-platform desktop application for performing LXST voice calls over Reticulum.
|
||||
|
||||
It supports various advanced features such as SAS verification, peer blocking, rate limiting, encrypted call history storage and contact management.
|
||||
|
||||
\\newpage
|
||||
|
||||
### LXMFy
|
||||
|
||||
[LXMFy](https://lxmfy.quad4.io/) is a comprehensive and advanced bot creation framework for LXMF, that allows building any kind of automation or bot system running over LXMF and Reticulum. [Bot implementations exist](https://github.com/lxmfy/awesome-lxmfy-bots) for Home Assistant control, LLM integrations, and various other purposes.
|
||||
|
|
@ -166,8 +146,6 @@ The [RNS FileSync](https://git.quad4.io/RNS-Things/RNS-Filesync) program enables
|
|||
|
||||
[RNMon](https://github.com/lbatalha/rnmon) is a monitoring daemon designed to monitor the status of multiple RNS applications and push the metrics to an InfluxDB instance over the influx line protocol.
|
||||
|
||||
\\newpage
|
||||
|
||||
## Protocols
|
||||
|
||||
A number of standard protocols have emerged through real-world usage and testing in the Reticulum community. While you may sometimes want to use completely custom protocols and implementations when writing Reticulum-based software, using these protocols provides application developers with an easy way to implement advanced functionality quickly and effortlessly. Using them also ensures compatibility and interoperability between many different client applications, creating an open communications ecosystem where users are free to choose the applications that suit their needs, while remaining connected to everyone else.
|
||||
|
|
@ -198,4 +176,4 @@ This section provides a list of various community-provided interface modules, gu
|
|||
* Guide for running [Reticulum over ICMP](https://github.com/matvik22000/rns-over-icmp) using `PipeInterface`
|
||||
* Guide for running [Reticulum over DNS](https://github.com/markqvist/Reticulum/discussions/1002) with Iodine
|
||||
* Guide for running [Reticulum over HF radio](https://github.com/RFnexus/reticulum-over-hf)
|
||||
* [Modem73](https://github.com/RFnexus/modem73) is a KISS TNC OFDM modem frontend that can be used with Reticulum
|
||||
* [Modem73](https://github.com/RFnexus/modem73) is a KISS TNC OFDM modem frontend that can be used with Reticulum
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="support-main"></a>
|
||||
|
||||
# Support Reticulum
|
||||
|
||||
You can help support the continued development of open, free and private communications
|
||||
|
|
@ -54,4 +52,4 @@ of view. Everything else will be ignored.
|
|||
|
||||
Absolutely no automated analytics, telemetry, error
|
||||
reporting or statistics is collected and reported by Reticulum under any
|
||||
circumstances, so we rely on old-fashioned human feedback.
|
||||
circumstances, so we rely on old-fashioned human feedback.
|
||||
|
|
@ -1,4 +1,168 @@
|
|||
<a id="understanding-destinationnaming"></a>
|
||||
# Understanding Reticulum
|
||||
|
||||
This chapter will briefly describe the overall purpose and operating principles of Reticulum.
|
||||
It should give you an overview of how the stack works, and an understanding of how to
|
||||
develop networked applications using Reticulum.
|
||||
|
||||
This chapter is not an exhaustive source of information on Reticulum, at least not yet. Currently,
|
||||
the only complete repository, and final authority on how Reticulum actually functions, is the Python
|
||||
reference implementation and API reference. That being said, this chapter is an essential resource in
|
||||
understanding how Reticulum works from a high-level perspective, along with the general principles of
|
||||
Reticulum, and how to apply them when creating your own networks or software.
|
||||
|
||||
After reading this chapter, you should be well-equipped to understand how a Reticulum network
|
||||
operates, what it can achieve, and how you can use it yourself. This chapter also seeks to provide an overview of the
|
||||
sentiments and the philosophy behind Reticulum, what problems it seeks to solve, and how it
|
||||
approaches those solutions.
|
||||
|
||||
## Motivation
|
||||
|
||||
The primary motivation for designing and implementing Reticulum has been the current lack of
|
||||
reliable, functional and secure minimal-infrastructure modes of digital communication. It is my
|
||||
belief that it is highly desirable to create a reliable and efficient way to set up long-range digital
|
||||
communication networks that can securely allow exchange of information between people and
|
||||
machines, with no central point of authority, control, censorship or barrier to entry.
|
||||
|
||||
Almost all of the various networking systems in use today share a common limitation: They
|
||||
require large amounts of coordination and centralised trust and power to function. To join such networks, you need approval
|
||||
of gatekeepers in control. This need for coordination and trust inevitably leads to an environment of
|
||||
central control, where it’s very easy for infrastructure operators or governments to control or alter
|
||||
traffic, and censor or persecute unwanted actors. It also makes it completely impossible to freely deploy
|
||||
and use networks at will, like one would use other common tools that enhance individual agency and freedom.
|
||||
|
||||
Reticulum aims to require as little coordination and trust as possible. It aims to make secure,
|
||||
anonymous and permissionless networking and information exchange a tool that anyone can just pick up and use.
|
||||
|
||||
Since Reticulum is completely medium agnostic, it can be used to build networks on whatever is best
|
||||
suited to the situation, or whatever you have available. In some cases, this might be packet radio
|
||||
links over VHF frequencies, in other cases it might be a 2.4 GHz
|
||||
network using off-the-shelf radios, or it might be using common LoRa development boards.
|
||||
|
||||
At the time of release of this document, the fastest and easiest setup for development and testing is using
|
||||
LoRa radio modules with an open source firmware (see the section [Reference Setup](#understanding-referencesystem)),
|
||||
connected to any kind of computer or mobile device that Reticulum can run on.
|
||||
|
||||
The ultimate aim of Reticulum is to allow anyone to be their own network operator, and to make it
|
||||
cheap and easy to cover vast areas with a myriad of independent, interconnectable and autonomous networks.
|
||||
Reticulum **is not** *one network*, it **is a tool** to build *thousands of networks*. Networks without
|
||||
kill-switches, surveillance, censorship and control. Networks that can freely interoperate, associate and disassociate
|
||||
with each other, and require no central oversight. Networks for human beings. *Networks for the people*.
|
||||
|
||||
## Goals
|
||||
|
||||
To be as widely usable and efficient to deploy as possible, the following goals have been used to
|
||||
guide the design of Reticulum:
|
||||
|
||||
* **Fully useable as open source software stack**
|
||||
: Reticulum must be implemented with, and be able to run using only open source software. This is
|
||||
critical to ensuring the availability, security and transparency of the system.
|
||||
* **Hardware layer agnosticism**
|
||||
: Reticulum must be fully hardware agnostic, and shall be useable over a wide range of
|
||||
physical networking layers, such as data radios, serial lines, modems, handheld transceivers,
|
||||
wired Ethernet, WiFi, or anything else that can carry a digital data stream. Hardware made for
|
||||
dedicated Reticulum use shall be as cheap as possible and use off-the-shelf components, so
|
||||
it can be easily modified and replicated by anyone interested in doing so.
|
||||
* **Very low bandwidth requirements**
|
||||
: Reticulum should be able to function reliably over links with a transmission capacity as low
|
||||
as *5 bits per second*.
|
||||
* **Encryption by default**
|
||||
: Reticulum must use strong encryption by default for all communication.
|
||||
* **Initiator Anonymity**
|
||||
: It must be possible to communicate over a Reticulum network without revealing any identifying
|
||||
information about oneself.
|
||||
* **Unlicensed use**
|
||||
: Reticulum shall be functional over physical communication mediums that do not require any
|
||||
form of license to use. Reticulum must be designed in a way, so it is usable over ISM radio
|
||||
frequency bands, and can provide functional long distance links in such conditions, for example
|
||||
by connecting a modem to a PMR or CB radio, or by using LoRa or WiFi modules.
|
||||
* **Supplied software**
|
||||
: In addition to the core networking stack and API, that allows a developer to build
|
||||
applications with Reticulum, a basic set of Reticulum-based communication tools must be
|
||||
implemented and released along with Reticulum itself. These shall serve both as a
|
||||
functional, basic communication suite, and as an example and learning resource to others wishing
|
||||
to build applications with Reticulum.
|
||||
* **Ease of use**
|
||||
: The reference implementation of Reticulum is written in Python, to make it easy to use
|
||||
and understand. A programmer with only basic experience should be able to use
|
||||
Reticulum to write networked applications.
|
||||
* **Low cost**
|
||||
: It shall be as cheap as possible to deploy a communication system based on Reticulum. This
|
||||
should be achieved by using cheap off-the-shelf hardware that potential users might already
|
||||
own. The cost of setting up a functioning node should be less than $100 even if all parts
|
||||
needs to be purchased.
|
||||
|
||||
## Introduction & Basic Functionality
|
||||
|
||||
Reticulum is a networking stack suited for high-latency, low-bandwidth links. Reticulum is at its
|
||||
core a *message oriented* system. It is suited for both local point-to-point or point-to-multipoint
|
||||
scenarios where all nodes are within range of each other, as well as scenarios where packets need
|
||||
to be transported over multiple hops in a complex network to reach the recipient.
|
||||
|
||||
Reticulum does away with the idea of addresses and ports known from IP, TCP and UDP. Instead
|
||||
Reticulum uses the singular concept of *destinations*. Any application using Reticulum as its
|
||||
networking stack will need to create one or more destinations to receive data, and know the
|
||||
destinations it needs to send data to.
|
||||
|
||||
All destinations in Reticulum are *represented* as a 16 byte hash. This hash is derived from truncating a full
|
||||
SHA-256 hash of identifying characteristics of the destination. To users, the destination addresses
|
||||
will be displayed as 16 hexadecimal bytes, like this example: `<13425ec15b621c1d928589718000d814>`.
|
||||
|
||||
The truncation size of 16 bytes (128 bits) for destinations has been chosen as a reasonable trade-off
|
||||
between address space
|
||||
and packet overhead. The address space accommodated by this size can support many billions of
|
||||
simultaneously active devices on the same network, while keeping packet overhead low, which is
|
||||
essential on low-bandwidth networks. In the very unlikely case that this address space nears
|
||||
congestion, a one-line code change can upgrade the Reticulum address space all the way up to 256
|
||||
bits, ensuring the Reticulum address space could potentially support galactic-scale networks.
|
||||
This is obviously complete and ridiculous over-allocation, and as such, the current 128 bits should
|
||||
be sufficient, even far into the future.
|
||||
|
||||
By default Reticulum encrypts all data using elliptic curve cryptography and AES. Any packet sent to a
|
||||
destination is encrypted with a per-packet derived key. Reticulum can also set up an encrypted
|
||||
channel to a destination, called a *Link*. Both data sent over Links and single packets offer
|
||||
*Initiator Anonymity*. Links additionally offer *Forward Secrecy* by default, employing an Elliptic Curve
|
||||
Diffie Hellman key exchange on Curve25519 to derive per-link ephemeral keys. Asymmetric, link-less
|
||||
packet communication can also provide forward secrecy, with automatic key ratcheting, by enabling
|
||||
ratchets on a per-destination basis. The multi-hop transport, coordination, verification and reliability
|
||||
layers are fully autonomous and also based on elliptic curve cryptography.
|
||||
|
||||
Reticulum also offers symmetric key encryption for group-oriented communications, as well as
|
||||
unencrypted packets (for local broadcast purposes **only**).
|
||||
|
||||
Reticulum can connect to a variety of interfaces such as radio modems, data radios and serial ports,
|
||||
and offers the possibility to easily tunnel Reticulum traffic over IP links such as the Internet or
|
||||
private IP networks.
|
||||
|
||||
### Destinations
|
||||
|
||||
To receive and send data with the Reticulum stack, an application needs to create one or more
|
||||
destinations. Reticulum uses three different basic destination types, and one special:
|
||||
|
||||
* **Single**
|
||||
: The *single* destination type is the most common type in Reticulum, and should be used for
|
||||
most purposes. It is always identified by a unique public key. Any data sent to this
|
||||
destination will be encrypted using ephemeral keys derived from an ECDH key exchange, and will
|
||||
only be readable by the creator of the destination, who holds the corresponding private key.
|
||||
* **Plain**
|
||||
: A *plain* destination type is unencrypted, and suited for traffic that should be broadcast to a
|
||||
number of users, or should be readable by anyone. Traffic to a *plain* destination is not encrypted.
|
||||
Generally, *plain* destinations can be used for broadcast information intended to be public.
|
||||
Plain destinations are only reachable directly, and packets addressed to plain destinations are
|
||||
never transported over multiple hops in the network. To be transportable over multiple hops in Reticulum, information
|
||||
*must* be encrypted, since Reticulum uses the per-packet encryption to verify routing paths and
|
||||
keep them alive.
|
||||
* **Group**
|
||||
: The *group* special destination type, that defines a symmetrically encrypted virtual destination.
|
||||
Data sent to this destination will be encrypted with a symmetric key, and will be readable by
|
||||
anyone in possession of the key, but as with the *plain* destination type, packets to this type
|
||||
of destination are not currently transported over multiple hops, although a planned upgrade
|
||||
to Reticulum will allow globally reachable *group* destinations.
|
||||
* **Link**
|
||||
: A *link* is a special destination type, that serves as an abstract channel to a *single*
|
||||
destination, directly connected or over multiple hops. The *link* also offers reliability and
|
||||
more efficient encryption, forward secrecy, initiator anonymity, and as such can be useful even
|
||||
when a node is directly reachable. It also offers a more capable API and allows easily carrying
|
||||
out requests and responses, large data transfers and more.
|
||||
|
||||
#### Destination Naming
|
||||
|
||||
|
|
@ -26,3 +190,711 @@ destination aspect before hashing. This is done to ensure only the correct desti
|
|||
since anyone can listen to any destination name. Appending the public key ensures that a given
|
||||
packet is only directed at the destination that holds the corresponding private key to decrypt the
|
||||
packet.
|
||||
|
||||
**Take note!** There is a very important concept to understand here:
|
||||
|
||||
* Anyone can use the destination name `environmentlogger.remotesensor.temperature`
|
||||
* Each destination that does so will still have a unique destination hash, and thus be uniquely
|
||||
addressable, because their public keys will differ.
|
||||
|
||||
In actual use of *single* destination naming, it is advisable not to use any uniquely identifying
|
||||
features in aspect naming. Aspect names should be general terms describing what kind of destination
|
||||
is represented. The uniquely identifying aspect is always achieved by appending the public key,
|
||||
which expands the destination into a uniquely identifiable one. Reticulum does this automatically.
|
||||
|
||||
Any destination on a Reticulum network can be addressed and reached simply by knowing its
|
||||
destination hash (and public key, but if the public key is not known, it can be requested from the
|
||||
network simply by knowing the destination hash). The use of app names and aspects makes it easy to
|
||||
structure Reticulum programs and makes it possible to filter what information and data your program
|
||||
receives.
|
||||
|
||||
To recap, the different destination types should be used in the following situations:
|
||||
|
||||
* **Single**
|
||||
: When private communication between two endpoints is needed. Supports multiple hops.
|
||||
* **Group**
|
||||
: When private communication between two or more endpoints is needed. Supports multiple hops
|
||||
indirectly, but must first be established through a *single* destination.
|
||||
* **Plain**
|
||||
: When plain-text communication is desirable, for example when broadcasting information, or for local discovery purposes.
|
||||
|
||||
To communicate with a *single* destination, you need to know its public key. Any method for
|
||||
obtaining the public key is valid, but Reticulum includes a simple mechanism for making other
|
||||
nodes aware of your destinations public key, called the *announce*. It is also possible to request
|
||||
an unknown public key from the network, as all transport instances serve as a distributed ledger
|
||||
of public keys.
|
||||
|
||||
Note that public key information can be shared and verified in other ways than using the
|
||||
built-in *announce* functionality, and that it is therefore not required to use the *announce* and *path request*
|
||||
functionality to obtain public keys. It is by far the easiest though, and should definitely be used
|
||||
if there is not a very good reason for doing it differently.
|
||||
|
||||
### Public Key Announcements
|
||||
|
||||
An *announce* will send a special packet over any relevant interfaces, containing all needed
|
||||
information about the destination hash and public key, and can also contain some additional,
|
||||
application specific data. The entire packet is signed by the sender to ensure authenticity. It is not
|
||||
required to use the announce functionality, but in many cases it will be the simplest way to share
|
||||
public keys on the network. The announce mechanism also serves to establish end-to-end connectivity
|
||||
to the announced destination, as the announce propagates through the network.
|
||||
|
||||
As an example, an announce in a simple messenger application might contain the following information:
|
||||
|
||||
* The announcers destination hash
|
||||
* The announcers public key
|
||||
* Application specific data, in this case the users nickname and availability status
|
||||
* A random blob, making each new announce unique
|
||||
* An Ed25519 signature of the above information, verifying authenticity
|
||||
|
||||
With this information, any Reticulum node that receives it will be able to reconstruct an outgoing
|
||||
destination to securely communicate with that destination. You might have noticed that there is one
|
||||
piece of information lacking to reconstruct full knowledge of the announced destination, and that is
|
||||
the aspect names of the destination. These are intentionally left out to save bandwidth, since they
|
||||
will be implicit in almost all cases. The receiving application will already know them. If a destination
|
||||
name is not entirely implicit, information can be included in the application specific data part that
|
||||
will allow the receiver to infer the naming.
|
||||
|
||||
It is important to note that announces will be forwarded throughout the network according to a
|
||||
certain pattern. This will be detailed in the section
|
||||
[The Announce Mechanism in Detail](#understanding-announce).
|
||||
|
||||
In Reticulum, destinations are allowed to move around the network at will. This is very different from
|
||||
protocols such as IP, where an address is always expected to stay within the network segment it was assigned in.
|
||||
This limitation does not exist in Reticulum, and any destination is *completely portable* over the entire topography
|
||||
of the network, and *can even be moved to other Reticulum networks* than the one it was created in, and
|
||||
still become reachable. To update its reachability, a destination simply needs to send an announce on any
|
||||
networks it is part of. After a short while, it will be globally reachable in the network.
|
||||
|
||||
Seeing how *single* destinations are always tied to a private/public key pair leads us to the next topic.
|
||||
|
||||
### Identities
|
||||
|
||||
In Reticulum, an *identity* does not necessarily represent a personal identity, but is an abstraction that
|
||||
can represent any kind of *verifiable entity*. This could very well be a person, but it could also be the
|
||||
control interface of a machine, a program, robot, computer, sensor or something else entirely. In
|
||||
general, any kind of agent that can act, or be acted upon, or store or manipulate information, can be
|
||||
represented as an identity. An *identity* can be used to create any number of destinations.
|
||||
|
||||
A *single* destination will always have an *identity* tied to it, but not *plain* or *group*
|
||||
destinations. Destinations and identities share a multilateral connection. You can create a
|
||||
destination, and if it is not connected to an identity upon creation, it will just create a new one to use
|
||||
automatically. This may be desirable in some situations, but often you will probably want to create
|
||||
the identity first, and then use it to create new destinations.
|
||||
|
||||
As an example, we could use an identity to represent the user of a messaging application.
|
||||
Destinations can then be created by this identity to allow communication to reach the user.
|
||||
In all cases it is of great importance to store the private keys associated with any
|
||||
Reticulum Identity securely and privately, since obtaining access to the identity keys equals
|
||||
obtaining access and controlling reachability to any destinations created by that identity.
|
||||
|
||||
### Getting Further
|
||||
|
||||
The above functions and principles form the core of Reticulum, and would suffice to create
|
||||
functional networked applications in local clusters, for example over radio links where all interested
|
||||
nodes can directly hear each other. But to be truly useful, we need a way to direct traffic over multiple
|
||||
hops in the network.
|
||||
|
||||
In the following sections, two concepts that allow this will be introduced, *paths* and *links*.
|
||||
|
||||
## Reticulum Transport
|
||||
|
||||
The methods of routing used in traditional networks are fundamentally incompatible with the physical medium
|
||||
types and circumstances that Reticulum was designed to handle. These mechanisms mostly assume trust at the physical layer,
|
||||
and often needs a lot more bandwidth than Reticulum can assume is available. Since Reticulum is designed to
|
||||
survive running over open radio spectrum, no such trust can be assumed, and bandwidth is often very limited.
|
||||
|
||||
To overcome such challenges, Reticulum’s *Transport* system uses asymmetric elliptic curve cryptography to
|
||||
implement the concept of *paths* that allow discovery of how to get information closer to a certain
|
||||
destination. It is important to note that no single node in a Reticulum network knows the complete
|
||||
path to a destination. Every Transport node participating in a Reticulum network will only
|
||||
know the most direct way to get a packet one hop closer to it’s destination.
|
||||
|
||||
### Node Types
|
||||
|
||||
Currently, Reticulum distinguishes between two types of network nodes. All nodes on a Reticulum network
|
||||
are *Reticulum Instances*, and some are also *Transport Nodes*. If a system running Reticulum is fixed in
|
||||
one place, and is intended to be kept available most of the time, it is a good contender to be a *Transport Node*.
|
||||
|
||||
Any Reticulum Instance can become a Transport Node by enabling it in the configuration.
|
||||
This distinction is made by the user configuring the node, and is used to determine what nodes on the
|
||||
network will help forward traffic, and what nodes rely on other nodes for wider connectivity.
|
||||
|
||||
If a node is an *Instance* it should be given the configuration directive `enable_transport = No`, which
|
||||
is the default setting.
|
||||
|
||||
If it is a *Transport Node*, it should be given the configuration directive `enable_transport = Yes`.
|
||||
|
||||
### The Announce Mechanism in Detail
|
||||
|
||||
When an *announce* for a destination is transmitted by a Reticulum instance, it will be forwarded by
|
||||
any transport node receiving it, but according to some specific rules:
|
||||
|
||||
* If this exact announce has already been received before, ignore it.
|
||||
<br/>
|
||||
* If not, record into a table which Transport Node the announce was received from, and how many times in
|
||||
total it has been retransmitted to get here.
|
||||
<br/>
|
||||
* If the announce has been retransmitted *m+1* times, it will not be forwarded any more. By default, *m* is
|
||||
set to 128.
|
||||
<br/>
|
||||
* After a randomised delay, the announce will be retransmitted on all interfaces that have bandwidth
|
||||
available for processing announces. By default, the maximum bandwidth allocation for processing
|
||||
announces is set at 2%, but can be configured on a per-interface basis.
|
||||
<br/>
|
||||
* If any given interface does not have enough bandwidth available for retransmitting the announce,
|
||||
the announce will be assigned a priority inversely proportional to its hop count, and be inserted
|
||||
into a queue managed by the interface.
|
||||
<br/>
|
||||
* When the interface has bandwidth available for processing an announce, it will prioritise announces
|
||||
for destinations that are closest in terms of hops, thus prioritising reachability and connectivity
|
||||
of local nodes, even on slow networks that connect to wider and faster networks.
|
||||
<br/>
|
||||
* After the announce has been re-transmitted, and if no other nodes are heard retransmitting the announce
|
||||
with a greater hop count than when it left this node, transmitting it will be retried *r* times. By default,
|
||||
*r* is set to 1.
|
||||
<br/>
|
||||
* If a newer announce from the same destination arrives, while an identical one is already waiting
|
||||
to be transmitted, the newest announce is discarded. If the newest announce contains different
|
||||
application specific data, it will replace the old announce.
|
||||
<br/>
|
||||
|
||||
Once an announce has reached a transport node in the network, any other node in direct contact with that
|
||||
transport node will be able to reach the destination the announce originated from, simply by sending a packet
|
||||
addressed to that destination. Any transport node with knowledge of the announce will be able to direct the
|
||||
packet towards the destination by looking up the most efficient next node to the destination.
|
||||
|
||||
According to these rules, an announce will propagate throughout the network in a predictable way,
|
||||
and make the announced destination reachable in a short amount of time. Fast networks that have the
|
||||
capacity to process many announces can reach full convergence very quickly, even when constantly adding
|
||||
new destinations. Slower segments of such networks might take a bit longer to gain full knowledge about
|
||||
the wide and fast networks they are connected to, but can still do so over time, while prioritising full
|
||||
and quickly converging end-to-end connectivity for their local, slower segments.
|
||||
|
||||
In general, even extremely complex networks, that utilize the maximum 128 hops will converge to full
|
||||
end-to-end connectivity in about one minute, given there is enough bandwidth available to process
|
||||
the required amount of announces.
|
||||
|
||||
### Reaching the Destination
|
||||
|
||||
In networks with changing topology and trustless connectivity, nodes need a way to establish
|
||||
*verified connectivity* with each other. Since the underlying network mediums are assumed to be trustless, Reticulum
|
||||
must provide a way to guarantee that the peer you are communicating with is actually who you
|
||||
expect. Reticulum offers two ways to do this.
|
||||
|
||||
For exchanges of small amounts of information, Reticulum offers the *Packet* API, which works exactly like you would expect - on a per packet level. The following process is employed when sending a packet:
|
||||
|
||||
* A packet is always created with an associated destination and some payload data. When the packet is sent
|
||||
to a *single* destination type, Reticulum will automatically create an ephemeral encryption key, perform
|
||||
an ECDH key exchange with the destination’s public key (or ratchet key, if available), and encrypt the information.
|
||||
<br/>
|
||||
* It is important to note that this key exchange does not require any network traffic. The sender already
|
||||
knows the public key of the destination from an earlier received announce, and can thus perform the ECDH
|
||||
key exchange locally, before sending the packet.
|
||||
<br/>
|
||||
* The public part of the newly generated ephemeral key-pair is included with the encrypted token, and sent
|
||||
along with the encrypted payload data in the packet.
|
||||
<br/>
|
||||
* When the destination receives the packet, it can itself perform an ECDH key exchange and decrypt the
|
||||
packet.
|
||||
<br/>
|
||||
* A new ephemeral key is used for every packet sent in this way.
|
||||
<br/>
|
||||
* Once the packet has been received and decrypted by the addressed destination, that destination can opt
|
||||
to *prove* its receipt of the packet. It does this by calculating the SHA-256 hash of the received packet,
|
||||
and signing this hash with its Ed25519 signing key. Transport nodes in the network can then direct this
|
||||
*proof* back to the packets origin, where the signature can be verified against the destination’s known
|
||||
public signing key.
|
||||
<br/>
|
||||
* In case the packet is addressed to a *group* destination type, the packet will be encrypted with the
|
||||
pre-shared AES-256 key associated with the destination. In case the packet is addressed to a *plain*
|
||||
destination type, the payload data will not be encrypted. Neither of these two destination types can offer
|
||||
forward secrecy. In general, it is recommended to always use the *single* destination type, unless it is
|
||||
strictly necessary to use one of the others.
|
||||
<br/>
|
||||
|
||||
For exchanges of larger amounts of data, or when longer sessions of bidirectional communication is desired, Reticulum offers the *Link* API. To establish a *link*, the following process is employed:
|
||||
|
||||
* First, the node that wishes to establish a link will send out a *link request* packet, that
|
||||
traverses the network and locates the desired destination. Along the way, the Transport Nodes that
|
||||
forward the packet will take note of this *link request*, and mark it as pending.
|
||||
<br/>
|
||||
* Second, if the destination accepts the *link request* , it will send back a packet that proves the
|
||||
authenticity of its identity (and the receipt of the link request) to the initiating node. All
|
||||
nodes that initially forwarded the packet will also be able to verify this proof, and thus
|
||||
accept the validity of the *link* throughout the network. The link is now marked as *established*.
|
||||
<br/>
|
||||
* When the validity of the *link* has been accepted by forwarding nodes, these nodes will
|
||||
remember the *link* , and it can subsequently be used by referring to a hash representing it.
|
||||
<br/>
|
||||
* As a part of the *link request*, an Elliptic Curve Diffie-Hellman key exchange takes place, that sets up an
|
||||
efficiently encrypted tunnel between the two nodes. As such, this mode of communication is preferred,
|
||||
even for situations when nodes can directly communicate, when the amount of data to be exchanged numbers
|
||||
in the tens of packets, or whenever the use of the more advanced API functions is desired.
|
||||
<br/>
|
||||
* When a *link* has been set up, it automatically provides message receipt functionality, through
|
||||
the same *proof* mechanism discussed before, so the sending node can obtain verified confirmation
|
||||
that the information reached the intended recipient.
|
||||
<br/>
|
||||
* Once the *link* has been set up, the initiator can remain anonymous, or choose to authenticate towards
|
||||
the destination using a Reticulum Identity. This authentication is happening inside the encrypted
|
||||
link, and is only revealed to the verified destination, and no intermediaries.
|
||||
<br/>
|
||||
|
||||
In a moment, we will discuss the details of how this methodology is
|
||||
implemented, but let’s first recap what purposes this methodology serves. We
|
||||
first ensure that the node answering our request is actually the one we want to
|
||||
communicate with, and not a malicious actor pretending to be so. At the same
|
||||
time we establish an efficient encrypted channel. The setup of this is
|
||||
relatively cheap in terms of bandwidth, so it can be used just for a short
|
||||
exchange, and then recreated as needed, which will also rotate encryption keys.
|
||||
The link can also be kept alive for longer periods of time, if this is more
|
||||
suitable to the application. The procedure also inserts the *link id* , a hash
|
||||
calculated from the link request packet, into the memory of forwarding nodes,
|
||||
which means that the communicating nodes can thereafter reach each other simply
|
||||
by referring to this *link id*.
|
||||
|
||||
The combined bandwidth cost of setting up a link is 3 packets totalling 297 bytes (more info in the
|
||||
[Binary Packet Format](#understanding-packetformat) section). The amount of bandwidth used on keeping
|
||||
a link open is practically negligible, at 0.45 bits per second. Even on a slow 1200 bits per second packet
|
||||
radio channel, 100 concurrent links will still leave 96% channel capacity for actual data.
|
||||
|
||||
#### Link Establishment in Detail
|
||||
|
||||
After exploring the basics of the announce mechanism, finding a path through the network, and an overview
|
||||
of the link establishment procedure, this section will go into greater detail about the Reticulum link
|
||||
establishment process.
|
||||
|
||||
The *link* in Reticulum terminology should not be viewed as a direct node-to-node link on the
|
||||
physical layer, but as an abstract channel, that can be open for any amount of time, and can span
|
||||
an arbitrary number of hops, where information will be exchanged between two nodes.
|
||||
|
||||
* When a node in the network wants to establish verified connectivity with another node, it
|
||||
will randomly generate a new X25519 private/public key pair. It then creates a *link request*
|
||||
packet, and broadcast it.
|
||||
<br/>
|
||||
<br/>
|
||||
*It should be noted that the X25519 public/private keypair mentioned above is two separate keypairs:
|
||||
An encryption key pair, used for derivation of a shared symmetric key, and a signing key pair, used
|
||||
for signing and verifying messages on the link. They are sent together over the wire, and can be
|
||||
considered as single public key for simplicity in this explanation.*
|
||||
<br/>
|
||||
* The *link request* is addressed to the destination hash of the desired destination, and
|
||||
contains the following data: The newly generated X25519 public key *LKi*.
|
||||
<br/>
|
||||
* The broadcasted packet will be directed through the network according to the rules laid out
|
||||
previously.
|
||||
<br/>
|
||||
* Any node that forwards the link request will store a *link id* in it’s *link table* , along with the
|
||||
amount of hops the packet had taken when received. The link id is a hash of the entire link
|
||||
request packet. If the link request packet is not *proven* by the addressed destination within some
|
||||
set amount of time, the entry will be dropped from the *link table* again.
|
||||
<br/>
|
||||
* When the destination receives the link request packet, it will decide whether to accept the request.
|
||||
If it is accepted, the destination will also generate a new X25519 private/public key pair, and
|
||||
perform a Diffie Hellman Key Exchange, deriving a new symmetric key that will be used to encrypt the
|
||||
channel, once it has been established.
|
||||
<br/>
|
||||
* A *link proof* packet is now constructed and transmitted over the network. This packet is
|
||||
addressed to the *link id* of the *link*. It contains the following data: The newly generated X25519
|
||||
public key *LKr* and an Ed25519 signature of the *link id* and *LKr* made by the *original signing key* of
|
||||
the addressed destination.
|
||||
<br/>
|
||||
* By verifying this *link proof* packet, all nodes that originally transported the *link request*
|
||||
packet to the destination from the originator can now verify that the intended destination received
|
||||
the request and accepted it, and that the path they chose for forwarding the request was valid.
|
||||
In successfully carrying out this verification, the transporting nodes marks the link as active.
|
||||
An abstract bi-directional communication channel has now been established along a path in the network.
|
||||
Packets can now be exchanged bi-directionally from either end of the link simply by adressing the
|
||||
packets to the *link id* of the link.
|
||||
<br/>
|
||||
* When the source receives the *proof* , it will know unequivocally that a verified path has been
|
||||
established to the destination. It can now also use the X25519 public key contained in the
|
||||
*link proof* to perform it’s own Diffie Hellman Key Exchange and derive the symmetric key
|
||||
that is used to encrypt the channel. Information can now be exchanged reliably and securely.
|
||||
<br/>
|
||||
|
||||
#### NOTE
|
||||
It’s important to note that this methodology ensures that the source of the request does not need to
|
||||
reveal any identifying information about itself. **The link initiator remains completely anonymous**.
|
||||
|
||||
When using *links*, Reticulum will automatically verify all data sent over the link, and can also
|
||||
automate retransmissions if *Resources* are used.
|
||||
|
||||
### Resources
|
||||
|
||||
For exchanging small amounts of data over a Reticulum network, the [Packet](reference.md#api-packet) interface
|
||||
is sufficient, but for exchanging data that would require many packets, an efficient way to coordinate
|
||||
the transfer is needed.
|
||||
|
||||
This is the purpose of the Reticulum [Resource](reference.md#api-resource). A *Resource* can automatically
|
||||
handle the reliable transfer of an arbitrary amount of data over an established [Link](reference.md#api-link).
|
||||
Resources can auto-compress data, will handle breaking the data into individual packets, sequencing
|
||||
the transfer, integrity verification and reassembling the data on the other end.
|
||||
|
||||
[Resources](reference.md#api-resource) are programmatically very simple to use, and only requires a few lines
|
||||
of codes to reliably transfer any amount of data. They can be used to transfer data stored in memory,
|
||||
or stream data directly from files.
|
||||
|
||||
## Network Identities
|
||||
|
||||
In Reticulum, every peer and application utilizes a cryptographic **Identity** to verify authenticity and establish encrypted channels. While standard identities are typically used to represent a single user, device, or service, Reticulum introduces the concept of a **Network Identity** to represent a logical group of nodes or an entire community infrastructure.
|
||||
|
||||
A Network Identity is, at its core, a standard Reticulum Identity keyset. However, its purpose and usage differ from a personal identity. Instead of identifying a single entity, a Network Identity acts as a shared credential that federates multiple independent Transport Instances under a single, verifiable administrative domain.
|
||||
|
||||
### Conceptual Overview
|
||||
|
||||
You can think of a standard Reticulum Identity as a self-sovereign, privately created passport for a single person. A Network Identity, conversely, is akin to a cryptographic flag, or a charter that flies over a fleet of ships. It signifies that while the ships may operate independently and be physically distant, they belong to the same organization, follow the same protocols, and are expected to act in concert.
|
||||
|
||||
When you configure a Network Identity on one or more of your nodes, you are effectively declaring that these nodes constitute a specific “network” within a broader Reticulum mesh. This allows other peers to recognize interfaces not just as “a node named Alice”, but as “a gateway belonging to The Eastern Ret Of Freedom”.
|
||||
|
||||
### Current Usage
|
||||
|
||||
At present, the primary function of a Network Identity is within the [Interface Discovery](using.md#using-interface-discovery) system.
|
||||
|
||||
When a Transport Instance broadcasts a discovery announce for an interface, it can optionally sign that announce with a Network Identity, instead of just its local transport identity. Remote peers receiving the announce can then verify the signature. This provides functionality for two important distinctions:
|
||||
|
||||
1. **Authenticity:** It proves that the interface was published by an operator who possesses the private key for that Network Identity.
|
||||
2. **Trust Boundaries:** It allows users to configure their systems to only accept and connect to interfaces that belong to specific Network Identities, effectively creating “whitelisted” zones of trusted infrastructure.
|
||||
|
||||
#### NOTE
|
||||
If you enable encryption on your discovery announces, the Network Identity is used as the shared secret. Only peers who have been explicitly provided with the Network Identity’s full keyset (and have it configured locally) will be able to decrypt and utilize the connection details.
|
||||
|
||||
This functionality will be expanded in the future, so that peers with delegated keys can be allowed to decrypt discovery announces without holding the root network key. Currently, the functionality is sufficient for sharing interface information privately where you control all nodes that must decrypt the discovered interfaces.
|
||||
|
||||
### Future Implications
|
||||
|
||||
While the current implementation focuses on interface discovery, the concept of Network Identities serves as the foundational building block for future Reticulum features designed to support large-scale, organic mesh formation.
|
||||
|
||||
As the ecosystem evolves, Network Identities will facilitate:
|
||||
|
||||
* **Distributed Name Resolution:** A system where networks can publish name-to-identity mappings, allowing human-readable names to resolve without centralized servers.
|
||||
* **Service Publishing:** Networks will be able to announce specific capabilities, services, or information endpoints available publicly or to their members.
|
||||
* **Inter-Network Federation:** Trust relationships between different networks, allowing for seamless but managed flow of traffic and information across distinct administrative boundaries.
|
||||
* **Distributed Blackhole Management:** A reputation-based system for blackhole list distribution, where trusted Network Identities can sign and publish lists of blackholed identities. This allows communities to collaboratively enforce security standards and filter spam or malicious identities across the parts of the wider mesh that they are responsible for.
|
||||
|
||||
By adopting the use of Network Identities now, you are preparing your infrastructure to be compatible with this future functionality.
|
||||
|
||||
### Creating and Using a Network Identity
|
||||
|
||||
Since a Network Identity is simply a standard Reticulum Identity, you create one using the built-in tools.
|
||||
|
||||
1. **Generate the Identity:**
|
||||
Use the `rnid` utility to generate a new identity file that will serve as your Network Identity.
|
||||
```sh
|
||||
$ rnid -g ~/.reticulum/storage/identities/my_network
|
||||
```
|
||||
2. **Distribute the Public Key:**
|
||||
The public key must be distributed to any Transport Instance that needs to verify your network’s announces and discovery information. By default, if your node is set up to use a network identity, this happens automatically (using the standard announce mechanism).
|
||||
3. **Configure Instances:**
|
||||
In the `[reticulum]` section of the configuration file on every node within your network, point the `network_identity` option to the file you created.
|
||||
```ini
|
||||
[reticulum]
|
||||
...
|
||||
network_identity = ~/.reticulum/storage/identities/my_network
|
||||
...
|
||||
```
|
||||
|
||||
Once configured, your instances will automatically utilize this identity for signing discovery announces (and potentially decrypting network-private information), presenting a unified front to the wider network.
|
||||
|
||||
## Reference Setup
|
||||
|
||||
This section will detail a recommended *Reference Setup* for Reticulum. It is important to
|
||||
note that Reticulum is designed to be usable on more or less any computing device, and over more
|
||||
or less any medium that allows you to send and receive data, which satisfies some very low
|
||||
minimum requirements.
|
||||
|
||||
The communication channel must support at least half-duplex operation, and provide an average
|
||||
throughput of 5 bits per second or greater, and supports a physical layer MTU of 500 bytes. The
|
||||
Reticulum stack should be able to run on more or less any hardware that can provide a Python 3.x
|
||||
runtime environment.
|
||||
|
||||
That being said, this reference setup has been outlined to provide a common platform for anyone
|
||||
who wants to help in the development of Reticulum, and for everyone who wants to know a
|
||||
recommended setup to get started experimenting. A reference system consists of three parts:
|
||||
|
||||
* **An Interface Device**
|
||||
: Which provides access to the physical medium whereupon the communication
|
||||
takes place, for example a radio with an integrated modem. A setup with a separate modem
|
||||
connected to a radio would also be an interface device.
|
||||
* **A Host Device**
|
||||
: Some sort of computing device that can run the necessary software, communicate with the
|
||||
interface device, and provide user interaction.
|
||||
* **A Software Stack**
|
||||
: The software implementing the Reticulum protocol and applications using it.
|
||||
|
||||
The reference setup can be considered a relatively stable platform to develop on, and also to start
|
||||
building networks or applications on. While details of the implementation might change at the current stage of
|
||||
development, it is the goal to maintain hardware compatibility for as long as entirely possible, and
|
||||
the current reference setup has been determined to provide a functional platform for many years
|
||||
into the future. The current Reference System Setup is as follows:
|
||||
|
||||
* **Interface Device**
|
||||
: A data radio consisting of a LoRa radio module, and a microcontroller with open source
|
||||
firmware, that can connect to host devices via USB. It operates in either the 430, 868 or 900
|
||||
MHz frequency bands. More details can be found on the [RNode Page](https://github.com/markqvist/rnode_firmware).
|
||||
* **Host Device**
|
||||
: Any computer device running Linux and Python. A Raspberry Pi with a Debian based OS is
|
||||
a good place to start, but anything can be used.
|
||||
* **Software Stack**
|
||||
: The most recently released Python Implementation of Reticulum, running on a Linux-based
|
||||
operating system.
|
||||
|
||||
#### NOTE
|
||||
To avoid confusion, it is very important to note, that the reference interface device **does not**
|
||||
use the LoRaWAN standard, but uses a custom MAC layer on top of the plain LoRa modulation! As such, you will
|
||||
need a plain LoRa radio module connected to a controller with the correct firmware. Full details on how to
|
||||
get or make such a device is available on the [RNode Page](https://github.com/markqvist/rnode_firmware).
|
||||
|
||||
With the current reference setup, it should be possible to get on a Reticulum network for around 100$
|
||||
even if you have none of the hardware already, and need to purchase everything.
|
||||
|
||||
This reference setup is of course just a recommendation for getting started easily, and you should
|
||||
tailor it to your own specific needs, or whatever hardware you have available.
|
||||
|
||||
## Protocol Specifics
|
||||
|
||||
This chapter will detail protocol specific information that is essential to the implementation of
|
||||
Reticulum, but non-critical in understanding how the protocol works on a general level. It should be
|
||||
treated more as a reference than as essential reading.
|
||||
|
||||
### Packet Prioritisation
|
||||
|
||||
Currently, Reticulum is completely priority-agnostic regarding *general* traffic. All traffic is handled
|
||||
on a first-come, first-serve basis. Announce re-transmission and other maintenance traffic is handled
|
||||
according to the re-transmission times and priorities described earlier in this chapter.
|
||||
|
||||
### Interface Access Codes
|
||||
|
||||
Reticulum can create named virtual networks, and networks that are only accessible by knowing a preshared
|
||||
passphrase. The configuration of this is detailed in the [Common Interface Options](interfaces.md#interfaces-options)
|
||||
section. To implement this feature, Reticulum uses the concept of Interface Access Codes, that are calculated
|
||||
and verified per-packet.
|
||||
|
||||
An interface with a named virtual network or passphrase authentication enabled will derive a shared Ed25519
|
||||
signing identity, and for every outbound packet generate a signature of the entire packet. This signature is
|
||||
then inserted into the packet as an Interface Access Code before transmission. Depending on the speed and
|
||||
capabilities of the interface, the IFAC can be the full 512-bit Ed25519 signature, or a truncated version.
|
||||
Configured IFAC length can be inspected for all interfaces with the `rnstatus` utility.
|
||||
|
||||
Upon receipt, the interface will check that the signature matches the expected value, and drop the packet if it
|
||||
does not. This ensures that only packets sent with the correct naming and/or passphrase parameters are allowed to
|
||||
pass onto the network.
|
||||
|
||||
### Wire Format
|
||||
|
||||
```text
|
||||
== Reticulum Wire Format ======
|
||||
|
||||
A Reticulum packet is composed of the following fields:
|
||||
|
||||
[HEADER 2 bytes] [ADDRESSES 16/32 bytes] [CONTEXT 1 byte] [DATA 0-465 bytes]
|
||||
|
||||
* The HEADER field is 2 bytes long.
|
||||
* Byte 1: [IFAC Flag], [Header Type], [Context Flag], [Propagation Type],
|
||||
[Destination Type] and [Packet Type]
|
||||
* Byte 2: Number of hops
|
||||
|
||||
* Interface Access Code field if the IFAC flag was set.
|
||||
* The length of the Interface Access Code can vary from
|
||||
1 to 64 bytes according to physical interface
|
||||
capabilities and configuration.
|
||||
|
||||
* The ADDRESSES field contains either 1 or 2 addresses.
|
||||
* Each address is 16 bytes long.
|
||||
* The Header Type flag in the HEADER field determines
|
||||
whether the ADDRESSES field contains 1 or 2 addresses.
|
||||
* Addresses are SHA-256 hashes truncated to 16 bytes.
|
||||
|
||||
* The CONTEXT field is 1 byte.
|
||||
* It is used by Reticulum to determine packet context.
|
||||
|
||||
* The DATA field is between 0 and 465 bytes.
|
||||
* It contains the packets data payload.
|
||||
|
||||
IFAC Flag
|
||||
-----------------
|
||||
open 0 Packet for publically accessible interface
|
||||
authenticated 1 Interface authentication is included in packet
|
||||
|
||||
|
||||
Header Types
|
||||
-----------------
|
||||
type 1 0 Two byte header, one 16 byte address field
|
||||
type 2 1 Two byte header, two 16 byte address fields
|
||||
|
||||
|
||||
Context Flag
|
||||
-----------------
|
||||
unset 0 The context flag is used for various types
|
||||
set 1 of signalling, depending on packet context
|
||||
|
||||
|
||||
Propagation Types
|
||||
-----------------
|
||||
broadcast 0
|
||||
transport 1
|
||||
|
||||
|
||||
Destination Types
|
||||
-----------------
|
||||
single 00
|
||||
group 01
|
||||
plain 10
|
||||
link 11
|
||||
|
||||
|
||||
Packet Types
|
||||
-----------------
|
||||
data 00
|
||||
announce 01
|
||||
link request 10
|
||||
proof 11
|
||||
|
||||
|
||||
+- Packet Example -+
|
||||
|
||||
HEADER FIELD DESTINATION FIELDS CONTEXT FIELD DATA FIELD
|
||||
_______|_______ ________________|________________ ________|______ __|_
|
||||
| | | | | | | |
|
||||
01010000 00000100 [HASH1, 16 bytes] [HASH2, 16 bytes] [CONTEXT, 1 byte] [DATA]
|
||||
|| | | | |
|
||||
|| | | | +-- Hops = 4
|
||||
|| | | +------- Packet Type = DATA
|
||||
|| | +--------- Destination Type = SINGLE
|
||||
|| +----------- Propagation Type = TRANSPORT
|
||||
|+------------- Header Type = HEADER_2 (two byte header, two address fields)
|
||||
+-------------- Access Codes = DISABLED
|
||||
|
||||
|
||||
+- Packet Example -+
|
||||
|
||||
HEADER FIELD DESTINATION FIELD CONTEXT FIELD DATA FIELD
|
||||
_______|_______ _______|_______ ________|______ __|_
|
||||
| | | | | | | |
|
||||
00000000 00000111 [HASH1, 16 bytes] [CONTEXT, 1 byte] [DATA]
|
||||
|| | | | |
|
||||
|| | | | +-- Hops = 7
|
||||
|| | | +------- Packet Type = DATA
|
||||
|| | +--------- Destination Type = SINGLE
|
||||
|| +----------- Propagation Type = BROADCAST
|
||||
|+------------- Header Type = HEADER_1 (two byte header, one address field)
|
||||
+-------------- Access Codes = DISABLED
|
||||
|
||||
|
||||
+- Packet Example -+
|
||||
|
||||
HEADER FIELD IFAC FIELD DESTINATION FIELD CONTEXT FIELD DATA FIELD
|
||||
_______|_______ ______|______ _______|_______ ________|______ __|_
|
||||
| | | | | | | | | |
|
||||
10000000 00000111 [IFAC, N bytes] [HASH1, 16 bytes] [CONTEXT, 1 byte] [DATA]
|
||||
|| | | | |
|
||||
|| | | | +-- Hops = 7
|
||||
|| | | +------- Packet Type = DATA
|
||||
|| | +--------- Destination Type = SINGLE
|
||||
|| +----------- Propagation Type = BROADCAST
|
||||
|+------------- Header Type = HEADER_1 (two byte header, one address field)
|
||||
+-------------- Access Codes = ENABLED
|
||||
|
||||
|
||||
Size examples of different packet types
|
||||
---------------------------------------
|
||||
|
||||
The following table lists example sizes of various
|
||||
packet types. The size listed are the complete on-
|
||||
wire size counting all fields including headers,
|
||||
but excluding any interface access codes.
|
||||
|
||||
- Path Request : 51 bytes
|
||||
- Announce : 167 bytes
|
||||
- Link Request : 83 bytes
|
||||
- Link Proof : 115 bytes
|
||||
- Link RTT packet : 99 bytes
|
||||
- Link keepalive : 20 bytes
|
||||
```
|
||||
|
||||
### Announce Propagation Rules
|
||||
|
||||
The following table illustrates the rules for automatically propagating announces
|
||||
from one interface type to another, for all possible combinations. For the purpose
|
||||
of announce propagation, the *Full* and *Gateway* modes are identical.
|
||||
|
||||

|
||||
|
||||
See the [Interface Modes](interfaces.md#interfaces-modes) section for a conceptual overview
|
||||
of the different interface modes, and how they are configured.
|
||||
|
||||
<!-- (.. code-block:: text)
|
||||
Full ────── ✓ ──┐ ┌── ✓ ── Full
|
||||
AP ──────── ✓ ──┼───> Full >───┼── ✕ ── AP
|
||||
Boundary ── ✓ ──┤ ├── ✓ ── Boundary
|
||||
Roaming ─── ✓ ──┘ └── ✓ ── Roaming
|
||||
|
||||
Full ────── ✕ ──┐ ┌── ✓ ── Full
|
||||
AP ──────── ✕ ──┼────> AP >────┼── ✕ ── AP
|
||||
Boundary ── ✕ ──┤ ├── ✓ ── Boundary
|
||||
Roaming ─── ✕ ──┘ └── ✓ ── Roaming
|
||||
|
||||
Full ────── ✓ ──┐ ┌── ✓ ── Full
|
||||
AP ──────── ✓ ──┼─> Roaming >──┼── ✕ ── AP
|
||||
Boundary ── ✕ ──┤ ├── ✕ ── Boundary
|
||||
Roaming ─── ✕ ──┘ └── ✕ ── Roaming
|
||||
|
||||
Full ────── ✓ ──┐ ┌── ✓ ── Full
|
||||
AP ──────── ✓ ──┼─> Boundary >─┼── ✕ ── AP
|
||||
Boundary ── ✓ ──┤ ├── ✓ ── Boundary
|
||||
Roaming ─── ✕ ──┘ └── ✕ ── Roaming -->
|
||||
|
||||
### Cryptographic Primitives
|
||||
|
||||
Reticulum uses a simple suite of efficient, strong and well-tested cryptographic
|
||||
primitives, with widely available implementations that can be used both on
|
||||
general-purpose CPUs and on microcontrollers.
|
||||
|
||||
One of the primary considerations for choosing this particular set of primitives is
|
||||
that they can be implemented *safely* with relatively few pitfalls, on practically
|
||||
all current computing platforms.
|
||||
|
||||
The primitives listed here **are authoritative**. Anything claiming to be Reticulum,
|
||||
but not using these exact primitives **is not** Reticulum, and possibly an
|
||||
intentionally compromised or weakened clone. The utilised primitives are:
|
||||
|
||||
* Ed25519 for signatures
|
||||
* X25519 for ECDH key exchanges
|
||||
* HKDF for key derivation
|
||||
* Encrypted tokens are based on the Fernet spec
|
||||
* Ephemeral keys derived from an ECDH key exchange on Curve25519
|
||||
* AES-256 in CBC mode with PKCS7 padding
|
||||
* HMAC using SHA256 for message authentication
|
||||
* IVs must be generated through `os.urandom()` or better
|
||||
* No Fernet version and timestamp metadata fields
|
||||
* SHA-256
|
||||
* SHA-512
|
||||
|
||||
In the default installation configuration, the `X25519`, `Ed25519` and `AES-256-CBC`
|
||||
primitives are provided by [OpenSSL](https://www.openssl.org/) (via the [PyCA/cryptography](https://github.com/pyca/cryptography)
|
||||
package). The hashing functions `SHA-256` and `SHA-512` are provided by the standard
|
||||
Python [hashlib](https://docs.python.org/3/library/hashlib.html). The `HKDF`, `HMAC`,
|
||||
`Token` primitives, and the `PKCS7` padding function are always provided by the
|
||||
following internal implementations:
|
||||
|
||||
- `RNS/Cryptography/HKDF.py`
|
||||
- `RNS/Cryptography/HMAC.py`
|
||||
- `RNS/Cryptography/Token.py`
|
||||
- `RNS/Cryptography/PKCS7.py`
|
||||
|
||||
Reticulum also includes a complete implementation of all necessary primitives in pure Python.
|
||||
If OpenSSL & PyCA are not available on the system when Reticulum is started, Reticulum will
|
||||
instead use the internal pure-python primitives. A trivial consequence of this is performance,
|
||||
with the OpenSSL backend being *much* faster. The most important consequence however, is the
|
||||
potential loss of security by using primitives that has not seen the same amount of scrutiny,
|
||||
testing and review as those from OpenSSL.
|
||||
|
||||
Using the normal RNS installation procedures, it is not possible to install Reticulum on a
|
||||
system without the required OpenSSL primitives being available, and if they are not, they will
|
||||
be resolved and installed as a dependency. It is only possible to use the pure-python primitives
|
||||
by manually specifying this, for example by using the `rnspure` package.
|
||||
|
||||
#### WARNING
|
||||
If you want to use the internal pure-python primitives, it is **highly advisable** that you
|
||||
have a good understanding of the risks that this pose, and make an informed decision on whether
|
||||
those risks are acceptable to you.
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="using-main"></a>
|
||||
|
||||
# Using Reticulum on Your System
|
||||
|
||||
Reticulum is not installed as a driver or kernel module, as one might expect
|
||||
|
|
@ -462,8 +460,6 @@ options:
|
|||
--version show program's version number and exit
|
||||
```
|
||||
|
||||
<a id="utility-rnpath"></a>
|
||||
|
||||
### The rnpath Utility
|
||||
|
||||
With the `rnpath` utility, you can look up and view paths for
|
||||
|
|
@ -1101,8 +1097,6 @@ options:
|
|||
For more information on how to create your own RNodes, please read the [Creating RNodes](hardware.md#rnode-creating)
|
||||
section of this manual.
|
||||
|
||||
<a id="using-interface-discovery"></a>
|
||||
|
||||
## Discovering Interfaces
|
||||
|
||||
Reticulum includes built-in functionality for discovering connectable interfaces over Reticulum itself. This is particularly useful in situations where you want to do one or more of the following:
|
||||
|
|
@ -1219,8 +1213,6 @@ remote_management_allowed = 9fb6d773498fb3feda407ed8ef2c3229, 2d882c5586e548d79b
|
|||
|
||||
For a complete example configuration, you can run `rnsd --exampleconfig`.
|
||||
|
||||
<a id="using-blackhole-management"></a>
|
||||
|
||||
## Blackhole Management
|
||||
|
||||
Reticulum networks are fundamentally permissionless and open, allowing anyone with a compatible interface to participate. While this openness is essential for a resilient and decentralized network, it also exposes the network to potential abuse, such as peers flooding the network with excessive announce broadcasts or other forms of resource exhaustion.
|
||||
|
|
@ -1371,8 +1363,6 @@ Using this methodology avoids potential naming mix-ups where physical devices
|
|||
might be plugged and unplugged in different orders, or when device name
|
||||
assignment varies from one boot to another.
|
||||
|
||||
<a id="using-systemd"></a>
|
||||
|
||||
### Reticulum as a System Service
|
||||
|
||||
Instead of starting Reticulum manually, you can install `rnsd` as a system
|
||||
|
|
@ -1468,4 +1458,4 @@ If you want to automatically start `rnsd` without having to log in as the USERNA
|
|||
```text
|
||||
sudo loginctl enable-linger USERNAMEHERE
|
||||
systemctl --user enable rnsd.service
|
||||
```
|
||||
```
|
||||
|
|
@ -141,4 +141,4 @@ Reticulum implements a range of generalised interface types that covers the comm
|
|||
* Or to quickly create interfaces with custom hardware
|
||||
* Anything else using [custom interface modules](interfaces.md#interfaces-custom) written in Python
|
||||
|
||||
For a full list and more details, see the [Supported Interfaces](interfaces.md#interfaces-main) chapter.
|
||||
For a full list and more details, see the [Supported Interfaces](interfaces.md#interfaces-main) chapter.
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
<a id="zen"></a>
|
||||
|
||||
# Zen of Reticulum
|
||||
|
||||
## The Illusion Of The Center
|
||||
|
|
@ -413,4 +411,4 @@ It looks like a single node on a windowsill, listening to the static. It looks l
|
|||
|
||||
You have the blueprints. You have the tools. You have the philosophy. The noise of the old world has fallen away, leaving you with the quiet clarity of the open spectrum.
|
||||
|
||||
*Mark, early 2026*
|
||||
*Mark, early 2026*
|
||||
Loading…
Add table
Add a link
Reference in a new issue