docs: refresh for the SERVER/OUTBOUND rename, OBP_BRIDGES, and Unix-socket feed
Documentation audit for the recent changes:
* MODE terminology MASTER->SERVER, PEER/CLIENT->OUTBOUND corrected across
README, INSTALL, CONFIGURING, ACLS, and the dashboard docs (the code only
accepts SERVER/OUTBOUND/OPENBRIDGE, so the old names in docs were wrong).
* README gains a top-of-file breaking-change warning (OBP routing moved to
OBP_BRIDGES; system-mode rename) with a pointer to the migration tool.
* CONFIGURING documents REPORT_TRANSPORT/REPORT_SOCKET (Unix-socket feed) and
a "Migrating from the old inline form" section for tools/migrate_obp_rules.py.
* dashboard/README documents HBLINK_TRANSPORT/HBLINK_SOCKET and corrects the
stale "changes appear on the next snapshot" claim (connect/disconnect are
granular pushes now).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
b43ea79c48
commit
a3e99a2da9
6 files changed
+59
-32
No files matched your search
@@ -79,7 +79,7 @@ HBlink3 applies four kinds of ACL. Each is a separate config key.
|
||||
|
||||
| Key | Gates | Value domain | Notes |
|
||||
|-----|-------|--------------|-------|
|
||||
| `REG_ACL` | **Repeater/peer registration** (login) | peer IDs, `1 … 4294967295` | Only meaningful on **server (master)** systems. Peers/OpenBridge don't register. **Always enforced** — see §5. |
|
||||
| `REG_ACL` | **Repeater/peer registration** (login) | peer IDs, `1 … 4294967295` | Only meaningful on **SERVER** systems. Outbound/OpenBridge links don't accept registrations. **Always enforced** — see §5. |
|
||||
| `SUB_ACL` | **Subscriber** (the source radio ID of a call) | subscriber IDs, `1 … 16776415` | Applied to every voice/data stream. |
|
||||
| `TGID_TS1_ACL` | **Destination talkgroup on Timeslot 1** | talkgroup IDs, `1 … 16776415` | |
|
||||
| `TGID_TS2_ACL` | **Destination talkgroup on Timeslot 2** | talkgroup IDs, `1 … 16776415` | |
|
||||
@@ -200,11 +200,11 @@ TGID_TS1_ACL: PERMIT:2,9,3120
|
||||
TGID_TS2_ACL: PERMIT:3120,31205
|
||||
```
|
||||
|
||||
**Registration control on a master.** Accept only two specific repeater IDs onto
|
||||
this master; reject all other login attempts:
|
||||
**Registration control on a server.** Accept only two specific repeater IDs onto
|
||||
this server; reject all other login attempts:
|
||||
|
||||
```ini
|
||||
[MASTER-1]
|
||||
[SERVER-1]
|
||||
MODE: SERVER
|
||||
REG_ACL: PERMIT:311111,311222
|
||||
```
|
||||
|
||||
+20
-6
@@ -4,7 +4,7 @@ HBlink3's conference bridge (`bridge.py`) is driven by two files:
|
||||
|
||||
| File | What it defines |
|
||||
|---|---|
|
||||
| `hblink.cfg` | The program itself: global timers, reporting, logging, alias lookups, and one stanza per **system** (a Server you host, a Client you dial out as, or an OpenBridge link). |
|
||||
| `hblink.cfg` | The program itself: global timers, reporting, logging, alias lookups, and one stanza per **system** (a Server you host, an Outbound system you dial out as, or an OpenBridge link). |
|
||||
| `rules.py` | The **routing**: which systems talk to which, on what timeslot/talkgroup, and the talkgroup triggers/timers that turn bridges on and off. |
|
||||
|
||||
This document is the full field reference. The sample files (`hblink-SAMPLE.cfg`, `rules_SAMPLE.py`) carry only terse inline notes and point back here.
|
||||
@@ -22,12 +22,12 @@ INI format (`configparser`). Section names in `[BRACKETS]`; `KEY: value` pairs.
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| `PATH` | Working directory for runtime files. `./` (the program's own directory) is normal. |
|
||||
| `PING_TIME` | Seconds between keepalive pings on Server/Client connections. |
|
||||
| `PING_TIME` | Seconds between keepalive pings on Server and Outbound connections. |
|
||||
| `MAX_MISSED` | Missed pings before a connection is declared dead and torn down. |
|
||||
| `PING_LOSS_WINDOW` | Optional (default `5`, range `1`–`60`). Minutes over which the dashboard measures each repeater's **ping loss** — the share of expected keepalive pings that went missing. Larger = smoother / longer memory. Surfaces a repeater that stays connected but has a lossy link (choppy audio). A repeater that merely pings less often is not counted as lossy. |
|
||||
| `PING_LOSS_WARN` | Optional (default `5`). Ping-loss **percent** at or above which the dashboard turns a repeater's callsign gold. `0` disables the flag. |
|
||||
| `USE_ACL` | `True`/`False` top-level on/off switch for the **global** ACLs below. System-level ACLs are independent of this. |
|
||||
| `REG_ACL` | Registration ACL — which Client **radio IDs** may log in to any Server you host. ACL syntax below. |
|
||||
| `REG_ACL` | Registration ACL — which **repeater radio IDs** may log in to any Server you host. ACL syntax below. |
|
||||
| `SUB_ACL` | Subscriber ACL — which **subscriber IDs** (the person keying up) may pass traffic, globally. |
|
||||
| `TGID_TS1_ACL` / `TGID_TS2_ACL` | Talkgroup ACLs applied to timeslot 1 / timeslot 2 traffic, globally. |
|
||||
|
||||
@@ -42,7 +42,7 @@ DENY:1-5,3120101 # block the range 1–5 and the single ID 3120101
|
||||
PERMIT:3100-3199,9 # allow only this range and ID 9; deny everything else
|
||||
```
|
||||
|
||||
A global ACL and a system ACL both apply — traffic must pass **both**. Registration ACLs are only meaningful for `SERVER` systems (a Client or OpenBridge link never registers). See **[ACLS.md](ACLS.md)** for the full ACL model — PERMIT/DENY precedence, how ranges are matched, and worked examples.
|
||||
A global ACL and a system ACL both apply — traffic must pass **both**. Registration ACLs are only meaningful for `SERVER` systems (an Outbound or OpenBridge link never accepts registrations). See **[ACLS.md](ACLS.md)** for the full ACL model — PERMIT/DENY precedence, how ranges are matched, and worked examples.
|
||||
|
||||
## `[REPORTS]`
|
||||
|
||||
@@ -52,8 +52,12 @@ Feeds the real-time dashboard. See [`dashboard/`](dashboard/).
|
||||
|---|---|
|
||||
| `REPORT` | `True`/`False` — emit the event stream at all. |
|
||||
| `REPORT_INTERVAL` | Seconds between periodic status reports. |
|
||||
| `REPORT_PORT` | TCP port the report service listens on. |
|
||||
| `REPORT_CLIENTS` | Comma-separated client IPs allowed to connect (e.g. `127.0.0.1`). |
|
||||
| `REPORT_TRANSPORT` | Optional (default `tcp`). `tcp` = listen on a TCP port (dashboard may be remote); `unix` = listen on a local Unix-domain socket instead. A same-box dashboard on a Unix socket can't be broken by a NIC flap or connection-tracking eviction, so use `unix` when the dashboard runs on the same host. |
|
||||
| `REPORT_PORT` | TCP port the report service listens on (when `REPORT_TRANSPORT` = `tcp`). |
|
||||
| `REPORT_SOCKET` | Filesystem path for the listening socket (when `REPORT_TRANSPORT` = `unix`), e.g. `/tmp/hblink3-report.sock`. Access is governed by filesystem permissions; `REPORT_CLIENTS` is not used on a Unix socket. |
|
||||
| `REPORT_CLIENTS` | Comma-separated client IPs allowed to connect (e.g. `127.0.0.1`) — TCP only. |
|
||||
|
||||
> The dashboard has matching `HBLINK_TRANSPORT` (`tcp`/`unix`) and `HBLINK_SOCKET` settings — see [dashboard/README.md](dashboard/README.md). Point the dashboard at the same transport the daemon serves.
|
||||
|
||||
## `[LOGGER]`
|
||||
|
||||
@@ -239,6 +243,16 @@ Read one row as **"on this OpenBridge, this TGID *is* this bridge."** That singl
|
||||
|
||||
`OBP_BRIDGES` is optional — omit it (or leave it `{}`) if you run no OpenBridges.
|
||||
|
||||
### Migrating from the old inline form
|
||||
|
||||
Earlier HBlink3 configured OpenBridge systems as inline `BRIDGES` members. To convert an existing `rules.py`, run the migration tool from the repo root:
|
||||
|
||||
```bash
|
||||
python tools/migrate_obp_rules.py --config hblink.cfg --rules rules.py --out rules.py.migrated
|
||||
```
|
||||
|
||||
It reads `hblink.cfg` to learn which systems are `OPENBRIDGE`, lifts each inline OBP member into `OBP_BRIDGES`, prints a summary of what moved, flags any ingress-fork **ERROR** or renumber **WARNING**, and writes a new file (it never overwrites your `rules.py`). Review the output — comments from the original are not carried over — then replace `rules.py` with it.
|
||||
|
||||
## `UNIT`
|
||||
|
||||
```python
|
||||
|
||||
+6
-5
@@ -38,11 +38,11 @@ Edit `hblink.cfg`:
|
||||
- **[LOGGER]** — log file, handlers, and level.
|
||||
- **[ALIASES]** — optional download of repeater/subscriber ID files from radioid.net.
|
||||
- **System stanzas** — one per connection. Set `MODE` to:
|
||||
- `MASTER` — accept incoming repeaters/hotspots
|
||||
- `PEER` — connect outward to another master
|
||||
- `SERVER` — accept incoming repeaters/hotspots (formerly `MASTER`)
|
||||
- `OUTBOUND` — connect outward to another server (formerly `PEER`/`CLIENT`)
|
||||
- `OPENBRIDGE` — link to Brandmeister / DMR+ (IPSC2)
|
||||
|
||||
Duplicate a stanza for each system; the stanza name (e.g. `[MASTER-1]`) must be unique.
|
||||
Duplicate a stanza for each system; the stanza name (e.g. `[SERVER-1]`) must be unique.
|
||||
|
||||
If you are running `bridge.py`, also create the rules file:
|
||||
|
||||
@@ -53,9 +53,10 @@ cp rules_SAMPLE.py rules.py
|
||||
`rules.py` defines:
|
||||
|
||||
- **`BRIDGES`** — each conference bridge and the system / timeslot / talkgroup that belongs to it, with optional ON/OFF/RESET trigger talkgroups and timeouts.
|
||||
- **`OBP_BRIDGES`** — OpenBridge (`OPENBRIDGE`) systems only: a per-OBP `{bridge: TGID}` table (not inline `BRIDGES` members). See [CONFIGURING.md](CONFIGURING.md#obp_bridges).
|
||||
- **`UNIT`** — the systems permitted to exchange private (unit) calls.
|
||||
|
||||
Every system named in `rules.py` must exist and be enabled in `hblink.cfg`.
|
||||
Every system named in `rules.py` must exist and be enabled in `hblink.cfg`. **Upgrading from an older HBlink3?** OpenBridge members used to live inline in `BRIDGES`; convert your file with `python tools/migrate_obp_rules.py` (see [CONFIGURING.md](CONFIGURING.md#obp_bridges)).
|
||||
|
||||
## 3. Run
|
||||
|
||||
@@ -65,7 +66,7 @@ python bridge.py -c hblink.cfg -r rules.py # conference-bridge router (main
|
||||
# or
|
||||
python bridge_all.py -c hblink.cfg # forward-everything proxy
|
||||
# or
|
||||
python hblink.py -c hblink.cfg # protocol core, standalone master/peer
|
||||
python hblink.py -c hblink.cfg # protocol core, standalone server/outbound
|
||||
```
|
||||
|
||||
`-c` / `-r` default to `hblink.cfg` and `rules.py` in the program directory. `-l LEVEL` overrides the configured log level.
|
||||
|
||||
@@ -4,17 +4,23 @@ HBlink3 is an open-source implementation of the DMR **HomeBrew Repeater Protocol
|
||||
|
||||
> **Which HBlink?** HBlink3 is "system-oriented" and built for **transit routing and conference bridging** between networks. Its companion, **HBlink4** (by the same author), is a repeater-oriented **endpoint server** for running a single end-point network with no granudlar transit routing. Pick the one that matches your role.
|
||||
|
||||
> ⚠️ **Upgrading? Two breaking config changes to know about.**
|
||||
> 1. **OpenBridge routing moved** — `MODE: OPENBRIDGE` systems are no longer inline `BRIDGES` members in `rules.py`; they now live in a dedicated **`OBP_BRIDGES`** table. Old configs stop with a clear startup error. Run **`python tools/migrate_obp_rules.py`** to convert your `rules.py` automatically, or see [CONFIGURING.md](CONFIGURING.md#obp_bridges).
|
||||
> 2. **System modes renamed** — `MASTER`→**`SERVER`** and `PEER`/`CLIENT`→**`OUTBOUND`** (`OPENBRIDGE` unchanged). Update the `MODE:` line of each stanza in `hblink.cfg`.
|
||||
>
|
||||
> Your `hblink.cfg`/`rules.py` are git-ignored, so a `git pull` won't touch them — but the new code won't accept the old values. Non-OpenBridge configs need only change (2).
|
||||
|
||||
## Applications
|
||||
|
||||
| Program | Purpose |
|
||||
|---|---|
|
||||
| `bridge.py` | The main application: a configurable conference-bridge call router with dynamic on/off triggering, timeouts, and private (unit) call routing. |
|
||||
| `bridge_all.py` | A simple proxy that forwards all traffic between every configured system — makes several repeaters appear as one. |
|
||||
| `hblink.py` | The protocol core. Runs standalone as a master/peer for testing, and is the module the applications are built on. |
|
||||
| `hblink.py` | The protocol core. Runs standalone as a server/outbound system for testing, and is the module the applications are built on. |
|
||||
|
||||
## Features
|
||||
|
||||
- HBP **server** (master) and **client** (peer) modes for MMDVM repeaters and hotspots
|
||||
- HBP **server** and **outbound** (client) modes for MMDVM repeaters and hotspots
|
||||
- **OpenBridge** connectivity to other transit call routers, including Brandmeister / DMR+ (IPSC2)
|
||||
- Rules-based **conference-bridge routing** with dynamic ON/OFF/RESET talkgroup triggers and timeouts, including the ability to use TGIDs as in-band signalling to trigger dynamic connections -- sometimes referred to as "dial-a-talkgroup".
|
||||
- **Private (unit) call** routing using a learned subscriber-to-system map that only floods systems configured for unit calls, and only until the target unit's system is located. It then prunes re-transmission to the system with the target unit.
|
||||
@@ -38,7 +44,7 @@ See **[INSTALL.md](INSTALL.md)** for full setup, configuration, and running as a
|
||||
|
||||
## Configuration
|
||||
|
||||
- **`hblink.cfg`** — global settings, reporting, logging, alias downloads, and one stanza per system (`MASTER`, `PEER`, or `OPENBRIDGE`). Start from `hblink-SAMPLE.cfg`.
|
||||
- **`hblink.cfg`** — global settings, reporting, logging, alias downloads, and one stanza per system (`SERVER`, `OUTBOUND`, or `OPENBRIDGE`). Start from `hblink-SAMPLE.cfg`.
|
||||
- **`rules.py`** — (`bridge.py` only) defines the conference bridges, the systems/talkgroups/timeslots that belong to each, and the systems permitted to pass unit calls. Start from `rules_SAMPLE.py`.
|
||||
|
||||
Your `hblink.cfg` and `rules.py` are git-ignored, so `git pull` won't overwrite them.
|
||||
@@ -79,7 +85,7 @@ used. Talkgroup IDs not present in the file are displayed as their raw numeric v
|
||||
## Dashboard
|
||||
|
||||
A real-time web dashboard lives in [`dashboard/`](dashboard/) — a separate program
|
||||
with a modern dark UI showing master/peer/OpenBridge systems, conference-bridge
|
||||
with a modern dark UI showing server/outbound/OpenBridge systems, conference-bridge
|
||||
state, and a live call log. Enable HBlink3's reporting feed (`[REPORTS]` in
|
||||
`hblink.cfg`) and see [dashboard/README.md](dashboard/README.md) to run it. the dashboard
|
||||
is kept separate to keep performance of the forwarding hot path free from unecessary
|
||||
|
||||
+7
-7
@@ -39,16 +39,16 @@ and its state is remembered in your browser.
|
||||
|
||||
---
|
||||
|
||||
## Master Systems
|
||||
## Server Systems
|
||||
|
||||
One block per HBlink3 **MASTER** instance (repeaters/hotspots connect *to* it).
|
||||
One block per HBlink3 **SERVER** instance (repeaters/hotspots connect *to* it).
|
||||
|
||||
**Block heading**
|
||||
|
||||
| Element | Meaning |
|
||||
|---|---|
|
||||
| System name | The master's name from `hblink.cfg` (e.g. `MASTER-1`). |
|
||||
| `repeat` / `isolate` pill | `repeat` if the master forwards traffic between its own peers (`REPEAT: True`), `isolate` if it does not. |
|
||||
| System name | The server's name from `hblink.cfg` (e.g. `SERVER-1`). |
|
||||
| `repeat` / `isolate` pill | `repeat` if the server forwards traffic between its own repeaters (`REPEAT: True`), `isolate` if it does not. |
|
||||
| *N* peer(s) | How many repeaters/hotspots are currently logged in. |
|
||||
| Show/Hide Connections | Collapses this system's connection table. When collapsed, system-level TS1/TS2 activity pills replace it so live calls stay visible. Default from `SERVER_REPEATERS`; per-system state is remembered in your browser. |
|
||||
|
||||
@@ -64,10 +64,10 @@ One block per HBlink3 **MASTER** instance (repeaters/hotspots connect *to* it).
|
||||
|
||||
---
|
||||
|
||||
## Peer Systems
|
||||
## Outbound Systems
|
||||
|
||||
One row per HBlink3 **PEER** instance (HBlink3 connecting *out* to an upstream
|
||||
master, e.g. another HBlink or a BrandMeister/IPSC2 server).
|
||||
One row per HBlink3 **OUTBOUND** instance (HBlink3 connecting *out* to an upstream
|
||||
server, e.g. another HBlink or a BrandMeister/IPSC2 server).
|
||||
|
||||
| Column | Meaning |
|
||||
|---|---|
|
||||
|
||||
+12
-6
@@ -14,13 +14,13 @@ full-table refreshes, and no pickle on the wire.
|
||||
- **Last Heard** — the most-recent unique callers (user, call type, source
|
||||
repeater, timeslot, talkgroup, and when), derived live from the call log. The
|
||||
table is collapsible; its open/closed state is remembered in your browser.
|
||||
- **Master Systems** — each master and its connected repeaters (ID, callsign,
|
||||
- **Server Systems** — each server and its connected repeaters (ID, callsign,
|
||||
location, IP, uptime, frequency, colorcode, slots) with the live call on each
|
||||
timeslot (source → destination, color-coded by direction). Each server's
|
||||
connection list can be collapsed with the **Show/Hide Connections** button;
|
||||
when collapsed, system-level TS1/TS2 activity pills replace the table so you
|
||||
still see what's talking. State is remembered per-browser.
|
||||
- **Peer Systems** — outbound peer connections with health (connection state,
|
||||
- **Outbound Systems** — outbound connections with health (connection state,
|
||||
pings sent/ackd/lost) and live per-timeslot calls.
|
||||
- **OpenBridge Systems** — network ID, target, and active streams.
|
||||
- **Conference Bridges** — each bridge's members: timeslot, talkgroup,
|
||||
@@ -45,7 +45,11 @@ Open `http://<host>:8080`.
|
||||
## Configuration (`config.py`)
|
||||
|
||||
- `HBLINK_IP` / `HBLINK_PORT` — HBlink3's reporting feed (the `[REPORTS]` section
|
||||
of `hblink.cfg`: `REPORT_PORT`, default 4321).
|
||||
of `hblink.cfg`: `REPORT_PORT`, default 4321). Used when `HBLINK_TRANSPORT` is `tcp`.
|
||||
- `HBLINK_TRANSPORT` / `HBLINK_SOCKET` — optional. Set `HBLINK_TRANSPORT = 'unix'`
|
||||
and `HBLINK_SOCKET` to the daemon's `REPORT_SOCKET` path to connect over a local
|
||||
Unix socket instead of TCP (same-box dashboard; immune to NIC flaps / conntrack
|
||||
eviction). Defaults to `tcp`. Must match the daemon's `REPORT_TRANSPORT`.
|
||||
- `WEB_HOST` / `WEB_PORT` — where the dashboard listens.
|
||||
- `PATH` / `*_FILE` — alias files mapping DMR IDs to callsigns/talkgroup names
|
||||
(the same files HBlink3 uses; point `PATH` at HBlink3's directory to share them).
|
||||
@@ -64,9 +68,11 @@ In `hblink.cfg`, under `[REPORTS]`:
|
||||
- `REPORT: True`
|
||||
- `REPORT_PORT` must match the dashboard's `HBLINK_PORT`
|
||||
- `REPORT_CLIENTS` must include the dashboard host's IP (or `*`)
|
||||
- `REPORT_INTERVAL` sets how often the systems/bridge snapshot is refreshed.
|
||||
**Live calls are pushed instantly**; connection/peer-state changes appear on the
|
||||
next snapshot, so `10` is a good value for dashboard use.
|
||||
- `REPORT_INTERVAL` sets how often the full systems/bridge snapshot is resent as a
|
||||
slow resync. **Live calls and repeater connect/disconnect are pushed as they
|
||||
happen** (granular events); the periodic snapshot is just a safety-net resync and
|
||||
also carries the per-repeater ping-quality figures, so a larger value like `60`
|
||||
is fine.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
Reference in new issue
Block a user