Home

Awesome

r n s h  Shell over Reticulum

CI  Release  PyPI version   PyPI - Downloads

rnsh is a utility written in Python that facilitates shell sessions over Reticulum networks. It is based on the rnx utility that ships with Reticulum and aims to provide a similar experience to SSH.

Contents

Reminder: Beta Software

The interface is starting to firm up, but some bug fixes at this point still may introduce breaking changes, especially in the protocol layers of the software.

Recent Changes

v0.1.4

v0.1.3

v0.1.2

v0.1.1

v0.1.0

v0.0.13, v0.0.14

v0.0.12

v0.0.11

v0.0.10

v0.0.9

Quickstart

Tested (thus far) on Python 3.11 macOS 13.1 ARM64. Should run on Python 3.6+ on Linux or Unix. WSL probably works. Cygwin might work, too.

Example: Shell server

Setup

Before running the listener or initiator, you'll need to get the listener destination hash and the initiator identity hash.

# On listener
rnsh -l -p

# On initiator
rnsh -p

Note: service name no longer is supplied on initiator. The destination hash encapsulates this information.

Listener

rnsh -l -a 6d47805065fa470852cf1b1ef417a1ac -- /bin/zsh

Initiator

rnsh a5f72aefc2cb3cdba648f73f77c4e887

Options

Usage:
    rnsh -l [-c <configdir>] [-i <identityfile> | -s <service_name>] [-v... | -q...] -p
    rnsh -l [-c <configdir>] [-i <identityfile> | -s <service_name>] [-v... | -q...] 
            [-b <period>] (-n | -a <identity_hash> [-a <identity_hash>] ...) [-A | -C] 
            [[--] <program> [<arg> ...]]
    rnsh [-c <configdir>] [-i <identityfile>] [-v... | -q...] -p
    rnsh [-c <configdir>] [-i <identityfile>] [-v... | -q...] [-N] [-m] [-w <timeout>] 
         <destination_hash> [[--] <program> [<arg> ...]]
    rnsh -h
    rnsh --version

Options:
    -c DIR --config DIR          Alternate Reticulum config directory to use
    -i FILE --identity FILE      Specific identity file to use
    -s NAME --service NAME       Service name for identity file if not default
    -p --print-identity          Print identity information and exit
    -l --listen                  Listen (server) mode. If supplied, <program> <arg>...will 
                                   be used as the command line when the initiator does not
                                   provide one or when remote command is disabled. If
                                   <program> is not supplied, the default shell of the 
                                   user rnsh is running under will be used.
    -b --announce PERIOD         Announce on startup and every PERIOD seconds
                                 Specify 0 for PERIOD to announce on startup only.
    -a HASH --allowed HASH       Specify identities allowed to connect
    -n --no-auth                 Disable authentication
    -N --no-id                   Disable identify on connect
    -A --remote-command-as-args  Concatenate remote command to argument list of <program>/shell
    -C --no-remote-command       Disable executing command line from remote
    -m --mirror                  Client returns with code of remote process
    -w TIME --timeout TIME       Specify client connect and request timeout in seconds
    -q --quiet                   Increase quietness (move level up), multiple increases effect
                                          DEFAULT LOGGING LEVEL
                                                  CRITICAL (silent)
                                    Initiator ->  ERROR
                                                  WARNING
                                     Listener ->  INFO
                                                  DEBUG    (insane)
    -v --verbose                 Increase verbosity (move level down), multiple increases effect
    --version                    Show version
    -h --help                    Show this help

How it works

Listeners

Listener instances are the servers. Each listener is configured with an RNS identity, and a service name. Together, RNS makes these into a destination hash that can be used to connect to your listener.

Each listener must use a unique identity. The -s parameter can be used to specify a service name, which creates a unique identity file.

Listeners can be configured with a command line to run on connect. Initiators can supply a command line as well. There are several different options for the way the command line is handled:

If the -n option is not set on the listener, the initiator is required to identify before starting a command. The program will be started with the initiator's identity hash string is set in the environment variable RNS_REMOTE_IDENTITY.

Listeners are set up using the -l flag.

Initiators

Initiators are the clients. Each initiator has an identity hash which is used as an authentication mechanism on Reticulum. You'll need this value to configure the listener to allow your connection. It is possible to run the server without authentication, but hopefully it's obvious that this is an advanced use case.

To get the identity hash, use the -p flag.

With the initiator identity set up in the listener command line, and with the listener identity copied (you'll need to do -p on the listener side, too), you can run the initiator.

I recommend staying pretty vanilla to start with and trying /bin/zsh or whatever your favorite shell is these days. The shell should start in login mode. Ideally it works just like an ssh shell session.

Protocol

The protocol is build on top of the Reticulum Packet API. Application software sends and receives Message objects, which are encapsulated by Packet objects. Messages are (currently) sent one per packet, and only one packet is sent at a time (per link). The next packet is not sent until the receiver proves the outstanding packet.

A future update will work to allow a sliding window of outstanding packets to improve channel utilization.

Session Establishment

  1. Initiator establishes link. Listener session enters state LSSTATE_WAIT_IDENT, or LSSTATE_WAIT_VERS if running with --no-auth option.

  2. Initiator identifies on link if not using --no-id.

    • If using --allowed-hash, listener validates identity against configuration and if no match, sends a protocol error message and tears down link after prune timer.
  3. Initiator transmits a VersionInformationMessage, which is evaluated by the server for compatibility. If incompatible, a protocol error is sent.

  4. Listener responds with a VersionInfoMessage and enters state LSSTATE_WAIT_CMD

  5. Initiator evaluates the listener's version information for compatibility and if incompatible, tears down link.

  6. Initiator sends an ExecuteCommandMessage (which could be an empty command) and enters the session event loop.

  7. Listener evaluates the command message against the configured options such as -A or -C and responds with a protocol error if not allowed.

  8. Listener starts the program. If success, the listener enters the session event loop. If failure, responds with a CommandExitedMessage.

Session Event Loop

Listener state LSSTATE_RUNNING

Process messages received from initiator.

Initiator state ISSTATE_RUNNING

Process messages received from listener.

Roadmap

  1. Plan a better roadmap
  2. ?
  3. Keep my day job

TODO

Miscellaneous

By piping into/out of rnsh, it is possible to transfer files using the same method discussed in this article. It's not terribly fast currently, due to the round-trip rule enforced by the protocol. Sliding window acknowledgements will speed this up significantly.

Running tests: poetry run pytest tests