fix(packaging): correct CachyOS firewall to ufw + ship ufw openers + web-console opener
apple / swift (push) Successful in 1m11s
android / android (push) Successful in 4m1s
apple / screenshots (push) Successful in 4m29s
arch / build-publish (push) Successful in 5m52s
ci / web (push) Successful in 1m16s
ci / docs-site (push) Successful in 1m11s
ci / rust (push) Successful in 4m54s
deb / build-publish (push) Successful in 3m0s
decky / build-publish (push) Successful in 24s
ci / bench (push) Successful in 4m44s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 32s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 2m50s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m30s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 53s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 2m18s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 10m14s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 10m5s
docker / deploy-docs (push) Successful in 22s

CachyOS ships ufw enabled by default (firewalld is not installed) — verified live
on the .21 box — but the docs and shipped firewall openers claimed "CachyOS enables
firewalld by default". Correct that everywhere and ship a ufw application profile
(the one-liner analogue of the firewalld service files):

- packaging/linux/punktfunk.ufw (new): [punktfunk-native], [punktfunk-gamestream],
  [punktfunk-web] profiles, installed to /etc/ufw/applications.d/punktfunk by the
  Arch (CachyOS) and .deb host packages. `sudo ufw allow punktfunk-native`.
- packaging/linux/punktfunk-web.xml (new): firewalld service for the optional web
  console (TCP 47992), installed by the host package on arch/deb/rpm. Neither the
  native nor gamestream opener covered 47992, so a firewalld/ufw host that enabled
  punktfunk-web could not reach the console over the LAN.
- Fix the "CachyOS enables firewalld" claim in arch.md, arch/README.md,
  debian/README.md, both firewalld service .xml comments, and the pacman scriptlet;
  firewalld now attributed to the spins that use it (EndeavourOS, Fedora/RHEL).
- Docs present both one-liners (ufw + firewalld) whichever firewall you run, plus a
  console-opener step; postinst/scriptlet hints detect ufw as well as firewalld.

