mirror of
https://github.com/markqvist/Reticulum.git
synced 2026-06-22 12:03:04 -07:00
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 422dc05549 | |||
| 50c0a354c9 | |||
| e98487c1cf | |||
| 50e03a24e8 | |||
| 0cc42568c7 | |||
| 41790ca707 | |||
| 20b1bfd01e | |||
| 1be5e10abe | |||
| 13a9ebed83 | |||
| aee8c3be0c | |||
| ef8ccf67ed | |||
| 91d531b053 | |||
| 0de169836e | |||
| a2ef978208 | |||
| 5b3bb050e7 | |||
| 9b9efe5fac | |||
| 482d5ac4cb | |||
| 804a7ddbe1 | |||
| 739fdd387e | |||
| f3517d2e4b | |||
| c59f1e3dd6 | |||
| 2cf07099e3 | |||
| 0292465666 | |||
| b4e15503c1 | |||
| a5ca1ee41e | |||
| f9c786fa28 | |||
| bcf35030bc | |||
| 237eada209 | |||
| afb984d3d4 | |||
| 675a25c90e | |||
| f6d6314842 | |||
| 22ab5c29bd | |||
| 4931c6a54c | |||
| d3fcc2a38c | |||
| e9609b7f25 | |||
| 70cd51f0fa | |||
| fa7699a37d | |||
| 2c9b794182 | |||
| eae84ed8ba | |||
| 31539c5a0e | |||
| abca32bca4 | |||
| 1d7cfe7c20 | |||
| a516960e6f | |||
| 870bee16b1 | |||
| 3814102936 | |||
| aaadff547d | |||
| f0a3fadcd1 | |||
| 7cbce84cbd | |||
| fe334c0d7c | |||
| 33d5a8e2a8 | |||
| e80bf471ec | |||
| 7dfdea2395 | |||
| 74b61aebd2 | |||
| ce9071e2d3 | |||
| d6cf59dcc8 | |||
| de61652d37 | |||
| 6181f62d93 | |||
| ed66b4873e | |||
| 26869941a4 | |||
| ee7b4e7ae5 | |||
| 7866484453 | |||
| 817b3b1a12 | |||
| 17f6968467 | |||
| a96a1d6692 | |||
| c1081fa9a4 | |||
| dd3104094b | |||
| dc68eea313 | |||
| 794e437f6d | |||
| ebf544d335 | |||
| 939f30fef2 | |||
| 4549bbfdb9 | |||
| 6c989eb38e | |||
| 137d73ad0d | |||
| 58d4162f6d | |||
| 67625395fe | |||
| f62512381a | |||
| 888e3102de | |||
| f83435c697 | |||
| 5243d646f0 | |||
| bdb284ce5d | |||
| 1b34820601 | |||
| 01010dd599 | |||
| da32709f7c | |||
| cdc6159a15 | |||
| eb2f7ae455 | |||
| a74f1bd89f | |||
| 603f709139 | |||
| 0dd063a32e |
@@ -14,3 +14,4 @@ tests/rnsconfig/logfile*
|
||||
*.data
|
||||
*.result
|
||||
.buildinfo.bak
|
||||
docs/Reticulum Manual.*
|
||||
|
||||
+102
-36
@@ -1,3 +1,105 @@
|
||||
### 2026-06-01: RNS 1.3.5
|
||||
|
||||
This maintenance release contains an important fix for `AutoInterface` reliability when roaming between different physical networks.
|
||||
|
||||
**Changes**
|
||||
- Fixed UDP listener replacement deadlocking inbound AutoInterface traffic when fast-roaming between physical interfaces or WiFi APs
|
||||
- Fixed some paths never resolving when using other interfaces at the same time as a deadlocked AutoInterface
|
||||
|
||||
**Verified Retrieval**
|
||||
You can retrieve and verify this release over Reticulum using the built-in `rngit release` utility. To retrieve only the installation `.whl` package, and the release manifest for future updates, you can use:
|
||||
|
||||
```sh
|
||||
rngit release rns://7649a50d84610232d1416b41d2896aff/reticulum/reticulum fetch "latest:rns-*.whl" --signer bc7291552be7a58f361522990465165c
|
||||
```
|
||||
|
||||
To download all artifacts, including the documentation and source archive, you can use the following command:
|
||||
|
||||
```sh
|
||||
rngit release rns://7649a50d84610232d1416b41d2896aff/reticulum/reticulum fetch latest:all --signer bc7291552be7a58f361522990465165c
|
||||
```
|
||||
|
||||
**Release Signatures**
|
||||
Release artifacts include a signed `rsm` release manifest and `rsg` signature files that can be validated against the RNS release signing identity `<bc7291552be7a58f361522990465165c>` using `rngit` or `rnid`. To perform an offline verification of all release artifacts using a manifest:
|
||||
|
||||
```sh
|
||||
rngit release rns_*.rsm verify --signer bc7291552be7a58f361522990465165c
|
||||
```
|
||||
|
||||
To verify release artifacts using individual `rsg` files, while also verifying the manifest itself, download the `rsm` and `rsg` signatures, make sure they are in the same folder as the release artifact, and run `rnid` signature verification with the release identity as the required signer:
|
||||
|
||||
```sh
|
||||
rnid -i bc7291552be7a58f361522990465165c -V rns_*.rsm *.rsg
|
||||
```
|
||||
|
||||
The `rnid` utility will then verify the signatures, and display whether they are valid. If the signature cannot be verified, the release has been tampered with and should be discarded.
|
||||
|
||||
### 2026-05-29: RNS 1.3.4
|
||||
|
||||
This release fixes a regression that could cause sub-optimal path selection under conditions where the same announce was received within a very short timespan on different interfaces, as well as a few other bugs and inefficiencies.
|
||||
|
||||
**Changes**
|
||||
- Fixed regression in inbound announce de-duplication
|
||||
- Fixed missing check for shared instance type configuration conflict
|
||||
- Fixed superfluous path state configuration on new announce from new destinations
|
||||
- Improved cleanup of stale known destinations
|
||||
- Improved shared instance RPC handling
|
||||
|
||||
### 2026-05-28: RNS 1.3.3
|
||||
|
||||
This release fixes a regression in persistence of known destination on Windows.
|
||||
|
||||
**Changes**
|
||||
- Fixed regression in known destinations persist on Windows
|
||||
|
||||
### 2026-05-28: RNS 1.3.2
|
||||
|
||||
This release adds commit signing and validation support to the `rngit` system, as well as improvements to the blackhole functionality.
|
||||
|
||||
**Changes**
|
||||
- Extended blackhole functionality to immediately terminate links from blackholed identities
|
||||
- Added commit signing and validation to `rngit`
|
||||
- Added commit hash inclusion in generated release manifest to `rngit`
|
||||
- Added local `verify` operation shorthand to `rngit release`
|
||||
- Added option to configure blackhole update interval
|
||||
- Added configuration option to log without timestamps
|
||||
|
||||
### 2026-05-22: RNS 1.3.1
|
||||
|
||||
This maintenance release fixes a single bug.
|
||||
|
||||
**Changes**
|
||||
- Fixed regression in request response transfer size accumulator
|
||||
|
||||
### 2026-05-21: RNS 1.3.0
|
||||
|
||||
This maintenance release fixes a number of bugs.
|
||||
|
||||
**Changes**
|
||||
- Added ability to use wildcards and pattern matches in `rngit` artifact fetch targets
|
||||
- Fixed channel outlet sequence holes and ghost envelopes on dying outlets by **neutral**
|
||||
- Fixed known destination iteration races by **neutral**
|
||||
- Fixed timeout deadlock in `rnsh` by **neutral**
|
||||
- Fixed commit message rendering in `rngit`
|
||||
- Fixed various minor bugs and output inconsistencies in `rngit`
|
||||
- Adjusted timeouts for remote operations in `rngit`
|
||||
- Updated documentation
|
||||
|
||||
### 2026-05-19: RNS 1.2.9
|
||||
|
||||
This release completes the operational functionality of the `rngit` system, which now has full release creation, fetch and verified update support using the `rngit release` command. Additionally, two chapters have been added to the manual should cover all the things that `rngit` is currently capable of.
|
||||
|
||||
**Changes**
|
||||
- Added full `rngit` documentation to the manual
|
||||
- Added offline `.rsm` release manifest verification
|
||||
- Added the ability to fetch release updates directly from `.rsm` manifests
|
||||
- Added canonical `.rsm` release structure validator to `rnid` for import
|
||||
- Added `.rsm` manifest saving when using `rngit release fetch`
|
||||
- Added remote `HEAD` tracking for forks and mirros to `rngit`
|
||||
- Improved known destinations persist reliability
|
||||
- Improved page node ref link handling in `rngit`
|
||||
- Improved logging in various locations
|
||||
|
||||
### 2026-05-18: RNS 1.2.8
|
||||
|
||||
This release improves the `rngit` system with signed release manifest generation and automatic artifact signing. It also includes several additions to `rnid` and various minor fixes and improvements to the `rngit` system.
|
||||
@@ -18,15 +120,6 @@ This release improves the `rngit` system with signed release manifest generation
|
||||
- Fixed various minor bugs and inconsistencies in `rngit`
|
||||
- Dropped `note` metadata field requirement from `rsg` structure
|
||||
|
||||
**Release Signatures**
|
||||
Release artifacts include a signed `rsm` release manifest and `rsg` signature files that can be validated against the RNS release signing identity `<bc7291552be7a58f361522990465165c>` using `rnid`. To verify files, download the `rsm` and `rsg` signatures, make sure they are in the same folder as the release artifact, and run `rnid` signature verification with the release identity as the required signer:
|
||||
|
||||
```sh
|
||||
rnid -i bc7291552be7a58f361522990465165c -V manifest.rsm *.rsg
|
||||
```
|
||||
|
||||
The `rnid` utility will then verify the signatures, and display whether they are valid. If the signature cannot be verified, the release has been tampered with and should be discarded.
|
||||
|
||||
### 2026-05-17: RNS 1.2.7
|
||||
|
||||
This release significantly improves the `rngit` system with fork, mirroring and empty repository creation functionality, a new work document proposals feature, improvements to the transport core reliability and efficiency and various other tweaks and improvements.
|
||||
@@ -44,15 +137,6 @@ This release significantly improves the `rngit` system with fork, mirroring and
|
||||
- Improved transfer completed feedback in `rncp`, thanks to **neutral**
|
||||
- Improved interface transport insertion and removal
|
||||
|
||||
**Release Signatures**
|
||||
Release artifacts include `rsg` signature files that can be validated against the RNS release signing identity `<bc7291552be7a58f361522990465165c>` using `rnid`. To verify files, download the `rsg` signatures, make sure they are in the same folder as the release artifact, and run `rnid` signature verification with the release identity as the required signer:
|
||||
|
||||
```sh
|
||||
rnid -i bc7291552be7a58f361522990465165c -V rns*.whl
|
||||
```
|
||||
|
||||
The `rnid` utility will then verify the signatures, and display whether it is valid. If the signature cannot be verified, the file has been tampered with and should be thrown very far away in a jiffy.
|
||||
|
||||
### 2026-05-14: RNS 1.2.6
|
||||
|
||||
This release adds further improvements to the `rnid` and `rngit` utilities, and includes several bugfixes and other improvements.
|
||||
@@ -74,15 +158,6 @@ This release adds further improvements to the `rnid` and `rngit` utilities, and
|
||||
- Fixed potential race condition in interface discovery
|
||||
- Fixed `rngit` remote helper hanging on startup if no client config had been created previously, and RNS loglevel was configured at debug or higher
|
||||
|
||||
**Release Signatures**
|
||||
Release artifacts include `rsg` signature files that can be validated against the RNS release signing identity `<bc7291552be7a58f361522990465165c>` using `rnid`. To verify files, download the `rsg` signatures, make sure they are in the same folder as the release artifact, and run `rnid` signature verification with the release identity as the required signer:
|
||||
|
||||
```sh
|
||||
rnid -i bc7291552be7a58f361522990465165c -V rns*.whl
|
||||
```
|
||||
|
||||
The `rnid` utility will then verify the signatures, and display whether it is valid. If the signature cannot be verified, the file has been tampered with and should be thrown very far away in a jiffy.
|
||||
|
||||
### 2026-05-09: RNS 1.2.5
|
||||
|
||||
This release brings substantial improvements to path request handling, and should significantly reduce overall network and local transport node processing loads. Path requests are now automatically ingress and egress limited per interface and sub-interface. Although the defaults are effective and sane, and should work right out of the box bring an end to practically all the PR and announce spam going on lately, the backend is fully configurable for both defaults and per interface, if you want to fiddle with the settings.
|
||||
@@ -111,15 +186,6 @@ For all node ops out there, I'd recomment updating to this at some sort of semi-
|
||||
- Ensured canonical validation functions in `rngit`
|
||||
- Lots of other small fixes and stability improvements to `rngit`
|
||||
|
||||
**Release Signatures**
|
||||
Release artifacts include `rsg` signature files that can be validated against the RNS release signing identity `<bc7291552be7a58f361522990465165c>` using `rnid`. To verify files, download the `rsg` signatures, make sure they are in the same folder as the release artifact, and run `rnid` signature verification with the release identity as the required signer:
|
||||
|
||||
```sh
|
||||
rnid -i bc7291552be7a58f361522990465165c -V rns-1.2.5-py3-none-any.whl
|
||||
```
|
||||
|
||||
The `rnid` utility will then verify the signatures, and display whether it is valid. If the signature cannot be verified, the file has been tampered with and should be thrown very far away in a jiffy.
|
||||
|
||||
### 2026-05-07: RNS 1.2.4
|
||||
|
||||
This release brings a complete rewrite and update to the `rnid` utility, which is now a lot more useful, and better at finding and saving identities. It also includes a bunch of other improvements, such as expanded `rngit` functionality, better transport performance and a few bugfixes. Enjoy!
|
||||
|
||||
@@ -56,22 +56,35 @@ documentation:
|
||||
manual:
|
||||
make -C docs latexpdf epub
|
||||
|
||||
distcollect:
|
||||
mv docs/Reticulum\ Manual.* dist
|
||||
|
||||
build_spkg: remove_symlinks build_sdist create_symlinks
|
||||
|
||||
release: test remove_symlinks build_sdist build_wheel build_pure_wheel documentation manual create_symlinks
|
||||
release: test remove_symlinks build_sdist build_wheel build_pure_wheel documentation manual distcollect create_symlinks
|
||||
|
||||
debug: remove_symlinks build_wheel build_pure_wheel create_symlinks
|
||||
|
||||
upload: upload-rns upload-rnspure
|
||||
local: release sign
|
||||
|
||||
upload-rns:
|
||||
sign:
|
||||
rngit release rns://7649a50d84610232d1416b41d2896aff/reticulum/reticulum create $$(python setup.py --getversion):dist --name rns --local
|
||||
|
||||
upload:
|
||||
@echo Ready to publish release over Reticulum
|
||||
@read VOID
|
||||
rngit release rns://7649a50d84610232d1416b41d2896aff/reticulum/reticulum create $$(python setup.py --getversion):dist --name rns
|
||||
|
||||
upload-pip: upload-rns-pip upload-rnspure-pip
|
||||
|
||||
upload-rns-pip:
|
||||
@echo Ready to publish rns release, hit enter to continue
|
||||
@read VOID
|
||||
@echo Uploading to PyPi...
|
||||
twine upload dist/rns-*.whl dist/rns-*.tar.gz
|
||||
@echo Release published
|
||||
|
||||
upload-rnspure:
|
||||
upload-rnspure-pip:
|
||||
@echo Ready to publish rnspure release, hit enter to continue
|
||||
@read VOID
|
||||
@echo Uploading to PyPi...
|
||||
|
||||
@@ -39,7 +39,7 @@ userland, and can run on practically any system that runs Python 3.
|
||||
## Read The Manual
|
||||
The full documentation for Reticulum is available at [markqvist.github.io/Reticulum/manual/](https://markqvist.github.io/Reticulum/manual/).
|
||||
|
||||
You can also download the [Reticulum manual as a PDF](https://github.com/markqvist/Reticulum/raw/master/docs/Reticulum%20Manual.pdf) or [as an e-book in EPUB format](https://github.com/markqvist/Reticulum/raw/master/docs/Reticulum%20Manual.epub).
|
||||
You can also download the [Reticulum manual as a PDF](https://github.com/markqvist/Reticulum/releases/latest/download/Reticulum.Manual.pdf) or [as an e-book in EPUB format](https://github.com/markqvist/Reticulum/releases/latest/download/Reticulum.Manual.epub).
|
||||
|
||||
For more info, see [reticulum.network](https://reticulum.network/) and [the FAQ section of the wiki](https://github.com/markqvist/Reticulum/wiki/Frequently-Asked-Questions).
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ No kernel modules or drivers are required. Reticulum runs completely in userland
|
||||
|
||||
The full documentation for Reticulum is available on `_`!`[this node`:/page/blob.mu`g=reticulum|r=reticulum|ref=HEAD|path=docs/markdown/index.md]`!`_.
|
||||
|
||||
You can also download the `_`!`[Reticulum manual as a PDF`:/file/download`g=reticulum|r=reticulum|ref=HEAD|path=docs%2FReticulum+Manual.pdf]`!`_ or `_`!`[as an e-book in EPUB format`:/file/download`g=reticulum|r=reticulum|ref=HEAD|path=docs%2FReticulum+Manual.pdf]`!`_.
|
||||
You can also download the `_`!`[Reticulum manual as a PDF`:/file/artifact`g=reticulum|r=reticulum|t=latest|a=Reticulum+Manual.pdf]`!`_ or `_`!`[as an e-book in EPUB format`:/file/artifact`g=reticulum|r=reticulum|t=latest|a=Reticulum+Manual.epub]`!`_.
|
||||
|
||||
>> Notable Features
|
||||
|
||||
|
||||
+89
-56
@@ -144,7 +144,7 @@ class MessageBase(abc.ABC):
|
||||
MSGTYPE = None
|
||||
"""
|
||||
Defines a unique identifier for a message class.
|
||||
|
||||
|
||||
* Must be unique within all classes registered with a ``Channel``
|
||||
* Must be less than ``0xf000``. Values greater than or equal to ``0xf000`` are reserved.
|
||||
"""
|
||||
@@ -255,11 +255,11 @@ class Channel(contextlib.AbstractContextManager):
|
||||
|
||||
# The maximum window size for transfers on fast links
|
||||
WINDOW_MAX_FAST = 48
|
||||
|
||||
|
||||
# For calculating maps and guard segments, this
|
||||
# must be set to the global maximum window.
|
||||
WINDOW_MAX = WINDOW_MAX_FAST
|
||||
|
||||
|
||||
# If the fast rate is sustained for this many request
|
||||
# rounds, the fast link window size will be allowed.
|
||||
FAST_RATE_THRESHOLD = 10
|
||||
@@ -285,6 +285,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
"""
|
||||
self._outlet = outlet
|
||||
self._lock = threading.RLock()
|
||||
self._send_lock = threading.Lock()
|
||||
self._tx_ring: collections.deque[Envelope] = collections.deque()
|
||||
self._rx_ring: collections.deque[Envelope] = collections.deque()
|
||||
self._message_callbacks: [MessageCallbackType] = []
|
||||
@@ -382,27 +383,30 @@ class Channel(contextlib.AbstractContextManager):
|
||||
if envelope.packet is not None:
|
||||
self._outlet.set_packet_timeout_callback(envelope.packet, None)
|
||||
self._outlet.set_packet_delivered_callback(envelope.packet, None)
|
||||
envelope.tracked = False
|
||||
for envelope in self._rx_ring:
|
||||
envelope.tracked = False
|
||||
self._tx_ring.clear()
|
||||
self._rx_ring.clear()
|
||||
|
||||
def _emplace_envelope(self, envelope: Envelope, ring: collections.deque[Envelope]) -> bool:
|
||||
with self._lock:
|
||||
i = 0
|
||||
|
||||
|
||||
for existing in ring:
|
||||
|
||||
if envelope.sequence == existing.sequence:
|
||||
RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence "+str(envelope.sequence), RNS.LOG_EXTREME)
|
||||
return False
|
||||
|
||||
|
||||
if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2):
|
||||
ring.insert(i, envelope)
|
||||
|
||||
envelope.tracked = True
|
||||
return True
|
||||
|
||||
|
||||
i += 1
|
||||
|
||||
|
||||
envelope.tracked = True
|
||||
ring.append(envelope)
|
||||
|
||||
@@ -457,7 +461,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
m = e.unpack(self._message_factories)
|
||||
else:
|
||||
m = e.message
|
||||
|
||||
|
||||
self._rx_ring.remove(e)
|
||||
self._run_callbacks(m)
|
||||
|
||||
@@ -476,7 +480,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
with self._lock:
|
||||
outstanding = 0
|
||||
for envelope in self._tx_ring:
|
||||
if envelope.outlet == self._outlet:
|
||||
if envelope.outlet == self._outlet:
|
||||
if not envelope.packet or not self._outlet.get_packet_state(envelope.packet) == MessageState.MSGSTATE_DELIVERED:
|
||||
outstanding += 1
|
||||
|
||||
@@ -486,8 +490,10 @@ class Channel(contextlib.AbstractContextManager):
|
||||
return True
|
||||
|
||||
def _packet_tx_op(self, packet: TPacket, op: Callable[[TPacket], bool]):
|
||||
target_id = self._outlet.get_packet_id(packet)
|
||||
with self._lock:
|
||||
envelope = next(filter(lambda e: self._outlet.get_packet_id(e.packet) == self._outlet.get_packet_id(packet),
|
||||
envelope = next(filter(lambda e: e.packet is not None
|
||||
and self._outlet.get_packet_id(e.packet) == target_id,
|
||||
self._tx_ring), None)
|
||||
|
||||
if envelope and op(envelope):
|
||||
@@ -516,7 +522,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Increased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_DEBUG)
|
||||
# RNS.log("Increased "+str(self)+" min window to "+str(self.window_min), RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
else:
|
||||
self.fast_rate_rounds += 1
|
||||
if self.window_max < Channel.WINDOW_MAX_FAST and self.fast_rate_rounds == Channel.FAST_RATE_THRESHOLD:
|
||||
@@ -547,36 +553,48 @@ class Channel(contextlib.AbstractContextManager):
|
||||
return to
|
||||
|
||||
def _packet_timeout(self, packet: TPacket):
|
||||
def retry_envelope(envelope: Envelope) -> bool:
|
||||
if self._outlet.get_packet_state(packet) == MessageState.MSGSTATE_DELIVERED:
|
||||
return
|
||||
|
||||
target_id = self._outlet.get_packet_id(packet)
|
||||
envelope_to_resend: Envelope | None = None
|
||||
should_teardown = False
|
||||
with self._lock:
|
||||
envelope = next(filter(
|
||||
lambda e: e.packet is not None and self._outlet.get_packet_id(e.packet) == target_id,
|
||||
self._tx_ring), None)
|
||||
if envelope is None:
|
||||
return
|
||||
|
||||
if envelope.tries >= self._max_tries:
|
||||
RNS.log("Retry count exceeded on "+str(self)+", tearing down Link.", RNS.LOG_ERROR)
|
||||
self._shutdown() # start on separate thread?
|
||||
self._outlet.timed_out()
|
||||
return True
|
||||
should_teardown = True
|
||||
else:
|
||||
envelope.tries += 1
|
||||
envelope_to_resend = envelope
|
||||
|
||||
envelope.tries += 1
|
||||
self._outlet.resend(envelope.packet)
|
||||
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)
|
||||
self._outlet.set_packet_timeout_callback(envelope.packet, self._packet_timeout, self._get_packet_timeout_time(envelope.tries))
|
||||
self._update_packet_timeouts()
|
||||
if self.window > self.window_min:
|
||||
self.window -= 1
|
||||
if self.window_max > (self.window_min+self.window_flexibility):
|
||||
self.window_max -= 1
|
||||
|
||||
if self.window > self.window_min:
|
||||
self.window -= 1
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Decreased "+str(self)+" window to "+str(self.window), RNS.LOG_DEBUG)
|
||||
if should_teardown:
|
||||
RNS.log("Retry count exceeded on "+str(self)+", tearing down Link.", RNS.LOG_ERROR)
|
||||
self._shutdown()
|
||||
self._outlet.timed_out()
|
||||
return
|
||||
|
||||
if self.window_max > (self.window_min+self.window_flexibility):
|
||||
self.window_max -= 1
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Decreased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_DEBUG)
|
||||
if envelope_to_resend is not None:
|
||||
self._outlet.resend(envelope_to_resend.packet)
|
||||
with self._lock:
|
||||
self._outlet.set_packet_delivered_callback(envelope_to_resend.packet, self._packet_delivered)
|
||||
self._outlet.set_packet_timeout_callback(
|
||||
envelope_to_resend.packet, self._packet_timeout,
|
||||
self._get_packet_timeout_time(envelope_to_resend.tries))
|
||||
self._update_packet_timeouts()
|
||||
already_delivered = (self._outlet.get_packet_state(envelope_to_resend.packet) == MessageState.MSGSTATE_DELIVERED)
|
||||
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Decreased "+str(self)+" window to "+str(self.window), RNS.LOG_EXTREME)
|
||||
|
||||
return False
|
||||
|
||||
if self._outlet.get_packet_state(packet) != MessageState.MSGSTATE_DELIVERED:
|
||||
self._packet_tx_op(packet, retry_envelope)
|
||||
if already_delivered:
|
||||
self._packet_delivered(envelope_to_resend.packet)
|
||||
|
||||
def send(self, message: MessageBase) -> Envelope:
|
||||
"""
|
||||
@@ -585,27 +603,39 @@ class Channel(contextlib.AbstractContextManager):
|
||||
|
||||
:param message: an instance of a ``MessageBase`` subclass
|
||||
"""
|
||||
envelope: Envelope | None = None
|
||||
with self._lock:
|
||||
if not self.is_ready_to_send():
|
||||
raise ChannelException(CEType.ME_LINK_NOT_READY, f"Link is not ready")
|
||||
|
||||
envelope = Envelope(self._outlet, message=message, sequence=self._next_sequence)
|
||||
self._next_sequence = (self._next_sequence + 1) % Channel.SEQ_MODULUS
|
||||
self._emplace_envelope(envelope, self._tx_ring)
|
||||
with self._send_lock:
|
||||
with self._lock:
|
||||
if not self.is_ready_to_send():
|
||||
raise ChannelException(CEType.ME_LINK_NOT_READY, f"Link is not ready")
|
||||
|
||||
if envelope is None:
|
||||
raise BlockingIOError()
|
||||
reserved_sequence = self._next_sequence
|
||||
envelope = Envelope(self._outlet, message=message, sequence=reserved_sequence)
|
||||
envelope.pack()
|
||||
if len(envelope.raw) > self._outlet.mdu:
|
||||
raise ChannelException(CEType.ME_TOO_BIG,
|
||||
f"Packed message too big for packet: {len(envelope.raw)} > {self._outlet.mdu}")
|
||||
self._next_sequence = (reserved_sequence + 1) % Channel.SEQ_MODULUS
|
||||
|
||||
envelope.pack()
|
||||
if len(envelope.raw) > self._outlet.mdu:
|
||||
raise ChannelException(CEType.ME_TOO_BIG, f"Packed message too big for packet: {len(envelope.raw)} > {self._outlet.mdu}")
|
||||
|
||||
envelope.packet = self._outlet.send(envelope.raw)
|
||||
envelope.tries += 1
|
||||
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)
|
||||
self._outlet.set_packet_timeout_callback(envelope.packet, self._packet_timeout, self._get_packet_timeout_time(envelope.tries))
|
||||
self._update_packet_timeouts()
|
||||
envelope.packet = self._outlet.send(envelope.raw)
|
||||
|
||||
if (envelope.packet is None
|
||||
or getattr(envelope.packet, "raw", None) is None
|
||||
or (hasattr(envelope.packet, "receipt") and envelope.packet.receipt is None)):
|
||||
with self._lock:
|
||||
self._next_sequence = reserved_sequence
|
||||
raise ChannelException(CEType.ME_LINK_NOT_READY, "Outlet did not transmit packet")
|
||||
|
||||
with self._lock:
|
||||
self._emplace_envelope(envelope, self._tx_ring)
|
||||
envelope.tries += 1
|
||||
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)
|
||||
self._outlet.set_packet_timeout_callback(envelope.packet, self._packet_timeout, self._get_packet_timeout_time(envelope.tries))
|
||||
self._update_packet_timeouts()
|
||||
already_delivered = (self._outlet.get_packet_state(envelope.packet) == MessageState.MSGSTATE_DELIVERED)
|
||||
|
||||
# prevent _tx_ring envelope leak
|
||||
if already_delivered:
|
||||
self._packet_delivered(envelope.packet)
|
||||
|
||||
return envelope
|
||||
|
||||
@@ -699,7 +729,10 @@ class LinkChannelOutlet(ChannelOutletBase):
|
||||
packet.receipt.set_delivery_callback(inner if callback else None)
|
||||
|
||||
def get_packet_id(self, packet: RNS.Packet) -> any:
|
||||
if packet and hasattr(packet, "get_hash") and callable(packet.get_hash):
|
||||
if (packet
|
||||
and getattr(packet, "raw", None) is not None
|
||||
and hasattr(packet, "get_hash")
|
||||
and callable(packet.get_hash)):
|
||||
return packet.get_hash()
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -65,4 +65,6 @@ def sha512(data):
|
||||
|
||||
def file_sha256(file):
|
||||
if not hashlib: raise SystemError("The hashlib module is not available on this system")
|
||||
# TODO: Could implement fallback for old snakes here
|
||||
if not hasattr(hashlib, "file_digest"): raise SystemError("The file_digest method is not available on this system. This functionality requires Python 3.11 or later.")
|
||||
else: return hashlib.file_digest(file, "sha256").digest()
|
||||
|
||||
+1
-1
@@ -746,7 +746,7 @@ class BlackholeUpdater():
|
||||
if identity_hash in self.last_updates: last_update = self.last_updates[identity_hash]
|
||||
else: last_update = 0
|
||||
|
||||
if now > last_update+self.UPDATE_INTERVAL:
|
||||
if now > last_update+RNS.Reticulum.blackhole_update_interval():
|
||||
try:
|
||||
destination_hash = RNS.Destination.hash_from_name_and_identity("rnstransport.info.blackhole", identity_hash)
|
||||
RNS.log(f"Attempting blackhole list update from {RNS.prettyhexrep(identity_hash)}...", RNS.LOG_DEBUG)
|
||||
|
||||
+33
-10
@@ -127,13 +127,15 @@ class Identity:
|
||||
:returns: An :ref:`RNS.Identity<api-identity>` instance that can be used to create an outgoing :ref:`RNS.Destination<api-destination>`, or *None* if the destination is unknown.
|
||||
"""
|
||||
if from_identity_hash:
|
||||
for destination_hash in Identity.known_destinations:
|
||||
if target_hash == Identity.truncated_hash(Identity.known_destinations[destination_hash][2]):
|
||||
with Identity.known_destinations_lock: destination_hashes = list(Identity.known_destinations.keys())
|
||||
for destination_hash in destination_hashes:
|
||||
entry = Identity.known_destinations.get(destination_hash)
|
||||
if not entry: continue
|
||||
if target_hash == Identity.truncated_hash(entry[2]):
|
||||
if not _no_use: RNS.Reticulum.get_instance()._used_destination_data(destination_hash)
|
||||
identity_data = Identity.known_destinations[destination_hash]
|
||||
identity = Identity(create_keys=False)
|
||||
identity.load_public_key(identity_data[2])
|
||||
identity.app_data = identity_data[3]
|
||||
identity.load_public_key(entry[2])
|
||||
identity.app_data = entry[3]
|
||||
return identity
|
||||
|
||||
return None
|
||||
@@ -212,8 +214,17 @@ class Identity:
|
||||
RNS.log("Skipped recombining known destinations from disk, since an error occurred: "+str(e), RNS.LOG_WARNING)
|
||||
|
||||
RNS.log("Saving "+str(len(Identity.known_destinations))+" known destinations to storage...", RNS.LOG_VERBOSE)
|
||||
with open(RNS.Reticulum.storagepath+"/known_destinations","wb") as file:
|
||||
umsgpack.dump(Identity.known_destinations.copy(), file)
|
||||
temp_file = RNS.Reticulum.storagepath+f"/known_destinations.tmp.{time.time()}"
|
||||
|
||||
try:
|
||||
with open(temp_file,"wb") as file: umsgpack.dump(Identity.known_destinations.copy(), file)
|
||||
os.replace(temp_file, RNS.Reticulum.storagepath+f"/known_destinations")
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Error while serializing and writing known destinations: {e}", RNS.LOG_ERROR)
|
||||
try: os.unlink(temp_file)
|
||||
except Exception as e: RNS.log(f"Could not clean up temporary file {temp_file}: {e}", RNS.LOG_WARNING)
|
||||
raise e
|
||||
|
||||
save_time = time.time() - save_start
|
||||
if save_time < 1: time_str = str(round(save_time*1000,2))+"ms"
|
||||
@@ -285,8 +296,11 @@ class Identity:
|
||||
def _retain_identity(identity_hash):
|
||||
try:
|
||||
retained = False
|
||||
for destination_hash in Identity.known_destinations:
|
||||
if identity_hash == Identity.truncated_hash(Identity.known_destinations[destination_hash][2]):
|
||||
with Identity.known_destinations_lock: destination_hashes = list(Identity.known_destinations.keys())
|
||||
for destination_hash in destination_hashes:
|
||||
entry = Identity.known_destinations.get(destination_hash)
|
||||
if not entry: continue
|
||||
if identity_hash == Identity.truncated_hash(entry[2]):
|
||||
if Identity._retain_destination_data(destination_hash): retained = True
|
||||
|
||||
return retained
|
||||
@@ -302,7 +316,10 @@ class Identity:
|
||||
no_path = 0
|
||||
retained = 0
|
||||
never_used = 0
|
||||
for destination_hash in Identity.known_destinations:
|
||||
ratchetdir = RNS.Reticulum.storagepath+"/ratchets"
|
||||
|
||||
with Identity.known_destinations_lock: destination_hashes = list(Identity.known_destinations.keys())
|
||||
for destination_hash in destination_hashes:
|
||||
try:
|
||||
if RNS.Transport.has_path(destination_hash): has_path = True
|
||||
else:
|
||||
@@ -343,6 +360,12 @@ class Identity:
|
||||
Identity.known_destinations.pop(destination_hash)
|
||||
removed += 1
|
||||
|
||||
try:
|
||||
hexhash = RNS.hexrep(destination_hash, delimit=False)
|
||||
ratchet_path = f"{ratchetdir}/{hexhash}"
|
||||
if os.path.isfile(ratchet_path): os.unlink(ratchet_path)
|
||||
except Exception as e: RNS.log(f"Could not clean stale ratchets for {RNS.prettyhexrep(destination_hash)}: {e}", RNS.LOG_WARNING)
|
||||
|
||||
# RNS.log(f"Total destinations: {total}, stale: {len(stale)}, removed: {removed}, no path: {no_path}, never used: {never_used}, with path: {total-no_path}, used: {total-never_used}, retained: {retained}. Completed in {RNS.prettyshorttime(time.time()-st)}", RNS.LOG_WARNING) # TODO: Remove
|
||||
if not RNS.Transport.owner.is_connected_to_shared_instance: Identity.save_known_destinations(recombine=False)
|
||||
|
||||
|
||||
@@ -428,14 +428,22 @@ class AutoInterface(Interface):
|
||||
if ifname in self.interface_servers:
|
||||
RNS.log("Shutting down previous UDP listener for "+str(self)+" "+str(ifname), RNS.LOG_DEBUG)
|
||||
previous_server = self.interface_servers[ifname]
|
||||
def shutdown_server():
|
||||
previous_server.shutdown()
|
||||
def shutdown_server(): previous_server.shutdown()
|
||||
threading.Thread(target=shutdown_server, daemon=True).start()
|
||||
|
||||
RNS.log("Starting new UDP listener for "+str(self)+" "+str(ifname), RNS.LOG_DEBUG)
|
||||
|
||||
udp_server = socketserver.UDPServer(listen_address, self.handler_factory(self.process_incoming))
|
||||
self.interface_servers[ifname] = udp_server
|
||||
retry_delay = 1.25
|
||||
listener_started = False
|
||||
while not listener_started:
|
||||
try:
|
||||
time.sleep(retry_delay)
|
||||
udp_server = socketserver.UDPServer(listen_address, self.handler_factory(self.process_incoming))
|
||||
self.interface_servers[ifname] = udp_server
|
||||
listener_started = True
|
||||
except Exception as e:
|
||||
RNS.log(f"Could not start new UDP listener for {self} on {listen_address}: {e}", RNS.LOG_WARNING)
|
||||
RNS.log(f"Retrying in {retry_delay} seconds", RNS.LOG_WARNING)
|
||||
|
||||
thread = threading.Thread(target=udp_server.serve_forever)
|
||||
thread.daemon = True
|
||||
|
||||
@@ -775,8 +775,8 @@ class WeaveDevice():
|
||||
self.cpu_load = frame.data[0]
|
||||
self.capture_stats_cpu()
|
||||
elif frame.event == Evt.ET_STAT_MEMORY:
|
||||
self.memory_free = int.from_bytes(frame.data[:4])
|
||||
self.memory_total = int.from_bytes(frame.data[4:])
|
||||
self.memory_free = int.from_bytes(frame.data[:4], "big")
|
||||
self.memory_total = int.from_bytes(frame.data[4:], "big")
|
||||
self.memory_used = self.memory_total-self.memory_free
|
||||
self.memory_used_pct = round((self.memory_used/self.memory_total)*100, 2)
|
||||
self.capture_stats_memory()
|
||||
|
||||
+18
-15
@@ -903,21 +903,21 @@ class Link:
|
||||
identity_string = str(self.get_remote_identity()) if self.get_remote_identity() != None else "<Unknown>"
|
||||
RNS.log("Request "+RNS.prettyhexrep(request_id)+" from "+identity_string+" not allowed for: "+str(path), RNS.LOG_DEBUG)
|
||||
|
||||
def handle_response(self, request_id, response_data, response_size, response_transfer_size, metadata=None):
|
||||
def handle_response(self, request_id, response_data, response_size, response_transfer_size, metadata=None, update_sizes=False):
|
||||
if self.status == Link.ACTIVE:
|
||||
remove = None
|
||||
for pending_request in self.pending_requests:
|
||||
if pending_request.request_id == request_id:
|
||||
remove = pending_request
|
||||
try:
|
||||
pending_request.response_size = response_size
|
||||
if pending_request.response_transfer_size == None:
|
||||
pending_request.response_transfer_size = 0
|
||||
pending_request.response_transfer_size += response_transfer_size
|
||||
pending_request.response_received(response_data, metadata)
|
||||
except Exception as e:
|
||||
RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
if update_sizes:
|
||||
pending_request.response_size = response_size
|
||||
if pending_request.response_transfer_size == None: pending_request.response_transfer_size = 0
|
||||
pending_request.response_transfer_size += response_transfer_size
|
||||
|
||||
pending_request.response_received(response_data, metadata)
|
||||
|
||||
except Exception as e: RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
break
|
||||
|
||||
if remove != None:
|
||||
@@ -1018,12 +1018,15 @@ class Link:
|
||||
identity.load_public_key(public_key)
|
||||
|
||||
if identity.validate(signature, signed_data):
|
||||
self.__remote_identity = identity
|
||||
if self.callbacks.remote_identified != None:
|
||||
try:
|
||||
self.callbacks.remote_identified(self, self.__remote_identity)
|
||||
except Exception as e:
|
||||
RNS.log("Error while executing remote identified callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
if RNS.Reticulum.get_instance().is_blackholed(identity.hash):
|
||||
RNS.log(f"Terminating incoming link from blackholed identity {RNS.prettyhexrep(identity.hash)}", RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
self.teardown()
|
||||
|
||||
else:
|
||||
self.__remote_identity = identity
|
||||
if self.callbacks.remote_identified != None:
|
||||
try: self.callbacks.remote_identified(self, self.__remote_identity)
|
||||
except Exception as e: RNS.log(f"Error while executing remote identified callback from {self}. The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
self.__update_phy_stats(packet, query_shared=True)
|
||||
|
||||
@@ -1047,7 +1050,7 @@ class Link:
|
||||
request_id = unpacked_response[0]
|
||||
response_data = unpacked_response[1]
|
||||
transfer_size = len(umsgpack.packb(response_data))-2
|
||||
def job(): self.handle_response(request_id, response_data, transfer_size, transfer_size)
|
||||
def job(): self.handle_response(request_id, response_data, transfer_size, transfer_size, update_sizes=True)
|
||||
threading.Thread(target=job, daemon=True).start()
|
||||
self.__update_phy_stats(packet, query_shared=True)
|
||||
except Exception as e:
|
||||
|
||||
+101
-69
@@ -48,6 +48,7 @@ else:
|
||||
|
||||
from RNS.vendor.configobj import ConfigObj
|
||||
from threading import Lock
|
||||
import RNS.vendor.umsgpack as mp
|
||||
import configparser
|
||||
import multiprocessing.connection
|
||||
import importlib.util
|
||||
@@ -260,6 +261,7 @@ class Reticulum:
|
||||
Reticulum.__autoconnect_discovered_interfaces = False
|
||||
Reticulum.__required_discovery_value = None
|
||||
Reticulum.__publish_blackhole = False
|
||||
Reticulum.__blackhole_update_interval = RNS.Discovery.BlackholeUpdater.UPDATE_INTERVAL
|
||||
Reticulum.__blackhole_sources = []
|
||||
Reticulum.__interface_sources = []
|
||||
Reticulum.__default_ar_target = None
|
||||
@@ -452,12 +454,12 @@ class Reticulum:
|
||||
value = self.config["logging"][option]
|
||||
if option == "loglevel" and self.requested_loglevel == None:
|
||||
RNS.loglevel = int(value)
|
||||
if self.requested_verbosity != None:
|
||||
RNS.loglevel += self.requested_verbosity
|
||||
if RNS.loglevel < 0:
|
||||
RNS.loglevel = 0
|
||||
if RNS.loglevel > 7:
|
||||
RNS.loglevel = 7
|
||||
if self.requested_verbosity != None: RNS.loglevel += self.requested_verbosity
|
||||
if RNS.loglevel < 0: RNS.loglevel = 0
|
||||
if RNS.loglevel > 7: RNS.loglevel = 7
|
||||
elif option == "logtimestamps":
|
||||
value = self.config["logging"].as_bool(option)
|
||||
RNS.logtimestamps = bool(value)
|
||||
|
||||
if "reticulum" in self.config:
|
||||
for option in self.config["reticulum"]:
|
||||
@@ -581,6 +583,11 @@ class Reticulum:
|
||||
except Exception as e: raise ValueError(f"Invalid identity hash for remote blackhole source: {hexhash}")
|
||||
if not source_identity_hash in Reticulum.__blackhole_sources: Reticulum.__blackhole_sources.append(source_identity_hash)
|
||||
|
||||
if option == "blackhole_update_interval":
|
||||
v = self.config["reticulum"].as_float(option)
|
||||
if v < 2: v = 2
|
||||
Reticulum.__blackhole_update_interval = v*60
|
||||
|
||||
if option == "interface_discovery_sources":
|
||||
v = self.config["reticulum"].as_list(option)
|
||||
for hexhash in v:
|
||||
@@ -662,6 +669,9 @@ class Reticulum:
|
||||
self.shared_instance_type = "tcp"
|
||||
self.use_af_unix = False
|
||||
|
||||
if self.shared_instance_type == "tcp":
|
||||
self.local_socket_path = None
|
||||
|
||||
if self.local_socket_path == None and self.use_af_unix:
|
||||
self.local_socket_path = "default"
|
||||
|
||||
@@ -1173,59 +1183,63 @@ class Reticulum:
|
||||
os.makedirs(Reticulum.configdir)
|
||||
self.config.write()
|
||||
|
||||
def rpc_return(self, connection, response):
|
||||
connection.send_bytes(mp.packb(response))
|
||||
|
||||
def rpc_loop(self):
|
||||
while RNS.Transport._should_run:
|
||||
try:
|
||||
rpc_connection = self.rpc_listener.accept()
|
||||
call = rpc_connection.recv()
|
||||
conn = self.rpc_listener.accept()
|
||||
call = mp.unpackb(conn.recv_bytes())
|
||||
|
||||
if "get" in call:
|
||||
path = call["get"]
|
||||
|
||||
if path == "path_table":
|
||||
mh = call["max_hops"]
|
||||
rpc_connection.send(self.get_path_table(max_hops=mh))
|
||||
self.rpc_return(conn, self.get_path_table(max_hops=mh))
|
||||
|
||||
if path == "interface_stats": rpc_connection.send(self.get_interface_stats())
|
||||
if path == "rate_table": rpc_connection.send(self.get_rate_table())
|
||||
if path == "next_hop_if_name": rpc_connection.send(self.get_next_hop_if_name(call["destination_hash"]))
|
||||
if path == "next_hop": rpc_connection.send(self.get_next_hop(call["destination_hash"]))
|
||||
if path == "first_hop_timeout": rpc_connection.send(self.get_first_hop_timeout(call["destination_hash"]))
|
||||
if path == "link_count": rpc_connection.send(self.get_link_count())
|
||||
if path == "packet_rssi": rpc_connection.send(self.get_packet_rssi(call["packet_hash"]))
|
||||
if path == "packet_snr": rpc_connection.send(self.get_packet_snr(call["packet_hash"]))
|
||||
if path == "packet_q": rpc_connection.send(self.get_packet_q(call["packet_hash"]))
|
||||
if path == "blackholed_identities": rpc_connection.send(self.get_blackholed_identities())
|
||||
if path == "interface_stats": self.rpc_return(conn, self.get_interface_stats())
|
||||
if path == "rate_table": self.rpc_return(conn, self.get_rate_table())
|
||||
if path == "next_hop_if_name": self.rpc_return(conn, self.get_next_hop_if_name(call["destination_hash"]))
|
||||
if path == "next_hop": self.rpc_return(conn, self.get_next_hop(call["destination_hash"]))
|
||||
if path == "first_hop_timeout": self.rpc_return(conn, self.get_first_hop_timeout(call["destination_hash"]))
|
||||
if path == "link_count": self.rpc_return(conn, self.get_link_count())
|
||||
if path == "packet_rssi": self.rpc_return(conn, self.get_packet_rssi(call["packet_hash"]))
|
||||
if path == "packet_snr": self.rpc_return(conn, self.get_packet_snr(call["packet_hash"]))
|
||||
if path == "packet_q": self.rpc_return(conn, self.get_packet_q(call["packet_hash"]))
|
||||
if path == "blackholed_identities": self.rpc_return(conn, self.get_blackholed_identities())
|
||||
if path == "is_blackholed": self.rpc_return(conn, self.is_blackholed(call["identity_hash"]))
|
||||
|
||||
if "drop" in call:
|
||||
path = call["drop"]
|
||||
if path == "path": rpc_connection.send(self.drop_path(call["destination_hash"]))
|
||||
if path == "all_via": rpc_connection.send(self.drop_all_via(call["destination_hash"]))
|
||||
if path == "announce_queues": rpc_connection.send(self.drop_announce_queues())
|
||||
if path == "path": self.rpc_return(conn, self.drop_path(call["destination_hash"]))
|
||||
if path == "all_via": self.rpc_return(conn, self.drop_all_via(call["destination_hash"]))
|
||||
if path == "announce_queues": self.rpc_return(conn, self.drop_announce_queues())
|
||||
|
||||
if "blackhole_identity" in call:
|
||||
identity_hash = call["blackhole_identity"]
|
||||
until = call["until"]
|
||||
reason = call["reason"]
|
||||
rpc_connection.send(self.blackhole_identity(identity_hash, until=until, reason=reason))
|
||||
self.rpc_return(conn, self.blackhole_identity(identity_hash, until=until, reason=reason))
|
||||
|
||||
if "unblackhole_identity" in call:
|
||||
identity_hash = call["unblackhole_identity"]
|
||||
rpc_connection.send(self.unblackhole_identity(identity_hash))
|
||||
self.rpc_return(conn, self.unblackhole_identity(identity_hash))
|
||||
|
||||
if "destination_data" in call:
|
||||
operation = call["destination_data"]
|
||||
destination_hash = call["destination_hash"]
|
||||
if operation == "used": rpc_connection.send(self._used_destination_data(destination_hash))
|
||||
elif operation == "retain": rpc_connection.send(self._retain_destination_data(destination_hash))
|
||||
elif operation == "unretain": rpc_connection.send(self._unretain_destination_data(destination_hash))
|
||||
if operation == "used": self.rpc_return(conn, self._used_destination_data(destination_hash))
|
||||
elif operation == "retain": self.rpc_return(conn, self._retain_destination_data(destination_hash))
|
||||
elif operation == "unretain": self.rpc_return(conn, self._unretain_destination_data(destination_hash))
|
||||
|
||||
if "identity_data" in call:
|
||||
operation = call["identity_data"]
|
||||
identity_hash = call["identity_hash"]
|
||||
if operation == "retain": rpc_connection.send(self._retain_identity(identity_hash))
|
||||
if operation == "retain": self.rpc_return(conn, self._retain_identity(identity_hash))
|
||||
|
||||
rpc_connection.close()
|
||||
conn.close()
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("An error ocurred while handling RPC call from local client: "+str(e), RNS.LOG_ERROR)
|
||||
@@ -1236,8 +1250,8 @@ class Reticulum:
|
||||
if self.is_connected_to_shared_instance:
|
||||
try:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"destination_data": "used", "destination_hash": destination_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"destination_data": "used", "destination_hash": destination_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
@@ -1250,8 +1264,8 @@ class Reticulum:
|
||||
if self.is_connected_to_shared_instance:
|
||||
try:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"destination_data": "retain", "destination_hash": destination_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"destination_data": "retain", "destination_hash": destination_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
@@ -1264,8 +1278,8 @@ class Reticulum:
|
||||
if self.is_connected_to_shared_instance:
|
||||
try:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"destination_data": "unretain", "destination_hash": destination_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"destination_data": "unretain", "destination_hash": destination_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
@@ -1281,8 +1295,8 @@ class Reticulum:
|
||||
if self.is_connected_to_shared_instance:
|
||||
try:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"identity_data": "retain", "identity_hash": identity_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"identity_data": "retain", "identity_hash": identity_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
@@ -1294,8 +1308,8 @@ class Reticulum:
|
||||
def get_interface_stats(self):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "interface_stats"})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "interface_stats"}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
else:
|
||||
interfaces = []
|
||||
@@ -1484,8 +1498,8 @@ class Reticulum:
|
||||
def get_path_table(self, max_hops=None):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "path_table", "max_hops": max_hops})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "path_table", "max_hops": max_hops}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1508,8 +1522,8 @@ class Reticulum:
|
||||
def get_rate_table(self):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "rate_table"})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "rate_table"}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1529,8 +1543,8 @@ class Reticulum:
|
||||
def drop_path(self, destination):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"drop": "path", "destination_hash": destination})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"drop": "path", "destination_hash": destination}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1539,8 +1553,8 @@ class Reticulum:
|
||||
def drop_all_via(self, transport_hash):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"drop": "all_via", "destination_hash": transport_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"drop": "all_via", "destination_hash": transport_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1555,8 +1569,8 @@ class Reticulum:
|
||||
def drop_announce_queues(self):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"drop": "announce_queues"})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"drop": "announce_queues"}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1565,8 +1579,8 @@ class Reticulum:
|
||||
def get_next_hop_if_name(self, destination):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "next_hop_if_name", "destination_hash": destination})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "next_hop_if_name", "destination_hash": destination}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1576,8 +1590,8 @@ class Reticulum:
|
||||
if self.is_connected_to_shared_instance:
|
||||
try:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "first_hop_timeout", "destination_hash": destination})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "first_hop_timeout", "destination_hash": destination}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
|
||||
if self.is_connected_to_shared_instance and hasattr(self, "_force_shared_instance_bitrate") and self._force_shared_instance_bitrate:
|
||||
simulated_latency = ((1/self._force_shared_instance_bitrate)*8)*RNS.Reticulum.MTU
|
||||
@@ -1595,8 +1609,8 @@ class Reticulum:
|
||||
def get_next_hop(self, destination):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "next_hop", "destination_hash": destination})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "next_hop", "destination_hash": destination}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
|
||||
return response
|
||||
|
||||
@@ -1606,8 +1620,8 @@ class Reticulum:
|
||||
def get_link_count(self):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "link_count"})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "link_count"}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1616,8 +1630,8 @@ class Reticulum:
|
||||
def get_packet_rssi(self, packet_hash):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "packet_rssi", "packet_hash": packet_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "packet_rssi", "packet_hash": packet_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1630,8 +1644,8 @@ class Reticulum:
|
||||
def get_packet_snr(self, packet_hash):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "packet_snr", "packet_hash": packet_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "packet_snr", "packet_hash": packet_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1644,8 +1658,8 @@ class Reticulum:
|
||||
def get_packet_q(self, packet_hash):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "packet_q", "packet_hash": packet_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "packet_q", "packet_hash": packet_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else:
|
||||
@@ -1667,19 +1681,33 @@ class Reticulum:
|
||||
def get_blackholed_identities(self):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"get": "blackholed_identities"})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "blackholed_identities"}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else: return RNS.Transport.blackholed_identities
|
||||
|
||||
def is_blackholed(self, identity):
|
||||
if type(identity) == RNS.Identity: identity_hash = identity.hash
|
||||
elif type(identity) == bytes: identity_hash = identity
|
||||
else: raise TypeError("Invalid identity for blackhole check, must be hash as bytes or RNS.Identity")
|
||||
if len(identity_hash) != RNS.Reticulum.TRUNCATED_HASHLENGTH//8: raise ValueError("Invalid identity hash length for blackhole check")
|
||||
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send_bytes(mp.packb({"get": "is_blackholed", "identity_hash": identity_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else: return identity_hash in RNS.Transport.blackholed_identities
|
||||
|
||||
def blackhole_identity(self, identity_hash, until=None, reason=None):
|
||||
if len(identity_hash) != RNS.Reticulum.TRUNCATED_HASHLENGTH//8: return False
|
||||
else:
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"blackhole_identity": identity_hash, "until": until, "reason": reason})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"blackhole_identity": identity_hash, "until": until, "reason": reason}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else: return RNS.Transport.blackhole_identity(identity_hash, until=until, reason=reason)
|
||||
@@ -1689,8 +1717,8 @@ class Reticulum:
|
||||
else:
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = self.get_rpc_client()
|
||||
rpc_connection.send({"unblackhole_identity": identity_hash})
|
||||
response = rpc_connection.recv()
|
||||
rpc_connection.send_bytes(mp.packb({"unblackhole_identity": identity_hash}))
|
||||
response = mp.unpackb(rpc_connection.recv_bytes())
|
||||
return response
|
||||
|
||||
else: return RNS.Transport.unblackhole_identity(identity_hash)
|
||||
@@ -1779,6 +1807,10 @@ class Reticulum:
|
||||
"""
|
||||
return Reticulum.__blackhole_sources
|
||||
|
||||
@staticmethod
|
||||
def blackhole_update_interval():
|
||||
return Reticulum.__blackhole_update_interval
|
||||
|
||||
@staticmethod
|
||||
def discovered_interfaces():
|
||||
"""
|
||||
|
||||
+25
-9
@@ -212,6 +212,7 @@ class Transport:
|
||||
@staticmethod
|
||||
def start(reticulum_instance):
|
||||
Transport.owner = reticulum_instance
|
||||
Transport.PR_LOGLEVEL = RNS.LOG_EXTREME
|
||||
|
||||
if Transport.identity == None:
|
||||
transport_identity_path = RNS.Reticulum.storagepath+"/transport_identity"
|
||||
@@ -289,6 +290,7 @@ class Transport:
|
||||
if RNS.Reticulum.transport_enabled():
|
||||
path_table_path = RNS.Reticulum.storagepath+"/destination_table"
|
||||
tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels"
|
||||
Transport.PR_LOGLEVEL = RNS.LOG_DEBUG
|
||||
|
||||
if os.path.isfile(path_table_path) and not Transport.owner.is_connected_to_shared_instance:
|
||||
serialised_destinations = []
|
||||
@@ -805,7 +807,7 @@ class Transport:
|
||||
if time.time() > entry["timeout"]:
|
||||
stale_discovery_path_requests.append(destination_hash)
|
||||
should_collect = True
|
||||
RNS.log("Waiting path request for "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
RNS.log("Waiting path request for "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_EXTREME) if RNS.sl(RNS.LOG_EXTREME) else None
|
||||
|
||||
# Cull the tunnel table
|
||||
stale_tunnels = []; ti = 0
|
||||
@@ -1753,6 +1755,7 @@ class Transport:
|
||||
random_blob = packet.data[RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8+10]
|
||||
random_blobs = []
|
||||
with Transport.inbound_announce_lock:
|
||||
announced_destination_known |= packet.destination_hash in Transport.path_table
|
||||
if announced_destination_known:
|
||||
random_blobs = Transport.path_table[packet.destination_hash][IDX_PT_RANDBLOBS]
|
||||
|
||||
@@ -1825,7 +1828,6 @@ class Transport:
|
||||
else:
|
||||
# If this destination is unknown in our table
|
||||
# we should add it
|
||||
Transport.mark_path_unknown_state(packet.destination_hash)
|
||||
should_add = True
|
||||
|
||||
if should_add:
|
||||
@@ -1984,7 +1986,7 @@ class Transport:
|
||||
|
||||
interface_str = " on "+str(attached_interface)
|
||||
|
||||
RNS.log("Got matching announce, answering waiting discovery path request for "+RNS.prettyhexrep(packet.destination_hash)+interface_str, RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
RNS.log("Got matching announce, answering waiting discovery path request for "+RNS.prettyhexrep(packet.destination_hash)+interface_str, Transport.PR_LOGLEVEL) if RNS.sl(Transport.PR_LOGLEVEL) else None
|
||||
announce_identity = RNS.Identity.recall(packet.destination_hash, _no_use=False)
|
||||
announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
|
||||
announce_destination.hash = packet.destination_hash
|
||||
@@ -2902,7 +2904,7 @@ class Transport:
|
||||
tag=tag_bytes)
|
||||
|
||||
else: RNS.log("Ignoring duplicate path request for "+RNS.prettyhexrep(destination_hash)+" with tag "+RNS.prettyhexrep(unique_tag), RNS.LOG_EXTREME) if RNS.sl(RNS.LOG_EXTREME) else None
|
||||
else: RNS.log("Ignoring tagless path request for "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
else: RNS.log("Ignoring tagless path request for "+RNS.prettyhexrep(destination_hash), Transport.PR_LOGLEVEL) if RNS.sl(Transport.PR_LOGLEVEL) else None
|
||||
except Exception as e: RNS.log(f"Error while handling path request. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
|
||||
@staticmethod
|
||||
@@ -2917,7 +2919,7 @@ class Transport:
|
||||
|
||||
if RNS.sl(RNS.LOG_DEBUG):
|
||||
interface_str = f" on {attached_interface}"
|
||||
RNS.log(f"Path request for {RNS.prettyhexrep(destination_hash)}{interface_str}", RNS.LOG_DEBUG)
|
||||
RNS.log(f"Path request for {RNS.prettyhexrep(destination_hash)}{interface_str}", Transport.PR_LOGLEVEL)
|
||||
|
||||
destination_exists_on_local_client = False
|
||||
if len(Transport.local_client_interfaces) > 0:
|
||||
@@ -2962,7 +2964,7 @@ class Transport:
|
||||
# convergence time. Maybe just drop it?
|
||||
RNS.log("Not answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", since next hop is the requestor", RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
else:
|
||||
RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", path is known", RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", path is known", Transport.PR_LOGLEVEL) if RNS.sl(Transport.PR_LOGLEVEL) else None
|
||||
|
||||
now = time.time()
|
||||
retries = Transport.PATHFINDER_R
|
||||
@@ -3004,7 +3006,7 @@ class Transport:
|
||||
elif is_from_local_client:
|
||||
# Forward path request on all interfaces
|
||||
# except the local client
|
||||
RNS.log("Forwarding path request from local client for "+RNS.prettyhexrep(destination_hash)+interface_str+" to all other interfaces", RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
RNS.log("Forwarding path request from local client for "+RNS.prettyhexrep(destination_hash)+interface_str+" to all other interfaces", Transport.PR_LOGLEVEL) if RNS.sl(Transport.PR_LOGLEVEL) else None
|
||||
request_tag = RNS.Identity.get_random_hash()
|
||||
for interface in Transport.interfaces:
|
||||
if not interface == attached_interface:
|
||||
@@ -3041,12 +3043,12 @@ class Transport:
|
||||
elif not is_from_local_client and len(Transport.local_client_interfaces) > 0:
|
||||
# Forward the path request on all local
|
||||
# client interfaces
|
||||
RNS.log("Forwarding path request for "+RNS.prettyhexrep(destination_hash)+interface_str+" to local clients", RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
RNS.log("Forwarding path request for "+RNS.prettyhexrep(destination_hash)+interface_str+" to local clients", Transport.PR_LOGLEVEL) if RNS.sl(Transport.PR_LOGLEVEL) else None
|
||||
for interface in Transport.local_client_interfaces:
|
||||
Transport.request_path(destination_hash, on_interface=interface)
|
||||
|
||||
else:
|
||||
RNS.log("Ignoring path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", no path known", RNS.LOG_DEBUG) if RNS.sl(RNS.LOG_DEBUG) else None
|
||||
RNS.log("Ignoring path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", no path known", Transport.PR_LOGLEVEL) if RNS.sl(Transport.PR_LOGLEVEL) else None
|
||||
|
||||
@staticmethod
|
||||
def from_local_client(packet):
|
||||
@@ -3405,6 +3407,14 @@ class Transport:
|
||||
|
||||
@staticmethod
|
||||
def blackhole_identity(identity_hash, until=None, reason=None):
|
||||
"""
|
||||
Blackholes an identity.
|
||||
|
||||
:param identity_hash: The identity hash to blackhole as *bytes*.
|
||||
:param until: Optional unix timestamp of when the blackhole expires as *float* or *int*.
|
||||
:param reason: Optional reason for the blackhole as *str*.
|
||||
:returns: *True* if successful, otherwise *False*.
|
||||
"""
|
||||
try:
|
||||
if not identity_hash in Transport.blackholed_identities:
|
||||
entry = {"source": Transport.identity.hash, "until": until, "reason": reason}
|
||||
@@ -3422,6 +3432,12 @@ class Transport:
|
||||
|
||||
@staticmethod
|
||||
def unblackhole_identity(identity_hash):
|
||||
"""
|
||||
Lifts blackhole for an identity.
|
||||
|
||||
:param identity_hash: The identity hash to blackhole as *bytes*.
|
||||
:returns: *True* if successful, otherwise *False*.
|
||||
"""
|
||||
try:
|
||||
if identity_hash in Transport.blackholed_identities:
|
||||
Transport.blackholed_identities.pop(identity_hash)
|
||||
|
||||
Executable
+324
@@ -0,0 +1,324 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Reticulum License
|
||||
#
|
||||
# Copyright (c) 2016-2026 Mark Qvist
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# - The Software shall not be used in any kind of system which includes amongst
|
||||
# its functions the ability to purposefully do harm to human beings.
|
||||
#
|
||||
# - The Software shall not be used, directly or indirectly, in the creation of
|
||||
# an artificial intelligence, machine learning or language model training
|
||||
# dataset, including but not limited to any use that contributes to the
|
||||
# training or development of such a model or algorithm.
|
||||
#
|
||||
# - The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# 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.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import RNS
|
||||
import struct
|
||||
import base64
|
||||
import argparse
|
||||
|
||||
from RNS.Utilities.rnid import validate_rsg, create_rsg, extract_signed_rsg_data
|
||||
|
||||
SSHSIG_MAGIC = b"SSHSIG"
|
||||
SSHSIG_VERSION = 1
|
||||
NAMESPACE_GIT = b"git"
|
||||
RESERVED_EMPTY = b""
|
||||
HASH_ALGORITHM = b"sha256"
|
||||
|
||||
def ssh_string(data): return struct.pack(">I", len(data)) + data
|
||||
|
||||
def read_ssh_string(data, offset):
|
||||
if offset + 4 > len(data): raise ValueError("Not enough data for string length")
|
||||
length = struct.unpack(">I", data[offset:offset+4])[0]
|
||||
if offset + 4 + length > len(data): raise ValueError("Not enough data for string content")
|
||||
return data[offset+4:offset+4+length], offset + 4 + length
|
||||
|
||||
def create_ssh_signature(public_key_wire, namespace, reserved, hash_algorithm, signature_data):
|
||||
# SSHSIG (6 bytes) || version (uint32) || pubkey (ssh-string) || namespace (ssh-string) ||
|
||||
# reserved (ssh-string) || hash_algorithm (ssh-string) || signature (ssh-string)
|
||||
sig_blob = SSHSIG_MAGIC
|
||||
sig_blob += struct.pack(">I", SSHSIG_VERSION)
|
||||
sig_blob += ssh_string(public_key_wire)
|
||||
sig_blob += ssh_string(namespace)
|
||||
sig_blob += ssh_string(reserved)
|
||||
sig_blob += ssh_string(hash_algorithm)
|
||||
sig_blob += ssh_string(signature_data)
|
||||
return sig_blob
|
||||
|
||||
def parse_ssh_signature(sig_data):
|
||||
offset = 0
|
||||
|
||||
if not sig_data.startswith(SSHSIG_MAGIC): raise ValueError("Invalid SSH signature: missing SSHSIG magic")
|
||||
offset += len(SSHSIG_MAGIC)
|
||||
|
||||
if offset + 4 > len(sig_data): raise ValueError("Invalid SSH signature: truncated")
|
||||
version = struct.unpack(">I", sig_data[offset:offset+4])[0]
|
||||
if version != SSHSIG_VERSION: raise ValueError(f"Unsupported SSH signature version: {version}")
|
||||
offset += 4
|
||||
|
||||
public_key, offset = read_ssh_string(sig_data, offset)
|
||||
namespace, offset = read_ssh_string(sig_data, offset)
|
||||
reserved, offset = read_ssh_string(sig_data, offset)
|
||||
hash_algorithm, offset = read_ssh_string(sig_data, offset)
|
||||
signature_data, offset = read_ssh_string(sig_data, offset)
|
||||
|
||||
return { "version": version,
|
||||
"public_key": public_key,
|
||||
"namespace": namespace,
|
||||
"reserved": reserved,
|
||||
"hash_algorithm": hash_algorithm,
|
||||
"signature_data": signature_data }
|
||||
|
||||
def armor_ssh_signature(sig_blob):
|
||||
b64_data = base64.b64encode(sig_blob).decode('ascii')
|
||||
lines = [b64_data[i:i+70] for i in range(0, len(b64_data), 70)]
|
||||
|
||||
result = "-----BEGIN SSH SIGNATURE-----\n"
|
||||
result += "\n".join(lines) + "\n"
|
||||
result += "-----END SSH SIGNATURE-----\n"
|
||||
return result
|
||||
|
||||
def unarmor_ssh_signature(armored_data):
|
||||
lines = armored_data.strip().split('\n')
|
||||
b64_data = ""
|
||||
in_sig = False
|
||||
|
||||
for line in lines:
|
||||
if 'BEGIN SSH SIGNATURE' in line: in_sig = True; continue
|
||||
if 'END SSH SIGNATURE' in line: break
|
||||
if in_sig: b64_data += line.strip()
|
||||
|
||||
if not b64_data: raise ValueError("No signature data found in armored input")
|
||||
|
||||
return base64.b64decode(b64_data)
|
||||
|
||||
def get_pubkey_wire_format(identity):
|
||||
return ssh_string(b"ssh-ed25519")+ssh_string(identity.sig_pub_bytes)
|
||||
|
||||
def sign(args):
|
||||
keyfile = args.keyfile
|
||||
if not keyfile or not os.path.isfile(keyfile):
|
||||
print(f"Identity file not found: {keyfile}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
identity = RNS.Identity.from_file(keyfile)
|
||||
if not identity or not identity.get_private_key():
|
||||
print("Error: Could not load identity or identity has no private key", file=sys.stderr)
|
||||
return 1
|
||||
except Exception as e:
|
||||
print(f"Error loading identity: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.file and os.path.isfile(args.file):
|
||||
with open(args.file, 'rb') as f: message = f.read()
|
||||
sig_file = args.file + ".sig"
|
||||
else:
|
||||
message = sys.stdin.buffer.read()
|
||||
sig_file = None
|
||||
|
||||
try: rsg = create_rsg(identity, message)
|
||||
except Exception as e:
|
||||
print(f"Error creating signature: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try: ssh_pubkey = get_pubkey_wire_format(identity)
|
||||
except Exception as e:
|
||||
print(f"Error converting public key: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try:
|
||||
ssh_sig = create_ssh_signature(public_key_wire=ssh_pubkey, namespace=NAMESPACE_GIT, reserved=RESERVED_EMPTY,
|
||||
hash_algorithm=HASH_ALGORITHM, signature_data=rsg)
|
||||
except Exception as e:
|
||||
print(f"Error creating SSH signature: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
try: armored = armor_ssh_signature(ssh_sig)
|
||||
except Exception as e:
|
||||
print(f"Error armoring signature: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if sig_file:
|
||||
try:
|
||||
with open(sig_file, 'w') as f: f.write(armored)
|
||||
except Exception as e:
|
||||
print(f"Error writing signature file: {e}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
else: print(armored, end="")
|
||||
|
||||
return 0
|
||||
|
||||
def find_principals(args):
|
||||
sigfile = args.sigfile
|
||||
if not sigfile or not os.path.isfile(sigfile): print("Error: Signature file not found", file=sys.stderr); return 1
|
||||
|
||||
try:
|
||||
with open(sigfile, 'r') as f: armored_sig = f.read()
|
||||
except Exception as e: print(f"Error reading signature file: {e}", file=sys.stderr); return 1
|
||||
|
||||
try: ssh_sig = parse_ssh_signature(unarmor_ssh_signature(armored_sig))
|
||||
except Exception as e: print(f"Error parsing SSH signature: {e}", file=sys.stderr); return 1
|
||||
|
||||
if ssh_sig["namespace"] != NAMESPACE_GIT:
|
||||
print(f"Error: Namespace mismatch: {ssh_sig['namespace']}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
rsg = ssh_sig["signature_data"]
|
||||
try: identity_hash = extract_signed_rsg_data(rsg)["meta"]["signer"]
|
||||
except Exception as e: print(f"Could not determine signer identity: {e}", file=sys.stderr); return 1
|
||||
|
||||
print(RNS.hexrep(identity_hash, delimit=False))
|
||||
return 0
|
||||
|
||||
def check_novalidate(args):
|
||||
sigfile = args.sigfile
|
||||
if not sigfile or not os.path.isfile(sigfile): return 1
|
||||
|
||||
try:
|
||||
with open(sigfile, 'r') as f: armored_sig = f.read()
|
||||
ssh_sig = parse_ssh_signature(unarmor_ssh_signature(armored_sig))
|
||||
|
||||
if ssh_sig["namespace"] != NAMESPACE_GIT: return 1
|
||||
|
||||
rsg = ssh_sig["signature_data"]
|
||||
signed_data = extract_signed_rsg_data(rsg)
|
||||
if not signed_data: return 1
|
||||
else: return 0
|
||||
|
||||
except Exception: return 1
|
||||
|
||||
def extract_commit_author(message):
|
||||
message_lines = message.splitlines()
|
||||
author = ""
|
||||
AUTHOR_TARGET = b"author "
|
||||
for line in message_lines:
|
||||
if not line.strip(b""): break
|
||||
elif line.startswith(AUTHOR_TARGET):
|
||||
try:
|
||||
spos = line.find(b"<"); epos = line.find(b">")
|
||||
if spos > len(AUTHOR_TARGET) and epos > spos and epos < len(line)-1:
|
||||
author = line[spos+1:epos].decode("utf-8")
|
||||
break
|
||||
except Exception as e: print(f"Error while determining author from signed commit"); return 1
|
||||
|
||||
return author
|
||||
|
||||
def extract_commit_committer(message):
|
||||
message_lines = message.splitlines()
|
||||
committer = ""
|
||||
COMMITTER_TARGET = b"committer "
|
||||
for line in message_lines:
|
||||
if not line.strip(b""): break
|
||||
elif line.startswith(COMMITTER_TARGET):
|
||||
try:
|
||||
spos = line.find(b"<"); epos = line.find(b">")
|
||||
if spos > len(COMMITTER_TARGET) and epos > spos and epos < len(line)-1:
|
||||
committer = line[spos+1:epos].decode("utf-8")
|
||||
break
|
||||
except Exception as e: print(f"Error while determining committer from signed commit"); return 1
|
||||
|
||||
return committer
|
||||
|
||||
def extract_commit_tagger(message):
|
||||
message_lines = message.splitlines()
|
||||
tagger = ""
|
||||
is_tag = False
|
||||
for line in message_lines:
|
||||
TAG_TARGET = b"tag "
|
||||
TAGGER_TARGET = b"tagger "
|
||||
if not line.strip(b""): break
|
||||
elif line.startswith(TAG_TARGET): is_tag = True
|
||||
elif line.startswith(TAGGER_TARGET) and is_tag:
|
||||
try:
|
||||
spos = line.find(b"<"); epos = line.find(b">")
|
||||
if spos > len(TAGGER_TARGET) and epos > spos and epos < len(line)-1:
|
||||
tagger = line[spos+1:epos].decode("utf-8")
|
||||
break
|
||||
except Exception as e: print(f"Error while determining tagger from signed commit"); return 1
|
||||
|
||||
return tagger, is_tag
|
||||
|
||||
def verify(args):
|
||||
sigfile = args.sigfile
|
||||
principal = args.principal
|
||||
if not sigfile or not os.path.isfile(sigfile): print("Error: Signature file not found", file=sys.stderr); return 1
|
||||
|
||||
message = sys.stdin.buffer.read()
|
||||
|
||||
try:
|
||||
with open(sigfile, 'r') as f: armored_sig = f.read()
|
||||
raw_sig = unarmor_ssh_signature(armored_sig)
|
||||
ssh_sig = parse_ssh_signature(raw_sig)
|
||||
|
||||
except Exception as e: print(f"Error parsing signature: {e}", file=sys.stderr); return 1
|
||||
|
||||
author = extract_commit_author(message)
|
||||
committer = extract_commit_committer(message)
|
||||
tagger, is_tag = extract_commit_tagger(message)
|
||||
|
||||
if ssh_sig["namespace"] != NAMESPACE_GIT: print(f"Invalid commit signature namespace", file=sys.stderr); return 1
|
||||
|
||||
rsg = ssh_sig["signature_data"]
|
||||
valid, signed_data, signing_identity = validate_rsg(rsg, message)
|
||||
|
||||
if not valid: print(f"Invalid signature", file=sys.stderr); return 1
|
||||
|
||||
if is_tag: author = tagger
|
||||
|
||||
signer_hash = RNS.hexrep(signing_identity.hash, delimit=False)
|
||||
if not author == signer_hash: print(f"Commit not signed by author <{author}>"); return 1
|
||||
|
||||
if principal:
|
||||
if principal != signer_hash: print(f"Principal mismatch", file=sys.stderr); return 1
|
||||
|
||||
print(f"Good \"git\" signature for commit, signed with Reticulum Identity key <{signer_hash}>")
|
||||
return 0
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Git commit signer and validator")
|
||||
parser.add_argument("-Y", dest="op", required=True, choices=["sign", "find-principals", "check-novalidate", "verify"], help="Operation to perform")
|
||||
parser.add_argument("-n", dest="namespace", default="git", help="Namespace")
|
||||
parser.add_argument("-f", dest="keyfile", help="Key file (for signing) or allowed signers file (for verification)")
|
||||
parser.add_argument("-I", dest="principal", help="Principal identity (for verification)")
|
||||
parser.add_argument("-s", dest="sigfile", help="Signature file")
|
||||
parser.add_argument("file", nargs="?", help="File to sign (for signing)")
|
||||
parser.add_argument("-O", dest="ssh_options", action="append", default=[], help="SSH options (for git compatibility, ignored)")
|
||||
|
||||
args, unknown = parser.parse_known_args()
|
||||
for arg in unknown:
|
||||
if arg.startswith('-O'): continue # TODO: Add options for time validation
|
||||
else:
|
||||
print(f"Error: Unknown argument: {arg}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if args.op == "sign": return sign(args)
|
||||
elif args.op == "find-principals": return find_principals(args)
|
||||
elif args.op == "check-novalidate": return check_novalidate(args)
|
||||
elif args.op == "verify": return verify(args)
|
||||
else:
|
||||
print(f"Error: Unknown operation: {args.op}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__": sys.exit(main())
|
||||
+121
-12
@@ -34,6 +34,8 @@ import threading
|
||||
import subprocess
|
||||
import urllib.parse
|
||||
import RNS
|
||||
import struct
|
||||
import base64
|
||||
from collections import deque
|
||||
from datetime import datetime
|
||||
from RNS.Utilities.rngit import APP_NAME
|
||||
@@ -42,6 +44,8 @@ from RNS.Utilities.rngit.highlight import SyntaxHighlighter
|
||||
from RNS.vendor.configobj import ConfigObj
|
||||
from RNS.vendor import umsgpack as mp
|
||||
from RNS._version import __version__
|
||||
from RNS.Utilities.rnid import validate_rsg, extract_signed_rsg_data
|
||||
from RNS.Utilities.rngit.commitsigs import unarmor_ssh_signature, parse_ssh_signature, extract_commit_author
|
||||
|
||||
class NomadNetworkNode():
|
||||
APP_NAME = "nomadnetwork"
|
||||
@@ -864,7 +868,7 @@ class NomadNetworkNode():
|
||||
author = commit["author"]
|
||||
date = self.format_absolute_time(commit["timestamp"])+" - "+self.format_relative_time(commit["timestamp"])
|
||||
|
||||
hash_link = self.m_link(short_hash, self.PATH_COMMIT, g=group_name, r=repo_name, h=commit["hash"])
|
||||
hash_link = self.m_link(short_hash, self.PATH_COMMIT, g=group_name, r=repo_name, ref=ref, h=commit["hash"])
|
||||
|
||||
content_parts.append(f"`F66d{hash_link}`f {self.m_escape(author)} {self.CLR_DIM}{date}`f\n")
|
||||
content_parts.append(f"{self.m_escape(subject)}\n\n")
|
||||
@@ -891,6 +895,7 @@ class NomadNetworkNode():
|
||||
if not data or not type(data) == dict: data = {}
|
||||
group_name = data.get("var_g", "") if data else ""
|
||||
repo_name = data.get("var_r", "") if data else ""
|
||||
ref = data.get("var_ref", "HEAD") if data else "HEAD"
|
||||
commit_hash = data.get("var_h", "") if data else ""
|
||||
|
||||
if not group_name or not repo_name:
|
||||
@@ -904,6 +909,12 @@ class NomadNetworkNode():
|
||||
|
||||
repo_path = repo["path"]
|
||||
|
||||
# Validate ref exists
|
||||
resolved_ref = self.resolve_ref(repo_path, ref)
|
||||
if not resolved_ref:
|
||||
content = self.m_heading("Ref Not Found", 1) + f"\n\nThe ref '{ref}' does not exist in this repository.\n"
|
||||
return self.render_template(content, st=st)
|
||||
|
||||
# Validate commit hash
|
||||
if not commit_hash or len(commit_hash) < 7:
|
||||
content = self.m_heading("Error", 2) + "\nNo valid commit hash specified.\n"
|
||||
@@ -917,7 +928,7 @@ class NomadNetworkNode():
|
||||
|
||||
# Breadcrumb navigation
|
||||
nav_parts = []
|
||||
breadcrumb = f"{self.m_link('Node', self.PATH_INDEX)} / {self.m_link(group_name, self.PATH_GROUP, g=group_name)} / {self.m_link(repo_name, self.PATH_REPO, g=group_name, r=repo_name)} / {resolved_hash[:7]}"
|
||||
breadcrumb = f"{self.m_link('Node', self.PATH_INDEX)} / {self.m_link(group_name, self.PATH_GROUP, g=group_name)} / {self.m_link(repo_name, self.PATH_REPO, g=group_name, r=repo_name)} / {self.m_link('commits', self.PATH_COMMITS, g=group_name, r=repo_name, ref=ref)} / {resolved_hash[:7]}"
|
||||
nav_parts.append(">>\n" + breadcrumb + "\n")
|
||||
nav_content = "".join(nav_parts)
|
||||
|
||||
@@ -951,27 +962,37 @@ class NomadNetworkNode():
|
||||
i_folder = self.icon("folder")
|
||||
content_parts.append(f"{self.m_link(f'{i_folder} Browse tree at this commit', self.PATH_TREE, g=group_name, r=repo_name, ref=resolved_hash)}\n\n")
|
||||
|
||||
# Validate and display commit signature status
|
||||
show_sig = False
|
||||
sig_status = self.get_commit_signature(repo_path, resolved_hash)
|
||||
if sig_status["signed"]:
|
||||
if sig_status["valid"] and sig_status["author_match"]: sig_text = f"`FT66BB85Valid, signed by author`f"; show_sig = True
|
||||
elif sig_status["valid"]: sig_text = f"`Faa0{self.m_escape(sig_status['message'])}`f"; show_sig = True
|
||||
else: sig_text = f"`F900{self.m_escape(sig_status['message'])}`f"; show_sig = True
|
||||
else: sig_text = "Not signed"
|
||||
|
||||
# Commit metadata
|
||||
if commit_info.get("parents"):
|
||||
parent_links = []
|
||||
for parent_hash in commit_info["parents"]:
|
||||
parent_link = self.m_link(parent_hash[:7], self.PATH_COMMIT, g=group_name, r=repo_name, h=parent_hash)
|
||||
parent_link = self.m_link(parent_hash[:7], self.PATH_COMMIT, g=group_name, r=repo_name, ref=ref, h=parent_hash)
|
||||
parent_links.append(parent_link)
|
||||
|
||||
content_parts.append(f"Parents: {' '.join(parent_links)}\n")
|
||||
content_parts.append(f"Parents : {' '.join(parent_links)}\n")
|
||||
|
||||
content_parts.append(f"Author: {self.m_escape(commit_info['author_name'])} <{self.m_escape(commit_info['author_email'])}>\n")
|
||||
content_parts.append(f"Date: {commit_info['author_date']}\n")
|
||||
content_parts.append(f"Author : {self.m_escape(commit_info['author_name'])} <{self.m_escape(commit_info['author_email'])}>\n")
|
||||
content_parts.append(f"Signature : {sig_text}\n") if show_sig else None
|
||||
content_parts.append(f"Date : {commit_info['author_date']}\n")
|
||||
|
||||
if commit_info.get("committer_name") != commit_info.get("author_name"):
|
||||
content_parts.append(f"Commit: {self.m_escape(commit_info['committer_name'])} <{self.m_escape(commit_info['committer_email'])}>\n")
|
||||
content_parts.append(f"Date: {commit_info['committer_date']}\n")
|
||||
content_parts.append(f"Committer : {self.m_escape(commit_info['committer_name'])} <{self.m_escape(commit_info['committer_email'])}>\n")
|
||||
content_parts.append(f"Date : {commit_info['committer_date']}\n")
|
||||
|
||||
content_parts.append("\n")
|
||||
|
||||
# Commit message
|
||||
if commit_info.get("message"):
|
||||
content_parts.append(self.m_escape(commit_info["message"]) + "\n")
|
||||
content_parts.append(self.format_commit(commit_info["message"]) + "\n")
|
||||
content_parts.append("\n")
|
||||
|
||||
# Changed files
|
||||
@@ -1140,7 +1161,7 @@ class NomadNetworkNode():
|
||||
|
||||
# Breadcrumb navigation
|
||||
repo_link = self.m_link(repo_name, self.PATH_REPO, g=group_name, r=repo_name)
|
||||
breadcrumb = f">>\n{self.m_link('Node', self.PATH_INDEX)} / {self.m_link(group_name, self.PATH_GROUP, g=group_name)} / {repo_link}"
|
||||
breadcrumb = f">>\n{self.m_link('Node', self.PATH_INDEX)} / {self.m_link(group_name, self.PATH_GROUP, g=group_name)} / {repo_link} / stats"
|
||||
nav_parts.append(breadcrumb + "\n")
|
||||
|
||||
repo = self.get_accessible_repository(remote_identity, group_name, repo_name)
|
||||
@@ -2190,7 +2211,8 @@ class NomadNetworkNode():
|
||||
"committer_date": lines[6],
|
||||
"message": "\n".join(lines[7:]).strip(),
|
||||
"files": [],
|
||||
"diff": None }
|
||||
"diff": None,
|
||||
"signature_status": None }
|
||||
|
||||
# Get file change statistics
|
||||
stats_result = subprocess.run(["git", "diff-tree", "--numstat", "-r", commit_hash],
|
||||
@@ -2260,6 +2282,84 @@ class NomadNetworkNode():
|
||||
RNS.log(f"Error getting commit info: {e}", RNS.LOG_WARNING)
|
||||
return None
|
||||
|
||||
def get_commit_signature(self, repo_path, commit_hash):
|
||||
try:
|
||||
result = subprocess.run(["git", "cat-file", "-p", commit_hash],
|
||||
cwd=repo_path, capture_output=True, text=True,
|
||||
timeout=self.GIT_COMMAND_TIMEOUT, check=False)
|
||||
|
||||
if result.returncode != 0:
|
||||
return {"signed": False, "valid": False, "signer_hash": None,
|
||||
"author_match": False, "message": "Could not read commit object"}
|
||||
|
||||
commit_content = result.stdout
|
||||
lines = commit_content.split("\n")
|
||||
sig_lines = []
|
||||
in_signature = False
|
||||
signed_content_lines = []
|
||||
|
||||
for line in lines:
|
||||
if line.startswith("gpgsig ") or line.startswith("gpgsig-sha256 "):
|
||||
in_signature = True
|
||||
sig_start = line.find(" ") + 1
|
||||
sig_lines.append(line[sig_start:])
|
||||
|
||||
elif in_signature:
|
||||
if line.startswith(" "): sig_lines.append(line[1:])
|
||||
else:
|
||||
in_signature = False
|
||||
signed_content_lines.append(line)
|
||||
|
||||
else: signed_content_lines.append(line)
|
||||
|
||||
if not sig_lines:
|
||||
return {"signed": False, "valid": False, "signer_hash": None,
|
||||
"author_match": False, "message": "Not signed"}
|
||||
|
||||
armored_sig = "\n".join(sig_lines)
|
||||
signed_content = "\n".join(signed_content_lines).encode("utf-8")
|
||||
|
||||
try:
|
||||
sig_data = unarmor_ssh_signature(armored_sig)
|
||||
try: rsg = parse_ssh_signature(sig_data)["signature_data"]
|
||||
except ValueError as e:
|
||||
return {"signed": True, "valid": False, "signer_hash": None,
|
||||
"author_match": False, "message": "Malformed SSH wrapping for RSG data"}
|
||||
|
||||
valid, signed_rsg_data, signing_identity = validate_rsg(rsg, signed_content)
|
||||
if not valid:
|
||||
return {"signed": True, "valid": False, "signer_hash": None,
|
||||
"author_match": False, "message": "Invalid signature"}
|
||||
|
||||
signer_hash = RNS.hexrep(signing_identity.hash, delimit=False)
|
||||
author = extract_commit_author(signed_content)
|
||||
|
||||
if not author:
|
||||
return {"signed": True, "valid": True, "signer_hash": signer_hash,
|
||||
"author_match": False, "message": "Could not verify author"}
|
||||
|
||||
if author == signer_hash:
|
||||
return {"signed": True, "valid": True, "signer_hash": signer_hash,
|
||||
"author_match": True, "message": f"Valid, signed by <{signer_hash}>"}
|
||||
else:
|
||||
return {"signed": True, "valid": True, "signer_hash": signer_hash,
|
||||
"author_match": False, "message": f"Invalid signer <{signer_hash}>, author is <{author}>"}
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Error validating commit signature: {e}", RNS.LOG_DEBUG)
|
||||
return {"signed": True, "valid": False, "signer_hash": None,
|
||||
"author_match": False, "message": "Signature validation error"}
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
RNS.log(f"Timeout checking commit signature", RNS.LOG_WARNING)
|
||||
return {"signed": False, "valid": False, "signer_hash": None,
|
||||
"author_match": False, "message": "Timeout"}
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Error checking commit signature: {e}", RNS.LOG_DEBUG)
|
||||
return {"signed": False, "valid": False, "signer_hash": None,
|
||||
"author_match": False, "message": "Error"}
|
||||
|
||||
def get_readme_content(self, repo_path):
|
||||
readme_names = [ ("README.mu", False), ("Readme.mu", False), ("readme.mu", False), ("README", False),
|
||||
("readme", False), ("README.md", True), ("readme.md", True), ("README.rst", False),
|
||||
@@ -2338,6 +2438,15 @@ class NomadNetworkNode():
|
||||
|
||||
return "\n".join(formatted_lines)
|
||||
|
||||
def format_commit(self, diff_text):
|
||||
lines = diff_text.replace("\\", "\\\\").split("\n")
|
||||
formatted_lines = []
|
||||
|
||||
for line in lines:
|
||||
if line.startswith("-"): formatted_lines.append(self.m_escape(f"\\{line}"))
|
||||
else: formatted_lines.append(self.m_escape(line))
|
||||
|
||||
return "\n".join(formatted_lines)
|
||||
|
||||
def repository_thanks(self, repo_path, add=False, link_id=None):
|
||||
if add:
|
||||
@@ -2465,7 +2574,7 @@ class NomadNetworkNode():
|
||||
line = "│"
|
||||
for val in data:
|
||||
upper_filled = val >= row_top
|
||||
lower_filled = val >= row_mid
|
||||
lower_filled = val >= row_mid or row == 1 and val > 0
|
||||
|
||||
if not upper_filled and not lower_filled: line += " "
|
||||
elif upper_filled: line += f"`FT{gradient_color(grad_top)}`BT{gradient_color(grad_mid)}▀`f`b"
|
||||
|
||||
+297
-150
File diff suppressed because it is too large
Load Diff
+16
-3
@@ -492,8 +492,7 @@ def create_rsg(signer_identity, message, embed=False, meta=None, output="bin"):
|
||||
|
||||
signed_data = { "hashtype": "sha256", "hash": get_rsg_hash(message),
|
||||
"meta": { "signer": signer_identity.hash,
|
||||
"pubkey": signer_identity.get_public_key(),
|
||||
"note" : None } } # TODO: Remove default note field in 1.2.9
|
||||
"pubkey": signer_identity.get_public_key() } }
|
||||
|
||||
if embed:
|
||||
if type(message) == str: message = message.encode("utf-8")
|
||||
@@ -586,6 +585,20 @@ def rsg_meta_from_str(meta, spec=None):
|
||||
|
||||
return parsed.dict()
|
||||
|
||||
def check_release_rsm_structure(signed_data):
|
||||
release_meta = signed_data.get("meta", None)
|
||||
if not release_meta: return "No release metadata in manifest"
|
||||
release_name = release_meta.get("name", None)
|
||||
release_version = release_meta.get("version", None)
|
||||
release_origin = release_meta.get("origin", None)
|
||||
release_origin_path = release_meta.get("path", None)
|
||||
if not release_name or not release_version: return "Incomplete package data in manifest"
|
||||
if not release_origin or not release_origin_path: return "Incomplete release origin data in manifest"
|
||||
if "/" in release_name or "/" in release_version: return "Invalid data in release manifest"
|
||||
if len(release_origin) != RNS.Identity.TRUNCATED_HASHLENGTH//8: return "Invalid origin hash length in manifest"
|
||||
if not type(release_origin) == bytes: return "Invalid origin hash in manifest"
|
||||
return True
|
||||
|
||||
###################################
|
||||
# Signing & Validation Operations #
|
||||
###################################
|
||||
@@ -701,7 +714,7 @@ def validate_message(args, identity, __recursive=False):
|
||||
elif type(entry) == int: etype = "i"
|
||||
elif type(entry) == float: etype = "f"
|
||||
elif entry == None: etype = "N"
|
||||
if key == "note" and entry == None: return # TODO: Remove this check in 1.2.9
|
||||
if key == "note" and entry == None: return # TODO: Remove this check in 1.3.3
|
||||
if type(entry) == bytes: entry = RNS.hexrep(entry, delimit=False)
|
||||
leadin = f"{etype}{indent}{key}="; leadln = len(leadin)
|
||||
entry = f"{entry}"; chunk = entry[:maxwidth]; entry = entry[maxwidth:]
|
||||
|
||||
@@ -248,6 +248,11 @@ instance_name = default
|
||||
|
||||
# blackhole_sources = 521c87a83afb8f29e4455e77930b973b
|
||||
|
||||
# You can set the interval in minutes at which remote
|
||||
# blackhole sources are updated. Defaults to one hour.
|
||||
|
||||
# blackhole_update_interval = 60
|
||||
|
||||
|
||||
[logging]
|
||||
# Valid log levels are 0 through 7:
|
||||
@@ -262,6 +267,12 @@ instance_name = default
|
||||
|
||||
loglevel = 4
|
||||
|
||||
# You can disable timestamp inclusion in logs. Useful if
|
||||
# you want to use an external logging tool that provides
|
||||
# its own timestamps or custom formatting.
|
||||
|
||||
# logtimestamps = no
|
||||
|
||||
|
||||
# The interfaces section defines the physical and virtual
|
||||
# interfaces Reticulum will use to communicate on. This
|
||||
|
||||
@@ -214,6 +214,8 @@ async def _handle_error(errmsg: RNS.MessageBase):
|
||||
async def initiate(configdir: str, rnsconfigdir:str, identitypath: str, verbosity: int, quietness: int, noid: bool, destination: str,
|
||||
timeout: float, command: [str] | None = None):
|
||||
global _finished, _link
|
||||
if timeout is None:
|
||||
timeout = RNS.Transport.PATH_REQUEST_TIMEOUT
|
||||
with process.TTYRestorer(sys.stdin.fileno()) as ttyRestorer:
|
||||
loop = asyncio.get_running_loop()
|
||||
state = InitiatorState.IS_INITIAL
|
||||
|
||||
+3
-2
@@ -82,6 +82,7 @@ loglevel = LOG_NOTICE
|
||||
logfile = None
|
||||
logdest = LOG_STDOUT
|
||||
logcall = None
|
||||
logtimestamps = True
|
||||
logtimefmt = "%Y-%m-%d %H:%M:%S"
|
||||
logtimefmt_p = "%H:%M:%S.%f"
|
||||
compact_log_fmt = False
|
||||
@@ -127,8 +128,8 @@ def log(msg, level=3, _override_destination = False, pt=False):
|
||||
if loglevel >= level:
|
||||
if pt: logstring = "["+precise_timestamp_str(time.time())+"] "+loglevelname(level)+" "+msg
|
||||
else:
|
||||
if not compact_log_fmt: logstring = "["+timestamp_str(time.time())+"] "+loglevelname(level)+" "+msg
|
||||
else: logstring = "["+timestamp_str(time.time())+"] "+msg
|
||||
if not compact_log_fmt: logstring = ("["+timestamp_str(time.time())+"] " if logtimestamps else "")+loglevelname(level)+" "+msg
|
||||
else: logstring = ("["+timestamp_str(time.time())+"] " if logtimestamps else "")+msg
|
||||
|
||||
with logging_lock:
|
||||
if (logdest == LOG_STDOUT or _always_override_destination or _override_destination):
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = "1.2.8"
|
||||
__version__ = "1.3.5"
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
Recently, and mostly from people who I've never seen before, the opinions about how this project should be run has started flooding in again. In a recent forum thread of such opinions, specifically about:
|
||||
|
||||
- The decision to no longer mirror release notes on GitHub.
|
||||
- Some people feeling there were too many "barriers to entry" to joining RNS development.
|
||||
- The project not really being "open source" because random strangers couldn't just "contribute".
|
||||
|
||||
Joakim posted some very relevant observations about how Reticulum operates, along with the following quote:
|
||||
|
||||
> The modern industrial system has a built-in tendency to grow; it cannot really work unless it is growing. The word “stability” has been struck from its dictionary and replaced by “stagnation”. Its continuous growth pursues no particular aims or objectives: it is growth for the sake of growing. No one even enquires after its final shape. There is none; there is no “saturation point”.
|
||||
|
||||
That E. F. Schumacher quote perfectly illustrates the ontological schism that makes it so tiresome to deal with stuff like this.
|
||||
|
||||
There is, in this day and age, between different people, widely different base conceptual integrations of what "open source" means. For many people, "open source" has become synonymous **not** with skilled people working together in a coordinated and careful way on complex engineering challenges, but a sort of growth- and attention-focused "free-for-all" *behavioral* codex that must be followed above all else; a *social* modus operandi of fake inclusivity where everyone "should have their voice heard", and adherence to that specific process is weighed much higher than the final results.
|
||||
|
||||
I do not subscribe to, and consequently do not operate the Reticulum project under *any* versions of that idea.
|
||||
|
||||
**Here's the statistical, boring reality:**
|
||||
|
||||
- Around 90% of pull requests and "recommendations" I received when people could just submit stuff via GitHub would
|
||||
have *severely* broken things, introduced bugs or security issues, created roadblocks for future work, or otherwise
|
||||
damaged the software. Usually just for the sake of satisfying a random newcomers "idea" or personal preference.
|
||||
|
||||
- Similarly, around 90% "bug reports" were actually people asking for help, because of having failed to read even the
|
||||
most basic parts of the documentation.
|
||||
|
||||
- The people with the least amount of understanding, skill and effort invested tend to be loudest and most vocal. When
|
||||
all you have is "opinions", those are iterated upon ad infinitum, apparently.
|
||||
|
||||
Can you imagine how much time that wasted? Can you imagine what we could have accomplished with that time instead?
|
||||
|
||||
The only thing that this creates is *noise* and confusion. Clogging up the mental and physical workspaces, of people who are actually investing time and effort on the project with stuff like that is objectively just taking time that could have been used on development, and replacing it with *nothing*.
|
||||
|
||||
I was receiving *actual* bug reports, pull requests, proper technical investigations and patches via methods outside GitHub and "public" internet-based channels *way* before GitHub interaction and similar was closed down. That was were almost *all* of the real contributions were coming from, anyway. Apparently, and not unsurprisingly, the people who has invested the time and effort to understand Reticulum also prefer to collaborate in this way. Since leaving the GitHub madhouse behind, the signal-to-noise ratio has **significantly** increased.
|
||||
|
||||
Managing a public "issue" tracker with global read/write access is a futile and useless endeavor. Consider this:
|
||||
|
||||
- User A reports a "bug" that is really just a failure of understanding.
|
||||
- User B sees this and seconds is, proposing a "fix" that in continued failure of understanding would actually break functionality X.
|
||||
- User C joins the bandwagon and asks why this hasn't already been implemented like that? It's obvious!
|
||||
|
||||
The sensible response here from the developer is closing the issue with "No. Go RTFM". Today, though, this usually results in hurt feelings, animosity towards the developer and in some cases (as experienced and documented in the case of RNS), months of perfidious personal vendetta against the developer for being so brazen as to suggest the user was wrong and wasting people's time.
|
||||
|
||||
When this pattern repeats, over and over, the only sensible, measured and constructive course of action is to shrug your shoulders and say:
|
||||
|
||||
*"This system is fundamentally broken. It ain't working. I can give up here, or I can go build something better that has a chance of working."*
|
||||
|
||||
So, now it's your turn. Go look at the diffs for the last six months. What does it look like I have been doing?
|
||||
|
||||
But I will be damned straight with you all, and say that part of that solution is **absolutely** to erect barriers to entry. You can fucking bet your arse on that. I don't want opinionated man-babies running around in my living-room at 3am. I don't want to clean up the floor after a wannabe "dev-ops stars" with LLMs and a peripheral case of influencitis has puked all over the office.
|
||||
|
||||
- If you want to join the fun of changing core networking code that thousands of people rely on for communication
|
||||
daily, you better know what the fuck you're doing.
|
||||
|
||||
- I'm not here to provide validation and hugs to random strangers. I'm here to make sure the reference implementation
|
||||
of Reticulum works.
|
||||
|
||||
- If you cannot figure out how to submit a patch or valid bug investigation over RNS, you cannot expect I will take
|
||||
you seriously. At all.
|
||||
|
||||
If someone can't handle that, they should find their entertainment elsewhere.
|
||||
|
||||
I've said it before: I've provided the information and code required to make Reticulum *work*, and build networked systems, protocols and applications on top of it. That information is deep, complex, and requires you to read hundreds of pages, and put in weeks of efforts to get the *full* picture. A lot less is required to get started, but it *will* still be a steep learning experience.
|
||||
|
||||
This is a full networking stack, based on some pretty complex principles, for crying out loud. It's **not** a `hello_world` designed to make you feel good about yourself. It turns almost everything you know about networked systems on its head. That's **challenging** for *anyone*. Climb the mountain, and it will be satisfying in the end. Refuse to climb... Well, what do you think will happen?
|
||||
|
||||
As for barriers to entry of *using* RNS and related programs, utilities and clients, it's not my task to teach every single user how to do X, Y and Z. The information *is* out there. If it wasn't organized optimally for your way of learning, you can choose to "raise your concerns" about it, discuss "the fact of it" on a forum or chatroom, or: *You can choose to remedy that, and help others along*.
|
||||
|
||||
I sure know what *I* would have done.
|
||||
Binary file not shown.
Binary file not shown.
@@ -11,6 +11,7 @@ LINE_START_PATTERNS = [
|
||||
]
|
||||
|
||||
LINE_ANY_PATTERNS = [
|
||||
# r'<br/>',
|
||||
# r'<div[^>]*>',
|
||||
# r'</div>',
|
||||
]
|
||||
@@ -36,6 +37,10 @@ def should_remove_line(line, start_patterns, any_patterns):
|
||||
|
||||
|
||||
def clean_markdown_content(content, start_patterns, any_patterns, api_ref=False):
|
||||
content = content.replace("**\n : ", "**\n ")
|
||||
content = content.replace("\n* **", "\n\n* **")
|
||||
content = content.replace("\n\n\n", "\n\n")
|
||||
|
||||
lines = content.split('\n')
|
||||
result = []
|
||||
skip_next_empty = False
|
||||
@@ -57,6 +62,8 @@ def clean_markdown_content(content, start_patterns, any_patterns, api_ref=False)
|
||||
if line.startswith("#### "): line = line.replace("#### ", "#### `")
|
||||
line = f"{line}`"
|
||||
|
||||
line = line.replace("<br/>", "")
|
||||
|
||||
result.append(line)
|
||||
|
||||
# Remove trailing empty lines from end of file
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Sphinx build info version 1
|
||||
# This file records the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||
config: d77ea3044971177c0a1e0c192353c10a
|
||||
config: 413fd91f2c1dcbed812c846a1cc95e82
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
.. _distributed-development:
|
||||
|
||||
***********************
|
||||
Distributed Development
|
||||
***********************
|
||||
|
||||
This chapter of the manual provides the conceptual basis for understanding *why* ``rngit`` exists, what it aims to achieve, and the kinds of spaces it seeks to reestablish. For the practical details of operating the system, refer to the :ref:`Git Over Reticulum<git-main>` chapter.
|
||||
|
||||
|
||||
The Original Architecture
|
||||
=========================
|
||||
|
||||
When Torvalds created Git in 2005, he designed a tool that reflected a specific philosophy of collaboration. Every copy of a repository would be a complete, sovereign instance. There was no central server, no single point of failure, no gatekeeper. Developers would be able to work independently, exchange patches directly, and maintain their own branches indefinitely. This concept was - and is - both beautiful and revolutionary. It's execution is peer-to-peer not as a marketing term, but in the most foundational sense: As fundamental, structural reality.
|
||||
|
||||
Such a design emerged from necessity. The Linux kernel development process operated across geographical boundaries, time zones, and organizational affiliations. Contributors did not "log in" to a shared server to do their work; they maintained their own trees, and the flow of code between these trees was negotiated through patches, reviews, and merge decisions. The architecture of Git mirrored the social architecture of the community: Autonomous, competent, and fundamentally distributed in its technical operation.
|
||||
|
||||
*The result of that work is, in the most direct sense, what makes it possible for you to read this today.*
|
||||
|
||||
There's something very important to take note of here: With Git, developers could collaborate effectively and perfectly well without any central server being present, without platform-mediated visibility into each other's work, and without a centralized authority validating their contributions. They needed *only* a protocol for exchanging differences and a mechanism for verification of authorship. Everything else - social organization, quality control, release management - was handled by careful *human judgment* operating on top of the technical substrate.
|
||||
|
||||
What Git provided was not a development environment, but a **language for versioning**. It specified how to represent history, how to compute differences, how to merge divergent branches. It did not specify who could participate, how they should communicate, or what workflows they should follow. These were left to the competence and discretion of the creators using the system.
|
||||
|
||||
The Platform Interregnum
|
||||
========================
|
||||
|
||||
What followed represents a very familiar pattern: Tools designed to distribute power were re-centralized by platforms that offered convenience in exchange for control. GitHub, GitLab, and similar services reintroduced the centralization that Git had eliminated architecturally. The activity feed replaced durable artifacts with ephemeral notifications. The social graph and open interaction became as important as the code itself, if not more.
|
||||
|
||||
This re-centralization was not technical, as such. It was **ontological**. When every developer pushes to the same server, when every merge is in theory controllable by a platform, when every issue is tracked in a database controlled by a corporation, the nature of collaboration changes. The platform, and its social dynamics, becomes the ground of reality. The platform mediates not just the technical exchange of information and the programmatics, but the social recognition and codices of contribution, the future archival prospects of the work, and the very identity of the project itself.
|
||||
|
||||
The consequences extend beyond individual inconvenience. Centralized platforms create single points of failure for entire ecosystem. When a platform changes its terms of service, suspends accounts, removes repositories or ceases operation, entire project histories and community relationships can be disrupted or destroyed. The extractive economics of platform capitalism mean that value created by open-source communities is captured by corporations, while communities remain dependent on infrastructure they do not control. And the surveillance inherent in platform operation means that every action - every commit, every comment, every page view - is logged, analyzed, and potentially monetized or weaponized.
|
||||
|
||||
More insidiously, platforms have completely reshaped the culture of development itself. They have created what we could call the **Teahouse Developer**: A participant who treats engineering projects as social venues for opinion-sharing rather than sites of disciplined and careful production. These personages have no actual stakes in the projects they act as leeches upon, and only a very base consciousness of the damage they are incurring in order to feed their attention and external validation dependencies.
|
||||
|
||||
When platforms optimize for engagement, when growth is the only metric, when every user with an opinion must have their voice heard, when a random social process is elevated to higher importance than results, the signal-to-noise ratio collapses catastrophically. Competent engineers find themselves drowning in feedback from the incompetent, managing the emotional needs and dysregulations of drive-by commentators rather than solving technical problems.
|
||||
|
||||
The platform model is predicated on **unsaturable expansion**. Like almost any industrial system, it cannot function without growth. It pursues no particular aims; it is growth for the sake of growing. There is no saturation point, no concept of "enough". Every barrier to entry must be put down to the very lowest common denominator, every voice must be amplified, every interaction must be converted into content that feeds the machine. This is fundamentally incompatible with the nature of social beings itself. It is also incompatible with serious engineering, which requires focus, discernment, and the right of people who know better to say "no".
|
||||
|
||||
Restoration
|
||||
===========
|
||||
|
||||
The ``rngit`` system represents a return to Git's original architectural principles, fortified with cryptographic networking capabilities that were not available in 2005. The ``rngit`` system *is* Git - but running over Reticulum. Welcome back to a world where your work is your own, but where everyone can still reach you - if you want them to.
|
||||
|
||||
Just as Git eliminated the need for a central version control server, ``rngit`` eliminates the need for a central hosting platform, "servers" or any kinds of middle-men between the people actually doing the work. By operating over Reticulum, it eliminates the visibility of development activity to platform operators, network observers, state actors and other malicious third-parties.
|
||||
|
||||
In this model, the repository node is a **sovereign entity**. It is reachable from anywhere in the Reticulum network but owned, operated, and controlled by the developer or community that runs it. It is an actual home for creative output, not an extraction mechanism to which dues are paid. The node operator decides who may contribute, what standards must be met, and which voices are worth listening to. This is not exclusion; it is **discernment**. It is the necessary exercise of judgment that separates engineering from theatrics.
|
||||
|
||||
I did not create this in a fit of nostalgia. I created it because it is a necessary response to the failures of the centralized model. Git's technical architecture was - and *is* - correct. It was the social and economic superstructure built atop it that introduced fragility, exploitation, and environments toxic to actual creativity. By returning to first principles - distributed version control on distributed infrastructure - we recover not just a technical capability, but a mode of collaboration that respects the autonomy of individual developers and the sovereignty of actual communities.
|
||||
|
||||
|
||||
Protocols Over Platforms
|
||||
========================
|
||||
|
||||
The distinction between platforms and protocols is fundamental to understanding the architecture of sovereignty in networked systems. A platform is a service you access; a protocol is a grammar you speak; actions you live. A platform requires permission to enter, a protocol requires only *comprehension* to employ. A platform can change its rules, suspend your account, or cease operation entirely, a protocol persists as long as there are participants who *understand* and *use* it. A protocol is an *idea*, a platform is a machine that turns its users into products.
|
||||
|
||||
Platforms operate on a client-server model that inherently creates power asymmetry. Even when platforms are built atop open-source software, the operational instance remains a black box of corporate control. You *may* be able to download *some* of your data, but you cannot download the connections to the people that are the true value-base of the platform, or take them with you if you want to leave.
|
||||
|
||||
Protocols, by contrast, are agreements. They specify how systems should communicate, but not who may communicate or on what terms. Email is a protocol; Gmail is a platform. HTTP is a protocol; Facebook is a platform. Git is a protocol; GitHub is a platform. The protocol persists regardless of any particular implementation's success or failure.
|
||||
|
||||
The power of protocols lies in their **permissionlessness**. Anyone can implement a protocol without approval. Anyone can extend it, fork it, or use it for purposes unforeseen by its creators. This creates resilience: protocols cannot be easily censored, monopolized, or shut down because they exist as shared understanding rather than centralized infrastructure.
|
||||
|
||||
Reticulum is a protocol in this strict sense. It specifies how packets should be formatted, how paths should be discovered, how encryption should be applied. The ``rngit`` system extends this protocol approach to development workflows. It is not an external platform that hosts your repositories; it is a protocol for exchanging repository data, release artifacts, and work documents over Reticulum's encrypted transport. But with a few commands and an old computer, it creates your own infrastructure for hosting repositories, or sharing them with who you choose. *That* is how tools should function, in case we had forgotten.
|
||||
|
||||
Unlike platforms, which extract value by creating dependency, there is no entity that can grant or deny you the privilege of running ``rngit``. Your Reticulum identity is not endowed by any platform; it is generated locally and certified by its own cryptographic properties. Your repositories are hosted on nodes you control or nodes operated by communities you trust. Your relationships with other developers are peer-to-peer connections established through cryptographic addressing, not social graph connections managed by recommendation algorithms.
|
||||
|
||||
On a platform, exit means abandonment: you lose your history, your relationships, your visibility. With protocols, exit is just migration. When you change your infrastructure, your identity and your work travel with you. There are no middlemen between you and your collaborators. If push comes to shove, you can write your entire life's work and connections to an SD card, swim across the lake, and set up camp on the other side.
|
||||
|
||||
|
||||
Sovereignty Through Infrastructure
|
||||
==================================
|
||||
|
||||
The concept of sovereignty - supreme authority within a territory - has traditionally been applied to nation-states. But in an age where creative work is conducted through digital infrastructure, sovereignty is essential for individuals and communities. **Creative sovereignty** means having supreme authority over the artifacts you produce, the processes by which you produce them, and the terms under which they are distributed. It means not merely legal ownership of copyright, but operational control of the infrastructure that mediates creation, collaboration, and dissemination.
|
||||
|
||||
Centralized development platforms strip away most layers of sovereignty. When you host code on a corporate platform, you retain *some* legal ownership of copyright, but you surrender complete operational control. The platform decides what content is acceptable, who can access it, and how it is presented. They can delete your repository, suspend your account, or change the visibility of your work without consent. In reality, legal ownership becomes meaningless as operational control is ceded.
|
||||
|
||||
Running your own ``rngit`` node restores this sovereignty. You control the hardware, the network configuration, the backup strategies, and the access permissions. You decide what constitutes acceptable use, who may contribute, and how contributions are evaluated. Taking this responsibility on yourself is an assertion that your creative work is not a product to be harvested by platform economics, but an autonomous activity to be conducted on your own terms.
|
||||
|
||||
This sovereignty and responsibility extends to the entry barriers you establish. The ``rngit`` system allows you to configure access controls that filter participants based on cryptographic identity and demonstrated competence. If, for example, someone cannot navigate a command line, or use Reticulum to submit a patch, they most likely lack the required competence to modify your code. In a world that apparently labels this as "exclusion", I would simply refer to it as a minimally acceptable level of quality control.
|
||||
|
||||
Such a stance protects projects from the noise that so often overwhelms and completely dilutes platform-based development, where every user with an opinion believes themselves entitled to attention and access to the decision process.
|
||||
|
||||
|
||||
Artifact-Centered Workflows
|
||||
===========================
|
||||
|
||||
Contemporary platform-based development has shifted focus from durable artifacts to ephemeral *activity*. It does not matter what constitutes this activity, as long as it's there. The primary interface is not the repository itself, not the produced artifacts, but the activity feed: *Notifications* of commits, comments, pull requests, and social interactions. Work is measured by velocity, throughput, and the constant stream of updates. This activity-centric model creates constant urgency, discourages discernment, encourages reactive rather than reflective work patterns, and produces vast quantities of ephemeral and useless communication that obscures actual project state and productivity.
|
||||
|
||||
The ``rngit`` system enables a return to **artifact-centered workflows**, where the focus is on durable, attributable, versioned outputs rather than the stream of notifications surrounding them. The fundamental unit of work is the commit - signed, immutable records of change. The fundamental unit of production is the signed artifact - a self-verifying package of functionality. The fundamental unit of discussion is the work document - a structured, threaded conversation attached to repositories.
|
||||
|
||||
Artifacts can persist independently of any platform's continued operation. A commit signed with your Reticulum identity is attributable to you regardless of where it is stored. A release signed with your private key is verifiable as authentic regardless of which network it traverses, and can be verified offline on any system running Reticulum. The work exists as **cryptographic fact**, distributed over the planet, not as database entries in a corporate cloud.
|
||||
|
||||
Such a shift has real psychological consequences. When work is measured in artifacts rather than activity, the pace changes. There is no need for constant visibility, no pressure to perform busyness. Developers can work deeply, reflectively, and submit complete solutions rather than incremental updates designed to maintain presence in an activity feed. The work becomes **substantial**, in the physical sense of the word, rather than performative.
|
||||
|
||||
Composable Primitives
|
||||
=====================
|
||||
|
||||
The ``rngit`` system is not a monolithic application prescribing a specific workflow; it is a collection of **composable primitives** that can be arranged to support diverse creative processes. Understanding these primitives as separate, orthogonal capabilities enables users to construct workflows suited to their specific needs and to recombine these primitives in ways unforeseen by the system's designers.
|
||||
|
||||
The core primitives include:
|
||||
|
||||
* **Repository Hosting**: Bare Git repositories served over Reticulum links, accessible via standard Git commands through the ``rns://`` URL scheme.
|
||||
* **Identity-Based Access Control**: Fine-grained permissions managed through cryptographically verifiable identity hashes, configurable at the group, repository, or document level.
|
||||
* **Release Distribution**: Cryptographically signed release artifacts with embedded provenance information, verifiable offline and distributable through any Reticulum or physical path.
|
||||
* **Work Document Tracking**: Structured, threaded work management attached to repositories, with precise permission controls, and the ability to contain updates or discussions.
|
||||
* **Forking and Mirroring**: Automated replication of repositories from any accessible Git URL, with metadata tracking upstream relationships for synchronization.
|
||||
* **Nomad Network Integration**: Page node functionality for browsing repository contents, commit history, and release information through the Nomad Network protocol.
|
||||
|
||||
These primitives can be composed into workflows ranging from single-developer projects to complex multi-organizational collaborations. A solo developer might use only repository hosting and release distribution. A research group might add work document tracking for structured peer review. A software distribution network might combine mirroring with cryptographic release verification to create resilient update channels.
|
||||
|
||||
The entire system is incredibly light-weight, and can host hundreds of repositories on a Raspberry Pi.
|
||||
|
||||
Composability is essential because **creative work is diverse**. Software development, academic research, technical writing, hardware design, music production and data analysis all have different requirements for collaboration, review, and distribution. A platform prescribes a single workflow and forces all users to conform. A protocol provides primitives and allows users to construct workflows appropriate to their domain.
|
||||
|
||||
With ``rngit``, you can re-build the system into anything you can imagine. Everything can be modified, extended and hooked into. Adding functionality or automation is never further away than a shell script, a cron-job, or a Python modification of the source.
|
||||
|
||||
Distribution Without Intermediaries
|
||||
===================================
|
||||
|
||||
Creating software is only part of the work. Then comes actually getting it to the people needing to use it. Centralized platforms handle distribution through their own infrastructure: Content delivery networks, central package registries, and download servers accessed through platform-controlled interfaces. This convenience masks a fundamental dependency: Your ability to distribute depends on the platform's continued operation, their policies regarding your content, and their technical infrastructure's reach.
|
||||
|
||||
The ``rngit`` release system enables distribution strategies **decoupled from any single infrastructure provider**. Releases are cryptographically signed using Ed25519 signatures and packaged in signed release manifests (``.rsm`` files). These manifests contain embedded signatures for each artifact. The manifest provides full verifiability of all release information, and contains embedded release artifact lists, per-file ``.rsg`` signatures, origin information, and the creator's Reticulum Identity. It can also be used to fetch verified updates of the software package over the network, and can always be verified completely offline.
|
||||
|
||||
Because releases are self-verifying, they can traverse any network or physical path that Reticulum can establish. A release can travel over LoRa radio, be carried on USB drives through areas without internet connectivity, disseminated over a mirror network, or be distributed through store-and-forward mechanisms on intermittent infrastructure. Recipients can verify authenticity regardless of how they obtained the files. This is particularly valuable in low-connectivity environments where Reticulum may be the only available communication channel.
|
||||
|
||||
The ``rngit release`` command provides tools for creating, publishing, fetching, and verifying releases. When fetching a release using an ``.rsm`` manifest, the system validates the manifest signature against the required Reticulum Identity, extracts the origin node and repository path, connects to the origin over Reticulum, retrieves the latest release manifest, and verifies each downloaded artifact against the signatures embedded in the manifest. If any verification fails, the fetch aborts, preventing installation of corrupted or tampered files.
|
||||
|
||||
This cryptographic verification replaces the trust model of platform distribution. Instead of trusting that a platform has not been compromised, users verify that artifacts match the signatures created by the developer's identity. It doesn't matter *how* they obtained the artifacts, they can **always** be verified. This security model shifts from **institutional trust** (just believe in the goodness of the platform) to **cryptographic proof** (verify the signatures).
|
||||
|
||||
Long Archive
|
||||
============
|
||||
|
||||
Software development is often conceived as an activity of the present only: Solving today's problems, meeting current deadlines, responding to immediate feedback. But the artifacts produced - code, documentation, releases - have lifespans extending *far* beyond their creation. They may be used for decades, studied by future developers, depended upon by systems not yet imagined, or preserved as historical records of technological development.
|
||||
|
||||
The ``rngit`` system is designed with this **extended timeframe** in mind, supporting the creation of archives that are durable, portable, and intelligible across generational timescales. Git repositories are always internally complete; they contain full history and can be migrated to new infrastructure without loss of information. Everything that ``rngit`` adds on top of this is stored in normal files in standard formats right next to the Git repository folders, not an esoteric database-cluster two thousand kilometers away. Because releases are cryptographically signed, they remain verifiable as authentic regardless of when or where they are retrieved. Because the system operates over Reticulum, it can function over communication mediums that may outlast the internet as we know it.
|
||||
|
||||
This long-term perspective influences technical decisions. The use of well-established cryptographic primitives ensures that signatures will remain verifiable for centuries. The use of standard formats ensures that repositories will remain readable by future tools. The protocol-based architecture ensures that the system can evolve without losing compatibility with existing data.
|
||||
|
||||
For critical infrastructure, this archival durability is not optional; it is essential. Communication systems, cryptographic libraries, and safety-critical code must remain available and verifiable for the lifespans of the systems that depend on them. The ``rngit`` system provides the tools to create such archives: distributed across multiple nodes, cryptographically verified, and independent of any corporate or governmental infrastructure, which as history has shown repeatedly, does *not* persist.
|
||||
|
||||
Start Of The Road
|
||||
=================
|
||||
|
||||
Distributed development and production over Reticulum is a *different mode of existence* for creative work. It restores the autonomy originally created by Git. It provides local sovereignty over production infrastructure, composability of workflow, and durability of artifact. It lets you filter participation through competence and cryptography rather than incentives of platform operators, raising the quality and enjoyment of work, and protecting the focus of real engineering and creative expression.
|
||||
|
||||
This is not a system for everyone, and that is the point. It requires investment - in understanding Reticulum, in configuring infrastructure, in establishing workflows. It requires accepting responsibility for your own tools rather than delegating them to platform operators. It requires the discipline to maintain your own node, manage your own backups, and nurture your own community.
|
||||
|
||||
But for those who make this investment, the returns are substantial. You gain **immunity from platform failure**; your work persists regardless of corporate decisions or service outages. You gain **shelter from surveillance**; your development activity is visible only to those that *you* choose to involve. You gain **control over process**; you decide how work is conducted, reviewed, and released, unmediated by terms of service, algorithmic feeds and thousands of uninformed and irrelevant opinions.
|
||||
|
||||
Most importantly, though, you regain the **dignity of craft**. Development becomes an activity conducted among peers, equals among equals, mediated by skill and cryptographic proof rather than corporate permission, producing artifacts that stand as independent testimony to competence, functionality or beauty rather than as content feeding engagement metrics. The *work* becomes the point. The artifacts become durable. And the network becomes *one* of the tools you wield in this endeavor.
|
||||
@@ -4,18 +4,14 @@
|
||||
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 number of examples are included in the source distribution of Reticulum. You can use these examples to learn how to write your own programs.
|
||||
|
||||
.. _example-minimal:
|
||||
|
||||
Minimal
|
||||
=======
|
||||
|
||||
The *Minimal* example demonstrates the bare-minimum setup required to connect to
|
||||
a Reticulum network from your program. In about five lines of code, you will
|
||||
have the Reticulum Network Stack initialised, and ready to pass traffic in your
|
||||
program.
|
||||
The *Minimal* example demonstrates the bare-minimum setup required to connect to a Reticulum network from your program. In about five lines of code, you will have the Reticulum Network Stack initialised, and ready to pass traffic in your program.
|
||||
|
||||
.. literalinclude:: ../../Examples/Minimal.py
|
||||
|
||||
@@ -26,9 +22,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Announce
|
||||
========
|
||||
|
||||
The *Announce* example builds upon the previous example by exploring how to
|
||||
announce a destination on the network, and how to let your program receive
|
||||
notifications about announces from relevant destinations.
|
||||
The *Announce* example builds upon the previous example by exploring how to announce a destination on the network, and how to let your program receive notifications about announces from relevant destinations.
|
||||
|
||||
.. literalinclude:: ../../Examples/Announce.py
|
||||
|
||||
@@ -38,8 +32,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
|
||||
Broadcast
|
||||
=========
|
||||
The *Broadcast* example explores how to transmit plaintext broadcast messages
|
||||
over the network.
|
||||
The *Broadcast* example explores how to transmit plaintext broadcast messages over the network.
|
||||
|
||||
.. literalinclude:: ../../Examples/Broadcast.py
|
||||
|
||||
@@ -50,8 +43,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Echo
|
||||
====
|
||||
|
||||
The *Echo* example demonstrates communication between two destinations using
|
||||
the Packet interface.
|
||||
The *Echo* example demonstrates communication between two destinations using the Packet interface.
|
||||
|
||||
.. literalinclude:: ../../Examples/Echo.py
|
||||
|
||||
@@ -62,8 +54,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Link
|
||||
====
|
||||
|
||||
The *Link* example explores establishing an encrypted link to a remote
|
||||
destination, and passing traffic back and forth over the link.
|
||||
The *Link* example explores establishing an encrypted link to a remote destination, and passing traffic back and forth over the link.
|
||||
|
||||
.. literalinclude:: ../../Examples/Link.py
|
||||
|
||||
@@ -74,8 +65,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Identification
|
||||
==============
|
||||
|
||||
The *Identify* example explores identifying an intiator of a link, once
|
||||
the link has been established.
|
||||
The *Identify* example explores identifying an intiator of a link, once the link has been established.
|
||||
|
||||
.. literalinclude:: ../../Examples/Identify.py
|
||||
|
||||
@@ -97,8 +87,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Channel
|
||||
=======
|
||||
|
||||
The *Channel* example explores using a ``Channel`` to send structured
|
||||
data between peers of a ``Link``.
|
||||
The *Channel* example explores using a ``Channel`` to send structured data between peers of a ``Link``.
|
||||
|
||||
.. literalinclude:: ../../Examples/Channel.py
|
||||
|
||||
@@ -107,8 +96,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Buffer
|
||||
======
|
||||
|
||||
The *Buffer* example explores using buffered readers and writers to send
|
||||
binary data between peers of a ``Link``.
|
||||
The *Buffer* example explores using buffered readers and writers to send binary data between peers of a ``Link``.
|
||||
|
||||
.. literalinclude:: ../../Examples/Buffer.py
|
||||
|
||||
@@ -119,9 +107,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Filetransfer
|
||||
============
|
||||
|
||||
The *Filetransfer* example implements a basic file-server program that
|
||||
allow clients to connect and download files. The program uses the Resource
|
||||
interface to efficiently pass files of any size over a Reticulum :ref:`Link<api-link>`.
|
||||
The *Filetransfer* example implements a basic file-server program that allow clients to connect and download files. The program uses the Resource interface to efficiently pass files of any size over a Reticulum :ref:`Link<api-link>`.
|
||||
|
||||
.. literalinclude:: ../../Examples/Filetransfer.py
|
||||
|
||||
@@ -132,10 +118,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Custom Interfaces
|
||||
=================
|
||||
|
||||
The *ExampleInterface* demonstrates creating custom interfaces for Reticulum.
|
||||
Any number of custom interfaces can be loaded and utilised by Reticulum, and
|
||||
will be fully on-par with natively included interfaces, including all supported
|
||||
:ref:`interface modes<interfaces-modes>` and :ref:`common configuration options<interfaces-options>`.
|
||||
The *ExampleInterface* demonstrates creating custom interfaces for Reticulum. Any number of custom interfaces can be loaded and utilised by Reticulum, and will be fully on-par with natively included interfaces, including all supported :ref:`interface modes<interfaces-modes>` and :ref:`common configuration options<interfaces-options>`.
|
||||
|
||||
.. literalinclude:: ../../Examples/ExampleInterface.py
|
||||
|
||||
|
||||
@@ -2,51 +2,38 @@
|
||||
Getting Started Fast
|
||||
********************
|
||||
|
||||
The best way to get started with the Reticulum Network Stack depends on what
|
||||
you want to do. This guide will outline sensible starting paths for different
|
||||
scenarios.
|
||||
The best way to get started with the Reticulum Network Stack depends on what you want to do. This guide will outline sensible starting paths for different scenarios.
|
||||
|
||||
|
||||
Standalone Reticulum Installation
|
||||
=================================
|
||||
If you simply want to install Reticulum and related utilities on a system,
|
||||
the easiest way is via the ``pip`` package manager:
|
||||
If you simply want to install Reticulum and related utilities on a system, the easiest way is via the ``pip`` package manager:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
pip install rns
|
||||
|
||||
If you do not already have pip installed, you can install it using the package manager
|
||||
of your system with a command like ``sudo apt install python3-pip``,
|
||||
``sudo pamac install python-pip`` or similar.
|
||||
If you do not already have pip installed, you can install it using the package manager of your system with a command like ``sudo apt install python3-pip``, ``sudo pamac install python-pip`` or similar.
|
||||
|
||||
You can also dowload the Reticulum release wheels from GitHub, or other release channels,
|
||||
and install them offline using ``pip``:
|
||||
You can also dowload the Reticulum release wheels from GitHub, or other release channels, and install them offline using ``pip``:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
pip install ./rns-1.1.2-py3-none-any.whl
|
||||
|
||||
On platforms that limit user package installation via ``pip``, you may need to manually
|
||||
allow this using the ``--break-system-packages`` command line flag when installing. This
|
||||
will not actually break any packages, unless you have installed Reticulum directly via
|
||||
your operating system's package manager.
|
||||
On platforms that limit user package installation via ``pip``, you may need to manually allow this using the ``--break-system-packages`` command line flag when installing. This will not actually break any packages, unless you have installed Reticulum directly via your operating system's package manager.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
pip install rns --break-system-packages
|
||||
|
||||
For more detailed installation instructions, please see the
|
||||
:ref:`Platform-Specific Install Notes<install-guides>` section.
|
||||
For more detailed installation instructions, please see the :ref:`Platform-Specific Install Notes<install-guides>` section.
|
||||
|
||||
After installation is complete, it might be helpful to refer to the
|
||||
:ref:`Using Reticulum on Your System<using-main>` chapter.
|
||||
After installation is complete, it might be helpful to refer to the :ref:`Using Reticulum on Your System<using-main>` chapter.
|
||||
|
||||
Resolving Dependency & Installation Issues
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On some platforms, there may not be binary packages available for all dependencies, and
|
||||
``pip`` installation may fail with an error message. In these cases, the issue can usually
|
||||
be resolved by installing the development essentials packages for your platform:
|
||||
On some platforms, there may not be binary packages available for all dependencies, and ``pip`` installation may fail with an error message. In these cases, the issue can usually be resolved by installing the development essentials packages for your platform:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -59,69 +46,38 @@ be resolved by installing the development essentials packages for your platform:
|
||||
# Fedora
|
||||
sudo dnf groupinstall "Development Tools" "Development Libraries"
|
||||
|
||||
With the base development packages installed, ``pip`` should be able to compile any missing
|
||||
dependencies from source, and complete installation even on platforms that don't have pre-
|
||||
compiled packages available.
|
||||
With the base development packages installed, ``pip`` should be able to compile any missing dependencies from source, and complete installation even on platforms that don't have pre-compiled packages available.
|
||||
|
||||
Try Using a Reticulum-based Program
|
||||
=============================================
|
||||
===================================
|
||||
|
||||
If you simply want to try using a program built with Reticulum, a :ref:`range of different
|
||||
programs <software-main>` exist that allow basic communication and a various other useful functions,
|
||||
even over extremely low-bandwidth Reticulum networks.
|
||||
If you simply want to try using a program built with Reticulum, a :ref:`range of different programs <software-main>` exist that allow basic communication and a various other useful functions, even over extremely low-bandwidth Reticulum networks.
|
||||
|
||||
|
||||
Using the Included Utilities
|
||||
=============================================
|
||||
Reticulum comes with a range of included utilities that make it easier to
|
||||
manage your network, check connectivity and make Reticulum available to other
|
||||
programs on your system.
|
||||
============================
|
||||
Reticulum comes with a range of included utilities that make it easier to manage your network, check connectivity and make Reticulum available to other programs on your system.
|
||||
|
||||
You can use ``rnsd`` to run Reticulum as a background or foreground service,
|
||||
and the ``rnstatus``, ``rnpath`` and ``rnprobe`` utilities to view and query
|
||||
network status and connectivity.
|
||||
You can use ``rnsd`` to run Reticulum as a background or foreground service, and the ``rnstatus``, ``rnpath`` and ``rnprobe`` utilities to view and query network status and connectivity.
|
||||
|
||||
To learn more about these utility programs, have a look at the
|
||||
:ref:`Using Reticulum on Your System<using-main>` chapter of this manual.
|
||||
To learn more about these utility programs, have a look at the :ref:`Using Reticulum on Your System<using-main>` chapter of this manual.
|
||||
|
||||
|
||||
Creating a Network With Reticulum
|
||||
=============================================
|
||||
To create a network, you will need to specify one or more *interfaces* for
|
||||
Reticulum to use. This is done in the Reticulum configuration file, which by
|
||||
default is located at ``~/.reticulum/config``. You can get an example
|
||||
configuration file with all options via ``rnsd --exampleconfig``.
|
||||
=================================
|
||||
To create a network, you will need to specify one or more *interfaces* for Reticulum to use. This is done in the Reticulum configuration file, which by default is located at ``~/.reticulum/config``. You can get an example configuration file with all options via ``rnsd --exampleconfig``.
|
||||
|
||||
When Reticulum is started for the first time, it will create a default
|
||||
configuration file, with one active interface. This default interface uses
|
||||
your existing Ethernet and WiFi networks (if any), and only allows you to
|
||||
communicate with other Reticulum peers within your local broadcast domains.
|
||||
When Reticulum is started for the first time, it will create a default configuration file, with one active interface. This default interface uses your existing Ethernet and WiFi networks (if any), and only allows you to communicate with other Reticulum peers within your local broadcast domains.
|
||||
|
||||
To communicate further, you will have to add one or more interfaces. The default
|
||||
configuration includes a number of examples, ranging from using TCP over the
|
||||
internet, to LoRa and Packet Radio interfaces.
|
||||
To communicate further, you will have to add one or more interfaces. The default configuration includes a number of examples, ranging from using TCP over the internet, to LoRa and Packet Radio interfaces.
|
||||
|
||||
With Reticulum, you only need to configure what interfaces you want to communicate
|
||||
over. There is no need to configure address spaces, subnets, routing tables,
|
||||
or other things you might be used to from other network types.
|
||||
With Reticulum, you only need to configure what interfaces you want to communicate over. There is no need to configure address spaces, subnets, routing tables, or other things you might be used to from other network types.
|
||||
|
||||
Once Reticulum knows which interfaces it should use, it will automatically
|
||||
discover topography and configure transport of data to any destinations it
|
||||
knows about.
|
||||
Once Reticulum knows which interfaces it should use, it will automatically discover topography and configure transport of data to any destinations it knows about.
|
||||
|
||||
In situations where you already have an established WiFi or Ethernet network, and
|
||||
many devices that want to utilise the same external Reticulum network paths (for example over
|
||||
LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by
|
||||
adding any external interfaces to the configuration of this system, and then enabling transport on it. Any
|
||||
other device on your local WiFi will then be able to connect to this wider Reticulum
|
||||
network just using the default (:ref:`AutoInterface<interfaces-auto>`) configuration.
|
||||
In situations where you already have an established WiFi or Ethernet network, and many devices that want to utilise the same external Reticulum network paths (for example over LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by adding any external interfaces to the configuration of this system, and then enabling transport on it. Any other device on your local WiFi will then be able to connect to this wider Reticulum network just using the default (:ref:`AutoInterface<interfaces-auto>`) configuration.
|
||||
|
||||
Possibly, the examples in the config file are enough to get you started. If
|
||||
you want more information, you can read the :ref:`Building Networks<networks-main>`
|
||||
and :ref:`Interfaces<interfaces-main>` chapters of this manual, but most importantly,
|
||||
start with reading the next section, :ref:`Bootstrapping Connectivity<bootstrapping-connectivity>`,
|
||||
as this provides the most essential understanding of how to ensure reliable
|
||||
connectivity with a minimum of maintenance.
|
||||
Possibly, the examples in the config file are enough to get you started. If you want more information, you can read the :ref:`Building Networks<networks-main>` and :ref:`Interfaces<interfaces-main>` chapters of this manual, but most importantly, start with reading the next section, :ref:`Bootstrapping Connectivity<bootstrapping-connectivity>`, as this provides the most essential understanding of how to ensure reliable connectivity with a minimum of maintenance.
|
||||
|
||||
|
||||
.. _bootstrapping-connectivity:
|
||||
@@ -216,20 +172,13 @@ As a good starting point, you can find interface definitions for connecting your
|
||||
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
|
||||
Internet. This section offers some helpful pointers. Once you have set up your public entrypoint, it is a great idea to :ref:`make it discoverable over Reticulum<interfaces-discoverable>`.
|
||||
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 Internet. This section offers some helpful pointers. Once you have set up your public entrypoint, it is a great idea to :ref:`make it discoverable over Reticulum<interfaces-discoverable>`.
|
||||
|
||||
You will need a machine, physical or virtual with a public IP address, that can be reached by other devices on the Internet.
|
||||
|
||||
The most efficient and performant way to host a connectable entry-point supporting many
|
||||
users is to use the ``BackboneInterface``. This interface type is fully compatible with
|
||||
the ``TCPClientInterface`` and ``TCPServerInterface`` types, but much faster and uses
|
||||
less system resources, allowing your device to handle thousands of connections even on
|
||||
small systems.
|
||||
The most efficient and performant way to host a connectable entry-point supporting many users is to use the ``BackboneInterface``. This interface type is fully compatible with the ``TCPClientInterface`` and ``TCPServerInterface`` types, but much faster and uses less system resources, allowing your device to handle thousands of connections even on small systems.
|
||||
|
||||
It is also important to set your connectable interface to ``gateway`` mode, since this
|
||||
will greatly improve network convergence time and path resolution for anyone connecting
|
||||
to your entry-point.
|
||||
It is also important to set your connectable interface to ``gateway`` mode, since this will greatly improve network convergence time and path resolution for anyone connecting to your entry-point.
|
||||
|
||||
.. code:: ini
|
||||
|
||||
@@ -251,8 +200,7 @@ to your entry-point.
|
||||
announce_rate_penalty = 3600
|
||||
announce_rate_grace = 6
|
||||
|
||||
If instead you want to make a private entry-point from the Internet, you can use the
|
||||
:ref:`IFAC name and passphrase options<interfaces-options>` to secure your interface with a network name and passphrase.
|
||||
If instead you want to make a private entry-point from the Internet, you can use the :ref:`IFAC name and passphrase options<interfaces-options>` to secure your interface with a network name and passphrase.
|
||||
|
||||
.. code:: ini
|
||||
|
||||
@@ -268,132 +216,79 @@ If instead you want to make a private entry-point from the Internet, you can use
|
||||
network_name = private_ret
|
||||
passphrase = 2owjajquafIanPecAc
|
||||
|
||||
If you are hosting an entry-point on an operating system that does not support
|
||||
``BackboneInterface``, you can use ``TCPServerInterface`` instead, although it will
|
||||
not be as performant.
|
||||
If you are hosting an entry-point on an operating system that does not support ``BackboneInterface``, you can use ``TCPServerInterface`` instead, although it will not be as performant.
|
||||
|
||||
|
||||
Connecting Reticulum Instances Over the Internet
|
||||
================================================
|
||||
Reticulum currently offers three interfaces suitable for connecting instances over the Internet: :ref:`Backbone<interfaces-backbone>`, :ref:`TCP<interfaces-tcps>`
|
||||
and :ref:`I2P<interfaces-i2p>`. Each interface offers a different set of features, and Reticulum
|
||||
users should carefully choose the interface which best suites their needs.
|
||||
Reticulum currently offers three interfaces suitable for connecting instances over the Internet: :ref:`Backbone<interfaces-backbone>`, :ref:`TCP<interfaces-tcps>` and :ref:`I2P<interfaces-i2p>`. Each interface offers a different set of features, and Reticulum users should carefully choose the interface which best suites their needs.
|
||||
|
||||
The ``TCPServerInterface`` allows users to host an instance accessible over TCP/IP. This
|
||||
method is generally faster, lower latency, and more energy efficient than using ``I2PInterface``,
|
||||
however it also leaks more data about the server host.
|
||||
The ``TCPServerInterface`` allows users to host an instance accessible over TCP/IP. This method is generally faster, lower latency, and more energy efficient than using ``I2PInterface``, however it also leaks more data about the server host.
|
||||
|
||||
The ``BackboneInterface`` is a very fast and efficient interface type available on POSIX operating
|
||||
systems, designed to handle thousands of connections simultaneously with low memory, processing
|
||||
and I/O overhead. It is fully compatible with the TCP-based interface types.
|
||||
The ``BackboneInterface`` is a very fast and efficient interface type available on POSIX operating systems, designed to handle thousands of connections simultaneously with low memory, processing and I/O overhead. It is fully compatible with the TCP-based interface types.
|
||||
|
||||
TCP connections reveal the IP address of both your instance and the server to anyone who can
|
||||
inspect the connection. Someone could use this information to determine your location or identity. Adversaries
|
||||
inspecting your packets may be able to record packet metadata like time of transmission and packet size.
|
||||
Even though Reticulum encrypts traffic, TCP does not, so an adversary may be able to use
|
||||
packet inspection to learn that a system is running Reticulum, and what other IP addresses connect to it.
|
||||
Hosting a publicly reachable instance over TCP also requires a publicly reachable IP address,
|
||||
which most Internet connections don't offer anymore.
|
||||
TCP connections reveal the IP address of both your instance and the server to anyone who can inspect the connection. Someone could use this information to determine your location or identity. Adversaries inspecting your packets may be able to record packet metadata like time of transmission and packet size. Even though Reticulum encrypts traffic, TCP does not, so an adversary may be able to use packet inspection to learn that a system is running Reticulum, and what other IP addresses connect to it. Hosting a publicly reachable instance over TCP also requires a publicly reachable IP address, which most Internet connections don't offer anymore.
|
||||
|
||||
The ``I2PInterface`` routes messages through the `Invisible Internet Protocol
|
||||
(I2P) <https://geti2p.net/en/>`_. To use this interface, users must also run an I2P daemon in
|
||||
parallel to ``rnsd``. For always-on I2P nodes it is recommended to use `i2pd <https://i2pd.website/>`_.
|
||||
The ``I2PInterface`` routes messages through the `Invisible Internet Protocol (I2P) <https://geti2p.net/en/>`_. To use this interface, users must also run an I2P daemon in parallel to ``rnsd``. For always-on I2P nodes it is recommended to use `i2pd <https://i2pd.website/>`_.
|
||||
|
||||
By default, I2P will encrypt and mix all traffic sent over the Internet, and
|
||||
hide both the sender and receiver Reticulum instance IP addresses. Running an I2P node
|
||||
will also relay other I2P user's encrypted packets, which will use extra
|
||||
bandwidth and compute power, but also makes timing attacks and other forms of
|
||||
deep-packet-inspection much more difficult.
|
||||
By default, I2P will encrypt and mix all traffic sent over the Internet, and hide both the sender and receiver Reticulum instance IP addresses. Running an I2P node will also relay other I2P user's encrypted packets, which will use extra bandwidth and compute power, but also makes timing attacks and other forms of deep-packet-inspection much more difficult.
|
||||
|
||||
I2P also allows users to host globally available Reticulum instances from non-public IP's and behind firewalls and NAT.
|
||||
|
||||
In general it is recommended to use an I2P node if you want to host a publicly accessible
|
||||
instance, while preserving anonymity. If you care more about performance, and a slightly
|
||||
easier setup, use TCP.
|
||||
In general it is recommended to use an I2P node if you want to host a publicly accessible instance, while preserving anonymity. If you care more about performance, and a slightly easier setup, use TCP.
|
||||
|
||||
Adding Radio Interfaces
|
||||
=======================
|
||||
Once you have Reticulum installed and working, you can add radio interfaces with
|
||||
any compatible hardware you have available. Reticulum supports a wide range of radio
|
||||
hardware, and if you already have any available, it is very likely that it will
|
||||
work with Reticulum. For information on how to configure this, see the
|
||||
:ref:`Interfaces<interfaces-main>` section of this manual.
|
||||
Once you have Reticulum installed and working, you can add radio interfaces with any compatible hardware you have available. Reticulum supports a wide range of radio hardware, and if you already have any available, it is very likely that it will work with Reticulum. For information on how to configure this, see the :ref:`Interfaces<interfaces-main>` section of this manual.
|
||||
|
||||
If you do not already have transceiver hardware available, you can easily and
|
||||
cheaply build an :ref:`RNode<rnode-main>`, which is a general-purpose long-range
|
||||
digital radio transceiver, that integrates easily with Reticulum.
|
||||
If you do not already have transceiver hardware available, you can easily and cheaply build an :ref:`RNode<rnode-main>`, which is a general-purpose long-range digital radio transceiver, that integrates easily with Reticulum.
|
||||
|
||||
To build one yourself requires installing a custom firmware on a supported LoRa
|
||||
development board with an auto-install script or web-based flasher.
|
||||
Please see the :ref:`Communications Hardware<hardware-main>` chapter for a guide.
|
||||
If you prefer purchasing a ready-made unit, you can refer to the
|
||||
:ref:`list of suppliers<rnode-suppliers>`.
|
||||
To build one yourself requires installing a custom firmware on a supported LoRa development board with an auto-install script or web-based flasher. Please see the :ref:`Communications Hardware<hardware-main>` chapter for a guide. If you prefer purchasing a ready-made unit, you can refer to the :ref:`list of suppliers<rnode-suppliers>`.
|
||||
|
||||
Other radio-based hardware interfaces are being developed and made available by
|
||||
the broader Reticulum community. You can find more information on such topics
|
||||
over Reticulum-based information sharing systems.
|
||||
Other radio-based hardware interfaces are being developed and made available by the broader Reticulum community. You can find more information on such topics over Reticulum-based information sharing systems.
|
||||
|
||||
If you have communications hardware that is not already supported by any of the
|
||||
:ref:`existing interface types<interfaces-main>`, it is easy to write (and potentially
|
||||
publish) a :ref:`custom interface module<interfaces-custom>` that makes it compatible with Reticulum.
|
||||
If you have communications hardware that is not already supported by any of the :ref:`existing interface types<interfaces-main>`, it is easy to write (and potentially publish) a :ref:`custom interface module<interfaces-custom>` that makes it compatible with Reticulum.
|
||||
|
||||
|
||||
Creating and Using Custom Interfaces
|
||||
====================================
|
||||
|
||||
While Reticulum includes a flexible and broad range of built-in interfaces, these
|
||||
will not cover every conceivable type of communications hardware that Reticulum
|
||||
can potentially use to communicate.
|
||||
While Reticulum includes a flexible and broad range of built-in interfaces, these will not cover every conceivable type of communications hardware that Reticulum can potentially use to communicate.
|
||||
|
||||
It is therefore possible to easily write your own interface modules, that can be
|
||||
loaded at run-time and used on-par with any of the built-in interface types.
|
||||
It is therefore possible to easily write your own interface modules, that can be loaded at run-time and used on-par with any of the built-in interface types.
|
||||
|
||||
For more information on this subject, and code examples to build on, please see
|
||||
the :ref:`Configuring Interfaces<interfaces-main>` chapter.
|
||||
For more information on this subject, and code examples to build on, please see the :ref:`Configuring Interfaces<interfaces-main>` chapter.
|
||||
|
||||
|
||||
Develop a Program with Reticulum
|
||||
===========================================
|
||||
If you want to develop programs that use Reticulum, the easiest way to get
|
||||
started is to install the latest release of Reticulum via pip:
|
||||
================================
|
||||
If you want to develop programs that use Reticulum, the easiest way to get started is to install the latest release of Reticulum via pip:
|
||||
|
||||
.. code::
|
||||
|
||||
pip install rns
|
||||
|
||||
The above command will install Reticulum and dependencies, and you will be
|
||||
ready to import and use RNS in your own programs. The next step will most
|
||||
likely be to look at some :ref:`Example Programs<examples-main>`.
|
||||
The above command will install Reticulum and dependencies, and you will be ready to import and use RNS in your own programs. The next step will most likely be to look at some :ref:`Example Programs<examples-main>`.
|
||||
|
||||
The entire Reticulum API is documented in the :ref:`API Reference<api-main>`
|
||||
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 :ref:`Understanding Reticulum<understanding-main>` chapter.
|
||||
The entire Reticulum API is documented in the :ref:`API Reference<api-main>` 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 :ref:`Understanding Reticulum<understanding-main>` chapter.
|
||||
|
||||
|
||||
.. _install-guides:
|
||||
|
||||
Platform-Specific Install Notes
|
||||
==============================================
|
||||
===============================
|
||||
|
||||
Some platforms require a slightly different installation procedure, or have
|
||||
various quirks that are worth being aware of. These are listed here.
|
||||
Some platforms require a slightly different installation procedure, or have various quirks that are worth being aware of. These are listed here.
|
||||
|
||||
Android
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Reticulum can be used on Android in different ways. The easiest way to get
|
||||
started is using an app like `Sideband <https://unsigned.io/sideband>`_.
|
||||
^^^^^^^
|
||||
Reticulum can be used on Android in different ways. The easiest way to get started is using an app like `Sideband <https://unsigned.io/sideband>`_.
|
||||
|
||||
For more control and features, you can use Reticulum and related programs via
|
||||
the `Termux app <https://termux.com/>`_, at the time of writing available on
|
||||
`F-droid <https://f-droid.org>`_.
|
||||
For more control and features, you can use Reticulum and related programs via the `Termux app <https://termux.com/>`_, at the time of writing available on `F-droid <https://f-droid.org>`_.
|
||||
|
||||
Termux is a terminal emulator and Linux environment for Android based devices,
|
||||
which includes the ability to use many different programs and libraries,
|
||||
including Reticulum.
|
||||
Termux is a terminal emulator and Linux environment for Android based devices, which includes the ability to use many different programs and libraries, including Reticulum.
|
||||
|
||||
To use Reticulum within the Termux environment, you will need to install
|
||||
``python`` and the ``python-cryptography`` library using ``pkg``, the package-manager
|
||||
build into Termux. After that, you can use ``pip`` to install Reticulum.
|
||||
To use Reticulum within the Termux environment, you will need to install ``python`` and the ``python-cryptography`` library using ``pkg``, the package-manager build into Termux. After that, you can use ``pip`` to install Reticulum.
|
||||
|
||||
From within Termux, execute the following:
|
||||
|
||||
@@ -412,9 +307,7 @@ From within Termux, execute the following:
|
||||
# Install Reticulum
|
||||
pip install rns
|
||||
|
||||
If for some reason the ``python-cryptography`` package is not available for
|
||||
your platform via the Termux package manager, you can attempt to build it
|
||||
locally on your device using the following command:
|
||||
If for some reason the ``python-cryptography`` package is not available for your platform via the Termux package manager, you can attempt to build it locally on your device using the following command:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -441,16 +334,12 @@ locally on your device using the following command:
|
||||
# Reticulum and any related software
|
||||
pip install rns
|
||||
|
||||
It is also possible to include Reticulum in apps compiled and distributed as
|
||||
Android APKs. A detailed tutorial and example source code will be included
|
||||
here at a later point. Until then you can use the `Sideband source code <https://github.com/markqvist/sideband>`_ as an example and starting point.
|
||||
It is also possible to include Reticulum in apps compiled and distributed as Android APKs. A detailed tutorial and example source code will be included here at a later point. Until then you can use the `Sideband source code <https://github.com/markqvist/sideband>`_ as an example and starting point.
|
||||
|
||||
|
||||
ARM64
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On some architectures, including ARM64, not all dependencies have precompiled
|
||||
binaries. On such systems, you may need to install ``python3-dev`` (or similar) before
|
||||
installing Reticulum or programs that depend on Reticulum.
|
||||
^^^^^
|
||||
On some architectures, including ARM64, not all dependencies have precompiled binaries. On such systems, you may need to install ``python3-dev`` (or similar) before installing Reticulum or programs that depend on Reticulum.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -466,12 +355,8 @@ on your system locally.
|
||||
|
||||
|
||||
Debian Bookworm
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On versions of Debian released after April 2023, it is no longer possible by default
|
||||
to use ``pip`` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement ``pipx`` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
^^^^^^^^^^^^^^^
|
||||
On versions of Debian released after April 2023, it is no longer possible by default to use ``pip`` to install packages onto your system. Unfortunately, you will need to use the replacement ``pipx`` command instead, which places installed packages in an isolated environment. This should not negatively affect Reticulum, but will not work for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -484,42 +369,30 @@ for including and using Reticulum in your own scripts and programs.
|
||||
# Install Reticulum
|
||||
pipx install rns
|
||||
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing
|
||||
the configuration file located at ``~/.config/pip/pip.conf``, and adding the
|
||||
following section:
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing the configuration file located at ``~/.config/pip/pip.conf``, and adding the following section:
|
||||
|
||||
.. code:: ini
|
||||
|
||||
[global]
|
||||
break-system-packages = true
|
||||
|
||||
For a one-shot installation of Reticulum, without globally enabling the ``break-system-packages``
|
||||
option, you can use the following command:
|
||||
For a one-shot installation of Reticulum, without globally enabling the ``break-system-packages`` option, you can use the following command:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
pip install rns --break-system-packages
|
||||
|
||||
.. note::
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing ``pip`` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
|
||||
MacOS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
To install Reticulum on macOS, you will need to have Python and the ``pip`` package
|
||||
manager installed.
|
||||
^^^^^
|
||||
To install Reticulum on macOS, you will need to have Python and the ``pip`` package manager installed.
|
||||
|
||||
Systems running macOS can vary quite widely in whether or not Python is pre-installed,
|
||||
and if it is, which version is installed, and whether the ``pip`` package manager is
|
||||
also installed and set up. If in doubt, you can `download and install <https://www.python.org/downloads/>`_
|
||||
Python manually.
|
||||
Systems running macOS can vary quite widely in whether or not Python is pre-installed, and if it is, which version is installed, and whether the ``pip`` package manager is also installed and set up. If in doubt, you can `download and install <https://www.python.org/downloads/>`_ Python manually.
|
||||
|
||||
When Python and ``pip`` is available on your system, simply open a terminal window
|
||||
and use one of the following commands:
|
||||
When Python and ``pip`` is available on your system, simply open a terminal window and use one of the following commands:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -531,16 +404,9 @@ and use one of the following commands:
|
||||
pip3 install rns --break-system-packages
|
||||
|
||||
.. note::
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing ``pip`` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
Additionally, some version combinations of macOS and Python require you to
|
||||
manually add your installed ``pip`` packages directory to your `PATH` environment
|
||||
variable, before you can use installed commands in your terminal. Usually, adding
|
||||
the following line to your shell init script (for example ``~/.zshrc``) will be enough:
|
||||
Additionally, some version combinations of macOS and Python require you to manually add your installed ``pip`` packages directory to your `PATH` environment variable, before you can use installed commands in your terminal. Usually, adding the following line to your shell init script (for example ``~/.zshrc``) will be enough:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -550,20 +416,13 @@ Adjust Python version and shell init script location according to your system.
|
||||
|
||||
|
||||
OpenWRT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On OpenWRT systems with sufficient storage and memory, you can install
|
||||
Reticulum and related utilities using the `opkg` package manager and `pip`.
|
||||
^^^^^^^
|
||||
On OpenWRT systems with sufficient storage and memory, you can install Reticulum and related utilities using the `opkg` package manager and `pip`.
|
||||
|
||||
.. note::
|
||||
At the time of releasing this manual, work is underway to create pre-built Reticulum packages for OpenWRT, with full configuration, service and ``uci`` integration. Please see the `feed-reticulum <https://github.com/gretel/feed-reticulum>`_ and `reticulum-openwrt <https://github.com/gretel/reticulum-openwrt>`_ repositories for more information.
|
||||
|
||||
At the time of releasing this manual, work is underway to create pre-built
|
||||
Reticulum packages for OpenWRT, with full configuration, service
|
||||
and ``uci`` integration. Please see the `feed-reticulum <https://github.com/gretel/feed-reticulum>`_
|
||||
and `reticulum-openwrt <https://github.com/gretel/reticulum-openwrt>`_
|
||||
repositories for more information.
|
||||
|
||||
To install Reticulum on OpenWRT, first log into a command line session, and
|
||||
then use the following instructions:
|
||||
To install Reticulum on OpenWRT, first log into a command line session, and then use the following instructions:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -577,30 +436,15 @@ then use the following instructions:
|
||||
rnsd -vvv
|
||||
|
||||
.. note::
|
||||
|
||||
The above instructions have been verified and tested on OpenWRT 21.02 only.
|
||||
It is likely that other versions may require slightly altered installation
|
||||
commands or package names. You will also need enough free space in your
|
||||
overlay FS, and enough free RAM to actually run Reticulum and any related
|
||||
programs and utilities.
|
||||
The above instructions have been verified and tested on OpenWRT 21.02 only. It is likely that other versions may require slightly altered installation commands or package names. You will also need enough free space in your overlay FS, and enough free RAM to actually run Reticulum and any related programs and utilities.
|
||||
|
||||
Depending on your device configuration, you may need to adjust firewall rules
|
||||
for Reticulum connectivity to and from your device to work. Until proper
|
||||
packaging is ready, you will also need to manually create a service or startup
|
||||
script to automatically laucnh Reticulum at boot time.
|
||||
Depending on your device configuration, you may need to adjust firewall rules for Reticulum connectivity to and from your device to work. Until proper packaging is ready, you will also need to manually create a service or startup script to automatically laucnh Reticulum at boot time.
|
||||
|
||||
Please also note that the `AutoInterface` requires link-local IPv6 addresses
|
||||
to be enabled for any Ethernet and WiFi devices you intend to use. If ``ip a``
|
||||
shows an address starting with ``fe80::`` for the device in question,
|
||||
``AutoInterface`` should work for that device.
|
||||
Please also note that the `AutoInterface` requires link-local IPv6 addresses to be enabled for any Ethernet and WiFi devices you intend to use. If ``ip a`` shows an address starting with ``fe80::`` for the device in question, ``AutoInterface`` should work for that device.
|
||||
|
||||
Raspberry Pi
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
It is currently recommended to use a 64-bit version of the Raspberry Pi OS
|
||||
if you want to run Reticulum on Raspberry Pi computers, since 32-bit versions
|
||||
don't always have packages available for some dependencies. If Python and the
|
||||
`pip` package manager is not already installed, do that first, and then
|
||||
install Reticulum using `pip`.
|
||||
^^^^^^^^^^^^
|
||||
It is currently recommended to use a 64-bit version of the Raspberry Pi OS if you want to run Reticulum on Raspberry Pi computers, since 32-bit versions don't always have packages available for some dependencies. If Python and the `pip` package manager is not already installed, do that first, and then install Reticulum using `pip`.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -611,22 +455,14 @@ install Reticulum using `pip`.
|
||||
pip install rns --break-system-packages
|
||||
|
||||
.. note::
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing ``pip`` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
While it is possible to install and run Reticulum on 32-bit Rasperry Pi OSes,
|
||||
it will require manually configuring and installing required build dependencies,
|
||||
and is not detailed in this manual.
|
||||
While it is possible to install and run Reticulum on 32-bit Rasperry Pi OSes, it will require manually configuring and installing required build dependencies, and is not detailed in this manual.
|
||||
|
||||
|
||||
RISC-V
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On some architectures, including RISC-V, not all dependencies have precompiled
|
||||
binaries. On such systems, you may need to install ``python3-dev`` (or similar) before
|
||||
installing Reticulum or programs that depend on Reticulum.
|
||||
^^^^^^
|
||||
On some architectures, including RISC-V, not all dependencies have precompiled binaries. On such systems, you may need to install ``python3-dev`` (or similar) before installing Reticulum or programs that depend on Reticulum.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -637,17 +473,12 @@ installing Reticulum or programs that depend on Reticulum.
|
||||
# Install Reticulum
|
||||
python3 -m pip install rns
|
||||
|
||||
With these packages installed, ``pip`` will be able to build any missing dependencies
|
||||
on your system locally.
|
||||
With these packages installed, ``pip`` will be able to build any missing dependencies on your system locally.
|
||||
|
||||
|
||||
Ubuntu Lunar
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible by default
|
||||
to use ``pip`` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement ``pipx`` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
^^^^^^^^^^^^
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible by default to use ``pip`` to install packages onto your system. Unfortunately, you will need to use the replacement ``pipx`` command instead, which places installed packages in an isolated environment. This should not negatively affect Reticulum, but will not work for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -660,42 +491,29 @@ for including and using Reticulum in your own scripts and programs.
|
||||
# Install Reticulum
|
||||
pipx install rns
|
||||
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing
|
||||
the configuration file located at ``~/.config/pip/pip.conf``, and adding the
|
||||
following section:
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing the configuration file located at ``~/.config/pip/pip.conf``, and adding the following section:
|
||||
|
||||
.. code:: text
|
||||
|
||||
[global]
|
||||
break-system-packages = true
|
||||
|
||||
For a one-shot installation of Reticulum, without globally enabling the ``break-system-packages``
|
||||
option, you can use the following command:
|
||||
For a one-shot installation of Reticulum, without globally enabling the ``break-system-packages`` option, you can use the following command:
|
||||
|
||||
.. code:: text
|
||||
|
||||
pip install rns --break-system-packages
|
||||
|
||||
.. note::
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing ``pip`` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
Windows
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On Windows operating systems, the easiest way to install Reticulum is by using the
|
||||
``pip`` package manager from the command line (either the command prompt or Windows
|
||||
Powershell).
|
||||
^^^^^^^
|
||||
On Windows operating systems, the easiest way to install Reticulum is by using the ``pip`` package manager from the command line (either the command prompt or Windows Powershell).
|
||||
|
||||
If you don't already have Python installed, `download and install Python <https://www.python.org/downloads/>`_.
|
||||
At the time of publication of this manual, the recommended version is `Python 3.12.7 <https://www.python.org/downloads/release/python-3127>`_.
|
||||
If you don't already have Python installed, `download and install Python <https://www.python.org/downloads/>`_. At the time of publication of this manual, the recommended version is `Python 3.12.7 <https://www.python.org/downloads/release/python-3127>`_.
|
||||
|
||||
**Important!** When asked by the installer, make sure to add the Python program to
|
||||
your PATH environment variables. If you don't do this, you will not be able to
|
||||
use the ``pip`` installer, or run the included Reticulum utility programs (such as
|
||||
``rnsd`` and ``rnstatus``) from the command line.
|
||||
**Important!** When asked by the installer, make sure to add the Python program to your PATH environment variables. If you don't do this, you will not be able to use the ``pip`` installer, or run the included Reticulum utility programs (such as ``rnsd`` and ``rnstatus``) from the command line.
|
||||
|
||||
After installing Python, open the command prompt or Windows Powershell, and type:
|
||||
|
||||
@@ -703,11 +521,10 @@ After installing Python, open the command prompt or Windows Powershell, and type
|
||||
|
||||
pip install rns
|
||||
|
||||
You can now use Reticulum and all included utility programs directly from your
|
||||
preferred command line interface.
|
||||
You can now use Reticulum and all included utility programs directly from your preferred command line interface.
|
||||
|
||||
Pure-Python Reticulum
|
||||
==============================================
|
||||
=====================
|
||||
|
||||
.. warning::
|
||||
If you use the ``rnspure`` package to run Reticulum on systems that
|
||||
@@ -715,17 +532,6 @@ Pure-Python Reticulum
|
||||
important that you read and understand the :ref:`Cryptographic Primitives <understanding-primitives>`
|
||||
section of this manual.
|
||||
|
||||
In some rare cases, and on more obscure system types, it is not possible to
|
||||
install one or more dependencies. In such situations,
|
||||
you can use the ``rnspure`` package instead of the ``rns`` package, or use ``pip``
|
||||
with the ``--no-dependencies`` command-line option. The ``rnspure``
|
||||
package requires no external dependencies for installation. Please note that the
|
||||
actual contents of the ``rns`` and ``rnspure`` packages are *completely identical*.
|
||||
The only difference is that the ``rnspure`` package lists no dependencies required
|
||||
for installation.
|
||||
In some rare cases, and on more obscure system types, it is not possible to install one or more dependencies. In such situations, you can use the ``rnspure`` package instead of the ``rns`` package, or use ``pip`` with the ``--no-dependencies`` command-line option. The ``rnspure`` package requires no external dependencies for installation. Please note that the actual contents of the ``rns`` and ``rnspure`` packages are *completely identical*. The only difference is that the ``rnspure`` package lists no dependencies required for installation.
|
||||
|
||||
No matter how Reticulum is installed and started, it will load external dependencies
|
||||
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.
|
||||
No matter how Reticulum is installed and started, it will load external dependencies 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.
|
||||
|
||||
@@ -4,13 +4,15 @@
|
||||
Git Over Reticulum
|
||||
******************
|
||||
|
||||
This chapter of the manual serves as the technical reference for the distributed software development and project collaboration tools included in RNS. For a conceptual overview, see the :ref:`Distributed Development<distributed-development>` chapter.
|
||||
|
||||
A set of utilities for distributed collaborative software development and publishing are included in RNS.
|
||||
|
||||
The system consists of two parts: The ``rngit`` node that hosts repositories, and the ``git-remote-rns`` helper that enables Git to communicate with rngit nodes. As soon as you have RNS installed on your system, you can transparently use Git with Reticulum-hosted repositories just like any other type of remote. Git over Reticulum uses URLs in the following format: ``rns://DESTINATION_HASH/group/repo``.
|
||||
|
||||
If you set a branch to track a Reticulum remote as the default upstream, you can simply use ``git`` as you normally would; all commands work transparently and as expected.
|
||||
|
||||
.. warning::
|
||||
.. important::
|
||||
**The rngit program is a new addition to RNS!** This functionality was introduced in RNS 1.2.0. While great care has been taken to design a secure, but highly configurable and flexible `permission system`_ for allowing many users to interact with many different repositories on a single node, ``rngit`` has not been tested extensively in the wild! Be careful when hosting repositories, especially if they are public or semi-public.
|
||||
|
||||
.. _permission system: #permissions
|
||||
@@ -170,10 +172,8 @@ To fork a repository:
|
||||
The source can be any valid Git URL, including:
|
||||
|
||||
- HTTPS URLs: ``https://github.com/user/repo.git``
|
||||
- Git URLs: ``git://host.com/repo.git``
|
||||
- SSH URLs: ``ssh://git@host.com/repo.git``
|
||||
- Reticulum URLs: ``rns://DESTINATION_HASH/group/repo``
|
||||
- Local paths: ``/path/to/repo.git``
|
||||
|
||||
Forks are created as bare repositories with metadata tracking their origin. The fork process:
|
||||
|
||||
@@ -321,8 +321,6 @@ These parameters are used by the sync system and can be queried using standard G
|
||||
1716230400
|
||||
|
||||
|
||||
|
||||
|
||||
Repository Structure
|
||||
====================
|
||||
|
||||
@@ -511,6 +509,75 @@ Permission Configuration Locations
|
||||
- Repository permissions: ``<group_root>/<group_name>/<repo_name>.allowed``
|
||||
- Document permissions: ``<group_root>/<group_name>.work/<doc_id>.allowed``
|
||||
|
||||
|
||||
Remote Permission Management
|
||||
============================
|
||||
|
||||
While permissions can be configured directly on the node by editing configuration files and ``.allowed`` files, ``rngit`` also supports remote permission management through the ``rngit perms`` command. This allows administrators to modify access controls for groups and repositories over Reticulum, without requiring shell access to the hosting node.
|
||||
|
||||
To use remote permission management, you must have ``admin`` permission on the target group or repository. The command opens your configured ``$EDITOR`` to modify permissions, using the same syntax and format as local ``.allowed`` files. When you save and exit the editor, the modified permissions are transmitted to the remote node and applied immediately.
|
||||
|
||||
Managing Group Permissions
|
||||
--------------------------
|
||||
|
||||
To view or modify permissions for an entire repository group, specify the group URL (ending with the group name):
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit perms rns://50824b711717f97c2fb1166ceddd5ea9/public
|
||||
|
||||
This retrieves the current permission configuration from the ``public.allowed`` file and opens it in your editor. Any changes you make are validated for syntax correctness. Invalid permission rules will be rejected with an error message indicating the problematic line.
|
||||
|
||||
Managing Repository Permissions
|
||||
-------------------------------
|
||||
|
||||
To manage permissions for a specific repository, include the repository name in the URL:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit perms rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo
|
||||
|
||||
This operates on the ``myrepo.allowed`` file next to the repository. Repository-level permissions take precedence over group-level permissions, allowing fine-grained access control for individual repositories within a group.
|
||||
|
||||
Permission Validation
|
||||
---------------------
|
||||
|
||||
When modifying permissions remotely, ``rngit`` validates that:
|
||||
|
||||
- Each permission line follows the correct ``permission:target`` syntax
|
||||
- Permission types are valid (r, w, rw, c, s, rel, i, p, adm)
|
||||
- Target specifications are valid (identity hashes, ``all``, or ``none``)
|
||||
- Identity hashes, when specified, are the correct length (32 hexadecimal characters)
|
||||
|
||||
If validation fails, the editor will reopen with an error message describing the issue, allowing you to correct the problem before resubmitting.
|
||||
|
||||
.. caution::
|
||||
Remote permission modification requires administrative access (the ``adm`` permission), which grants full control over the repository or group. The permission change request is transmitted over the encrypted Reticulum link, and the remote node verifies your identity cryptographically before applying changes. However, be aware that granting ``adm`` permissions to remote identities effectively delegates full control, including the ability to revoke your own access or modify permissions in ways you may not anticipate.
|
||||
|
||||
**All Command-Line Options (rngit perms)**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rngit perms [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-v] [-q] [--version]
|
||||
remote
|
||||
|
||||
Reticulum Git Permission Manager
|
||||
|
||||
positional arguments:
|
||||
remote URL of remote group or repository
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative config directory
|
||||
--rnsconfig RNSCONFIG
|
||||
path to alternative Reticulum config directory
|
||||
-i, --identity PATH path to identity
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
|
||||
|
||||
Identity & Destination Aliases
|
||||
==============================
|
||||
|
||||
@@ -679,6 +746,219 @@ A complete node configuration might look like this:
|
||||
unicode_icons = no
|
||||
|
||||
|
||||
Verified Releases
|
||||
=================
|
||||
|
||||
The ``rngit`` release system provides cryptographic provenance and integrity guarantees through automatic signing of release artifacts and signed release manifests. When you create a release, ``rngit`` generates an Ed25519 signature for each artifact and embeds these signatures in a cryptographically signed release manifest (``.rsm`` file). This allows anyone who obtains the release to verify its authenticity and integrity, regardless of how the files were distributed.
|
||||
|
||||
.. _git-release-obtain:
|
||||
|
||||
Obtaining Verified Releases
|
||||
---------------------------
|
||||
|
||||
The ``rngit`` system lets you obtain releases securely and in a verified manner, by validating cryptographically signed release manifests in the ``.rsm`` format during the retrieval process. Once a release has been published with ``rngit``, anyone that has read access to it can obtain the release with the ``rngit release`` command, for example:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/group/some_program fetch latest:all
|
||||
|
||||
This command will connect to the remote, retrieve the latest release manifest, verify it's signature and integrity (you can optionally specify a required signer identity with ``--signer``), and then download and sequentially verify all artifacts included in the release.
|
||||
|
||||
If verification succeeds, the retrieved artifact files, along with the release manifest will be saved in the current working directory. From the above example, you would end up with a number of downloaded files, and a version- and package specific release manifest, such as ``some_program_1.5.2.rsm``.
|
||||
|
||||
.. important::
|
||||
Keeping the retrieved release manifest is a **very** good idea! It allows you to easily obtain future releases and updates to the software directly, while verifying they came from the same publisher.
|
||||
|
||||
**Obtaining & Updating Releases Using RSM Manifests**
|
||||
|
||||
One of the key features of the ``rngit`` release system is the ability to fetch and verify new releases using only a signed release manifest. This is particularly valuable for distributing software over Reticulum. Once someone has an ``.rsm`` manifest of your package, they can use it to continually retrieve and update the software.
|
||||
|
||||
To fetch a release using a manifest:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release some_program_1.5.2.rsm fetch latest:all
|
||||
|
||||
This command:
|
||||
|
||||
1. Validates the manifest signature to confirm authenticity
|
||||
2. Extracts the origin node and repository path from the signed manifest
|
||||
3. Connects to the origin node over Reticulum
|
||||
4. Gets the *latest* release manifest from the developer
|
||||
5. Verifies it against the existing manifest
|
||||
6. Fetches each artifact listed in the manifest
|
||||
7. Verifies each downloaded file against the signature embedded in the manifest
|
||||
|
||||
If any artifact fails signature verification, the fetch aborts with an error, preventing the installation of corrupted or tampered files.
|
||||
|
||||
**Specifying Required Signers**
|
||||
|
||||
You can require that releases be signed by specific identities. When fetching a release, use the ``--signer`` option to specify the identity hash of the required signer:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch latest:all --signer 21a8daa6d9c3d3b8aab6e94b6bcb0e33
|
||||
|
||||
If the release was not signed by the specified identity, the fetch will abort before any files are downloaded. Likewise, if any downloaded artifacts were not signed by the required identity, the process will abort at the first invalid signature. This provides strong guarantees about the provenance of the software you are installing.
|
||||
|
||||
The signer check also works when fetching from a local manifest:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release manifest.rsm fetch latest:all --signer 21a8daa6d9c3d3b8aab6e94b6bcb0e33
|
||||
|
||||
**Selective & Partial Fetches**
|
||||
|
||||
You can fetch individual artifacts from a release by specifying the artifact name instead of ``all``:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch 1.2.0:myapp-1.2.0.tar.gz
|
||||
|
||||
This downloads only the specified artifact and verifies its signature against the manifest. If a file already exists locally, ``rngit`` verifies it against the manifest signature and skips the download if valid, making it safe to run the command multiple times. When fetching releases, ``rngit release`` will only download files that are missing or invalid according to the manifest. This means that partially completed release fetches can be continued later, if interrupted.
|
||||
|
||||
**Pattern Matching for Artifacts**
|
||||
|
||||
When fetching selective artifacts, you are not limited to exact names or the ``all`` keyword. You can use shell-style wildcard patterns to match multiple artifacts flexibly. This is particularly useful for selecting platform-specific builds, version ranges, or file types without specifying each file individually.
|
||||
|
||||
.. tip::
|
||||
When using pattern matching, make sure to enclose the target specification in quotes. Otherwise,
|
||||
your shell will probably interpret it as a shell expansion pattern *before* it is passed as an
|
||||
argument to ``rngit``!
|
||||
|
||||
The pattern matching supports standard Unix wildcards:
|
||||
|
||||
- ``*`` matches any sequence of characters (including empty)
|
||||
- ``?`` matches any single character
|
||||
- ``[seq]`` matches any character in *seq* (for example ``[0-9]`` or ``[abc]``)
|
||||
- ``[!seq]`` matches any character not in *seq*
|
||||
|
||||
For example, to fetch all wheel files for Python 3 across any platform:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:*-py3-*.whl"
|
||||
|
||||
To fetch a specific patch version when you know the major and minor version:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:myapp-1.2.?-linux-x86_64.tar.gz"
|
||||
|
||||
Or to retrieve all source archives:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:source_*.tgz"
|
||||
|
||||
If your pattern contains no wildcard characters, it must match an artifact name exactly, which is useful for fetching single, specific artifacts. When a pattern matches multiple artifacts, all matched files are fetched and verified. If no artifacts match the pattern, the fetch aborts with an error indicating no matches were found.
|
||||
|
||||
Offline Verification
|
||||
--------------------
|
||||
|
||||
Because the release manifest contains embedded signatures, you can verify the integrity of release artifacts offline, without connecting to the repository node. The ``rnid`` and ``rngit`` utilities can validate artifact signatures against ``.rsg`` and manifest files.
|
||||
|
||||
**Using a release manifest:**
|
||||
|
||||
Ensure the release manifest is located in the same directory as the release artifacts, then run:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Verify all artifacts in the manifest
|
||||
$ rngit release myapp-1.2.0.rsm verify
|
||||
|
||||
# Or, verify only specific artifacts
|
||||
$ rngit release myapp-1.2.0.rsm verify "latest:*.whl"
|
||||
|
||||
This will load the manifest, and verify all files currently on-disk, but will not attempt to fetch the latest release manifest from the origin, or update local files to match it.
|
||||
|
||||
.. note::
|
||||
The ``verify`` operation is functionally equivalent to using the ``fetch`` operation with the ``--offline`` flag, and they can be used interchangably.
|
||||
|
||||
**For individual files:**
|
||||
|
||||
Ensure the ``.rsg`` signature is located in the same directory as the release artifact, then run:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -V myapp-1.2.0.tar.gz
|
||||
|
||||
This validates that the artifact file matches the signature created during the release process. Combined with the manifest's own signature, this provides end-to-end verification from the original release creation to the final installation.
|
||||
|
||||
.. _git-release-create:
|
||||
|
||||
Creating Signed Releases
|
||||
------------------------
|
||||
|
||||
Reticulum and the ``rngit`` system makes it easy to create signed releases that your users can verify and update securely. When you create a release using ``rngit``, the program automatically:
|
||||
|
||||
1. Generates an Ed25519 signature for each artifact file using your identity's signing key
|
||||
2. Creates ``.rsg`` signature files alongside each artifact in your distribution directory
|
||||
3. Constructs a signed ``manifest.rsm`` release manifest containing metadata, an artifact list, and embedded signatures
|
||||
4. Transmits both artifacts, signatures and manifest to the remote node specified as release origin
|
||||
|
||||
As an example, to create and publish a release from all files in the folder named ``dist``, simply run:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://my_node/group/myrepo create 1.2.0:./dist
|
||||
|
||||
Everything is automatically signed and uploaded to your node, and the release manifest will now include the following signed attestation information:
|
||||
|
||||
- Package name and version
|
||||
- The release notes for this release
|
||||
- Release timestamp and commit hash
|
||||
- Origin node identity and repository path
|
||||
- Complete list of artifacts
|
||||
- Embedded signatures for each artifact
|
||||
|
||||
That's it, there's nothing more to it than one command. Users can now securely obtain your release using ``rngit release fetch``.
|
||||
|
||||
**Release Manifest Format**
|
||||
|
||||
Release manifests use the ``.rsm`` format (a general-purpose, structured signed message format) and are themselves cryptographically signed documents. The manifest format embeds the signing identity's public key and a detached signature that covers the entire manifest content. This creates a chain of trust: the manifest signature proves the manifest's authenticity, and the embedded artifact signatures prove each file's integrity.
|
||||
|
||||
When a release is created, the manifest is stored as ``manifest.rsm`` in the release artifacts directory. You can also generate a local release manifest without uploading by using the ``--local`` flag:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://f2d31b2e080e5d4e358d32822ee4a3b7/public/myrepo create 1.2.0:./dist --local
|
||||
|
||||
This creates the ``.rsg`` signature files and ``manifest.rsm`` in your local distribution directory without connecting to the remote node, allowing you to inspect or distribute the signed release through alternative channels.
|
||||
|
||||
**Signature File Format**
|
||||
|
||||
Individual artifact signatures use the Reticulum Signature (``.rsg``) format and contain:
|
||||
|
||||
- The Ed25519 signature of the file
|
||||
- The signing identity's public key
|
||||
- Optional metadata, such as timestamps or notes
|
||||
|
||||
These signature files are created automatically during the release process and can be used independently of the manifest for verification purposes. The ``rnid`` utility can create and validate RSG signatures for any file, making this signature format useful beyond the ``rngit`` release system.
|
||||
|
||||
**Good Practices for Signature Distribution**
|
||||
|
||||
While release manifests in the ``.rsm`` format *include* embedded ``.rsg`` signatures for every listed artifact, it is dependent on the situation and requirements whether individual ``.rsg`` signatures are distributed as well. It is generally a good idea to do so, since they are very light-weight, and provide an easy and convenient way to validate and authenticate *individual* files, as opposed to entire releases.
|
||||
|
||||
When distributing software through multiple channels (direct download, mirror networks, physical media), including the ``.rsm`` manifest allows recipients to verify authenticity regardless of how they obtained the files. This is particularly valuable in low-connectivity environments where Reticulum may be the only available communication channel, as the manifest ensures that software updates can be verified even when received via store-and-forward mechanisms or physical media transport.
|
||||
|
||||
**Integration with Package Management**
|
||||
|
||||
While this functionality is still under development, the signed release manifest format is designed to be consumed by package management systems and automated deployment tools. Because the manifest is cryptographically signed and contains all necessary metadata and integrity checks, it can serve as a trusted source of truth for software distribution, even when fetched over untrusted channels or stored for long periods.
|
||||
|
||||
**Release Encryption**
|
||||
|
||||
While API primitives and command-line tools are currently not implemented for this, the release, distribution and verification system has been designed to also support *encrypted* releases, which can be distributed securely to authorized recipients.
|
||||
|
||||
**Verified Package Format**
|
||||
|
||||
The current system is being expanded to also include an ``.rvp`` package format, which can contain packaged releases including all relevant artifacts, metadata, manifest and signatures.
|
||||
|
||||
**Automated Mirror Discovery**
|
||||
|
||||
The ``rngit`` release system is designed to support automated mirror discovery and distribution package retrieval over Reticulum networks. Since everything is cryptographically signed and verified, it is possible to create automated mirror and distribution networks, where users can obtain software and information from local sources, without risking malicious modifications to the software they rely on. This functionality is currently in development.
|
||||
|
||||
|
||||
Release Management
|
||||
==================
|
||||
|
||||
@@ -693,11 +973,11 @@ To create a release, specify the tag name and path to artifacts:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create v1.2.0:./dist
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create 1.2.0:./dist
|
||||
|
||||
This will:
|
||||
|
||||
1. Verify that the tag ``v1.2.0`` exists in the repository
|
||||
1. Verify that the tag ``1.2.0`` exists in the repository
|
||||
2. Open your editor to write release notes
|
||||
3. Upload all files from the ``./dist`` directory
|
||||
4. Publish the release
|
||||
@@ -728,9 +1008,9 @@ To view all releases for a repository:
|
||||
|
||||
Tag Status Created Objs Notes
|
||||
------------------------------------------------------------------
|
||||
v1.2.0 published 2025-01-15 14:32 3 Another release
|
||||
v1.1.0 published 2024-12-03 09:15 2 Bug fix release
|
||||
v1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
1.2.0 published 2025-01-15 14:32 3 Another release
|
||||
1.1.0 published 2024-12-03 09:15 2 Bug fix release
|
||||
1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
|
||||
**Viewing Release Details**
|
||||
|
||||
@@ -738,9 +1018,9 @@ To see full information about a specific release:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo view v1.2.0
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo view 1.2.0
|
||||
|
||||
Release : 0.9.2
|
||||
Release : 1.2.0
|
||||
Status : published
|
||||
Created : 2026-05-04 23:53:09
|
||||
Thanks : 5
|
||||
@@ -756,16 +1036,37 @@ To see full information about a specific release:
|
||||
- myapp-1.2.0.zip (1.6 MB)
|
||||
- checksums.txt (256 B)
|
||||
|
||||
|
||||
**Fetching Releases**
|
||||
|
||||
To fetch a release, specify the remote URL, version and artifacts:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo fetch latest:all
|
||||
|
||||
This process is described in greater detail in the :ref:`Obtaining Verified Releases<git-release-obtain>` section.
|
||||
|
||||
**Creating Releases**
|
||||
|
||||
To fetch a release, specify the remote URL, version and artifacts:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create 1.3.9:artifacts_dir
|
||||
|
||||
This process is described in greater detail in the :ref:`Creating Signed Releases<git-release-create>` section.
|
||||
|
||||
**Deleting Releases**
|
||||
|
||||
To remove a release:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo delete v1.2.0
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo delete 1.2.0
|
||||
|
||||
Are you sure you want to delete release 'v1.2.0'? [y/N]: y
|
||||
Release v1.2.0 deleted
|
||||
Are you sure you want to delete release '1.2.0'? [y/N]: y
|
||||
Release 1.2.0 deleted
|
||||
|
||||
**Requirements & Validation**
|
||||
|
||||
@@ -793,15 +1094,16 @@ When the Nomad Network page node is enabled, releases are displayed on a dedicat
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rngit release [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-v] [-q] [--version]
|
||||
[repository] [operation] [target]
|
||||
usage: python -m RNS.Utilities.rngit.server [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-s PATH] [-n name] [-L]
|
||||
[-o] [-v] [-q] [--version]
|
||||
[repository] [operation] [target]
|
||||
|
||||
Reticulum Git Release Manager
|
||||
|
||||
positional arguments:
|
||||
repository URL of remote repository
|
||||
operation list, view, create or delete
|
||||
repository URL of remote repository, or path to RSM manifest
|
||||
operation list, view, fetch, create, latest or delete
|
||||
target tag and path to release artifacts directory
|
||||
|
||||
options:
|
||||
@@ -810,6 +1112,10 @@ When the Nomad Network page node is enabled, releases are displayed on a dedicat
|
||||
--rnsconfig RNSCONFIG
|
||||
path to alternative Reticulum config directory
|
||||
-i, --identity PATH path to release identity
|
||||
-s, --signer PATH path to signing identity, if different from release identity
|
||||
-n, --name name package name if different from repo name
|
||||
-L, --local generate release locally, but don't upload
|
||||
-o, --offline verify manifest locally, but don't fetch updates
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
@@ -1020,7 +1326,33 @@ Each document is a numbered directory containing:
|
||||
|
||||
**Nomad Network Interface**
|
||||
|
||||
When the Nomad Network page node is enabled, work documents are viewable through the web interface. The work page lists all documents with their status, and clicking a document shows its full content and updates.
|
||||
When the Nomad Network page node is enabled, work documents are viewable through the nomadnet interface. The work page lists all documents with their status, and clicking a document shows its full content and updates.
|
||||
|
||||
Cryptographic Attribution
|
||||
-------------------------
|
||||
|
||||
Every work document is cryptographically signed by its creator using their Reticulum identity. When you create or edit a document, ``rngit`` generates an Ed25519 signature of the content, which is stored alongside the document contents and verified by the remote node, or locally when viewing the work document through the command-line interface. This provides two essential guarantees:
|
||||
|
||||
- **Attribution:** Every document and comment can be cryptographically attributed to its actual author
|
||||
- **Integrity:** Any modification to the content after creation would invalidate the signature
|
||||
|
||||
When viewing a work document, the signature validation status is displayed:
|
||||
|
||||
.. code:: text
|
||||
|
||||
Author : 9710b86ba12c42d1d8f30f74fe509286 (not locally validated)
|
||||
Signature : Document not signed
|
||||
|
||||
Or, for valid signatures:
|
||||
|
||||
.. code:: text
|
||||
|
||||
Author : <9710b86ba12c42d1d8f30f74fe509286>
|
||||
Signature : Valid
|
||||
|
||||
The "Valid" status indicates that the document content matches the author's signature, and that the signing identity corresponds to the stated author. This can be used to create tamper-proof records of project decisions, investigations, and discussions that cannot be repudiated, or modified by third parties without detection.
|
||||
|
||||
This cryptographic provenance is particularly valuable for distributed teams operating across trust boundaries. Because signatures are verified using the author's Reticulum identity public keys - which can be recalled from any transport node on the network - work documents provide authoritative records of who said what, and when, without requiring a central authority to notarize or validate the communication. Even if the repository node hosting the documents becomes unavailable, the signed document files themselves retain validity and can be verified independently using standard Reticulum identity tools.
|
||||
|
||||
**All Command-Line Options (rngit work)**
|
||||
|
||||
@@ -1049,4 +1381,132 @@ When the Nomad Network page node is enabled, work documents are viewable through
|
||||
-d, --id ID document ID
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
--version show program's version number and exit
|
||||
|
||||
|
||||
.. _git-commit-signing:
|
||||
|
||||
Commit Signing
|
||||
==============
|
||||
|
||||
The ``rngit`` system includes ``rngcs``, a Git commit signing and validation shim that enables commit signing and validation using Reticulum identities. By hooking into Git's SSH-based signing format, commits can be signed and verified using Reticulum identity keys directly.
|
||||
|
||||
Unlike traditional GPG and SSH-based commit signing, which relies on centralized keyservers, cumbersome co-signing procedures or manual per-signer setup, Reticulum commit signing uses self-contained RSG signatures, that can be deterministically resolved to Reticulum identity hashes.
|
||||
|
||||
This enables offline verification with no external infrastructure. The signature itself contains everything needed to cryptographically verify the signer's Reticulum identity and that the commit was signed correctly by the claimed identity.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
Before you can sign commits, you need a Reticulum identity with a private key. If you don't already have one, you can generate it using ``rnid``:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -g ~/.rngit/client_identity
|
||||
|
||||
New identity <1a54d64db7e8beca6f2c6cd17b0cb479> written to /home/user/.rngit/client_identity
|
||||
|
||||
The identity file must contain the private key to be usable for signing. The corresponding Reticulum identity hash will be used as the commit author identity.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Git must be configured to use SSH-format signatures with the ``rngcs`` signing shim, which is included in RNS. You can configure this either globally or per-repository.
|
||||
|
||||
**Global Configuration**
|
||||
|
||||
Enabling Reticulum commit signing for all repositories is as simple as:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ git config --global gpg.format ssh
|
||||
$ git config --global gpg.ssh.program rngcs
|
||||
$ git config --global gpg.ssh.allowedsignersfile none
|
||||
$ git config --global user.signingKey ~/.rngit/client_identity
|
||||
|
||||
With this configuration, all commits you sign with ``git commit -S`` will use your Reticulum identity.
|
||||
|
||||
.. note::
|
||||
The ``gpg.ssh.allowedsignersfile`` configuration key **must** be *set* for ``git`` to allow invoking the signing and verification shim. It is not actually used by ``rngcs``, and can be set to an arbitrary value. All validation operations happen exclusively based on the information in the embedded RSG data.
|
||||
|
||||
**Per-Repository Configuration**
|
||||
|
||||
To enable signing only for a specific repository:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ cd /path/to/repository
|
||||
$ git config --local gpg.format ssh
|
||||
$ git config --local gpg.ssh.program rngcs
|
||||
$ git config --local gpg.ssh.allowedsignersfile none
|
||||
$ git config --local user.signingKey ~/.rngit/client_identity
|
||||
|
||||
This is useful when you want to use different identities for different projects, or when only specific repositories require signed commits.
|
||||
|
||||
Author Identity Binding
|
||||
-----------------------
|
||||
|
||||
For the signature to be valid, the Git author email **must** match the Reticulum identity hash of the signing key. You can configure this using a command like the following:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ git config --global user.email "1a54d64db7e8beca6f2c6cd17b0cb479"
|
||||
|
||||
When ``rngcs`` verifies a commit, it extracts both the Git author field of the signed commit message and the signer identity from the RSG signature, ensuring they match. This binding is necessary to prevent identity spoofing. If someone crafts a commit with your identity hash in the author field but signs with a different key, verification will fail.
|
||||
|
||||
Signing Commits
|
||||
---------------
|
||||
|
||||
Once configured, sign commits using the standard Git ``-S`` flag:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ git commit -S -m "Refactored module"
|
||||
|
||||
[master 8f7e6d5] Refactored module
|
||||
|
||||
This will create a self-contained RSG-formatted signature, encode the RSG payload using base64, and wrap it in an ASCII-armored SSH-formatted signature block. The signature is then stored in the commit object's signature header and includes:
|
||||
|
||||
- The SHA256 hash of the commit content
|
||||
- The signer's Reticulum identity hash
|
||||
- The signer's public key
|
||||
- The actual signature of the complete envelope
|
||||
|
||||
Validating Commit Signatures
|
||||
----------------------------
|
||||
|
||||
Commits are automatically validated when using ``git log --show-signature`` or ``git show --show-signature``. The ``rngcs`` shim handles all verification operations. If any step fails, verification fails and Git displays an error.
|
||||
|
||||
To view signature information for commits, use Git's standard ``--show-signature`` option:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ git log --show-signature
|
||||
|
||||
commit 8f7e6d5c8f7e6d5c8f7e6d5c8f7e6d5c8f7e6d5
|
||||
Good "git" signature for commit, signed with Reticulum Identity key <1a54d64db7e8beca6f2c6cd17b0cb479>
|
||||
Author: Developer <1a54d64db7e8beca6f2c6cd17b0cb479>
|
||||
Date: Mon Jan 15 09:30:00 2026 +0100
|
||||
|
||||
Refactored module
|
||||
|
||||
The output shows whether the commit signature is valid, and whether the author field matches the signing identity.
|
||||
|
||||
.. tip::
|
||||
If you want to display both the identity hash and LXMF address for authors, you can generate a ``.mailmap`` file that resolves identities to LXMF addresses with the following script:
|
||||
|
||||
.. code::
|
||||
#!/bin/bash
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
cd $DIR
|
||||
|
||||
id_regex="<([0-9a-f]{32})( .*)*>"
|
||||
extract_id="s/.*$id_regex/\1/g"
|
||||
|
||||
rm -f .mailmap
|
||||
git shortlog -se | grep -Ee "$id_regex" | sed -r "$extract_id" | while read -r id ; do
|
||||
if lxmf=$(rnid -i $id -H lxmf.delivery | grep -Ee "destination for this Identity is" | sed -r "$extract_id"); then
|
||||
echo "<$id lxmf:$lxmf> <$id>" >> .mailmap
|
||||
fi
|
||||
done
|
||||
@@ -27,6 +27,7 @@ to participate in the development of Reticulum itself.
|
||||
hardware
|
||||
interfaces
|
||||
networks
|
||||
distributed
|
||||
git
|
||||
support
|
||||
examples
|
||||
|
||||
@@ -3,64 +3,35 @@
|
||||
***********************
|
||||
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 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.
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-motivation:
|
||||
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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 :ref:`Reference Setup<understanding-referencesystem>`),
|
||||
connected to any kind of computer or mobile device that Reticulum can run on.
|
||||
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 :ref:`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*.
|
||||
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*.
|
||||
|
||||
.. _understanding-goals:
|
||||
|
||||
Goals
|
||||
=====
|
||||
|
||||
To be as widely usable and efficient to deploy as possible, the following goals have been used to
|
||||
guide the design of Reticulum:
|
||||
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**
|
||||
@@ -83,18 +54,18 @@ guide the design of Reticulum:
|
||||
* **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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
@@ -106,53 +77,26 @@ guide the design of Reticulum:
|
||||
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 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.
|
||||
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>``.
|
||||
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.
|
||||
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.
|
||||
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 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.
|
||||
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.
|
||||
|
||||
.. _understanding-destinations:
|
||||
|
||||
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:
|
||||
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**
|
||||
@@ -165,9 +109,9 @@ destinations. Reticulum uses three different basic destination types, and one sp
|
||||
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.
|
||||
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
|
||||
@@ -186,16 +130,11 @@ destinations. Reticulum uses three different basic destination types, and one sp
|
||||
Destination Naming
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Destinations are created and named in an easy to understand dotted notation of *aspects*, and
|
||||
represented on the network as a hash of this value. The hash is a SHA-256 truncated to 128 bits. The
|
||||
top level aspect should always be a unique identifier for the application using the destination.
|
||||
The next levels of aspects can be defined in any way by the creator of the application.
|
||||
Destinations are created and named in an easy to understand dotted notation of *aspects*, and represented on the network as a hash of this value. The hash is a SHA-256 truncated to 128 bits. The top level aspect should always be a unique identifier for the application using the destination. The next levels of aspects can be defined in any way by the creator of the application.
|
||||
|
||||
Aspects can be as long and as plentiful as required, and a resulting long destination name will not
|
||||
impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.
|
||||
Aspects can be as long and as plentiful as required, and a resulting long destination name will not impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.
|
||||
|
||||
As an example, a destination for a environmental monitoring application could be made up of the
|
||||
application name, a device type and measurement type, like this:
|
||||
As an example, a destination for a environmental monitoring application could be made up of the application name, a device type and measurement type, like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
@@ -205,11 +144,7 @@ application name, a device type and measurement type, like this:
|
||||
full name : environmentlogger.remotesensor.temperature
|
||||
hash : 4faf1b2e0a077e6a9d92fa051f256038
|
||||
|
||||
For the *single* destination, Reticulum will automatically append the associated public key as a
|
||||
destination aspect before hashing. This is done to ensure only the correct destination is reached,
|
||||
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.
|
||||
For the *single* destination, Reticulum will automatically append the associated public key as a destination aspect before hashing. This is done to ensure only the correct destination is reached, 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:
|
||||
|
||||
@@ -218,16 +153,9 @@ packet.
|
||||
* 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.
|
||||
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.
|
||||
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:
|
||||
|
||||
@@ -239,56 +167,30 @@ To recap, the different destination types should be used in the following situat
|
||||
* **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.
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-keyannouncements:
|
||||
|
||||
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.
|
||||
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.
|
||||
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
|
||||
:ref:`The Announce Mechanism in Detail<understanding-announce>`.
|
||||
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 :ref:`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.
|
||||
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.
|
||||
|
||||
@@ -297,33 +199,18 @@ Seeing how *single* destinations are always tied to a private/public key pair le
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-gettingfurther:
|
||||
|
||||
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.
|
||||
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*.
|
||||
|
||||
@@ -332,16 +219,9 @@ In the following sections, two concepts that allow this will be introduced, *pat
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
.. _understanding-nodetypes:
|
||||
@@ -349,16 +229,11 @@ 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*.
|
||||
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.
|
||||
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 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``.
|
||||
|
||||
@@ -368,8 +243,7 @@ If it is a *Transport Node*, it should be given the configuration directive ``en
|
||||
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:
|
||||
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.
|
||||
@@ -400,42 +274,23 @@ any transport node receiving it, but according to some specific rules:
|
||||
to be transmitted, the newest announce is discarded. If the newest announce contains different
|
||||
application specific data, it will replace the old announce.
|
||||
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
||||
.. tip::
|
||||
Even very slow networks, that simply don't have the capacity to ever reach *full* convergence will generally still be able to reach **any other destination on any connected segments**, since interconnecting transport nodes will prioritize announces into the slower segments that are actually requested by nodes on these.
|
||||
|
||||
Even very slow networks, that simply don't have the capacity to ever reach *full* convergence
|
||||
will generally still be able to reach **any other destination on any connected segments**, since
|
||||
interconnecting transport nodes will prioritize announces into the slower segments that are
|
||||
actually requested by nodes on these.
|
||||
This means that slow, low-capacity or low-resource segments **don't** need to have full network knowledge, since paths can always be recursively resolved from other segments that do have knowledge about them.
|
||||
|
||||
This means that slow, low-capacity or low-resource segments **don't** need to have full network
|
||||
knowledge, since paths can always be recursively resolved from other segments that do have
|
||||
knowledge about them.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-paths:
|
||||
|
||||
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.
|
||||
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:
|
||||
|
||||
@@ -495,35 +350,17 @@ For exchanges of larger amounts of data, or when longer sessions of bidirectiona
|
||||
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.
|
||||
|
||||
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*.
|
||||
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
|
||||
:ref:`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.
|
||||
The combined bandwidth cost of setting up a link is 3 packets totalling 297 bytes (more info in the :ref:`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.
|
||||
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.
|
||||
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
|
||||
@@ -570,30 +407,20 @@ an arbitrary number of hops, where information will be exchanged between two nod
|
||||
that is used to encrypt the channel. Information can now be exchanged reliably and securely.
|
||||
|
||||
.. 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**.
|
||||
|
||||
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.
|
||||
When using *links*, Reticulum will automatically verify all data sent over the link, and can also automate retransmissions if *Resources* are used.
|
||||
|
||||
.. _understanding-resources:
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
For exchanging small amounts of data over a Reticulum network, the :ref:`Packet<api-packet>` interface
|
||||
is sufficient, but for exchanging data that would require many packets, an efficient way to coordinate
|
||||
the transfer is needed.
|
||||
For exchanging small amounts of data over a Reticulum network, the :ref:`Packet<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 :ref:`Resource<api-resource>`. A *Resource* can automatically
|
||||
handle the reliable transfer of an arbitrary amount of data over an established :ref:`Link<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.
|
||||
This is the purpose of the Reticulum :ref:`Resource<api-resource>`. A *Resource* can automatically handle the reliable transfer of an arbitrary amount of data over an established :ref:`Link<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.
|
||||
|
||||
:ref:`Resources<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.
|
||||
:ref:`Resources<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.
|
||||
|
||||
.. _understanding-network_identities:
|
||||
|
||||
@@ -676,19 +503,11 @@ Once configured, your instances will automatically utilize this identity for sig
|
||||
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.
|
||||
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.
|
||||
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:
|
||||
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
|
||||
@@ -700,11 +519,7 @@ recommended setup to get started experimenting. A reference system consists of t
|
||||
* **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:
|
||||
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**
|
||||
@@ -719,53 +534,34 @@ into the future. The current Reference System Setup is as follows:
|
||||
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>`_.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-protocolspecifics:
|
||||
|
||||
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.
|
||||
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.
|
||||
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 :ref:`Common Interface Options<interfaces-options>`
|
||||
section. To implement this feature, Reticulum uses the concept of Interface Access Codes, that are calculated
|
||||
and verified per-packet.
|
||||
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 :ref:`Common Interface Options<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.
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
.. _understanding-packetformat:
|
||||
@@ -909,14 +705,11 @@ Wire Format
|
||||
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.
|
||||
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.
|
||||
|
||||
.. image:: graphics/if_mode_graph_b.png
|
||||
|
||||
See the :ref:`Interface Modes<interfaces-modes>` section for a conceptual overview
|
||||
of the different interface modes, and how they are configured.
|
||||
See the :ref:`Interface Modes<interfaces-modes>` section for a conceptual overview of the different interface modes, and how they are configured.
|
||||
|
||||
..
|
||||
(.. code-block:: text)
|
||||
@@ -946,17 +739,11 @@ of the different interface modes, and how they are configured.
|
||||
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.
|
||||
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.
|
||||
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:
|
||||
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
|
||||
|
||||
@@ -980,12 +767,7 @@ intentionally compromised or weakened clone. The utilised primitives are:
|
||||
|
||||
* 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:
|
||||
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``
|
||||
@@ -993,17 +775,9 @@ following internal implementations:
|
||||
- ``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.
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -1316,7 +1316,7 @@ To see all identities currently blackholed on your local instance, use the ``-b`
|
||||
Automated List Sourcing
|
||||
=======================
|
||||
|
||||
Manually blocking identities is effective for immediate threats, but maintaining an up-to-date blocklist for a large network is impractical. Reticulum supports **automated list sourcing**, allowing your node to subscribe to blackhole lists maintained by trusted peers, or a central authority you manage yourself.
|
||||
Manually blocking identities is effective for immediate threats and annoyances, but maintaining an up-to-date blocklist across many nodes on a large network is impractical. Reticulum supports **automated list sourcing**, allowing your node to subscribe to blackhole lists maintained by trusted peers, or a central authority you manage yourself.
|
||||
|
||||
.. warning::
|
||||
**Verify Before Subscribing!** Subscribing to a blackhole source is a powerful action that grants that source the ability to dictate who you can communicate with. Before adding a source to your configuration, verify that the maintainer aligns with your usage policy and values. Blindly subscribing to untrusted lists could inadvertently block legitimate peers or essential services.
|
||||
@@ -1333,6 +1333,9 @@ To enable automated sourcing, add the ``blackhole_sources`` option to the ``[ret
|
||||
...
|
||||
# Automatically fetch blackhole lists from these trusted sources
|
||||
blackhole_sources = 521c87a83afb8f29e4455e77930b973b, 68a4aa91ac350c4087564e8a69f84e86
|
||||
|
||||
# Optional update interval, defaults to one hour
|
||||
blackhole_update_interval = 60
|
||||
...
|
||||
|
||||
**How It Works**
|
||||
|
||||
@@ -210,8 +210,8 @@ This is not about "dropping out" of society. It is about building a substrate on
|
||||
|
||||
**Consider:**
|
||||
|
||||
- **The Old Way:** "My connection is slow. I should call my ISP and complain."
|
||||
- **The Zen Way:** "The path is noisy. I will adjust the antenna or find a better route."
|
||||
- **The Old Way:** *"My connection is slow. I should call my ISP and complain."*
|
||||
- **The Zen Way:** *"The path is noisy. I will adjust the antenna or find a better route."*
|
||||
|
||||
By taking ownership of the infrastructure, you take ownership of your voice. You stop shouting into someone else's megaphone and start building your own. The network is no longer something that happens to you; it is something you make happen.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const DOCUMENTATION_OPTIONS = {
|
||||
VERSION: '1.2.8',
|
||||
VERSION: '1.3.5',
|
||||
LANGUAGE: 'en',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
@@ -0,0 +1,441 @@
|
||||
<!doctype html>
|
||||
<html class="no-js" lang="en" data-content_root="./">
|
||||
<head><meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="color-scheme" content="light dark"><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="index" title="Index" href="genindex.html"><link rel="search" title="Search" href="search.html"><link rel="next" title="Git Over Reticulum" href="git.html"><link rel="prev" title="Building Networks" href="networks.html">
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Distributed Development - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?v=8dab3a3b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
body {
|
||||
--color-code-background: #f2f2f2;
|
||||
--color-code-foreground: #1e1e1e;
|
||||
|
||||
}
|
||||
@media not print {
|
||||
body[data-theme="dark"] {
|
||||
--color-code-background: #202020;
|
||||
--color-code-foreground: #d0d0d0;
|
||||
--color-background-primary: #202b38;
|
||||
--color-background-secondary: #161f27;
|
||||
--color-foreground-primary: #dbdbdb;
|
||||
--color-foreground-secondary: #a9b1ba;
|
||||
--color-brand-primary: #41adff;
|
||||
--color-background-hover: #161f27;
|
||||
--color-api-name: #ffbe85;
|
||||
--color-api-pre-name: #efae75;
|
||||
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body:not([data-theme="light"]) {
|
||||
--color-code-background: #202020;
|
||||
--color-code-foreground: #d0d0d0;
|
||||
--color-background-primary: #202b38;
|
||||
--color-background-secondary: #161f27;
|
||||
--color-foreground-primary: #dbdbdb;
|
||||
--color-foreground-secondary: #a9b1ba;
|
||||
--color-brand-primary: #41adff;
|
||||
--color-background-hover: #161f27;
|
||||
--color-api-name: #ffbe85;
|
||||
--color-api-pre-name: #efae75;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</style></head>
|
||||
<body>
|
||||
|
||||
<script>
|
||||
document.body.dataset.theme = localStorage.getItem("theme") || "auto";
|
||||
</script>
|
||||
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
|
||||
<symbol id="svg-toc" viewBox="0 0 24 24">
|
||||
<title>Contents</title>
|
||||
<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 1024 1024">
|
||||
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM115.4 518.9L271.7 642c5.8 4.6 14.4.5 14.4-6.9V388.9c0-7.4-8.5-11.5-14.4-6.9L115.4 505.1a8.74 8.74 0 0 0 0 13.8z"/>
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-menu" viewBox="0 0 24 24">
|
||||
<title>Menu</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-menu">
|
||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-arrow-right" viewBox="0 0 24 24">
|
||||
<title>Expand</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather-chevron-right">
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-sun" viewBox="0 0 24 24">
|
||||
<title>Light mode</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="feather-sun">
|
||||
<circle cx="12" cy="12" r="5"></circle>
|
||||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-moon" viewBox="0 0 24 24">
|
||||
<title>Dark mode</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-moon">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-sun-with-moon" viewBox="0 0 24 24">
|
||||
<title>Auto light/dark, in light mode</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="icon-custom-derived-from-feather-sun-and-tabler-moon">
|
||||
<path style="opacity: 50%" d="M 5.411 14.504 C 5.471 14.504 5.532 14.504 5.591 14.504 C 3.639 16.319 4.383 19.569 6.931 20.352 C 7.693 20.586 8.512 20.551 9.25 20.252 C 8.023 23.207 4.056 23.725 2.11 21.184 C 0.166 18.642 1.702 14.949 4.874 14.536 C 5.051 14.512 5.231 14.5 5.411 14.5 L 5.411 14.504 Z"/>
|
||||
<line x1="14.5" y1="3.25" x2="14.5" y2="1.25"/>
|
||||
<line x1="14.5" y1="15.85" x2="14.5" y2="17.85"/>
|
||||
<line x1="10.044" y1="5.094" x2="8.63" y2="3.68"/>
|
||||
<line x1="19" y1="14.05" x2="20.414" y2="15.464"/>
|
||||
<line x1="8.2" y1="9.55" x2="6.2" y2="9.55"/>
|
||||
<line x1="20.8" y1="9.55" x2="22.8" y2="9.55"/>
|
||||
<line x1="10.044" y1="14.006" x2="8.63" y2="15.42"/>
|
||||
<line x1="19" y1="5.05" x2="20.414" y2="3.636"/>
|
||||
<circle cx="14.5" cy="9.55" r="3.6"/>
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-moon-with-sun" viewBox="0 0 24 24">
|
||||
<title>Auto light/dark, in dark mode</title>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1" stroke-linecap="round" stroke-linejoin="round"
|
||||
class="icon-custom-derived-from-feather-sun-and-tabler-moon">
|
||||
<path d="M 8.282 7.007 C 8.385 7.007 8.494 7.007 8.595 7.007 C 5.18 10.184 6.481 15.869 10.942 17.24 C 12.275 17.648 13.706 17.589 15 17.066 C 12.851 22.236 5.91 23.143 2.505 18.696 C -0.897 14.249 1.791 7.786 7.342 7.063 C 7.652 7.021 7.965 7 8.282 7 L 8.282 7.007 Z"/>
|
||||
<line style="opacity: 50%" x1="18" y1="3.705" x2="18" y2="2.5"/>
|
||||
<line style="opacity: 50%" x1="18" y1="11.295" x2="18" y2="12.5"/>
|
||||
<line style="opacity: 50%" x1="15.316" y1="4.816" x2="14.464" y2="3.964"/>
|
||||
<line style="opacity: 50%" x1="20.711" y1="10.212" x2="21.563" y2="11.063"/>
|
||||
<line style="opacity: 50%" x1="14.205" y1="7.5" x2="13.001" y2="7.5"/>
|
||||
<line style="opacity: 50%" x1="21.795" y1="7.5" x2="23" y2="7.5"/>
|
||||
<line style="opacity: 50%" x1="15.316" y1="10.184" x2="14.464" y2="11.036"/>
|
||||
<line style="opacity: 50%" x1="20.711" y1="4.789" x2="21.563" y2="3.937"/>
|
||||
<circle style="opacity: 50%" cx="18" cy="7.5" r="2.169"/>
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-pencil" viewBox="0 0 24 24">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-pencil-code">
|
||||
<path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4" />
|
||||
<path d="M13.5 6.5l4 4" />
|
||||
<path d="M20 21l2 -2l-2 -2" />
|
||||
<path d="M17 17l-2 2l2 2" />
|
||||
</svg>
|
||||
</symbol>
|
||||
<symbol id="svg-eye" viewBox="0 0 24 24">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="1" stroke-linecap="round" stroke-linejoin="round" class="icon-tabler-eye-code">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0" />
|
||||
<path
|
||||
d="M11.11 17.958c-3.209 -.307 -5.91 -2.293 -8.11 -5.958c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6c-.21 .352 -.427 .688 -.647 1.008" />
|
||||
<path d="M20 21l2 -2l-2 -2" />
|
||||
<path d="M17 17l-2 2l2 2" />
|
||||
</svg>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
<input type="checkbox" class="sidebar-toggle" name="__navigation" id="__navigation" aria-label="Toggle site navigation sidebar">
|
||||
<input type="checkbox" class="sidebar-toggle" name="__toc" id="__toc" aria-label="Toggle table of contents sidebar">
|
||||
<label class="overlay sidebar-overlay" for="__navigation"></label>
|
||||
<label class="overlay toc-overlay" for="__toc"></label>
|
||||
|
||||
<a class="skip-to-content muted-link" href="#furo-main-content">Skip to content</a>
|
||||
|
||||
|
||||
|
||||
<div class="page">
|
||||
<header class="mobile-header">
|
||||
<div class="header-left">
|
||||
<label class="nav-overlay-icon" for="__navigation">
|
||||
<span class="icon"><svg><use href="#svg-menu"></use></svg></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
<button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
|
||||
<svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
|
||||
<svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
|
||||
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||||
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<label class="toc-overlay-icon toc-header-icon" for="__toc">
|
||||
<span class="icon"><svg><use href="#svg-toc"></use></svg></span>
|
||||
</label>
|
||||
</div>
|
||||
</header>
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
<input type="hidden" name="check_keywords" value="yes">
|
||||
<input type="hidden" name="area" value="default">
|
||||
</form>
|
||||
<div id="searchbox"></div><div class="sidebar-scroll"><div class="sidebar-tree">
|
||||
<ul class="current">
|
||||
<li class="toctree-l1"><a class="reference internal" href="whatis.html">What is Reticulum?</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="gettingstartedfast.html">Getting Started Fast</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="zen.html">Zen of Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="software.html">Programs Using Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="license.html">Reticulum License</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="reference.html">API Reference</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</aside>
|
||||
<div class="main">
|
||||
<div class="content">
|
||||
<div class="article-container">
|
||||
<a href="#" class="back-to-top muted-link">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12z"></path>
|
||||
</svg>
|
||||
<span>Back to top</span>
|
||||
</a>
|
||||
<div class="content-icon-container">
|
||||
<div class="theme-toggle-container theme-toggle-content">
|
||||
<button class="theme-toggle" aria-label="Toggle Light / Dark / Auto color theme">
|
||||
<svg class="theme-icon-when-auto-light"><use href="#svg-sun-with-moon"></use></svg>
|
||||
<svg class="theme-icon-when-auto-dark"><use href="#svg-moon-with-sun"></use></svg>
|
||||
<svg class="theme-icon-when-dark"><use href="#svg-moon"></use></svg>
|
||||
<svg class="theme-icon-when-light"><use href="#svg-sun"></use></svg>
|
||||
</button>
|
||||
</div>
|
||||
<label class="toc-overlay-icon toc-content-icon" for="__toc">
|
||||
<span class="icon"><svg><use href="#svg-toc"></use></svg></span>
|
||||
</label>
|
||||
</div>
|
||||
<article role="main" id="furo-main-content">
|
||||
<section id="distributed-development">
|
||||
<span id="id1"></span><h1>Distributed Development<a class="headerlink" href="#distributed-development" title="Link to this heading">¶</a></h1>
|
||||
<p>This chapter of the manual provides the conceptual basis for understanding <em>why</em> <code class="docutils literal notranslate"><span class="pre">rngit</span></code> exists, what it aims to achieve, and the kinds of spaces it seeks to reestablish. For the practical details of operating the system, refer to the <a class="reference internal" href="git.html#git-main"><span class="std std-ref">Git Over Reticulum</span></a> chapter.</p>
|
||||
<section id="the-original-architecture">
|
||||
<h2>The Original Architecture<a class="headerlink" href="#the-original-architecture" title="Link to this heading">¶</a></h2>
|
||||
<p>When Torvalds created Git in 2005, he designed a tool that reflected a specific philosophy of collaboration. Every copy of a repository would be a complete, sovereign instance. There was no central server, no single point of failure, no gatekeeper. Developers would be able to work independently, exchange patches directly, and maintain their own branches indefinitely. This concept was - and is - both beautiful and revolutionary. It’s execution is peer-to-peer not as a marketing term, but in the most foundational sense: As fundamental, structural reality.</p>
|
||||
<p>Such a design emerged from necessity. The Linux kernel development process operated across geographical boundaries, time zones, and organizational affiliations. Contributors did not “log in” to a shared server to do their work; they maintained their own trees, and the flow of code between these trees was negotiated through patches, reviews, and merge decisions. The architecture of Git mirrored the social architecture of the community: Autonomous, competent, and fundamentally distributed in its technical operation.</p>
|
||||
<p><em>The result of that work is, in the most direct sense, what makes it possible for you to read this today.</em></p>
|
||||
<p>There’s something very important to take note of here: With Git, developers could collaborate effectively and perfectly well without any central server being present, without platform-mediated visibility into each other’s work, and without a centralized authority validating their contributions. They needed <em>only</em> a protocol for exchanging differences and a mechanism for verification of authorship. Everything else - social organization, quality control, release management - was handled by careful <em>human judgment</em> operating on top of the technical substrate.</p>
|
||||
<p>What Git provided was not a development environment, but a <strong>language for versioning</strong>. It specified how to represent history, how to compute differences, how to merge divergent branches. It did not specify who could participate, how they should communicate, or what workflows they should follow. These were left to the competence and discretion of the creators using the system.</p>
|
||||
</section>
|
||||
<section id="the-platform-interregnum">
|
||||
<h2>The Platform Interregnum<a class="headerlink" href="#the-platform-interregnum" title="Link to this heading">¶</a></h2>
|
||||
<p>What followed represents a very familiar pattern: Tools designed to distribute power were re-centralized by platforms that offered convenience in exchange for control. GitHub, GitLab, and similar services reintroduced the centralization that Git had eliminated architecturally. The activity feed replaced durable artifacts with ephemeral notifications. The social graph and open interaction became as important as the code itself, if not more.</p>
|
||||
<p>This re-centralization was not technical, as such. It was <strong>ontological</strong>. When every developer pushes to the same server, when every merge is in theory controllable by a platform, when every issue is tracked in a database controlled by a corporation, the nature of collaboration changes. The platform, and its social dynamics, becomes the ground of reality. The platform mediates not just the technical exchange of information and the programmatics, but the social recognition and codices of contribution, the future archival prospects of the work, and the very identity of the project itself.</p>
|
||||
<p>The consequences extend beyond individual inconvenience. Centralized platforms create single points of failure for entire ecosystem. When a platform changes its terms of service, suspends accounts, removes repositories or ceases operation, entire project histories and community relationships can be disrupted or destroyed. The extractive economics of platform capitalism mean that value created by open-source communities is captured by corporations, while communities remain dependent on infrastructure they do not control. And the surveillance inherent in platform operation means that every action - every commit, every comment, every page view - is logged, analyzed, and potentially monetized or weaponized.</p>
|
||||
<p>More insidiously, platforms have completely reshaped the culture of development itself. They have created what we could call the <strong>Teahouse Developer</strong>: A participant who treats engineering projects as social venues for opinion-sharing rather than sites of disciplined and careful production. These personages have no actual stakes in the projects they act as leeches upon, and only a very base consciousness of the damage they are incurring in order to feed their attention and external validation dependencies.</p>
|
||||
<p>When platforms optimize for engagement, when growth is the only metric, when every user with an opinion must have their voice heard, when a random social process is elevated to higher importance than results, the signal-to-noise ratio collapses catastrophically. Competent engineers find themselves drowning in feedback from the incompetent, managing the emotional needs and dysregulations of drive-by commentators rather than solving technical problems.</p>
|
||||
<p>The platform model is predicated on <strong>unsaturable expansion</strong>. Like almost any industrial system, it cannot function without growth. It pursues no particular aims; it is growth for the sake of growing. There is no saturation point, no concept of “enough”. Every barrier to entry must be put down to the very lowest common denominator, every voice must be amplified, every interaction must be converted into content that feeds the machine. This is fundamentally incompatible with the nature of social beings itself. It is also incompatible with serious engineering, which requires focus, discernment, and the right of people who know better to say “no”.</p>
|
||||
</section>
|
||||
<section id="restoration">
|
||||
<h2>Restoration<a class="headerlink" href="#restoration" title="Link to this heading">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system represents a return to Git’s original architectural principles, fortified with cryptographic networking capabilities that were not available in 2005. The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system <em>is</em> Git - but running over Reticulum. Welcome back to a world where your work is your own, but where everyone can still reach you - if you want them to.</p>
|
||||
<p>Just as Git eliminated the need for a central version control server, <code class="docutils literal notranslate"><span class="pre">rngit</span></code> eliminates the need for a central hosting platform, “servers” or any kinds of middle-men between the people actually doing the work. By operating over Reticulum, it eliminates the visibility of development activity to platform operators, network observers, state actors and other malicious third-parties.</p>
|
||||
<p>In this model, the repository node is a <strong>sovereign entity</strong>. It is reachable from anywhere in the Reticulum network but owned, operated, and controlled by the developer or community that runs it. It is an actual home for creative output, not an extraction mechanism to which dues are paid. The node operator decides who may contribute, what standards must be met, and which voices are worth listening to. This is not exclusion; it is <strong>discernment</strong>. It is the necessary exercise of judgment that separates engineering from theatrics.</p>
|
||||
<p>I did not create this in a fit of nostalgia. I created it because it is a necessary response to the failures of the centralized model. Git’s technical architecture was - and <em>is</em> - correct. It was the social and economic superstructure built atop it that introduced fragility, exploitation, and environments toxic to actual creativity. By returning to first principles - distributed version control on distributed infrastructure - we recover not just a technical capability, but a mode of collaboration that respects the autonomy of individual developers and the sovereignty of actual communities.</p>
|
||||
</section>
|
||||
<section id="protocols-over-platforms">
|
||||
<h2>Protocols Over Platforms<a class="headerlink" href="#protocols-over-platforms" title="Link to this heading">¶</a></h2>
|
||||
<p>The distinction between platforms and protocols is fundamental to understanding the architecture of sovereignty in networked systems. A platform is a service you access; a protocol is a grammar you speak; actions you live. A platform requires permission to enter, a protocol requires only <em>comprehension</em> to employ. A platform can change its rules, suspend your account, or cease operation entirely, a protocol persists as long as there are participants who <em>understand</em> and <em>use</em> it. A protocol is an <em>idea</em>, a platform is a machine that turns its users into products.</p>
|
||||
<p>Platforms operate on a client-server model that inherently creates power asymmetry. Even when platforms are built atop open-source software, the operational instance remains a black box of corporate control. You <em>may</em> be able to download <em>some</em> of your data, but you cannot download the connections to the people that are the true value-base of the platform, or take them with you if you want to leave.</p>
|
||||
<p>Protocols, by contrast, are agreements. They specify how systems should communicate, but not who may communicate or on what terms. Email is a protocol; Gmail is a platform. HTTP is a protocol; Facebook is a platform. Git is a protocol; GitHub is a platform. The protocol persists regardless of any particular implementation’s success or failure.</p>
|
||||
<p>The power of protocols lies in their <strong>permissionlessness</strong>. Anyone can implement a protocol without approval. Anyone can extend it, fork it, or use it for purposes unforeseen by its creators. This creates resilience: protocols cannot be easily censored, monopolized, or shut down because they exist as shared understanding rather than centralized infrastructure.</p>
|
||||
<p>Reticulum is a protocol in this strict sense. It specifies how packets should be formatted, how paths should be discovered, how encryption should be applied. The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system extends this protocol approach to development workflows. It is not an external platform that hosts your repositories; it is a protocol for exchanging repository data, release artifacts, and work documents over Reticulum’s encrypted transport. But with a few commands and an old computer, it creates your own infrastructure for hosting repositories, or sharing them with who you choose. <em>That</em> is how tools should function, in case we had forgotten.</p>
|
||||
<p>Unlike platforms, which extract value by creating dependency, there is no entity that can grant or deny you the privilege of running <code class="docutils literal notranslate"><span class="pre">rngit</span></code>. Your Reticulum identity is not endowed by any platform; it is generated locally and certified by its own cryptographic properties. Your repositories are hosted on nodes you control or nodes operated by communities you trust. Your relationships with other developers are peer-to-peer connections established through cryptographic addressing, not social graph connections managed by recommendation algorithms.</p>
|
||||
<p>On a platform, exit means abandonment: you lose your history, your relationships, your visibility. With protocols, exit is just migration. When you change your infrastructure, your identity and your work travel with you. There are no middlemen between you and your collaborators. If push comes to shove, you can write your entire life’s work and connections to an SD card, swim across the lake, and set up camp on the other side.</p>
|
||||
</section>
|
||||
<section id="sovereignty-through-infrastructure">
|
||||
<h2>Sovereignty Through Infrastructure<a class="headerlink" href="#sovereignty-through-infrastructure" title="Link to this heading">¶</a></h2>
|
||||
<p>The concept of sovereignty - supreme authority within a territory - has traditionally been applied to nation-states. But in an age where creative work is conducted through digital infrastructure, sovereignty is essential for individuals and communities. <strong>Creative sovereignty</strong> means having supreme authority over the artifacts you produce, the processes by which you produce them, and the terms under which they are distributed. It means not merely legal ownership of copyright, but operational control of the infrastructure that mediates creation, collaboration, and dissemination.</p>
|
||||
<p>Centralized development platforms strip away most layers of sovereignty. When you host code on a corporate platform, you retain <em>some</em> legal ownership of copyright, but you surrender complete operational control. The platform decides what content is acceptable, who can access it, and how it is presented. They can delete your repository, suspend your account, or change the visibility of your work without consent. In reality, legal ownership becomes meaningless as operational control is ceded.</p>
|
||||
<p>Running your own <code class="docutils literal notranslate"><span class="pre">rngit</span></code> node restores this sovereignty. You control the hardware, the network configuration, the backup strategies, and the access permissions. You decide what constitutes acceptable use, who may contribute, and how contributions are evaluated. Taking this responsibility on yourself is an assertion that your creative work is not a product to be harvested by platform economics, but an autonomous activity to be conducted on your own terms.</p>
|
||||
<p>This sovereignty and responsibility extends to the entry barriers you establish. The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system allows you to configure access controls that filter participants based on cryptographic identity and demonstrated competence. If, for example, someone cannot navigate a command line, or use Reticulum to submit a patch, they most likely lack the required competence to modify your code. In a world that apparently labels this as “exclusion”, I would simply refer to it as a minimally acceptable level of quality control.</p>
|
||||
<p>Such a stance protects projects from the noise that so often overwhelms and completely dilutes platform-based development, where every user with an opinion believes themselves entitled to attention and access to the decision process.</p>
|
||||
</section>
|
||||
<section id="artifact-centered-workflows">
|
||||
<h2>Artifact-Centered Workflows<a class="headerlink" href="#artifact-centered-workflows" title="Link to this heading">¶</a></h2>
|
||||
<p>Contemporary platform-based development has shifted focus from durable artifacts to ephemeral <em>activity</em>. It does not matter what constitutes this activity, as long as it’s there. The primary interface is not the repository itself, not the produced artifacts, but the activity feed: <em>Notifications</em> of commits, comments, pull requests, and social interactions. Work is measured by velocity, throughput, and the constant stream of updates. This activity-centric model creates constant urgency, discourages discernment, encourages reactive rather than reflective work patterns, and produces vast quantities of ephemeral and useless communication that obscures actual project state and productivity.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system enables a return to <strong>artifact-centered workflows</strong>, where the focus is on durable, attributable, versioned outputs rather than the stream of notifications surrounding them. The fundamental unit of work is the commit - signed, immutable records of change. The fundamental unit of production is the signed artifact - a self-verifying package of functionality. The fundamental unit of discussion is the work document - a structured, threaded conversation attached to repositories.</p>
|
||||
<p>Artifacts can persist independently of any platform’s continued operation. A commit signed with your Reticulum identity is attributable to you regardless of where it is stored. A release signed with your private key is verifiable as authentic regardless of which network it traverses, and can be verified offline on any system running Reticulum. The work exists as <strong>cryptographic fact</strong>, distributed over the planet, not as database entries in a corporate cloud.</p>
|
||||
<p>Such a shift has real psychological consequences. When work is measured in artifacts rather than activity, the pace changes. There is no need for constant visibility, no pressure to perform busyness. Developers can work deeply, reflectively, and submit complete solutions rather than incremental updates designed to maintain presence in an activity feed. The work becomes <strong>substantial</strong>, in the physical sense of the word, rather than performative.</p>
|
||||
</section>
|
||||
<section id="composable-primitives">
|
||||
<h2>Composable Primitives<a class="headerlink" href="#composable-primitives" title="Link to this heading">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system is not a monolithic application prescribing a specific workflow; it is a collection of <strong>composable primitives</strong> that can be arranged to support diverse creative processes. Understanding these primitives as separate, orthogonal capabilities enables users to construct workflows suited to their specific needs and to recombine these primitives in ways unforeseen by the system’s designers.</p>
|
||||
<p>The core primitives include:</p>
|
||||
<ul class="simple">
|
||||
<li><p><strong>Repository Hosting</strong>: Bare Git repositories served over Reticulum links, accessible via standard Git commands through the <code class="docutils literal notranslate"><span class="pre">rns://</span></code> URL scheme.</p></li>
|
||||
<li><p><strong>Identity-Based Access Control</strong>: Fine-grained permissions managed through cryptographically verifiable identity hashes, configurable at the group, repository, or document level.</p></li>
|
||||
<li><p><strong>Release Distribution</strong>: Cryptographically signed release artifacts with embedded provenance information, verifiable offline and distributable through any Reticulum or physical path.</p></li>
|
||||
<li><p><strong>Work Document Tracking</strong>: Structured, threaded work management attached to repositories, with precise permission controls, and the ability to contain updates or discussions.</p></li>
|
||||
<li><p><strong>Forking and Mirroring</strong>: Automated replication of repositories from any accessible Git URL, with metadata tracking upstream relationships for synchronization.</p></li>
|
||||
<li><p><strong>Nomad Network Integration</strong>: Page node functionality for browsing repository contents, commit history, and release information through the Nomad Network protocol.</p></li>
|
||||
</ul>
|
||||
<p>These primitives can be composed into workflows ranging from single-developer projects to complex multi-organizational collaborations. A solo developer might use only repository hosting and release distribution. A research group might add work document tracking for structured peer review. A software distribution network might combine mirroring with cryptographic release verification to create resilient update channels.</p>
|
||||
<p>The entire system is incredibly light-weight, and can host hundreds of repositories on a Raspberry Pi.</p>
|
||||
<p>Composability is essential because <strong>creative work is diverse</strong>. Software development, academic research, technical writing, hardware design, music production and data analysis all have different requirements for collaboration, review, and distribution. A platform prescribes a single workflow and forces all users to conform. A protocol provides primitives and allows users to construct workflows appropriate to their domain.</p>
|
||||
<p>With <code class="docutils literal notranslate"><span class="pre">rngit</span></code>, you can re-build the system into anything you can imagine. Everything can be modified, extended and hooked into. Adding functionality or automation is never further away than a shell script, a cron-job, or a Python modification of the source.</p>
|
||||
</section>
|
||||
<section id="distribution-without-intermediaries">
|
||||
<h2>Distribution Without Intermediaries<a class="headerlink" href="#distribution-without-intermediaries" title="Link to this heading">¶</a></h2>
|
||||
<p>Creating software is only part of the work. Then comes actually getting it to the people needing to use it. Centralized platforms handle distribution through their own infrastructure: Content delivery networks, central package registries, and download servers accessed through platform-controlled interfaces. This convenience masks a fundamental dependency: Your ability to distribute depends on the platform’s continued operation, their policies regarding your content, and their technical infrastructure’s reach.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> release system enables distribution strategies <strong>decoupled from any single infrastructure provider</strong>. Releases are cryptographically signed using Ed25519 signatures and packaged in signed release manifests (<code class="docutils literal notranslate"><span class="pre">.rsm</span></code> files). These manifests contain embedded signatures for each artifact. The manifest provides full verifiability of all release information, and contains embedded release artifact lists, per-file <code class="docutils literal notranslate"><span class="pre">.rsg</span></code> signatures, origin information, and the creator’s Reticulum Identity. It can also be used to fetch verified updates of the software package over the network, and can always be verified completely offline.</p>
|
||||
<p>Because releases are self-verifying, they can traverse any network or physical path that Reticulum can establish. A release can travel over LoRa radio, be carried on USB drives through areas without internet connectivity, disseminated over a mirror network, or be distributed through store-and-forward mechanisms on intermittent infrastructure. Recipients can verify authenticity regardless of how they obtained the files. This is particularly valuable in low-connectivity environments where Reticulum may be the only available communication channel.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span> <span class="pre">release</span></code> command provides tools for creating, publishing, fetching, and verifying releases. When fetching a release using an <code class="docutils literal notranslate"><span class="pre">.rsm</span></code> manifest, the system validates the manifest signature against the required Reticulum Identity, extracts the origin node and repository path, connects to the origin over Reticulum, retrieves the latest release manifest, and verifies each downloaded artifact against the signatures embedded in the manifest. If any verification fails, the fetch aborts, preventing installation of corrupted or tampered files.</p>
|
||||
<p>This cryptographic verification replaces the trust model of platform distribution. Instead of trusting that a platform has not been compromised, users verify that artifacts match the signatures created by the developer’s identity. It doesn’t matter <em>how</em> they obtained the artifacts, they can <strong>always</strong> be verified. This security model shifts from <strong>institutional trust</strong> (just believe in the goodness of the platform) to <strong>cryptographic proof</strong> (verify the signatures).</p>
|
||||
</section>
|
||||
<section id="long-archive">
|
||||
<h2>Long Archive<a class="headerlink" href="#long-archive" title="Link to this heading">¶</a></h2>
|
||||
<p>Software development is often conceived as an activity of the present only: Solving today’s problems, meeting current deadlines, responding to immediate feedback. But the artifacts produced - code, documentation, releases - have lifespans extending <em>far</em> beyond their creation. They may be used for decades, studied by future developers, depended upon by systems not yet imagined, or preserved as historical records of technological development.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system is designed with this <strong>extended timeframe</strong> in mind, supporting the creation of archives that are durable, portable, and intelligible across generational timescales. Git repositories are always internally complete; they contain full history and can be migrated to new infrastructure without loss of information. Everything that <code class="docutils literal notranslate"><span class="pre">rngit</span></code> adds on top of this is stored in normal files in standard formats right next to the Git repository folders, not an esoteric database-cluster two thousand kilometers away. Because releases are cryptographically signed, they remain verifiable as authentic regardless of when or where they are retrieved. Because the system operates over Reticulum, it can function over communication mediums that may outlast the internet as we know it.</p>
|
||||
<p>This long-term perspective influences technical decisions. The use of well-established cryptographic primitives ensures that signatures will remain verifiable for centuries. The use of standard formats ensures that repositories will remain readable by future tools. The protocol-based architecture ensures that the system can evolve without losing compatibility with existing data.</p>
|
||||
<p>For critical infrastructure, this archival durability is not optional; it is essential. Communication systems, cryptographic libraries, and safety-critical code must remain available and verifiable for the lifespans of the systems that depend on them. The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system provides the tools to create such archives: distributed across multiple nodes, cryptographically verified, and independent of any corporate or governmental infrastructure, which as history has shown repeatedly, does <em>not</em> persist.</p>
|
||||
</section>
|
||||
<section id="start-of-the-road">
|
||||
<h2>Start Of The Road<a class="headerlink" href="#start-of-the-road" title="Link to this heading">¶</a></h2>
|
||||
<p>Distributed development and production over Reticulum is a <em>different mode of existence</em> for creative work. It restores the autonomy originally created by Git. It provides local sovereignty over production infrastructure, composability of workflow, and durability of artifact. It lets you filter participation through competence and cryptography rather than incentives of platform operators, raising the quality and enjoyment of work, and protecting the focus of real engineering and creative expression.</p>
|
||||
<p>This is not a system for everyone, and that is the point. It requires investment - in understanding Reticulum, in configuring infrastructure, in establishing workflows. It requires accepting responsibility for your own tools rather than delegating them to platform operators. It requires the discipline to maintain your own node, manage your own backups, and nurture your own community.</p>
|
||||
<p>But for those who make this investment, the returns are substantial. You gain <strong>immunity from platform failure</strong>; your work persists regardless of corporate decisions or service outages. You gain <strong>shelter from surveillance</strong>; your development activity is visible only to those that <em>you</em> choose to involve. You gain <strong>control over process</strong>; you decide how work is conducted, reviewed, and released, unmediated by terms of service, algorithmic feeds and thousands of uninformed and irrelevant opinions.</p>
|
||||
<p>Most importantly, though, you regain the <strong>dignity of craft</strong>. Development becomes an activity conducted among peers, equals among equals, mediated by skill and cryptographic proof rather than corporate permission, producing artifacts that stand as independent testimony to competence, functionality or beauty rather than as content feeding engagement metrics. The <em>work</em> becomes the point. The artifacts become durable. And the network becomes <em>one</em> of the tools you wield in this endeavor.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
</div>
|
||||
<footer>
|
||||
|
||||
<div class="related-pages">
|
||||
<a class="next-page" href="git.html">
|
||||
<div class="page-info">
|
||||
<div class="context">
|
||||
<span>Next</span>
|
||||
</div>
|
||||
<div class="title">Git Over Reticulum</div>
|
||||
</div>
|
||||
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
|
||||
</a>
|
||||
<a class="prev-page" href="networks.html">
|
||||
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
|
||||
<div class="page-info">
|
||||
<div class="context">
|
||||
<span>Previous</span>
|
||||
</div>
|
||||
|
||||
<div class="title">Building Networks</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="bottom-of-page">
|
||||
<div class="left-details">
|
||||
<div class="copyright">
|
||||
Copyright © 2025, Mark Qvist
|
||||
</div>
|
||||
Generated with <a href="https://www.sphinx-doc.org/">Sphinx</a> and
|
||||
<a href="https://github.com/pradyunsg/furo">Furo</a>
|
||||
|
||||
</div>
|
||||
<div class="right-details">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
</div>
|
||||
<aside class="toc-drawer">
|
||||
|
||||
|
||||
<div class="toc-sticky toc-scroll">
|
||||
<div class="toc-title-container">
|
||||
<span class="toc-title">
|
||||
On this page
|
||||
</span>
|
||||
</div>
|
||||
<div class="toc-tree-container">
|
||||
<div class="toc-tree">
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Distributed Development</a><ul>
|
||||
<li><a class="reference internal" href="#the-original-architecture">The Original Architecture</a></li>
|
||||
<li><a class="reference internal" href="#the-platform-interregnum">The Platform Interregnum</a></li>
|
||||
<li><a class="reference internal" href="#restoration">Restoration</a></li>
|
||||
<li><a class="reference internal" href="#protocols-over-platforms">Protocols Over Platforms</a></li>
|
||||
<li><a class="reference internal" href="#sovereignty-through-infrastructure">Sovereignty Through Infrastructure</a></li>
|
||||
<li><a class="reference internal" href="#artifact-centered-workflows">Artifact-Centered Workflows</a></li>
|
||||
<li><a class="reference internal" href="#composable-primitives">Composable Primitives</a></li>
|
||||
<li><a class="reference internal" href="#distribution-without-intermediaries">Distribution Without Intermediaries</a></li>
|
||||
<li><a class="reference internal" href="#long-archive">Long Archive</a></li>
|
||||
<li><a class="reference internal" href="#start-of-the-road">Start Of The Road</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+16
-32
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Code Examples - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Code Examples - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Code Examples</a></li>
|
||||
@@ -263,14 +264,10 @@
|
||||
<article role="main" id="furo-main-content">
|
||||
<section id="code-examples">
|
||||
<span id="examples-main"></span><h1>Code Examples<a class="headerlink" href="#code-examples" title="Link to this heading">¶</a></h1>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<section id="minimal">
|
||||
<span id="example-minimal"></span><h2>Minimal<a class="headerlink" href="#minimal" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Minimal</em> example demonstrates the bare-minimum setup required to connect to
|
||||
a Reticulum network from your program. In about five lines of code, you will
|
||||
have the Reticulum Network Stack initialised, and ready to pass traffic in your
|
||||
program.</p>
|
||||
<p>The <em>Minimal</em> example demonstrates the bare-minimum setup required to connect to a Reticulum network from your program. In about five lines of code, you will have the Reticulum Network Stack initialised, and ready to pass traffic in your program.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates a minimal setup, that #</span>
|
||||
<span class="c1"># will start up the Reticulum Network Stack, generate a #</span>
|
||||
@@ -379,9 +376,7 @@ program.</p>
|
||||
</section>
|
||||
<section id="announce">
|
||||
<span id="example-announce"></span><h2>Announce<a class="headerlink" href="#announce" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Announce</em> example builds upon the previous example by exploring how to
|
||||
announce a destination on the network, and how to let your program receive
|
||||
notifications about announces from relevant destinations.</p>
|
||||
<p>The <em>Announce</em> example builds upon the previous example by exploring how to announce a destination on the network, and how to let your program receive notifications about announces from relevant destinations.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates setting up announce #</span>
|
||||
<span class="c1"># callbacks, which will let an application receive a #</span>
|
||||
@@ -560,8 +555,7 @@ notifications about announces from relevant destinations.</p>
|
||||
</section>
|
||||
<section id="broadcast">
|
||||
<span id="example-broadcast"></span><h2>Broadcast<a class="headerlink" href="#broadcast" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Broadcast</em> example explores how to transmit plaintext broadcast messages
|
||||
over the network.</p>
|
||||
<p>The <em>Broadcast</em> example explores how to transmit plaintext broadcast messages over the network.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates broadcasting unencrypted #</span>
|
||||
<span class="c1"># information to any listening destinations. #</span>
|
||||
@@ -689,8 +683,7 @@ over the network.</p>
|
||||
</section>
|
||||
<section id="echo">
|
||||
<span id="example-echo"></span><h2>Echo<a class="headerlink" href="#echo" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Echo</em> example demonstrates communication between two destinations using
|
||||
the Packet interface.</p>
|
||||
<p>The <em>Echo</em> example demonstrates communication between two destinations using the Packet interface.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates a simple client/server #</span>
|
||||
<span class="c1"># echo utility. A client can send an echo request to the #</span>
|
||||
@@ -1029,8 +1022,7 @@ the Packet interface.</p>
|
||||
</section>
|
||||
<section id="link">
|
||||
<span id="example-link"></span><h2>Link<a class="headerlink" href="#link" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Link</em> example explores establishing an encrypted link to a remote
|
||||
destination, and passing traffic back and forth over the link.</p>
|
||||
<p>The <em>Link</em> example explores establishing an encrypted link to a remote destination, and passing traffic back and forth over the link.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates how to set up a link to #</span>
|
||||
<span class="c1"># a destination, and pass data back and forth over it. #</span>
|
||||
@@ -1327,8 +1319,7 @@ destination, and passing traffic back and forth over the link.</p>
|
||||
</section>
|
||||
<section id="example-identify">
|
||||
<span id="identification"></span><h2>Identification<a class="headerlink" href="#example-identify" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Identify</em> example explores identifying an intiator of a link, once
|
||||
the link has been established.</p>
|
||||
<p>The <em>Identify</em> example explores identifying an intiator of a link, once the link has been established.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates how to set up a link to #</span>
|
||||
<span class="c1"># a destination, and identify the initiator to it's peer #</span>
|
||||
@@ -1941,8 +1932,7 @@ the link has been established.</p>
|
||||
</section>
|
||||
<section id="channel">
|
||||
<span id="example-channel"></span><h2>Channel<a class="headerlink" href="#channel" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Channel</em> example explores using a <code class="docutils literal notranslate"><span class="pre">Channel</span></code> to send structured
|
||||
data between peers of a <code class="docutils literal notranslate"><span class="pre">Link</span></code>.</p>
|
||||
<p>The <em>Channel</em> example explores using a <code class="docutils literal notranslate"><span class="pre">Channel</span></code> to send structured data between peers of a <code class="docutils literal notranslate"><span class="pre">Link</span></code>.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates how to set up a link to #</span>
|
||||
<span class="c1"># a destination, and pass structured messages over it #</span>
|
||||
@@ -2338,8 +2328,7 @@ data between peers of a <code class="docutils literal notranslate"><span class="
|
||||
</section>
|
||||
<section id="buffer">
|
||||
<h2>Buffer<a class="headerlink" href="#buffer" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Buffer</em> example explores using buffered readers and writers to send
|
||||
binary data between peers of a <code class="docutils literal notranslate"><span class="pre">Link</span></code>.</p>
|
||||
<p>The <em>Buffer</em> example explores using buffered readers and writers to send binary data between peers of a <code class="docutils literal notranslate"><span class="pre">Link</span></code>.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates how to set up a link to #</span>
|
||||
<span class="c1"># a destination, and pass binary data over it using a #</span>
|
||||
@@ -2668,9 +2657,7 @@ binary data between peers of a <code class="docutils literal notranslate"><span
|
||||
</section>
|
||||
<section id="filetransfer">
|
||||
<span id="example-filetransfer"></span><h2>Filetransfer<a class="headerlink" href="#filetransfer" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>Filetransfer</em> example implements a basic file-server program that
|
||||
allow clients to connect and download files. The program uses the Resource
|
||||
interface to efficiently pass files of any size over a Reticulum <a class="reference internal" href="reference.html#api-link"><span class="std std-ref">Link</span></a>.</p>
|
||||
<p>The <em>Filetransfer</em> example implements a basic file-server program that allow clients to connect and download files. The program uses the Resource interface to efficiently pass files of any size over a Reticulum <a class="reference internal" href="reference.html#api-link"><span class="std std-ref">Link</span></a>.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates a simple filetransfer #</span>
|
||||
<span class="c1"># server and client program. The server will serve a #</span>
|
||||
@@ -3280,10 +3267,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
</section>
|
||||
<section id="custom-interfaces">
|
||||
<span id="example-custominterface"></span><h2>Custom Interfaces<a class="headerlink" href="#custom-interfaces" title="Link to this heading">¶</a></h2>
|
||||
<p>The <em>ExampleInterface</em> demonstrates creating custom interfaces for Reticulum.
|
||||
Any number of custom interfaces can be loaded and utilised by Reticulum, and
|
||||
will be fully on-par with natively included interfaces, including all supported
|
||||
<a class="reference internal" href="interfaces.html#interfaces-modes"><span class="std std-ref">interface modes</span></a> and <a class="reference internal" href="interfaces.html#interfaces-options"><span class="std std-ref">common configuration options</span></a>.</p>
|
||||
<p>The <em>ExampleInterface</em> demonstrates creating custom interfaces for Reticulum. Any number of custom interfaces can be loaded and utilised by Reticulum, and will be fully on-par with natively included interfaces, including all supported <a class="reference internal" href="interfaces.html#interfaces-modes"><span class="std std-ref">interface modes</span></a> and <a class="reference internal" href="interfaces.html#interfaces-options"><span class="std std-ref">common configuration options</span></a>.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This example illustrates creating a custom interface</span>
|
||||
<span class="c1"># definition, that can be loaded and used by Reticulum at</span>
|
||||
<span class="c1"># runtime. Any number of custom interfaces can be created</span>
|
||||
@@ -3664,7 +3648,7 @@ will be fully on-par with natively included interfaces, including all supported
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -295,7 +296,7 @@
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#"><link rel="search" title="Search" href="search.html">
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 --><title>Index - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 --><title>Index - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -178,7 +178,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -202,7 +202,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -220,6 +220,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -308,10 +309,12 @@
|
||||
<h2>B</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Reticulum.blackhole_sources">blackhole_sources() (RNS.Reticulum static method)</a>
|
||||
<li><a href="reference.html#RNS.Transport.blackhole_identity">blackhole_identity() (RNS.Transport static method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Reticulum.blackhole_sources">blackhole_sources() (RNS.Reticulum static method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Buffer">Buffer (class in RNS)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
@@ -791,6 +794,10 @@
|
||||
<section id="U" class="genindex-section">
|
||||
<h2>U</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Transport.unblackhole_identity">unblackhole_identity() (RNS.Transport static method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.MessageBase.unpack">unpack() (RNS.MessageBase method)</a>
|
||||
</li>
|
||||
@@ -839,7 +846,7 @@
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Getting Started Fast - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Getting Started Fast - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -263,40 +264,27 @@
|
||||
<article role="main" id="furo-main-content">
|
||||
<section id="getting-started-fast">
|
||||
<h1>Getting Started Fast<a class="headerlink" href="#getting-started-fast" title="Link to this heading">¶</a></h1>
|
||||
<p>The best way to get started with the Reticulum Network Stack depends on what
|
||||
you want to do. This guide will outline sensible starting paths for different
|
||||
scenarios.</p>
|
||||
<p>The best way to get started with the Reticulum Network Stack depends on what you want to do. This guide will outline sensible starting paths for different scenarios.</p>
|
||||
<section id="standalone-reticulum-installation">
|
||||
<h2>Standalone Reticulum Installation<a class="headerlink" href="#standalone-reticulum-installation" title="Link to this heading">¶</a></h2>
|
||||
<p>If you simply want to install Reticulum and related utilities on a system,
|
||||
the easiest way is via the <code class="docutils literal notranslate"><span class="pre">pip</span></code> package manager:</p>
|
||||
<p>If you simply want to install Reticulum and related utilities on a system, the easiest way is via the <code class="docutils literal notranslate"><span class="pre">pip</span></code> package manager:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>pip<span class="w"> </span>install<span class="w"> </span>rns
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you do not already have pip installed, you can install it using the package manager
|
||||
of your system with a command like <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">apt</span> <span class="pre">install</span> <span class="pre">python3-pip</span></code>,
|
||||
<code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">pamac</span> <span class="pre">install</span> <span class="pre">python-pip</span></code> or similar.</p>
|
||||
<p>You can also dowload the Reticulum release wheels from GitHub, or other release channels,
|
||||
and install them offline using <code class="docutils literal notranslate"><span class="pre">pip</span></code>:</p>
|
||||
<p>If you do not already have pip installed, you can install it using the package manager of your system with a command like <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">apt</span> <span class="pre">install</span> <span class="pre">python3-pip</span></code>, <code class="docutils literal notranslate"><span class="pre">sudo</span> <span class="pre">pamac</span> <span class="pre">install</span> <span class="pre">python-pip</span></code> or similar.</p>
|
||||
<p>You can also dowload the Reticulum release wheels from GitHub, or other release channels, and install them offline using <code class="docutils literal notranslate"><span class="pre">pip</span></code>:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>pip<span class="w"> </span>install<span class="w"> </span>./rns-1.1.2-py3-none-any.whl
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>On platforms that limit user package installation via <code class="docutils literal notranslate"><span class="pre">pip</span></code>, you may need to manually
|
||||
allow this using the <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> command line flag when installing. This
|
||||
will not actually break any packages, unless you have installed Reticulum directly via
|
||||
your operating system’s package manager.</p>
|
||||
<p>On platforms that limit user package installation via <code class="docutils literal notranslate"><span class="pre">pip</span></code>, you may need to manually allow this using the <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> command line flag when installing. This will not actually break any packages, unless you have installed Reticulum directly via your operating system’s package manager.</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>pip<span class="w"> </span>install<span class="w"> </span>rns<span class="w"> </span>--break-system-packages
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For more detailed installation instructions, please see the
|
||||
<a class="reference internal" href="#install-guides"><span class="std std-ref">Platform-Specific Install Notes</span></a> section.</p>
|
||||
<p>After installation is complete, it might be helpful to refer to the
|
||||
<a class="reference internal" href="using.html#using-main"><span class="std std-ref">Using Reticulum on Your System</span></a> chapter.</p>
|
||||
<p>For more detailed installation instructions, please see the <a class="reference internal" href="#install-guides"><span class="std std-ref">Platform-Specific Install Notes</span></a> section.</p>
|
||||
<p>After installation is complete, it might be helpful to refer to the <a class="reference internal" href="using.html#using-main"><span class="std std-ref">Using Reticulum on Your System</span></a> chapter.</p>
|
||||
<section id="resolving-dependency-installation-issues">
|
||||
<h3>Resolving Dependency & Installation Issues<a class="headerlink" href="#resolving-dependency-installation-issues" title="Link to this heading">¶</a></h3>
|
||||
<p>On some platforms, there may not be binary packages available for all dependencies, and
|
||||
<code class="docutils literal notranslate"><span class="pre">pip</span></code> installation may fail with an error message. In these cases, the issue can usually
|
||||
be resolved by installing the development essentials packages for your platform:</p>
|
||||
<p>On some platforms, there may not be binary packages available for all dependencies, and <code class="docutils literal notranslate"><span class="pre">pip</span></code> installation may fail with an error message. In these cases, the issue can usually be resolved by installing the development essentials packages for your platform:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># Debian / Ubuntu / Derivatives</span>
|
||||
sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>build-essential
|
||||
|
||||
@@ -307,59 +295,28 @@ sudo<span class="w"> </span>pamac<span class="w"> </span>install<span class="w">
|
||||
sudo<span class="w"> </span>dnf<span class="w"> </span>groupinstall<span class="w"> </span><span class="s2">"Development Tools"</span><span class="w"> </span><span class="s2">"Development Libraries"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>With the base development packages installed, <code class="docutils literal notranslate"><span class="pre">pip</span></code> should be able to compile any missing
|
||||
dependencies from source, and complete installation even on platforms that don’t have pre-
|
||||
compiled packages available.</p>
|
||||
<p>With the base development packages installed, <code class="docutils literal notranslate"><span class="pre">pip</span></code> should be able to compile any missing dependencies from source, and complete installation even on platforms that don’t have pre-compiled packages available.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="try-using-a-reticulum-based-program">
|
||||
<h2>Try Using a Reticulum-based Program<a class="headerlink" href="#try-using-a-reticulum-based-program" title="Link to this heading">¶</a></h2>
|
||||
<p>If you simply want to try using a program built with Reticulum, a <a class="reference internal" href="software.html#software-main"><span class="std std-ref">range of different
|
||||
programs</span></a> exist that allow basic communication and a various other useful functions,
|
||||
even over extremely low-bandwidth Reticulum networks.</p>
|
||||
<p>If you simply want to try using a program built with Reticulum, a <a class="reference internal" href="software.html#software-main"><span class="std std-ref">range of different programs</span></a> exist that allow basic communication and a various other useful functions, even over extremely low-bandwidth Reticulum networks.</p>
|
||||
</section>
|
||||
<section id="using-the-included-utilities">
|
||||
<h2>Using the Included Utilities<a class="headerlink" href="#using-the-included-utilities" title="Link to this heading">¶</a></h2>
|
||||
<p>Reticulum comes with a range of included utilities that make it easier to
|
||||
manage your network, check connectivity and make Reticulum available to other
|
||||
programs on your system.</p>
|
||||
<p>You can use <code class="docutils literal notranslate"><span class="pre">rnsd</span></code> to run Reticulum as a background or foreground service,
|
||||
and the <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code>, <code class="docutils literal notranslate"><span class="pre">rnpath</span></code> and <code class="docutils literal notranslate"><span class="pre">rnprobe</span></code> utilities to view and query
|
||||
network status and connectivity.</p>
|
||||
<p>To learn more about these utility programs, have a look at the
|
||||
<a class="reference internal" href="using.html#using-main"><span class="std std-ref">Using Reticulum on Your System</span></a> chapter of this manual.</p>
|
||||
<p>Reticulum comes with a range of included utilities that make it easier to manage your network, check connectivity and make Reticulum available to other programs on your system.</p>
|
||||
<p>You can use <code class="docutils literal notranslate"><span class="pre">rnsd</span></code> to run Reticulum as a background or foreground service, and the <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code>, <code class="docutils literal notranslate"><span class="pre">rnpath</span></code> and <code class="docutils literal notranslate"><span class="pre">rnprobe</span></code> utilities to view and query network status and connectivity.</p>
|
||||
<p>To learn more about these utility programs, have a look at the <a class="reference internal" href="using.html#using-main"><span class="std std-ref">Using Reticulum on Your System</span></a> chapter of this manual.</p>
|
||||
</section>
|
||||
<section id="creating-a-network-with-reticulum">
|
||||
<h2>Creating a Network With Reticulum<a class="headerlink" href="#creating-a-network-with-reticulum" title="Link to this heading">¶</a></h2>
|
||||
<p>To create a network, you will need to specify one or more <em>interfaces</em> for
|
||||
Reticulum to use. This is done in the Reticulum configuration file, which by
|
||||
default is located at <code class="docutils literal notranslate"><span class="pre">~/.reticulum/config</span></code>. You can get an example
|
||||
configuration file with all options via <code class="docutils literal notranslate"><span class="pre">rnsd</span> <span class="pre">--exampleconfig</span></code>.</p>
|
||||
<p>When Reticulum is started for the first time, it will create a default
|
||||
configuration file, with one active interface. This default interface uses
|
||||
your existing Ethernet and WiFi networks (if any), and only allows you to
|
||||
communicate with other Reticulum peers within your local broadcast domains.</p>
|
||||
<p>To communicate further, you will have to add one or more interfaces. The default
|
||||
configuration includes a number of examples, ranging from using TCP over the
|
||||
internet, to LoRa and Packet Radio interfaces.</p>
|
||||
<p>With Reticulum, you only need to configure what interfaces you want to communicate
|
||||
over. There is no need to configure address spaces, subnets, routing tables,
|
||||
or other things you might be used to from other network types.</p>
|
||||
<p>Once Reticulum knows which interfaces it should use, it will automatically
|
||||
discover topography and configure transport of data to any destinations it
|
||||
knows about.</p>
|
||||
<p>In situations where you already have an established WiFi or Ethernet network, and
|
||||
many devices that want to utilise the same external Reticulum network paths (for example over
|
||||
LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by
|
||||
adding any external interfaces to the configuration of this system, and then enabling transport on it. Any
|
||||
other device on your local WiFi will then be able to connect to this wider Reticulum
|
||||
network just using the default (<a class="reference internal" href="interfaces.html#interfaces-auto"><span class="std std-ref">AutoInterface</span></a>) configuration.</p>
|
||||
<p>Possibly, the examples in the config file are enough to get you started. If
|
||||
you want more information, you can read the <a class="reference internal" href="networks.html#networks-main"><span class="std std-ref">Building Networks</span></a>
|
||||
and <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Interfaces</span></a> chapters of this manual, but most importantly,
|
||||
start with reading the next section, <a class="reference internal" href="#bootstrapping-connectivity"><span class="std std-ref">Bootstrapping Connectivity</span></a>,
|
||||
as this provides the most essential understanding of how to ensure reliable
|
||||
connectivity with a minimum of maintenance.</p>
|
||||
<p>To create a network, you will need to specify one or more <em>interfaces</em> for Reticulum to use. This is done in the Reticulum configuration file, which by default is located at <code class="docutils literal notranslate"><span class="pre">~/.reticulum/config</span></code>. You can get an example configuration file with all options via <code class="docutils literal notranslate"><span class="pre">rnsd</span> <span class="pre">--exampleconfig</span></code>.</p>
|
||||
<p>When Reticulum is started for the first time, it will create a default configuration file, with one active interface. This default interface uses your existing Ethernet and WiFi networks (if any), and only allows you to communicate with other Reticulum peers within your local broadcast domains.</p>
|
||||
<p>To communicate further, you will have to add one or more interfaces. The default configuration includes a number of examples, ranging from using TCP over the internet, to LoRa and Packet Radio interfaces.</p>
|
||||
<p>With Reticulum, you only need to configure what interfaces you want to communicate over. There is no need to configure address spaces, subnets, routing tables, or other things you might be used to from other network types.</p>
|
||||
<p>Once Reticulum knows which interfaces it should use, it will automatically discover topography and configure transport of data to any destinations it knows about.</p>
|
||||
<p>In situations where you already have an established WiFi or Ethernet network, and many devices that want to utilise the same external Reticulum network paths (for example over LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by adding any external interfaces to the configuration of this system, and then enabling transport on it. Any other device on your local WiFi will then be able to connect to this wider Reticulum network just using the default (<a class="reference internal" href="interfaces.html#interfaces-auto"><span class="std std-ref">AutoInterface</span></a>) configuration.</p>
|
||||
<p>Possibly, the examples in the config file are enough to get you started. If you want more information, you can read the <a class="reference internal" href="networks.html#networks-main"><span class="std std-ref">Building Networks</span></a> and <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Interfaces</span></a> chapters of this manual, but most importantly, start with reading the next section, <a class="reference internal" href="#bootstrapping-connectivity"><span class="std std-ref">Bootstrapping Connectivity</span></a>, as this provides the most essential understanding of how to ensure reliable connectivity with a minimum of maintenance.</p>
|
||||
</section>
|
||||
<section id="bootstrapping-connectivity">
|
||||
<span id="id1"></span><h2>Bootstrapping Connectivity<a class="headerlink" href="#bootstrapping-connectivity" title="Link to this heading">¶</a></h2>
|
||||
@@ -424,17 +381,10 @@ connectivity with a minimum of maintenance.</p>
|
||||
</section>
|
||||
<section id="hosting-public-entrypoints">
|
||||
<span id="hosting-entrypoints"></span><h2>Hosting Public Entrypoints<a class="headerlink" href="#hosting-public-entrypoints" title="Link to this heading">¶</a></h2>
|
||||
<p>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
|
||||
Internet. This section offers some helpful pointers. Once you have set up your public entrypoint, it is a great idea to <a class="reference internal" href="interfaces.html#interfaces-discoverable"><span class="std std-ref">make it discoverable over Reticulum</span></a>.</p>
|
||||
<p>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 Internet. This section offers some helpful pointers. Once you have set up your public entrypoint, it is a great idea to <a class="reference internal" href="interfaces.html#interfaces-discoverable"><span class="std std-ref">make it discoverable over Reticulum</span></a>.</p>
|
||||
<p>You will need a machine, physical or virtual with a public IP address, that can be reached by other devices on the Internet.</p>
|
||||
<p>The most efficient and performant way to host a connectable entry-point supporting many
|
||||
users is to use the <code class="docutils literal notranslate"><span class="pre">BackboneInterface</span></code>. This interface type is fully compatible with
|
||||
the <code class="docutils literal notranslate"><span class="pre">TCPClientInterface</span></code> and <code class="docutils literal notranslate"><span class="pre">TCPServerInterface</span></code> types, but much faster and uses
|
||||
less system resources, allowing your device to handle thousands of connections even on
|
||||
small systems.</p>
|
||||
<p>It is also important to set your connectable interface to <code class="docutils literal notranslate"><span class="pre">gateway</span></code> mode, since this
|
||||
will greatly improve network convergence time and path resolution for anyone connecting
|
||||
to your entry-point.</p>
|
||||
<p>The most efficient and performant way to host a connectable entry-point supporting many users is to use the <code class="docutils literal notranslate"><span class="pre">BackboneInterface</span></code>. This interface type is fully compatible with the <code class="docutils literal notranslate"><span class="pre">TCPClientInterface</span></code> and <code class="docutils literal notranslate"><span class="pre">TCPServerInterface</span></code> types, but much faster and uses less system resources, allowing your device to handle thousands of connections even on small systems.</p>
|
||||
<p>It is also important to set your connectable interface to <code class="docutils literal notranslate"><span class="pre">gateway</span></code> mode, since this will greatly improve network convergence time and path resolution for anyone connecting to your entry-point.</p>
|
||||
<div class="highlight-ini notranslate"><div class="highlight"><pre><span></span><span class="c1"># This example demonstrates a backbone interface</span>
|
||||
<span class="c1"># configured for acting as a gateway for users to</span>
|
||||
<span class="c1"># connect to either a public or private network</span>
|
||||
@@ -454,8 +404,7 @@ to your entry-point.</p>
|
||||
<span class="w"> </span><span class="na">announce_rate_grace</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">6</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If instead you want to make a private entry-point from the Internet, you can use the
|
||||
<a class="reference internal" href="interfaces.html#interfaces-options"><span class="std std-ref">IFAC name and passphrase options</span></a> to secure your interface with a network name and passphrase.</p>
|
||||
<p>If instead you want to make a private entry-point from the Internet, you can use the <a class="reference internal" href="interfaces.html#interfaces-options"><span class="std std-ref">IFAC name and passphrase options</span></a> to secure your interface with a network name and passphrase.</p>
|
||||
<div class="highlight-ini notranslate"><div class="highlight"><pre><span></span><span class="c1"># A private entry-point requiring a pre-shared</span>
|
||||
<span class="c1"># network name and passphrase to connect to.</span>
|
||||
|
||||
@@ -469,104 +418,51 @@ to your entry-point.</p>
|
||||
<span class="w"> </span><span class="na">passphrase</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">2owjajquafIanPecAc</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you are hosting an entry-point on an operating system that does not support
|
||||
<code class="docutils literal notranslate"><span class="pre">BackboneInterface</span></code>, you can use <code class="docutils literal notranslate"><span class="pre">TCPServerInterface</span></code> instead, although it will
|
||||
not be as performant.</p>
|
||||
<p>If you are hosting an entry-point on an operating system that does not support <code class="docutils literal notranslate"><span class="pre">BackboneInterface</span></code>, you can use <code class="docutils literal notranslate"><span class="pre">TCPServerInterface</span></code> instead, although it will not be as performant.</p>
|
||||
</section>
|
||||
<section id="connecting-reticulum-instances-over-the-internet">
|
||||
<h2>Connecting Reticulum Instances Over the Internet<a class="headerlink" href="#connecting-reticulum-instances-over-the-internet" title="Link to this heading">¶</a></h2>
|
||||
<p>Reticulum currently offers three interfaces suitable for connecting instances over the Internet: <a class="reference internal" href="interfaces.html#interfaces-backbone"><span class="std std-ref">Backbone</span></a>, <a class="reference internal" href="interfaces.html#interfaces-tcps"><span class="std std-ref">TCP</span></a>
|
||||
and <a class="reference internal" href="interfaces.html#interfaces-i2p"><span class="std std-ref">I2P</span></a>. Each interface offers a different set of features, and Reticulum
|
||||
users should carefully choose the interface which best suites their needs.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">TCPServerInterface</span></code> allows users to host an instance accessible over TCP/IP. This
|
||||
method is generally faster, lower latency, and more energy efficient than using <code class="docutils literal notranslate"><span class="pre">I2PInterface</span></code>,
|
||||
however it also leaks more data about the server host.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">BackboneInterface</span></code> is a very fast and efficient interface type available on POSIX operating
|
||||
systems, designed to handle thousands of connections simultaneously with low memory, processing
|
||||
and I/O overhead. It is fully compatible with the TCP-based interface types.</p>
|
||||
<p>TCP connections reveal the IP address of both your instance and the server to anyone who can
|
||||
inspect the connection. Someone could use this information to determine your location or identity. Adversaries
|
||||
inspecting your packets may be able to record packet metadata like time of transmission and packet size.
|
||||
Even though Reticulum encrypts traffic, TCP does not, so an adversary may be able to use
|
||||
packet inspection to learn that a system is running Reticulum, and what other IP addresses connect to it.
|
||||
Hosting a publicly reachable instance over TCP also requires a publicly reachable IP address,
|
||||
which most Internet connections don’t offer anymore.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">I2PInterface</span></code> routes messages through the <a class="reference external" href="https://geti2p.net/en/">Invisible Internet Protocol
|
||||
(I2P)</a>. To use this interface, users must also run an I2P daemon in
|
||||
parallel to <code class="docutils literal notranslate"><span class="pre">rnsd</span></code>. For always-on I2P nodes it is recommended to use <a class="reference external" href="https://i2pd.website/">i2pd</a>.</p>
|
||||
<p>By default, I2P will encrypt and mix all traffic sent over the Internet, and
|
||||
hide both the sender and receiver Reticulum instance IP addresses. Running an I2P node
|
||||
will also relay other I2P user’s encrypted packets, which will use extra
|
||||
bandwidth and compute power, but also makes timing attacks and other forms of
|
||||
deep-packet-inspection much more difficult.</p>
|
||||
<p>Reticulum currently offers three interfaces suitable for connecting instances over the Internet: <a class="reference internal" href="interfaces.html#interfaces-backbone"><span class="std std-ref">Backbone</span></a>, <a class="reference internal" href="interfaces.html#interfaces-tcps"><span class="std std-ref">TCP</span></a> and <a class="reference internal" href="interfaces.html#interfaces-i2p"><span class="std std-ref">I2P</span></a>. Each interface offers a different set of features, and Reticulum users should carefully choose the interface which best suites their needs.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">TCPServerInterface</span></code> allows users to host an instance accessible over TCP/IP. This method is generally faster, lower latency, and more energy efficient than using <code class="docutils literal notranslate"><span class="pre">I2PInterface</span></code>, however it also leaks more data about the server host.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">BackboneInterface</span></code> is a very fast and efficient interface type available on POSIX operating systems, designed to handle thousands of connections simultaneously with low memory, processing and I/O overhead. It is fully compatible with the TCP-based interface types.</p>
|
||||
<p>TCP connections reveal the IP address of both your instance and the server to anyone who can inspect the connection. Someone could use this information to determine your location or identity. Adversaries inspecting your packets may be able to record packet metadata like time of transmission and packet size. Even though Reticulum encrypts traffic, TCP does not, so an adversary may be able to use packet inspection to learn that a system is running Reticulum, and what other IP addresses connect to it. Hosting a publicly reachable instance over TCP also requires a publicly reachable IP address, which most Internet connections don’t offer anymore.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">I2PInterface</span></code> routes messages through the <a class="reference external" href="https://geti2p.net/en/">Invisible Internet Protocol (I2P)</a>. To use this interface, users must also run an I2P daemon in parallel to <code class="docutils literal notranslate"><span class="pre">rnsd</span></code>. For always-on I2P nodes it is recommended to use <a class="reference external" href="https://i2pd.website/">i2pd</a>.</p>
|
||||
<p>By default, I2P will encrypt and mix all traffic sent over the Internet, and hide both the sender and receiver Reticulum instance IP addresses. Running an I2P node will also relay other I2P user’s encrypted packets, which will use extra bandwidth and compute power, but also makes timing attacks and other forms of deep-packet-inspection much more difficult.</p>
|
||||
<p>I2P also allows users to host globally available Reticulum instances from non-public IP’s and behind firewalls and NAT.</p>
|
||||
<p>In general it is recommended to use an I2P node if you want to host a publicly accessible
|
||||
instance, while preserving anonymity. If you care more about performance, and a slightly
|
||||
easier setup, use TCP.</p>
|
||||
<p>In general it is recommended to use an I2P node if you want to host a publicly accessible instance, while preserving anonymity. If you care more about performance, and a slightly easier setup, use TCP.</p>
|
||||
</section>
|
||||
<section id="adding-radio-interfaces">
|
||||
<h2>Adding Radio Interfaces<a class="headerlink" href="#adding-radio-interfaces" title="Link to this heading">¶</a></h2>
|
||||
<p>Once you have Reticulum installed and working, you can add radio interfaces with
|
||||
any compatible hardware you have available. Reticulum supports a wide range of radio
|
||||
hardware, and if you already have any available, it is very likely that it will
|
||||
work with Reticulum. For information on how to configure this, see the
|
||||
<a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Interfaces</span></a> section of this manual.</p>
|
||||
<p>If you do not already have transceiver hardware available, you can easily and
|
||||
cheaply build an <a class="reference internal" href="hardware.html#rnode-main"><span class="std std-ref">RNode</span></a>, which is a general-purpose long-range
|
||||
digital radio transceiver, that integrates easily with Reticulum.</p>
|
||||
<p>To build one yourself requires installing a custom firmware on a supported LoRa
|
||||
development board with an auto-install script or web-based flasher.
|
||||
Please see the <a class="reference internal" href="hardware.html#hardware-main"><span class="std std-ref">Communications Hardware</span></a> chapter for a guide.
|
||||
If you prefer purchasing a ready-made unit, you can refer to the
|
||||
<span class="xref std std-ref">list of suppliers</span>.</p>
|
||||
<p>Other radio-based hardware interfaces are being developed and made available by
|
||||
the broader Reticulum community. You can find more information on such topics
|
||||
over Reticulum-based information sharing systems.</p>
|
||||
<p>If you have communications hardware that is not already supported by any of the
|
||||
<a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">existing interface types</span></a>, it is easy to write (and potentially
|
||||
publish) a <a class="reference internal" href="interfaces.html#interfaces-custom"><span class="std std-ref">custom interface module</span></a> that makes it compatible with Reticulum.</p>
|
||||
<p>Once you have Reticulum installed and working, you can add radio interfaces with any compatible hardware you have available. Reticulum supports a wide range of radio hardware, and if you already have any available, it is very likely that it will work with Reticulum. For information on how to configure this, see the <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Interfaces</span></a> section of this manual.</p>
|
||||
<p>If you do not already have transceiver hardware available, you can easily and cheaply build an <a class="reference internal" href="hardware.html#rnode-main"><span class="std std-ref">RNode</span></a>, which is a general-purpose long-range digital radio transceiver, that integrates easily with Reticulum.</p>
|
||||
<p>To build one yourself requires installing a custom firmware on a supported LoRa development board with an auto-install script or web-based flasher. Please see the <a class="reference internal" href="hardware.html#hardware-main"><span class="std std-ref">Communications Hardware</span></a> chapter for a guide. If you prefer purchasing a ready-made unit, you can refer to the <span class="xref std std-ref">list of suppliers</span>.</p>
|
||||
<p>Other radio-based hardware interfaces are being developed and made available by the broader Reticulum community. You can find more information on such topics over Reticulum-based information sharing systems.</p>
|
||||
<p>If you have communications hardware that is not already supported by any of the <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">existing interface types</span></a>, it is easy to write (and potentially publish) a <a class="reference internal" href="interfaces.html#interfaces-custom"><span class="std std-ref">custom interface module</span></a> that makes it compatible with Reticulum.</p>
|
||||
</section>
|
||||
<section id="creating-and-using-custom-interfaces">
|
||||
<h2>Creating and Using Custom Interfaces<a class="headerlink" href="#creating-and-using-custom-interfaces" title="Link to this heading">¶</a></h2>
|
||||
<p>While Reticulum includes a flexible and broad range of built-in interfaces, these
|
||||
will not cover every conceivable type of communications hardware that Reticulum
|
||||
can potentially use to communicate.</p>
|
||||
<p>It is therefore possible to easily write your own interface modules, that can be
|
||||
loaded at run-time and used on-par with any of the built-in interface types.</p>
|
||||
<p>For more information on this subject, and code examples to build on, please see
|
||||
the <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Configuring Interfaces</span></a> chapter.</p>
|
||||
<p>While Reticulum includes a flexible and broad range of built-in interfaces, these will not cover every conceivable type of communications hardware that Reticulum can potentially use to communicate.</p>
|
||||
<p>It is therefore possible to easily write your own interface modules, that can be loaded at run-time and used on-par with any of the built-in interface types.</p>
|
||||
<p>For more information on this subject, and code examples to build on, please see the <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Configuring Interfaces</span></a> chapter.</p>
|
||||
</section>
|
||||
<section id="develop-a-program-with-reticulum">
|
||||
<h2>Develop a Program with Reticulum<a class="headerlink" href="#develop-a-program-with-reticulum" title="Link to this heading">¶</a></h2>
|
||||
<p>If you want to develop programs that use Reticulum, the easiest way to get
|
||||
started is to install the latest release of Reticulum via pip:</p>
|
||||
<p>If you want to develop programs that use Reticulum, the easiest way to get started is to install the latest release of Reticulum via pip:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="n">rns</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The above command will install Reticulum and dependencies, and you will be
|
||||
ready to import and use RNS in your own programs. The next step will most
|
||||
likely be to look at some <a class="reference internal" href="examples.html#examples-main"><span class="std std-ref">Example Programs</span></a>.</p>
|
||||
<p>The entire Reticulum API is documented in the <a class="reference internal" href="reference.html#api-main"><span class="std std-ref">API Reference</span></a>
|
||||
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 <a class="reference internal" href="understanding.html#understanding-main"><span class="std std-ref">Understanding Reticulum</span></a> chapter.</p>
|
||||
<p>The above command will install Reticulum and dependencies, and you will be ready to import and use RNS in your own programs. The next step will most likely be to look at some <a class="reference internal" href="examples.html#examples-main"><span class="std std-ref">Example Programs</span></a>.</p>
|
||||
<p>The entire Reticulum API is documented in the <a class="reference internal" href="reference.html#api-main"><span class="std std-ref">API Reference</span></a> 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 <a class="reference internal" href="understanding.html#understanding-main"><span class="std std-ref">Understanding Reticulum</span></a> chapter.</p>
|
||||
</section>
|
||||
<section id="platform-specific-install-notes">
|
||||
<span id="install-guides"></span><h2>Platform-Specific Install Notes<a class="headerlink" href="#platform-specific-install-notes" title="Link to this heading">¶</a></h2>
|
||||
<p>Some platforms require a slightly different installation procedure, or have
|
||||
various quirks that are worth being aware of. These are listed here.</p>
|
||||
<p>Some platforms require a slightly different installation procedure, or have various quirks that are worth being aware of. These are listed here.</p>
|
||||
<section id="android">
|
||||
<h3>Android<a class="headerlink" href="#android" title="Link to this heading">¶</a></h3>
|
||||
<p>Reticulum can be used on Android in different ways. The easiest way to get
|
||||
started is using an app like <a class="reference external" href="https://unsigned.io/sideband">Sideband</a>.</p>
|
||||
<p>For more control and features, you can use Reticulum and related programs via
|
||||
the <a class="reference external" href="https://termux.com/">Termux app</a>, at the time of writing available on
|
||||
<a class="reference external" href="https://f-droid.org">F-droid</a>.</p>
|
||||
<p>Termux is a terminal emulator and Linux environment for Android based devices,
|
||||
which includes the ability to use many different programs and libraries,
|
||||
including Reticulum.</p>
|
||||
<p>To use Reticulum within the Termux environment, you will need to install
|
||||
<code class="docutils literal notranslate"><span class="pre">python</span></code> and the <code class="docutils literal notranslate"><span class="pre">python-cryptography</span></code> library using <code class="docutils literal notranslate"><span class="pre">pkg</span></code>, the package-manager
|
||||
build into Termux. After that, you can use <code class="docutils literal notranslate"><span class="pre">pip</span></code> to install Reticulum.</p>
|
||||
<p>Reticulum can be used on Android in different ways. The easiest way to get started is using an app like <a class="reference external" href="https://unsigned.io/sideband">Sideband</a>.</p>
|
||||
<p>For more control and features, you can use Reticulum and related programs via the <a class="reference external" href="https://termux.com/">Termux app</a>, at the time of writing available on <a class="reference external" href="https://f-droid.org">F-droid</a>.</p>
|
||||
<p>Termux is a terminal emulator and Linux environment for Android based devices, which includes the ability to use many different programs and libraries, including Reticulum.</p>
|
||||
<p>To use Reticulum within the Termux environment, you will need to install <code class="docutils literal notranslate"><span class="pre">python</span></code> and the <code class="docutils literal notranslate"><span class="pre">python-cryptography</span></code> library using <code class="docutils literal notranslate"><span class="pre">pkg</span></code>, the package-manager build into Termux. After that, you can use <code class="docutils literal notranslate"><span class="pre">pip</span></code> to install Reticulum.</p>
|
||||
<p>From within Termux, execute the following:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># First, make sure indexes and packages are up to date.</span>
|
||||
pkg<span class="w"> </span>update
|
||||
@@ -582,9 +478,7 @@ pip<span class="w"> </span>install<span class="w"> </span>wheel<span class="w">
|
||||
pip<span class="w"> </span>install<span class="w"> </span>rns
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If for some reason the <code class="docutils literal notranslate"><span class="pre">python-cryptography</span></code> package is not available for
|
||||
your platform via the Termux package manager, you can attempt to build it
|
||||
locally on your device using the following command:</p>
|
||||
<p>If for some reason the <code class="docutils literal notranslate"><span class="pre">python-cryptography</span></code> package is not available for your platform via the Termux package manager, you can attempt to build it locally on your device using the following command:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># First, make sure indexes and packages are up to date.</span>
|
||||
pkg<span class="w"> </span>update
|
||||
pkg<span class="w"> </span>upgrade
|
||||
@@ -609,15 +503,11 @@ pip<span class="w"> </span>install<span class="w"> </span>cryptography
|
||||
pip<span class="w"> </span>install<span class="w"> </span>rns
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>It is also possible to include Reticulum in apps compiled and distributed as
|
||||
Android APKs. A detailed tutorial and example source code will be included
|
||||
here at a later point. Until then you can use the <a class="reference external" href="https://github.com/markqvist/sideband">Sideband source code</a> as an example and starting point.</p>
|
||||
<p>It is also possible to include Reticulum in apps compiled and distributed as Android APKs. A detailed tutorial and example source code will be included here at a later point. Until then you can use the <a class="reference external" href="https://github.com/markqvist/sideband">Sideband source code</a> as an example and starting point.</p>
|
||||
</section>
|
||||
<section id="arm64">
|
||||
<h3>ARM64<a class="headerlink" href="#arm64" title="Link to this heading">¶</a></h3>
|
||||
<p>On some architectures, including ARM64, not all dependencies have precompiled
|
||||
binaries. On such systems, you may need to install <code class="docutils literal notranslate"><span class="pre">python3-dev</span></code> (or similar) before
|
||||
installing Reticulum or programs that depend on Reticulum.</p>
|
||||
<p>On some architectures, including ARM64, not all dependencies have precompiled binaries. On such systems, you may need to install <code class="docutils literal notranslate"><span class="pre">python3-dev</span></code> (or similar) before installing Reticulum or programs that depend on Reticulum.</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install Python and development packages</span>
|
||||
sudo<span class="w"> </span>apt<span class="w"> </span>update
|
||||
sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>python3<span class="w"> </span>python3-pip<span class="w"> </span>python3-dev
|
||||
@@ -631,11 +521,7 @@ on your system locally.</p>
|
||||
</section>
|
||||
<section id="debian-bookworm">
|
||||
<h3>Debian Bookworm<a class="headerlink" href="#debian-bookworm" title="Link to this heading">¶</a></h3>
|
||||
<p>On versions of Debian released after April 2023, it is no longer possible by default
|
||||
to use <code class="docutils literal notranslate"><span class="pre">pip</span></code> to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement <code class="docutils literal notranslate"><span class="pre">pipx</span></code> command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.</p>
|
||||
<p>On versions of Debian released after April 2023, it is no longer possible by default to use <code class="docutils literal notranslate"><span class="pre">pip</span></code> to install packages onto your system. Unfortunately, you will need to use the replacement <code class="docutils literal notranslate"><span class="pre">pipx</span></code> command instead, which places installed packages in an isolated environment. This should not negatively affect Reticulum, but will not work for including and using Reticulum in your own scripts and programs.</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install pipx</span>
|
||||
sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>pipx
|
||||
|
||||
@@ -646,37 +532,25 @@ pipx<span class="w"> </span>ensurepath
|
||||
pipx<span class="w"> </span>install<span class="w"> </span>rns
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Alternatively, you can restore normal behaviour to <code class="docutils literal notranslate"><span class="pre">pip</span></code> by creating or editing
|
||||
the configuration file located at <code class="docutils literal notranslate"><span class="pre">~/.config/pip/pip.conf</span></code>, and adding the
|
||||
following section:</p>
|
||||
<p>Alternatively, you can restore normal behaviour to <code class="docutils literal notranslate"><span class="pre">pip</span></code> by creating or editing the configuration file located at <code class="docutils literal notranslate"><span class="pre">~/.config/pip/pip.conf</span></code>, and adding the following section:</p>
|
||||
<div class="highlight-ini notranslate"><div class="highlight"><pre><span></span><span class="k">[global]</span>
|
||||
<span class="na">break-system-packages</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">true</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For a one-shot installation of Reticulum, without globally enabling the <code class="docutils literal notranslate"><span class="pre">break-system-packages</span></code>
|
||||
option, you can use the following command:</p>
|
||||
<p>For a one-shot installation of Reticulum, without globally enabling the <code class="docutils literal notranslate"><span class="pre">break-system-packages</span></code> option, you can use the following command:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>pip<span class="w"> </span>install<span class="w"> </span>rns<span class="w"> </span>--break-system-packages
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="macos">
|
||||
<h3>MacOS<a class="headerlink" href="#macos" title="Link to this heading">¶</a></h3>
|
||||
<p>To install Reticulum on macOS, you will need to have Python and the <code class="docutils literal notranslate"><span class="pre">pip</span></code> package
|
||||
manager installed.</p>
|
||||
<p>Systems running macOS can vary quite widely in whether or not Python is pre-installed,
|
||||
and if it is, which version is installed, and whether the <code class="docutils literal notranslate"><span class="pre">pip</span></code> package manager is
|
||||
also installed and set up. If in doubt, you can <a class="reference external" href="https://www.python.org/downloads/">download and install</a>
|
||||
Python manually.</p>
|
||||
<p>When Python and <code class="docutils literal notranslate"><span class="pre">pip</span></code> is available on your system, simply open a terminal window
|
||||
and use one of the following commands:</p>
|
||||
<p>To install Reticulum on macOS, you will need to have Python and the <code class="docutils literal notranslate"><span class="pre">pip</span></code> package manager installed.</p>
|
||||
<p>Systems running macOS can vary quite widely in whether or not Python is pre-installed, and if it is, which version is installed, and whether the <code class="docutils literal notranslate"><span class="pre">pip</span></code> package manager is also installed and set up. If in doubt, you can <a class="reference external" href="https://www.python.org/downloads/">download and install</a> Python manually.</p>
|
||||
<p>When Python and <code class="docutils literal notranslate"><span class="pre">pip</span></code> is available on your system, simply open a terminal window and use one of the following commands:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install Reticulum and utilities with pip:</span>
|
||||
pip3<span class="w"> </span>install<span class="w"> </span>rns
|
||||
|
||||
@@ -687,16 +561,9 @@ pip3<span class="w"> </span>install<span class="w"> </span>rns<span class="w"> <
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.</p>
|
||||
</div>
|
||||
<p>Additionally, some version combinations of macOS and Python require you to
|
||||
manually add your installed <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages directory to your <cite>PATH</cite> environment
|
||||
variable, before you can use installed commands in your terminal. Usually, adding
|
||||
the following line to your shell init script (for example <code class="docutils literal notranslate"><span class="pre">~/.zshrc</span></code>) will be enough:</p>
|
||||
<p>Additionally, some version combinations of macOS and Python require you to manually add your installed <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages directory to your <cite>PATH</cite> environment variable, before you can use installed commands in your terminal. Usually, adding the following line to your shell init script (for example <code class="docutils literal notranslate"><span class="pre">~/.zshrc</span></code>) will be enough:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="nb">export</span><span class="w"> </span><span class="nv">PATH</span><span class="o">=</span><span class="nv">$PATH</span>:~/Library/Python/3.9/bin
|
||||
</pre></div>
|
||||
</div>
|
||||
@@ -704,18 +571,12 @@ the following line to your shell init script (for example <code class="docutils
|
||||
</section>
|
||||
<section id="openwrt">
|
||||
<h3>OpenWRT<a class="headerlink" href="#openwrt" title="Link to this heading">¶</a></h3>
|
||||
<p>On OpenWRT systems with sufficient storage and memory, you can install
|
||||
Reticulum and related utilities using the <cite>opkg</cite> package manager and <cite>pip</cite>.</p>
|
||||
<p>On OpenWRT systems with sufficient storage and memory, you can install Reticulum and related utilities using the <cite>opkg</cite> package manager and <cite>pip</cite>.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>At the time of releasing this manual, work is underway to create pre-built
|
||||
Reticulum packages for OpenWRT, with full configuration, service
|
||||
and <code class="docutils literal notranslate"><span class="pre">uci</span></code> integration. Please see the <a class="reference external" href="https://github.com/gretel/feed-reticulum">feed-reticulum</a>
|
||||
and <a class="reference external" href="https://github.com/gretel/reticulum-openwrt">reticulum-openwrt</a>
|
||||
repositories for more information.</p>
|
||||
<p>At the time of releasing this manual, work is underway to create pre-built Reticulum packages for OpenWRT, with full configuration, service and <code class="docutils literal notranslate"><span class="pre">uci</span></code> integration. Please see the <a class="reference external" href="https://github.com/gretel/feed-reticulum">feed-reticulum</a> and <a class="reference external" href="https://github.com/gretel/reticulum-openwrt">reticulum-openwrt</a> repositories for more information.</p>
|
||||
</div>
|
||||
<p>To install Reticulum on OpenWRT, first log into a command line session, and
|
||||
then use the following instructions:</p>
|
||||
<p>To install Reticulum on OpenWRT, first log into a command line session, and then use the following instructions:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install dependencies</span>
|
||||
opkg<span class="w"> </span>install<span class="w"> </span>python3<span class="w"> </span>python3-pip<span class="w"> </span>python3-cryptography<span class="w"> </span>python3-pyserial
|
||||
|
||||
@@ -728,28 +589,14 @@ rnsd<span class="w"> </span>-vvv
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The above instructions have been verified and tested on OpenWRT 21.02 only.
|
||||
It is likely that other versions may require slightly altered installation
|
||||
commands or package names. You will also need enough free space in your
|
||||
overlay FS, and enough free RAM to actually run Reticulum and any related
|
||||
programs and utilities.</p>
|
||||
<p>The above instructions have been verified and tested on OpenWRT 21.02 only. It is likely that other versions may require slightly altered installation commands or package names. You will also need enough free space in your overlay FS, and enough free RAM to actually run Reticulum and any related programs and utilities.</p>
|
||||
</div>
|
||||
<p>Depending on your device configuration, you may need to adjust firewall rules
|
||||
for Reticulum connectivity to and from your device to work. Until proper
|
||||
packaging is ready, you will also need to manually create a service or startup
|
||||
script to automatically laucnh Reticulum at boot time.</p>
|
||||
<p>Please also note that the <cite>AutoInterface</cite> requires link-local IPv6 addresses
|
||||
to be enabled for any Ethernet and WiFi devices you intend to use. If <code class="docutils literal notranslate"><span class="pre">ip</span> <span class="pre">a</span></code>
|
||||
shows an address starting with <code class="docutils literal notranslate"><span class="pre">fe80::</span></code> for the device in question,
|
||||
<code class="docutils literal notranslate"><span class="pre">AutoInterface</span></code> should work for that device.</p>
|
||||
<p>Depending on your device configuration, you may need to adjust firewall rules for Reticulum connectivity to and from your device to work. Until proper packaging is ready, you will also need to manually create a service or startup script to automatically laucnh Reticulum at boot time.</p>
|
||||
<p>Please also note that the <cite>AutoInterface</cite> requires link-local IPv6 addresses to be enabled for any Ethernet and WiFi devices you intend to use. If <code class="docutils literal notranslate"><span class="pre">ip</span> <span class="pre">a</span></code> shows an address starting with <code class="docutils literal notranslate"><span class="pre">fe80::</span></code> for the device in question, <code class="docutils literal notranslate"><span class="pre">AutoInterface</span></code> should work for that device.</p>
|
||||
</section>
|
||||
<section id="raspberry-pi">
|
||||
<h3>Raspberry Pi<a class="headerlink" href="#raspberry-pi" title="Link to this heading">¶</a></h3>
|
||||
<p>It is currently recommended to use a 64-bit version of the Raspberry Pi OS
|
||||
if you want to run Reticulum on Raspberry Pi computers, since 32-bit versions
|
||||
don’t always have packages available for some dependencies. If Python and the
|
||||
<cite>pip</cite> package manager is not already installed, do that first, and then
|
||||
install Reticulum using <cite>pip</cite>.</p>
|
||||
<p>It is currently recommended to use a 64-bit version of the Raspberry Pi OS if you want to run Reticulum on Raspberry Pi computers, since 32-bit versions don’t always have packages available for some dependencies. If Python and the <cite>pip</cite> package manager is not already installed, do that first, and then install Reticulum using <cite>pip</cite>.</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install dependencies</span>
|
||||
sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>python3<span class="w"> </span>python3-pip<span class="w"> </span>python3-cryptography<span class="w"> </span>python3-pyserial
|
||||
|
||||
@@ -759,21 +606,13 @@ pip<span class="w"> </span>install<span class="w"> </span>rns<span class="w"> </
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.</p>
|
||||
</div>
|
||||
<p>While it is possible to install and run Reticulum on 32-bit Rasperry Pi OSes,
|
||||
it will require manually configuring and installing required build dependencies,
|
||||
and is not detailed in this manual.</p>
|
||||
<p>While it is possible to install and run Reticulum on 32-bit Rasperry Pi OSes, it will require manually configuring and installing required build dependencies, and is not detailed in this manual.</p>
|
||||
</section>
|
||||
<section id="risc-v">
|
||||
<h3>RISC-V<a class="headerlink" href="#risc-v" title="Link to this heading">¶</a></h3>
|
||||
<p>On some architectures, including RISC-V, not all dependencies have precompiled
|
||||
binaries. On such systems, you may need to install <code class="docutils literal notranslate"><span class="pre">python3-dev</span></code> (or similar) before
|
||||
installing Reticulum or programs that depend on Reticulum.</p>
|
||||
<p>On some architectures, including RISC-V, not all dependencies have precompiled binaries. On such systems, you may need to install <code class="docutils literal notranslate"><span class="pre">python3-dev</span></code> (or similar) before installing Reticulum or programs that depend on Reticulum.</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install Python and development packages</span>
|
||||
sudo<span class="w"> </span>apt<span class="w"> </span>update
|
||||
sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>python3<span class="w"> </span>python3-pip<span class="w"> </span>python3-dev
|
||||
@@ -782,16 +621,11 @@ sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> <
|
||||
python3<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>rns
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>With these packages installed, <code class="docutils literal notranslate"><span class="pre">pip</span></code> will be able to build any missing dependencies
|
||||
on your system locally.</p>
|
||||
<p>With these packages installed, <code class="docutils literal notranslate"><span class="pre">pip</span></code> will be able to build any missing dependencies on your system locally.</p>
|
||||
</section>
|
||||
<section id="ubuntu-lunar">
|
||||
<h3>Ubuntu Lunar<a class="headerlink" href="#ubuntu-lunar" title="Link to this heading">¶</a></h3>
|
||||
<p>On versions of Ubuntu released after April 2023, it is no longer possible by default
|
||||
to use <code class="docutils literal notranslate"><span class="pre">pip</span></code> to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement <code class="docutils literal notranslate"><span class="pre">pipx</span></code> command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.</p>
|
||||
<p>On versions of Ubuntu released after April 2023, it is no longer possible by default to use <code class="docutils literal notranslate"><span class="pre">pip</span></code> to install packages onto your system. Unfortunately, you will need to use the replacement <code class="docutils literal notranslate"><span class="pre">pipx</span></code> command instead, which places installed packages in an isolated environment. This should not negatively affect Reticulum, but will not work for including and using Reticulum in your own scripts and programs.</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install pipx</span>
|
||||
sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>pipx
|
||||
|
||||
@@ -802,44 +636,30 @@ pipx<span class="w"> </span>ensurepath
|
||||
pipx<span class="w"> </span>install<span class="w"> </span>rns
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Alternatively, you can restore normal behaviour to <code class="docutils literal notranslate"><span class="pre">pip</span></code> by creating or editing
|
||||
the configuration file located at <code class="docutils literal notranslate"><span class="pre">~/.config/pip/pip.conf</span></code>, and adding the
|
||||
following section:</p>
|
||||
<p>Alternatively, you can restore normal behaviour to <code class="docutils literal notranslate"><span class="pre">pip</span></code> by creating or editing the configuration file located at <code class="docutils literal notranslate"><span class="pre">~/.config/pip/pip.conf</span></code>, and adding the following section:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>[global]
|
||||
break-system-packages = true
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For a one-shot installation of Reticulum, without globally enabling the <code class="docutils literal notranslate"><span class="pre">break-system-packages</span></code>
|
||||
option, you can use the following command:</p>
|
||||
<p>For a one-shot installation of Reticulum, without globally enabling the <code class="docutils literal notranslate"><span class="pre">break-system-packages</span></code> option, you can use the following command:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>pip install rns --break-system-packages
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">--break-system-packages</span></code> directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="windows">
|
||||
<h3>Windows<a class="headerlink" href="#windows" title="Link to this heading">¶</a></h3>
|
||||
<p>On Windows operating systems, the easiest way to install Reticulum is by using the
|
||||
<code class="docutils literal notranslate"><span class="pre">pip</span></code> package manager from the command line (either the command prompt or Windows
|
||||
Powershell).</p>
|
||||
<p>If you don’t already have Python installed, <a class="reference external" href="https://www.python.org/downloads/">download and install Python</a>.
|
||||
At the time of publication of this manual, the recommended version is <a class="reference external" href="https://www.python.org/downloads/release/python-3127">Python 3.12.7</a>.</p>
|
||||
<p><strong>Important!</strong> When asked by the installer, make sure to add the Python program to
|
||||
your PATH environment variables. If you don’t do this, you will not be able to
|
||||
use the <code class="docutils literal notranslate"><span class="pre">pip</span></code> installer, or run the included Reticulum utility programs (such as
|
||||
<code class="docutils literal notranslate"><span class="pre">rnsd</span></code> and <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code>) from the command line.</p>
|
||||
<p>On Windows operating systems, the easiest way to install Reticulum is by using the <code class="docutils literal notranslate"><span class="pre">pip</span></code> package manager from the command line (either the command prompt or Windows Powershell).</p>
|
||||
<p>If you don’t already have Python installed, <a class="reference external" href="https://www.python.org/downloads/">download and install Python</a>. At the time of publication of this manual, the recommended version is <a class="reference external" href="https://www.python.org/downloads/release/python-3127">Python 3.12.7</a>.</p>
|
||||
<p><strong>Important!</strong> When asked by the installer, make sure to add the Python program to your PATH environment variables. If you don’t do this, you will not be able to use the <code class="docutils literal notranslate"><span class="pre">pip</span></code> installer, or run the included Reticulum utility programs (such as <code class="docutils literal notranslate"><span class="pre">rnsd</span></code> and <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code>) from the command line.</p>
|
||||
<p>After installing Python, open the command prompt or Windows Powershell, and type:</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>pip<span class="w"> </span>install<span class="w"> </span>rns
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can now use Reticulum and all included utility programs directly from your
|
||||
preferred command line interface.</p>
|
||||
<p>You can now use Reticulum and all included utility programs directly from your preferred command line interface.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="pure-python-reticulum">
|
||||
@@ -851,19 +671,8 @@ do not support <a class="reference external" href="https://github.com/pyca/crypt
|
||||
important that you read and understand the <a class="reference internal" href="understanding.html#understanding-primitives"><span class="std std-ref">Cryptographic Primitives</span></a>
|
||||
section of this manual.</p>
|
||||
</div>
|
||||
<p>In some rare cases, and on more obscure system types, it is not possible to
|
||||
install one or more dependencies. In such situations,
|
||||
you can use the <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> package instead of the <code class="docutils literal notranslate"><span class="pre">rns</span></code> package, or use <code class="docutils literal notranslate"><span class="pre">pip</span></code>
|
||||
with the <code class="docutils literal notranslate"><span class="pre">--no-dependencies</span></code> command-line option. The <code class="docutils literal notranslate"><span class="pre">rnspure</span></code>
|
||||
package requires no external dependencies for installation. Please note that the
|
||||
actual contents of the <code class="docutils literal notranslate"><span class="pre">rns</span></code> and <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> packages are <em>completely identical</em>.
|
||||
The only difference is that the <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> package lists no dependencies required
|
||||
for installation.</p>
|
||||
<p>No matter how Reticulum is installed and started, it will load external dependencies
|
||||
only if they are <em>needed</em> and <em>available</em>. If for example you want to use Reticulum
|
||||
on a system that cannot support <code class="docutils literal notranslate"><span class="pre">pyserial</span></code>, it is perfectly possible to do so using
|
||||
the <cite>rnspure</cite> package, but Reticulum will not be able to use serial-based interfaces.
|
||||
All other available modules will still be loaded when needed.</p>
|
||||
<p>In some rare cases, and on more obscure system types, it is not possible to install one or more dependencies. In such situations, you can use the <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> package instead of the <code class="docutils literal notranslate"><span class="pre">rns</span></code> package, or use <code class="docutils literal notranslate"><span class="pre">pip</span></code> with the <code class="docutils literal notranslate"><span class="pre">--no-dependencies</span></code> command-line option. The <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> package requires no external dependencies for installation. Please note that the actual contents of the <code class="docutils literal notranslate"><span class="pre">rns</span></code> and <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> packages are <em>completely identical</em>. The only difference is that the <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> package lists no dependencies required for installation.</p>
|
||||
<p>No matter how Reticulum is installed and started, it will load external dependencies only if they are <em>needed</em> and <em>available</em>. If for example you want to use Reticulum on a system that cannot support <code class="docutils literal notranslate"><span class="pre">pyserial</span></code>, it is perfectly possible to do so using the <cite>rnspure</cite> package, but Reticulum will not be able to use serial-based interfaces. All other available modules will still be loaded when needed.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -967,7 +776,7 @@ All other available modules will still be loaded when needed.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
+395
-27
@@ -3,11 +3,11 @@
|
||||
<head><meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="color-scheme" content="light dark"><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="index" title="Index" href="genindex.html"><link rel="search" title="Search" href="search.html"><link rel="next" title="Support Reticulum" href="support.html"><link rel="prev" title="Building Networks" href="networks.html">
|
||||
<link rel="index" title="Index" href="genindex.html"><link rel="search" title="Search" href="search.html"><link rel="next" title="Support Reticulum" href="support.html"><link rel="prev" title="Distributed Development" href="distributed.html">
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Git Over Reticulum - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Git Over Reticulum - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -263,11 +264,12 @@
|
||||
<article role="main" id="furo-main-content">
|
||||
<section id="git-over-reticulum">
|
||||
<span id="git-main"></span><h1>Git Over Reticulum<a class="headerlink" href="#git-over-reticulum" title="Link to this heading">¶</a></h1>
|
||||
<p>This chapter of the manual serves as the technical reference for the distributed software development and project collaboration tools included in RNS. For a conceptual overview, see the <a class="reference internal" href="distributed.html#distributed-development"><span class="std std-ref">Distributed Development</span></a> chapter.</p>
|
||||
<p>A set of utilities for distributed collaborative software development and publishing are included in RNS.</p>
|
||||
<p>The system consists of two parts: The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> node that hosts repositories, and the <code class="docutils literal notranslate"><span class="pre">git-remote-rns</span></code> helper that enables Git to communicate with rngit nodes. As soon as you have RNS installed on your system, you can transparently use Git with Reticulum-hosted repositories just like any other type of remote. Git over Reticulum uses URLs in the following format: <code class="docutils literal notranslate"><span class="pre">rns://DESTINATION_HASH/group/repo</span></code>.</p>
|
||||
<p>If you set a branch to track a Reticulum remote as the default upstream, you can simply use <code class="docutils literal notranslate"><span class="pre">git</span></code> as you normally would; all commands work transparently and as expected.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<div class="admonition important">
|
||||
<p class="admonition-title">Important</p>
|
||||
<p><strong>The rngit program is a new addition to RNS!</strong> This functionality was introduced in RNS 1.2.0. While great care has been taken to design a secure, but highly configurable and flexible <a class="reference external" href="#permissions">permission system</a> for allowing many users to interact with many different repositories on a single node, <code class="docutils literal notranslate"><span class="pre">rngit</span></code> has not been tested extensively in the wild! Be careful when hosting repositories, especially if they are public or semi-public.</p>
|
||||
</div>
|
||||
<section id="the-rngit-utility">
|
||||
@@ -388,10 +390,8 @@ Repository forked to public/myfork
|
||||
<p>The source can be any valid Git URL, including:</p>
|
||||
<ul class="simple">
|
||||
<li><p>HTTPS URLs: <code class="docutils literal notranslate"><span class="pre">https://github.com/user/repo.git</span></code></p></li>
|
||||
<li><p>Git URLs: <code class="docutils literal notranslate"><span class="pre">git://host.com/repo.git</span></code></p></li>
|
||||
<li><p>SSH URLs: <code class="docutils literal notranslate"><span class="pre">ssh://git@host.com/repo.git</span></code></p></li>
|
||||
<li><p>Reticulum URLs: <code class="docutils literal notranslate"><span class="pre">rns://DESTINATION_HASH/group/repo</span></code></p></li>
|
||||
<li><p>Local paths: <code class="docutils literal notranslate"><span class="pre">/path/to/repo.git</span></code></p></li>
|
||||
</ul>
|
||||
<p>Forks are created as bare repositories with metadata tracking their origin. The fork process:</p>
|
||||
<ol class="arabic simple">
|
||||
@@ -676,6 +676,63 @@ w:none
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
<section id="remote-permission-management">
|
||||
<h2>Remote Permission Management<a class="headerlink" href="#remote-permission-management" title="Link to this heading">¶</a></h2>
|
||||
<p>While permissions can be configured directly on the node by editing configuration files and <code class="docutils literal notranslate"><span class="pre">.allowed</span></code> files, <code class="docutils literal notranslate"><span class="pre">rngit</span></code> also supports remote permission management through the <code class="docutils literal notranslate"><span class="pre">rngit</span> <span class="pre">perms</span></code> command. This allows administrators to modify access controls for groups and repositories over Reticulum, without requiring shell access to the hosting node.</p>
|
||||
<p>To use remote permission management, you must have <code class="docutils literal notranslate"><span class="pre">admin</span></code> permission on the target group or repository. The command opens your configured <code class="docutils literal notranslate"><span class="pre">$EDITOR</span></code> to modify permissions, using the same syntax and format as local <code class="docutils literal notranslate"><span class="pre">.allowed</span></code> files. When you save and exit the editor, the modified permissions are transmitted to the remote node and applied immediately.</p>
|
||||
<section id="managing-group-permissions">
|
||||
<h3>Managing Group Permissions<a class="headerlink" href="#managing-group-permissions" title="Link to this heading">¶</a></h3>
|
||||
<p>To view or modify permissions for an entire repository group, specify the group URL (ending with the group name):</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit perms rns://50824b711717f97c2fb1166ceddd5ea9/public
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This retrieves the current permission configuration from the <code class="docutils literal notranslate"><span class="pre">public.allowed</span></code> file and opens it in your editor. Any changes you make are validated for syntax correctness. Invalid permission rules will be rejected with an error message indicating the problematic line.</p>
|
||||
</section>
|
||||
<section id="managing-repository-permissions">
|
||||
<h3>Managing Repository Permissions<a class="headerlink" href="#managing-repository-permissions" title="Link to this heading">¶</a></h3>
|
||||
<p>To manage permissions for a specific repository, include the repository name in the URL:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit perms rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This operates on the <code class="docutils literal notranslate"><span class="pre">myrepo.allowed</span></code> file next to the repository. Repository-level permissions take precedence over group-level permissions, allowing fine-grained access control for individual repositories within a group.</p>
|
||||
</section>
|
||||
<section id="permission-validation">
|
||||
<h3>Permission Validation<a class="headerlink" href="#permission-validation" title="Link to this heading">¶</a></h3>
|
||||
<p>When modifying permissions remotely, <code class="docutils literal notranslate"><span class="pre">rngit</span></code> validates that:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Each permission line follows the correct <code class="docutils literal notranslate"><span class="pre">permission:target</span></code> syntax</p></li>
|
||||
<li><p>Permission types are valid (r, w, rw, c, s, rel, i, p, adm)</p></li>
|
||||
<li><p>Target specifications are valid (identity hashes, <code class="docutils literal notranslate"><span class="pre">all</span></code>, or <code class="docutils literal notranslate"><span class="pre">none</span></code>)</p></li>
|
||||
<li><p>Identity hashes, when specified, are the correct length (32 hexadecimal characters)</p></li>
|
||||
</ul>
|
||||
<p>If validation fails, the editor will reopen with an error message describing the issue, allowing you to correct the problem before resubmitting.</p>
|
||||
<div class="admonition caution">
|
||||
<p class="admonition-title">Caution</p>
|
||||
<p>Remote permission modification requires administrative access (the <code class="docutils literal notranslate"><span class="pre">adm</span></code> permission), which grants full control over the repository or group. The permission change request is transmitted over the encrypted Reticulum link, and the remote node verifies your identity cryptographically before applying changes. However, be aware that granting <code class="docutils literal notranslate"><span class="pre">adm</span></code> permissions to remote identities effectively delegates full control, including the ability to revoke your own access or modify permissions in ways you may not anticipate.</p>
|
||||
</div>
|
||||
<p><strong>All Command-Line Options (rngit perms)</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rngit perms [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-v] [-q] [--version]
|
||||
remote
|
||||
|
||||
Reticulum Git Permission Manager
|
||||
|
||||
positional arguments:
|
||||
remote URL of remote group or repository
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative config directory
|
||||
--rnsconfig RNSCONFIG
|
||||
path to alternative Reticulum config directory
|
||||
-i, --identity PATH path to identity
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="identity-destination-aliases">
|
||||
<h2>Identity & Destination Aliases<a class="headerlink" href="#identity-destination-aliases" title="Link to this heading">¶</a></h2>
|
||||
<p>To make permission and remote destination management easier, you can locally define aliases for commonly used identity and destination hashes. Identity aliases used in permissions resolution can be defined in the <code class="docutils literal notranslate"><span class="pre">[aliases]</span></code> section of the <code class="docutils literal notranslate"><span class="pre">~/.rngit/config</span></code> file, while destination aliases are defined in the <code class="docutils literal notranslate"><span class="pre">[aliases]</span></code> section of the <code class="docutils literal notranslate"><span class="pre">~/.rngit/client_config</span></code> file.</p>
|
||||
@@ -813,6 +870,158 @@ unicode_icons = yes
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="verified-releases">
|
||||
<h2>Verified Releases<a class="headerlink" href="#verified-releases" title="Link to this heading">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> release system provides cryptographic provenance and integrity guarantees through automatic signing of release artifacts and signed release manifests. When you create a release, <code class="docutils literal notranslate"><span class="pre">rngit</span></code> generates an Ed25519 signature for each artifact and embeds these signatures in a cryptographically signed release manifest (<code class="docutils literal notranslate"><span class="pre">.rsm</span></code> file). This allows anyone who obtains the release to verify its authenticity and integrity, regardless of how the files were distributed.</p>
|
||||
<section id="obtaining-verified-releases">
|
||||
<span id="git-release-obtain"></span><h3>Obtaining Verified Releases<a class="headerlink" href="#obtaining-verified-releases" title="Link to this heading">¶</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system lets you obtain releases securely and in a verified manner, by validating cryptographically signed release manifests in the <code class="docutils literal notranslate"><span class="pre">.rsm</span></code> format during the retrieval process. Once a release has been published with <code class="docutils literal notranslate"><span class="pre">rngit</span></code>, anyone that has read access to it can obtain the release with the <code class="docutils literal notranslate"><span class="pre">rngit</span> <span class="pre">release</span></code> command, for example:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://remote_node/group/some_program fetch latest:all
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This command will connect to the remote, retrieve the latest release manifest, verify it’s signature and integrity (you can optionally specify a required signer identity with <code class="docutils literal notranslate"><span class="pre">--signer</span></code>), and then download and sequentially verify all artifacts included in the release.</p>
|
||||
<p>If verification succeeds, the retrieved artifact files, along with the release manifest will be saved in the current working directory. From the above example, you would end up with a number of downloaded files, and a version- and package specific release manifest, such as <code class="docutils literal notranslate"><span class="pre">some_program_1.5.2.rsm</span></code>.</p>
|
||||
<div class="admonition important">
|
||||
<p class="admonition-title">Important</p>
|
||||
<p>Keeping the retrieved release manifest is a <strong>very</strong> good idea! It allows you to easily obtain future releases and updates to the software directly, while verifying they came from the same publisher.</p>
|
||||
</div>
|
||||
<p><strong>Obtaining & Updating Releases Using RSM Manifests</strong></p>
|
||||
<p>One of the key features of the <code class="docutils literal notranslate"><span class="pre">rngit</span></code> release system is the ability to fetch and verify new releases using only a signed release manifest. This is particularly valuable for distributing software over Reticulum. Once someone has an <code class="docutils literal notranslate"><span class="pre">.rsm</span></code> manifest of your package, they can use it to continually retrieve and update the software.</p>
|
||||
<p>To fetch a release using a manifest:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release some_program_1.5.2.rsm fetch latest:all
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This command:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>Validates the manifest signature to confirm authenticity</p></li>
|
||||
<li><p>Extracts the origin node and repository path from the signed manifest</p></li>
|
||||
<li><p>Connects to the origin node over Reticulum</p></li>
|
||||
<li><p>Gets the <em>latest</em> release manifest from the developer</p></li>
|
||||
<li><p>Verifies it against the existing manifest</p></li>
|
||||
<li><p>Fetches each artifact listed in the manifest</p></li>
|
||||
<li><p>Verifies each downloaded file against the signature embedded in the manifest</p></li>
|
||||
</ol>
|
||||
<p>If any artifact fails signature verification, the fetch aborts with an error, preventing the installation of corrupted or tampered files.</p>
|
||||
<p><strong>Specifying Required Signers</strong></p>
|
||||
<p>You can require that releases be signed by specific identities. When fetching a release, use the <code class="docutils literal notranslate"><span class="pre">--signer</span></code> option to specify the identity hash of the required signer:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://remote_node/public/myrepo fetch latest:all --signer 21a8daa6d9c3d3b8aab6e94b6bcb0e33
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If the release was not signed by the specified identity, the fetch will abort before any files are downloaded. Likewise, if any downloaded artifacts were not signed by the required identity, the process will abort at the first invalid signature. This provides strong guarantees about the provenance of the software you are installing.</p>
|
||||
<p>The signer check also works when fetching from a local manifest:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release manifest.rsm fetch latest:all --signer 21a8daa6d9c3d3b8aab6e94b6bcb0e33
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>Selective & Partial Fetches</strong></p>
|
||||
<p>You can fetch individual artifacts from a release by specifying the artifact name instead of <code class="docutils literal notranslate"><span class="pre">all</span></code>:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://remote_node/public/myrepo fetch 1.2.0:myapp-1.2.0.tar.gz
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This downloads only the specified artifact and verifies its signature against the manifest. If a file already exists locally, <code class="docutils literal notranslate"><span class="pre">rngit</span></code> verifies it against the manifest signature and skips the download if valid, making it safe to run the command multiple times. When fetching releases, <code class="docutils literal notranslate"><span class="pre">rngit</span> <span class="pre">release</span></code> will only download files that are missing or invalid according to the manifest. This means that partially completed release fetches can be continued later, if interrupted.</p>
|
||||
<p><strong>Pattern Matching for Artifacts</strong></p>
|
||||
<p>When fetching selective artifacts, you are not limited to exact names or the <code class="docutils literal notranslate"><span class="pre">all</span></code> keyword. You can use shell-style wildcard patterns to match multiple artifacts flexibly. This is particularly useful for selecting platform-specific builds, version ranges, or file types without specifying each file individually.</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>When using pattern matching, make sure to enclose the target specification in quotes. Otherwise,
|
||||
your shell will probably interpret it as a shell expansion pattern <em>before</em> it is passed as an
|
||||
argument to <code class="docutils literal notranslate"><span class="pre">rngit</span></code>!</p>
|
||||
</div>
|
||||
<p>The pattern matching supports standard Unix wildcards:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">*</span></code> matches any sequence of characters (including empty)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">?</span></code> matches any single character</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">[seq]</span></code> matches any character in <em>seq</em> (for example <code class="docutils literal notranslate"><span class="pre">[0-9]</span></code> or <code class="docutils literal notranslate"><span class="pre">[abc]</span></code>)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">[!seq]</span></code> matches any character not in <em>seq</em></p></li>
|
||||
</ul>
|
||||
<p>For example, to fetch all wheel files for Python 3 across any platform:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:*-py3-*.whl"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>To fetch a specific patch version when you know the major and minor version:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:myapp-1.2.?-linux-x86_64.tar.gz"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Or to retrieve all source archives:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:source_*.tgz"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If your pattern contains no wildcard characters, it must match an artifact name exactly, which is useful for fetching single, specific artifacts. When a pattern matches multiple artifacts, all matched files are fetched and verified. If no artifacts match the pattern, the fetch aborts with an error indicating no matches were found.</p>
|
||||
</section>
|
||||
<section id="offline-verification">
|
||||
<h3>Offline Verification<a class="headerlink" href="#offline-verification" title="Link to this heading">¶</a></h3>
|
||||
<p>Because the release manifest contains embedded signatures, you can verify the integrity of release artifacts offline, without connecting to the repository node. The <code class="docutils literal notranslate"><span class="pre">rnid</span></code> and <code class="docutils literal notranslate"><span class="pre">rngit</span></code> utilities can validate artifact signatures against <code class="docutils literal notranslate"><span class="pre">.rsg</span></code> and manifest files.</p>
|
||||
<p><strong>Using a release manifest:</strong></p>
|
||||
<p>Ensure the release manifest is located in the same directory as the release artifacts, then run:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Verify all artifacts in the manifest
|
||||
$ rngit release myapp-1.2.0.rsm verify
|
||||
|
||||
# Or, verify only specific artifacts
|
||||
$ rngit release myapp-1.2.0.rsm verify "latest:*.whl"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will load the manifest, and verify all files currently on-disk, but will not attempt to fetch the latest release manifest from the origin, or update local files to match it.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">verify</span></code> operation is functionally equivalent to using the <code class="docutils literal notranslate"><span class="pre">fetch</span></code> operation with the <code class="docutils literal notranslate"><span class="pre">--offline</span></code> flag, and they can be used interchangably.</p>
|
||||
</div>
|
||||
<p><strong>For individual files:</strong></p>
|
||||
<p>Ensure the <code class="docutils literal notranslate"><span class="pre">.rsg</span></code> signature is located in the same directory as the release artifact, then run:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnid -V myapp-1.2.0.tar.gz
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This validates that the artifact file matches the signature created during the release process. Combined with the manifest’s own signature, this provides end-to-end verification from the original release creation to the final installation.</p>
|
||||
</section>
|
||||
<section id="creating-signed-releases">
|
||||
<span id="git-release-create"></span><h3>Creating Signed Releases<a class="headerlink" href="#creating-signed-releases" title="Link to this heading">¶</a></h3>
|
||||
<p>Reticulum and the <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system makes it easy to create signed releases that your users can verify and update securely. When you create a release using <code class="docutils literal notranslate"><span class="pre">rngit</span></code>, the program automatically:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>Generates an Ed25519 signature for each artifact file using your identity’s signing key</p></li>
|
||||
<li><p>Creates <code class="docutils literal notranslate"><span class="pre">.rsg</span></code> signature files alongside each artifact in your distribution directory</p></li>
|
||||
<li><p>Constructs a signed <code class="docutils literal notranslate"><span class="pre">manifest.rsm</span></code> release manifest containing metadata, an artifact list, and embedded signatures</p></li>
|
||||
<li><p>Transmits both artifacts, signatures and manifest to the remote node specified as release origin</p></li>
|
||||
</ol>
|
||||
<p>As an example, to create and publish a release from all files in the folder named <code class="docutils literal notranslate"><span class="pre">dist</span></code>, simply run:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://my_node/group/myrepo create 1.2.0:./dist
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Everything is automatically signed and uploaded to your node, and the release manifest will now include the following signed attestation information:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Package name and version</p></li>
|
||||
<li><p>The release notes for this release</p></li>
|
||||
<li><p>Release timestamp and commit hash</p></li>
|
||||
<li><p>Origin node identity and repository path</p></li>
|
||||
<li><p>Complete list of artifacts</p></li>
|
||||
<li><p>Embedded signatures for each artifact</p></li>
|
||||
</ul>
|
||||
<p>That’s it, there’s nothing more to it than one command. Users can now securely obtain your release using <code class="docutils literal notranslate"><span class="pre">rngit</span> <span class="pre">release</span> <span class="pre">fetch</span></code>.</p>
|
||||
<p><strong>Release Manifest Format</strong></p>
|
||||
<p>Release manifests use the <code class="docutils literal notranslate"><span class="pre">.rsm</span></code> format (a general-purpose, structured signed message format) and are themselves cryptographically signed documents. The manifest format embeds the signing identity’s public key and a detached signature that covers the entire manifest content. This creates a chain of trust: the manifest signature proves the manifest’s authenticity, and the embedded artifact signatures prove each file’s integrity.</p>
|
||||
<p>When a release is created, the manifest is stored as <code class="docutils literal notranslate"><span class="pre">manifest.rsm</span></code> in the release artifacts directory. You can also generate a local release manifest without uploading by using the <code class="docutils literal notranslate"><span class="pre">--local</span></code> flag:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://f2d31b2e080e5d4e358d32822ee4a3b7/public/myrepo create 1.2.0:./dist --local
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This creates the <code class="docutils literal notranslate"><span class="pre">.rsg</span></code> signature files and <code class="docutils literal notranslate"><span class="pre">manifest.rsm</span></code> in your local distribution directory without connecting to the remote node, allowing you to inspect or distribute the signed release through alternative channels.</p>
|
||||
<p><strong>Signature File Format</strong></p>
|
||||
<p>Individual artifact signatures use the Reticulum Signature (<code class="docutils literal notranslate"><span class="pre">.rsg</span></code>) format and contain:</p>
|
||||
<ul class="simple">
|
||||
<li><p>The Ed25519 signature of the file</p></li>
|
||||
<li><p>The signing identity’s public key</p></li>
|
||||
<li><p>Optional metadata, such as timestamps or notes</p></li>
|
||||
</ul>
|
||||
<p>These signature files are created automatically during the release process and can be used independently of the manifest for verification purposes. The <code class="docutils literal notranslate"><span class="pre">rnid</span></code> utility can create and validate RSG signatures for any file, making this signature format useful beyond the <code class="docutils literal notranslate"><span class="pre">rngit</span></code> release system.</p>
|
||||
<p><strong>Good Practices for Signature Distribution</strong></p>
|
||||
<p>While release manifests in the <code class="docutils literal notranslate"><span class="pre">.rsm</span></code> format <em>include</em> embedded <code class="docutils literal notranslate"><span class="pre">.rsg</span></code> signatures for every listed artifact, it is dependent on the situation and requirements whether individual <code class="docutils literal notranslate"><span class="pre">.rsg</span></code> signatures are distributed as well. It is generally a good idea to do so, since they are very light-weight, and provide an easy and convenient way to validate and authenticate <em>individual</em> files, as opposed to entire releases.</p>
|
||||
<p>When distributing software through multiple channels (direct download, mirror networks, physical media), including the <code class="docutils literal notranslate"><span class="pre">.rsm</span></code> manifest allows recipients to verify authenticity regardless of how they obtained the files. This is particularly valuable in low-connectivity environments where Reticulum may be the only available communication channel, as the manifest ensures that software updates can be verified even when received via store-and-forward mechanisms or physical media transport.</p>
|
||||
<p><strong>Integration with Package Management</strong></p>
|
||||
<p>While this functionality is still under development, the signed release manifest format is designed to be consumed by package management systems and automated deployment tools. Because the manifest is cryptographically signed and contains all necessary metadata and integrity checks, it can serve as a trusted source of truth for software distribution, even when fetched over untrusted channels or stored for long periods.</p>
|
||||
<p><strong>Release Encryption</strong></p>
|
||||
<p>While API primitives and command-line tools are currently not implemented for this, the release, distribution and verification system has been designed to also support <em>encrypted</em> releases, which can be distributed securely to authorized recipients.</p>
|
||||
<p><strong>Verified Package Format</strong></p>
|
||||
<p>The current system is being expanded to also include an <code class="docutils literal notranslate"><span class="pre">.rvp</span></code> package format, which can contain packaged releases including all relevant artifacts, metadata, manifest and signatures.</p>
|
||||
<p><strong>Automated Mirror Discovery</strong></p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> release system is designed to support automated mirror discovery and distribution package retrieval over Reticulum networks. Since everything is cryptographically signed and verified, it is possible to create automated mirror and distribution networks, where users can obtain software and information from local sources, without risking malicious modifications to the software they rely on. This functionality is currently in development.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="release-management">
|
||||
<h2>Release Management<a class="headerlink" href="#release-management" title="Link to this heading">¶</a></h2>
|
||||
<p>In addition to hosting Git repositories, <code class="docutils literal notranslate"><span class="pre">rngit</span></code> provides a complete release management system. This allows you to publish versioned releases with associated artifacts, release notes and metadata. Releases are managed through the <code class="docutils literal notranslate"><span class="pre">rngit</span> <span class="pre">release</span></code> subcommand, and are also viewable through the Nomad Network page interface.</p>
|
||||
@@ -820,12 +1029,12 @@ unicode_icons = yes
|
||||
<h3>The Release Workflow<a class="headerlink" href="#the-release-workflow" title="Link to this heading">¶</a></h3>
|
||||
<p>Creating a release involves specifying a Git tag and a directory containing build artifacts or other files to distribute. The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> client will open your configured <code class="docutils literal notranslate"><span class="pre">$EDITOR</span></code> to compose release notes, then upload all artifacts to the remote repository node.</p>
|
||||
<p>To create a release, specify the tag name and path to artifacts:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create v1.2.0:./dist
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create 1.2.0:./dist
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will:</p>
|
||||
<ol class="arabic simple">
|
||||
<li><p>Verify that the tag <code class="docutils literal notranslate"><span class="pre">v1.2.0</span></code> exists in the repository</p></li>
|
||||
<li><p>Verify that the tag <code class="docutils literal notranslate"><span class="pre">1.2.0</span></code> exists in the repository</p></li>
|
||||
<li><p>Open your editor to write release notes</p></li>
|
||||
<li><p>Upload all files from the <code class="docutils literal notranslate"><span class="pre">./dist</span></code> directory</p></li>
|
||||
<li><p>Publish the release</p></li>
|
||||
@@ -850,16 +1059,16 @@ unicode_icons = yes
|
||||
|
||||
Tag Status Created Objs Notes
|
||||
------------------------------------------------------------------
|
||||
v1.2.0 published 2025-01-15 14:32 3 Another release
|
||||
v1.1.0 published 2024-12-03 09:15 2 Bug fix release
|
||||
v1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
1.2.0 published 2025-01-15 14:32 3 Another release
|
||||
1.1.0 published 2024-12-03 09:15 2 Bug fix release
|
||||
1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>Viewing Release Details</strong></p>
|
||||
<p>To see full information about a specific release:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo view v1.2.0
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo view 1.2.0
|
||||
|
||||
Release : 0.9.2
|
||||
Release : 1.2.0
|
||||
Status : published
|
||||
Created : 2026-05-04 23:53:09
|
||||
Thanks : 5
|
||||
@@ -876,12 +1085,24 @@ Artifacts (4)
|
||||
- checksums.txt (256 B)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>Fetching Releases</strong></p>
|
||||
<p>To fetch a release, specify the remote URL, version and artifacts:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo fetch latest:all
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This process is described in greater detail in the <a class="reference internal" href="#git-release-obtain"><span class="std std-ref">Obtaining Verified Releases</span></a> section.</p>
|
||||
<p><strong>Creating Releases</strong></p>
|
||||
<p>To fetch a release, specify the remote URL, version and artifacts:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create 1.3.9:artifacts_dir
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This process is described in greater detail in the <a class="reference internal" href="#git-release-create"><span class="std std-ref">Creating Signed Releases</span></a> section.</p>
|
||||
<p><strong>Deleting Releases</strong></p>
|
||||
<p>To remove a release:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo delete v1.2.0
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo delete 1.2.0
|
||||
|
||||
Are you sure you want to delete release 'v1.2.0'? [y/N]: y
|
||||
Release v1.2.0 deleted
|
||||
Are you sure you want to delete release '1.2.0'? [y/N]: y
|
||||
Release 1.2.0 deleted
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>Requirements & Validation</strong></p>
|
||||
@@ -902,15 +1123,16 @@ rel:none # Deny everyone
|
||||
<p><strong>Nomad Network Interface</strong></p>
|
||||
<p>When the Nomad Network page node is enabled, releases are displayed on a dedicated releases page for each repository. Each release is listed with its tag, creation date, artifact count and a preview of the release notes. Clicking a release shows the full details including formatted release notes and a listing of all artifacts with their sizes.</p>
|
||||
<p><strong>All Command-Line Options (rngit release)</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rngit release [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-v] [-q] [--version]
|
||||
[repository] [operation] [target]
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: python -m RNS.Utilities.rngit.server [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-s PATH] [-n name] [-L]
|
||||
[-o] [-v] [-q] [--version]
|
||||
[repository] [operation] [target]
|
||||
|
||||
Reticulum Git Release Manager
|
||||
|
||||
positional arguments:
|
||||
repository URL of remote repository
|
||||
operation list, view, create or delete
|
||||
repository URL of remote repository, or path to RSM manifest
|
||||
operation list, view, fetch, create, latest or delete
|
||||
target tag and path to release artifacts directory
|
||||
|
||||
options:
|
||||
@@ -919,6 +1141,10 @@ options:
|
||||
--rnsconfig RNSCONFIG
|
||||
path to alternative Reticulum config directory
|
||||
-i, --identity PATH path to release identity
|
||||
-s, --signer PATH path to signing identity, if different from release identity
|
||||
-n, --name name package name if different from repo name
|
||||
-L, --local generate release locally, but don't upload
|
||||
-o, --offline verify manifest locally, but don't fetch updates
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
@@ -1080,7 +1306,27 @@ adm:9710b86ba12c42d1d8f30f74fe509286
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">N</span></code> - Numbered comment files (msgpack format)</p></li>
|
||||
</ul>
|
||||
<p><strong>Nomad Network Interface</strong></p>
|
||||
<p>When the Nomad Network page node is enabled, work documents are viewable through the web interface. The work page lists all documents with their status, and clicking a document shows its full content and updates.</p>
|
||||
<p>When the Nomad Network page node is enabled, work documents are viewable through the nomadnet interface. The work page lists all documents with their status, and clicking a document shows its full content and updates.</p>
|
||||
</section>
|
||||
<section id="cryptographic-attribution">
|
||||
<h3>Cryptographic Attribution<a class="headerlink" href="#cryptographic-attribution" title="Link to this heading">¶</a></h3>
|
||||
<p>Every work document is cryptographically signed by its creator using their Reticulum identity. When you create or edit a document, <code class="docutils literal notranslate"><span class="pre">rngit</span></code> generates an Ed25519 signature of the content, which is stored alongside the document contents and verified by the remote node, or locally when viewing the work document through the command-line interface. This provides two essential guarantees:</p>
|
||||
<ul class="simple">
|
||||
<li><p><strong>Attribution:</strong> Every document and comment can be cryptographically attributed to its actual author</p></li>
|
||||
<li><p><strong>Integrity:</strong> Any modification to the content after creation would invalidate the signature</p></li>
|
||||
</ul>
|
||||
<p>When viewing a work document, the signature validation status is displayed:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>Author : 9710b86ba12c42d1d8f30f74fe509286 (not locally validated)
|
||||
Signature : Document not signed
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Or, for valid signatures:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>Author : <9710b86ba12c42d1d8f30f74fe509286>
|
||||
Signature : Valid
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The “Valid” status indicates that the document content matches the author’s signature, and that the signing identity corresponds to the stated author. This can be used to create tamper-proof records of project decisions, investigations, and discussions that cannot be repudiated, or modified by third parties without detection.</p>
|
||||
<p>This cryptographic provenance is particularly valuable for distributed teams operating across trust boundaries. Because signatures are verified using the author’s Reticulum identity public keys - which can be recalled from any transport node on the network - work documents provide authoritative records of who said what, and when, without requiring a central authority to notarize or validate the communication. Even if the repository node hosting the documents becomes unavailable, the signed document files themselves retain validity and can be verified independently using standard Reticulum identity tools.</p>
|
||||
<p><strong>All Command-Line Options (rngit work)</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rngit work [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [--scope SCOPE] [-t TITLE] [-d ID] [-v]
|
||||
@@ -1110,6 +1356,107 @@ options:
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="commit-signing">
|
||||
<span id="git-commit-signing"></span><h2>Commit Signing<a class="headerlink" href="#commit-signing" title="Link to this heading">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rngit</span></code> system includes <code class="docutils literal notranslate"><span class="pre">rngcs</span></code>, a Git commit signing and validation shim that enables commit signing and validation using Reticulum identities. By hooking into Git’s SSH-based signing format, commits can be signed and verified using Reticulum identity keys directly.</p>
|
||||
<p>Unlike traditional GPG and SSH-based commit signing, which relies on centralized keyservers, cumbersome co-signing procedures or manual per-signer setup, Reticulum commit signing uses self-contained RSG signatures, that can be deterministically resolved to Reticulum identity hashes.</p>
|
||||
<p>This enables offline verification with no external infrastructure. The signature itself contains everything needed to cryptographically verify the signer’s Reticulum identity and that the commit was signed correctly by the claimed identity.</p>
|
||||
<section id="prerequisites">
|
||||
<h3>Prerequisites<a class="headerlink" href="#prerequisites" title="Link to this heading">¶</a></h3>
|
||||
<p>Before you can sign commits, you need a Reticulum identity with a private key. If you don’t already have one, you can generate it using <code class="docutils literal notranslate"><span class="pre">rnid</span></code>:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnid -g ~/.rngit/client_identity
|
||||
|
||||
New identity <1a54d64db7e8beca6f2c6cd17b0cb479> written to /home/user/.rngit/client_identity
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The identity file must contain the private key to be usable for signing. The corresponding Reticulum identity hash will be used as the commit author identity.</p>
|
||||
</section>
|
||||
<section id="id1">
|
||||
<h3>Configuration<a class="headerlink" href="#id1" title="Link to this heading">¶</a></h3>
|
||||
<p>Git must be configured to use SSH-format signatures with the <code class="docutils literal notranslate"><span class="pre">rngcs</span></code> signing shim, which is included in RNS. You can configure this either globally or per-repository.</p>
|
||||
<p><strong>Global Configuration</strong></p>
|
||||
<p>Enabling Reticulum commit signing for all repositories is as simple as:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ git config --global gpg.format ssh
|
||||
$ git config --global gpg.ssh.program rngcs
|
||||
$ git config --global gpg.ssh.allowedsignersfile none
|
||||
$ git config --global user.signingKey ~/.rngit/client_identity
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>With this configuration, all commits you sign with <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">commit</span> <span class="pre">-S</span></code> will use your Reticulum identity.</p>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">gpg.ssh.allowedsignersfile</span></code> configuration key <strong>must</strong> be <em>set</em> for <code class="docutils literal notranslate"><span class="pre">git</span></code> to allow invoking the signing and verification shim. It is not actually used by <code class="docutils literal notranslate"><span class="pre">rngcs</span></code>, and can be set to an arbitrary value. All validation operations happen exclusively based on the information in the embedded RSG data.</p>
|
||||
</div>
|
||||
<p><strong>Per-Repository Configuration</strong></p>
|
||||
<p>To enable signing only for a specific repository:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ cd /path/to/repository
|
||||
$ git config --local gpg.format ssh
|
||||
$ git config --local gpg.ssh.program rngcs
|
||||
$ git config --local gpg.ssh.allowedsignersfile none
|
||||
$ git config --local user.signingKey ~/.rngit/client_identity
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This is useful when you want to use different identities for different projects, or when only specific repositories require signed commits.</p>
|
||||
</section>
|
||||
<section id="author-identity-binding">
|
||||
<h3>Author Identity Binding<a class="headerlink" href="#author-identity-binding" title="Link to this heading">¶</a></h3>
|
||||
<p>For the signature to be valid, the Git author email <strong>must</strong> match the Reticulum identity hash of the signing key. You can configure this using a command like the following:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ git config --global user.email "1a54d64db7e8beca6f2c6cd17b0cb479"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>When <code class="docutils literal notranslate"><span class="pre">rngcs</span></code> verifies a commit, it extracts both the Git author field of the signed commit message and the signer identity from the RSG signature, ensuring they match. This binding is necessary to prevent identity spoofing. If someone crafts a commit with your identity hash in the author field but signs with a different key, verification will fail.</p>
|
||||
</section>
|
||||
<section id="signing-commits">
|
||||
<h3>Signing Commits<a class="headerlink" href="#signing-commits" title="Link to this heading">¶</a></h3>
|
||||
<p>Once configured, sign commits using the standard Git <code class="docutils literal notranslate"><span class="pre">-S</span></code> flag:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ git commit -S -m "Refactored module"
|
||||
|
||||
[master 8f7e6d5] Refactored module
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will create a self-contained RSG-formatted signature, encode the RSG payload using base64, and wrap it in an ASCII-armored SSH-formatted signature block. The signature is then stored in the commit object’s signature header and includes:</p>
|
||||
<ul class="simple">
|
||||
<li><p>The SHA256 hash of the commit content</p></li>
|
||||
<li><p>The signer’s Reticulum identity hash</p></li>
|
||||
<li><p>The signer’s public key</p></li>
|
||||
<li><p>The actual signature of the complete envelope</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="validating-commit-signatures">
|
||||
<h3>Validating Commit Signatures<a class="headerlink" href="#validating-commit-signatures" title="Link to this heading">¶</a></h3>
|
||||
<p>Commits are automatically validated when using <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">log</span> <span class="pre">--show-signature</span></code> or <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">show</span> <span class="pre">--show-signature</span></code>. The <code class="docutils literal notranslate"><span class="pre">rngcs</span></code> shim handles all verification operations. If any step fails, verification fails and Git displays an error.</p>
|
||||
<p>To view signature information for commits, use Git’s standard <code class="docutils literal notranslate"><span class="pre">--show-signature</span></code> option:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ git log --show-signature
|
||||
|
||||
commit 8f7e6d5c8f7e6d5c8f7e6d5c8f7e6d5c8f7e6d5
|
||||
Good "git" signature for commit, signed with Reticulum Identity key <1a54d64db7e8beca6f2c6cd17b0cb479>
|
||||
Author: Developer <1a54d64db7e8beca6f2c6cd17b0cb479>
|
||||
Date: Mon Jan 15 09:30:00 2026 +0100
|
||||
|
||||
Refactored module
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The output shows whether the commit signature is valid, and whether the author field matches the signing identity.</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>If you want to display both the identity hash and LXMF address for authors, you can generate a <code class="docutils literal notranslate"><span class="pre">.mailmap</span></code> file that resolves identities to LXMF addresses with the following script:</p>
|
||||
<div class="highlight-#!/bin/bash notranslate"><div class="highlight"><pre><span></span>DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
cd $DIR
|
||||
|
||||
id_regex="<([0-9a-f]{32})( .*)*>"
|
||||
extract_id="s/.*$id_regex/\1/g"
|
||||
|
||||
rm -f .mailmap
|
||||
git shortlog -se | grep -Ee "$id_regex" | sed -r "$extract_id" | while read -r id ; do
|
||||
if lxmf=$(rnid -i $id -H lxmf.delivery | grep -Ee "destination for this Identity is" | sed -r "$extract_id"); then
|
||||
echo "<$id lxmf:$lxmf> <$id>" >> .mailmap
|
||||
fi
|
||||
done
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
@@ -1126,14 +1473,14 @@ options:
|
||||
</div>
|
||||
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
|
||||
</a>
|
||||
<a class="prev-page" href="networks.html">
|
||||
<a class="prev-page" href="distributed.html">
|
||||
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
|
||||
<div class="page-info">
|
||||
<div class="context">
|
||||
<span>Previous</span>
|
||||
</div>
|
||||
|
||||
<div class="title">Building Networks</div>
|
||||
<div class="title">Distributed Development</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
@@ -1192,6 +1539,12 @@ options:
|
||||
<li><a class="reference internal" href="#permission-configuration-locations">Permission Configuration Locations</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#remote-permission-management">Remote Permission Management</a><ul>
|
||||
<li><a class="reference internal" href="#managing-group-permissions">Managing Group Permissions</a></li>
|
||||
<li><a class="reference internal" href="#managing-repository-permissions">Managing Repository Permissions</a></li>
|
||||
<li><a class="reference internal" href="#permission-validation">Permission Validation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#identity-destination-aliases">Identity & Destination Aliases</a></li>
|
||||
<li><a class="reference internal" href="#serving-pages-over-nomad-network">Serving Pages Over Nomad Network</a><ul>
|
||||
<li><a class="reference internal" href="#enabling-the-git-page-node">Enabling the Git Page Node</a></li>
|
||||
@@ -1202,6 +1555,12 @@ options:
|
||||
<li><a class="reference internal" href="#configuration-example">Configuration Example</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#verified-releases">Verified Releases</a><ul>
|
||||
<li><a class="reference internal" href="#obtaining-verified-releases">Obtaining Verified Releases</a></li>
|
||||
<li><a class="reference internal" href="#offline-verification">Offline Verification</a></li>
|
||||
<li><a class="reference internal" href="#creating-signed-releases">Creating Signed Releases</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#release-management">Release Management</a><ul>
|
||||
<li><a class="reference internal" href="#the-release-workflow">The Release Workflow</a></li>
|
||||
<li><a class="reference internal" href="#release-storage-structure">Release Storage & Structure</a></li>
|
||||
@@ -1213,6 +1572,15 @@ options:
|
||||
<li><a class="reference internal" href="#proposing-work-documents">Proposing Work Documents</a></li>
|
||||
<li><a class="reference internal" href="#state-management">State Management</a></li>
|
||||
<li><a class="reference internal" href="#managing-work-document-permissions">Managing Work Document Permissions</a></li>
|
||||
<li><a class="reference internal" href="#cryptographic-attribution">Cryptographic Attribution</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#commit-signing">Commit Signing</a><ul>
|
||||
<li><a class="reference internal" href="#prerequisites">Prerequisites</a></li>
|
||||
<li><a class="reference internal" href="#id1">Configuration</a></li>
|
||||
<li><a class="reference internal" href="#author-identity-binding">Author Identity Binding</a></li>
|
||||
<li><a class="reference internal" href="#signing-commits">Signing Commits</a></li>
|
||||
<li><a class="reference internal" href="#validating-commit-signatures">Validating Commit Signatures</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1226,7 +1594,7 @@ options:
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Communications Hardware - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Communications Hardware - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -675,7 +676,7 @@ can be used with Reticulum. This includes virtual software modems such as
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
+39
-4
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="#"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="#"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -523,6 +524,19 @@ to participate in the development of Reticulum itself.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#the-original-architecture">The Original Architecture</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#the-platform-interregnum">The Platform Interregnum</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#restoration">Restoration</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#protocols-over-platforms">Protocols Over Platforms</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#sovereignty-through-infrastructure">Sovereignty Through Infrastructure</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#artifact-centered-workflows">Artifact-Centered Workflows</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#composable-primitives">Composable Primitives</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#distribution-without-intermediaries">Distribution Without Intermediaries</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#long-archive">Long Archive</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="distributed.html#start-of-the-road">Start Of The Road</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="git.html#the-rngit-utility">The rngit Utility</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="git.html#repository-creation-management">Repository Creation & Management</a><ul>
|
||||
@@ -549,6 +563,12 @@ to participate in the development of Reticulum itself.</p>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#permission-configuration-locations">Permission Configuration Locations</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="git.html#remote-permission-management">Remote Permission Management</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#managing-group-permissions">Managing Group Permissions</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#managing-repository-permissions">Managing Repository Permissions</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#permission-validation">Permission Validation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="git.html#identity-destination-aliases">Identity & Destination Aliases</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="git.html#serving-pages-over-nomad-network">Serving Pages Over Nomad Network</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#enabling-the-git-page-node">Enabling the Git Page Node</a></li>
|
||||
@@ -559,6 +579,12 @@ to participate in the development of Reticulum itself.</p>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#configuration-example">Configuration Example</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="git.html#verified-releases">Verified Releases</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#obtaining-verified-releases">Obtaining Verified Releases</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#offline-verification">Offline Verification</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#creating-signed-releases">Creating Signed Releases</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="git.html#release-management">Release Management</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#the-release-workflow">The Release Workflow</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#release-storage-structure">Release Storage & Structure</a></li>
|
||||
@@ -570,6 +596,15 @@ to participate in the development of Reticulum itself.</p>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#proposing-work-documents">Proposing Work Documents</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#state-management">State Management</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#managing-work-document-permissions">Managing Work Document Permissions</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#cryptographic-attribution">Cryptographic Attribution</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="git.html#commit-signing">Commit Signing</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#prerequisites">Prerequisites</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#id1">Configuration</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#author-identity-binding">Author Identity Binding</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#signing-commits">Signing Commits</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="git.html#validating-commit-signatures">Validating Commit Signatures</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -684,7 +719,7 @@ to participate in the development of Reticulum itself.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Configuring Interfaces - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Configuring Interfaces - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -1773,7 +1774,7 @@ interface basis under the relevant interface configuration section.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Reticulum License - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Reticulum License - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -344,7 +345,7 @@ SOFTWARE.
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<head><meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<meta name="color-scheme" content="light dark"><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="index" title="Index" href="genindex.html"><link rel="search" title="Search" href="search.html"><link rel="next" title="Git Over Reticulum" href="git.html"><link rel="prev" title="Configuring Interfaces" href="interfaces.html">
|
||||
<link rel="index" title="Index" href="genindex.html"><link rel="search" title="Search" href="search.html"><link rel="next" title="Distributed Development" href="distributed.html"><link rel="prev" title="Configuring Interfaces" href="interfaces.html">
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Building Networks - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Building Networks - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -594,12 +595,12 @@ differently than a mobile device roaming between radio cells.</p>
|
||||
<footer>
|
||||
|
||||
<div class="related-pages">
|
||||
<a class="next-page" href="git.html">
|
||||
<a class="next-page" href="distributed.html">
|
||||
<div class="page-info">
|
||||
<div class="context">
|
||||
<span>Next</span>
|
||||
</div>
|
||||
<div class="title">Git Over Reticulum</div>
|
||||
<div class="title">Distributed Development</div>
|
||||
</div>
|
||||
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
|
||||
</a>
|
||||
@@ -663,7 +664,7 @@ differently than a mobile device roaming between radio cells.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
Binary file not shown.
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>API Reference - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>API Reference - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -2233,6 +2234,38 @@ will announce it.</p>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Transport.blackhole_identity">
|
||||
<em class="property"><span class="k"><span class="pre">static</span></span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">blackhole_identity</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">identity_hash</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">until</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">reason</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Transport.blackhole_identity" title="Link to this definition">¶</a></dt>
|
||||
<dd><p>Blackholes an identity.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||
<dd class="field-odd"><ul class="simple">
|
||||
<li><p><strong>identity_hash</strong> – The identity hash to blackhole as <em>bytes</em>.</p></li>
|
||||
<li><p><strong>until</strong> – Optional unix timestamp of when the blackhole expires as <em>float</em> or <em>int</em>.</p></li>
|
||||
<li><p><strong>reason</strong> – Optional reason for the blackhole as <em>str</em>.</p></li>
|
||||
</ul>
|
||||
</dd>
|
||||
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||
<dd class="field-even"><p><em>True</em> if successful, otherwise <em>False</em>.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Transport.unblackhole_identity">
|
||||
<em class="property"><span class="k"><span class="pre">static</span></span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">unblackhole_identity</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">identity_hash</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Transport.unblackhole_identity" title="Link to this definition">¶</a></dt>
|
||||
<dd><p>Lifts blackhole for an identity.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||
<dd class="field-odd"><p><strong>identity_hash</strong> – The identity hash to blackhole as <em>bytes</em>.</p>
|
||||
</dd>
|
||||
<dt class="field-even">Returns<span class="colon">:</span></dt>
|
||||
<dd class="field-even"><p><em>True</em> if successful, otherwise <em>False</em>.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
||||
</section>
|
||||
@@ -2471,6 +2504,8 @@ will announce it.</p>
|
||||
<li><a class="reference internal" href="#RNS.Transport.next_hop_interface"><code class="docutils literal notranslate"><span class="pre">next_hop_interface()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Transport.await_path"><code class="docutils literal notranslate"><span class="pre">await_path()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Transport.request_path"><code class="docutils literal notranslate"><span class="pre">request_path()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Transport.blackhole_identity"><code class="docutils literal notranslate"><span class="pre">blackhole_identity()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Transport.unblackhole_identity"><code class="docutils literal notranslate"><span class="pre">unblackhole_identity()</span></code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -2484,7 +2519,7 @@ will announce it.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<meta name="robots" content="noindex" />
|
||||
<title>Search - Reticulum Network Stack 1.2.8 documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<title>Search - Reticulum Network Stack 1.3.5 documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?v=8dab3a3b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="#" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -303,7 +304,7 @@
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Programs Using Reticulum - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Programs Using Reticulum - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -512,7 +513,7 @@ plugin system for expandability.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Support Reticulum - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Support Reticulum - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -382,7 +383,7 @@ circumstances, so we rely on old-fashioned human feedback.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
+90
-311
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Understanding Reticulum - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Understanding Reticulum - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -263,50 +264,21 @@
|
||||
<article role="main" id="furo-main-content">
|
||||
<section id="understanding-reticulum">
|
||||
<span id="understanding-main"></span><h1>Understanding Reticulum<a class="headerlink" href="#understanding-reticulum" title="Link to this heading">¶</a></h1>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<section id="motivation">
|
||||
<span id="understanding-motivation"></span><h2>Motivation<a class="headerlink" href="#motivation" title="Link to this heading">¶</a></h2>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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 <a class="reference internal" href="#understanding-referencesystem"><span class="std std-ref">Reference Setup</span></a>),
|
||||
connected to any kind of computer or mobile device that Reticulum can run on.</p>
|
||||
<p>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 <strong>is not</strong> <em>one network</em>, it <strong>is a tool</strong> to build <em>thousands of networks</em>. 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. <em>Networks for the people</em>.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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 <a class="reference internal" href="#understanding-referencesystem"><span class="std std-ref">Reference Setup</span></a>), connected to any kind of computer or mobile device that Reticulum can run on.</p>
|
||||
<p>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 <strong>is not</strong> <em>one network</em>, it <strong>is a tool</strong> to build <em>thousands of networks</em>. 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. <em>Networks for the people</em>.</p>
|
||||
</section>
|
||||
<section id="goals">
|
||||
<span id="understanding-goals"></span><h2>Goals<a class="headerlink" href="#goals" title="Link to this heading">¶</a></h2>
|
||||
<p>To be as widely usable and efficient to deploy as possible, the following goals have been used to
|
||||
guide the design of Reticulum:</p>
|
||||
<p>To be as widely usable and efficient to deploy as possible, the following goals have been used to guide the design of Reticulum:</p>
|
||||
<ul class="simple">
|
||||
<li><dl class="simple">
|
||||
<dt><strong>Fully useable as open source software stack</strong></dt><dd><p>Reticulum must be implemented with, and be able to run using only open source software. This is
|
||||
@@ -343,8 +315,8 @@ information about oneself.</p>
|
||||
<li><dl class="simple">
|
||||
<dt><strong>Unlicensed use</strong></dt><dd><p>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.</p>
|
||||
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.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
@@ -352,15 +324,15 @@ by connecting a modem to a PMR or CB radio, or by using LoRa or WiFi modules.</p
|
||||
<dt><strong>Supplied software</strong></dt><dd><p>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.</p>
|
||||
functional, basic communication suite, and as an example and learning resource to others
|
||||
wishing to build applications with Reticulum.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li><dl class="simple">
|
||||
<dt><strong>Ease of use</strong></dt><dd><p>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.</p>
|
||||
<dt><strong>Ease of use</strong></dt><dd><p>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.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
@@ -376,43 +348,16 @@ needs to be purchased.</p>
|
||||
</section>
|
||||
<section id="introduction-basic-functionality">
|
||||
<span id="understanding-basicfunctionality"></span><h2>Introduction & Basic Functionality<a class="headerlink" href="#introduction-basic-functionality" title="Link to this heading">¶</a></h2>
|
||||
<p>Reticulum is a networking stack suited for high-latency, low-bandwidth links. Reticulum is at its
|
||||
core a <em>message oriented</em> 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.</p>
|
||||
<p>Reticulum does away with the idea of addresses and ports known from IP, TCP and UDP. Instead
|
||||
Reticulum uses the singular concept of <em>destinations</em>. 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.</p>
|
||||
<p>All destinations in Reticulum are <em>represented</em> 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: <code class="docutils literal notranslate"><span class="pre"><13425ec15b621c1d928589718000d814></span></code>.</p>
|
||||
<p>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.</p>
|
||||
<p>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 <em>Link</em>. Both data sent over Links and single packets offer
|
||||
<em>Initiator Anonymity</em>. Links additionally offer <em>Forward Secrecy</em> 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.</p>
|
||||
<p>Reticulum also offers symmetric key encryption for group-oriented communications, as well as
|
||||
unencrypted packets (for local broadcast purposes <strong>only</strong>).</p>
|
||||
<p>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.</p>
|
||||
<p>Reticulum is a networking stack suited for high-latency, low-bandwidth links. Reticulum is at its core a <em>message oriented</em> 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.</p>
|
||||
<p>Reticulum does away with the idea of addresses and ports known from IP, TCP and UDP. Instead Reticulum uses the singular concept of <em>destinations</em>. 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.</p>
|
||||
<p>All destinations in Reticulum are <em>represented</em> 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: <code class="docutils literal notranslate"><span class="pre"><13425ec15b621c1d928589718000d814></span></code>.</p>
|
||||
<p>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.</p>
|
||||
<p>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 <em>Link</em>. Both data sent over Links and single packets offer <em>Initiator Anonymity</em>. Links additionally offer <em>Forward Secrecy</em> 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.</p>
|
||||
<p>Reticulum also offers symmetric key encryption for group-oriented communications, as well as unencrypted packets (for local broadcast purposes <strong>only</strong>).</p>
|
||||
<p>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.</p>
|
||||
<section id="destinations">
|
||||
<span id="understanding-destinations"></span><h3>Destinations<a class="headerlink" href="#destinations" title="Link to this heading">¶</a></h3>
|
||||
<p>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:</p>
|
||||
<p>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:</p>
|
||||
<ul class="simple">
|
||||
<li><dl class="simple">
|
||||
<dt><strong>Single</strong></dt><dd><p>The <em>single</em> destination type is the most common type in Reticulum, and should be used for
|
||||
@@ -427,9 +372,9 @@ only be readable by the creator of the destination, who holds the corresponding
|
||||
number of users, or should be readable by anyone. Traffic to a <em>plain</em> destination is not encrypted.
|
||||
Generally, <em>plain</em> 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
|
||||
<em>must</em> be encrypted, since Reticulum uses the per-packet encryption to verify routing paths and
|
||||
keep them alive.</p>
|
||||
never transported over multiple hops in the network. To be transportable over multiple hops in
|
||||
Reticulum, information <em>must</em> be encrypted, since Reticulum uses the per-packet encryption to verify
|
||||
routing paths and keep them alive.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</li>
|
||||
@@ -454,14 +399,9 @@ out requests and responses, large data transfers and more.</p>
|
||||
</ul>
|
||||
<section id="destination-naming">
|
||||
<span id="understanding-destinationnaming"></span><h4>Destination Naming<a class="headerlink" href="#destination-naming" title="Link to this heading">¶</a></h4>
|
||||
<p>Destinations are created and named in an easy to understand dotted notation of <em>aspects</em>, and
|
||||
represented on the network as a hash of this value. The hash is a SHA-256 truncated to 128 bits. The
|
||||
top level aspect should always be a unique identifier for the application using the destination.
|
||||
The next levels of aspects can be defined in any way by the creator of the application.</p>
|
||||
<p>Aspects can be as long and as plentiful as required, and a resulting long destination name will not
|
||||
impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.</p>
|
||||
<p>As an example, a destination for a environmental monitoring application could be made up of the
|
||||
application name, a device type and measurement type, like this:</p>
|
||||
<p>Destinations are created and named in an easy to understand dotted notation of <em>aspects</em>, and represented on the network as a hash of this value. The hash is a SHA-256 truncated to 128 bits. The top level aspect should always be a unique identifier for the application using the destination. The next levels of aspects can be defined in any way by the creator of the application.</p>
|
||||
<p>Aspects can be as long and as plentiful as required, and a resulting long destination name will not impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.</p>
|
||||
<p>As an example, a destination for a environmental monitoring application could be made up of the application name, a device type and measurement type, like this:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>app name : environmentlogger
|
||||
aspects : remotesensor, temperature
|
||||
|
||||
@@ -469,26 +409,15 @@ full name : environmentlogger.remotesensor.temperature
|
||||
hash : 4faf1b2e0a077e6a9d92fa051f256038
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>For the <em>single</em> destination, Reticulum will automatically append the associated public key as a
|
||||
destination aspect before hashing. This is done to ensure only the correct destination is reached,
|
||||
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.</p>
|
||||
<p>For the <em>single</em> destination, Reticulum will automatically append the associated public key as a destination aspect before hashing. This is done to ensure only the correct destination is reached, 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.</p>
|
||||
<p><strong>Take note!</strong> There is a very important concept to understand here:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Anyone can use the destination name <code class="docutils literal notranslate"><span class="pre">environmentlogger.remotesensor.temperature</span></code></p></li>
|
||||
<li><p>Each destination that does so will still have a unique destination hash, and thus be uniquely
|
||||
addressable, because their public keys will differ.</p></li>
|
||||
</ul>
|
||||
<p>In actual use of <em>single</em> 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.</p>
|
||||
<p>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.</p>
|
||||
<p>In actual use of <em>single</em> 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.</p>
|
||||
<p>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.</p>
|
||||
<p>To recap, the different destination types should be used in the following situations:</p>
|
||||
<ul class="simple">
|
||||
<li><dl class="simple">
|
||||
@@ -508,25 +437,13 @@ indirectly, but must first be established through a <em>single</em> destination.
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
<p>To communicate with a <em>single</em> 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 <em>announce</em>. 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.</p>
|
||||
<p>Note that public key information can be shared and verified in other ways than using the
|
||||
built-in <em>announce</em> functionality, and that it is therefore not required to use the <em>announce</em> and <em>path request</em>
|
||||
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.</p>
|
||||
<p>To communicate with a <em>single</em> 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 <em>announce</em>. 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.</p>
|
||||
<p>Note that public key information can be shared and verified in other ways than using the built-in <em>announce</em> functionality, and that it is therefore not required to use the <em>announce</em> and <em>path request</em> 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.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="public-key-announcements">
|
||||
<span id="understanding-keyannouncements"></span><h3>Public Key Announcements<a class="headerlink" href="#public-key-announcements" title="Link to this heading">¶</a></h3>
|
||||
<p>An <em>announce</em> 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.</p>
|
||||
<p>An <em>announce</em> 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.</p>
|
||||
<p>As an example, an announce in a simple messenger application might contain the following information:</p>
|
||||
<ul class="simple">
|
||||
<li><p>The announcers destination hash</p></li>
|
||||
@@ -535,78 +452,37 @@ to the announced destination, as the announce propagates through the network.</p
|
||||
<li><p>A random blob, making each new announce unique</p></li>
|
||||
<li><p>An Ed25519 signature of the above information, verifying authenticity</p></li>
|
||||
</ul>
|
||||
<p>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.</p>
|
||||
<p>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
|
||||
<a class="reference internal" href="#understanding-announce"><span class="std std-ref">The Announce Mechanism in Detail</span></a>.</p>
|
||||
<p>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 <em>completely portable</em> over the entire topography
|
||||
of the network, and <em>can even be moved to other Reticulum networks</em> 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.</p>
|
||||
<p>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.</p>
|
||||
<p>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 <a class="reference internal" href="#understanding-announce"><span class="std std-ref">The Announce Mechanism in Detail</span></a>.</p>
|
||||
<p>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 <em>completely portable</em> over the entire topography of the network, and <em>can even be moved to other Reticulum networks</em> 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.</p>
|
||||
<p>Seeing how <em>single</em> destinations are always tied to a private/public key pair leads us to the next topic.</p>
|
||||
</section>
|
||||
<section id="understanding-identities">
|
||||
<span id="identities"></span><h3>Identities<a class="headerlink" href="#understanding-identities" title="Link to this heading">¶</a></h3>
|
||||
<p>In Reticulum, an <em>identity</em> does not necessarily represent a personal identity, but is an abstraction that
|
||||
can represent any kind of <em>verifiable entity</em>. 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 <em>identity</em> can be used to create any number of destinations.</p>
|
||||
<p>A <em>single</em> destination will always have an <em>identity</em> tied to it, but not <em>plain</em> or <em>group</em>
|
||||
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.</p>
|
||||
<p>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.</p>
|
||||
<p>In Reticulum, an <em>identity</em> does not necessarily represent a personal identity, but is an abstraction that can represent any kind of <em>verifiable entity</em>. 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 <em>identity</em> can be used to create any number of destinations.</p>
|
||||
<p>A <em>single</em> destination will always have an <em>identity</em> tied to it, but not <em>plain</em> or <em>group</em> 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.</p>
|
||||
<p>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.</p>
|
||||
</section>
|
||||
<section id="getting-further">
|
||||
<span id="understanding-gettingfurther"></span><h3>Getting Further<a class="headerlink" href="#getting-further" title="Link to this heading">¶</a></h3>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>In the following sections, two concepts that allow this will be introduced, <em>paths</em> and <em>links</em>.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="reticulum-transport">
|
||||
<span id="understanding-transport"></span><h2>Reticulum Transport<a class="headerlink" href="#reticulum-transport" title="Link to this heading">¶</a></h2>
|
||||
<p>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.</p>
|
||||
<p>To overcome such challenges, Reticulum’s <em>Transport</em> system uses asymmetric elliptic curve cryptography to
|
||||
implement the concept of <em>paths</em> 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.</p>
|
||||
<p>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.</p>
|
||||
<p>To overcome such challenges, Reticulum’s <em>Transport</em> system uses asymmetric elliptic curve cryptography to implement the concept of <em>paths</em> 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.</p>
|
||||
<section id="node-types">
|
||||
<span id="understanding-nodetypes"></span><h3>Node Types<a class="headerlink" href="#node-types" title="Link to this heading">¶</a></h3>
|
||||
<p>Currently, Reticulum distinguishes between two types of network nodes. All nodes on a Reticulum network
|
||||
are <em>Reticulum Instances</em>, and some are also <em>Transport Nodes</em>. 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 <em>Transport Node</em>.</p>
|
||||
<p>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.</p>
|
||||
<p>If a node is an <em>Instance</em> it should be given the configuration directive <code class="docutils literal notranslate"><span class="pre">enable_transport</span> <span class="pre">=</span> <span class="pre">No</span></code>, which
|
||||
is the default setting.</p>
|
||||
<p>Currently, Reticulum distinguishes between two types of network nodes. All nodes on a Reticulum network are <em>Reticulum Instances</em>, and some are also <em>Transport Nodes</em>. 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 <em>Transport Node</em>.</p>
|
||||
<p>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.</p>
|
||||
<p>If a node is an <em>Instance</em> it should be given the configuration directive <code class="docutils literal notranslate"><span class="pre">enable_transport</span> <span class="pre">=</span> <span class="pre">No</span></code>, which is the default setting.</p>
|
||||
<p>If it is a <em>Transport Node</em>, it should be given the configuration directive <code class="docutils literal notranslate"><span class="pre">enable_transport</span> <span class="pre">=</span> <span class="pre">Yes</span></code>.</p>
|
||||
</section>
|
||||
<section id="the-announce-mechanism-in-detail">
|
||||
<span id="understanding-announce"></span><h3>The Announce Mechanism in Detail<a class="headerlink" href="#the-announce-mechanism-in-detail" title="Link to this heading">¶</a></h3>
|
||||
<p>When an <em>announce</em> 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:</p>
|
||||
<p>When an <em>announce</em> 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:</p>
|
||||
<ul>
|
||||
<li><div class="line-block">
|
||||
<div class="line">If this exact announce has already been received before, ignore it.</div>
|
||||
@@ -653,36 +529,18 @@ application specific data, it will replace the old announce.</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<div class="admonition tip">
|
||||
<p class="admonition-title">Tip</p>
|
||||
<p>Even very slow networks, that simply don’t have the capacity to ever reach <em>full</em> convergence
|
||||
will generally still be able to reach <strong>any other destination on any connected segments</strong>, since
|
||||
interconnecting transport nodes will prioritize announces into the slower segments that are
|
||||
actually requested by nodes on these.</p>
|
||||
<p>This means that slow, low-capacity or low-resource segments <strong>don’t</strong> need to have full network
|
||||
knowledge, since paths can always be recursively resolved from other segments that do have
|
||||
knowledge about them.</p>
|
||||
<p>Even very slow networks, that simply don’t have the capacity to ever reach <em>full</em> convergence will generally still be able to reach <strong>any other destination on any connected segments</strong>, since interconnecting transport nodes will prioritize announces into the slower segments that are actually requested by nodes on these.</p>
|
||||
<p>This means that slow, low-capacity or low-resource segments <strong>don’t</strong> need to have full network knowledge, since paths can always be recursively resolved from other segments that do have knowledge about them.</p>
|
||||
</div>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
</section>
|
||||
<section id="reaching-the-destination">
|
||||
<span id="understanding-paths"></span><h3>Reaching the Destination<a class="headerlink" href="#reaching-the-destination" title="Link to this heading">¶</a></h3>
|
||||
<p>In networks with changing topology and trustless connectivity, nodes need a way to establish
|
||||
<em>verified connectivity</em> 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.</p>
|
||||
<p>In networks with changing topology and trustless connectivity, nodes need a way to establish <em>verified connectivity</em> 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.</p>
|
||||
<p>For exchanges of small amounts of information, Reticulum offers the <em>Packet</em> API, which works exactly like you would expect - on a per packet level. The following process is employed when sending a packet:</p>
|
||||
<ul>
|
||||
<li><div class="line-block">
|
||||
@@ -768,30 +626,12 @@ link, and is only revealed to the verified destination, and no intermediaries.</
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<p>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 <em>link id</em> , 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 <em>link id</em>.</p>
|
||||
<p>The combined bandwidth cost of setting up a link is 3 packets totalling 297 bytes (more info in the
|
||||
<a class="reference internal" href="#understanding-packetformat"><span class="std std-ref">Binary Packet Format</span></a> 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.</p>
|
||||
<p>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 <em>link id</em> , 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 <em>link id</em>.</p>
|
||||
<p>The combined bandwidth cost of setting up a link is 3 packets totalling 297 bytes (more info in the <a class="reference internal" href="#understanding-packetformat"><span class="std std-ref">Binary Packet Format</span></a> 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.</p>
|
||||
<section id="link-establishment-in-detail">
|
||||
<h4>Link Establishment in Detail<a class="headerlink" href="#link-establishment-in-detail" title="Link to this heading">¶</a></h4>
|
||||
<p>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.</p>
|
||||
<p>The <em>link</em> 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.</p>
|
||||
<p>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.</p>
|
||||
<p>The <em>link</em> 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.</p>
|
||||
<ul>
|
||||
<li><div class="line-block">
|
||||
<div class="line">When a node in the network wants to establish verified connectivity with another node, it
|
||||
@@ -855,25 +695,16 @@ that is used to encrypt the channel. Information can now be exchanged reliably a
|
||||
</ul>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>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. <strong>The link initiator remains completely anonymous</strong>.</p>
|
||||
<p>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. <strong>The link initiator remains completely anonymous</strong>.</p>
|
||||
</div>
|
||||
<p>When using <em>links</em>, Reticulum will automatically verify all data sent over the link, and can also
|
||||
automate retransmissions if <em>Resources</em> are used.</p>
|
||||
<p>When using <em>links</em>, Reticulum will automatically verify all data sent over the link, and can also automate retransmissions if <em>Resources</em> are used.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="resources">
|
||||
<span id="understanding-resources"></span><h3>Resources<a class="headerlink" href="#resources" title="Link to this heading">¶</a></h3>
|
||||
<p>For exchanging small amounts of data over a Reticulum network, the <a class="reference internal" href="reference.html#api-packet"><span class="std std-ref">Packet</span></a> interface
|
||||
is sufficient, but for exchanging data that would require many packets, an efficient way to coordinate
|
||||
the transfer is needed.</p>
|
||||
<p>This is the purpose of the Reticulum <a class="reference internal" href="reference.html#api-resource"><span class="std std-ref">Resource</span></a>. A <em>Resource</em> can automatically
|
||||
handle the reliable transfer of an arbitrary amount of data over an established <a class="reference internal" href="reference.html#api-link"><span class="std std-ref">Link</span></a>.
|
||||
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.</p>
|
||||
<p><a class="reference internal" href="reference.html#api-resource"><span class="std std-ref">Resources</span></a> 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.</p>
|
||||
<p>For exchanging small amounts of data over a Reticulum network, the <a class="reference internal" href="reference.html#api-packet"><span class="std std-ref">Packet</span></a> interface is sufficient, but for exchanging data that would require many packets, an efficient way to coordinate the transfer is needed.</p>
|
||||
<p>This is the purpose of the Reticulum <a class="reference internal" href="reference.html#api-resource"><span class="std std-ref">Resource</span></a>. A <em>Resource</em> can automatically handle the reliable transfer of an arbitrary amount of data over an established <a class="reference internal" href="reference.html#api-link"><span class="std std-ref">Link</span></a>. 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.</p>
|
||||
<p><a class="reference internal" href="reference.html#api-resource"><span class="std std-ref">Resources</span></a> 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.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="network-identities">
|
||||
@@ -938,17 +769,9 @@ In the <code class="docutils literal notranslate"><span class="pre">[reticulum]<
|
||||
</section>
|
||||
<section id="reference-setup">
|
||||
<span id="understanding-referencesystem"></span><h2>Reference Setup<a class="headerlink" href="#reference-setup" title="Link to this heading">¶</a></h2>
|
||||
<p>This section will detail a recommended <em>Reference Setup</em> 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.</p>
|
||||
<p>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.</p>
|
||||
<p>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:</p>
|
||||
<p>This section will detail a recommended <em>Reference Setup</em> 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.</p>
|
||||
<p>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.</p>
|
||||
<p>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:</p>
|
||||
<ul class="simple">
|
||||
<li><dl class="simple">
|
||||
<dt><strong>An Interface Device</strong></dt><dd><p>Which provides access to the physical medium whereupon the communication
|
||||
@@ -969,11 +792,7 @@ interface device, and provide user interaction.</p>
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
<p>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:</p>
|
||||
<p>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:</p>
|
||||
<ul class="simple">
|
||||
<li><dl class="simple">
|
||||
<dt><strong>Interface Device</strong></dt><dd><p>A data radio consisting of a LoRa radio module, and a microcontroller with open source
|
||||
@@ -997,41 +816,23 @@ operating system.</p>
|
||||
</ul>
|
||||
<div class="admonition note">
|
||||
<p class="admonition-title">Note</p>
|
||||
<p>To avoid confusion, it is very important to note, that the reference interface device <strong>does not</strong>
|
||||
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 <a class="reference external" href="https://github.com/markqvist/rnode_firmware">RNode Page</a>.</p>
|
||||
<p>To avoid confusion, it is very important to note, that the reference interface device <strong>does not</strong> 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 <a class="reference external" href="https://github.com/markqvist/rnode_firmware">RNode Page</a>.</p>
|
||||
</div>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
</section>
|
||||
<section id="protocol-specifics">
|
||||
<span id="understanding-protocolspecifics"></span><h2>Protocol Specifics<a class="headerlink" href="#protocol-specifics" title="Link to this heading">¶</a></h2>
|
||||
<p>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.</p>
|
||||
<p>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.</p>
|
||||
<section id="packet-prioritisation">
|
||||
<h3>Packet Prioritisation<a class="headerlink" href="#packet-prioritisation" title="Link to this heading">¶</a></h3>
|
||||
<p>Currently, Reticulum is completely priority-agnostic regarding <em>general</em> 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.</p>
|
||||
<p>Currently, Reticulum is completely priority-agnostic regarding <em>general</em> 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.</p>
|
||||
</section>
|
||||
<section id="interface-access-codes">
|
||||
<h3>Interface Access Codes<a class="headerlink" href="#interface-access-codes" title="Link to this heading">¶</a></h3>
|
||||
<p>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 <a class="reference internal" href="interfaces.html#interfaces-options"><span class="std std-ref">Common Interface Options</span></a>
|
||||
section. To implement this feature, Reticulum uses the concept of Interface Access Codes, that are calculated
|
||||
and verified per-packet.</p>
|
||||
<p>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 <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code> utility.</p>
|
||||
<p>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.</p>
|
||||
<p>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 <a class="reference internal" href="interfaces.html#interfaces-options"><span class="std std-ref">Common Interface Options</span></a> section. To implement this feature, Reticulum uses the concept of Interface Access Codes, that are calculated and verified per-packet.</p>
|
||||
<p>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 <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code> utility.</p>
|
||||
<p>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.</p>
|
||||
</section>
|
||||
<section id="wire-format">
|
||||
<span id="understanding-packetformat"></span><h3>Wire Format<a class="headerlink" href="#wire-format" title="Link to this heading">¶</a></h3>
|
||||
@@ -1167,24 +968,15 @@ but excluding any interface access codes.
|
||||
</section>
|
||||
<section id="announce-propagation-rules">
|
||||
<span id="understanding-announcepropagation"></span><h3>Announce Propagation Rules<a class="headerlink" href="#announce-propagation-rules" title="Link to this heading">¶</a></h3>
|
||||
<p>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 <em>Full</em> and <em>Gateway</em> modes are identical.</p>
|
||||
<p>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 <em>Full</em> and <em>Gateway</em> modes are identical.</p>
|
||||
<img alt="_images/if_mode_graph_b.png" src="_images/if_mode_graph_b.png" />
|
||||
<p>See the <a class="reference internal" href="interfaces.html#interfaces-modes"><span class="std std-ref">Interface Modes</span></a> section for a conceptual overview
|
||||
of the different interface modes, and how they are configured.</p>
|
||||
<p>See the <a class="reference internal" href="interfaces.html#interfaces-modes"><span class="std std-ref">Interface Modes</span></a> section for a conceptual overview of the different interface modes, and how they are configured.</p>
|
||||
</section>
|
||||
<section id="cryptographic-primitives">
|
||||
<span id="understanding-primitives"></span><h3>Cryptographic Primitives<a class="headerlink" href="#cryptographic-primitives" title="Link to this heading">¶</a></h3>
|
||||
<p>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.</p>
|
||||
<p>One of the primary considerations for choosing this particular set of primitives is
|
||||
that they can be implemented <em>safely</em> with relatively few pitfalls, on practically
|
||||
all current computing platforms.</p>
|
||||
<p>The primitives listed here <strong>are authoritative</strong>. Anything claiming to be Reticulum,
|
||||
but not using these exact primitives <strong>is not</strong> Reticulum, and possibly an
|
||||
intentionally compromised or weakened clone. The utilised primitives are:</p>
|
||||
<p>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.</p>
|
||||
<p>One of the primary considerations for choosing this particular set of primitives is that they can be implemented <em>safely</em> with relatively few pitfalls, on practically all current computing platforms.</p>
|
||||
<p>The primitives listed here <strong>are authoritative</strong>. Anything claiming to be Reticulum, but not using these exact primitives <strong>is not</strong> Reticulum, and possibly an intentionally compromised or weakened clone. The utilised primitives are:</p>
|
||||
<ul class="simple">
|
||||
<li><p>Ed25519 for signatures</p></li>
|
||||
<li><p>X25519 for ECDH key exchanges</p></li>
|
||||
@@ -1201,28 +993,15 @@ intentionally compromised or weakened clone. The utilised primitives are:</p>
|
||||
<li><p>SHA-256</p></li>
|
||||
<li><p>SHA-512</p></li>
|
||||
</ul>
|
||||
<p>In the default installation configuration, the <code class="docutils literal notranslate"><span class="pre">X25519</span></code>, <code class="docutils literal notranslate"><span class="pre">Ed25519</span></code> and <code class="docutils literal notranslate"><span class="pre">AES-256-CBC</span></code>
|
||||
primitives are provided by <a class="reference external" href="https://www.openssl.org/">OpenSSL</a> (via the <a class="reference external" href="https://github.com/pyca/cryptography">PyCA/cryptography</a>
|
||||
package). The hashing functions <code class="docutils literal notranslate"><span class="pre">SHA-256</span></code> and <code class="docutils literal notranslate"><span class="pre">SHA-512</span></code> are provided by the standard
|
||||
Python <a class="reference external" href="https://docs.python.org/3/library/hashlib.html">hashlib</a>. The <code class="docutils literal notranslate"><span class="pre">HKDF</span></code>, <code class="docutils literal notranslate"><span class="pre">HMAC</span></code>,
|
||||
<code class="docutils literal notranslate"><span class="pre">Token</span></code> primitives, and the <code class="docutils literal notranslate"><span class="pre">PKCS7</span></code> padding function are always provided by the
|
||||
following internal implementations:</p>
|
||||
<p>In the default installation configuration, the <code class="docutils literal notranslate"><span class="pre">X25519</span></code>, <code class="docutils literal notranslate"><span class="pre">Ed25519</span></code> and <code class="docutils literal notranslate"><span class="pre">AES-256-CBC</span></code> primitives are provided by <a class="reference external" href="https://www.openssl.org/">OpenSSL</a> (via the <a class="reference external" href="https://github.com/pyca/cryptography">PyCA/cryptography</a> package). The hashing functions <code class="docutils literal notranslate"><span class="pre">SHA-256</span></code> and <code class="docutils literal notranslate"><span class="pre">SHA-512</span></code> are provided by the standard Python <a class="reference external" href="https://docs.python.org/3/library/hashlib.html">hashlib</a>. The <code class="docutils literal notranslate"><span class="pre">HKDF</span></code>, <code class="docutils literal notranslate"><span class="pre">HMAC</span></code>, <code class="docutils literal notranslate"><span class="pre">Token</span></code> primitives, and the <code class="docutils literal notranslate"><span class="pre">PKCS7</span></code> padding function are always provided by the following internal implementations:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">RNS/Cryptography/HKDF.py</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">RNS/Cryptography/HMAC.py</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">RNS/Cryptography/Token.py</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">RNS/Cryptography/PKCS7.py</span></code></p></li>
|
||||
</ul>
|
||||
<p>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 <em>much</em> 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.</p>
|
||||
<p>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 <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> package.</p>
|
||||
<p>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 <em>much</em> 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.</p>
|
||||
<p>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 <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> package.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>If you want to use the internal pure-python primitives, it is <strong>highly advisable</strong> that you
|
||||
@@ -1337,7 +1116,7 @@ those risks are acceptable to you.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Using Reticulum on Your System - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Using Reticulum on Your System - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -1373,7 +1374,7 @@ remote_management_allowed = 9fb6d773498fb3feda407ed8ef2c3229, 2d882c5586e548d79b
|
||||
</section>
|
||||
<section id="automated-list-sourcing">
|
||||
<h3>Automated List Sourcing<a class="headerlink" href="#automated-list-sourcing" title="Link to this heading">¶</a></h3>
|
||||
<p>Manually blocking identities is effective for immediate threats, but maintaining an up-to-date blocklist for a large network is impractical. Reticulum supports <strong>automated list sourcing</strong>, allowing your node to subscribe to blackhole lists maintained by trusted peers, or a central authority you manage yourself.</p>
|
||||
<p>Manually blocking identities is effective for immediate threats and annoyances, but maintaining an up-to-date blocklist across many nodes on a large network is impractical. Reticulum supports <strong>automated list sourcing</strong>, allowing your node to subscribe to blackhole lists maintained by trusted peers, or a central authority you manage yourself.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p><strong>Verify Before Subscribing!</strong> Subscribing to a blackhole source is a powerful action that grants that source the ability to dictate who you can communicate with. Before adding a source to your configuration, verify that the maintainer aligns with your usage policy and values. Blindly subscribing to untrusted lists could inadvertently block legitimate peers or essential services.</p>
|
||||
@@ -1385,6 +1386,9 @@ remote_management_allowed = 9fb6d773498fb3feda407ed8ef2c3229, 2d882c5586e548d79b
|
||||
<span class="na">...</span>
|
||||
<span class="c1"># Automatically fetch blackhole lists from these trusted sources</span>
|
||||
<span class="na">blackhole_sources</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">521c87a83afb8f29e4455e77930b973b, 68a4aa91ac350c4087564e8a69f84e86</span>
|
||||
|
||||
<span class="c1"># Optional update interval, defaults to one hour</span>
|
||||
<span class="na">blackhole_update_interval</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">60</span>
|
||||
<span class="na">...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
@@ -1635,7 +1639,7 @@ systemctl --user enable rnsd.service
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>What is Reticulum? - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>What is Reticulum? - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -504,7 +505,7 @@ network, and vice versa.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<link rel="prefetch" href="_static/rns_logo_512.png" as="image">
|
||||
|
||||
<!-- Generated with Sphinx 8.2.3 and Furo 2025.09.25.dev1 -->
|
||||
<title>Zen of Reticulum - Reticulum Network Stack 1.2.8 documentation</title>
|
||||
<title>Zen of Reticulum - Reticulum Network Stack 1.3.5 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=d111a655" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?v=580074bf" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||||
@@ -180,7 +180,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.2.8 documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 1.3.5 documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -204,7 +204,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.2.8 documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 1.3.5 documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -222,6 +222,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="distributed.html">Distributed Development</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="git.html">Git Over Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
@@ -398,8 +399,8 @@
|
||||
<p>This is not about “dropping out” of society. It is about building a substrate on which an actual <em>Society</em> can function.</p>
|
||||
<p><strong>Consider:</strong></p>
|
||||
<ul class="simple">
|
||||
<li><p><strong>The Old Way:</strong> “My connection is slow. I should call my ISP and complain.”</p></li>
|
||||
<li><p><strong>The Zen Way:</strong> “The path is noisy. I will adjust the antenna or find a better route.”</p></li>
|
||||
<li><p><strong>The Old Way:</strong> <em>“My connection is slow. I should call my ISP and complain.”</em></p></li>
|
||||
<li><p><strong>The Zen Way:</strong> <em>“The path is noisy. I will adjust the antenna or find a better route.”</em></p></li>
|
||||
</ul>
|
||||
<p>By taking ownership of the infrastructure, you take ownership of your voice. You stop shouting into someone else’s megaphone and start building your own. The network is no longer something that happens to you; it is something you make happen.</p>
|
||||
</section>
|
||||
@@ -676,7 +677,7 @@ Imagine a messaging app. You write it once. It works on a laptop connected to fi
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script src="_static/documentation_options.js?v=4d6f9085"></script>
|
||||
</div><script src="_static/documentation_options.js?v=4720776d"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/scripts/furo.js?v=46bd48cc"></script>
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
# Distributed Development
|
||||
|
||||
This chapter of the manual provides the conceptual basis for understanding *why* `rngit` exists, what it aims to achieve, and the kinds of spaces it seeks to reestablish. For the practical details of operating the system, refer to the [Git Over Reticulum](git.md#git-main) chapter.
|
||||
|
||||
## The Original Architecture
|
||||
|
||||
When Torvalds created Git in 2005, he designed a tool that reflected a specific philosophy of collaboration. Every copy of a repository would be a complete, sovereign instance. There was no central server, no single point of failure, no gatekeeper. Developers would be able to work independently, exchange patches directly, and maintain their own branches indefinitely. This concept was - and is - both beautiful and revolutionary. It’s execution is peer-to-peer not as a marketing term, but in the most foundational sense: As fundamental, structural reality.
|
||||
|
||||
Such a design emerged from necessity. The Linux kernel development process operated across geographical boundaries, time zones, and organizational affiliations. Contributors did not “log in” to a shared server to do their work; they maintained their own trees, and the flow of code between these trees was negotiated through patches, reviews, and merge decisions. The architecture of Git mirrored the social architecture of the community: Autonomous, competent, and fundamentally distributed in its technical operation.
|
||||
|
||||
*The result of that work is, in the most direct sense, what makes it possible for you to read this today.*
|
||||
|
||||
There’s something very important to take note of here: With Git, developers could collaborate effectively and perfectly well without any central server being present, without platform-mediated visibility into each other’s work, and without a centralized authority validating their contributions. They needed *only* a protocol for exchanging differences and a mechanism for verification of authorship. Everything else - social organization, quality control, release management - was handled by careful *human judgment* operating on top of the technical substrate.
|
||||
|
||||
What Git provided was not a development environment, but a **language for versioning**. It specified how to represent history, how to compute differences, how to merge divergent branches. It did not specify who could participate, how they should communicate, or what workflows they should follow. These were left to the competence and discretion of the creators using the system.
|
||||
|
||||
## The Platform Interregnum
|
||||
|
||||
What followed represents a very familiar pattern: Tools designed to distribute power were re-centralized by platforms that offered convenience in exchange for control. GitHub, GitLab, and similar services reintroduced the centralization that Git had eliminated architecturally. The activity feed replaced durable artifacts with ephemeral notifications. The social graph and open interaction became as important as the code itself, if not more.
|
||||
|
||||
This re-centralization was not technical, as such. It was **ontological**. When every developer pushes to the same server, when every merge is in theory controllable by a platform, when every issue is tracked in a database controlled by a corporation, the nature of collaboration changes. The platform, and its social dynamics, becomes the ground of reality. The platform mediates not just the technical exchange of information and the programmatics, but the social recognition and codices of contribution, the future archival prospects of the work, and the very identity of the project itself.
|
||||
|
||||
The consequences extend beyond individual inconvenience. Centralized platforms create single points of failure for entire ecosystem. When a platform changes its terms of service, suspends accounts, removes repositories or ceases operation, entire project histories and community relationships can be disrupted or destroyed. The extractive economics of platform capitalism mean that value created by open-source communities is captured by corporations, while communities remain dependent on infrastructure they do not control. And the surveillance inherent in platform operation means that every action - every commit, every comment, every page view - is logged, analyzed, and potentially monetized or weaponized.
|
||||
|
||||
More insidiously, platforms have completely reshaped the culture of development itself. They have created what we could call the **Teahouse Developer**: A participant who treats engineering projects as social venues for opinion-sharing rather than sites of disciplined and careful production. These personages have no actual stakes in the projects they act as leeches upon, and only a very base consciousness of the damage they are incurring in order to feed their attention and external validation dependencies.
|
||||
|
||||
When platforms optimize for engagement, when growth is the only metric, when every user with an opinion must have their voice heard, when a random social process is elevated to higher importance than results, the signal-to-noise ratio collapses catastrophically. Competent engineers find themselves drowning in feedback from the incompetent, managing the emotional needs and dysregulations of drive-by commentators rather than solving technical problems.
|
||||
|
||||
The platform model is predicated on **unsaturable expansion**. Like almost any industrial system, it cannot function without growth. It pursues no particular aims; it is growth for the sake of growing. There is no saturation point, no concept of “enough”. Every barrier to entry must be put down to the very lowest common denominator, every voice must be amplified, every interaction must be converted into content that feeds the machine. This is fundamentally incompatible with the nature of social beings itself. It is also incompatible with serious engineering, which requires focus, discernment, and the right of people who know better to say “no”.
|
||||
|
||||
## Restoration
|
||||
|
||||
The `rngit` system represents a return to Git’s original architectural principles, fortified with cryptographic networking capabilities that were not available in 2005. The `rngit` system *is* Git - but running over Reticulum. Welcome back to a world where your work is your own, but where everyone can still reach you - if you want them to.
|
||||
|
||||
Just as Git eliminated the need for a central version control server, `rngit` eliminates the need for a central hosting platform, “servers” or any kinds of middle-men between the people actually doing the work. By operating over Reticulum, it eliminates the visibility of development activity to platform operators, network observers, state actors and other malicious third-parties.
|
||||
|
||||
In this model, the repository node is a **sovereign entity**. It is reachable from anywhere in the Reticulum network but owned, operated, and controlled by the developer or community that runs it. It is an actual home for creative output, not an extraction mechanism to which dues are paid. The node operator decides who may contribute, what standards must be met, and which voices are worth listening to. This is not exclusion; it is **discernment**. It is the necessary exercise of judgment that separates engineering from theatrics.
|
||||
|
||||
I did not create this in a fit of nostalgia. I created it because it is a necessary response to the failures of the centralized model. Git’s technical architecture was - and *is* - correct. It was the social and economic superstructure built atop it that introduced fragility, exploitation, and environments toxic to actual creativity. By returning to first principles - distributed version control on distributed infrastructure - we recover not just a technical capability, but a mode of collaboration that respects the autonomy of individual developers and the sovereignty of actual communities.
|
||||
|
||||
## Protocols Over Platforms
|
||||
|
||||
The distinction between platforms and protocols is fundamental to understanding the architecture of sovereignty in networked systems. A platform is a service you access; a protocol is a grammar you speak; actions you live. A platform requires permission to enter, a protocol requires only *comprehension* to employ. A platform can change its rules, suspend your account, or cease operation entirely, a protocol persists as long as there are participants who *understand* and *use* it. A protocol is an *idea*, a platform is a machine that turns its users into products.
|
||||
|
||||
Platforms operate on a client-server model that inherently creates power asymmetry. Even when platforms are built atop open-source software, the operational instance remains a black box of corporate control. You *may* be able to download *some* of your data, but you cannot download the connections to the people that are the true value-base of the platform, or take them with you if you want to leave.
|
||||
|
||||
Protocols, by contrast, are agreements. They specify how systems should communicate, but not who may communicate or on what terms. Email is a protocol; Gmail is a platform. HTTP is a protocol; Facebook is a platform. Git is a protocol; GitHub is a platform. The protocol persists regardless of any particular implementation’s success or failure.
|
||||
|
||||
The power of protocols lies in their **permissionlessness**. Anyone can implement a protocol without approval. Anyone can extend it, fork it, or use it for purposes unforeseen by its creators. This creates resilience: protocols cannot be easily censored, monopolized, or shut down because they exist as shared understanding rather than centralized infrastructure.
|
||||
|
||||
Reticulum is a protocol in this strict sense. It specifies how packets should be formatted, how paths should be discovered, how encryption should be applied. The `rngit` system extends this protocol approach to development workflows. It is not an external platform that hosts your repositories; it is a protocol for exchanging repository data, release artifacts, and work documents over Reticulum’s encrypted transport. But with a few commands and an old computer, it creates your own infrastructure for hosting repositories, or sharing them with who you choose. *That* is how tools should function, in case we had forgotten.
|
||||
|
||||
Unlike platforms, which extract value by creating dependency, there is no entity that can grant or deny you the privilege of running `rngit`. Your Reticulum identity is not endowed by any platform; it is generated locally and certified by its own cryptographic properties. Your repositories are hosted on nodes you control or nodes operated by communities you trust. Your relationships with other developers are peer-to-peer connections established through cryptographic addressing, not social graph connections managed by recommendation algorithms.
|
||||
|
||||
On a platform, exit means abandonment: you lose your history, your relationships, your visibility. With protocols, exit is just migration. When you change your infrastructure, your identity and your work travel with you. There are no middlemen between you and your collaborators. If push comes to shove, you can write your entire life’s work and connections to an SD card, swim across the lake, and set up camp on the other side.
|
||||
|
||||
## Sovereignty Through Infrastructure
|
||||
|
||||
The concept of sovereignty - supreme authority within a territory - has traditionally been applied to nation-states. But in an age where creative work is conducted through digital infrastructure, sovereignty is essential for individuals and communities. **Creative sovereignty** means having supreme authority over the artifacts you produce, the processes by which you produce them, and the terms under which they are distributed. It means not merely legal ownership of copyright, but operational control of the infrastructure that mediates creation, collaboration, and dissemination.
|
||||
|
||||
Centralized development platforms strip away most layers of sovereignty. When you host code on a corporate platform, you retain *some* legal ownership of copyright, but you surrender complete operational control. The platform decides what content is acceptable, who can access it, and how it is presented. They can delete your repository, suspend your account, or change the visibility of your work without consent. In reality, legal ownership becomes meaningless as operational control is ceded.
|
||||
|
||||
Running your own `rngit` node restores this sovereignty. You control the hardware, the network configuration, the backup strategies, and the access permissions. You decide what constitutes acceptable use, who may contribute, and how contributions are evaluated. Taking this responsibility on yourself is an assertion that your creative work is not a product to be harvested by platform economics, but an autonomous activity to be conducted on your own terms.
|
||||
|
||||
This sovereignty and responsibility extends to the entry barriers you establish. The `rngit` system allows you to configure access controls that filter participants based on cryptographic identity and demonstrated competence. If, for example, someone cannot navigate a command line, or use Reticulum to submit a patch, they most likely lack the required competence to modify your code. In a world that apparently labels this as “exclusion”, I would simply refer to it as a minimally acceptable level of quality control.
|
||||
|
||||
Such a stance protects projects from the noise that so often overwhelms and completely dilutes platform-based development, where every user with an opinion believes themselves entitled to attention and access to the decision process.
|
||||
|
||||
## Artifact-Centered Workflows
|
||||
|
||||
Contemporary platform-based development has shifted focus from durable artifacts to ephemeral *activity*. It does not matter what constitutes this activity, as long as it’s there. The primary interface is not the repository itself, not the produced artifacts, but the activity feed: *Notifications* of commits, comments, pull requests, and social interactions. Work is measured by velocity, throughput, and the constant stream of updates. This activity-centric model creates constant urgency, discourages discernment, encourages reactive rather than reflective work patterns, and produces vast quantities of ephemeral and useless communication that obscures actual project state and productivity.
|
||||
|
||||
The `rngit` system enables a return to **artifact-centered workflows**, where the focus is on durable, attributable, versioned outputs rather than the stream of notifications surrounding them. The fundamental unit of work is the commit - signed, immutable records of change. The fundamental unit of production is the signed artifact - a self-verifying package of functionality. The fundamental unit of discussion is the work document - a structured, threaded conversation attached to repositories.
|
||||
|
||||
Artifacts can persist independently of any platform’s continued operation. A commit signed with your Reticulum identity is attributable to you regardless of where it is stored. A release signed with your private key is verifiable as authentic regardless of which network it traverses, and can be verified offline on any system running Reticulum. The work exists as **cryptographic fact**, distributed over the planet, not as database entries in a corporate cloud.
|
||||
|
||||
Such a shift has real psychological consequences. When work is measured in artifacts rather than activity, the pace changes. There is no need for constant visibility, no pressure to perform busyness. Developers can work deeply, reflectively, and submit complete solutions rather than incremental updates designed to maintain presence in an activity feed. The work becomes **substantial**, in the physical sense of the word, rather than performative.
|
||||
|
||||
## Composable Primitives
|
||||
|
||||
The `rngit` system is not a monolithic application prescribing a specific workflow; it is a collection of **composable primitives** that can be arranged to support diverse creative processes. Understanding these primitives as separate, orthogonal capabilities enables users to construct workflows suited to their specific needs and to recombine these primitives in ways unforeseen by the system’s designers.
|
||||
|
||||
The core primitives include:
|
||||
|
||||
* **Repository Hosting**: Bare Git repositories served over Reticulum links, accessible via standard Git commands through the `rns://` URL scheme.
|
||||
|
||||
* **Identity-Based Access Control**: Fine-grained permissions managed through cryptographically verifiable identity hashes, configurable at the group, repository, or document level.
|
||||
|
||||
* **Release Distribution**: Cryptographically signed release artifacts with embedded provenance information, verifiable offline and distributable through any Reticulum or physical path.
|
||||
|
||||
* **Work Document Tracking**: Structured, threaded work management attached to repositories, with precise permission controls, and the ability to contain updates or discussions.
|
||||
|
||||
* **Forking and Mirroring**: Automated replication of repositories from any accessible Git URL, with metadata tracking upstream relationships for synchronization.
|
||||
|
||||
* **Nomad Network Integration**: Page node functionality for browsing repository contents, commit history, and release information through the Nomad Network protocol.
|
||||
|
||||
These primitives can be composed into workflows ranging from single-developer projects to complex multi-organizational collaborations. A solo developer might use only repository hosting and release distribution. A research group might add work document tracking for structured peer review. A software distribution network might combine mirroring with cryptographic release verification to create resilient update channels.
|
||||
|
||||
The entire system is incredibly light-weight, and can host hundreds of repositories on a Raspberry Pi.
|
||||
|
||||
Composability is essential because **creative work is diverse**. Software development, academic research, technical writing, hardware design, music production and data analysis all have different requirements for collaboration, review, and distribution. A platform prescribes a single workflow and forces all users to conform. A protocol provides primitives and allows users to construct workflows appropriate to their domain.
|
||||
|
||||
With `rngit`, you can re-build the system into anything you can imagine. Everything can be modified, extended and hooked into. Adding functionality or automation is never further away than a shell script, a cron-job, or a Python modification of the source.
|
||||
|
||||
## Distribution Without Intermediaries
|
||||
|
||||
Creating software is only part of the work. Then comes actually getting it to the people needing to use it. Centralized platforms handle distribution through their own infrastructure: Content delivery networks, central package registries, and download servers accessed through platform-controlled interfaces. This convenience masks a fundamental dependency: Your ability to distribute depends on the platform’s continued operation, their policies regarding your content, and their technical infrastructure’s reach.
|
||||
|
||||
The `rngit` release system enables distribution strategies **decoupled from any single infrastructure provider**. Releases are cryptographically signed using Ed25519 signatures and packaged in signed release manifests (`.rsm` files). These manifests contain embedded signatures for each artifact. The manifest provides full verifiability of all release information, and contains embedded release artifact lists, per-file `.rsg` signatures, origin information, and the creator’s Reticulum Identity. It can also be used to fetch verified updates of the software package over the network, and can always be verified completely offline.
|
||||
|
||||
Because releases are self-verifying, they can traverse any network or physical path that Reticulum can establish. A release can travel over LoRa radio, be carried on USB drives through areas without internet connectivity, disseminated over a mirror network, or be distributed through store-and-forward mechanisms on intermittent infrastructure. Recipients can verify authenticity regardless of how they obtained the files. This is particularly valuable in low-connectivity environments where Reticulum may be the only available communication channel.
|
||||
|
||||
The `rngit release` command provides tools for creating, publishing, fetching, and verifying releases. When fetching a release using an `.rsm` manifest, the system validates the manifest signature against the required Reticulum Identity, extracts the origin node and repository path, connects to the origin over Reticulum, retrieves the latest release manifest, and verifies each downloaded artifact against the signatures embedded in the manifest. If any verification fails, the fetch aborts, preventing installation of corrupted or tampered files.
|
||||
|
||||
This cryptographic verification replaces the trust model of platform distribution. Instead of trusting that a platform has not been compromised, users verify that artifacts match the signatures created by the developer’s identity. It doesn’t matter *how* they obtained the artifacts, they can **always** be verified. This security model shifts from **institutional trust** (just believe in the goodness of the platform) to **cryptographic proof** (verify the signatures).
|
||||
|
||||
## Long Archive
|
||||
|
||||
Software development is often conceived as an activity of the present only: Solving today’s problems, meeting current deadlines, responding to immediate feedback. But the artifacts produced - code, documentation, releases - have lifespans extending *far* beyond their creation. They may be used for decades, studied by future developers, depended upon by systems not yet imagined, or preserved as historical records of technological development.
|
||||
|
||||
The `rngit` system is designed with this **extended timeframe** in mind, supporting the creation of archives that are durable, portable, and intelligible across generational timescales. Git repositories are always internally complete; they contain full history and can be migrated to new infrastructure without loss of information. Everything that `rngit` adds on top of this is stored in normal files in standard formats right next to the Git repository folders, not an esoteric database-cluster two thousand kilometers away. Because releases are cryptographically signed, they remain verifiable as authentic regardless of when or where they are retrieved. Because the system operates over Reticulum, it can function over communication mediums that may outlast the internet as we know it.
|
||||
|
||||
This long-term perspective influences technical decisions. The use of well-established cryptographic primitives ensures that signatures will remain verifiable for centuries. The use of standard formats ensures that repositories will remain readable by future tools. The protocol-based architecture ensures that the system can evolve without losing compatibility with existing data.
|
||||
|
||||
For critical infrastructure, this archival durability is not optional; it is essential. Communication systems, cryptographic libraries, and safety-critical code must remain available and verifiable for the lifespans of the systems that depend on them. The `rngit` system provides the tools to create such archives: distributed across multiple nodes, cryptographically verified, and independent of any corporate or governmental infrastructure, which as history has shown repeatedly, does *not* persist.
|
||||
|
||||
## Start Of The Road
|
||||
|
||||
Distributed development and production over Reticulum is a *different mode of existence* for creative work. It restores the autonomy originally created by Git. It provides local sovereignty over production infrastructure, composability of workflow, and durability of artifact. It lets you filter participation through competence and cryptography rather than incentives of platform operators, raising the quality and enjoyment of work, and protecting the focus of real engineering and creative expression.
|
||||
|
||||
This is not a system for everyone, and that is the point. It requires investment - in understanding Reticulum, in configuring infrastructure, in establishing workflows. It requires accepting responsibility for your own tools rather than delegating them to platform operators. It requires the discipline to maintain your own node, manage your own backups, and nurture your own community.
|
||||
|
||||
But for those who make this investment, the returns are substantial. You gain **immunity from platform failure**; your work persists regardless of corporate decisions or service outages. You gain **shelter from surveillance**; your development activity is visible only to those that *you* choose to involve. You gain **control over process**; you decide how work is conducted, reviewed, and released, unmediated by terms of service, algorithmic feeds and thousands of uninformed and irrelevant opinions.
|
||||
|
||||
Most importantly, though, you regain the **dignity of craft**. Development becomes an activity conducted among peers, equals among equals, mediated by skill and cryptographic proof rather than corporate permission, producing artifacts that stand as independent testimony to competence, functionality or beauty rather than as content feeding engagement metrics. The *work* becomes the point. The artifacts become durable. And the network becomes *one* of the tools you wield in this endeavor.
|
||||
+11
-57
@@ -1,14 +1,10 @@
|
||||
# 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 number of examples are included in the source distribution of Reticulum. You can use these examples to learn how to write your own programs.
|
||||
|
||||
## Minimal
|
||||
|
||||
The *Minimal* example demonstrates the bare-minimum setup required to connect to
|
||||
a Reticulum network from your program. In about five lines of code, you will
|
||||
have the Reticulum Network Stack initialised, and ready to pass traffic in your
|
||||
program.
|
||||
The *Minimal* example demonstrates the bare-minimum setup required to connect to a Reticulum network from your program. In about five lines of code, you will have the Reticulum Network Stack initialised, and ready to pass traffic in your program.
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -61,7 +57,6 @@ def program_setup(configpath):
|
||||
# Let's hand over control to the announce loop
|
||||
announceLoop(destination)
|
||||
|
||||
|
||||
def announceLoop(destination):
|
||||
# Let the user know that everything is ready
|
||||
RNS.log(
|
||||
@@ -79,7 +74,6 @@ def announceLoop(destination):
|
||||
destination.announce()
|
||||
RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash))
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Program Startup #####################################
|
||||
##########################################################
|
||||
@@ -119,9 +113,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Announce
|
||||
|
||||
The *Announce* example builds upon the previous example by exploring how to
|
||||
announce a destination on the network, and how to let your program receive
|
||||
notifications about announces from relevant destinations.
|
||||
The *Announce* example builds upon the previous example by exploring how to announce a destination on the network, and how to let your program receive notifications about announces from relevant destinations.
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -202,7 +194,6 @@ def program_setup(configpath):
|
||||
# Let's hand over control to the announce loop
|
||||
announceLoop(destination_1, destination_2)
|
||||
|
||||
|
||||
def announceLoop(destination_1, destination_2):
|
||||
# Let the user know that everything is ready
|
||||
RNS.log("Announce example running, hit enter to manually send an announce (Ctrl-C to quit)")
|
||||
@@ -302,8 +293,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Broadcast
|
||||
|
||||
The *Broadcast* example explores how to transmit plaintext broadcast messages
|
||||
over the network.
|
||||
The *Broadcast* example explores how to transmit plaintext broadcast messages over the network.
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -380,7 +370,6 @@ def broadcastLoop(destination):
|
||||
packet.send()
|
||||
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Program Startup #####################################
|
||||
##########################################################
|
||||
@@ -433,8 +422,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Echo
|
||||
|
||||
The *Echo* example demonstrates communication between two destinations using
|
||||
the Packet interface.
|
||||
The *Echo* example demonstrates communication between two destinations using the Packet interface.
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -454,7 +442,6 @@ import RNS
|
||||
# them all within the app namespace "example_utilities"
|
||||
APP_NAME = "example_utilities"
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Server Part #########################################
|
||||
##########################################################
|
||||
@@ -500,7 +487,6 @@ def server(configpath):
|
||||
# Let's Wait for client requests or user input
|
||||
announceLoop(echo_destination)
|
||||
|
||||
|
||||
def announceLoop(destination):
|
||||
# Let the user know that everything is ready
|
||||
RNS.log(
|
||||
@@ -518,7 +504,6 @@ def announceLoop(destination):
|
||||
destination.announce()
|
||||
RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash))
|
||||
|
||||
|
||||
def server_callback(message, packet):
|
||||
global reticulum
|
||||
|
||||
@@ -547,7 +532,6 @@ def server_callback(message, packet):
|
||||
|
||||
RNS.log("Received packet from echo client, proof sent"+reception_stats)
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Client Part #########################################
|
||||
##########################################################
|
||||
@@ -698,7 +682,6 @@ def packet_timed_out(receipt):
|
||||
if receipt.status == RNS.PacketReceipt.FAILED:
|
||||
RNS.log("Packet "+RNS.prettyhexrep(receipt.hash)+" timed out")
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Program Startup #####################################
|
||||
##########################################################
|
||||
@@ -775,8 +758,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Link
|
||||
|
||||
The *Link* example explores establishing an encrypted link to a remote
|
||||
destination, and passing traffic back and forth over the link.
|
||||
The *Link* example explores establishing an encrypted link to a remote destination, and passing traffic back and forth over the link.
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -877,7 +859,6 @@ def server_packet_received(message, packet):
|
||||
reply_data = reply_text.encode("utf-8")
|
||||
RNS.Packet(latest_client_link, reply_data).send()
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Client Part #########################################
|
||||
##########################################################
|
||||
@@ -1014,7 +995,6 @@ def client_packet_received(message, packet):
|
||||
print("> ", end=" ")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Program Startup #####################################
|
||||
##########################################################
|
||||
@@ -1075,8 +1055,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Identification
|
||||
|
||||
The *Identify* example explores identifying an intiator of a link, once
|
||||
the link has been established.
|
||||
The *Identify* example explores identifying an intiator of a link, once the link has been established.
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -1187,7 +1166,6 @@ def server_packet_received(message, packet):
|
||||
reply_data = reply_text.encode("utf-8")
|
||||
RNS.Packet(latest_client_link, reply_data).send()
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Client Part #########################################
|
||||
##########################################################
|
||||
@@ -1337,7 +1315,6 @@ def client_packet_received(message, packet):
|
||||
print("> ", end=" ")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Program Startup #####################################
|
||||
##########################################################
|
||||
@@ -1499,7 +1476,6 @@ def client_connected(link):
|
||||
def client_disconnected(link):
|
||||
RNS.log("Client disconnected")
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Client Part #########################################
|
||||
##########################################################
|
||||
@@ -1588,7 +1564,6 @@ def client_loop():
|
||||
failed_callback = request_failed
|
||||
)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Error while sending request over the link: "+str(e))
|
||||
should_quit = True
|
||||
@@ -1606,7 +1581,6 @@ def request_received(request_receipt):
|
||||
def request_failed(request_receipt):
|
||||
RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" failed.")
|
||||
|
||||
|
||||
# This function is called when a link
|
||||
# has been established with the server
|
||||
def link_established(link):
|
||||
@@ -1632,7 +1606,6 @@ def link_closed(link):
|
||||
time.sleep(1.5)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Program Startup #####################################
|
||||
##########################################################
|
||||
@@ -1693,8 +1666,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Channel
|
||||
|
||||
The *Channel* example explores using a `Channel` to send structured
|
||||
data between peers of a `Link`.
|
||||
The *Channel* example explores using a `Channel` to send structured data between peers of a `Link`.
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -1784,7 +1756,6 @@ class StringMessage(RNS.MessageBase):
|
||||
def unpack(self, raw):
|
||||
self.data, self.timestamp = umsgpack.unpackb(raw)
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Server Part #########################################
|
||||
##########################################################
|
||||
@@ -1888,7 +1859,6 @@ def server_message_received(message):
|
||||
# handlers are skipped.
|
||||
return True
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Client Part #########################################
|
||||
##########################################################
|
||||
@@ -2031,7 +2001,6 @@ def client_message_received(message):
|
||||
print("> ", end=" ")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Program Startup #####################################
|
||||
##########################################################
|
||||
@@ -2092,8 +2061,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Buffer
|
||||
|
||||
The *Buffer* example explores using buffered readers and writers to send
|
||||
binary data between peers of a `Link`.
|
||||
The *Buffer* example explores using buffered readers and writers to send binary data between peers of a `Link`.
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -2117,7 +2085,6 @@ from RNS.vendor import umsgpack
|
||||
# them all within the app namespace "example_utilities"
|
||||
APP_NAME = "example_utilities"
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Server Part #########################################
|
||||
##########################################################
|
||||
@@ -2190,7 +2157,6 @@ def client_connected(link):
|
||||
if latest_buffer:
|
||||
latest_buffer.close()
|
||||
|
||||
|
||||
# Create buffer objects.
|
||||
# The stream_id parameter to these functions is
|
||||
# a bit like a file descriptor, except that it
|
||||
@@ -2227,7 +2193,6 @@ def server_buffer_ready(ready_bytes: int):
|
||||
|
||||
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Client Part #########################################
|
||||
##########################################################
|
||||
@@ -2319,7 +2284,6 @@ def client_loop():
|
||||
# Flush the buffer to force the data to be sent.
|
||||
buffer.flush()
|
||||
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Error while sending data over the link buffer: "+str(e))
|
||||
should_quit = True
|
||||
@@ -2363,7 +2327,6 @@ def client_buffer_ready(ready_bytes: int):
|
||||
print("> ", end=" ")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Program Startup #####################################
|
||||
##########################################################
|
||||
@@ -2424,9 +2387,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Filetransfer
|
||||
|
||||
The *Filetransfer* example implements a basic file-server program that
|
||||
allow clients to connect and download files. The program uses the Resource
|
||||
interface to efficiently pass files of any size over a Reticulum [Link](reference.md#api-link).
|
||||
The *Filetransfer* example implements a basic file-server program that allow clients to connect and download files. The program uses the Resource interface to efficiently pass files of any size over a Reticulum [Link](reference.md#api-link).
|
||||
|
||||
```default
|
||||
##########################################################
|
||||
@@ -2639,7 +2600,6 @@ download_time = 0
|
||||
transfer_size = 0
|
||||
file_size = 0
|
||||
|
||||
|
||||
# This initialisation is executed when the users chooses
|
||||
# to run as a client
|
||||
def client(destination_hexhash, configpath):
|
||||
@@ -2660,7 +2620,6 @@ def client(destination_hexhash, configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Check if we know a path to the destination
|
||||
if not RNS.Transport.has_path(destination_hash):
|
||||
RNS.log("Destination is not yet known. Requesting path and waiting for announce to arrive...")
|
||||
@@ -2895,7 +2854,6 @@ def filelist_timeout_job():
|
||||
RNS.log("Timed out waiting for filelist, exiting")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# When a link is closed, we'll inform the
|
||||
# user, and exit the program
|
||||
def link_closed(link):
|
||||
@@ -3038,10 +2996,7 @@ This example can also be found at [https://github.com/markqvist/Reticulum/blob/m
|
||||
|
||||
## Custom Interfaces
|
||||
|
||||
The *ExampleInterface* demonstrates creating custom interfaces for Reticulum.
|
||||
Any number of custom interfaces can be loaded and utilised by Reticulum, and
|
||||
will be fully on-par with natively included interfaces, including all supported
|
||||
[interface modes](interfaces.md#interfaces-modes) and [common configuration options](interfaces.md#interfaces-options).
|
||||
The *ExampleInterface* demonstrates creating custom interfaces for Reticulum. Any number of custom interfaces can be loaded and utilised by Reticulum, and will be fully on-par with natively included interfaces, including all supported [interface modes](interfaces.md#interfaces-modes) and [common configuration options](interfaces.md#interfaces-options).
|
||||
|
||||
```default
|
||||
# This example illustrates creating a custom interface
|
||||
@@ -3226,7 +3181,6 @@ class ExampleInterface(Interface):
|
||||
self.online = True
|
||||
RNS.log("Serial port "+self.port+" is now open", RNS.LOG_VERBOSE)
|
||||
|
||||
|
||||
# This method will be called from our read-loop
|
||||
# whenever a full packet has been received over
|
||||
# the underlying medium.
|
||||
|
||||
@@ -1,49 +1,36 @@
|
||||
# Getting Started Fast
|
||||
|
||||
The best way to get started with the Reticulum Network Stack depends on what
|
||||
you want to do. This guide will outline sensible starting paths for different
|
||||
scenarios.
|
||||
The best way to get started with the Reticulum Network Stack depends on what you want to do. This guide will outline sensible starting paths for different scenarios.
|
||||
|
||||
## Standalone Reticulum Installation
|
||||
|
||||
If you simply want to install Reticulum and related utilities on a system,
|
||||
the easiest way is via the `pip` package manager:
|
||||
If you simply want to install Reticulum and related utilities on a system, the easiest way is via the `pip` package manager:
|
||||
|
||||
```shell
|
||||
pip install rns
|
||||
```
|
||||
|
||||
If you do not already have pip installed, you can install it using the package manager
|
||||
of your system with a command like `sudo apt install python3-pip`,
|
||||
`sudo pamac install python-pip` or similar.
|
||||
If you do not already have pip installed, you can install it using the package manager of your system with a command like `sudo apt install python3-pip`, `sudo pamac install python-pip` or similar.
|
||||
|
||||
You can also dowload the Reticulum release wheels from GitHub, or other release channels,
|
||||
and install them offline using `pip`:
|
||||
You can also dowload the Reticulum release wheels from GitHub, or other release channels, and install them offline using `pip`:
|
||||
|
||||
```shell
|
||||
pip install ./rns-1.1.2-py3-none-any.whl
|
||||
```
|
||||
|
||||
On platforms that limit user package installation via `pip`, you may need to manually
|
||||
allow this using the `--break-system-packages` command line flag when installing. This
|
||||
will not actually break any packages, unless you have installed Reticulum directly via
|
||||
your operating system’s package manager.
|
||||
On platforms that limit user package installation via `pip`, you may need to manually allow this using the `--break-system-packages` command line flag when installing. This will not actually break any packages, unless you have installed Reticulum directly via your operating system’s package manager.
|
||||
|
||||
```shell
|
||||
pip install rns --break-system-packages
|
||||
```
|
||||
|
||||
For more detailed installation instructions, please see the
|
||||
[Platform-Specific Install Notes](#install-guides) section.
|
||||
For more detailed installation instructions, please see the [Platform-Specific Install Notes](#install-guides) section.
|
||||
|
||||
After installation is complete, it might be helpful to refer to the
|
||||
[Using Reticulum on Your System](using.md#using-main) chapter.
|
||||
After installation is complete, it might be helpful to refer to the [Using Reticulum on Your System](using.md#using-main) chapter.
|
||||
|
||||
### Resolving Dependency & Installation Issues
|
||||
|
||||
On some platforms, there may not be binary packages available for all dependencies, and
|
||||
`pip` installation may fail with an error message. In these cases, the issue can usually
|
||||
be resolved by installing the development essentials packages for your platform:
|
||||
On some platforms, there may not be binary packages available for all dependencies, and `pip` installation may fail with an error message. In these cases, the issue can usually be resolved by installing the development essentials packages for your platform:
|
||||
|
||||
```shell
|
||||
# Debian / Ubuntu / Derivatives
|
||||
@@ -56,66 +43,35 @@ sudo pamac install base-devel
|
||||
sudo dnf groupinstall "Development Tools" "Development Libraries"
|
||||
```
|
||||
|
||||
With the base development packages installed, `pip` should be able to compile any missing
|
||||
dependencies from source, and complete installation even on platforms that don’t have pre-
|
||||
compiled packages available.
|
||||
With the base development packages installed, `pip` should be able to compile any missing dependencies from source, and complete installation even on platforms that don’t have pre-compiled packages available.
|
||||
|
||||
## Try Using a Reticulum-based Program
|
||||
|
||||
If you simply want to try using a program built with Reticulum, a [range of different
|
||||
programs](software.md#software-main) exist that allow basic communication and a various other useful functions,
|
||||
even over extremely low-bandwidth Reticulum networks.
|
||||
If you simply want to try using a program built with Reticulum, a [range of different programs](software.md#software-main) exist that allow basic communication and a various other useful functions, even over extremely low-bandwidth Reticulum networks.
|
||||
|
||||
## Using the Included Utilities
|
||||
|
||||
Reticulum comes with a range of included utilities that make it easier to
|
||||
manage your network, check connectivity and make Reticulum available to other
|
||||
programs on your system.
|
||||
Reticulum comes with a range of included utilities that make it easier to manage your network, check connectivity and make Reticulum available to other programs on your system.
|
||||
|
||||
You can use `rnsd` to run Reticulum as a background or foreground service,
|
||||
and the `rnstatus`, `rnpath` and `rnprobe` utilities to view and query
|
||||
network status and connectivity.
|
||||
You can use `rnsd` to run Reticulum as a background or foreground service, and the `rnstatus`, `rnpath` and `rnprobe` utilities to view and query network status and connectivity.
|
||||
|
||||
To learn more about these utility programs, have a look at the
|
||||
[Using Reticulum on Your System](using.md#using-main) chapter of this manual.
|
||||
To learn more about these utility programs, have a look at the [Using Reticulum on Your System](using.md#using-main) chapter of this manual.
|
||||
|
||||
## Creating a Network With Reticulum
|
||||
|
||||
To create a network, you will need to specify one or more *interfaces* for
|
||||
Reticulum to use. This is done in the Reticulum configuration file, which by
|
||||
default is located at `~/.reticulum/config`. You can get an example
|
||||
configuration file with all options via `rnsd --exampleconfig`.
|
||||
To create a network, you will need to specify one or more *interfaces* for Reticulum to use. This is done in the Reticulum configuration file, which by default is located at `~/.reticulum/config`. You can get an example configuration file with all options via `rnsd --exampleconfig`.
|
||||
|
||||
When Reticulum is started for the first time, it will create a default
|
||||
configuration file, with one active interface. This default interface uses
|
||||
your existing Ethernet and WiFi networks (if any), and only allows you to
|
||||
communicate with other Reticulum peers within your local broadcast domains.
|
||||
When Reticulum is started for the first time, it will create a default configuration file, with one active interface. This default interface uses your existing Ethernet and WiFi networks (if any), and only allows you to communicate with other Reticulum peers within your local broadcast domains.
|
||||
|
||||
To communicate further, you will have to add one or more interfaces. The default
|
||||
configuration includes a number of examples, ranging from using TCP over the
|
||||
internet, to LoRa and Packet Radio interfaces.
|
||||
To communicate further, you will have to add one or more interfaces. The default configuration includes a number of examples, ranging from using TCP over the internet, to LoRa and Packet Radio interfaces.
|
||||
|
||||
With Reticulum, you only need to configure what interfaces you want to communicate
|
||||
over. There is no need to configure address spaces, subnets, routing tables,
|
||||
or other things you might be used to from other network types.
|
||||
With Reticulum, you only need to configure what interfaces you want to communicate over. There is no need to configure address spaces, subnets, routing tables, or other things you might be used to from other network types.
|
||||
|
||||
Once Reticulum knows which interfaces it should use, it will automatically
|
||||
discover topography and configure transport of data to any destinations it
|
||||
knows about.
|
||||
Once Reticulum knows which interfaces it should use, it will automatically discover topography and configure transport of data to any destinations it knows about.
|
||||
|
||||
In situations where you already have an established WiFi or Ethernet network, and
|
||||
many devices that want to utilise the same external Reticulum network paths (for example over
|
||||
LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by
|
||||
adding any external interfaces to the configuration of this system, and then enabling transport on it. Any
|
||||
other device on your local WiFi will then be able to connect to this wider Reticulum
|
||||
network just using the default ([AutoInterface](interfaces.md#interfaces-auto)) configuration.
|
||||
In situations where you already have an established WiFi or Ethernet network, and many devices that want to utilise the same external Reticulum network paths (for example over LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by adding any external interfaces to the configuration of this system, and then enabling transport on it. Any other device on your local WiFi will then be able to connect to this wider Reticulum network just using the default ([AutoInterface](interfaces.md#interfaces-auto)) configuration.
|
||||
|
||||
Possibly, the examples in the config file are enough to get you started. If
|
||||
you want more information, you can read the [Building Networks](networks.md#networks-main)
|
||||
and [Interfaces](interfaces.md#interfaces-main) chapters of this manual, but most importantly,
|
||||
start with reading the next section, [Bootstrapping Connectivity](#bootstrapping-connectivity),
|
||||
as this provides the most essential understanding of how to ensure reliable
|
||||
connectivity with a minimum of maintenance.
|
||||
Possibly, the examples in the config file are enough to get you started. If you want more information, you can read the [Building Networks](networks.md#networks-main) and [Interfaces](interfaces.md#interfaces-main) chapters of this manual, but most importantly, start with reading the next section, [Bootstrapping Connectivity](#bootstrapping-connectivity), as this provides the most essential understanding of how to ensure reliable connectivity with a minimum of maintenance.
|
||||
|
||||
## Bootstrapping Connectivity
|
||||
|
||||
@@ -161,7 +117,9 @@ We strongly encourage everyone, even home users, to think in terms of building *
|
||||
There is no requirement to commit to a single strategy. The most robust setups often mix static, dynamic, and discovered interfaces.
|
||||
|
||||
* **Static Interfaces:** You maintain a permanent interface to a trusted friend or organization using a static configuration.
|
||||
|
||||
* **Bootstrap Links:** You connect a `bootstrap_only` interface to a public gateway on the Internet to scan for new connectable peers or to regain connectivity if your other interfaces fail.
|
||||
|
||||
* **Local Wide-Area Connectivity:** You run a `RNodeInterface` on a shared frequency, giving you completely self-sovereign and private wide-area access to both your own network and other Reticulum peers globally, without any “service providers” being able to control or monitor how you interact with people.
|
||||
|
||||
By combining these methods, you create a system that is secure against single points of failure, adaptable to changing network conditions, and better integrated into your physical and social reality.
|
||||
@@ -186,20 +144,13 @@ As a good starting point, you can find interface definitions for connecting your
|
||||
|
||||
## 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
|
||||
Internet. This section offers some helpful pointers. Once you have set up your public entrypoint, it is a great idea to [make it discoverable over Reticulum](interfaces.md#interfaces-discoverable).
|
||||
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 Internet. This section offers some helpful pointers. Once you have set up your public entrypoint, it is a great idea to [make it discoverable over Reticulum](interfaces.md#interfaces-discoverable).
|
||||
|
||||
You will need a machine, physical or virtual with a public IP address, that can be reached by other devices on the Internet.
|
||||
|
||||
The most efficient and performant way to host a connectable entry-point supporting many
|
||||
users is to use the `BackboneInterface`. This interface type is fully compatible with
|
||||
the `TCPClientInterface` and `TCPServerInterface` types, but much faster and uses
|
||||
less system resources, allowing your device to handle thousands of connections even on
|
||||
small systems.
|
||||
The most efficient and performant way to host a connectable entry-point supporting many users is to use the `BackboneInterface`. This interface type is fully compatible with the `TCPClientInterface` and `TCPServerInterface` types, but much faster and uses less system resources, allowing your device to handle thousands of connections even on small systems.
|
||||
|
||||
It is also important to set your connectable interface to `gateway` mode, since this
|
||||
will greatly improve network convergence time and path resolution for anyone connecting
|
||||
to your entry-point.
|
||||
It is also important to set your connectable interface to `gateway` mode, since this will greatly improve network convergence time and path resolution for anyone connecting to your entry-point.
|
||||
|
||||
```ini
|
||||
# This example demonstrates a backbone interface
|
||||
@@ -221,8 +172,7 @@ to your entry-point.
|
||||
announce_rate_grace = 6
|
||||
```
|
||||
|
||||
If instead you want to make a private entry-point from the Internet, you can use the
|
||||
[IFAC name and passphrase options](interfaces.md#interfaces-options) to secure your interface with a network name and passphrase.
|
||||
If instead you want to make a private entry-point from the Internet, you can use the [IFAC name and passphrase options](interfaces.md#interfaces-options) to secure your interface with a network name and passphrase.
|
||||
|
||||
```ini
|
||||
# A private entry-point requiring a pre-shared
|
||||
@@ -238,124 +188,71 @@ If instead you want to make a private entry-point from the Internet, you can use
|
||||
passphrase = 2owjajquafIanPecAc
|
||||
```
|
||||
|
||||
If you are hosting an entry-point on an operating system that does not support
|
||||
`BackboneInterface`, you can use `TCPServerInterface` instead, although it will
|
||||
not be as performant.
|
||||
If you are hosting an entry-point on an operating system that does not support `BackboneInterface`, you can use `TCPServerInterface` instead, although it will not be as performant.
|
||||
|
||||
## Connecting Reticulum Instances Over the Internet
|
||||
|
||||
Reticulum currently offers three interfaces suitable for connecting instances over the Internet: [Backbone](interfaces.md#interfaces-backbone), [TCP](interfaces.md#interfaces-tcps)
|
||||
and [I2P](interfaces.md#interfaces-i2p). Each interface offers a different set of features, and Reticulum
|
||||
users should carefully choose the interface which best suites their needs.
|
||||
Reticulum currently offers three interfaces suitable for connecting instances over the Internet: [Backbone](interfaces.md#interfaces-backbone), [TCP](interfaces.md#interfaces-tcps) and [I2P](interfaces.md#interfaces-i2p). Each interface offers a different set of features, and Reticulum users should carefully choose the interface which best suites their needs.
|
||||
|
||||
The `TCPServerInterface` allows users to host an instance accessible over TCP/IP. This
|
||||
method is generally faster, lower latency, and more energy efficient than using `I2PInterface`,
|
||||
however it also leaks more data about the server host.
|
||||
The `TCPServerInterface` allows users to host an instance accessible over TCP/IP. This method is generally faster, lower latency, and more energy efficient than using `I2PInterface`, however it also leaks more data about the server host.
|
||||
|
||||
The `BackboneInterface` is a very fast and efficient interface type available on POSIX operating
|
||||
systems, designed to handle thousands of connections simultaneously with low memory, processing
|
||||
and I/O overhead. It is fully compatible with the TCP-based interface types.
|
||||
The `BackboneInterface` is a very fast and efficient interface type available on POSIX operating systems, designed to handle thousands of connections simultaneously with low memory, processing and I/O overhead. It is fully compatible with the TCP-based interface types.
|
||||
|
||||
TCP connections reveal the IP address of both your instance and the server to anyone who can
|
||||
inspect the connection. Someone could use this information to determine your location or identity. Adversaries
|
||||
inspecting your packets may be able to record packet metadata like time of transmission and packet size.
|
||||
Even though Reticulum encrypts traffic, TCP does not, so an adversary may be able to use
|
||||
packet inspection to learn that a system is running Reticulum, and what other IP addresses connect to it.
|
||||
Hosting a publicly reachable instance over TCP also requires a publicly reachable IP address,
|
||||
which most Internet connections don’t offer anymore.
|
||||
TCP connections reveal the IP address of both your instance and the server to anyone who can inspect the connection. Someone could use this information to determine your location or identity. Adversaries inspecting your packets may be able to record packet metadata like time of transmission and packet size. Even though Reticulum encrypts traffic, TCP does not, so an adversary may be able to use packet inspection to learn that a system is running Reticulum, and what other IP addresses connect to it. Hosting a publicly reachable instance over TCP also requires a publicly reachable IP address, which most Internet connections don’t offer anymore.
|
||||
|
||||
The `I2PInterface` routes messages through the [Invisible Internet Protocol
|
||||
(I2P)](https://geti2p.net/en/). To use this interface, users must also run an I2P daemon in
|
||||
parallel to `rnsd`. For always-on I2P nodes it is recommended to use [i2pd](https://i2pd.website/).
|
||||
The `I2PInterface` routes messages through the [Invisible Internet Protocol (I2P)](https://geti2p.net/en/). To use this interface, users must also run an I2P daemon in parallel to `rnsd`. For always-on I2P nodes it is recommended to use [i2pd](https://i2pd.website/).
|
||||
|
||||
By default, I2P will encrypt and mix all traffic sent over the Internet, and
|
||||
hide both the sender and receiver Reticulum instance IP addresses. Running an I2P node
|
||||
will also relay other I2P user’s encrypted packets, which will use extra
|
||||
bandwidth and compute power, but also makes timing attacks and other forms of
|
||||
deep-packet-inspection much more difficult.
|
||||
By default, I2P will encrypt and mix all traffic sent over the Internet, and hide both the sender and receiver Reticulum instance IP addresses. Running an I2P node will also relay other I2P user’s encrypted packets, which will use extra bandwidth and compute power, but also makes timing attacks and other forms of deep-packet-inspection much more difficult.
|
||||
|
||||
I2P also allows users to host globally available Reticulum instances from non-public IP’s and behind firewalls and NAT.
|
||||
|
||||
In general it is recommended to use an I2P node if you want to host a publicly accessible
|
||||
instance, while preserving anonymity. If you care more about performance, and a slightly
|
||||
easier setup, use TCP.
|
||||
In general it is recommended to use an I2P node if you want to host a publicly accessible instance, while preserving anonymity. If you care more about performance, and a slightly easier setup, use TCP.
|
||||
|
||||
## Adding Radio Interfaces
|
||||
|
||||
Once you have Reticulum installed and working, you can add radio interfaces with
|
||||
any compatible hardware you have available. Reticulum supports a wide range of radio
|
||||
hardware, and if you already have any available, it is very likely that it will
|
||||
work with Reticulum. For information on how to configure this, see the
|
||||
[Interfaces](interfaces.md#interfaces-main) section of this manual.
|
||||
Once you have Reticulum installed and working, you can add radio interfaces with any compatible hardware you have available. Reticulum supports a wide range of radio hardware, and if you already have any available, it is very likely that it will work with Reticulum. For information on how to configure this, see the [Interfaces](interfaces.md#interfaces-main) section of this manual.
|
||||
|
||||
If you do not already have transceiver hardware available, you can easily and
|
||||
cheaply build an [RNode](hardware.md#rnode-main), which is a general-purpose long-range
|
||||
digital radio transceiver, that integrates easily with Reticulum.
|
||||
If you do not already have transceiver hardware available, you can easily and cheaply build an [RNode](hardware.md#rnode-main), which is a general-purpose long-range digital radio transceiver, that integrates easily with Reticulum.
|
||||
|
||||
To build one yourself requires installing a custom firmware on a supported LoRa
|
||||
development board with an auto-install script or web-based flasher.
|
||||
Please see the [Communications Hardware](hardware.md#hardware-main) chapter for a guide.
|
||||
If you prefer purchasing a ready-made unit, you can refer to the
|
||||
list of suppliers.
|
||||
To build one yourself requires installing a custom firmware on a supported LoRa development board with an auto-install script or web-based flasher. Please see the [Communications Hardware](hardware.md#hardware-main) chapter for a guide. If you prefer purchasing a ready-made unit, you can refer to the list of suppliers.
|
||||
|
||||
Other radio-based hardware interfaces are being developed and made available by
|
||||
the broader Reticulum community. You can find more information on such topics
|
||||
over Reticulum-based information sharing systems.
|
||||
Other radio-based hardware interfaces are being developed and made available by the broader Reticulum community. You can find more information on such topics over Reticulum-based information sharing systems.
|
||||
|
||||
If you have communications hardware that is not already supported by any of the
|
||||
[existing interface types](interfaces.md#interfaces-main), it is easy to write (and potentially
|
||||
publish) a [custom interface module](interfaces.md#interfaces-custom) that makes it compatible with Reticulum.
|
||||
If you have communications hardware that is not already supported by any of the [existing interface types](interfaces.md#interfaces-main), it is easy to write (and potentially publish) a [custom interface module](interfaces.md#interfaces-custom) that makes it compatible with Reticulum.
|
||||
|
||||
## Creating and Using Custom Interfaces
|
||||
|
||||
While Reticulum includes a flexible and broad range of built-in interfaces, these
|
||||
will not cover every conceivable type of communications hardware that Reticulum
|
||||
can potentially use to communicate.
|
||||
While Reticulum includes a flexible and broad range of built-in interfaces, these will not cover every conceivable type of communications hardware that Reticulum can potentially use to communicate.
|
||||
|
||||
It is therefore possible to easily write your own interface modules, that can be
|
||||
loaded at run-time and used on-par with any of the built-in interface types.
|
||||
It is therefore possible to easily write your own interface modules, that can be loaded at run-time and used on-par with any of the built-in interface types.
|
||||
|
||||
For more information on this subject, and code examples to build on, please see
|
||||
the [Configuring Interfaces](interfaces.md#interfaces-main) chapter.
|
||||
For more information on this subject, and code examples to build on, please see the [Configuring Interfaces](interfaces.md#interfaces-main) chapter.
|
||||
|
||||
## Develop a Program with Reticulum
|
||||
|
||||
If you want to develop programs that use Reticulum, the easiest way to get
|
||||
started is to install the latest release of Reticulum via pip:
|
||||
If you want to develop programs that use Reticulum, the easiest way to get started is to install the latest release of Reticulum via pip:
|
||||
|
||||
```default
|
||||
pip install rns
|
||||
```
|
||||
|
||||
The above command will install Reticulum and dependencies, and you will be
|
||||
ready to import and use RNS in your own programs. The next step will most
|
||||
likely be to look at some [Example Programs](examples.md#examples-main).
|
||||
The above command will install Reticulum and dependencies, and you will be ready to import and use RNS in your own programs. The next step will most likely be to look at some [Example Programs](examples.md#examples-main).
|
||||
|
||||
The entire Reticulum API is documented in the [API Reference](reference.md#api-main)
|
||||
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.
|
||||
The entire Reticulum API is documented in the [API Reference](reference.md#api-main) 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.
|
||||
|
||||
## Platform-Specific Install Notes
|
||||
|
||||
Some platforms require a slightly different installation procedure, or have
|
||||
various quirks that are worth being aware of. These are listed here.
|
||||
Some platforms require a slightly different installation procedure, or have various quirks that are worth being aware of. These are listed here.
|
||||
|
||||
### Android
|
||||
|
||||
Reticulum can be used on Android in different ways. The easiest way to get
|
||||
started is using an app like [Sideband](https://unsigned.io/sideband).
|
||||
Reticulum can be used on Android in different ways. The easiest way to get started is using an app like [Sideband](https://unsigned.io/sideband).
|
||||
|
||||
For more control and features, you can use Reticulum and related programs via
|
||||
the [Termux app](https://termux.com/), at the time of writing available on
|
||||
[F-droid](https://f-droid.org).
|
||||
For more control and features, you can use Reticulum and related programs via the [Termux app](https://termux.com/), at the time of writing available on [F-droid](https://f-droid.org).
|
||||
|
||||
Termux is a terminal emulator and Linux environment for Android based devices,
|
||||
which includes the ability to use many different programs and libraries,
|
||||
including Reticulum.
|
||||
Termux is a terminal emulator and Linux environment for Android based devices, which includes the ability to use many different programs and libraries, including Reticulum.
|
||||
|
||||
To use Reticulum within the Termux environment, you will need to install
|
||||
`python` and the `python-cryptography` library using `pkg`, the package-manager
|
||||
build into Termux. After that, you can use `pip` to install Reticulum.
|
||||
To use Reticulum within the Termux environment, you will need to install `python` and the `python-cryptography` library using `pkg`, the package-manager build into Termux. After that, you can use `pip` to install Reticulum.
|
||||
|
||||
From within Termux, execute the following:
|
||||
|
||||
@@ -374,9 +271,7 @@ pip install wheel pip --upgrade
|
||||
pip install rns
|
||||
```
|
||||
|
||||
If for some reason the `python-cryptography` package is not available for
|
||||
your platform via the Termux package manager, you can attempt to build it
|
||||
locally on your device using the following command:
|
||||
If for some reason the `python-cryptography` package is not available for your platform via the Termux package manager, you can attempt to build it locally on your device using the following command:
|
||||
|
||||
```shell
|
||||
# First, make sure indexes and packages are up to date.
|
||||
@@ -403,15 +298,11 @@ pip install cryptography
|
||||
pip install rns
|
||||
```
|
||||
|
||||
It is also possible to include Reticulum in apps compiled and distributed as
|
||||
Android APKs. A detailed tutorial and example source code will be included
|
||||
here at a later point. Until then you can use the [Sideband source code](https://github.com/markqvist/sideband) as an example and starting point.
|
||||
It is also possible to include Reticulum in apps compiled and distributed as Android APKs. A detailed tutorial and example source code will be included here at a later point. Until then you can use the [Sideband source code](https://github.com/markqvist/sideband) as an example and starting point.
|
||||
|
||||
### ARM64
|
||||
|
||||
On some architectures, including ARM64, not all dependencies have precompiled
|
||||
binaries. On such systems, you may need to install `python3-dev` (or similar) before
|
||||
installing Reticulum or programs that depend on Reticulum.
|
||||
On some architectures, including ARM64, not all dependencies have precompiled binaries. On such systems, you may need to install `python3-dev` (or similar) before installing Reticulum or programs that depend on Reticulum.
|
||||
|
||||
```shell
|
||||
# Install Python and development packages
|
||||
@@ -427,11 +318,7 @@ on your system locally.
|
||||
|
||||
### Debian Bookworm
|
||||
|
||||
On versions of Debian released after April 2023, it is no longer possible by default
|
||||
to use `pip` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement `pipx` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
On versions of Debian released after April 2023, it is no longer possible by default to use `pip` to install packages onto your system. Unfortunately, you will need to use the replacement `pipx` command instead, which places installed packages in an isolated environment. This should not negatively affect Reticulum, but will not work for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
```shell
|
||||
# Install pipx
|
||||
@@ -444,41 +331,29 @@ pipx ensurepath
|
||||
pipx install rns
|
||||
```
|
||||
|
||||
Alternatively, you can restore normal behaviour to `pip` by creating or editing
|
||||
the configuration file located at `~/.config/pip/pip.conf`, and adding the
|
||||
following section:
|
||||
Alternatively, you can restore normal behaviour to `pip` by creating or editing the configuration file located at `~/.config/pip/pip.conf`, and adding the following section:
|
||||
|
||||
```ini
|
||||
[global]
|
||||
break-system-packages = true
|
||||
```
|
||||
|
||||
For a one-shot installation of Reticulum, without globally enabling the `break-system-packages`
|
||||
option, you can use the following command:
|
||||
For a one-shot installation of Reticulum, without globally enabling the `break-system-packages` option, you can use the following command:
|
||||
|
||||
```shell
|
||||
pip install rns --break-system-packages
|
||||
```
|
||||
|
||||
#### NOTE
|
||||
The `--break-system-packages` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing `pip` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The `--break-system-packages` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing `pip` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
### MacOS
|
||||
|
||||
To install Reticulum on macOS, you will need to have Python and the `pip` package
|
||||
manager installed.
|
||||
To install Reticulum on macOS, you will need to have Python and the `pip` package manager installed.
|
||||
|
||||
Systems running macOS can vary quite widely in whether or not Python is pre-installed,
|
||||
and if it is, which version is installed, and whether the `pip` package manager is
|
||||
also installed and set up. If in doubt, you can [download and install](https://www.python.org/downloads/)
|
||||
Python manually.
|
||||
Systems running macOS can vary quite widely in whether or not Python is pre-installed, and if it is, which version is installed, and whether the `pip` package manager is also installed and set up. If in doubt, you can [download and install](https://www.python.org/downloads/) Python manually.
|
||||
|
||||
When Python and `pip` is available on your system, simply open a terminal window
|
||||
and use one of the following commands:
|
||||
When Python and `pip` is available on your system, simply open a terminal window and use one of the following commands:
|
||||
|
||||
```shell
|
||||
# Install Reticulum and utilities with pip:
|
||||
@@ -490,16 +365,9 @@ pip3 install rns --break-system-packages
|
||||
```
|
||||
|
||||
#### NOTE
|
||||
The `--break-system-packages` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing `pip` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The `--break-system-packages` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing `pip` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
Additionally, some version combinations of macOS and Python require you to
|
||||
manually add your installed `pip` packages directory to your PATH environment
|
||||
variable, before you can use installed commands in your terminal. Usually, adding
|
||||
the following line to your shell init script (for example `~/.zshrc`) will be enough:
|
||||
Additionally, some version combinations of macOS and Python require you to manually add your installed `pip` packages directory to your PATH environment variable, before you can use installed commands in your terminal. Usually, adding the following line to your shell init script (for example `~/.zshrc`) will be enough:
|
||||
|
||||
```shell
|
||||
export PATH=$PATH:~/Library/Python/3.9/bin
|
||||
@@ -509,18 +377,12 @@ Adjust Python version and shell init script location according to your system.
|
||||
|
||||
### OpenWRT
|
||||
|
||||
On OpenWRT systems with sufficient storage and memory, you can install
|
||||
Reticulum and related utilities using the opkg package manager and pip.
|
||||
On OpenWRT systems with sufficient storage and memory, you can install Reticulum and related utilities using the opkg package manager and pip.
|
||||
|
||||
#### NOTE
|
||||
At the time of releasing this manual, work is underway to create pre-built
|
||||
Reticulum packages for OpenWRT, with full configuration, service
|
||||
and `uci` integration. Please see the [feed-reticulum](https://github.com/gretel/feed-reticulum)
|
||||
and [reticulum-openwrt](https://github.com/gretel/reticulum-openwrt)
|
||||
repositories for more information.
|
||||
At the time of releasing this manual, work is underway to create pre-built Reticulum packages for OpenWRT, with full configuration, service and `uci` integration. Please see the [feed-reticulum](https://github.com/gretel/feed-reticulum) and [reticulum-openwrt](https://github.com/gretel/reticulum-openwrt) repositories for more information.
|
||||
|
||||
To install Reticulum on OpenWRT, first log into a command line session, and
|
||||
then use the following instructions:
|
||||
To install Reticulum on OpenWRT, first log into a command line session, and then use the following instructions:
|
||||
|
||||
```shell
|
||||
# Install dependencies
|
||||
@@ -534,29 +396,15 @@ rnsd -vvv
|
||||
```
|
||||
|
||||
#### NOTE
|
||||
The above instructions have been verified and tested on OpenWRT 21.02 only.
|
||||
It is likely that other versions may require slightly altered installation
|
||||
commands or package names. You will also need enough free space in your
|
||||
overlay FS, and enough free RAM to actually run Reticulum and any related
|
||||
programs and utilities.
|
||||
The above instructions have been verified and tested on OpenWRT 21.02 only. It is likely that other versions may require slightly altered installation commands or package names. You will also need enough free space in your overlay FS, and enough free RAM to actually run Reticulum and any related programs and utilities.
|
||||
|
||||
Depending on your device configuration, you may need to adjust firewall rules
|
||||
for Reticulum connectivity to and from your device to work. Until proper
|
||||
packaging is ready, you will also need to manually create a service or startup
|
||||
script to automatically laucnh Reticulum at boot time.
|
||||
Depending on your device configuration, you may need to adjust firewall rules for Reticulum connectivity to and from your device to work. Until proper packaging is ready, you will also need to manually create a service or startup script to automatically laucnh Reticulum at boot time.
|
||||
|
||||
Please also note that the AutoInterface requires link-local IPv6 addresses
|
||||
to be enabled for any Ethernet and WiFi devices you intend to use. If `ip a`
|
||||
shows an address starting with `fe80::` for the device in question,
|
||||
`AutoInterface` should work for that device.
|
||||
Please also note that the AutoInterface requires link-local IPv6 addresses to be enabled for any Ethernet and WiFi devices you intend to use. If `ip a` shows an address starting with `fe80::` for the device in question, `AutoInterface` should work for that device.
|
||||
|
||||
### Raspberry Pi
|
||||
|
||||
It is currently recommended to use a 64-bit version of the Raspberry Pi OS
|
||||
if you want to run Reticulum on Raspberry Pi computers, since 32-bit versions
|
||||
don’t always have packages available for some dependencies. If Python and the
|
||||
pip package manager is not already installed, do that first, and then
|
||||
install Reticulum using pip.
|
||||
It is currently recommended to use a 64-bit version of the Raspberry Pi OS if you want to run Reticulum on Raspberry Pi computers, since 32-bit versions don’t always have packages available for some dependencies. If Python and the pip package manager is not already installed, do that first, and then install Reticulum using pip.
|
||||
|
||||
```shell
|
||||
# Install dependencies
|
||||
@@ -567,21 +415,13 @@ pip install rns --break-system-packages
|
||||
```
|
||||
|
||||
#### NOTE
|
||||
The `--break-system-packages` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing `pip` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The `--break-system-packages` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing `pip` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
While it is possible to install and run Reticulum on 32-bit Rasperry Pi OSes,
|
||||
it will require manually configuring and installing required build dependencies,
|
||||
and is not detailed in this manual.
|
||||
While it is possible to install and run Reticulum on 32-bit Rasperry Pi OSes, it will require manually configuring and installing required build dependencies, and is not detailed in this manual.
|
||||
|
||||
### RISC-V
|
||||
|
||||
On some architectures, including RISC-V, not all dependencies have precompiled
|
||||
binaries. On such systems, you may need to install `python3-dev` (or similar) before
|
||||
installing Reticulum or programs that depend on Reticulum.
|
||||
On some architectures, including RISC-V, not all dependencies have precompiled binaries. On such systems, you may need to install `python3-dev` (or similar) before installing Reticulum or programs that depend on Reticulum.
|
||||
|
||||
```shell
|
||||
# Install Python and development packages
|
||||
@@ -592,16 +432,11 @@ sudo apt install python3 python3-pip python3-dev
|
||||
python3 -m pip install rns
|
||||
```
|
||||
|
||||
With these packages installed, `pip` will be able to build any missing dependencies
|
||||
on your system locally.
|
||||
With these packages installed, `pip` will be able to build any missing dependencies on your system locally.
|
||||
|
||||
### Ubuntu Lunar
|
||||
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible by default
|
||||
to use `pip` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement `pipx` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible by default to use `pip` to install packages onto your system. Unfortunately, you will need to use the replacement `pipx` command instead, which places installed packages in an isolated environment. This should not negatively affect Reticulum, but will not work for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
```shell
|
||||
# Install pipx
|
||||
@@ -614,42 +449,29 @@ pipx ensurepath
|
||||
pipx install rns
|
||||
```
|
||||
|
||||
Alternatively, you can restore normal behaviour to `pip` by creating or editing
|
||||
the configuration file located at `~/.config/pip/pip.conf`, and adding the
|
||||
following section:
|
||||
Alternatively, you can restore normal behaviour to `pip` by creating or editing the configuration file located at `~/.config/pip/pip.conf`, and adding the following section:
|
||||
|
||||
```text
|
||||
[global]
|
||||
break-system-packages = true
|
||||
```
|
||||
|
||||
For a one-shot installation of Reticulum, without globally enabling the `break-system-packages`
|
||||
option, you can use the following command:
|
||||
For a one-shot installation of Reticulum, without globally enabling the `break-system-packages` option, you can use the following command:
|
||||
|
||||
```text
|
||||
pip install rns --break-system-packages
|
||||
```
|
||||
|
||||
#### NOTE
|
||||
The `--break-system-packages` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing `pip` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The `--break-system-packages` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing `pip` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
### Windows
|
||||
|
||||
On Windows operating systems, the easiest way to install Reticulum is by using the
|
||||
`pip` package manager from the command line (either the command prompt or Windows
|
||||
Powershell).
|
||||
On Windows operating systems, the easiest way to install Reticulum is by using the `pip` package manager from the command line (either the command prompt or Windows Powershell).
|
||||
|
||||
If you don’t already have Python installed, [download and install Python](https://www.python.org/downloads/).
|
||||
At the time of publication of this manual, the recommended version is [Python 3.12.7](https://www.python.org/downloads/release/python-3127).
|
||||
If you don’t already have Python installed, [download and install Python](https://www.python.org/downloads/). At the time of publication of this manual, the recommended version is [Python 3.12.7](https://www.python.org/downloads/release/python-3127).
|
||||
|
||||
**Important!** When asked by the installer, make sure to add the Python program to
|
||||
your PATH environment variables. If you don’t do this, you will not be able to
|
||||
use the `pip` installer, or run the included Reticulum utility programs (such as
|
||||
`rnsd` and `rnstatus`) from the command line.
|
||||
**Important!** When asked by the installer, make sure to add the Python program to your PATH environment variables. If you don’t do this, you will not be able to use the `pip` installer, or run the included Reticulum utility programs (such as `rnsd` and `rnstatus`) from the command line.
|
||||
|
||||
After installing Python, open the command prompt or Windows Powershell, and type:
|
||||
|
||||
@@ -657,8 +479,7 @@ After installing Python, open the command prompt or Windows Powershell, and type
|
||||
pip install rns
|
||||
```
|
||||
|
||||
You can now use Reticulum and all included utility programs directly from your
|
||||
preferred command line interface.
|
||||
You can now use Reticulum and all included utility programs directly from your preferred command line interface.
|
||||
|
||||
## Pure-Python Reticulum
|
||||
|
||||
@@ -668,17 +489,6 @@ do not support [PyCA/cryptography](https://github.com/pyca/cryptography), it is
|
||||
important that you read and understand the [Cryptographic Primitives](understanding.md#understanding-primitives)
|
||||
section of this manual.
|
||||
|
||||
In some rare cases, and on more obscure system types, it is not possible to
|
||||
install one or more dependencies. In such situations,
|
||||
you can use the `rnspure` package instead of the `rns` package, or use `pip`
|
||||
with the `--no-dependencies` command-line option. The `rnspure`
|
||||
package requires no external dependencies for installation. Please note that the
|
||||
actual contents of the `rns` and `rnspure` packages are *completely identical*.
|
||||
The only difference is that the `rnspure` package lists no dependencies required
|
||||
for installation.
|
||||
In some rare cases, and on more obscure system types, it is not possible to install one or more dependencies. In such situations, you can use the `rnspure` package instead of the `rns` package, or use `pip` with the `--no-dependencies` command-line option. The `rnspure` package requires no external dependencies for installation. Please note that the actual contents of the `rns` and `rnspure` packages are *completely identical*. The only difference is that the `rnspure` package lists no dependencies required for installation.
|
||||
|
||||
No matter how Reticulum is installed and started, it will load external dependencies
|
||||
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.
|
||||
No matter how Reticulum is installed and started, it will load external dependencies 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.
|
||||
+429
-20
@@ -1,12 +1,14 @@
|
||||
# Git Over Reticulum
|
||||
|
||||
This chapter of the manual serves as the technical reference for the distributed software development and project collaboration tools included in RNS. For a conceptual overview, see the [Distributed Development](distributed.md#distributed-development) chapter.
|
||||
|
||||
A set of utilities for distributed collaborative software development and publishing are included in RNS.
|
||||
|
||||
The system consists of two parts: The `rngit` node that hosts repositories, and the `git-remote-rns` helper that enables Git to communicate with rngit nodes. As soon as you have RNS installed on your system, you can transparently use Git with Reticulum-hosted repositories just like any other type of remote. Git over Reticulum uses URLs in the following format: `rns://DESTINATION_HASH/group/repo`.
|
||||
|
||||
If you set a branch to track a Reticulum remote as the default upstream, you can simply use `git` as you normally would; all commands work transparently and as expected.
|
||||
|
||||
#### WARNING
|
||||
#### IMPORTANT
|
||||
**The rngit program is a new addition to RNS!** This functionality was introduced in RNS 1.2.0. While great care has been taken to design a secure, but highly configurable and flexible [permission system](#permissions) for allowing many users to interact with many different repositories on a single node, `rngit` has not been tested extensively in the wild! Be careful when hosting repositories, especially if they are public or semi-public.
|
||||
|
||||
## The rngit Utility
|
||||
@@ -158,10 +160,8 @@ Repository forked to public/myfork
|
||||
The source can be any valid Git URL, including:
|
||||
|
||||
- HTTPS URLs: `https://github.com/user/repo.git`
|
||||
- Git URLs: `git://host.com/repo.git`
|
||||
- SSH URLs: `ssh://git@host.com/repo.git`
|
||||
- Reticulum URLs: `rns://DESTINATION_HASH/group/repo`
|
||||
- Local paths: `/path/to/repo.git`
|
||||
|
||||
Forks are created as bare repositories with metadata tracking their origin. The fork process:
|
||||
|
||||
@@ -480,6 +480,66 @@ Targets can also use short forms:
|
||||
- Repository permissions: `<group_root>/<group_name>/<repo_name>.allowed`
|
||||
- Document permissions: `<group_root>/<group_name>.work/<doc_id>.allowed`
|
||||
|
||||
## Remote Permission Management
|
||||
|
||||
While permissions can be configured directly on the node by editing configuration files and `.allowed` files, `rngit` also supports remote permission management through the `rngit perms` command. This allows administrators to modify access controls for groups and repositories over Reticulum, without requiring shell access to the hosting node.
|
||||
|
||||
To use remote permission management, you must have `admin` permission on the target group or repository. The command opens your configured `$EDITOR` to modify permissions, using the same syntax and format as local `.allowed` files. When you save and exit the editor, the modified permissions are transmitted to the remote node and applied immediately.
|
||||
|
||||
### Managing Group Permissions
|
||||
|
||||
To view or modify permissions for an entire repository group, specify the group URL (ending with the group name):
|
||||
|
||||
```text
|
||||
$ rngit perms rns://50824b711717f97c2fb1166ceddd5ea9/public
|
||||
```
|
||||
|
||||
This retrieves the current permission configuration from the `public.allowed` file and opens it in your editor. Any changes you make are validated for syntax correctness. Invalid permission rules will be rejected with an error message indicating the problematic line.
|
||||
|
||||
### Managing Repository Permissions
|
||||
|
||||
To manage permissions for a specific repository, include the repository name in the URL:
|
||||
|
||||
```text
|
||||
$ rngit perms rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo
|
||||
```
|
||||
|
||||
This operates on the `myrepo.allowed` file next to the repository. Repository-level permissions take precedence over group-level permissions, allowing fine-grained access control for individual repositories within a group.
|
||||
|
||||
### Permission Validation
|
||||
|
||||
When modifying permissions remotely, `rngit` validates that:
|
||||
|
||||
- Each permission line follows the correct `permission:target` syntax
|
||||
- Permission types are valid (r, w, rw, c, s, rel, i, p, adm)
|
||||
- Target specifications are valid (identity hashes, `all`, or `none`)
|
||||
- Identity hashes, when specified, are the correct length (32 hexadecimal characters)
|
||||
|
||||
If validation fails, the editor will reopen with an error message describing the issue, allowing you to correct the problem before resubmitting.
|
||||
|
||||
**All Command-Line Options (rngit perms)**
|
||||
|
||||
```text
|
||||
usage: rngit perms [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-v] [-q] [--version]
|
||||
remote
|
||||
|
||||
Reticulum Git Permission Manager
|
||||
|
||||
positional arguments:
|
||||
remote URL of remote group or repository
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative config directory
|
||||
--rnsconfig RNSCONFIG
|
||||
path to alternative Reticulum config directory
|
||||
-i, --identity PATH path to identity
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
```
|
||||
|
||||
## Identity & Destination Aliases
|
||||
|
||||
To make permission and remote destination management easier, you can locally define aliases for commonly used identity and destination hashes. Identity aliases used in permissions resolution can be defined in the `[aliases]` section of the `~/.rngit/config` file, while destination aliases are defined in the `[aliases]` section of the `~/.rngit/client_config` file.
|
||||
@@ -639,6 +699,205 @@ A complete node configuration might look like this:
|
||||
unicode_icons = no
|
||||
```
|
||||
|
||||
## Verified Releases
|
||||
|
||||
The `rngit` release system provides cryptographic provenance and integrity guarantees through automatic signing of release artifacts and signed release manifests. When you create a release, `rngit` generates an Ed25519 signature for each artifact and embeds these signatures in a cryptographically signed release manifest (`.rsm` file). This allows anyone who obtains the release to verify its authenticity and integrity, regardless of how the files were distributed.
|
||||
|
||||
### Obtaining Verified Releases
|
||||
|
||||
The `rngit` system lets you obtain releases securely and in a verified manner, by validating cryptographically signed release manifests in the `.rsm` format during the retrieval process. Once a release has been published with `rngit`, anyone that has read access to it can obtain the release with the `rngit release` command, for example:
|
||||
|
||||
```text
|
||||
$ rngit release rns://remote_node/group/some_program fetch latest:all
|
||||
```
|
||||
|
||||
This command will connect to the remote, retrieve the latest release manifest, verify it’s signature and integrity (you can optionally specify a required signer identity with `--signer`), and then download and sequentially verify all artifacts included in the release.
|
||||
|
||||
If verification succeeds, the retrieved artifact files, along with the release manifest will be saved in the current working directory. From the above example, you would end up with a number of downloaded files, and a version- and package specific release manifest, such as `some_program_1.5.2.rsm`.
|
||||
|
||||
#### IMPORTANT
|
||||
Keeping the retrieved release manifest is a **very** good idea! It allows you to easily obtain future releases and updates to the software directly, while verifying they came from the same publisher.
|
||||
|
||||
**Obtaining & Updating Releases Using RSM Manifests**
|
||||
|
||||
One of the key features of the `rngit` release system is the ability to fetch and verify new releases using only a signed release manifest. This is particularly valuable for distributing software over Reticulum. Once someone has an `.rsm` manifest of your package, they can use it to continually retrieve and update the software.
|
||||
|
||||
To fetch a release using a manifest:
|
||||
|
||||
```text
|
||||
$ rngit release some_program_1.5.2.rsm fetch latest:all
|
||||
```
|
||||
|
||||
This command:
|
||||
|
||||
1. Validates the manifest signature to confirm authenticity
|
||||
2. Extracts the origin node and repository path from the signed manifest
|
||||
3. Connects to the origin node over Reticulum
|
||||
4. Gets the *latest* release manifest from the developer
|
||||
5. Verifies it against the existing manifest
|
||||
6. Fetches each artifact listed in the manifest
|
||||
7. Verifies each downloaded file against the signature embedded in the manifest
|
||||
|
||||
If any artifact fails signature verification, the fetch aborts with an error, preventing the installation of corrupted or tampered files.
|
||||
|
||||
**Specifying Required Signers**
|
||||
|
||||
You can require that releases be signed by specific identities. When fetching a release, use the `--signer` option to specify the identity hash of the required signer:
|
||||
|
||||
```text
|
||||
$ rngit release rns://remote_node/public/myrepo fetch latest:all --signer 21a8daa6d9c3d3b8aab6e94b6bcb0e33
|
||||
```
|
||||
|
||||
If the release was not signed by the specified identity, the fetch will abort before any files are downloaded. Likewise, if any downloaded artifacts were not signed by the required identity, the process will abort at the first invalid signature. This provides strong guarantees about the provenance of the software you are installing.
|
||||
|
||||
The signer check also works when fetching from a local manifest:
|
||||
|
||||
```text
|
||||
$ rngit release manifest.rsm fetch latest:all --signer 21a8daa6d9c3d3b8aab6e94b6bcb0e33
|
||||
```
|
||||
|
||||
**Selective & Partial Fetches**
|
||||
|
||||
You can fetch individual artifacts from a release by specifying the artifact name instead of `all`:
|
||||
|
||||
```text
|
||||
$ rngit release rns://remote_node/public/myrepo fetch 1.2.0:myapp-1.2.0.tar.gz
|
||||
```
|
||||
|
||||
This downloads only the specified artifact and verifies its signature against the manifest. If a file already exists locally, `rngit` verifies it against the manifest signature and skips the download if valid, making it safe to run the command multiple times. When fetching releases, `rngit release` will only download files that are missing or invalid according to the manifest. This means that partially completed release fetches can be continued later, if interrupted.
|
||||
|
||||
**Pattern Matching for Artifacts**
|
||||
|
||||
When fetching selective artifacts, you are not limited to exact names or the `all` keyword. You can use shell-style wildcard patterns to match multiple artifacts flexibly. This is particularly useful for selecting platform-specific builds, version ranges, or file types without specifying each file individually.
|
||||
|
||||
The pattern matching supports standard Unix wildcards:
|
||||
|
||||
- `*` matches any sequence of characters (including empty)
|
||||
- `?` matches any single character
|
||||
- `[seq]` matches any character in *seq* (for example `[0-9]` or `[abc]`)
|
||||
- `[!seq]` matches any character not in *seq*
|
||||
|
||||
For example, to fetch all wheel files for Python 3 across any platform:
|
||||
|
||||
```text
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:*-py3-*.whl"
|
||||
```
|
||||
|
||||
To fetch a specific patch version when you know the major and minor version:
|
||||
|
||||
```text
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:myapp-1.2.?-linux-x86_64.tar.gz"
|
||||
```
|
||||
|
||||
Or to retrieve all source archives:
|
||||
|
||||
```text
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:source_*.tgz"
|
||||
```
|
||||
|
||||
If your pattern contains no wildcard characters, it must match an artifact name exactly, which is useful for fetching single, specific artifacts. When a pattern matches multiple artifacts, all matched files are fetched and verified. If no artifacts match the pattern, the fetch aborts with an error indicating no matches were found.
|
||||
|
||||
### Offline Verification
|
||||
|
||||
Because the release manifest contains embedded signatures, you can verify the integrity of release artifacts offline, without connecting to the repository node. The `rnid` and `rngit` utilities can validate artifact signatures against `.rsg` and manifest files.
|
||||
|
||||
**Using a release manifest:**
|
||||
|
||||
Ensure the release manifest is located in the same directory as the release artifacts, then run:
|
||||
|
||||
```text
|
||||
# Verify all artifacts in the manifest
|
||||
$ rngit release myapp-1.2.0.rsm verify
|
||||
|
||||
# Or, verify only specific artifacts
|
||||
$ rngit release myapp-1.2.0.rsm verify "latest:*.whl"
|
||||
```
|
||||
|
||||
This will load the manifest, and verify all files currently on-disk, but will not attempt to fetch the latest release manifest from the origin, or update local files to match it.
|
||||
|
||||
#### NOTE
|
||||
The `verify` operation is functionally equivalent to using the `fetch` operation with the `--offline` flag, and they can be used interchangably.
|
||||
|
||||
**For individual files:**
|
||||
|
||||
Ensure the `.rsg` signature is located in the same directory as the release artifact, then run:
|
||||
|
||||
```text
|
||||
$ rnid -V myapp-1.2.0.tar.gz
|
||||
```
|
||||
|
||||
This validates that the artifact file matches the signature created during the release process. Combined with the manifest’s own signature, this provides end-to-end verification from the original release creation to the final installation.
|
||||
|
||||
### Creating Signed Releases
|
||||
|
||||
Reticulum and the `rngit` system makes it easy to create signed releases that your users can verify and update securely. When you create a release using `rngit`, the program automatically:
|
||||
|
||||
1. Generates an Ed25519 signature for each artifact file using your identity’s signing key
|
||||
2. Creates `.rsg` signature files alongside each artifact in your distribution directory
|
||||
3. Constructs a signed `manifest.rsm` release manifest containing metadata, an artifact list, and embedded signatures
|
||||
4. Transmits both artifacts, signatures and manifest to the remote node specified as release origin
|
||||
|
||||
As an example, to create and publish a release from all files in the folder named `dist`, simply run:
|
||||
|
||||
```text
|
||||
$ rngit release rns://my_node/group/myrepo create 1.2.0:./dist
|
||||
```
|
||||
|
||||
Everything is automatically signed and uploaded to your node, and the release manifest will now include the following signed attestation information:
|
||||
|
||||
- Package name and version
|
||||
- The release notes for this release
|
||||
- Release timestamp and commit hash
|
||||
- Origin node identity and repository path
|
||||
- Complete list of artifacts
|
||||
- Embedded signatures for each artifact
|
||||
|
||||
That’s it, there’s nothing more to it than one command. Users can now securely obtain your release using `rngit release fetch`.
|
||||
|
||||
**Release Manifest Format**
|
||||
|
||||
Release manifests use the `.rsm` format (a general-purpose, structured signed message format) and are themselves cryptographically signed documents. The manifest format embeds the signing identity’s public key and a detached signature that covers the entire manifest content. This creates a chain of trust: the manifest signature proves the manifest’s authenticity, and the embedded artifact signatures prove each file’s integrity.
|
||||
|
||||
When a release is created, the manifest is stored as `manifest.rsm` in the release artifacts directory. You can also generate a local release manifest without uploading by using the `--local` flag:
|
||||
|
||||
```text
|
||||
$ rngit release rns://f2d31b2e080e5d4e358d32822ee4a3b7/public/myrepo create 1.2.0:./dist --local
|
||||
```
|
||||
|
||||
This creates the `.rsg` signature files and `manifest.rsm` in your local distribution directory without connecting to the remote node, allowing you to inspect or distribute the signed release through alternative channels.
|
||||
|
||||
**Signature File Format**
|
||||
|
||||
Individual artifact signatures use the Reticulum Signature (`.rsg`) format and contain:
|
||||
|
||||
- The Ed25519 signature of the file
|
||||
- The signing identity’s public key
|
||||
- Optional metadata, such as timestamps or notes
|
||||
|
||||
These signature files are created automatically during the release process and can be used independently of the manifest for verification purposes. The `rnid` utility can create and validate RSG signatures for any file, making this signature format useful beyond the `rngit` release system.
|
||||
|
||||
**Good Practices for Signature Distribution**
|
||||
|
||||
While release manifests in the `.rsm` format *include* embedded `.rsg` signatures for every listed artifact, it is dependent on the situation and requirements whether individual `.rsg` signatures are distributed as well. It is generally a good idea to do so, since they are very light-weight, and provide an easy and convenient way to validate and authenticate *individual* files, as opposed to entire releases.
|
||||
|
||||
When distributing software through multiple channels (direct download, mirror networks, physical media), including the `.rsm` manifest allows recipients to verify authenticity regardless of how they obtained the files. This is particularly valuable in low-connectivity environments where Reticulum may be the only available communication channel, as the manifest ensures that software updates can be verified even when received via store-and-forward mechanisms or physical media transport.
|
||||
|
||||
**Integration with Package Management**
|
||||
|
||||
While this functionality is still under development, the signed release manifest format is designed to be consumed by package management systems and automated deployment tools. Because the manifest is cryptographically signed and contains all necessary metadata and integrity checks, it can serve as a trusted source of truth for software distribution, even when fetched over untrusted channels or stored for long periods.
|
||||
|
||||
**Release Encryption**
|
||||
|
||||
While API primitives and command-line tools are currently not implemented for this, the release, distribution and verification system has been designed to also support *encrypted* releases, which can be distributed securely to authorized recipients.
|
||||
|
||||
**Verified Package Format**
|
||||
|
||||
The current system is being expanded to also include an `.rvp` package format, which can contain packaged releases including all relevant artifacts, metadata, manifest and signatures.
|
||||
|
||||
**Automated Mirror Discovery**
|
||||
|
||||
The `rngit` release system is designed to support automated mirror discovery and distribution package retrieval over Reticulum networks. Since everything is cryptographically signed and verified, it is possible to create automated mirror and distribution networks, where users can obtain software and information from local sources, without risking malicious modifications to the software they rely on. This functionality is currently in development.
|
||||
|
||||
## Release Management
|
||||
|
||||
In addition to hosting Git repositories, `rngit` provides a complete release management system. This allows you to publish versioned releases with associated artifacts, release notes and metadata. Releases are managed through the `rngit release` subcommand, and are also viewable through the Nomad Network page interface.
|
||||
@@ -650,12 +909,12 @@ Creating a release involves specifying a Git tag and a directory containing buil
|
||||
To create a release, specify the tag name and path to artifacts:
|
||||
|
||||
```text
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create v1.2.0:./dist
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create 1.2.0:./dist
|
||||
```
|
||||
|
||||
This will:
|
||||
|
||||
1. Verify that the tag `v1.2.0` exists in the repository
|
||||
1. Verify that the tag `1.2.0` exists in the repository
|
||||
2. Open your editor to write release notes
|
||||
3. Upload all files from the `./dist` directory
|
||||
4. Publish the release
|
||||
@@ -682,9 +941,9 @@ $ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo list
|
||||
|
||||
Tag Status Created Objs Notes
|
||||
------------------------------------------------------------------
|
||||
v1.2.0 published 2025-01-15 14:32 3 Another release
|
||||
v1.1.0 published 2024-12-03 09:15 2 Bug fix release
|
||||
v1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
1.2.0 published 2025-01-15 14:32 3 Another release
|
||||
1.1.0 published 2024-12-03 09:15 2 Bug fix release
|
||||
1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
```
|
||||
|
||||
**Viewing Release Details**
|
||||
@@ -692,9 +951,9 @@ v1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
To see full information about a specific release:
|
||||
|
||||
```text
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo view v1.2.0
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo view 1.2.0
|
||||
|
||||
Release : 0.9.2
|
||||
Release : 1.2.0
|
||||
Status : published
|
||||
Created : 2026-05-04 23:53:09
|
||||
Thanks : 5
|
||||
@@ -711,15 +970,35 @@ Artifacts (4)
|
||||
- checksums.txt (256 B)
|
||||
```
|
||||
|
||||
**Fetching Releases**
|
||||
|
||||
To fetch a release, specify the remote URL, version and artifacts:
|
||||
|
||||
```text
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo fetch latest:all
|
||||
```
|
||||
|
||||
This process is described in greater detail in the [Obtaining Verified Releases](#git-release-obtain) section.
|
||||
|
||||
**Creating Releases**
|
||||
|
||||
To fetch a release, specify the remote URL, version and artifacts:
|
||||
|
||||
```text
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create 1.3.9:artifacts_dir
|
||||
```
|
||||
|
||||
This process is described in greater detail in the [Creating Signed Releases](#git-release-create) section.
|
||||
|
||||
**Deleting Releases**
|
||||
|
||||
To remove a release:
|
||||
|
||||
```text
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo delete v1.2.0
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo delete 1.2.0
|
||||
|
||||
Are you sure you want to delete release 'v1.2.0'? [y/N]: y
|
||||
Release v1.2.0 deleted
|
||||
Are you sure you want to delete release '1.2.0'? [y/N]: y
|
||||
Release 1.2.0 deleted
|
||||
```
|
||||
|
||||
**Requirements & Validation**
|
||||
@@ -747,15 +1026,16 @@ When the Nomad Network page node is enabled, releases are displayed on a dedicat
|
||||
**All Command-Line Options (rngit release)**
|
||||
|
||||
```text
|
||||
usage: rngit release [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-v] [-q] [--version]
|
||||
[repository] [operation] [target]
|
||||
usage: python -m RNS.Utilities.rngit.server [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-s PATH] [-n name] [-L]
|
||||
[-o] [-v] [-q] [--version]
|
||||
[repository] [operation] [target]
|
||||
|
||||
Reticulum Git Release Manager
|
||||
|
||||
positional arguments:
|
||||
repository URL of remote repository
|
||||
operation list, view, create or delete
|
||||
repository URL of remote repository, or path to RSM manifest
|
||||
operation list, view, fetch, create, latest or delete
|
||||
target tag and path to release artifacts directory
|
||||
|
||||
options:
|
||||
@@ -764,6 +1044,10 @@ options:
|
||||
--rnsconfig RNSCONFIG
|
||||
path to alternative Reticulum config directory
|
||||
-i, --identity PATH path to release identity
|
||||
-s, --signer PATH path to signing identity, if different from release identity
|
||||
-n, --name name package name if different from repo name
|
||||
-L, --local generate release locally, but don't upload
|
||||
-o, --offline verify manifest locally, but don't fetch updates
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
@@ -966,7 +1250,32 @@ Each document is a numbered directory containing:
|
||||
|
||||
**Nomad Network Interface**
|
||||
|
||||
When the Nomad Network page node is enabled, work documents are viewable through the web interface. The work page lists all documents with their status, and clicking a document shows its full content and updates.
|
||||
When the Nomad Network page node is enabled, work documents are viewable through the nomadnet interface. The work page lists all documents with their status, and clicking a document shows its full content and updates.
|
||||
|
||||
### Cryptographic Attribution
|
||||
|
||||
Every work document is cryptographically signed by its creator using their Reticulum identity. When you create or edit a document, `rngit` generates an Ed25519 signature of the content, which is stored alongside the document contents and verified by the remote node, or locally when viewing the work document through the command-line interface. This provides two essential guarantees:
|
||||
|
||||
- **Attribution:** Every document and comment can be cryptographically attributed to its actual author
|
||||
- **Integrity:** Any modification to the content after creation would invalidate the signature
|
||||
|
||||
When viewing a work document, the signature validation status is displayed:
|
||||
|
||||
```text
|
||||
Author : 9710b86ba12c42d1d8f30f74fe509286 (not locally validated)
|
||||
Signature : Document not signed
|
||||
```
|
||||
|
||||
Or, for valid signatures:
|
||||
|
||||
```text
|
||||
Author : <9710b86ba12c42d1d8f30f74fe509286>
|
||||
Signature : Valid
|
||||
```
|
||||
|
||||
The “Valid” status indicates that the document content matches the author’s signature, and that the signing identity corresponds to the stated author. This can be used to create tamper-proof records of project decisions, investigations, and discussions that cannot be repudiated, or modified by third parties without detection.
|
||||
|
||||
This cryptographic provenance is particularly valuable for distributed teams operating across trust boundaries. Because signatures are verified using the author’s Reticulum identity public keys - which can be recalled from any transport node on the network - work documents provide authoritative records of who said what, and when, without requiring a central authority to notarize or validate the communication. Even if the repository node hosting the documents becomes unavailable, the signed document files themselves retain validity and can be verified independently using standard Reticulum identity tools.
|
||||
|
||||
**All Command-Line Options (rngit work)**
|
||||
|
||||
@@ -995,4 +1304,104 @@ options:
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
```
|
||||
```
|
||||
|
||||
## Commit Signing
|
||||
|
||||
The `rngit` system includes `rngcs`, a Git commit signing and validation shim that enables commit signing and validation using Reticulum identities. By hooking into Git’s SSH-based signing format, commits can be signed and verified using Reticulum identity keys directly.
|
||||
|
||||
Unlike traditional GPG and SSH-based commit signing, which relies on centralized keyservers, cumbersome co-signing procedures or manual per-signer setup, Reticulum commit signing uses self-contained RSG signatures, that can be deterministically resolved to Reticulum identity hashes.
|
||||
|
||||
This enables offline verification with no external infrastructure. The signature itself contains everything needed to cryptographically verify the signer’s Reticulum identity and that the commit was signed correctly by the claimed identity.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before you can sign commits, you need a Reticulum identity with a private key. If you don’t already have one, you can generate it using `rnid`:
|
||||
|
||||
```text
|
||||
$ rnid -g ~/.rngit/client_identity
|
||||
|
||||
New identity <1a54d64db7e8beca6f2c6cd17b0cb479> written to /home/user/.rngit/client_identity
|
||||
```
|
||||
|
||||
The identity file must contain the private key to be usable for signing. The corresponding Reticulum identity hash will be used as the commit author identity.
|
||||
|
||||
### Configuration
|
||||
|
||||
Git must be configured to use SSH-format signatures with the `rngcs` signing shim, which is included in RNS. You can configure this either globally or per-repository.
|
||||
|
||||
**Global Configuration**
|
||||
|
||||
Enabling Reticulum commit signing for all repositories is as simple as:
|
||||
|
||||
```text
|
||||
$ git config --global gpg.format ssh
|
||||
$ git config --global gpg.ssh.program rngcs
|
||||
$ git config --global gpg.ssh.allowedsignersfile none
|
||||
$ git config --global user.signingKey ~/.rngit/client_identity
|
||||
```
|
||||
|
||||
With this configuration, all commits you sign with `git commit -S` will use your Reticulum identity.
|
||||
|
||||
#### NOTE
|
||||
The `gpg.ssh.allowedsignersfile` configuration key **must** be *set* for `git` to allow invoking the signing and verification shim. It is not actually used by `rngcs`, and can be set to an arbitrary value. All validation operations happen exclusively based on the information in the embedded RSG data.
|
||||
|
||||
**Per-Repository Configuration**
|
||||
|
||||
To enable signing only for a specific repository:
|
||||
|
||||
```text
|
||||
$ cd /path/to/repository
|
||||
$ git config --local gpg.format ssh
|
||||
$ git config --local gpg.ssh.program rngcs
|
||||
$ git config --local gpg.ssh.allowedsignersfile none
|
||||
$ git config --local user.signingKey ~/.rngit/client_identity
|
||||
```
|
||||
|
||||
This is useful when you want to use different identities for different projects, or when only specific repositories require signed commits.
|
||||
|
||||
### Author Identity Binding
|
||||
|
||||
For the signature to be valid, the Git author email **must** match the Reticulum identity hash of the signing key. You can configure this using a command like the following:
|
||||
|
||||
```text
|
||||
$ git config --global user.email "1a54d64db7e8beca6f2c6cd17b0cb479"
|
||||
```
|
||||
|
||||
When `rngcs` verifies a commit, it extracts both the Git author field of the signed commit message and the signer identity from the RSG signature, ensuring they match. This binding is necessary to prevent identity spoofing. If someone crafts a commit with your identity hash in the author field but signs with a different key, verification will fail.
|
||||
|
||||
### Signing Commits
|
||||
|
||||
Once configured, sign commits using the standard Git `-S` flag:
|
||||
|
||||
```text
|
||||
$ git commit -S -m "Refactored module"
|
||||
|
||||
[master 8f7e6d5] Refactored module
|
||||
```
|
||||
|
||||
This will create a self-contained RSG-formatted signature, encode the RSG payload using base64, and wrap it in an ASCII-armored SSH-formatted signature block. The signature is then stored in the commit object’s signature header and includes:
|
||||
|
||||
- The SHA256 hash of the commit content
|
||||
- The signer’s Reticulum identity hash
|
||||
- The signer’s public key
|
||||
- The actual signature of the complete envelope
|
||||
|
||||
### Validating Commit Signatures
|
||||
|
||||
Commits are automatically validated when using `git log --show-signature` or `git show --show-signature`. The `rngcs` shim handles all verification operations. If any step fails, verification fails and Git displays an error.
|
||||
|
||||
To view signature information for commits, use Git’s standard `--show-signature` option:
|
||||
|
||||
```text
|
||||
$ git log --show-signature
|
||||
|
||||
commit 8f7e6d5c8f7e6d5c8f7e6d5c8f7e6d5c8f7e6d5
|
||||
Good "git" signature for commit, signed with Reticulum Identity key <1a54d64db7e8beca6f2c6cd17b0cb479>
|
||||
Author: Developer <1a54d64db7e8beca6f2c6cd17b0cb479>
|
||||
Date: Mon Jan 15 09:30:00 2026 +0100
|
||||
|
||||
Refactored module
|
||||
```
|
||||
|
||||
The output shows whether the commit signature is valid, and whether the author field matches the signing identity.
|
||||
@@ -189,6 +189,17 @@ to participate in the development of Reticulum itself.
|
||||
* [Transport Nodes and Instances](networks.md#transport-nodes-and-instances)
|
||||
* [Trustless Networking](networks.md#trustless-networking)
|
||||
* [Heterogeneous Connectivity](networks.md#heterogeneous-connectivity)
|
||||
* [Distributed Development](distributed.md)
|
||||
* [The Original Architecture](distributed.md#the-original-architecture)
|
||||
* [The Platform Interregnum](distributed.md#the-platform-interregnum)
|
||||
* [Restoration](distributed.md#restoration)
|
||||
* [Protocols Over Platforms](distributed.md#protocols-over-platforms)
|
||||
* [Sovereignty Through Infrastructure](distributed.md#sovereignty-through-infrastructure)
|
||||
* [Artifact-Centered Workflows](distributed.md#artifact-centered-workflows)
|
||||
* [Composable Primitives](distributed.md#composable-primitives)
|
||||
* [Distribution Without Intermediaries](distributed.md#distribution-without-intermediaries)
|
||||
* [Long Archive](distributed.md#long-archive)
|
||||
* [Start Of The Road](distributed.md#start-of-the-road)
|
||||
* [Git Over Reticulum](git.md)
|
||||
* [The rngit Utility](git.md#the-rngit-utility)
|
||||
* [Repository Creation & Management](git.md#repository-creation-management)
|
||||
@@ -209,6 +220,10 @@ to participate in the development of Reticulum itself.
|
||||
* [Permission Examples](git.md#permission-examples)
|
||||
* [Permission Short Forms](git.md#permission-short-forms)
|
||||
* [Permission Configuration Locations](git.md#permission-configuration-locations)
|
||||
* [Remote Permission Management](git.md#remote-permission-management)
|
||||
* [Managing Group Permissions](git.md#managing-group-permissions)
|
||||
* [Managing Repository Permissions](git.md#managing-repository-permissions)
|
||||
* [Permission Validation](git.md#permission-validation)
|
||||
* [Identity & Destination Aliases](git.md#identity-destination-aliases)
|
||||
* [Serving Pages Over Nomad Network](git.md#serving-pages-over-nomad-network)
|
||||
* [Enabling the Git Page Node](git.md#enabling-the-git-page-node)
|
||||
@@ -217,6 +232,10 @@ to participate in the development of Reticulum itself.
|
||||
* [Customizing Templates](git.md#customizing-templates)
|
||||
* [Repository Statistics](git.md#repository-statistics)
|
||||
* [Configuration Example](git.md#configuration-example)
|
||||
* [Verified Releases](git.md#verified-releases)
|
||||
* [Obtaining Verified Releases](git.md#obtaining-verified-releases)
|
||||
* [Offline Verification](git.md#offline-verification)
|
||||
* [Creating Signed Releases](git.md#creating-signed-releases)
|
||||
* [Release Management](git.md#release-management)
|
||||
* [The Release Workflow](git.md#the-release-workflow)
|
||||
* [Release Storage & Structure](git.md#release-storage-structure)
|
||||
@@ -226,6 +245,13 @@ to participate in the development of Reticulum itself.
|
||||
* [Proposing Work Documents](git.md#proposing-work-documents)
|
||||
* [State Management](git.md#state-management)
|
||||
* [Managing Work Document Permissions](git.md#managing-work-document-permissions)
|
||||
* [Cryptographic Attribution](git.md#cryptographic-attribution)
|
||||
* [Commit Signing](git.md#commit-signing)
|
||||
* [Prerequisites](git.md#prerequisites)
|
||||
* [Configuration](git.md#id1)
|
||||
* [Author Identity Binding](git.md#author-identity-binding)
|
||||
* [Signing Commits](git.md#signing-commits)
|
||||
* [Validating Commit Signatures](git.md#validating-commit-signatures)
|
||||
* [Support Reticulum](support.md)
|
||||
* [Donations](support.md#donations)
|
||||
* [Provide Feedback](support.md#provide-feedback)
|
||||
|
||||
+36
-36
@@ -901,10 +901,10 @@ When `discoverable` is enabled, a variety of additional options become available
|
||||
|
||||
`reachable_on`
|
||||
: Specifies the address that remote peers should use to connect to this interface.
|
||||
<br/>
|
||||
|
||||
* For TCP and Backbone interfaces, this is typically the public IP address or hostname. Do not include the port, this is fetched automatically from the interface.
|
||||
* For I2P interfaces, this is usually the I2P `b32` address. This value is fetched automatically from the `I2PInterface` once it is up and connected to the I2P network, so you should not set this manually, unless you absolutely know what you’re doing.
|
||||
<br/>
|
||||
|
||||
**Dynamic Resolution:** This option also accepts a path to an external executable script or binary. If a path is provided, Reticulum will execute the script and use its `stdout` as the reachability address. This is useful for devices behind dynamic DNS, NATs, or complex cloud environments where the external IP is not known locally. The script must simply print the address to stdout and exit.
|
||||
|
||||
#### NOTE
|
||||
@@ -1064,10 +1064,10 @@ These can be used to control various aspects of interface behaviour.
|
||||
> to bring up the interface. Defaults to `False`. For any
|
||||
> interface to be brought up, the `enabled` option
|
||||
> must be set to `True` or `Yes`.
|
||||
> <br/>
|
||||
>
|
||||
> * The `mode` option allows selecting the high-level behaviour
|
||||
> of the interface from a number of options.
|
||||
> <br/>
|
||||
>
|
||||
> > - The default value is `full`. In this mode, all discovery,
|
||||
> > meshing and transport functionality is available.
|
||||
> > - In the `access_point` (or shorthand `ap`) mode, the
|
||||
@@ -1083,15 +1083,15 @@ These can be used to control various aspects of interface behaviour.
|
||||
> * The `outgoing` option sets whether an interface is allowed
|
||||
> to transmit. Defaults to `True`. If set to `False` or `No`
|
||||
> the interface will only receive data, and never transmit.
|
||||
> <br/>
|
||||
>
|
||||
> * The `network_name` option sets the virtual network name for
|
||||
> the interface. This allows multiple separate network segments
|
||||
> to exist on the same physical channel or medium.
|
||||
> <br/>
|
||||
>
|
||||
> * The `passphrase` option sets an authentication passphrase on
|
||||
> the interface. This option can be used in conjunction with the
|
||||
> `network_name` option, or be used alone.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ifac_size` option allows customising the length of the
|
||||
> Interface Authentication Codes carried by each packet on named
|
||||
> and/or authenticated network segments. It is set by default to
|
||||
@@ -1099,13 +1099,13 @@ These can be used to control various aspects of interface behaviour.
|
||||
> to a custom size between 8 and 512 bits by using this option.
|
||||
> In normal usage, this option should not be changed from the
|
||||
> default.
|
||||
> <br/>
|
||||
>
|
||||
> * The `announce_cap` option lets you configure the maximum
|
||||
> bandwidth to allocate, at any given time, to propagating
|
||||
> announces and other network upkeep traffic. It is configured at
|
||||
> 2% by default, and should normally not need to be changed. Can
|
||||
> be set to any value between `1` and `100`.
|
||||
> <br/>
|
||||
>
|
||||
> > *If an interface exceeds its announce cap, it will queue announces
|
||||
> > for later transmission. Reticulum will always prioritise propagating
|
||||
> > announces from nearby nodes first. This ensures that the local
|
||||
@@ -1126,7 +1126,7 @@ These can be used to control various aspects of interface behaviour.
|
||||
> any. In most cases, the automatically found rate should be
|
||||
> sufficient, but it can be configured by using the `bitrate`
|
||||
> option, to set the interface speed in *bits per second*.
|
||||
> <br/>
|
||||
>
|
||||
> * The `bootstrap_only` option designates an interface as a temporary
|
||||
> bridge for initial connectivity. If this option is enabled, the
|
||||
> interface will be monitored and automatically detached once the
|
||||
@@ -1135,7 +1135,7 @@ These can be used to control various aspects of interface behaviour.
|
||||
> for using a slow or expensive connection (such as a single LoRa
|
||||
> link or a remote TCP tunnel) solely to discover better local
|
||||
> infrastructure, which then supersedes the bootstrap interface.
|
||||
> <br/>
|
||||
>
|
||||
|
||||
## Interface Modes
|
||||
|
||||
@@ -1152,7 +1152,7 @@ the default mode.
|
||||
|
||||
> * The default mode is `full`. In this mode, all discovery,
|
||||
> meshing and transport functionality is activated.
|
||||
> <br/>
|
||||
>
|
||||
> * The `gateway` mode (or shorthand `gw`) also has all
|
||||
> discovery, meshing and transport functionality available,
|
||||
> but will additionally try to discover unknown paths on
|
||||
@@ -1162,18 +1162,18 @@ the default mode.
|
||||
> will try to discover this path via all other active interfaces,
|
||||
> and forward the discovered path to the requestor if one is
|
||||
> found.
|
||||
> <br/>
|
||||
>
|
||||
> If you want to allow other nodes to widely resolve paths or connect
|
||||
> to a network via an interface, it might be useful to put it in this
|
||||
> mode. By creating a chain of `gateway` interfaces, other
|
||||
> nodes will be able to immediately discover paths to any
|
||||
> destination along the chain.
|
||||
> <br/>
|
||||
>
|
||||
> *Please note!* It is the interface *facing the clients* that
|
||||
> must be put into `gateway` mode for this to work, not
|
||||
> the interface facing the wider network (for this, the `boundary`
|
||||
> mode can be useful, though).
|
||||
> <br/>
|
||||
>
|
||||
> * In the `access_point` (or shorthand `ap`) mode, the
|
||||
> interface will operate as a network access point. In this
|
||||
> mode, announces will not be automatically broadcasted on
|
||||
@@ -1181,13 +1181,13 @@ the default mode.
|
||||
> will have a much shorter expiry time. In addition, path
|
||||
> requests from clients on the access point interface will
|
||||
> be handled in the same way as the `gateway` interface.
|
||||
> <br/>
|
||||
>
|
||||
> This mode is useful for creating interfaces that remain
|
||||
> quiet, until someone actually starts using them. An example
|
||||
> of this could be a radio interface serving a wide area,
|
||||
> where users are expected to connect momentarily, use the
|
||||
> network, and then disappear again.
|
||||
> <br/>
|
||||
>
|
||||
> * The `roaming` mode should be used on interfaces that are
|
||||
> roaming (physically mobile), seen from the perspective of
|
||||
> other nodes in the network. As an example, if a vehicle is
|
||||
@@ -1202,7 +1202,7 @@ the default mode.
|
||||
> side of the network will also be able to reach devices
|
||||
> internal to the vehicle, when it is in range. Paths via
|
||||
> `roaming` interfaces also expire faster.
|
||||
> <br/>
|
||||
>
|
||||
> * The purpose of the `boundary` mode is to specify interfaces
|
||||
> that establish connectivity with network segments that are
|
||||
> significantly different than the one this node exists on.
|
||||
@@ -1210,7 +1210,7 @@ the default mode.
|
||||
> network, but also has a high-speed connection to a
|
||||
> public Transport Node available on the Internet, the interface
|
||||
> connecting over the Internet should be set to `boundary` mode.
|
||||
> <br/>
|
||||
>
|
||||
|
||||
For a table describing the impact of all modes on announce propagation,
|
||||
please see the [Announce Propagation Rules](understanding.md#understanding-announcepropagation) section.
|
||||
@@ -1233,16 +1233,16 @@ re-broadcasted to other interfaces*.
|
||||
> announces *received* on this interface will only be re-transmitted and
|
||||
> propagated to other interfaces once every hour, no matter how often they
|
||||
> are received.
|
||||
> <br/>
|
||||
>
|
||||
> * The optional `announce_rate_grace` defines the number of times a destination
|
||||
> can violate the announce rate before the target rate is enforced.
|
||||
> <br/>
|
||||
>
|
||||
> * The optional `announce_rate_penalty` configures an extra amount of
|
||||
> time that is added to the normal rate target. As an example, if a penalty
|
||||
> of `7200` seconds is defined, once the rate target is enforced, the
|
||||
> destination in question will only have its announces propagated every
|
||||
> 3 hours, until it lowers its actual announce rate to within the target.
|
||||
> <br/>
|
||||
>
|
||||
|
||||
You can also configure default announce rate parameters for all interfaces that
|
||||
do not have these parameters set explicitly by setting the `default_ar_target`
|
||||
@@ -1309,41 +1309,41 @@ but all the parameters are exposed for configuration if needed.
|
||||
|
||||
> * The `ingress_control` option tells Reticulum whether or not
|
||||
> to enable ingress control on the interface. Defaults to `True`.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ic_new_time` option configures how long (in seconds) an
|
||||
> interface is considered newly spawned. Defaults to `2*60*60` seconds. This
|
||||
> option is useful on publicly accessible interfaces that spawn new
|
||||
> sub-interfaces when a new client connects.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ic_burst_freq_new` option sets the maximum announce ingress
|
||||
> frequency for newly spawned interfaces. Defaults to `3.5`
|
||||
> announces per second.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ic_burst_freq` option sets the maximum announce ingress
|
||||
> frequency for other interfaces. Defaults to `12` announces
|
||||
> per second.
|
||||
> <br/>
|
||||
>
|
||||
> > *If an interface exceeds its burst frequency, incoming announces
|
||||
> > for unknown destinations will be temporarily held in a queue, and
|
||||
> > not processed until later.*
|
||||
> * The `ic_max_held_announces` option sets the maximum amount of
|
||||
> unique announces that will be held in the queue. Any additional
|
||||
> unique announces will be dropped. Defaults to `256` announces.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ic_burst_hold` option sets how much time (in seconds) must
|
||||
> pass after the burst frequency drops below its threshold, for the
|
||||
> announce burst to be considered cleared. Defaults to `60`
|
||||
> seconds.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ic_burst_penalty` option sets how much time (in seconds) must
|
||||
> pass after the burst is considered cleared, before held announces can
|
||||
> start being released from the queue. Defaults to `5*60`
|
||||
> seconds.
|
||||
> <br/>
|
||||
>
|
||||
> * 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/>
|
||||
>
|
||||
|
||||
All of the above settings can be configured both as instance-wide defaults
|
||||
under the `[reticulum]` section of the configuration file, or on a per-
|
||||
@@ -1373,28 +1373,28 @@ but all the parameters are exposed for configuration if needed.
|
||||
|
||||
> * The `ingress_control` option tells Reticulum whether or not
|
||||
> to enable ingress control on the interface. Defaults to `True`.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ic_new_time` option configures how long (in seconds) an
|
||||
> interface is considered newly spawned. Defaults to `2*60*60` seconds. This
|
||||
> option is useful on publicly accessible interfaces that spawn new
|
||||
> sub-interfaces when a new client connects.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ic_pr_burst_freq_new` option sets the maximum path request
|
||||
> ingress frequency for newly spawned interfaces. Defaults to `3`
|
||||
> path requests per second.
|
||||
> <br/>
|
||||
>
|
||||
> * The `ic_pr_burst_freq` option sets the maximum path request
|
||||
> ingress frequency for other interfaces. Defaults to `8` path requests
|
||||
> per second.
|
||||
> <br/>
|
||||
>
|
||||
> > *If an interface exceeds its burst frequency, incoming path requests
|
||||
> > from that system will not traverse the network further.*
|
||||
> * The `egress_control` option enables hard-limiting path request egress
|
||||
> control per-interface. Defaults to `False`
|
||||
> <br/>
|
||||
>
|
||||
> * The `ec_pr_freq` option sets the hard limit for outbound path requests
|
||||
> per second on a given interface.
|
||||
> <br/>
|
||||
>
|
||||
|
||||
All of the above settings can be configured both as instance-wide defaults
|
||||
under the `[reticulum]` section of the configuration file, or on a per-
|
||||
|
||||
@@ -46,11 +46,11 @@ with Reticulum:
|
||||
> (called *destinations* in Reticulum terminology) as it needs, which become
|
||||
> globally reachable to the rest of the network. There is no central point of
|
||||
> control over the address space.
|
||||
> <br/>
|
||||
>
|
||||
> * Reticulum was designed to handle both very small, and very large networks.
|
||||
> While the address space can support billions of endpoints, Reticulum is
|
||||
> also very useful when just a few devices needs to communicate.
|
||||
> <br/>
|
||||
>
|
||||
> * Low-bandwidth networks, like LoRa and packet radio, can interoperate and
|
||||
> interconnect with much larger and higher bandwidth networks without issue.
|
||||
> Reticulum automatically manages the flow of information to and from various
|
||||
@@ -60,27 +60,27 @@ with Reticulum:
|
||||
> it will try as best as possible to comply with this, while still respecting
|
||||
> bandwidth limits, but you *will* waste a lot of precious bandwidth and airtime,
|
||||
> and your LoRa network will not work very well.
|
||||
> <br/>
|
||||
>
|
||||
> * Reticulum provides sender/initiator anonymity by default. There is no way
|
||||
> to filter traffic or discriminate it based on the source of the traffic.
|
||||
> <br/>
|
||||
>
|
||||
> * All traffic is encrypted using ephemeral keys generated by an Elliptic Curve
|
||||
> Diffie-Hellman key exchange on Curve25519. There is no way to inspect traffic
|
||||
> contents, and no way to prioritise or throttle certain kinds of traffic.
|
||||
> All transport and routing layers are thus completely agnostic to traffic type,
|
||||
> and will pass all traffic equally.
|
||||
> <br/>
|
||||
>
|
||||
> * Reticulum can function both with and without infrastructure. When *transport
|
||||
> nodes* are available, they can route traffic over multiple hops for other
|
||||
> nodes, and will function as a distributed cryptographic keystore. When there
|
||||
> is no transport nodes available, all nodes that are within communication range
|
||||
> can still communicate.
|
||||
> <br/>
|
||||
>
|
||||
> * Every node can become a transport node, simply by enabling it in it’s
|
||||
> configuration, but there is no need for every node on the network to be a
|
||||
> transport node. Letting every node be a transport node will in most cases
|
||||
> degrade the performance and reliability of the network.
|
||||
> <br/>
|
||||
>
|
||||
> > *In general terms, if a node is stationary, well-connected and kept running
|
||||
> > most of the time, it is a good candidate to be a transport node. For optimal
|
||||
> > performance, a network should contain the amount of transport nodes that
|
||||
@@ -92,14 +92,14 @@ with Reticulum:
|
||||
> entirely new, and so far, mostly unexplored class of networked applications,
|
||||
> where networks, and the information flow within them can form and dissolve
|
||||
> organically.
|
||||
> <br/>
|
||||
>
|
||||
> * You can just as easily create closed networks, since Reticulum allows you to
|
||||
> add authentication to any interface. This means you can restrict access on
|
||||
> any interface type, even when using legacy devices, such as modems. You can
|
||||
> also mix authenticated and open interfaces on the same system. See the
|
||||
> [Common Interface Options](interfaces.md#interfaces-options) section of the [Interfaces](interfaces.md#interfaces-main)
|
||||
> chapter of this manual for information on how to set up interface authentication.
|
||||
> <br/>
|
||||
>
|
||||
|
||||
Reticulum allows you to mix very different kinds of networking mediums into a
|
||||
unified mesh, or to keep everything within one medium. You could build a “virtual
|
||||
@@ -142,16 +142,19 @@ This has profound implications for network design:
|
||||
* **No address allocation planning:** You never need to reserve address ranges,
|
||||
plan subnets, or coordinate with other network operators. Nodes simply generate
|
||||
destinations and announce them.
|
||||
|
||||
* **Global portability:** A destination is not tied to a physical location or
|
||||
network segment. A node can move its destinations across interfaces, mediums,
|
||||
or even between entirely separate Reticulum networks simply by sending an
|
||||
announce on the new medium.
|
||||
|
||||
* **Implicit authentication:** Because destinations are bound to public keys,
|
||||
communication to a destination is inherently cryptographically authenticated.
|
||||
Only the holder of the corresponding private key can decrypt and respond to
|
||||
traffic addressed to that destination. This also makes application-level
|
||||
authentication *much* simpler, since it can directly use the foundational
|
||||
identity verification built into the core networking layer.
|
||||
|
||||
* **Identity abstraction:** A single Reticulum Identity can create multiple
|
||||
destinations. This allows a single entity (a person, a device, a service) to
|
||||
present multiple endpoints without needing multiple cryptographic keypairs.
|
||||
@@ -191,9 +194,11 @@ The distinction is important. **Not** every node should be a Transport Node:
|
||||
* **Resource consumption:** Transport nodes maintain path tables, process
|
||||
announces, and forward traffic. This requires memory and CPU resources that
|
||||
may be limited on low-powered devices.
|
||||
|
||||
* **Stability requirements:** Transport nodes contribute to network convergence.
|
||||
If Transport Nodes frequently go offline, path tables become stale and
|
||||
convergence suffers. Stable, always-on nodes make better Transport Nodes.
|
||||
|
||||
* **Bandwidth considerations:** Transport nodes process and rebroadcast network
|
||||
maintenance traffic. On very low-bandwidth mediums, having too many Transport
|
||||
Nodes will consume capacity that should be used for actual data.
|
||||
@@ -228,15 +233,19 @@ of communication is secured cryptographically:
|
||||
|
||||
* **Traffic encryption:** All traffic to single destinations is encrypted using
|
||||
ephemeral keys.
|
||||
|
||||
* **Source anonymity:** Reticulum packets do not include source addresses.
|
||||
An observer intercepting a packet cannot determine who sent it, only who it is
|
||||
addressed to (unless IFAC is enabled, in which case nothing can be determined).
|
||||
This provides initiator anonymity by default.
|
||||
|
||||
* **Path verification:** The announce mechanism includes cryptographic signatures that
|
||||
prove the authenticity of destination announcements.
|
||||
|
||||
* **Unforgeable delivery confirmations:** When a destination proves receipt of a
|
||||
packet, the proof is signed with the destination’s identity key. This prevents
|
||||
false acknowledgments and ensures reliable delivery verification.
|
||||
|
||||
* **Interface authentication:** When using Interface Access Codes (IFAC), packets
|
||||
on authenticated interfaces carry signatures derived from a shared secret. Only
|
||||
nodes with the correct network name and passphrase can generate valid packets, allowing creation
|
||||
@@ -248,10 +257,12 @@ The trustless design has important consequences for network design:
|
||||
join without pre-approval. Because traffic is encrypted and authenticated end-
|
||||
to-end, participants cannot interfere with each other’s private communication,
|
||||
even if they share the same transport infrastructure.
|
||||
|
||||
* **No traffic inspection or prioritization:** Because traffic contents and
|
||||
sources are opaque to intermediate nodes, there is no mechanism for filtering,
|
||||
prioritizing, or throttling traffic based on its type or origin. All traffic
|
||||
is treated equally. From a neutrality perspective, this is a feature.
|
||||
|
||||
* **Adversarial resilience:** The network can operate even if some nodes are
|
||||
malicious or controlled by adversaries. While a malicious Transport Node could
|
||||
refuse to forward certain traffic or drop packets, it cannot decrypt, modify,
|
||||
@@ -280,12 +291,15 @@ to seamlessly mix mediums with vastly different characteristics:
|
||||
interconnect with gigabit Ethernet backbones. Reticulum automatically manages
|
||||
the flow of information, prioritizing local traffic on slow segments while
|
||||
allowing global convergence.
|
||||
|
||||
* **Latency:** Satellite links with multi-second latency can coexist with local
|
||||
links measured in milliseconds. The transport system handles timing, asynchronous
|
||||
delivery and retransmissions transparently.
|
||||
|
||||
* **Topology:** Point-to-point microwave links, broadcast radio networks,
|
||||
switched Ethernet fabrics, and virtual tunnels over the Internet can all be
|
||||
part of the same Reticulum network.
|
||||
|
||||
* **Reliability:** Intermittent connections that come and go (such as mobile
|
||||
devices or opportunistic radio contacts) can participate alongside always-on
|
||||
infrastructure. Reticulum gracefully handles link loss and reconnection.
|
||||
@@ -295,12 +309,15 @@ This heterogeneity is achieved through several design elements:
|
||||
* **Expandable, medium-agnostic interface system:** Reticulum communicates with the physical
|
||||
world through interface modules. Adding support for a new medium is a matter
|
||||
of implementing an interface class. The protocol itself remains unchanged.
|
||||
|
||||
* **Interface modes:** Different modes (`full`, `gateway`, `access_point`,
|
||||
`roaming`, `boundary`) allow you to configure how interfaces interact with
|
||||
the wider network based on their characteristics and role.
|
||||
|
||||
* **Announce propagation rules:** Announces are forwarded between interfaces
|
||||
according to rules that account for bandwidth limitations and interface modes.
|
||||
Slow segments are not overwhelmed by traffic from fast segments.
|
||||
|
||||
* **Local traffic prioritization:** When bandwidth is constrained, Reticulum
|
||||
prioritizes announces for nearby destinations. This ensures that local
|
||||
connectivity remains functional even when global convergence is incomplete.
|
||||
|
||||
@@ -198,6 +198,7 @@ search for an identity from a known *identity hash*, by setting the
|
||||
* **Parameters:**
|
||||
* **target_hash** – Destination or identity hash as *bytes*.
|
||||
* **from_identity_hash** – Whether to search based on identity hash instead of destination hash as *bool*.
|
||||
|
||||
* **Returns:**
|
||||
An [RNS.Identity](#api-identity) instance that can be used to create an outgoing [RNS.Destination](#api-destination), or *None* if the destination is unknown.
|
||||
|
||||
@@ -207,6 +208,7 @@ Recall last heard app_data for a destination hash.
|
||||
|
||||
* **Parameters:**
|
||||
**destination_hash** – Destination hash as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
*Bytes* containing app_data, or *None* if the destination is unknown.
|
||||
|
||||
@@ -216,6 +218,7 @@ Get a SHA-256 hash of passed data.
|
||||
|
||||
* **Parameters:**
|
||||
**data** – Data to be hashed as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
SHA-256 hash as *bytes*.
|
||||
|
||||
@@ -225,6 +228,7 @@ Get a truncated SHA-256 hash of passed data.
|
||||
|
||||
* **Parameters:**
|
||||
**data** – Data to be hashed as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
Truncated SHA-256 hash as *bytes*.
|
||||
|
||||
@@ -234,6 +238,7 @@ Get a random SHA-256 hash.
|
||||
|
||||
* **Parameters:**
|
||||
**data** – Data to be hashed as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
Truncated SHA-256 hash of random data as *bytes*.
|
||||
|
||||
@@ -243,6 +248,7 @@ Get the ID of the currently used ratchet key for a given destination hash
|
||||
|
||||
* **Parameters:**
|
||||
**destination_hash** – A destination hash as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
A ratchet ID as *bytes* or *None*.
|
||||
|
||||
@@ -253,6 +259,7 @@ Can be used to load previously created and saved identities into Reticulum.
|
||||
|
||||
* **Parameters:**
|
||||
**prv_bytes** – The *bytes* of private a saved private key. **HAZARD!** Never use this to generate a new key by feeding random data in prv_bytes.
|
||||
|
||||
* **Returns:**
|
||||
A [RNS.Identity](#api-identity) instance, or *None* if the *bytes* data was invalid.
|
||||
|
||||
@@ -263,6 +270,7 @@ Can be used to load previously created and saved identities into Reticulum.
|
||||
|
||||
* **Parameters:**
|
||||
**path** – The full path to the saved [RNS.Identity](#api-identity) data
|
||||
|
||||
* **Returns:**
|
||||
A [RNS.Identity](#api-identity) instance, or *None* if the loaded data was invalid.
|
||||
|
||||
@@ -274,6 +282,7 @@ communication for the identity. Be very careful with this method.
|
||||
|
||||
* **Parameters:**
|
||||
**path** – The full path specifying where to save the identity.
|
||||
|
||||
* **Returns:**
|
||||
True if the file was saved, otherwise False.
|
||||
|
||||
@@ -283,6 +292,7 @@ Saves the public identity to a file.
|
||||
|
||||
* **Parameters:**
|
||||
**path** – The full path specifying where to save the identity.
|
||||
|
||||
* **Returns:**
|
||||
True if the file was saved, otherwise False.
|
||||
|
||||
@@ -302,6 +312,7 @@ Load a private key into the instance.
|
||||
|
||||
* **Parameters:**
|
||||
**prv_bytes** – The private key as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
True if the key was loaded, otherwise False.
|
||||
|
||||
@@ -311,6 +322,7 @@ Load a public key into the instance.
|
||||
|
||||
* **Parameters:**
|
||||
**pub_bytes** – The public key as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
True if the key was loaded, otherwise False.
|
||||
|
||||
@@ -320,8 +332,10 @@ Encrypts information for the identity.
|
||||
|
||||
* **Parameters:**
|
||||
**plaintext** – The plaintext to be encrypted as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
Ciphertext token as *bytes*.
|
||||
|
||||
* **Raises:**
|
||||
*KeyError* if the instance does not hold a public key.
|
||||
|
||||
@@ -331,8 +345,10 @@ Decrypts information for the identity.
|
||||
|
||||
* **Parameters:**
|
||||
**ciphertext** – The ciphertext to be decrypted as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
Plaintext as *bytes*, or *None* if decryption fails.
|
||||
|
||||
* **Raises:**
|
||||
*KeyError* if the instance does not hold a private key.
|
||||
|
||||
@@ -342,8 +358,10 @@ Signs information by the identity.
|
||||
|
||||
* **Parameters:**
|
||||
**message** – The message to be signed as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
Signature as *bytes*.
|
||||
|
||||
* **Raises:**
|
||||
*KeyError* if the instance does not hold a private key.
|
||||
|
||||
@@ -354,8 +372,10 @@ Validates the signature of a signed message.
|
||||
* **Parameters:**
|
||||
* **signature** – The signature to be validated as *bytes*.
|
||||
* **message** – The message to be validated as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
True if the signature is valid, otherwise False.
|
||||
|
||||
* **Raises:**
|
||||
*KeyError* if the instance does not hold a public key.
|
||||
|
||||
@@ -418,6 +438,7 @@ Set or query whether the destination accepts incoming link requests.
|
||||
|
||||
* **Parameters:**
|
||||
**accepts** – If `True` or `False`, this method sets whether the destination accepts incoming link requests. If not provided or `None`, the method returns whether the destination currently accepts link requests.
|
||||
|
||||
* **Returns:**
|
||||
`True` or `False` depending on whether the destination accepts incoming link requests, if the *accepts* parameter is not provided or `None`.
|
||||
|
||||
@@ -463,6 +484,7 @@ Registers a request handler.
|
||||
* **allow** – One of `RNS.Destination.ALLOW_NONE`, `RNS.Destination.ALLOW_ALL` or `RNS.Destination.ALLOW_LIST`. If `RNS.Destination.ALLOW_LIST` is set, the request handler will only respond to requests for identified peers in the supplied list.
|
||||
* **allowed_list** – A list of *bytes-like* [RNS.Identity](#api-identity) hashes.
|
||||
* **auto_compress** – If `True` or `False`, determines whether automatic compression of responses should be carried out. If set to an integer value, responses will only be auto-compressed if under this size in bytes. If omitted, the default compression settings will be followed.
|
||||
|
||||
* **Raises:**
|
||||
`ValueError` if any of the supplied arguments are invalid.
|
||||
|
||||
@@ -472,6 +494,7 @@ Deregisters a request handler.
|
||||
|
||||
* **Parameters:**
|
||||
**path** – The path for the request handler to be deregistered.
|
||||
|
||||
* **Returns:**
|
||||
True if the handler was deregistered, otherwise False.
|
||||
|
||||
@@ -489,6 +512,7 @@ Enabling ratchets will have a small impact on announce size, adding 32 bytes to
|
||||
|
||||
* **Parameters:**
|
||||
**ratchets_path** – The path to a file to store ratchet data in.
|
||||
|
||||
* **Returns:**
|
||||
True if the operation succeeded, otherwise False.
|
||||
|
||||
@@ -505,6 +529,7 @@ and try to use when decrypting incoming packets. Defaults to `Destination.RATCHE
|
||||
|
||||
* **Parameters:**
|
||||
**retained_ratchets** – The number of generated ratchets to retain.
|
||||
|
||||
* **Returns:**
|
||||
True if the operation succeeded, False if not.
|
||||
|
||||
@@ -515,6 +540,7 @@ Defaults to `Destination.RATCHET_INTERVAL`.
|
||||
|
||||
* **Parameters:**
|
||||
**interval** – The minimum interval in seconds.
|
||||
|
||||
* **Returns:**
|
||||
True if the operation succeeded, False if not.
|
||||
|
||||
@@ -538,6 +564,7 @@ For a `RNS.Destination.GROUP` type destination, loads a symmetric private key.
|
||||
|
||||
* **Parameters:**
|
||||
**key** – A *bytes-like* containing the symmetric key.
|
||||
|
||||
* **Raises:**
|
||||
`TypeError` if called on an incompatible type of destination.
|
||||
|
||||
@@ -547,6 +574,7 @@ Encrypts information for `RNS.Destination.SINGLE` or `RNS.Destination.GROUP` typ
|
||||
|
||||
* **Parameters:**
|
||||
**plaintext** – A *bytes-like* containing the plaintext to be encrypted.
|
||||
|
||||
* **Raises:**
|
||||
`ValueError` if destination does not hold a necessary key for encryption.
|
||||
|
||||
@@ -556,6 +584,7 @@ Decrypts information for `RNS.Destination.SINGLE` or `RNS.Destination.GROUP` typ
|
||||
|
||||
* **Parameters:**
|
||||
**ciphertext** – *Bytes* containing the ciphertext to be decrypted.
|
||||
|
||||
* **Raises:**
|
||||
`ValueError` if destination does not hold a necessary key for decryption.
|
||||
|
||||
@@ -565,6 +594,7 @@ Signs information for `RNS.Destination.SINGLE` type destination.
|
||||
|
||||
* **Parameters:**
|
||||
**message** – *Bytes* containing the message to be signed.
|
||||
|
||||
* **Returns:**
|
||||
A *bytes-like* containing the message signature, or *None* if the destination could not sign the message.
|
||||
|
||||
@@ -737,6 +767,7 @@ Sends a request to the remote peer.
|
||||
* **failed_callback** – An optional function or method with the signature *failed_callback(request_receipt)* to be called when a request fails. See the [Request Example](examples.md#example-request) for more info.
|
||||
* **progress_callback** – An optional function or method with the signature *progress_callback(request_receipt)* to be called when progress is made receiving the response. Progress can be accessed as a float between 0.0 and 1.0 by the *request_receipt.progress* property.
|
||||
* **timeout** – An optional timeout in seconds for the request. If *None* is supplied it will be calculated based on link RTT.
|
||||
|
||||
* **Returns:**
|
||||
A [RNS.RequestReceipt](#api-requestreceipt) instance if the request was sent, or *False* if it was not.
|
||||
|
||||
@@ -888,6 +919,7 @@ Sets the resource strategy for the link.
|
||||
|
||||
* **Parameters:**
|
||||
**resource_strategy** – One of `RNS.Link.ACCEPT_NONE`, `RNS.Link.ACCEPT_ALL` or `RNS.Link.ACCEPT_APP`. If `RNS.Link.ACCEPT_APP` is set, the resource_callback will be called to determine whether the resource should be accepted or not.
|
||||
|
||||
* **Raises:**
|
||||
*TypeError* if the resource strategy is unsupported.
|
||||
|
||||
@@ -1121,6 +1153,7 @@ of this object, see the Python documentation for
|
||||
* **stream_id** – the local stream id to receive from
|
||||
* **channel** – the channel to receive on
|
||||
* **ready_callback** – function to call when new data is available
|
||||
|
||||
* **Returns:**
|
||||
a BufferedReader object
|
||||
|
||||
@@ -1136,6 +1169,7 @@ of this object, see the Python documentation for
|
||||
* **Parameters:**
|
||||
* **stream_id** – the remote stream id to send to
|
||||
* **channel** – the channel to send on
|
||||
|
||||
* **Returns:**
|
||||
a BufferedWriter object
|
||||
|
||||
@@ -1156,6 +1190,7 @@ of this object, see the Python documentation for
|
||||
* **send_stream_id** – the remote stream id to send to
|
||||
* **channel** – the channel to send and receive on
|
||||
* **ready_callback** – function to call when new data is available
|
||||
|
||||
* **Returns:**
|
||||
a BufferedRWPair object
|
||||
|
||||
@@ -1251,6 +1286,7 @@ Deregisters an announce handler.
|
||||
|
||||
* **Parameters:**
|
||||
**destination_hash** – A destination hash as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
*True* if a path to the destination is known, otherwise *False*.
|
||||
|
||||
@@ -1258,6 +1294,7 @@ Deregisters an announce handler.
|
||||
|
||||
* **Parameters:**
|
||||
**destination_hash** – A destination hash as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
The number of hops to the specified destination, or `RNS.Transport.PATHFINDER_M` if the number of hops is unknown.
|
||||
|
||||
@@ -1265,6 +1302,7 @@ Deregisters an announce handler.
|
||||
|
||||
* **Parameters:**
|
||||
**destination_hash** – A destination hash as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
The destination hash as *bytes* for the next hop to the specified destination, or *None* if the next hop is unknown.
|
||||
|
||||
@@ -1272,6 +1310,7 @@ Deregisters an announce handler.
|
||||
|
||||
* **Parameters:**
|
||||
**destination_hash** – A destination hash as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
The interface for the next hop to the specified destination, or *None* if the interface is unknown.
|
||||
|
||||
@@ -1284,6 +1323,7 @@ blocks until the path is available, or the timeout is reached.
|
||||
* **destination_hash** – A destination hash as *bytes*.
|
||||
* **timeout** – An optional timeout in seconds.
|
||||
* **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.
|
||||
|
||||
* **Returns:**
|
||||
*True* if a path to the destination is found, otherwise *False*.
|
||||
|
||||
@@ -1295,4 +1335,26 @@ 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.
|
||||
|
||||
#### `static blackhole_identity(identity_hash, until=None, reason=None)`
|
||||
|
||||
Blackholes an identity.
|
||||
|
||||
* **Parameters:**
|
||||
* **identity_hash** – The identity hash to blackhole as *bytes*.
|
||||
* **until** – Optional unix timestamp of when the blackhole expires as *float* or *int*.
|
||||
* **reason** – Optional reason for the blackhole as *str*.
|
||||
|
||||
* **Returns:**
|
||||
*True* if successful, otherwise *False*.
|
||||
|
||||
#### `static unblackhole_identity(identity_hash)`
|
||||
|
||||
Lifts blackhole for an identity.
|
||||
|
||||
* **Parameters:**
|
||||
**identity_hash** – The identity hash to blackhole as *bytes*.
|
||||
|
||||
* **Returns:**
|
||||
*True* if successful, otherwise *False*.
|
||||
+158
-364
@@ -1,164 +1,119 @@
|
||||
# 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 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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*.
|
||||
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:
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
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
|
||||
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
|
||||
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.
|
||||
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
|
||||
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.
|
||||
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.
|
||||
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
|
||||
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 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.
|
||||
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>`.
|
||||
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.
|
||||
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.
|
||||
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 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.
|
||||
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:
|
||||
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
|
||||
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
|
||||
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.
|
||||
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.
|
||||
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*
|
||||
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
|
||||
@@ -166,16 +121,11 @@ destinations. Reticulum uses three different basic destination types, and one sp
|
||||
|
||||
#### Destination Naming
|
||||
|
||||
Destinations are created and named in an easy to understand dotted notation of *aspects*, and
|
||||
represented on the network as a hash of this value. The hash is a SHA-256 truncated to 128 bits. The
|
||||
top level aspect should always be a unique identifier for the application using the destination.
|
||||
The next levels of aspects can be defined in any way by the creator of the application.
|
||||
Destinations are created and named in an easy to understand dotted notation of *aspects*, and represented on the network as a hash of this value. The hash is a SHA-256 truncated to 128 bits. The top level aspect should always be a unique identifier for the application using the destination. The next levels of aspects can be defined in any way by the creator of the application.
|
||||
|
||||
Aspects can be as long and as plentiful as required, and a resulting long destination name will not
|
||||
impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.
|
||||
Aspects can be as long and as plentiful as required, and a resulting long destination name will not impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.
|
||||
|
||||
As an example, a destination for a environmental monitoring application could be made up of the
|
||||
application name, a device type and measurement type, like this:
|
||||
As an example, a destination for a environmental monitoring application could be made up of the application name, a device type and measurement type, like this:
|
||||
|
||||
```text
|
||||
app name : environmentlogger
|
||||
@@ -185,11 +135,7 @@ full name : environmentlogger.remotesensor.temperature
|
||||
hash : 4faf1b2e0a077e6a9d92fa051f256038
|
||||
```
|
||||
|
||||
For the *single* destination, Reticulum will automatically append the associated public key as a
|
||||
destination aspect before hashing. This is done to ensure only the correct destination is reached,
|
||||
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.
|
||||
For the *single* destination, Reticulum will automatically append the associated public key as a destination aspect before hashing. This is done to ensure only the correct destination is reached, 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:
|
||||
|
||||
@@ -197,46 +143,29 @@ packet.
|
||||
* 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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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:
|
||||
|
||||
@@ -246,259 +175,187 @@ As an example, an announce in a simple messenger application might contain the f
|
||||
* 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.
|
||||
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).
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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*.
|
||||
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.
|
||||
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 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:
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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*.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
@@ -506,34 +363,25 @@ an arbitrary number of hops, where information will be exchanged between two nod
|
||||
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**.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
[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
|
||||
|
||||
@@ -568,8 +416,11 @@ While the current implementation focuses on interface discovery, the concept of
|
||||
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.
|
||||
@@ -598,87 +449,61 @@ Once configured, your instances will automatically utilize this identity for sig
|
||||
|
||||
## 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.
|
||||
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.
|
||||
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:
|
||||
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
|
||||
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:
|
||||
* **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
|
||||
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
|
||||
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
|
||||
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).
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -716,25 +541,21 @@ 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
|
||||
@@ -742,7 +563,6 @@ group 01
|
||||
plain 10
|
||||
link 11
|
||||
|
||||
|
||||
Packet Types
|
||||
-----------------
|
||||
data 00
|
||||
@@ -750,7 +570,6 @@ announce 01
|
||||
link request 10
|
||||
proof 11
|
||||
|
||||
|
||||
+- Packet Example -+
|
||||
|
||||
HEADER FIELD DESTINATION FIELDS CONTEXT FIELD DATA FIELD
|
||||
@@ -765,7 +584,6 @@ proof 11
|
||||
|+------------- Header Type = HEADER_2 (two byte header, two address fields)
|
||||
+-------------- Access Codes = DISABLED
|
||||
|
||||
|
||||
+- Packet Example -+
|
||||
|
||||
HEADER FIELD DESTINATION FIELD CONTEXT FIELD DATA FIELD
|
||||
@@ -780,7 +598,6 @@ proof 11
|
||||
|+------------- 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
|
||||
@@ -795,7 +612,6 @@ proof 11
|
||||
|+------------- Header Type = HEADER_1 (two byte header, one address field)
|
||||
+-------------- Access Codes = ENABLED
|
||||
|
||||
|
||||
Size examples of different packet types
|
||||
---------------------------------------
|
||||
|
||||
@@ -814,14 +630,11 @@ but excluding any interface access codes.
|
||||
|
||||
### 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.
|
||||
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.
|
||||
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
|
||||
@@ -846,17 +659,11 @@ 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.
|
||||
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.
|
||||
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:
|
||||
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
|
||||
@@ -870,29 +677,16 @@ intentionally compromised or weakened clone. The utilised primitives are:
|
||||
* 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:
|
||||
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.
|
||||
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.
|
||||
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
|
||||
|
||||
+5
-11
@@ -58,7 +58,6 @@ configuration file is created. The default configuration looks like this:
|
||||
# configuration example, you can run the command:
|
||||
# rnsd --exampleconfig
|
||||
|
||||
|
||||
[reticulum]
|
||||
|
||||
# If you enable Transport, your system will route traffic
|
||||
@@ -70,7 +69,6 @@ configuration file is created. The default configuration looks like this:
|
||||
|
||||
enable_transport = No
|
||||
|
||||
|
||||
# By default, the first program to launch the Reticulum
|
||||
# Network Stack will create a shared instance, that other
|
||||
# programs can communicate with. Only the shared instance
|
||||
@@ -82,7 +80,6 @@ enable_transport = No
|
||||
|
||||
share_instance = Yes
|
||||
|
||||
|
||||
# If you want to run multiple *different* shared instances
|
||||
# on the same system, you will need to specify different
|
||||
# instance names for each. On platforms supporting domain
|
||||
@@ -97,14 +94,12 @@ instance_name = default
|
||||
# shared_instance_port = 37428
|
||||
# instance_control_port = 37429
|
||||
|
||||
|
||||
# If you want to explicitly use TCP for shared instance
|
||||
# communication, instead of domain sockets, this is also
|
||||
# possible, by using the following option:
|
||||
|
||||
# shared_instance_type = tcp
|
||||
|
||||
|
||||
# On systems where running instances may not have access
|
||||
# to the same shared Reticulum configuration directory,
|
||||
# it is still possible to allow full interactivity for
|
||||
@@ -115,7 +110,6 @@ instance_name = default
|
||||
|
||||
# rpc_key = e5c032d3ec4e64a6aca9927ba8ab73336780f6d71790
|
||||
|
||||
|
||||
# It is possible to allow remote management of Reticulum
|
||||
# systems using the various built-in utilities, such as
|
||||
# rnstatus and rnpath. You will need to specify one or
|
||||
@@ -127,7 +121,6 @@ instance_name = default
|
||||
# enable_remote_management = yes
|
||||
# remote_management_allowed = 9fb6d773498fb3feda407ed8ef2c3229, 2d882c5586e548d79b5af27bca1776dc
|
||||
|
||||
|
||||
# You can configure Reticulum to panic and forcibly close
|
||||
# if an unrecoverable interface error occurs, such as the
|
||||
# hardware device for an interface disappearing. This is
|
||||
@@ -136,7 +129,6 @@ instance_name = default
|
||||
|
||||
# panic_on_interface_error = No
|
||||
|
||||
|
||||
# When Transport is enabled, it is possible to allow the
|
||||
# Transport Instance to respond to probe requests from
|
||||
# the rnprobe utility. This can be a useful tool to test
|
||||
@@ -147,7 +139,6 @@ instance_name = default
|
||||
|
||||
# respond_to_probes = No
|
||||
|
||||
|
||||
[logging]
|
||||
# Valid log levels are 0 through 7:
|
||||
# 0: Log only critical information
|
||||
@@ -161,7 +152,6 @@ instance_name = default
|
||||
|
||||
loglevel = 4
|
||||
|
||||
|
||||
# The interfaces section defines the physical and virtual
|
||||
# interfaces Reticulum will use to communicate on. This
|
||||
# section will contain examples for a variety of interface
|
||||
@@ -1227,6 +1217,7 @@ This provides users and operators with control over what they want to allow *on
|
||||
This functionality serves a dual purpose:
|
||||
|
||||
* **For Individual Users:** It offers a simple way to maintain a quiet and efficient local network by manually blocking spammy or unwanted peers.
|
||||
|
||||
* **For Network Operators:** It enables the creation of federated, community-wide security standards. By publishing and sharing blackhole lists, operators can protect large infrastructures and distribute spam filtering rules across the mesh without manual intervention.
|
||||
|
||||
### Local Blackhole Management
|
||||
@@ -1271,7 +1262,7 @@ $ rnpath -b
|
||||
|
||||
### Automated List Sourcing
|
||||
|
||||
Manually blocking identities is effective for immediate threats, but maintaining an up-to-date blocklist for a large network is impractical. Reticulum supports **automated list sourcing**, allowing your node to subscribe to blackhole lists maintained by trusted peers, or a central authority you manage yourself.
|
||||
Manually blocking identities is effective for immediate threats and annoyances, but maintaining an up-to-date blocklist across many nodes on a large network is impractical. Reticulum supports **automated list sourcing**, allowing your node to subscribe to blackhole lists maintained by trusted peers, or a central authority you manage yourself.
|
||||
|
||||
#### WARNING
|
||||
**Verify Before Subscribing!** Subscribing to a blackhole source is a powerful action that grants that source the ability to dictate who you can communicate with. Before adding a source to your configuration, verify that the maintainer aligns with your usage policy and values. Blindly subscribing to untrusted lists could inadvertently block legitimate peers or essential services.
|
||||
@@ -1287,6 +1278,9 @@ To enable automated sourcing, add the `blackhole_sources` option to the `[reticu
|
||||
...
|
||||
# Automatically fetch blackhole lists from these trusted sources
|
||||
blackhole_sources = 521c87a83afb8f29e4455e77930b973b, 68a4aa91ac350c4087564e8a69f84e86
|
||||
|
||||
# Optional update interval, defaults to one hour
|
||||
blackhole_update_interval = 60
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
@@ -189,8 +189,8 @@ This is not about “dropping out” of society. It is about building a substrat
|
||||
|
||||
**Consider:**
|
||||
|
||||
- **The Old Way:** “My connection is slow. I should call my ISP and complain.”
|
||||
- **The Zen Way:** “The path is noisy. I will adjust the antenna or find a better route.”
|
||||
- **The Old Way:** *“My connection is slow. I should call my ISP and complain.”*
|
||||
- **The Zen Way:** *“The path is noisy. I will adjust the antenna or find a better route.”*
|
||||
|
||||
By taking ownership of the infrastructure, you take ownership of your voice. You stop shouting into someone else’s megaphone and start building your own. The network is no longer something that happens to you; it is something you make happen.
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
.. _distributed-development:
|
||||
|
||||
***********************
|
||||
Distributed Development
|
||||
***********************
|
||||
|
||||
This chapter of the manual provides the conceptual basis for understanding *why* ``rngit`` exists, what it aims to achieve, and the kinds of spaces it seeks to reestablish. For the practical details of operating the system, refer to the :ref:`Git Over Reticulum<git-main>` chapter.
|
||||
|
||||
|
||||
The Original Architecture
|
||||
=========================
|
||||
|
||||
When Torvalds created Git in 2005, he designed a tool that reflected a specific philosophy of collaboration. Every copy of a repository would be a complete, sovereign instance. There was no central server, no single point of failure, no gatekeeper. Developers would be able to work independently, exchange patches directly, and maintain their own branches indefinitely. This concept was - and is - both beautiful and revolutionary. It's execution is peer-to-peer not as a marketing term, but in the most foundational sense: As fundamental, structural reality.
|
||||
|
||||
Such a design emerged from necessity. The Linux kernel development process operated across geographical boundaries, time zones, and organizational affiliations. Contributors did not "log in" to a shared server to do their work; they maintained their own trees, and the flow of code between these trees was negotiated through patches, reviews, and merge decisions. The architecture of Git mirrored the social architecture of the community: Autonomous, competent, and fundamentally distributed in its technical operation.
|
||||
|
||||
*The result of that work is, in the most direct sense, what makes it possible for you to read this today.*
|
||||
|
||||
There's something very important to take note of here: With Git, developers could collaborate effectively and perfectly well without any central server being present, without platform-mediated visibility into each other's work, and without a centralized authority validating their contributions. They needed *only* a protocol for exchanging differences and a mechanism for verification of authorship. Everything else - social organization, quality control, release management - was handled by careful *human judgment* operating on top of the technical substrate.
|
||||
|
||||
What Git provided was not a development environment, but a **language for versioning**. It specified how to represent history, how to compute differences, how to merge divergent branches. It did not specify who could participate, how they should communicate, or what workflows they should follow. These were left to the competence and discretion of the creators using the system.
|
||||
|
||||
The Platform Interregnum
|
||||
========================
|
||||
|
||||
What followed represents a very familiar pattern: Tools designed to distribute power were re-centralized by platforms that offered convenience in exchange for control. GitHub, GitLab, and similar services reintroduced the centralization that Git had eliminated architecturally. The activity feed replaced durable artifacts with ephemeral notifications. The social graph and open interaction became as important as the code itself, if not more.
|
||||
|
||||
This re-centralization was not technical, as such. It was **ontological**. When every developer pushes to the same server, when every merge is in theory controllable by a platform, when every issue is tracked in a database controlled by a corporation, the nature of collaboration changes. The platform, and its social dynamics, becomes the ground of reality. The platform mediates not just the technical exchange of information and the programmatics, but the social recognition and codices of contribution, the future archival prospects of the work, and the very identity of the project itself.
|
||||
|
||||
The consequences extend beyond individual inconvenience. Centralized platforms create single points of failure for entire ecosystem. When a platform changes its terms of service, suspends accounts, removes repositories or ceases operation, entire project histories and community relationships can be disrupted or destroyed. The extractive economics of platform capitalism mean that value created by open-source communities is captured by corporations, while communities remain dependent on infrastructure they do not control. And the surveillance inherent in platform operation means that every action - every commit, every comment, every page view - is logged, analyzed, and potentially monetized or weaponized.
|
||||
|
||||
More insidiously, platforms have completely reshaped the culture of development itself. They have created what we could call the **Teahouse Developer**: A participant who treats engineering projects as social venues for opinion-sharing rather than sites of disciplined and careful production. These personages have no actual stakes in the projects they act as leeches upon, and only a very base consciousness of the damage they are incurring in order to feed their attention and external validation dependencies.
|
||||
|
||||
When platforms optimize for engagement, when growth is the only metric, when every user with an opinion must have their voice heard, when a random social process is elevated to higher importance than results, the signal-to-noise ratio collapses catastrophically. Competent engineers find themselves drowning in feedback from the incompetent, managing the emotional needs and dysregulations of drive-by commentators rather than solving technical problems.
|
||||
|
||||
The platform model is predicated on **unsaturable expansion**. Like almost any industrial system, it cannot function without growth. It pursues no particular aims; it is growth for the sake of growing. There is no saturation point, no concept of "enough". Every barrier to entry must be put down to the very lowest common denominator, every voice must be amplified, every interaction must be converted into content that feeds the machine. This is fundamentally incompatible with the nature of social beings itself. It is also incompatible with serious engineering, which requires focus, discernment, and the right of people who know better to say "no".
|
||||
|
||||
Restoration
|
||||
===========
|
||||
|
||||
The ``rngit`` system represents a return to Git's original architectural principles, fortified with cryptographic networking capabilities that were not available in 2005. The ``rngit`` system *is* Git - but running over Reticulum. Welcome back to a world where your work is your own, but where everyone can still reach you - if you want them to.
|
||||
|
||||
Just as Git eliminated the need for a central version control server, ``rngit`` eliminates the need for a central hosting platform, "servers" or any kinds of middle-men between the people actually doing the work. By operating over Reticulum, it eliminates the visibility of development activity to platform operators, network observers, state actors and other malicious third-parties.
|
||||
|
||||
In this model, the repository node is a **sovereign entity**. It is reachable from anywhere in the Reticulum network but owned, operated, and controlled by the developer or community that runs it. It is an actual home for creative output, not an extraction mechanism to which dues are paid. The node operator decides who may contribute, what standards must be met, and which voices are worth listening to. This is not exclusion; it is **discernment**. It is the necessary exercise of judgment that separates engineering from theatrics.
|
||||
|
||||
I did not create this in a fit of nostalgia. I created it because it is a necessary response to the failures of the centralized model. Git's technical architecture was - and *is* - correct. It was the social and economic superstructure built atop it that introduced fragility, exploitation, and environments toxic to actual creativity. By returning to first principles - distributed version control on distributed infrastructure - we recover not just a technical capability, but a mode of collaboration that respects the autonomy of individual developers and the sovereignty of actual communities.
|
||||
|
||||
|
||||
Protocols Over Platforms
|
||||
========================
|
||||
|
||||
The distinction between platforms and protocols is fundamental to understanding the architecture of sovereignty in networked systems. A platform is a service you access; a protocol is a grammar you speak; actions you live. A platform requires permission to enter, a protocol requires only *comprehension* to employ. A platform can change its rules, suspend your account, or cease operation entirely, a protocol persists as long as there are participants who *understand* and *use* it. A protocol is an *idea*, a platform is a machine that turns its users into products.
|
||||
|
||||
Platforms operate on a client-server model that inherently creates power asymmetry. Even when platforms are built atop open-source software, the operational instance remains a black box of corporate control. You *may* be able to download *some* of your data, but you cannot download the connections to the people that are the true value-base of the platform, or take them with you if you want to leave.
|
||||
|
||||
Protocols, by contrast, are agreements. They specify how systems should communicate, but not who may communicate or on what terms. Email is a protocol; Gmail is a platform. HTTP is a protocol; Facebook is a platform. Git is a protocol; GitHub is a platform. The protocol persists regardless of any particular implementation's success or failure.
|
||||
|
||||
The power of protocols lies in their **permissionlessness**. Anyone can implement a protocol without approval. Anyone can extend it, fork it, or use it for purposes unforeseen by its creators. This creates resilience: protocols cannot be easily censored, monopolized, or shut down because they exist as shared understanding rather than centralized infrastructure.
|
||||
|
||||
Reticulum is a protocol in this strict sense. It specifies how packets should be formatted, how paths should be discovered, how encryption should be applied. The ``rngit`` system extends this protocol approach to development workflows. It is not an external platform that hosts your repositories; it is a protocol for exchanging repository data, release artifacts, and work documents over Reticulum's encrypted transport. But with a few commands and an old computer, it creates your own infrastructure for hosting repositories, or sharing them with who you choose. *That* is how tools should function, in case we had forgotten.
|
||||
|
||||
Unlike platforms, which extract value by creating dependency, there is no entity that can grant or deny you the privilege of running ``rngit``. Your Reticulum identity is not endowed by any platform; it is generated locally and certified by its own cryptographic properties. Your repositories are hosted on nodes you control or nodes operated by communities you trust. Your relationships with other developers are peer-to-peer connections established through cryptographic addressing, not social graph connections managed by recommendation algorithms.
|
||||
|
||||
On a platform, exit means abandonment: you lose your history, your relationships, your visibility. With protocols, exit is just migration. When you change your infrastructure, your identity and your work travel with you. There are no middlemen between you and your collaborators. If push comes to shove, you can write your entire life's work and connections to an SD card, swim across the lake, and set up camp on the other side.
|
||||
|
||||
|
||||
Sovereignty Through Infrastructure
|
||||
==================================
|
||||
|
||||
The concept of sovereignty - supreme authority within a territory - has traditionally been applied to nation-states. But in an age where creative work is conducted through digital infrastructure, sovereignty is essential for individuals and communities. **Creative sovereignty** means having supreme authority over the artifacts you produce, the processes by which you produce them, and the terms under which they are distributed. It means not merely legal ownership of copyright, but operational control of the infrastructure that mediates creation, collaboration, and dissemination.
|
||||
|
||||
Centralized development platforms strip away most layers of sovereignty. When you host code on a corporate platform, you retain *some* legal ownership of copyright, but you surrender complete operational control. The platform decides what content is acceptable, who can access it, and how it is presented. They can delete your repository, suspend your account, or change the visibility of your work without consent. In reality, legal ownership becomes meaningless as operational control is ceded.
|
||||
|
||||
Running your own ``rngit`` node restores this sovereignty. You control the hardware, the network configuration, the backup strategies, and the access permissions. You decide what constitutes acceptable use, who may contribute, and how contributions are evaluated. Taking this responsibility on yourself is an assertion that your creative work is not a product to be harvested by platform economics, but an autonomous activity to be conducted on your own terms.
|
||||
|
||||
This sovereignty and responsibility extends to the entry barriers you establish. The ``rngit`` system allows you to configure access controls that filter participants based on cryptographic identity and demonstrated competence. If, for example, someone cannot navigate a command line, or use Reticulum to submit a patch, they most likely lack the required competence to modify your code. In a world that apparently labels this as "exclusion", I would simply refer to it as a minimally acceptable level of quality control.
|
||||
|
||||
Such a stance protects projects from the noise that so often overwhelms and completely dilutes platform-based development, where every user with an opinion believes themselves entitled to attention and access to the decision process.
|
||||
|
||||
|
||||
Artifact-Centered Workflows
|
||||
===========================
|
||||
|
||||
Contemporary platform-based development has shifted focus from durable artifacts to ephemeral *activity*. It does not matter what constitutes this activity, as long as it's there. The primary interface is not the repository itself, not the produced artifacts, but the activity feed: *Notifications* of commits, comments, pull requests, and social interactions. Work is measured by velocity, throughput, and the constant stream of updates. This activity-centric model creates constant urgency, discourages discernment, encourages reactive rather than reflective work patterns, and produces vast quantities of ephemeral and useless communication that obscures actual project state and productivity.
|
||||
|
||||
The ``rngit`` system enables a return to **artifact-centered workflows**, where the focus is on durable, attributable, versioned outputs rather than the stream of notifications surrounding them. The fundamental unit of work is the commit - signed, immutable records of change. The fundamental unit of production is the signed artifact - a self-verifying package of functionality. The fundamental unit of discussion is the work document - a structured, threaded conversation attached to repositories.
|
||||
|
||||
Artifacts can persist independently of any platform's continued operation. A commit signed with your Reticulum identity is attributable to you regardless of where it is stored. A release signed with your private key is verifiable as authentic regardless of which network it traverses, and can be verified offline on any system running Reticulum. The work exists as **cryptographic fact**, distributed over the planet, not as database entries in a corporate cloud.
|
||||
|
||||
Such a shift has real psychological consequences. When work is measured in artifacts rather than activity, the pace changes. There is no need for constant visibility, no pressure to perform busyness. Developers can work deeply, reflectively, and submit complete solutions rather than incremental updates designed to maintain presence in an activity feed. The work becomes **substantial**, in the physical sense of the word, rather than performative.
|
||||
|
||||
Composable Primitives
|
||||
=====================
|
||||
|
||||
The ``rngit`` system is not a monolithic application prescribing a specific workflow; it is a collection of **composable primitives** that can be arranged to support diverse creative processes. Understanding these primitives as separate, orthogonal capabilities enables users to construct workflows suited to their specific needs and to recombine these primitives in ways unforeseen by the system's designers.
|
||||
|
||||
The core primitives include:
|
||||
|
||||
* **Repository Hosting**: Bare Git repositories served over Reticulum links, accessible via standard Git commands through the ``rns://`` URL scheme.
|
||||
* **Identity-Based Access Control**: Fine-grained permissions managed through cryptographically verifiable identity hashes, configurable at the group, repository, or document level.
|
||||
* **Release Distribution**: Cryptographically signed release artifacts with embedded provenance information, verifiable offline and distributable through any Reticulum or physical path.
|
||||
* **Work Document Tracking**: Structured, threaded work management attached to repositories, with precise permission controls, and the ability to contain updates or discussions.
|
||||
* **Forking and Mirroring**: Automated replication of repositories from any accessible Git URL, with metadata tracking upstream relationships for synchronization.
|
||||
* **Nomad Network Integration**: Page node functionality for browsing repository contents, commit history, and release information through the Nomad Network protocol.
|
||||
|
||||
These primitives can be composed into workflows ranging from single-developer projects to complex multi-organizational collaborations. A solo developer might use only repository hosting and release distribution. A research group might add work document tracking for structured peer review. A software distribution network might combine mirroring with cryptographic release verification to create resilient update channels.
|
||||
|
||||
The entire system is incredibly light-weight, and can host hundreds of repositories on a Raspberry Pi.
|
||||
|
||||
Composability is essential because **creative work is diverse**. Software development, academic research, technical writing, hardware design, music production and data analysis all have different requirements for collaboration, review, and distribution. A platform prescribes a single workflow and forces all users to conform. A protocol provides primitives and allows users to construct workflows appropriate to their domain.
|
||||
|
||||
With ``rngit``, you can re-build the system into anything you can imagine. Everything can be modified, extended and hooked into. Adding functionality or automation is never further away than a shell script, a cron-job, or a Python modification of the source.
|
||||
|
||||
Distribution Without Intermediaries
|
||||
===================================
|
||||
|
||||
Creating software is only part of the work. Then comes actually getting it to the people needing to use it. Centralized platforms handle distribution through their own infrastructure: Content delivery networks, central package registries, and download servers accessed through platform-controlled interfaces. This convenience masks a fundamental dependency: Your ability to distribute depends on the platform's continued operation, their policies regarding your content, and their technical infrastructure's reach.
|
||||
|
||||
The ``rngit`` release system enables distribution strategies **decoupled from any single infrastructure provider**. Releases are cryptographically signed using Ed25519 signatures and packaged in signed release manifests (``.rsm`` files). These manifests contain embedded signatures for each artifact. The manifest provides full verifiability of all release information, and contains embedded release artifact lists, per-file ``.rsg`` signatures, origin information, and the creator's Reticulum Identity. It can also be used to fetch verified updates of the software package over the network, and can always be verified completely offline.
|
||||
|
||||
Because releases are self-verifying, they can traverse any network or physical path that Reticulum can establish. A release can travel over LoRa radio, be carried on USB drives through areas without internet connectivity, disseminated over a mirror network, or be distributed through store-and-forward mechanisms on intermittent infrastructure. Recipients can verify authenticity regardless of how they obtained the files. This is particularly valuable in low-connectivity environments where Reticulum may be the only available communication channel.
|
||||
|
||||
The ``rngit release`` command provides tools for creating, publishing, fetching, and verifying releases. When fetching a release using an ``.rsm`` manifest, the system validates the manifest signature against the required Reticulum Identity, extracts the origin node and repository path, connects to the origin over Reticulum, retrieves the latest release manifest, and verifies each downloaded artifact against the signatures embedded in the manifest. If any verification fails, the fetch aborts, preventing installation of corrupted or tampered files.
|
||||
|
||||
This cryptographic verification replaces the trust model of platform distribution. Instead of trusting that a platform has not been compromised, users verify that artifacts match the signatures created by the developer's identity. It doesn't matter *how* they obtained the artifacts, they can **always** be verified. This security model shifts from **institutional trust** (just believe in the goodness of the platform) to **cryptographic proof** (verify the signatures).
|
||||
|
||||
Long Archive
|
||||
============
|
||||
|
||||
Software development is often conceived as an activity of the present only: Solving today's problems, meeting current deadlines, responding to immediate feedback. But the artifacts produced - code, documentation, releases - have lifespans extending *far* beyond their creation. They may be used for decades, studied by future developers, depended upon by systems not yet imagined, or preserved as historical records of technological development.
|
||||
|
||||
The ``rngit`` system is designed with this **extended timeframe** in mind, supporting the creation of archives that are durable, portable, and intelligible across generational timescales. Git repositories are always internally complete; they contain full history and can be migrated to new infrastructure without loss of information. Everything that ``rngit`` adds on top of this is stored in normal files in standard formats right next to the Git repository folders, not an esoteric database-cluster two thousand kilometers away. Because releases are cryptographically signed, they remain verifiable as authentic regardless of when or where they are retrieved. Because the system operates over Reticulum, it can function over communication mediums that may outlast the internet as we know it.
|
||||
|
||||
This long-term perspective influences technical decisions. The use of well-established cryptographic primitives ensures that signatures will remain verifiable for centuries. The use of standard formats ensures that repositories will remain readable by future tools. The protocol-based architecture ensures that the system can evolve without losing compatibility with existing data.
|
||||
|
||||
For critical infrastructure, this archival durability is not optional; it is essential. Communication systems, cryptographic libraries, and safety-critical code must remain available and verifiable for the lifespans of the systems that depend on them. The ``rngit`` system provides the tools to create such archives: distributed across multiple nodes, cryptographically verified, and independent of any corporate or governmental infrastructure, which as history has shown repeatedly, does *not* persist.
|
||||
|
||||
Start Of The Road
|
||||
=================
|
||||
|
||||
Distributed development and production over Reticulum is a *different mode of existence* for creative work. It restores the autonomy originally created by Git. It provides local sovereignty over production infrastructure, composability of workflow, and durability of artifact. It lets you filter participation through competence and cryptography rather than incentives of platform operators, raising the quality and enjoyment of work, and protecting the focus of real engineering and creative expression.
|
||||
|
||||
This is not a system for everyone, and that is the point. It requires investment - in understanding Reticulum, in configuring infrastructure, in establishing workflows. It requires accepting responsibility for your own tools rather than delegating them to platform operators. It requires the discipline to maintain your own node, manage your own backups, and nurture your own community.
|
||||
|
||||
But for those who make this investment, the returns are substantial. You gain **immunity from platform failure**; your work persists regardless of corporate decisions or service outages. You gain **shelter from surveillance**; your development activity is visible only to those that *you* choose to involve. You gain **control over process**; you decide how work is conducted, reviewed, and released, unmediated by terms of service, algorithmic feeds and thousands of uninformed and irrelevant opinions.
|
||||
|
||||
Most importantly, though, you regain the **dignity of craft**. Development becomes an activity conducted among peers, equals among equals, mediated by skill and cryptographic proof rather than corporate permission, producing artifacts that stand as independent testimony to competence, functionality or beauty rather than as content feeding engagement metrics. The *work* becomes the point. The artifacts become durable. And the network becomes *one* of the tools you wield in this endeavor.
|
||||
+11
-28
@@ -4,18 +4,14 @@
|
||||
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 number of examples are included in the source distribution of Reticulum. You can use these examples to learn how to write your own programs.
|
||||
|
||||
.. _example-minimal:
|
||||
|
||||
Minimal
|
||||
=======
|
||||
|
||||
The *Minimal* example demonstrates the bare-minimum setup required to connect to
|
||||
a Reticulum network from your program. In about five lines of code, you will
|
||||
have the Reticulum Network Stack initialised, and ready to pass traffic in your
|
||||
program.
|
||||
The *Minimal* example demonstrates the bare-minimum setup required to connect to a Reticulum network from your program. In about five lines of code, you will have the Reticulum Network Stack initialised, and ready to pass traffic in your program.
|
||||
|
||||
.. literalinclude:: ../../Examples/Minimal.py
|
||||
|
||||
@@ -26,9 +22,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Announce
|
||||
========
|
||||
|
||||
The *Announce* example builds upon the previous example by exploring how to
|
||||
announce a destination on the network, and how to let your program receive
|
||||
notifications about announces from relevant destinations.
|
||||
The *Announce* example builds upon the previous example by exploring how to announce a destination on the network, and how to let your program receive notifications about announces from relevant destinations.
|
||||
|
||||
.. literalinclude:: ../../Examples/Announce.py
|
||||
|
||||
@@ -38,8 +32,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
|
||||
Broadcast
|
||||
=========
|
||||
The *Broadcast* example explores how to transmit plaintext broadcast messages
|
||||
over the network.
|
||||
The *Broadcast* example explores how to transmit plaintext broadcast messages over the network.
|
||||
|
||||
.. literalinclude:: ../../Examples/Broadcast.py
|
||||
|
||||
@@ -50,8 +43,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Echo
|
||||
====
|
||||
|
||||
The *Echo* example demonstrates communication between two destinations using
|
||||
the Packet interface.
|
||||
The *Echo* example demonstrates communication between two destinations using the Packet interface.
|
||||
|
||||
.. literalinclude:: ../../Examples/Echo.py
|
||||
|
||||
@@ -62,8 +54,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Link
|
||||
====
|
||||
|
||||
The *Link* example explores establishing an encrypted link to a remote
|
||||
destination, and passing traffic back and forth over the link.
|
||||
The *Link* example explores establishing an encrypted link to a remote destination, and passing traffic back and forth over the link.
|
||||
|
||||
.. literalinclude:: ../../Examples/Link.py
|
||||
|
||||
@@ -74,8 +65,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Identification
|
||||
==============
|
||||
|
||||
The *Identify* example explores identifying an intiator of a link, once
|
||||
the link has been established.
|
||||
The *Identify* example explores identifying an intiator of a link, once the link has been established.
|
||||
|
||||
.. literalinclude:: ../../Examples/Identify.py
|
||||
|
||||
@@ -97,8 +87,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Channel
|
||||
=======
|
||||
|
||||
The *Channel* example explores using a ``Channel`` to send structured
|
||||
data between peers of a ``Link``.
|
||||
The *Channel* example explores using a ``Channel`` to send structured data between peers of a ``Link``.
|
||||
|
||||
.. literalinclude:: ../../Examples/Channel.py
|
||||
|
||||
@@ -107,8 +96,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Buffer
|
||||
======
|
||||
|
||||
The *Buffer* example explores using buffered readers and writers to send
|
||||
binary data between peers of a ``Link``.
|
||||
The *Buffer* example explores using buffered readers and writers to send binary data between peers of a ``Link``.
|
||||
|
||||
.. literalinclude:: ../../Examples/Buffer.py
|
||||
|
||||
@@ -119,9 +107,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Filetransfer
|
||||
============
|
||||
|
||||
The *Filetransfer* example implements a basic file-server program that
|
||||
allow clients to connect and download files. The program uses the Resource
|
||||
interface to efficiently pass files of any size over a Reticulum :ref:`Link<api-link>`.
|
||||
The *Filetransfer* example implements a basic file-server program that allow clients to connect and download files. The program uses the Resource interface to efficiently pass files of any size over a Reticulum :ref:`Link<api-link>`.
|
||||
|
||||
.. literalinclude:: ../../Examples/Filetransfer.py
|
||||
|
||||
@@ -132,10 +118,7 @@ This example can also be found at `<https://github.com/markqvist/Reticulum/blob/
|
||||
Custom Interfaces
|
||||
=================
|
||||
|
||||
The *ExampleInterface* demonstrates creating custom interfaces for Reticulum.
|
||||
Any number of custom interfaces can be loaded and utilised by Reticulum, and
|
||||
will be fully on-par with natively included interfaces, including all supported
|
||||
:ref:`interface modes<interfaces-modes>` and :ref:`common configuration options<interfaces-options>`.
|
||||
The *ExampleInterface* demonstrates creating custom interfaces for Reticulum. Any number of custom interfaces can be loaded and utilised by Reticulum, and will be fully on-par with natively included interfaces, including all supported :ref:`interface modes<interfaces-modes>` and :ref:`common configuration options<interfaces-options>`.
|
||||
|
||||
.. literalinclude:: ../../Examples/ExampleInterface.py
|
||||
|
||||
|
||||
@@ -2,51 +2,38 @@
|
||||
Getting Started Fast
|
||||
********************
|
||||
|
||||
The best way to get started with the Reticulum Network Stack depends on what
|
||||
you want to do. This guide will outline sensible starting paths for different
|
||||
scenarios.
|
||||
The best way to get started with the Reticulum Network Stack depends on what you want to do. This guide will outline sensible starting paths for different scenarios.
|
||||
|
||||
|
||||
Standalone Reticulum Installation
|
||||
=================================
|
||||
If you simply want to install Reticulum and related utilities on a system,
|
||||
the easiest way is via the ``pip`` package manager:
|
||||
If you simply want to install Reticulum and related utilities on a system, the easiest way is via the ``pip`` package manager:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
pip install rns
|
||||
|
||||
If you do not already have pip installed, you can install it using the package manager
|
||||
of your system with a command like ``sudo apt install python3-pip``,
|
||||
``sudo pamac install python-pip`` or similar.
|
||||
If you do not already have pip installed, you can install it using the package manager of your system with a command like ``sudo apt install python3-pip``, ``sudo pamac install python-pip`` or similar.
|
||||
|
||||
You can also dowload the Reticulum release wheels from GitHub, or other release channels,
|
||||
and install them offline using ``pip``:
|
||||
You can also dowload the Reticulum release wheels from GitHub, or other release channels, and install them offline using ``pip``:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
pip install ./rns-1.1.2-py3-none-any.whl
|
||||
|
||||
On platforms that limit user package installation via ``pip``, you may need to manually
|
||||
allow this using the ``--break-system-packages`` command line flag when installing. This
|
||||
will not actually break any packages, unless you have installed Reticulum directly via
|
||||
your operating system's package manager.
|
||||
On platforms that limit user package installation via ``pip``, you may need to manually allow this using the ``--break-system-packages`` command line flag when installing. This will not actually break any packages, unless you have installed Reticulum directly via your operating system's package manager.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
pip install rns --break-system-packages
|
||||
|
||||
For more detailed installation instructions, please see the
|
||||
:ref:`Platform-Specific Install Notes<install-guides>` section.
|
||||
For more detailed installation instructions, please see the :ref:`Platform-Specific Install Notes<install-guides>` section.
|
||||
|
||||
After installation is complete, it might be helpful to refer to the
|
||||
:ref:`Using Reticulum on Your System<using-main>` chapter.
|
||||
After installation is complete, it might be helpful to refer to the :ref:`Using Reticulum on Your System<using-main>` chapter.
|
||||
|
||||
Resolving Dependency & Installation Issues
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On some platforms, there may not be binary packages available for all dependencies, and
|
||||
``pip`` installation may fail with an error message. In these cases, the issue can usually
|
||||
be resolved by installing the development essentials packages for your platform:
|
||||
On some platforms, there may not be binary packages available for all dependencies, and ``pip`` installation may fail with an error message. In these cases, the issue can usually be resolved by installing the development essentials packages for your platform:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -59,69 +46,38 @@ be resolved by installing the development essentials packages for your platform:
|
||||
# Fedora
|
||||
sudo dnf groupinstall "Development Tools" "Development Libraries"
|
||||
|
||||
With the base development packages installed, ``pip`` should be able to compile any missing
|
||||
dependencies from source, and complete installation even on platforms that don't have pre-
|
||||
compiled packages available.
|
||||
With the base development packages installed, ``pip`` should be able to compile any missing dependencies from source, and complete installation even on platforms that don't have pre-compiled packages available.
|
||||
|
||||
Try Using a Reticulum-based Program
|
||||
=============================================
|
||||
===================================
|
||||
|
||||
If you simply want to try using a program built with Reticulum, a :ref:`range of different
|
||||
programs <software-main>` exist that allow basic communication and a various other useful functions,
|
||||
even over extremely low-bandwidth Reticulum networks.
|
||||
If you simply want to try using a program built with Reticulum, a :ref:`range of different programs <software-main>` exist that allow basic communication and a various other useful functions, even over extremely low-bandwidth Reticulum networks.
|
||||
|
||||
|
||||
Using the Included Utilities
|
||||
=============================================
|
||||
Reticulum comes with a range of included utilities that make it easier to
|
||||
manage your network, check connectivity and make Reticulum available to other
|
||||
programs on your system.
|
||||
============================
|
||||
Reticulum comes with a range of included utilities that make it easier to manage your network, check connectivity and make Reticulum available to other programs on your system.
|
||||
|
||||
You can use ``rnsd`` to run Reticulum as a background or foreground service,
|
||||
and the ``rnstatus``, ``rnpath`` and ``rnprobe`` utilities to view and query
|
||||
network status and connectivity.
|
||||
You can use ``rnsd`` to run Reticulum as a background or foreground service, and the ``rnstatus``, ``rnpath`` and ``rnprobe`` utilities to view and query network status and connectivity.
|
||||
|
||||
To learn more about these utility programs, have a look at the
|
||||
:ref:`Using Reticulum on Your System<using-main>` chapter of this manual.
|
||||
To learn more about these utility programs, have a look at the :ref:`Using Reticulum on Your System<using-main>` chapter of this manual.
|
||||
|
||||
|
||||
Creating a Network With Reticulum
|
||||
=============================================
|
||||
To create a network, you will need to specify one or more *interfaces* for
|
||||
Reticulum to use. This is done in the Reticulum configuration file, which by
|
||||
default is located at ``~/.reticulum/config``. You can get an example
|
||||
configuration file with all options via ``rnsd --exampleconfig``.
|
||||
=================================
|
||||
To create a network, you will need to specify one or more *interfaces* for Reticulum to use. This is done in the Reticulum configuration file, which by default is located at ``~/.reticulum/config``. You can get an example configuration file with all options via ``rnsd --exampleconfig``.
|
||||
|
||||
When Reticulum is started for the first time, it will create a default
|
||||
configuration file, with one active interface. This default interface uses
|
||||
your existing Ethernet and WiFi networks (if any), and only allows you to
|
||||
communicate with other Reticulum peers within your local broadcast domains.
|
||||
When Reticulum is started for the first time, it will create a default configuration file, with one active interface. This default interface uses your existing Ethernet and WiFi networks (if any), and only allows you to communicate with other Reticulum peers within your local broadcast domains.
|
||||
|
||||
To communicate further, you will have to add one or more interfaces. The default
|
||||
configuration includes a number of examples, ranging from using TCP over the
|
||||
internet, to LoRa and Packet Radio interfaces.
|
||||
To communicate further, you will have to add one or more interfaces. The default configuration includes a number of examples, ranging from using TCP over the internet, to LoRa and Packet Radio interfaces.
|
||||
|
||||
With Reticulum, you only need to configure what interfaces you want to communicate
|
||||
over. There is no need to configure address spaces, subnets, routing tables,
|
||||
or other things you might be used to from other network types.
|
||||
With Reticulum, you only need to configure what interfaces you want to communicate over. There is no need to configure address spaces, subnets, routing tables, or other things you might be used to from other network types.
|
||||
|
||||
Once Reticulum knows which interfaces it should use, it will automatically
|
||||
discover topography and configure transport of data to any destinations it
|
||||
knows about.
|
||||
Once Reticulum knows which interfaces it should use, it will automatically discover topography and configure transport of data to any destinations it knows about.
|
||||
|
||||
In situations where you already have an established WiFi or Ethernet network, and
|
||||
many devices that want to utilise the same external Reticulum network paths (for example over
|
||||
LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by
|
||||
adding any external interfaces to the configuration of this system, and then enabling transport on it. Any
|
||||
other device on your local WiFi will then be able to connect to this wider Reticulum
|
||||
network just using the default (:ref:`AutoInterface<interfaces-auto>`) configuration.
|
||||
In situations where you already have an established WiFi or Ethernet network, and many devices that want to utilise the same external Reticulum network paths (for example over LoRa), it will often be sufficient to let one system act as a Reticulum gateway, by adding any external interfaces to the configuration of this system, and then enabling transport on it. Any other device on your local WiFi will then be able to connect to this wider Reticulum network just using the default (:ref:`AutoInterface<interfaces-auto>`) configuration.
|
||||
|
||||
Possibly, the examples in the config file are enough to get you started. If
|
||||
you want more information, you can read the :ref:`Building Networks<networks-main>`
|
||||
and :ref:`Interfaces<interfaces-main>` chapters of this manual, but most importantly,
|
||||
start with reading the next section, :ref:`Bootstrapping Connectivity<bootstrapping-connectivity>`,
|
||||
as this provides the most essential understanding of how to ensure reliable
|
||||
connectivity with a minimum of maintenance.
|
||||
Possibly, the examples in the config file are enough to get you started. If you want more information, you can read the :ref:`Building Networks<networks-main>` and :ref:`Interfaces<interfaces-main>` chapters of this manual, but most importantly, start with reading the next section, :ref:`Bootstrapping Connectivity<bootstrapping-connectivity>`, as this provides the most essential understanding of how to ensure reliable connectivity with a minimum of maintenance.
|
||||
|
||||
|
||||
.. _bootstrapping-connectivity:
|
||||
@@ -216,20 +172,13 @@ As a good starting point, you can find interface definitions for connecting your
|
||||
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
|
||||
Internet. This section offers some helpful pointers. Once you have set up your public entrypoint, it is a great idea to :ref:`make it discoverable over Reticulum<interfaces-discoverable>`.
|
||||
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 Internet. This section offers some helpful pointers. Once you have set up your public entrypoint, it is a great idea to :ref:`make it discoverable over Reticulum<interfaces-discoverable>`.
|
||||
|
||||
You will need a machine, physical or virtual with a public IP address, that can be reached by other devices on the Internet.
|
||||
|
||||
The most efficient and performant way to host a connectable entry-point supporting many
|
||||
users is to use the ``BackboneInterface``. This interface type is fully compatible with
|
||||
the ``TCPClientInterface`` and ``TCPServerInterface`` types, but much faster and uses
|
||||
less system resources, allowing your device to handle thousands of connections even on
|
||||
small systems.
|
||||
The most efficient and performant way to host a connectable entry-point supporting many users is to use the ``BackboneInterface``. This interface type is fully compatible with the ``TCPClientInterface`` and ``TCPServerInterface`` types, but much faster and uses less system resources, allowing your device to handle thousands of connections even on small systems.
|
||||
|
||||
It is also important to set your connectable interface to ``gateway`` mode, since this
|
||||
will greatly improve network convergence time and path resolution for anyone connecting
|
||||
to your entry-point.
|
||||
It is also important to set your connectable interface to ``gateway`` mode, since this will greatly improve network convergence time and path resolution for anyone connecting to your entry-point.
|
||||
|
||||
.. code:: ini
|
||||
|
||||
@@ -251,8 +200,7 @@ to your entry-point.
|
||||
announce_rate_penalty = 3600
|
||||
announce_rate_grace = 6
|
||||
|
||||
If instead you want to make a private entry-point from the Internet, you can use the
|
||||
:ref:`IFAC name and passphrase options<interfaces-options>` to secure your interface with a network name and passphrase.
|
||||
If instead you want to make a private entry-point from the Internet, you can use the :ref:`IFAC name and passphrase options<interfaces-options>` to secure your interface with a network name and passphrase.
|
||||
|
||||
.. code:: ini
|
||||
|
||||
@@ -268,132 +216,79 @@ If instead you want to make a private entry-point from the Internet, you can use
|
||||
network_name = private_ret
|
||||
passphrase = 2owjajquafIanPecAc
|
||||
|
||||
If you are hosting an entry-point on an operating system that does not support
|
||||
``BackboneInterface``, you can use ``TCPServerInterface`` instead, although it will
|
||||
not be as performant.
|
||||
If you are hosting an entry-point on an operating system that does not support ``BackboneInterface``, you can use ``TCPServerInterface`` instead, although it will not be as performant.
|
||||
|
||||
|
||||
Connecting Reticulum Instances Over the Internet
|
||||
================================================
|
||||
Reticulum currently offers three interfaces suitable for connecting instances over the Internet: :ref:`Backbone<interfaces-backbone>`, :ref:`TCP<interfaces-tcps>`
|
||||
and :ref:`I2P<interfaces-i2p>`. Each interface offers a different set of features, and Reticulum
|
||||
users should carefully choose the interface which best suites their needs.
|
||||
Reticulum currently offers three interfaces suitable for connecting instances over the Internet: :ref:`Backbone<interfaces-backbone>`, :ref:`TCP<interfaces-tcps>` and :ref:`I2P<interfaces-i2p>`. Each interface offers a different set of features, and Reticulum users should carefully choose the interface which best suites their needs.
|
||||
|
||||
The ``TCPServerInterface`` allows users to host an instance accessible over TCP/IP. This
|
||||
method is generally faster, lower latency, and more energy efficient than using ``I2PInterface``,
|
||||
however it also leaks more data about the server host.
|
||||
The ``TCPServerInterface`` allows users to host an instance accessible over TCP/IP. This method is generally faster, lower latency, and more energy efficient than using ``I2PInterface``, however it also leaks more data about the server host.
|
||||
|
||||
The ``BackboneInterface`` is a very fast and efficient interface type available on POSIX operating
|
||||
systems, designed to handle thousands of connections simultaneously with low memory, processing
|
||||
and I/O overhead. It is fully compatible with the TCP-based interface types.
|
||||
The ``BackboneInterface`` is a very fast and efficient interface type available on POSIX operating systems, designed to handle thousands of connections simultaneously with low memory, processing and I/O overhead. It is fully compatible with the TCP-based interface types.
|
||||
|
||||
TCP connections reveal the IP address of both your instance and the server to anyone who can
|
||||
inspect the connection. Someone could use this information to determine your location or identity. Adversaries
|
||||
inspecting your packets may be able to record packet metadata like time of transmission and packet size.
|
||||
Even though Reticulum encrypts traffic, TCP does not, so an adversary may be able to use
|
||||
packet inspection to learn that a system is running Reticulum, and what other IP addresses connect to it.
|
||||
Hosting a publicly reachable instance over TCP also requires a publicly reachable IP address,
|
||||
which most Internet connections don't offer anymore.
|
||||
TCP connections reveal the IP address of both your instance and the server to anyone who can inspect the connection. Someone could use this information to determine your location or identity. Adversaries inspecting your packets may be able to record packet metadata like time of transmission and packet size. Even though Reticulum encrypts traffic, TCP does not, so an adversary may be able to use packet inspection to learn that a system is running Reticulum, and what other IP addresses connect to it. Hosting a publicly reachable instance over TCP also requires a publicly reachable IP address, which most Internet connections don't offer anymore.
|
||||
|
||||
The ``I2PInterface`` routes messages through the `Invisible Internet Protocol
|
||||
(I2P) <https://geti2p.net/en/>`_. To use this interface, users must also run an I2P daemon in
|
||||
parallel to ``rnsd``. For always-on I2P nodes it is recommended to use `i2pd <https://i2pd.website/>`_.
|
||||
The ``I2PInterface`` routes messages through the `Invisible Internet Protocol (I2P) <https://geti2p.net/en/>`_. To use this interface, users must also run an I2P daemon in parallel to ``rnsd``. For always-on I2P nodes it is recommended to use `i2pd <https://i2pd.website/>`_.
|
||||
|
||||
By default, I2P will encrypt and mix all traffic sent over the Internet, and
|
||||
hide both the sender and receiver Reticulum instance IP addresses. Running an I2P node
|
||||
will also relay other I2P user's encrypted packets, which will use extra
|
||||
bandwidth and compute power, but also makes timing attacks and other forms of
|
||||
deep-packet-inspection much more difficult.
|
||||
By default, I2P will encrypt and mix all traffic sent over the Internet, and hide both the sender and receiver Reticulum instance IP addresses. Running an I2P node will also relay other I2P user's encrypted packets, which will use extra bandwidth and compute power, but also makes timing attacks and other forms of deep-packet-inspection much more difficult.
|
||||
|
||||
I2P also allows users to host globally available Reticulum instances from non-public IP's and behind firewalls and NAT.
|
||||
|
||||
In general it is recommended to use an I2P node if you want to host a publicly accessible
|
||||
instance, while preserving anonymity. If you care more about performance, and a slightly
|
||||
easier setup, use TCP.
|
||||
In general it is recommended to use an I2P node if you want to host a publicly accessible instance, while preserving anonymity. If you care more about performance, and a slightly easier setup, use TCP.
|
||||
|
||||
Adding Radio Interfaces
|
||||
=======================
|
||||
Once you have Reticulum installed and working, you can add radio interfaces with
|
||||
any compatible hardware you have available. Reticulum supports a wide range of radio
|
||||
hardware, and if you already have any available, it is very likely that it will
|
||||
work with Reticulum. For information on how to configure this, see the
|
||||
:ref:`Interfaces<interfaces-main>` section of this manual.
|
||||
Once you have Reticulum installed and working, you can add radio interfaces with any compatible hardware you have available. Reticulum supports a wide range of radio hardware, and if you already have any available, it is very likely that it will work with Reticulum. For information on how to configure this, see the :ref:`Interfaces<interfaces-main>` section of this manual.
|
||||
|
||||
If you do not already have transceiver hardware available, you can easily and
|
||||
cheaply build an :ref:`RNode<rnode-main>`, which is a general-purpose long-range
|
||||
digital radio transceiver, that integrates easily with Reticulum.
|
||||
If you do not already have transceiver hardware available, you can easily and cheaply build an :ref:`RNode<rnode-main>`, which is a general-purpose long-range digital radio transceiver, that integrates easily with Reticulum.
|
||||
|
||||
To build one yourself requires installing a custom firmware on a supported LoRa
|
||||
development board with an auto-install script or web-based flasher.
|
||||
Please see the :ref:`Communications Hardware<hardware-main>` chapter for a guide.
|
||||
If you prefer purchasing a ready-made unit, you can refer to the
|
||||
:ref:`list of suppliers<rnode-suppliers>`.
|
||||
To build one yourself requires installing a custom firmware on a supported LoRa development board with an auto-install script or web-based flasher. Please see the :ref:`Communications Hardware<hardware-main>` chapter for a guide. If you prefer purchasing a ready-made unit, you can refer to the :ref:`list of suppliers<rnode-suppliers>`.
|
||||
|
||||
Other radio-based hardware interfaces are being developed and made available by
|
||||
the broader Reticulum community. You can find more information on such topics
|
||||
over Reticulum-based information sharing systems.
|
||||
Other radio-based hardware interfaces are being developed and made available by the broader Reticulum community. You can find more information on such topics over Reticulum-based information sharing systems.
|
||||
|
||||
If you have communications hardware that is not already supported by any of the
|
||||
:ref:`existing interface types<interfaces-main>`, it is easy to write (and potentially
|
||||
publish) a :ref:`custom interface module<interfaces-custom>` that makes it compatible with Reticulum.
|
||||
If you have communications hardware that is not already supported by any of the :ref:`existing interface types<interfaces-main>`, it is easy to write (and potentially publish) a :ref:`custom interface module<interfaces-custom>` that makes it compatible with Reticulum.
|
||||
|
||||
|
||||
Creating and Using Custom Interfaces
|
||||
====================================
|
||||
|
||||
While Reticulum includes a flexible and broad range of built-in interfaces, these
|
||||
will not cover every conceivable type of communications hardware that Reticulum
|
||||
can potentially use to communicate.
|
||||
While Reticulum includes a flexible and broad range of built-in interfaces, these will not cover every conceivable type of communications hardware that Reticulum can potentially use to communicate.
|
||||
|
||||
It is therefore possible to easily write your own interface modules, that can be
|
||||
loaded at run-time and used on-par with any of the built-in interface types.
|
||||
It is therefore possible to easily write your own interface modules, that can be loaded at run-time and used on-par with any of the built-in interface types.
|
||||
|
||||
For more information on this subject, and code examples to build on, please see
|
||||
the :ref:`Configuring Interfaces<interfaces-main>` chapter.
|
||||
For more information on this subject, and code examples to build on, please see the :ref:`Configuring Interfaces<interfaces-main>` chapter.
|
||||
|
||||
|
||||
Develop a Program with Reticulum
|
||||
===========================================
|
||||
If you want to develop programs that use Reticulum, the easiest way to get
|
||||
started is to install the latest release of Reticulum via pip:
|
||||
================================
|
||||
If you want to develop programs that use Reticulum, the easiest way to get started is to install the latest release of Reticulum via pip:
|
||||
|
||||
.. code::
|
||||
|
||||
pip install rns
|
||||
|
||||
The above command will install Reticulum and dependencies, and you will be
|
||||
ready to import and use RNS in your own programs. The next step will most
|
||||
likely be to look at some :ref:`Example Programs<examples-main>`.
|
||||
The above command will install Reticulum and dependencies, and you will be ready to import and use RNS in your own programs. The next step will most likely be to look at some :ref:`Example Programs<examples-main>`.
|
||||
|
||||
The entire Reticulum API is documented in the :ref:`API Reference<api-main>`
|
||||
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 :ref:`Understanding Reticulum<understanding-main>` chapter.
|
||||
The entire Reticulum API is documented in the :ref:`API Reference<api-main>` 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 :ref:`Understanding Reticulum<understanding-main>` chapter.
|
||||
|
||||
|
||||
.. _install-guides:
|
||||
|
||||
Platform-Specific Install Notes
|
||||
==============================================
|
||||
===============================
|
||||
|
||||
Some platforms require a slightly different installation procedure, or have
|
||||
various quirks that are worth being aware of. These are listed here.
|
||||
Some platforms require a slightly different installation procedure, or have various quirks that are worth being aware of. These are listed here.
|
||||
|
||||
Android
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Reticulum can be used on Android in different ways. The easiest way to get
|
||||
started is using an app like `Sideband <https://unsigned.io/sideband>`_.
|
||||
^^^^^^^
|
||||
Reticulum can be used on Android in different ways. The easiest way to get started is using an app like `Sideband <https://unsigned.io/sideband>`_.
|
||||
|
||||
For more control and features, you can use Reticulum and related programs via
|
||||
the `Termux app <https://termux.com/>`_, at the time of writing available on
|
||||
`F-droid <https://f-droid.org>`_.
|
||||
For more control and features, you can use Reticulum and related programs via the `Termux app <https://termux.com/>`_, at the time of writing available on `F-droid <https://f-droid.org>`_.
|
||||
|
||||
Termux is a terminal emulator and Linux environment for Android based devices,
|
||||
which includes the ability to use many different programs and libraries,
|
||||
including Reticulum.
|
||||
Termux is a terminal emulator and Linux environment for Android based devices, which includes the ability to use many different programs and libraries, including Reticulum.
|
||||
|
||||
To use Reticulum within the Termux environment, you will need to install
|
||||
``python`` and the ``python-cryptography`` library using ``pkg``, the package-manager
|
||||
build into Termux. After that, you can use ``pip`` to install Reticulum.
|
||||
To use Reticulum within the Termux environment, you will need to install ``python`` and the ``python-cryptography`` library using ``pkg``, the package-manager build into Termux. After that, you can use ``pip`` to install Reticulum.
|
||||
|
||||
From within Termux, execute the following:
|
||||
|
||||
@@ -412,9 +307,7 @@ From within Termux, execute the following:
|
||||
# Install Reticulum
|
||||
pip install rns
|
||||
|
||||
If for some reason the ``python-cryptography`` package is not available for
|
||||
your platform via the Termux package manager, you can attempt to build it
|
||||
locally on your device using the following command:
|
||||
If for some reason the ``python-cryptography`` package is not available for your platform via the Termux package manager, you can attempt to build it locally on your device using the following command:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -441,16 +334,12 @@ locally on your device using the following command:
|
||||
# Reticulum and any related software
|
||||
pip install rns
|
||||
|
||||
It is also possible to include Reticulum in apps compiled and distributed as
|
||||
Android APKs. A detailed tutorial and example source code will be included
|
||||
here at a later point. Until then you can use the `Sideband source code <https://github.com/markqvist/sideband>`_ as an example and starting point.
|
||||
It is also possible to include Reticulum in apps compiled and distributed as Android APKs. A detailed tutorial and example source code will be included here at a later point. Until then you can use the `Sideband source code <https://github.com/markqvist/sideband>`_ as an example and starting point.
|
||||
|
||||
|
||||
ARM64
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On some architectures, including ARM64, not all dependencies have precompiled
|
||||
binaries. On such systems, you may need to install ``python3-dev`` (or similar) before
|
||||
installing Reticulum or programs that depend on Reticulum.
|
||||
^^^^^
|
||||
On some architectures, including ARM64, not all dependencies have precompiled binaries. On such systems, you may need to install ``python3-dev`` (or similar) before installing Reticulum or programs that depend on Reticulum.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -466,12 +355,8 @@ on your system locally.
|
||||
|
||||
|
||||
Debian Bookworm
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On versions of Debian released after April 2023, it is no longer possible by default
|
||||
to use ``pip`` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement ``pipx`` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
^^^^^^^^^^^^^^^
|
||||
On versions of Debian released after April 2023, it is no longer possible by default to use ``pip`` to install packages onto your system. Unfortunately, you will need to use the replacement ``pipx`` command instead, which places installed packages in an isolated environment. This should not negatively affect Reticulum, but will not work for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -484,42 +369,30 @@ for including and using Reticulum in your own scripts and programs.
|
||||
# Install Reticulum
|
||||
pipx install rns
|
||||
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing
|
||||
the configuration file located at ``~/.config/pip/pip.conf``, and adding the
|
||||
following section:
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing the configuration file located at ``~/.config/pip/pip.conf``, and adding the following section:
|
||||
|
||||
.. code:: ini
|
||||
|
||||
[global]
|
||||
break-system-packages = true
|
||||
|
||||
For a one-shot installation of Reticulum, without globally enabling the ``break-system-packages``
|
||||
option, you can use the following command:
|
||||
For a one-shot installation of Reticulum, without globally enabling the ``break-system-packages`` option, you can use the following command:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
pip install rns --break-system-packages
|
||||
|
||||
.. note::
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing ``pip`` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
|
||||
MacOS
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
To install Reticulum on macOS, you will need to have Python and the ``pip`` package
|
||||
manager installed.
|
||||
^^^^^
|
||||
To install Reticulum on macOS, you will need to have Python and the ``pip`` package manager installed.
|
||||
|
||||
Systems running macOS can vary quite widely in whether or not Python is pre-installed,
|
||||
and if it is, which version is installed, and whether the ``pip`` package manager is
|
||||
also installed and set up. If in doubt, you can `download and install <https://www.python.org/downloads/>`_
|
||||
Python manually.
|
||||
Systems running macOS can vary quite widely in whether or not Python is pre-installed, and if it is, which version is installed, and whether the ``pip`` package manager is also installed and set up. If in doubt, you can `download and install <https://www.python.org/downloads/>`_ Python manually.
|
||||
|
||||
When Python and ``pip`` is available on your system, simply open a terminal window
|
||||
and use one of the following commands:
|
||||
When Python and ``pip`` is available on your system, simply open a terminal window and use one of the following commands:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -531,16 +404,9 @@ and use one of the following commands:
|
||||
pip3 install rns --break-system-packages
|
||||
|
||||
.. note::
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing ``pip`` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
Additionally, some version combinations of macOS and Python require you to
|
||||
manually add your installed ``pip`` packages directory to your `PATH` environment
|
||||
variable, before you can use installed commands in your terminal. Usually, adding
|
||||
the following line to your shell init script (for example ``~/.zshrc``) will be enough:
|
||||
Additionally, some version combinations of macOS and Python require you to manually add your installed ``pip`` packages directory to your `PATH` environment variable, before you can use installed commands in your terminal. Usually, adding the following line to your shell init script (for example ``~/.zshrc``) will be enough:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -550,20 +416,13 @@ Adjust Python version and shell init script location according to your system.
|
||||
|
||||
|
||||
OpenWRT
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On OpenWRT systems with sufficient storage and memory, you can install
|
||||
Reticulum and related utilities using the `opkg` package manager and `pip`.
|
||||
^^^^^^^
|
||||
On OpenWRT systems with sufficient storage and memory, you can install Reticulum and related utilities using the `opkg` package manager and `pip`.
|
||||
|
||||
.. note::
|
||||
At the time of releasing this manual, work is underway to create pre-built Reticulum packages for OpenWRT, with full configuration, service and ``uci`` integration. Please see the `feed-reticulum <https://github.com/gretel/feed-reticulum>`_ and `reticulum-openwrt <https://github.com/gretel/reticulum-openwrt>`_ repositories for more information.
|
||||
|
||||
At the time of releasing this manual, work is underway to create pre-built
|
||||
Reticulum packages for OpenWRT, with full configuration, service
|
||||
and ``uci`` integration. Please see the `feed-reticulum <https://github.com/gretel/feed-reticulum>`_
|
||||
and `reticulum-openwrt <https://github.com/gretel/reticulum-openwrt>`_
|
||||
repositories for more information.
|
||||
|
||||
To install Reticulum on OpenWRT, first log into a command line session, and
|
||||
then use the following instructions:
|
||||
To install Reticulum on OpenWRT, first log into a command line session, and then use the following instructions:
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -577,30 +436,15 @@ then use the following instructions:
|
||||
rnsd -vvv
|
||||
|
||||
.. note::
|
||||
|
||||
The above instructions have been verified and tested on OpenWRT 21.02 only.
|
||||
It is likely that other versions may require slightly altered installation
|
||||
commands or package names. You will also need enough free space in your
|
||||
overlay FS, and enough free RAM to actually run Reticulum and any related
|
||||
programs and utilities.
|
||||
The above instructions have been verified and tested on OpenWRT 21.02 only. It is likely that other versions may require slightly altered installation commands or package names. You will also need enough free space in your overlay FS, and enough free RAM to actually run Reticulum and any related programs and utilities.
|
||||
|
||||
Depending on your device configuration, you may need to adjust firewall rules
|
||||
for Reticulum connectivity to and from your device to work. Until proper
|
||||
packaging is ready, you will also need to manually create a service or startup
|
||||
script to automatically laucnh Reticulum at boot time.
|
||||
Depending on your device configuration, you may need to adjust firewall rules for Reticulum connectivity to and from your device to work. Until proper packaging is ready, you will also need to manually create a service or startup script to automatically laucnh Reticulum at boot time.
|
||||
|
||||
Please also note that the `AutoInterface` requires link-local IPv6 addresses
|
||||
to be enabled for any Ethernet and WiFi devices you intend to use. If ``ip a``
|
||||
shows an address starting with ``fe80::`` for the device in question,
|
||||
``AutoInterface`` should work for that device.
|
||||
Please also note that the `AutoInterface` requires link-local IPv6 addresses to be enabled for any Ethernet and WiFi devices you intend to use. If ``ip a`` shows an address starting with ``fe80::`` for the device in question, ``AutoInterface`` should work for that device.
|
||||
|
||||
Raspberry Pi
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
It is currently recommended to use a 64-bit version of the Raspberry Pi OS
|
||||
if you want to run Reticulum on Raspberry Pi computers, since 32-bit versions
|
||||
don't always have packages available for some dependencies. If Python and the
|
||||
`pip` package manager is not already installed, do that first, and then
|
||||
install Reticulum using `pip`.
|
||||
^^^^^^^^^^^^
|
||||
It is currently recommended to use a 64-bit version of the Raspberry Pi OS if you want to run Reticulum on Raspberry Pi computers, since 32-bit versions don't always have packages available for some dependencies. If Python and the `pip` package manager is not already installed, do that first, and then install Reticulum using `pip`.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -611,22 +455,14 @@ install Reticulum using `pip`.
|
||||
pip install rns --break-system-packages
|
||||
|
||||
.. note::
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing ``pip`` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
While it is possible to install and run Reticulum on 32-bit Rasperry Pi OSes,
|
||||
it will require manually configuring and installing required build dependencies,
|
||||
and is not detailed in this manual.
|
||||
While it is possible to install and run Reticulum on 32-bit Rasperry Pi OSes, it will require manually configuring and installing required build dependencies, and is not detailed in this manual.
|
||||
|
||||
|
||||
RISC-V
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On some architectures, including RISC-V, not all dependencies have precompiled
|
||||
binaries. On such systems, you may need to install ``python3-dev`` (or similar) before
|
||||
installing Reticulum or programs that depend on Reticulum.
|
||||
^^^^^^
|
||||
On some architectures, including RISC-V, not all dependencies have precompiled binaries. On such systems, you may need to install ``python3-dev`` (or similar) before installing Reticulum or programs that depend on Reticulum.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -637,17 +473,12 @@ installing Reticulum or programs that depend on Reticulum.
|
||||
# Install Reticulum
|
||||
python3 -m pip install rns
|
||||
|
||||
With these packages installed, ``pip`` will be able to build any missing dependencies
|
||||
on your system locally.
|
||||
With these packages installed, ``pip`` will be able to build any missing dependencies on your system locally.
|
||||
|
||||
|
||||
Ubuntu Lunar
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible by default
|
||||
to use ``pip`` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement ``pipx`` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
^^^^^^^^^^^^
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible by default to use ``pip`` to install packages onto your system. Unfortunately, you will need to use the replacement ``pipx`` command instead, which places installed packages in an isolated environment. This should not negatively affect Reticulum, but will not work for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
.. code:: shell
|
||||
|
||||
@@ -660,42 +491,29 @@ for including and using Reticulum in your own scripts and programs.
|
||||
# Install Reticulum
|
||||
pipx install rns
|
||||
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing
|
||||
the configuration file located at ``~/.config/pip/pip.conf``, and adding the
|
||||
following section:
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing the configuration file located at ``~/.config/pip/pip.conf``, and adding the following section:
|
||||
|
||||
.. code:: text
|
||||
|
||||
[global]
|
||||
break-system-packages = true
|
||||
|
||||
For a one-shot installation of Reticulum, without globally enabling the ``break-system-packages``
|
||||
option, you can use the following command:
|
||||
For a one-shot installation of Reticulum, without globally enabling the ``break-system-packages`` option, you can use the following command:
|
||||
|
||||
.. code:: text
|
||||
|
||||
pip install rns --break-system-packages
|
||||
|
||||
.. note::
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems, especially
|
||||
not in the case of installing Reticulum.
|
||||
The ``--break-system-packages`` directive is a somewhat misleading choice of words. Setting it will of course not break any system packages, but will simply allow installing ``pip`` packages user- and system-wide. While this *could* in rare cases lead to version conflicts, it does not generally pose any problems, especially not in the case of installing Reticulum.
|
||||
|
||||
Windows
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On Windows operating systems, the easiest way to install Reticulum is by using the
|
||||
``pip`` package manager from the command line (either the command prompt or Windows
|
||||
Powershell).
|
||||
^^^^^^^
|
||||
On Windows operating systems, the easiest way to install Reticulum is by using the ``pip`` package manager from the command line (either the command prompt or Windows Powershell).
|
||||
|
||||
If you don't already have Python installed, `download and install Python <https://www.python.org/downloads/>`_.
|
||||
At the time of publication of this manual, the recommended version is `Python 3.12.7 <https://www.python.org/downloads/release/python-3127>`_.
|
||||
If you don't already have Python installed, `download and install Python <https://www.python.org/downloads/>`_. At the time of publication of this manual, the recommended version is `Python 3.12.7 <https://www.python.org/downloads/release/python-3127>`_.
|
||||
|
||||
**Important!** When asked by the installer, make sure to add the Python program to
|
||||
your PATH environment variables. If you don't do this, you will not be able to
|
||||
use the ``pip`` installer, or run the included Reticulum utility programs (such as
|
||||
``rnsd`` and ``rnstatus``) from the command line.
|
||||
**Important!** When asked by the installer, make sure to add the Python program to your PATH environment variables. If you don't do this, you will not be able to use the ``pip`` installer, or run the included Reticulum utility programs (such as ``rnsd`` and ``rnstatus``) from the command line.
|
||||
|
||||
After installing Python, open the command prompt or Windows Powershell, and type:
|
||||
|
||||
@@ -703,11 +521,10 @@ After installing Python, open the command prompt or Windows Powershell, and type
|
||||
|
||||
pip install rns
|
||||
|
||||
You can now use Reticulum and all included utility programs directly from your
|
||||
preferred command line interface.
|
||||
You can now use Reticulum and all included utility programs directly from your preferred command line interface.
|
||||
|
||||
Pure-Python Reticulum
|
||||
==============================================
|
||||
=====================
|
||||
|
||||
.. warning::
|
||||
If you use the ``rnspure`` package to run Reticulum on systems that
|
||||
@@ -715,17 +532,6 @@ Pure-Python Reticulum
|
||||
important that you read and understand the :ref:`Cryptographic Primitives <understanding-primitives>`
|
||||
section of this manual.
|
||||
|
||||
In some rare cases, and on more obscure system types, it is not possible to
|
||||
install one or more dependencies. In such situations,
|
||||
you can use the ``rnspure`` package instead of the ``rns`` package, or use ``pip``
|
||||
with the ``--no-dependencies`` command-line option. The ``rnspure``
|
||||
package requires no external dependencies for installation. Please note that the
|
||||
actual contents of the ``rns`` and ``rnspure`` packages are *completely identical*.
|
||||
The only difference is that the ``rnspure`` package lists no dependencies required
|
||||
for installation.
|
||||
In some rare cases, and on more obscure system types, it is not possible to install one or more dependencies. In such situations, you can use the ``rnspure`` package instead of the ``rns`` package, or use ``pip`` with the ``--no-dependencies`` command-line option. The ``rnspure`` package requires no external dependencies for installation. Please note that the actual contents of the ``rns`` and ``rnspure`` packages are *completely identical*. The only difference is that the ``rnspure`` package lists no dependencies required for installation.
|
||||
|
||||
No matter how Reticulum is installed and started, it will load external dependencies
|
||||
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.
|
||||
No matter how Reticulum is installed and started, it will load external dependencies 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.
|
||||
|
||||
+482
-22
@@ -4,13 +4,15 @@
|
||||
Git Over Reticulum
|
||||
******************
|
||||
|
||||
This chapter of the manual serves as the technical reference for the distributed software development and project collaboration tools included in RNS. For a conceptual overview, see the :ref:`Distributed Development<distributed-development>` chapter.
|
||||
|
||||
A set of utilities for distributed collaborative software development and publishing are included in RNS.
|
||||
|
||||
The system consists of two parts: The ``rngit`` node that hosts repositories, and the ``git-remote-rns`` helper that enables Git to communicate with rngit nodes. As soon as you have RNS installed on your system, you can transparently use Git with Reticulum-hosted repositories just like any other type of remote. Git over Reticulum uses URLs in the following format: ``rns://DESTINATION_HASH/group/repo``.
|
||||
|
||||
If you set a branch to track a Reticulum remote as the default upstream, you can simply use ``git`` as you normally would; all commands work transparently and as expected.
|
||||
|
||||
.. warning::
|
||||
.. important::
|
||||
**The rngit program is a new addition to RNS!** This functionality was introduced in RNS 1.2.0. While great care has been taken to design a secure, but highly configurable and flexible `permission system`_ for allowing many users to interact with many different repositories on a single node, ``rngit`` has not been tested extensively in the wild! Be careful when hosting repositories, especially if they are public or semi-public.
|
||||
|
||||
.. _permission system: #permissions
|
||||
@@ -170,10 +172,8 @@ To fork a repository:
|
||||
The source can be any valid Git URL, including:
|
||||
|
||||
- HTTPS URLs: ``https://github.com/user/repo.git``
|
||||
- Git URLs: ``git://host.com/repo.git``
|
||||
- SSH URLs: ``ssh://git@host.com/repo.git``
|
||||
- Reticulum URLs: ``rns://DESTINATION_HASH/group/repo``
|
||||
- Local paths: ``/path/to/repo.git``
|
||||
|
||||
Forks are created as bare repositories with metadata tracking their origin. The fork process:
|
||||
|
||||
@@ -321,8 +321,6 @@ These parameters are used by the sync system and can be queried using standard G
|
||||
1716230400
|
||||
|
||||
|
||||
|
||||
|
||||
Repository Structure
|
||||
====================
|
||||
|
||||
@@ -511,6 +509,75 @@ Permission Configuration Locations
|
||||
- Repository permissions: ``<group_root>/<group_name>/<repo_name>.allowed``
|
||||
- Document permissions: ``<group_root>/<group_name>.work/<doc_id>.allowed``
|
||||
|
||||
|
||||
Remote Permission Management
|
||||
============================
|
||||
|
||||
While permissions can be configured directly on the node by editing configuration files and ``.allowed`` files, ``rngit`` also supports remote permission management through the ``rngit perms`` command. This allows administrators to modify access controls for groups and repositories over Reticulum, without requiring shell access to the hosting node.
|
||||
|
||||
To use remote permission management, you must have ``admin`` permission on the target group or repository. The command opens your configured ``$EDITOR`` to modify permissions, using the same syntax and format as local ``.allowed`` files. When you save and exit the editor, the modified permissions are transmitted to the remote node and applied immediately.
|
||||
|
||||
Managing Group Permissions
|
||||
--------------------------
|
||||
|
||||
To view or modify permissions for an entire repository group, specify the group URL (ending with the group name):
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit perms rns://50824b711717f97c2fb1166ceddd5ea9/public
|
||||
|
||||
This retrieves the current permission configuration from the ``public.allowed`` file and opens it in your editor. Any changes you make are validated for syntax correctness. Invalid permission rules will be rejected with an error message indicating the problematic line.
|
||||
|
||||
Managing Repository Permissions
|
||||
-------------------------------
|
||||
|
||||
To manage permissions for a specific repository, include the repository name in the URL:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit perms rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo
|
||||
|
||||
This operates on the ``myrepo.allowed`` file next to the repository. Repository-level permissions take precedence over group-level permissions, allowing fine-grained access control for individual repositories within a group.
|
||||
|
||||
Permission Validation
|
||||
---------------------
|
||||
|
||||
When modifying permissions remotely, ``rngit`` validates that:
|
||||
|
||||
- Each permission line follows the correct ``permission:target`` syntax
|
||||
- Permission types are valid (r, w, rw, c, s, rel, i, p, adm)
|
||||
- Target specifications are valid (identity hashes, ``all``, or ``none``)
|
||||
- Identity hashes, when specified, are the correct length (32 hexadecimal characters)
|
||||
|
||||
If validation fails, the editor will reopen with an error message describing the issue, allowing you to correct the problem before resubmitting.
|
||||
|
||||
.. caution::
|
||||
Remote permission modification requires administrative access (the ``adm`` permission), which grants full control over the repository or group. The permission change request is transmitted over the encrypted Reticulum link, and the remote node verifies your identity cryptographically before applying changes. However, be aware that granting ``adm`` permissions to remote identities effectively delegates full control, including the ability to revoke your own access or modify permissions in ways you may not anticipate.
|
||||
|
||||
**All Command-Line Options (rngit perms)**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rngit perms [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-v] [-q] [--version]
|
||||
remote
|
||||
|
||||
Reticulum Git Permission Manager
|
||||
|
||||
positional arguments:
|
||||
remote URL of remote group or repository
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative config directory
|
||||
--rnsconfig RNSCONFIG
|
||||
path to alternative Reticulum config directory
|
||||
-i, --identity PATH path to identity
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
|
||||
|
||||
Identity & Destination Aliases
|
||||
==============================
|
||||
|
||||
@@ -679,6 +746,219 @@ A complete node configuration might look like this:
|
||||
unicode_icons = no
|
||||
|
||||
|
||||
Verified Releases
|
||||
=================
|
||||
|
||||
The ``rngit`` release system provides cryptographic provenance and integrity guarantees through automatic signing of release artifacts and signed release manifests. When you create a release, ``rngit`` generates an Ed25519 signature for each artifact and embeds these signatures in a cryptographically signed release manifest (``.rsm`` file). This allows anyone who obtains the release to verify its authenticity and integrity, regardless of how the files were distributed.
|
||||
|
||||
.. _git-release-obtain:
|
||||
|
||||
Obtaining Verified Releases
|
||||
---------------------------
|
||||
|
||||
The ``rngit`` system lets you obtain releases securely and in a verified manner, by validating cryptographically signed release manifests in the ``.rsm`` format during the retrieval process. Once a release has been published with ``rngit``, anyone that has read access to it can obtain the release with the ``rngit release`` command, for example:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/group/some_program fetch latest:all
|
||||
|
||||
This command will connect to the remote, retrieve the latest release manifest, verify it's signature and integrity (you can optionally specify a required signer identity with ``--signer``), and then download and sequentially verify all artifacts included in the release.
|
||||
|
||||
If verification succeeds, the retrieved artifact files, along with the release manifest will be saved in the current working directory. From the above example, you would end up with a number of downloaded files, and a version- and package specific release manifest, such as ``some_program_1.5.2.rsm``.
|
||||
|
||||
.. important::
|
||||
Keeping the retrieved release manifest is a **very** good idea! It allows you to easily obtain future releases and updates to the software directly, while verifying they came from the same publisher.
|
||||
|
||||
**Obtaining & Updating Releases Using RSM Manifests**
|
||||
|
||||
One of the key features of the ``rngit`` release system is the ability to fetch and verify new releases using only a signed release manifest. This is particularly valuable for distributing software over Reticulum. Once someone has an ``.rsm`` manifest of your package, they can use it to continually retrieve and update the software.
|
||||
|
||||
To fetch a release using a manifest:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release some_program_1.5.2.rsm fetch latest:all
|
||||
|
||||
This command:
|
||||
|
||||
1. Validates the manifest signature to confirm authenticity
|
||||
2. Extracts the origin node and repository path from the signed manifest
|
||||
3. Connects to the origin node over Reticulum
|
||||
4. Gets the *latest* release manifest from the developer
|
||||
5. Verifies it against the existing manifest
|
||||
6. Fetches each artifact listed in the manifest
|
||||
7. Verifies each downloaded file against the signature embedded in the manifest
|
||||
|
||||
If any artifact fails signature verification, the fetch aborts with an error, preventing the installation of corrupted or tampered files.
|
||||
|
||||
**Specifying Required Signers**
|
||||
|
||||
You can require that releases be signed by specific identities. When fetching a release, use the ``--signer`` option to specify the identity hash of the required signer:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch latest:all --signer 21a8daa6d9c3d3b8aab6e94b6bcb0e33
|
||||
|
||||
If the release was not signed by the specified identity, the fetch will abort before any files are downloaded. Likewise, if any downloaded artifacts were not signed by the required identity, the process will abort at the first invalid signature. This provides strong guarantees about the provenance of the software you are installing.
|
||||
|
||||
The signer check also works when fetching from a local manifest:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release manifest.rsm fetch latest:all --signer 21a8daa6d9c3d3b8aab6e94b6bcb0e33
|
||||
|
||||
**Selective & Partial Fetches**
|
||||
|
||||
You can fetch individual artifacts from a release by specifying the artifact name instead of ``all``:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch 1.2.0:myapp-1.2.0.tar.gz
|
||||
|
||||
This downloads only the specified artifact and verifies its signature against the manifest. If a file already exists locally, ``rngit`` verifies it against the manifest signature and skips the download if valid, making it safe to run the command multiple times. When fetching releases, ``rngit release`` will only download files that are missing or invalid according to the manifest. This means that partially completed release fetches can be continued later, if interrupted.
|
||||
|
||||
**Pattern Matching for Artifacts**
|
||||
|
||||
When fetching selective artifacts, you are not limited to exact names or the ``all`` keyword. You can use shell-style wildcard patterns to match multiple artifacts flexibly. This is particularly useful for selecting platform-specific builds, version ranges, or file types without specifying each file individually.
|
||||
|
||||
.. tip::
|
||||
When using pattern matching, make sure to enclose the target specification in quotes. Otherwise,
|
||||
your shell will probably interpret it as a shell expansion pattern *before* it is passed as an
|
||||
argument to ``rngit``!
|
||||
|
||||
The pattern matching supports standard Unix wildcards:
|
||||
|
||||
- ``*`` matches any sequence of characters (including empty)
|
||||
- ``?`` matches any single character
|
||||
- ``[seq]`` matches any character in *seq* (for example ``[0-9]`` or ``[abc]``)
|
||||
- ``[!seq]`` matches any character not in *seq*
|
||||
|
||||
For example, to fetch all wheel files for Python 3 across any platform:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:*-py3-*.whl"
|
||||
|
||||
To fetch a specific patch version when you know the major and minor version:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:myapp-1.2.?-linux-x86_64.tar.gz"
|
||||
|
||||
Or to retrieve all source archives:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://remote_node/public/myrepo fetch "1.2.0:source_*.tgz"
|
||||
|
||||
If your pattern contains no wildcard characters, it must match an artifact name exactly, which is useful for fetching single, specific artifacts. When a pattern matches multiple artifacts, all matched files are fetched and verified. If no artifacts match the pattern, the fetch aborts with an error indicating no matches were found.
|
||||
|
||||
Offline Verification
|
||||
--------------------
|
||||
|
||||
Because the release manifest contains embedded signatures, you can verify the integrity of release artifacts offline, without connecting to the repository node. The ``rnid`` and ``rngit`` utilities can validate artifact signatures against ``.rsg`` and manifest files.
|
||||
|
||||
**Using a release manifest:**
|
||||
|
||||
Ensure the release manifest is located in the same directory as the release artifacts, then run:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Verify all artifacts in the manifest
|
||||
$ rngit release myapp-1.2.0.rsm verify
|
||||
|
||||
# Or, verify only specific artifacts
|
||||
$ rngit release myapp-1.2.0.rsm verify "latest:*.whl"
|
||||
|
||||
This will load the manifest, and verify all files currently on-disk, but will not attempt to fetch the latest release manifest from the origin, or update local files to match it.
|
||||
|
||||
.. note::
|
||||
The ``verify`` operation is functionally equivalent to using the ``fetch`` operation with the ``--offline`` flag, and they can be used interchangably.
|
||||
|
||||
**For individual files:**
|
||||
|
||||
Ensure the ``.rsg`` signature is located in the same directory as the release artifact, then run:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -V myapp-1.2.0.tar.gz
|
||||
|
||||
This validates that the artifact file matches the signature created during the release process. Combined with the manifest's own signature, this provides end-to-end verification from the original release creation to the final installation.
|
||||
|
||||
.. _git-release-create:
|
||||
|
||||
Creating Signed Releases
|
||||
------------------------
|
||||
|
||||
Reticulum and the ``rngit`` system makes it easy to create signed releases that your users can verify and update securely. When you create a release using ``rngit``, the program automatically:
|
||||
|
||||
1. Generates an Ed25519 signature for each artifact file using your identity's signing key
|
||||
2. Creates ``.rsg`` signature files alongside each artifact in your distribution directory
|
||||
3. Constructs a signed ``manifest.rsm`` release manifest containing metadata, an artifact list, and embedded signatures
|
||||
4. Transmits both artifacts, signatures and manifest to the remote node specified as release origin
|
||||
|
||||
As an example, to create and publish a release from all files in the folder named ``dist``, simply run:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://my_node/group/myrepo create 1.2.0:./dist
|
||||
|
||||
Everything is automatically signed and uploaded to your node, and the release manifest will now include the following signed attestation information:
|
||||
|
||||
- Package name and version
|
||||
- The release notes for this release
|
||||
- Release timestamp and commit hash
|
||||
- Origin node identity and repository path
|
||||
- Complete list of artifacts
|
||||
- Embedded signatures for each artifact
|
||||
|
||||
That's it, there's nothing more to it than one command. Users can now securely obtain your release using ``rngit release fetch``.
|
||||
|
||||
**Release Manifest Format**
|
||||
|
||||
Release manifests use the ``.rsm`` format (a general-purpose, structured signed message format) and are themselves cryptographically signed documents. The manifest format embeds the signing identity's public key and a detached signature that covers the entire manifest content. This creates a chain of trust: the manifest signature proves the manifest's authenticity, and the embedded artifact signatures prove each file's integrity.
|
||||
|
||||
When a release is created, the manifest is stored as ``manifest.rsm`` in the release artifacts directory. You can also generate a local release manifest without uploading by using the ``--local`` flag:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://f2d31b2e080e5d4e358d32822ee4a3b7/public/myrepo create 1.2.0:./dist --local
|
||||
|
||||
This creates the ``.rsg`` signature files and ``manifest.rsm`` in your local distribution directory without connecting to the remote node, allowing you to inspect or distribute the signed release through alternative channels.
|
||||
|
||||
**Signature File Format**
|
||||
|
||||
Individual artifact signatures use the Reticulum Signature (``.rsg``) format and contain:
|
||||
|
||||
- The Ed25519 signature of the file
|
||||
- The signing identity's public key
|
||||
- Optional metadata, such as timestamps or notes
|
||||
|
||||
These signature files are created automatically during the release process and can be used independently of the manifest for verification purposes. The ``rnid`` utility can create and validate RSG signatures for any file, making this signature format useful beyond the ``rngit`` release system.
|
||||
|
||||
**Good Practices for Signature Distribution**
|
||||
|
||||
While release manifests in the ``.rsm`` format *include* embedded ``.rsg`` signatures for every listed artifact, it is dependent on the situation and requirements whether individual ``.rsg`` signatures are distributed as well. It is generally a good idea to do so, since they are very light-weight, and provide an easy and convenient way to validate and authenticate *individual* files, as opposed to entire releases.
|
||||
|
||||
When distributing software through multiple channels (direct download, mirror networks, physical media), including the ``.rsm`` manifest allows recipients to verify authenticity regardless of how they obtained the files. This is particularly valuable in low-connectivity environments where Reticulum may be the only available communication channel, as the manifest ensures that software updates can be verified even when received via store-and-forward mechanisms or physical media transport.
|
||||
|
||||
**Integration with Package Management**
|
||||
|
||||
While this functionality is still under development, the signed release manifest format is designed to be consumed by package management systems and automated deployment tools. Because the manifest is cryptographically signed and contains all necessary metadata and integrity checks, it can serve as a trusted source of truth for software distribution, even when fetched over untrusted channels or stored for long periods.
|
||||
|
||||
**Release Encryption**
|
||||
|
||||
While API primitives and command-line tools are currently not implemented for this, the release, distribution and verification system has been designed to also support *encrypted* releases, which can be distributed securely to authorized recipients.
|
||||
|
||||
**Verified Package Format**
|
||||
|
||||
The current system is being expanded to also include an ``.rvp`` package format, which can contain packaged releases including all relevant artifacts, metadata, manifest and signatures.
|
||||
|
||||
**Automated Mirror Discovery**
|
||||
|
||||
The ``rngit`` release system is designed to support automated mirror discovery and distribution package retrieval over Reticulum networks. Since everything is cryptographically signed and verified, it is possible to create automated mirror and distribution networks, where users can obtain software and information from local sources, without risking malicious modifications to the software they rely on. This functionality is currently in development.
|
||||
|
||||
|
||||
Release Management
|
||||
==================
|
||||
|
||||
@@ -693,11 +973,11 @@ To create a release, specify the tag name and path to artifacts:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create v1.2.0:./dist
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create 1.2.0:./dist
|
||||
|
||||
This will:
|
||||
|
||||
1. Verify that the tag ``v1.2.0`` exists in the repository
|
||||
1. Verify that the tag ``1.2.0`` exists in the repository
|
||||
2. Open your editor to write release notes
|
||||
3. Upload all files from the ``./dist`` directory
|
||||
4. Publish the release
|
||||
@@ -728,9 +1008,9 @@ To view all releases for a repository:
|
||||
|
||||
Tag Status Created Objs Notes
|
||||
------------------------------------------------------------------
|
||||
v1.2.0 published 2025-01-15 14:32 3 Another release
|
||||
v1.1.0 published 2024-12-03 09:15 2 Bug fix release
|
||||
v1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
1.2.0 published 2025-01-15 14:32 3 Another release
|
||||
1.1.0 published 2024-12-03 09:15 2 Bug fix release
|
||||
1.0.0 published 2024-10-20 16:45 2 Initial release
|
||||
|
||||
**Viewing Release Details**
|
||||
|
||||
@@ -738,9 +1018,9 @@ To see full information about a specific release:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo view v1.2.0
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo view 1.2.0
|
||||
|
||||
Release : 0.9.2
|
||||
Release : 1.2.0
|
||||
Status : published
|
||||
Created : 2026-05-04 23:53:09
|
||||
Thanks : 5
|
||||
@@ -756,16 +1036,37 @@ To see full information about a specific release:
|
||||
- myapp-1.2.0.zip (1.6 MB)
|
||||
- checksums.txt (256 B)
|
||||
|
||||
|
||||
**Fetching Releases**
|
||||
|
||||
To fetch a release, specify the remote URL, version and artifacts:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo fetch latest:all
|
||||
|
||||
This process is described in greater detail in the :ref:`Obtaining Verified Releases<git-release-obtain>` section.
|
||||
|
||||
**Creating Releases**
|
||||
|
||||
To fetch a release, specify the remote URL, version and artifacts:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo create 1.3.9:artifacts_dir
|
||||
|
||||
This process is described in greater detail in the :ref:`Creating Signed Releases<git-release-create>` section.
|
||||
|
||||
**Deleting Releases**
|
||||
|
||||
To remove a release:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo delete v1.2.0
|
||||
$ rngit release rns://50824b711717f97c2fb1166ceddd5ea9/public/myrepo delete 1.2.0
|
||||
|
||||
Are you sure you want to delete release 'v1.2.0'? [y/N]: y
|
||||
Release v1.2.0 deleted
|
||||
Are you sure you want to delete release '1.2.0'? [y/N]: y
|
||||
Release 1.2.0 deleted
|
||||
|
||||
**Requirements & Validation**
|
||||
|
||||
@@ -793,15 +1094,16 @@ When the Nomad Network page node is enabled, releases are displayed on a dedicat
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rngit release [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-v] [-q] [--version]
|
||||
[repository] [operation] [target]
|
||||
usage: python -m RNS.Utilities.rngit.server [-h] [--config CONFIG] [--rnsconfig RNSCONFIG]
|
||||
[-i PATH] [-s PATH] [-n name] [-L]
|
||||
[-o] [-v] [-q] [--version]
|
||||
[repository] [operation] [target]
|
||||
|
||||
Reticulum Git Release Manager
|
||||
|
||||
positional arguments:
|
||||
repository URL of remote repository
|
||||
operation list, view, create or delete
|
||||
repository URL of remote repository, or path to RSM manifest
|
||||
operation list, view, fetch, create, latest or delete
|
||||
target tag and path to release artifacts directory
|
||||
|
||||
options:
|
||||
@@ -810,6 +1112,10 @@ When the Nomad Network page node is enabled, releases are displayed on a dedicat
|
||||
--rnsconfig RNSCONFIG
|
||||
path to alternative Reticulum config directory
|
||||
-i, --identity PATH path to release identity
|
||||
-s, --signer PATH path to signing identity, if different from release identity
|
||||
-n, --name name package name if different from repo name
|
||||
-L, --local generate release locally, but don't upload
|
||||
-o, --offline verify manifest locally, but don't fetch updates
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
@@ -1020,7 +1326,33 @@ Each document is a numbered directory containing:
|
||||
|
||||
**Nomad Network Interface**
|
||||
|
||||
When the Nomad Network page node is enabled, work documents are viewable through the web interface. The work page lists all documents with their status, and clicking a document shows its full content and updates.
|
||||
When the Nomad Network page node is enabled, work documents are viewable through the nomadnet interface. The work page lists all documents with their status, and clicking a document shows its full content and updates.
|
||||
|
||||
Cryptographic Attribution
|
||||
-------------------------
|
||||
|
||||
Every work document is cryptographically signed by its creator using their Reticulum identity. When you create or edit a document, ``rngit`` generates an Ed25519 signature of the content, which is stored alongside the document contents and verified by the remote node, or locally when viewing the work document through the command-line interface. This provides two essential guarantees:
|
||||
|
||||
- **Attribution:** Every document and comment can be cryptographically attributed to its actual author
|
||||
- **Integrity:** Any modification to the content after creation would invalidate the signature
|
||||
|
||||
When viewing a work document, the signature validation status is displayed:
|
||||
|
||||
.. code:: text
|
||||
|
||||
Author : 9710b86ba12c42d1d8f30f74fe509286 (not locally validated)
|
||||
Signature : Document not signed
|
||||
|
||||
Or, for valid signatures:
|
||||
|
||||
.. code:: text
|
||||
|
||||
Author : <9710b86ba12c42d1d8f30f74fe509286>
|
||||
Signature : Valid
|
||||
|
||||
The "Valid" status indicates that the document content matches the author's signature, and that the signing identity corresponds to the stated author. This can be used to create tamper-proof records of project decisions, investigations, and discussions that cannot be repudiated, or modified by third parties without detection.
|
||||
|
||||
This cryptographic provenance is particularly valuable for distributed teams operating across trust boundaries. Because signatures are verified using the author's Reticulum identity public keys - which can be recalled from any transport node on the network - work documents provide authoritative records of who said what, and when, without requiring a central authority to notarize or validate the communication. Even if the repository node hosting the documents becomes unavailable, the signed document files themselves retain validity and can be verified independently using standard Reticulum identity tools.
|
||||
|
||||
**All Command-Line Options (rngit work)**
|
||||
|
||||
@@ -1049,4 +1381,132 @@ When the Nomad Network page node is enabled, work documents are viewable through
|
||||
-d, --id ID document ID
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
--version show program's version number and exit
|
||||
--version show program's version number and exit
|
||||
|
||||
|
||||
.. _git-commit-signing:
|
||||
|
||||
Commit Signing
|
||||
==============
|
||||
|
||||
The ``rngit`` system includes ``rngcs``, a Git commit signing and validation shim that enables commit signing and validation using Reticulum identities. By hooking into Git's SSH-based signing format, commits can be signed and verified using Reticulum identity keys directly.
|
||||
|
||||
Unlike traditional GPG and SSH-based commit signing, which relies on centralized keyservers, cumbersome co-signing procedures or manual per-signer setup, Reticulum commit signing uses self-contained RSG signatures, that can be deterministically resolved to Reticulum identity hashes.
|
||||
|
||||
This enables offline verification with no external infrastructure. The signature itself contains everything needed to cryptographically verify the signer's Reticulum identity and that the commit was signed correctly by the claimed identity.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
Before you can sign commits, you need a Reticulum identity with a private key. If you don't already have one, you can generate it using ``rnid``:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -g ~/.rngit/client_identity
|
||||
|
||||
New identity <1a54d64db7e8beca6f2c6cd17b0cb479> written to /home/user/.rngit/client_identity
|
||||
|
||||
The identity file must contain the private key to be usable for signing. The corresponding Reticulum identity hash will be used as the commit author identity.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Git must be configured to use SSH-format signatures with the ``rngcs`` signing shim, which is included in RNS. You can configure this either globally or per-repository.
|
||||
|
||||
**Global Configuration**
|
||||
|
||||
Enabling Reticulum commit signing for all repositories is as simple as:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ git config --global gpg.format ssh
|
||||
$ git config --global gpg.ssh.program rngcs
|
||||
$ git config --global gpg.ssh.allowedsignersfile none
|
||||
$ git config --global user.signingKey ~/.rngit/client_identity
|
||||
|
||||
With this configuration, all commits you sign with ``git commit -S`` will use your Reticulum identity.
|
||||
|
||||
.. note::
|
||||
The ``gpg.ssh.allowedsignersfile`` configuration key **must** be *set* for ``git`` to allow invoking the signing and verification shim. It is not actually used by ``rngcs``, and can be set to an arbitrary value. All validation operations happen exclusively based on the information in the embedded RSG data.
|
||||
|
||||
**Per-Repository Configuration**
|
||||
|
||||
To enable signing only for a specific repository:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ cd /path/to/repository
|
||||
$ git config --local gpg.format ssh
|
||||
$ git config --local gpg.ssh.program rngcs
|
||||
$ git config --local gpg.ssh.allowedsignersfile none
|
||||
$ git config --local user.signingKey ~/.rngit/client_identity
|
||||
|
||||
This is useful when you want to use different identities for different projects, or when only specific repositories require signed commits.
|
||||
|
||||
Author Identity Binding
|
||||
-----------------------
|
||||
|
||||
For the signature to be valid, the Git author email **must** match the Reticulum identity hash of the signing key. You can configure this using a command like the following:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ git config --global user.email "1a54d64db7e8beca6f2c6cd17b0cb479"
|
||||
|
||||
When ``rngcs`` verifies a commit, it extracts both the Git author field of the signed commit message and the signer identity from the RSG signature, ensuring they match. This binding is necessary to prevent identity spoofing. If someone crafts a commit with your identity hash in the author field but signs with a different key, verification will fail.
|
||||
|
||||
Signing Commits
|
||||
---------------
|
||||
|
||||
Once configured, sign commits using the standard Git ``-S`` flag:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ git commit -S -m "Refactored module"
|
||||
|
||||
[master 8f7e6d5] Refactored module
|
||||
|
||||
This will create a self-contained RSG-formatted signature, encode the RSG payload using base64, and wrap it in an ASCII-armored SSH-formatted signature block. The signature is then stored in the commit object's signature header and includes:
|
||||
|
||||
- The SHA256 hash of the commit content
|
||||
- The signer's Reticulum identity hash
|
||||
- The signer's public key
|
||||
- The actual signature of the complete envelope
|
||||
|
||||
Validating Commit Signatures
|
||||
----------------------------
|
||||
|
||||
Commits are automatically validated when using ``git log --show-signature`` or ``git show --show-signature``. The ``rngcs`` shim handles all verification operations. If any step fails, verification fails and Git displays an error.
|
||||
|
||||
To view signature information for commits, use Git's standard ``--show-signature`` option:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ git log --show-signature
|
||||
|
||||
commit 8f7e6d5c8f7e6d5c8f7e6d5c8f7e6d5c8f7e6d5
|
||||
Good "git" signature for commit, signed with Reticulum Identity key <1a54d64db7e8beca6f2c6cd17b0cb479>
|
||||
Author: Developer <1a54d64db7e8beca6f2c6cd17b0cb479>
|
||||
Date: Mon Jan 15 09:30:00 2026 +0100
|
||||
|
||||
Refactored module
|
||||
|
||||
The output shows whether the commit signature is valid, and whether the author field matches the signing identity.
|
||||
|
||||
.. tip::
|
||||
If you want to display both the identity hash and LXMF address for authors, you can generate a ``.mailmap`` file that resolves identities to LXMF addresses with the following script:
|
||||
|
||||
.. code::
|
||||
#!/bin/bash
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||
cd $DIR
|
||||
|
||||
id_regex="<([0-9a-f]{32})( .*)*>"
|
||||
extract_id="s/.*$id_regex/\1/g"
|
||||
|
||||
rm -f .mailmap
|
||||
git shortlog -se | grep -Ee "$id_regex" | sed -r "$extract_id" | while read -r id ; do
|
||||
if lxmf=$(rnid -i $id -H lxmf.delivery | grep -Ee "destination for this Identity is" | sed -r "$extract_id"); then
|
||||
echo "<$id lxmf:$lxmf> <$id>" >> .mailmap
|
||||
fi
|
||||
done
|
||||
@@ -27,6 +27,7 @@ to participate in the development of Reticulum itself.
|
||||
hardware
|
||||
interfaces
|
||||
networks
|
||||
distributed
|
||||
git
|
||||
support
|
||||
examples
|
||||
|
||||
+85
-311
@@ -3,64 +3,35 @@
|
||||
***********************
|
||||
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 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.
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-motivation:
|
||||
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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 :ref:`Reference Setup<understanding-referencesystem>`),
|
||||
connected to any kind of computer or mobile device that Reticulum can run on.
|
||||
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 :ref:`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*.
|
||||
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*.
|
||||
|
||||
.. _understanding-goals:
|
||||
|
||||
Goals
|
||||
=====
|
||||
|
||||
To be as widely usable and efficient to deploy as possible, the following goals have been used to
|
||||
guide the design of Reticulum:
|
||||
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**
|
||||
@@ -83,18 +54,18 @@ guide the design of Reticulum:
|
||||
* **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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
@@ -106,53 +77,26 @@ guide the design of Reticulum:
|
||||
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 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.
|
||||
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>``.
|
||||
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.
|
||||
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.
|
||||
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 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.
|
||||
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.
|
||||
|
||||
.. _understanding-destinations:
|
||||
|
||||
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:
|
||||
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**
|
||||
@@ -165,9 +109,9 @@ destinations. Reticulum uses three different basic destination types, and one sp
|
||||
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.
|
||||
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
|
||||
@@ -186,16 +130,11 @@ destinations. Reticulum uses three different basic destination types, and one sp
|
||||
Destination Naming
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Destinations are created and named in an easy to understand dotted notation of *aspects*, and
|
||||
represented on the network as a hash of this value. The hash is a SHA-256 truncated to 128 bits. The
|
||||
top level aspect should always be a unique identifier for the application using the destination.
|
||||
The next levels of aspects can be defined in any way by the creator of the application.
|
||||
Destinations are created and named in an easy to understand dotted notation of *aspects*, and represented on the network as a hash of this value. The hash is a SHA-256 truncated to 128 bits. The top level aspect should always be a unique identifier for the application using the destination. The next levels of aspects can be defined in any way by the creator of the application.
|
||||
|
||||
Aspects can be as long and as plentiful as required, and a resulting long destination name will not
|
||||
impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.
|
||||
Aspects can be as long and as plentiful as required, and a resulting long destination name will not impact efficiency, as names are always represented as truncated SHA-256 hashes on the network.
|
||||
|
||||
As an example, a destination for a environmental monitoring application could be made up of the
|
||||
application name, a device type and measurement type, like this:
|
||||
As an example, a destination for a environmental monitoring application could be made up of the application name, a device type and measurement type, like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
@@ -205,11 +144,7 @@ application name, a device type and measurement type, like this:
|
||||
full name : environmentlogger.remotesensor.temperature
|
||||
hash : 4faf1b2e0a077e6a9d92fa051f256038
|
||||
|
||||
For the *single* destination, Reticulum will automatically append the associated public key as a
|
||||
destination aspect before hashing. This is done to ensure only the correct destination is reached,
|
||||
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.
|
||||
For the *single* destination, Reticulum will automatically append the associated public key as a destination aspect before hashing. This is done to ensure only the correct destination is reached, 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:
|
||||
|
||||
@@ -218,16 +153,9 @@ packet.
|
||||
* 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.
|
||||
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.
|
||||
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:
|
||||
|
||||
@@ -239,56 +167,30 @@ To recap, the different destination types should be used in the following situat
|
||||
* **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.
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-keyannouncements:
|
||||
|
||||
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.
|
||||
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.
|
||||
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
|
||||
:ref:`The Announce Mechanism in Detail<understanding-announce>`.
|
||||
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 :ref:`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.
|
||||
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.
|
||||
|
||||
@@ -297,33 +199,18 @@ Seeing how *single* destinations are always tied to a private/public key pair le
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-gettingfurther:
|
||||
|
||||
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.
|
||||
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*.
|
||||
|
||||
@@ -332,16 +219,9 @@ In the following sections, two concepts that allow this will be introduced, *pat
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
.. _understanding-nodetypes:
|
||||
@@ -349,16 +229,11 @@ 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*.
|
||||
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.
|
||||
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 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``.
|
||||
|
||||
@@ -368,8 +243,7 @@ If it is a *Transport Node*, it should be given the configuration directive ``en
|
||||
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:
|
||||
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.
|
||||
@@ -400,42 +274,23 @@ any transport node receiving it, but according to some specific rules:
|
||||
to be transmitted, the newest announce is discarded. If the newest announce contains different
|
||||
application specific data, it will replace the old announce.
|
||||
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
|
||||
.. tip::
|
||||
Even very slow networks, that simply don't have the capacity to ever reach *full* convergence will generally still be able to reach **any other destination on any connected segments**, since interconnecting transport nodes will prioritize announces into the slower segments that are actually requested by nodes on these.
|
||||
|
||||
Even very slow networks, that simply don't have the capacity to ever reach *full* convergence
|
||||
will generally still be able to reach **any other destination on any connected segments**, since
|
||||
interconnecting transport nodes will prioritize announces into the slower segments that are
|
||||
actually requested by nodes on these.
|
||||
This means that slow, low-capacity or low-resource segments **don't** need to have full network knowledge, since paths can always be recursively resolved from other segments that do have knowledge about them.
|
||||
|
||||
This means that slow, low-capacity or low-resource segments **don't** need to have full network
|
||||
knowledge, since paths can always be recursively resolved from other segments that do have
|
||||
knowledge about them.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-paths:
|
||||
|
||||
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.
|
||||
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:
|
||||
|
||||
@@ -495,35 +350,17 @@ For exchanges of larger amounts of data, or when longer sessions of bidirectiona
|
||||
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.
|
||||
|
||||
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*.
|
||||
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
|
||||
:ref:`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.
|
||||
The combined bandwidth cost of setting up a link is 3 packets totalling 297 bytes (more info in the :ref:`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.
|
||||
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.
|
||||
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
|
||||
@@ -570,30 +407,20 @@ an arbitrary number of hops, where information will be exchanged between two nod
|
||||
that is used to encrypt the channel. Information can now be exchanged reliably and securely.
|
||||
|
||||
.. 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**.
|
||||
|
||||
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.
|
||||
When using *links*, Reticulum will automatically verify all data sent over the link, and can also automate retransmissions if *Resources* are used.
|
||||
|
||||
.. _understanding-resources:
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
For exchanging small amounts of data over a Reticulum network, the :ref:`Packet<api-packet>` interface
|
||||
is sufficient, but for exchanging data that would require many packets, an efficient way to coordinate
|
||||
the transfer is needed.
|
||||
For exchanging small amounts of data over a Reticulum network, the :ref:`Packet<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 :ref:`Resource<api-resource>`. A *Resource* can automatically
|
||||
handle the reliable transfer of an arbitrary amount of data over an established :ref:`Link<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.
|
||||
This is the purpose of the Reticulum :ref:`Resource<api-resource>`. A *Resource* can automatically handle the reliable transfer of an arbitrary amount of data over an established :ref:`Link<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.
|
||||
|
||||
:ref:`Resources<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.
|
||||
:ref:`Resources<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.
|
||||
|
||||
.. _understanding-network_identities:
|
||||
|
||||
@@ -676,19 +503,11 @@ Once configured, your instances will automatically utilize this identity for sig
|
||||
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.
|
||||
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.
|
||||
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:
|
||||
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
|
||||
@@ -700,11 +519,7 @@ recommended setup to get started experimenting. A reference system consists of t
|
||||
* **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:
|
||||
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**
|
||||
@@ -719,53 +534,34 @@ into the future. The current Reference System Setup is as follows:
|
||||
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>`_.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
.. _understanding-protocolspecifics:
|
||||
|
||||
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.
|
||||
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.
|
||||
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 :ref:`Common Interface Options<interfaces-options>`
|
||||
section. To implement this feature, Reticulum uses the concept of Interface Access Codes, that are calculated
|
||||
and verified per-packet.
|
||||
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 :ref:`Common Interface Options<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.
|
||||
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.
|
||||
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.
|
||||
|
||||
|
||||
.. _understanding-packetformat:
|
||||
@@ -909,14 +705,11 @@ Wire Format
|
||||
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.
|
||||
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.
|
||||
|
||||
.. image:: graphics/if_mode_graph_b.png
|
||||
|
||||
See the :ref:`Interface Modes<interfaces-modes>` section for a conceptual overview
|
||||
of the different interface modes, and how they are configured.
|
||||
See the :ref:`Interface Modes<interfaces-modes>` section for a conceptual overview of the different interface modes, and how they are configured.
|
||||
|
||||
..
|
||||
(.. code-block:: text)
|
||||
@@ -946,17 +739,11 @@ of the different interface modes, and how they are configured.
|
||||
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.
|
||||
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.
|
||||
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:
|
||||
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
|
||||
|
||||
@@ -980,12 +767,7 @@ intentionally compromised or weakened clone. The utilised primitives are:
|
||||
|
||||
* 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:
|
||||
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``
|
||||
@@ -993,17 +775,9 @@ following internal implementations:
|
||||
- ``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.
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -1316,7 +1316,7 @@ To see all identities currently blackholed on your local instance, use the ``-b`
|
||||
Automated List Sourcing
|
||||
=======================
|
||||
|
||||
Manually blocking identities is effective for immediate threats, but maintaining an up-to-date blocklist for a large network is impractical. Reticulum supports **automated list sourcing**, allowing your node to subscribe to blackhole lists maintained by trusted peers, or a central authority you manage yourself.
|
||||
Manually blocking identities is effective for immediate threats and annoyances, but maintaining an up-to-date blocklist across many nodes on a large network is impractical. Reticulum supports **automated list sourcing**, allowing your node to subscribe to blackhole lists maintained by trusted peers, or a central authority you manage yourself.
|
||||
|
||||
.. warning::
|
||||
**Verify Before Subscribing!** Subscribing to a blackhole source is a powerful action that grants that source the ability to dictate who you can communicate with. Before adding a source to your configuration, verify that the maintainer aligns with your usage policy and values. Blindly subscribing to untrusted lists could inadvertently block legitimate peers or essential services.
|
||||
@@ -1333,6 +1333,9 @@ To enable automated sourcing, add the ``blackhole_sources`` option to the ``[ret
|
||||
...
|
||||
# Automatically fetch blackhole lists from these trusted sources
|
||||
blackhole_sources = 521c87a83afb8f29e4455e77930b973b, 68a4aa91ac350c4087564e8a69f84e86
|
||||
|
||||
# Optional update interval, defaults to one hour
|
||||
blackhole_update_interval = 60
|
||||
...
|
||||
|
||||
**How It Works**
|
||||
|
||||
+2
-2
@@ -210,8 +210,8 @@ This is not about "dropping out" of society. It is about building a substrate on
|
||||
|
||||
**Consider:**
|
||||
|
||||
- **The Old Way:** "My connection is slow. I should call my ISP and complain."
|
||||
- **The Zen Way:** "The path is noisy. I will adjust the antenna or find a better route."
|
||||
- **The Old Way:** *"My connection is slow. I should call my ISP and complain."*
|
||||
- **The Zen Way:** *"The path is noisy. I will adjust the antenna or find a better route."*
|
||||
|
||||
By taking ownership of the infrastructure, you take ownership of your voice. You stop shouting into someone else's megaphone and start building your own. The network is no longer something that happens to you; it is something you make happen.
|
||||
|
||||
|
||||
Binary file not shown.
@@ -13,6 +13,10 @@ exec(open("RNS/_version.py", "r").read())
|
||||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
if "--getversion" in sys.argv:
|
||||
print(__version__, end="")
|
||||
exit(0)
|
||||
|
||||
if pure_python:
|
||||
pkg_name = "rnspure"
|
||||
requirements = []
|
||||
@@ -54,6 +58,7 @@ setuptools.setup(
|
||||
'rnpkg=RNS.Utilities.rnpkg:main',
|
||||
'rnsh=RNS.Utilities.rnsh.rnsh:main',
|
||||
'rngit=RNS.Utilities.rngit.server:main',
|
||||
'rngcs=RNS.Utilities.rngit.commitsigs:main',
|
||||
'git-remote-rns=RNS.Utilities.rngit.client:main',
|
||||
'rnodeconf=RNS.Utilities.rnodeconf:main',
|
||||
]
|
||||
|
||||
+42
-1
@@ -62,7 +62,7 @@ class Packet:
|
||||
|
||||
def set_delivered_callback(self, callback: Callable[[Packet], None]):
|
||||
self.delivered_callback = callback
|
||||
|
||||
|
||||
def delivered(self):
|
||||
with self.lock:
|
||||
self.state = MessageState.MSGSTATE_DELIVERED
|
||||
@@ -265,6 +265,47 @@ class TestChannel(unittest.TestCase):
|
||||
self.assertEqual(MessageState.MSGSTATE_FAILED, packet.state)
|
||||
self.assertFalse(envelope.tracked)
|
||||
|
||||
def test_send_on_failing_outlet_does_not_corrupt_state(self):
|
||||
# if outlet.send() returns a packet that never reached
|
||||
# the wire (LinkChannelOutlet does this when the link is not ACTIVE; the
|
||||
# returned packet has raw=None), Channel.send() must not consume a
|
||||
# sequence number or leave a packetless envelope in _tx_ring. Before
|
||||
# the fix, the envelope was queued before outlet.send() returned, so a
|
||||
# "dead" return left a raw=None envelope in the ring and silently
|
||||
# advanced _next_sequence, stalling the channel on the other end.
|
||||
print("Channel test send on failing outlet")
|
||||
|
||||
original_send = self.h.outlet.send
|
||||
|
||||
def ghost_send(raw):
|
||||
with self.h.outlet.lock:
|
||||
packet = Packet(None)
|
||||
packet.state = MessageState.MSGSTATE_FAILED
|
||||
self.h.outlet.packets.append(packet)
|
||||
return packet
|
||||
|
||||
self.h.outlet.send = ghost_send
|
||||
|
||||
pre_sequence = self.h.channel._next_sequence
|
||||
self.assertEqual(0, len(self.h.channel._tx_ring))
|
||||
|
||||
with self.assertRaises(RNS.Channel.ChannelException):
|
||||
self.h.channel.send(MessageTest())
|
||||
|
||||
# Sequence must not have been consumed.
|
||||
self.assertEqual(pre_sequence, self.h.channel._next_sequence)
|
||||
# _tx_ring must not contain a packetless envelope.
|
||||
self.assertEqual(0, len(self.h.channel._tx_ring))
|
||||
|
||||
# A subsequent successful send should use the same sequence number as
|
||||
# was reserved for the failed attempt.
|
||||
self.h.outlet.send = original_send
|
||||
envelope = self.h.channel.send(MessageTest())
|
||||
self.assertEqual(pre_sequence, envelope.sequence)
|
||||
self.assertIsNotNone(envelope.packet)
|
||||
self.assertIsNotNone(envelope.packet.raw)
|
||||
self.assertTrue(envelope in self.h.channel._tx_ring)
|
||||
|
||||
def test_multiple_handler(self):
|
||||
print("Channel test multiple handler short circuit")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user