Remove the Python source excerpts, return-value structure, and the 'how matching works' section that would confuse most operators; keep the config grammar, examples, performance guidance, and warnings. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8.1 KiB
DMRlink3 Access Control Lists (ACLs)
DMRlink3 shares its ACL engine with HBlink3, but because of what DMRlink3 is —
a Motorola MOTOTRBO IPSC bridge/monitor — it applies ACLs in a narrower, more
focused way. In DMRlink3 the ACL system is primarily about peer registration:
deciding which repeaters/peers are allowed to join an IPSC network where
DMRlink3 is the master. The bridge application adds one global subscriber
filter on top. This document explains the grammar, the exact matching rules
(verified against config.py, dmrlink.py, and bridge.py), worked examples,
and honest performance guidance.
ACLs here are cheap and safe. Read the Performance section — for an IPSC master, a registration ACL is close to free and is your first line of defense.
1. The two-part grammar
Every ACL is a single string of the form:
ACTION:entry,entry,entry,...
- ACTION is either
PERMITorDENY. - entries are comma-separated, and each entry is one of:
- a single ID — e.g.
12345 - a range — two IDs joined by a hyphen, low first — e.g.
1000-2000 - the literal keyword
ALL— matches every possible ID.
- a single ID — e.g.
Examples of valid ACLs:
PERMIT:ALL
DENY:1
PERMIT:311111,311222,312000-312099
DENY:3120101,3120124
An empty value is treated as PERMIT:ALL (permit everything).
There is exactly one ACTION per ACL. You cannot mix
PERMITandDENYentries in the same list.
2. The single most important rule: what happens to IDs you didn't list
This is the part that trips everyone up, so read it twice.
An ACL does two things at once. It defines an ACTION for the IDs you list, and it implies the opposite ACTION for every ID you don't list.
| You write | A listed ID is… | An unlisted ID is… | Mental model |
|---|---|---|---|
PERMIT:… |
permitted | denied | whitelist — only these get in |
DENY:… |
denied | permitted | blacklist — everyone except these |
So for a registration ACL:
PERMIT:311111,311222means "only peers 311111 and 311222 may register, reject every other login."DENY:311999means "reject peer 311999, accept every other peer."
A listed ID gets the ACTION; an unlisted ID gets the opposite.
Rule of thumb: use PERMIT: when you run a closed IPSC network and want only
a known list of repeaters to join. Use DENY: when you want an otherwise-open
network minus a few blocked IDs.
3. The two ACLs DMRlink3 actually uses
Unlike HBlink3, DMRlink3 does not apply per-timeslot talkgroup ACLs or
per-system subscriber ACLs. Its process_acls() wires up exactly two:
| Key | Where | Gates | Value domain | Enforced when |
|---|---|---|---|---|
REG_ACL |
per-system ([SAMPLE-PEER] etc.) |
Peer registration (an IPSC peer requesting to join) | peer IDs, 1 … 4294967295 |
Only when MASTER_PEER: True |
SUB_ACL |
[GLOBAL] only |
Subscriber source ID of a group/private call passing through the bridge | subscriber IDs, 1 … 16776415 |
When the bridge (bridge.py) is running |
3a. REG_ACL — the heart of DMRlink3 ACLs
A registration ACL only makes sense on a system where DMRlink3 is the IPSC
master (MASTER_PEER: True). When a peer sends a registration request,
DMRlink3 checks the peer's ID against REG_ACL and, if it is denied, refuses the
registration and logs Peer Registration ***REJECTED BY ACL***.
If DMRlink3 is a peer on someone else's master (MASTER_PEER: False), the
REG_ACL is ignored — a peer does not decide who else joins the master's
network. The sample config says so directly:
# REG_ACL is ignored when MASTER_PEER: False — peers don't control registration
REG_ACL: PERMIT:ALL
Registration IDs are peer IDs and are validated against the full 32-bit range
(1 … 4294967295, const.PEER_MAX).
3b. SUB_ACL — global subscriber gate on the bridge
When the bridge is running, it checks the global SUB_ACL against the source
subscriber before propagating a call, and drops the call (logging
***REJECTED BY ACL***) if the subscriber is denied.
There is only one SUB_ACL, in [GLOBAL]. It is checked against subscriber
IDs (1 … 16776415, const.ID_MAX). Set it to PERMIT:ALL if you don't want
subscriber filtering.
USE_ACL in [GLOBAL] is the master enable switch for subscriber filtering.
4. Worked examples
Closed IPSC network (recommended for a private master). Only these repeaters may register; everything else is rejected:
[MY-IPSC-MASTER]
MASTER_PEER: True
REG_ACL: PERMIT:311111,311222,311333
Open network minus a few bad actors. Accept any peer except two known-bad IDs:
[MY-IPSC-MASTER]
MASTER_PEER: True
REG_ACL: DENY:311998,311999
Registering a block of site repeaters by range. Allow an allocated peer-ID block plus one out-of-block gateway:
[MY-IPSC-MASTER]
MASTER_PEER: True
REG_ACL: PERMIT:311000-311099,312500
Global subscriber blacklist on the bridge. Let all subscribers through except a few, while leaving registration wide open:
[GLOBAL]
USE_ACL: True
SUB_ACL: DENY:1,2606234,3141592
[MY-IPSC-MASTER]
MASTER_PEER: True
REG_ACL: PERMIT:ALL
Members-only subscriber policy on the bridge. Only your membership block may be bridged:
[GLOBAL]
USE_ACL: True
SUB_ACL: PERMIT:3120000-3120999
Large but efficient range list. Adjacent and contiguous ranges are merged at load time, so this…
REG_ACL: PERMIT:311000-311099,311100-311199,311200-311299,312500
…collapses internally to a single span 311000–311299 plus the single ID
312500. Write ranges however is clearest to you; the engine tidies them up.
Performance
Short version: on an IPSC master, use a REG_ACL. It costs almost nothing.
- All of the work of reading and organizing your ACLs happens once, when DMRlink3 starts — not while traffic is flowing.
- Registration is a rare event (a peer registers, then periodically
re-registers on the ping interval). A
REG_ACLcheck runs a handful of times per peer per interval — utterly negligible, and it protects your network from unwanted peers. - The global
SUB_ACLis checked once per call on the bridge, and it stays fast no matter how long your list gets — a thousand entries is checked essentially as quickly as ten. You won't measure it. - Runs of consecutive IDs are combined internally, so a large-looking config often takes very little memory.
Practical guidance:
- Prefer ranges (
311000-311099) over listing many consecutive IDs — less typing, smaller memory, same speed. - A registration ACL is the single highest-value, lowest-cost ACL you can set on
a master. There is no performance reason to leave it at
PERMIT:ALLif you actually want to restrict who joins. - If you truly want no subscriber filtering,
USE_ACL: False(orSUB_ACL: PERMIT:ALL) skips it.
Warnings
PERMITis a whitelist — it rejects every peer/ID you didn't list. WritingREG_ACL: PERMIT:311111intending "also allow 311111" will lock out every other repeater on the network. Re-read Section 2.REG_ACLonly applies whenMASTER_PEER: True. On a peer system it is ignored — you cannot filter registrations on a network you don't master.- Out-of-range entries stop DMRlink3 at startup. A subscriber entry above
16776415, or a peer entry above 4294967295, triggers
ACL CREATION ERROR, VALUE OUT OF RANGEand the program exits. Recheck your numbers if DMRlink3 won't start after an ACL edit. - Write ranges low-to-high (
311000-311099, not311099-311000). A reversed range will silently never match. - There is only one
SUB_ACL, and it lives in[GLOBAL]. DMRlink3 does not read per-system subscriber or talkgroup ACLs — don't expect aSUB_ACLunder a peer stanza to do anything. USE_ACLgates the subscriber filter, not registration.REG_ACLon a master is governed byMASTER_PEER, not byUSE_ACL.