Installing and using Periplus

Periplus (PRP) is a cryptographic mesh-networking protocol; plexus is its Rust stack. There are two binaries: prpd (the daemon / transport node) and periplus (the command-line tools). Both are statically linked — no runtime, no shared libraries.

Periplus is a fork of Reticulum and is not wire-compatible with it. The protocol is specified in RFC 0001.

Install

Grab the static musl binaries from the downloads, verify the digest, and put them on your PATH:

curl -LO https://plexus.beer/dist/prpd-x86_64-linux-musl
curl -LO https://plexus.beer/dist/periplus-x86_64-linux-musl
curl -LO https://plexus.beer/dist/SHA256SUMS
sha256sum -c SHA256SUMS                       # verify before running
install -m755 prpd-x86_64-linux-musl     /usr/local/bin/prpd
install -m755 periplus-x86_64-linux-musl /usr/local/bin/periplus
prpd --version && periplus --version

The short prp* command names (prpwalk, prpctl, …) are the same periplus binary invoked under a different name — it dispatches on argv[0]. Symlink the ones you want (or just use periplus <verb>, e.g. periplus walk == prpwalk):

cd /usr/local/bin && for c in prpctl prpose prplex prpend prpwalk prpath prping \
    prpeer prpoll prpub prpull prpush prpipe prpkey prpsign; do ln -sf periplus "$c"; done

From source

A recent stable Rust toolchain, nothing else:

git clone https://git.itys.net/mjh/plexus.git && cd plexus
cargo build --release                  # -> target/release/{prpd,periplus}
cargo xtask install-commands           # symlink the prp* names alongside the binary

Static (musl), the way the downloads are built:

rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl -p plexus-prpd -p plexus-cli

Optional, off by default: --features iroh (an out-of-band Iroh QUIC control/status plane) and, on plexus-prpd, --features pq (post-quantum link upgrade).

Run as a service

For a persistent node, use the hardened systemd unit deploy/prpd.service from the source tree: it runs prpd as an unprivileged user with only CAP_NET_ADMIN (for the plane), keeps the identity + recall cache in /var/lib/periplus so the node's address survives restarts, and restarts on failure.

install -Dm644 deploy/prpd.service /etc/systemd/system/prpd.service
install -d /etc/periplus && periplus config init > /etc/periplus/periplus.toml  # then edit
systemctl daemon-reload && systemctl enable --now prpd

Usage

Run a node

The daemon owns the protocol; the periplus CLI talks to it and to the mesh. The simplest node listens for peers and announces itself:

prpd --listen 0.0.0.0:4242

To join an existing network, describe your links in a config file instead of the bare flags:

periplus config init > periplus.toml      # a commented starter
$EDITOR periplus.toml
prpd --config periplus.toml

Each [[interface]] block is one link; type is TCPServer (listen), TCPClient (dial a peer), or Auto (zero-config IPv6-multicast LAN discovery):

[[interface]]
type = "TCPClient"
peer = "hub.example.org:4242"

prpd writes its identity to plexus.identity (keep it — it is your address), a recall cache to plexus.known, and a control socket at /tmp/prpd.sock that the CLI uses. prpd --help lists every flag.

Identities & addresses

Your address is the hash of your keys — there is no registrar. Manage identities with periplus id (aka prpkey):

periplus id generate node.identity         # mint an identity
periplus id show node.identity             # its identity hash (= address) + public key
periplus id hash node.identity plexus.node # the destination address for an app.aspect

Inspect & control a running node

These talk to the local prpd over its control socket:

periplus status        # interfaces + traffic       (prpctl interfaces)
periplus path          # the path table             (prpctl paths)
prplex                 # routing graph: destinations grouped by interface
prpeer list            # known peers
prpub                  # tell prpd to announce now
prpend <dest-hash>     # dry-run: resolve a destination + report reachability, sends nothing

prpctl is the automation-facing variant (prpctl paths --json).

Reach other nodes

# Round-trip reachability + RTT — a signed-proof ping:
prping <dest-hash> --peer <hub:port>

# Walk the known path (hops, next-hop, interface) to a destination:
prpwalk <dest-hash>

# Send / receive / fetch a file over the mesh (prpush and prpull are shorthands):
periplus copy <file> <dest-hash> --peer <hub:port>                 # send
periplus copy --listen --bind 0.0.0.0:5000 --save .                # receive
periplus copy --fetch <remote-path> <listener-hash> --peer <hub:port> --identity node.identity

# A full-duplex byte pipe (netcat over the mesh):
prpipe --listen --bind 0.0.0.0:5000                                # one end
echo hello | prpipe <dest-hash> --peer <hub:port> --identity node.identity

For prping to get a reply, the target's prpd must answer probes — run it with --respond-to-probes. Remote status of another node:

prpoll <node-id-hash> --peer <hub:port> --identity node.identity   # = periplus status --remote

The fd73 plane — IP over the mesh

Bring up the fd73::/16 IPv6 overlay on a TUN device (needs CAP_NET_ADMIN); ordinary IP tools then ride the mesh:

sudo prpd --config periplus.toml --plane plexus0 --plane-name ord-01
# prpd logs its fd73:: address; from another plane host:
ping6 <fd73-address>

Add the built-in resolver so names work for unmodified programs — <name>.host.fd73 resolves to a node's fd73:: address, and the daemon forwards everything else upstream:

sudo prpd --config periplus.toml --plane plexus0 --plane-name ord-01 \
          --plane-dns 127.0.0.1:53 --plane-upstream 1.1.1.1:53
# point the host's resolver at 127.0.0.1, then:
ping6 ord-01.host.fd73
ssh me@mjh.host.fd73

Enrollment and naming are loopback DNS lookups: dig enroll.ca.fd73 mints a certificate and registers with the mesh's CA, and dig <name>.enroll.dns.fd73 claims a name. Run a CA with --ca; trust one elsewhere with --trust-root <its public key>.


Full protocol details are in RFC 0001. --help on any command or subcommand prints its full options.