astar-server¶
astar-server is the node daemon: a long-running, headless process that
holds one IAX2 station open, answers inbound calls, optionally registers with
the AllStarLink registrar, and bridges everyone connected to it.
It is AllStarLink-first — it speaks the app_rpt link-layer dialect and
node-to-node ilink semantics — but plain IAX2 underneath. It is the same
engine the macOS app uses, with no UI attached.
Work in progress — read this before deploying one
The daemon runs and has been used against live nodes, but it is not
finished and is not a drop-in app_rpt replacement. Known gaps, each with
a backlog item:
| Gap | Item |
|---|---|
Inbound authentication is not wired to config. IncomingCallPolicy supports MD5 challenge/validate, but node.toml has no credentials map, so the practical default is an open listener. |
iax-12fb |
| The D-Star keying guard is a runtime check in the controller, not a build-level one. Cargo feature unification compiles D-Star into the daemon even though its manifest does not ask for it. | iax-d9f4 |
Node-to-node link control (*3 / *2 / *1) is not at parity with AllStar. |
iax-d829 |
| In-band DTMF from RX/mic is not decoded into the command mapper — DTMF commands arrive over the control channel only. | iax-72df |
/events is not flushed per frame, so the status page lags roughly 3 s. |
iax-5562 |
These pages document what exists today, so that anyone — human or agent — picking up one of those items can see the current shape without reading 6,400 lines of Rust first. Where behaviour is unfinished it says so.
What it does¶
- Inbound IAX2 listener on UDP 4569 (bind address, answer policy, call cap, authentication policy, and an optional caller allowlist are all configurable).
- Registration with an upstream registrar, so your node is reachable by number.
- Node-to-node links — connect (
*3), monitor (*2), disconnect (*1). - Conference bridge — mix-minus by default, so each member hears everyone but themselves; switchable live between handset, bridge and conference topologies.
- Voice / CW announcements — a station ID and per-event announcements (incoming call, hangup, registered, answered), optionally through a TTS binary.
- DTMF command execution — off by default, because enabling it lets any connected member command your links.
- A control channel: HTTP for commands, Server-Sent Events for a live stream, plus a small read-only status page.
Running it¶
cp deploy/node.toml.example node.toml # then edit it
just node # astar-server serve --config node.toml
Directly, without just:
astar-server serve --config node.toml # HTTP + SSE control channel
astar-server tui --config node.toml # interactive stdin menu
Two subcommands, one config file:
| Subcommand | What it is |
|---|---|
serve |
The daemon. Runs the control channel and the node loop until SIGINT, SIGTERM, or POST /shutdown. |
tui |
An interactive terminal menu over the same controller — handy for bring-up on a machine you are sitting in front of. |
Argument parsing is hand-rolled rather than clap: the binary accepts a
subcommand, --config <path>, and --help, and nothing else.
If the config path does not exist, serve writes a commented template there and
carries on with safe defaults rather than exiting — a daemon under
--restart=always must not crash-loop over a missing file.
Credentials never touch disk¶
The config file is secret-free by design
node.toml carries no passwords and no tokens. The registration secret
arrives at runtime, either from the environment (ALLSTAR_SECRET) or by
being POSTed to the loopback control port. The [portal] section names an
environment variable rather than holding a password.
Secrets are connect/init arguments only: they are never stored on a station, never present in snapshots, events or errors, and never logged. Do not put a password in an example config, a bug report, or a screenshot.
See Configuration.
Keying is operator-supervised¶
POST /key is remote keying
The control channel can key the transmitter. Bind it to loopback
(127.0.0.1) — every example here does — and treat a key command as
something a licensed operator does deliberately, not something a script
does on a timer.
POST /key is refused outright while a D-Star session is active:
D-Star is the one network this daemon must never key remotely. The guard is
key_refusal in controller.rs, checked on every NodeCommand::Key. See
Control API.
Working on it¶
The crate is crates/astar-server, about 6,400 lines of Rust. Where things
live:
| File | Lines | What is in it |
|---|---|---|
controller.rs |
2278 | The node loop and every NodeCommand. Start here — this is where behaviour lives. |
http.rs |
553 | The request router and JSON responses. One arm per route. |
main.rs |
372 | Argument parsing, config load, station construction, mode dispatch. |
tui.rs |
303 | The interactive menu, over the same controller as serve. |
dtmf_commands.rs |
254 | DTMF sequence to NodeCommand mapping. |
secrets.rs |
245 | Runtime secret injection. Nothing here is written to disk. |
server.rs |
196 | The HTTP listener and the /events SSE path, ahead of the router. |
sse.rs |
169 | Event serialization for the SSE stream. |
config.rs |
— | node.toml deserialization; one struct per section. |
template.rs |
85 | The commented config written when the file is missing. |
Tests are crates/astar-server/tests/config_bootstrap.rs and serve_wiring.rs,
plus unit tests inside the source files:
The controller is driven by a pump rather than threads-per-connection, so a
behaviour change is usually a new NodeCommand arm plus a route in http.rs
plus a menu entry in tui.rs — the three surfaces are deliberately parallel.
Two rules that are load-bearing rather than stylistic, and which a change here must not break:
- Secrets are in-args only. They never reach a
Station, a snapshot, an event, an error, or a log line.secrets.rsexists to keep it that way. - The
key_refusalguard stays.POST /keymust keep refusing whiledstar_active.iax-d9f4tracks making that structural instead of a runtime check; until then the runtime check is the only thing holding the line.
Next steps¶
- Configuration — every section of
node.toml. - Control API — the HTTP and SSE surface.
- Building astar-server — the build itself.