The native data plane stays hole-punched (ephemeral UDP, no fixed port) — its
openers correctly open only 9777/udp + mDNS; the stale "open a UDP range" note is
replaced with the accurate outbound-UDP explanation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-05 16:52:35 +00:00
parent e27718b406
commit c2bc72a8e9
11 changed files with 197 additions and 73 deletions
+40 -26
View File
@@ -139,33 +139,45 @@ so it's a much lighter sysext than the host.
**Stock Arch ships no firewall** — every port is open by default, so there is nothing to do.
Spins that enable one **do not** get their ports opened for you: an Arch package never touches the
admin's running firewall. **CachyOS is the common case** — its installer turns on `firewalld` by
default, so out of the box the host is unreachable until you allow it.
admin's running firewall. **CachyOS is the common case** — it ships `ufw` enabled by default (not
firewalld), so out of the box the host is unreachable until you allow it. Some other spins (e.g.
EndeavourOS) enable `firewalld` instead.
The `punktfunk-host` package ships **firewalld service definitions** (installed to
`/usr/lib/firewalld/services/`) so enabling is one command — pick the plane your host serves:
The `punktfunk-host` package ships openers for **both** — a ufw application profile
(`/etc/ufw/applications.d/punktfunk`) and firewalld service definitions
(`/usr/lib/firewalld/services/`) — so enabling is one command whichever you run:
```sh
# Reload once so firewalld picks up the just-installed service definition, add it, reload to apply.
sudo firewall-cmd --reload
sudo firewall-cmd --permanent --add-service=punktfunk-gamestream # Moonlight/GameStream host
# --add-service=punktfunk-native # …or the native-only host
# ufw (CachyOS, and Ubuntu once you enable ufw) — reads the profile at once, no reload needed:
sudo ufw allow punktfunk-native # the native-only host (the default)
sudo ufw allow punktfunk-gamestream # …or add this for the Moonlight/GameStream host
# firewalld (EndeavourOS and other Fedora-like spins):
sudo firewall-cmd --reload # pick up the installed def
sudo firewall-cmd --permanent --add-service=punktfunk-native
# --add-service=punktfunk-gamestream # …for the Moonlight host
sudo firewall-cmd --reload
```
`punktfunk-gamestream` opens the fixed Moonlight ports + mDNS; `punktfunk-native` opens the QUIC
control port (UDP 9777) + mDNS. Enable both if the host runs `serve --gamestream` (which serves
both planes). The **data plane is an *ephemeral* UDP port** negotiated per session, so there is no
fixed data port in either service; a restrictive firewall must additionally allow a UDP range (the
project does not pin one). The mgmt REST API (TCP 47990) binds to loopback by default — leave it
closed unless you move it off loopback with `--mgmt-bind IP:PORT` (which then requires
`--mgmt-token`).
both planes). The **data plane is an *ephemeral* UDP port** the client opens with a hole-punch, so
there is no fixed data port in either service — the host streams back out through the path the
client opened, which any firewall that allows outbound UDP (the default) passes. The mgmt REST API
(TCP 47990) binds to loopback by default — leave it closed unless you move it off loopback with
`--mgmt-bind IP:PORT` (which then requires `--mgmt-token`).
For a non-firewalld setup, open the ports directly. The **native `punktfunk/1`** plane:
If you installed the **web console** (`punktfunk-web`) and want it reachable from another device,
open its port with the matching one-liner — `sudo ufw allow punktfunk-web` or `sudo firewall-cmd
--permanent --add-service=punktfunk-web && sudo firewall-cmd --reload` — which opens **TCP 47992**
(HTTPS, login-gated). The mgmt API (47990) stays loopback-only.
Prefer explicit rules (or a firewall the shipped profiles don't cover)? Open the ports directly.
The **native `punktfunk/1`** plane:
- **QUIC control plane: UDP 9777** (`serve --native-port N` to change).
- **Data plane: an *ephemeral* UDP port** — negotiated per session, so there is no fixed port to
open. For a restrictive firewall you'd need to allow a UDP range (the repo does not pin one).
- **Data plane: an *ephemeral* UDP port** the client hole-punches — nothing to open inbound as long
as outbound UDP is allowed (the host streams back out through the client-opened path).
And the **GameStream / Moonlight** ports (fixed) — only needed if you run the host with
`serve --gamestream` (opt-in, trusted LAN only); bare `serve` is native-only and doesn't open these:
@@ -181,14 +193,14 @@ And the **GameStream / Moonlight** ports (fixed) — only needed if you run the
The mgmt API (TCP 47990) binds to loopback by default — leave it closed unless you move it off
loopback with `--mgmt-bind IP:PORT` (which then requires `--mgmt-token`).
With `ufw`:
With `ufw` (explicit ports, instead of the shipped `punktfunk-native`/`punktfunk-gamestream` profile):
```sh
sudo ufw allow 9777/udp # punktfunk/1 control plane
sudo ufw allow 47984/tcp && sudo ufw allow 47989/tcp && sudo ufw allow 48010/tcp
sudo ufw allow 47998:48010/udp
sudo ufw allow 5353/udp
# plus the ephemeral punktfunk/1 data port — open a UDP range you reserve for it.
sudo ufw allow 47998,47999,48000/udp # GameStream video/control/audio
sudo ufw allow 5353/udp # mDNS discovery
# The punktfunk/1 data plane is an ephemeral UDP port the host hole-punches — nothing to open here.
```
With raw `nftables` (add to your `inet filter input` chain):
@@ -196,18 +208,20 @@ With raw `nftables` (add to your `inet filter input` chain):
```
udp dport 9777 accept # punktfunk/1 control plane
tcp dport { 47984, 47989, 48010 } accept
udp dport { 47998-48010, 5353 } accept
# plus the ephemeral punktfunk/1 data port (a reserved UDP range).
udp dport { 47998-48000, 5353 } accept # GameStream video/control/audio + mDNS
# The punktfunk/1 data plane is an ephemeral UDP port the host hole-punches — a stateful chain that
# accepts ct state established,related (as this one should) passes the return with nothing extra.
```
## Files
- `PKGBUILD` — split package: `punktfunk-host` + `punktfunk-client` (builds the working tree via
`PF_SRCDIR`, or a git tag for AUR).
- `punktfunk-host.install` / `punktfunk-client.install` — pacman scriptlets (udev reload + sysctl +
first-run hint, incl. the firewalld enable command when firewalld is present), mirror the RPM
first-run hint, incl. the ufw/firewalld enable command for whichever is present), mirror the RPM
`%post` / deb postinst.
- The firewalld service definitions (`punktfunk-gamestream.xml` / `punktfunk-native.xml`) are shared
across all Linux packaging and live in [`../linux/`](../linux/); the host package installs them to
`/usr/lib/firewalld/services/` (not auto-enabled; see Firewall above).
- The firewall openers are shared across all Linux packaging and live in [`../linux/`](../linux/):
the ufw application profile (`punktfunk.ufw``/etc/ufw/applications.d/punktfunk`) and the
firewalld service definitions (`punktfunk-native.xml` / `punktfunk-gamestream.xml` /
`punktfunk-web.xml``/usr/lib/firewalld/services/`). None auto-enabled; see Firewall above.
- `build-sysext.sh` — wraps either built `.pkg.tar.zst` into a `systemd-sysext` `.raw` for SteamOS
(derives the name from the package, so it works for host or client).