Repository navigation
v0.8.22 — xray loopback guard, one holder per credential, MTProto instance scoping, silent-core recovery, L2TP upgrade billing, x/net v0.62.0
LatestRelease commit e4b18be7589a76a6f1abb01f2d9f44284aba6a2e on main. Previous release: v0.8.21 (347da494). This
release carries the 41 commits in v0.8.21..v0.8.22 (86 files, +5673 / -308); every one is listed by
git log v0.8.21..v0.8.22. NodeVersion 0.6.22 (e05d805b). One patch step after v0.8.21.
Before the fleet rollout
- One node must pass the L2TP upgrade check below (OBS-a5) before any node is moved from 0.6.20, because that is the
path v0.8.21 billed wrongly. - Any panel config that gives two users the same VLESS id, VMess id or Trojan password now gives the credential to one
of them only (C2). Check the panel for shared credentials before the rollout.
Xray: no user reaches a loopback destination (C1)
- Own control ports (
a6af5dd7RED,90759cd5fix,7fd97ebepins): ApplyAPI writes two rules for this instance's
API and metrics ports, ahead of every panel rule, to a blackhole outbound the node adds itself. They cover loopback,
unspecified, link-local and the host's interface addresses, pluslocalhost,*.localhostand numeric host forms
(2130706433,127.1,0x7f000001,localhost.). They live in the config every clone, Restart and
restorePreviousConfig replays, and ApplyAPI stays idempotent. - Every loopback destination on the user inbounds (
decd7f1etest infra,e8594146RED,2e5f9649fix): two more
rules send 127.0.0.0/8, 0.0.0.0/8, 169.254.0.0/16, ::1/128, ::/128, fe80::/10 and the IPv4-mapped forms, plus
localhostand*.localhost, on every port, to the blackhole, only for inbounds the node manages users on (vless,
vmess, trojan, shadowsocks, hysteria). Panel dokodemo-door and other non-user inbounds keep the panel's routing. - Known residual, accepted: under
routing.domainStrategyAsIs, a public domain name whose DNS record points at
loopback is matched by neither rule. UnderIPIfNonMatchorIPOnDemandthe address rule catches it. Operators of
cores set toAsIsshould add their own private-address block (for examplegeoip:privateto a blackhole) or move
the core toIPIfNonMatch.
Xray: one holder per credential on every inbound (C2)
- Core patch (
fbaddb22RED,6283e614fix):patches/xray-validator-credential-owner.patch, the 20th fork patch at
the xray pind2758a0. VLESS and Trojan validators refuse a key another email holds and remove only what still
belongs to the removed user; VMess refuses a command key whose decoder belongs to another email and removes a decoder
only while the removed user holds it. The Dockerfile guards every changed file. - Node holder logic (
bb2f4b63RED,86959bdefix, newbackend/xray/credential.go): a user whose credential another
user holds is refused and waits; it is installed when the holder leaves, including through UpdateUsersAndRestart. A
removed user never takes another user's credential. A user that moves onto a held credential is refused and its old
account leaves the core. - A batch frees the keys its users move off before it admits anyone, and revokes every replaced account before adding
(db45fd9cRED,3adeb7c8fix). - Tests:
8083f007,40dd004b,96c12a19,86da26e5.
Xray: a silent core is restarted after its full sync was abandoned
- A health restart aborts a silent full sync even after its caller gave up (
2d195875RED,92504e43fix). - Readiness bounds are per-Xray fields with the production defaults (
32147e60RED,388b3581fix); an abort racing
a core that turns ready ends in one clean outcome (f498a706, interleaving test).
MTProto: instance scoping and per-instance live cut (C3/C4)
- Each MTProto instance accepts only users that have its inbound (
308ffcfcRED,cae14431fix). Before, a user taken
off one MTProto inbound but kept on another still authenticated on the one it lost. - A live session is cut the moment its user loses the inbound it authenticated on (
fafc7cbdRED,e8cd97f7fix,
merged in9498dde6). Sessions on the instances the user keeps, and other users' sessions, survive.
L2TP: no rebilling after an upgrade from 0.6.20 (OBS-a5)
baf27844: each inbound keeps a persistent marker under/var/lib/pg-node/l2tp-counted, written on the first
successful save of its counted state. A missing counted file without the marker takes the present sessions as already
counted; with the marker it still means a fresh/runafter a reboot and counts from zero.- Upgrade check:
/var/lib/pg-nodemust be on persistent storage in the node's container setup, so the marker survives
a container recreate. - Forward accept rules stay out of mangle chains (
0bc4b8caRED,0544e60bfix); the linux-only IPsec guard tests
build only on linux (caf0987e).
Upstream PasarGuard node parity
- PasarGuard#55: recent node logs are kept and log streams fan out per subscriber (
38744465,pkg/logstream). - PasarGuard#101: WireGuard forward accept rules stay out of mangle chains (
3998a572). - Upstream
81af68e(released in upstream node v0.5.7): golang.org/x/net v0.60.0 -> v0.62.0 and the indirect module
refresh at upstream's exact versions (3bf215e8); thegodirective moves to 1.26.9, the toolchain stays 1.26.10. - Waiver ledger (
69e17a0f,e4b18be7):81af68e,24e2b12(PasarGuard#55) anda3d2d2f(PasarGuard#101) are ported; the version bumps
739eab9(v0.5.7) and675bdaa(v0.5.6) are not applicable to the fork's version line.
Pins
- mtg: Free-Guy-IR/mtg main
1ca247ba6e85e785d09c890301035096e5469bcb(was1563871b36dd,181af755): an accept
loop stalled by a slow PROXY protocol header and a panic inconns.goare fixed, with tests. - sing-box:
SINGBOX_COMMITdbd00be874a06d9870b2602dd92885367384c779(was5a7c1f1a31cd,46c8bc1e), still
v1.13.21, adds the port of upstream sing-quic7e0a586(hysteria2: ignore EMSGSIZE in the port hopping receive
loop). - xray:
XRAY_COMMITd2758a023cd7unchanged; one new fork patch (C2). - Go toolchain 1.26.10 unchanged.
Build, CI and supply chain
- Every published image carries
org.opencontainers.image.revision, the commit it was built from (5a470e57RED,
3a911231fix); a workflow gate refuses any image build step without it. - govulncheck: GO-2026-6866, GO-2026-6860 (x/net) and GO-2026-5841 (klauspost/compress) are gone. The node never called
the fixed x/net symbols, so this is not a security release for the node. - The sing-box ledger test fails on the test goroutine instead of hanging (
5b9281ab, D-a1).
Upgrade and compatibility
- Panel side: no
.protoor controller API change; only NodeVersion moves to0.6.22. - Shared credentials across users on one xray inbound are no longer served to both (C2): the second user waits.
- A user moved off one MTProto inbound is refused there and its live sessions there are cut (C3/C4).
- An xray user on a user inbound can no longer reach loopback, unspecified or link-local destinations (C1), except the
AsIsresidual above. - L2TP needs
/var/lib/pg-nodeto persist (OBS-a5).
Rollback
Redeploy the image the node ran before (ghcr.io/free-guy-ir/node:v0.8.20-degraded-start for nodes upgraded from
0.6.20). Rollback loses the C1, C2, C3/C4, OBS-a5 and silent-core fixes. Older images do not read the markers under
/var/lib/pg-node/l2tp-counted, so they can stay in place.
Known, tracked
- C2H1-S1, C2H1-S2 (LOW): a batch claimant admitted while a stock core's revoke fails, and extra drops if the core
crashes during the revoke phase until the panel resends; both need a fault-injecting fake core to test. - GO-2026-6651: the govulncheck waiver expires 2026-11-30.
- Upstream waivers:
8d0a7cf8expires 2026-11-10 and 36 more pending waivers expire 2026-11-20; the Upstream Drift
gate goes red after an expiry unless the item is ported or the waiver renewed. - GO-2026-5932 (x/crypto openpgp) is reported with no call path.