Skip to content

feat(tsig): Plesk — key in common-allow-transfer, restored after every rewrite - #100

Merged
0kaba0 merged 3 commits into
developfrom
feat/tsig-plesk
Oct 13, 2026
Merged

0kaba0 merged 3 commits into
developfrom
feat/tsig-plesk

Conversation

@0kaba0

@0kaba0 0kaba0 commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

#96 for Plesk. It builds on #98 (TSIG for BIND panels) and #99 (Plesk transfer ACL).

What is different on Plesk. Seen read-only on a live Plesk 18.0.81, AlmaLinux 9:

  • every zone has allow-transfer { common-allow-transfer; }, so the list to edit is that ACL, not options;
  • BIND runs chrooted (-t /var/named/chroot);
  • Plesk rewrites named.conf from its own settings and keeps only the "custom directives" block;
  • server_dns has no command to take an IP out of the Transfer Restrictions Template.

How it works:

  • Target in seconddns-tsig: bind (as before) or plesk. Plesk is detected by the plesk CLI plus /usr/local/psa, or forced with SECONDDNS_TSIG_FLAVOR in tests.
  • Plesk:
    • key file /var/named/chroot/etc/seconddns-tsig.key, included as /etc/seconddns-tsig.key right below "PLEASE ADD YOUR CUSTOM DIRECTIVES BELOW THIS LINE";
    • key "…" in acl common-allow-transfer;
    • enable refuses when the custom block is missing.
  • enable keeps the BIND order: key next to our IPs → [tsig] + worker restart → zones get the key → our IPs leave the ACL (removed_entries recorded). On Plesk it then installs seconddns-tsig-restore.path (PathChanged on the real named.conf), .service (seconddns-tsig restore) and .timer (every 5 min).
  • restore: when the key file, include or ACL key are missing, or a recorded IP came back, it adds the key and drops those IPs again. Otherwise it is silent and writes nothing, so the path unit firing on our own write ends there.
  • The window between a Plesk rewrite and restore. SecondDNS signs every request for a keyed zone. After an ACL-only rewrite those signed requests still pass: named keeps knowing the key through the include in the custom block, and our IP is back in the ACL. If Plesk ever drops the include as well, named no longer knows the key, so signed requests are refused (BADKEY) until restore runs, and the secondary retries on its schedule. Both cases are rows in the real-named test.
  • disable stops the units first (they would re-add the key midway), then mirrors enable and removes the unit files. The uninstaller already runs disable --zones first (feat(tsig): BIND panels — enable, disable, restore and the installer choice #98).
  • The list editor is shared: _edit_list serves both edit_allow_transfer and the new edit_acl. test_tsig_bind.sh passes unchanged (56/56).

Existing code touched:

Tests:

  • test_tsig_plesk.sh (28, stand-ins for API, checkconf, reload and systemctl, fixture with the live server's structure):

    • enable: named-checkconf called as -t <chroot> /etc/named.conf, key in the chroot, include under the custom line with the chroot path, our IP out of the ACL, customer's entry kept, zones untouched, units written and enabled;
    • Plesk rewrite then restore: key back, IP out; a second restore is a byte-identical no-op;
    • restore of a lost include;
    • disable: units stopped before any edit, IP back, key, include, key file and units gone, zone unsigned;
    • no custom block: refused, nothing kept.
  • test_tsig_plesk_named.sh (11, real named with a Plesk-style named.conf, signed AXFR as SecondDNS sends it):

    • after enable, our IP without the key is refused, with the key it transfers, the customer's other secondary keeps IP access;
    • after an ACL-only rewrite signed AXFR still passes; after restore unsigned is refused again and signed passes;
    • after a rewrite that also drops the include, signed AXFR is refused until restore, then passes;
    • after disable, IP transfers work again.
  • Ubuntu 24.04, BIND 9.18, non-root: test_tsig_plesk_named 8/8, test_tsig_plesk 27/27, test_tsig_bind_named 9/9, test_tsig_bind 56/56, test_plesk_acl_named 4/4. Locally also test_tsig 35, test_queue 104, test_named_conf_edit 26, test_plesk_acl 13.

  • test_tsig_plesk_chroot.sh (5, root, run with sudo in CI): the real named-checkconf -t against a chroot built from the fixture. enable passes and keeps its edit; outside the chroot the include does not resolve, so -t is what makes the check pass. Before this fix, enable rolled back on every real Plesk.

Not verified on a live Plesk (owner decision, no test panel): the chroot path on other Plesk/OS combinations, and whether Plesk ever rewrites the custom directives block.

…y rewrite

On Plesk every zone has allow-transfer { common-allow-transfer; }, BIND
runs chrooted and Plesk rewrites named.conf from its own settings. The
key file goes into the chroot, the include into the custom directives
block Plesk keeps, and the key into the ACL. enable drops our IPs from
the ACL only after every zone has the key and installs a systemd path
unit on named.conf plus a 5-minute timer that run restore: after a
rewrite it puts the key back and our IPs out again. disable stops them
first. BIND and Plesk now share one list editor (Target).
@0kaba0

0kaba0 commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

CHANGES REQUESTED at 03e5424, two points.

Verified: the Plesk target edits acl common-allow-transfer with the same masked list editor as the options block, the include goes under the custom-directives line that Plesk keeps, enable keeps the BIND order (key next to our IPs → zones switched → IPs dropped), restore is complete-or-fix (key file, include, key in the ACL, none of the dropped entries back) so the path unit does not loop, disable removes the units first, the installer gets --tsig and the prompt; stand-in test 27 rows incl. a lost include and a missing custom block; real-named test 8 rows. No attribution lines.

  1. The window after a Plesk rewrite is a refusal, not "transfers by IP". Once a zone carries tsigKeyId, our secondary signs every SOA query and AXFR for it; a signed request whose key the server no longer knows is answered NOTAUTH/BADKEY regardless of the source address. Row 2 of test_tsig_plesk_named.sh sends an unsigned AXFR after the rewrite, which is not what SecondDNS sends. Add the row that sends the signed AXFR (-y $KEY) after the rewrite and expects a refusal until restore; then state in the README and the PR body that for those seconds transfers are refused and the secondary retries at its next refresh/retry, and drop "never refused". (This was the condition when the scheme was agreed.)

  2. named-checkconf outside the chroot cannot see the key file. On a real Plesk the key is written to /var/named/chroot/etc/seconddns-tsig.key and included as /etc/seconddns-tsig.key, the path named sees from inside the chroot; checkconf_ok() runs plain named-checkconf, which resolves that include against the host's /etc, where the file does not exist, so the check fails and edit_named rolls back on every real Plesk host. Neither test can show it: the stand-in stubs checkconf, the real-named test runs without a chroot. For the plesk flavor with a chroot, run named-checkconf -t <chroot> /etc/named.conf (root, as the installer and the restore service are), and add a stand-in row asserting the -t argument.

…rs in the rewrite window

named-checkconf ran outside the chroot, where the include
(/etc/seconddns-tsig.key, the path named sees) does not exist, so enable
would roll back on every real Plesk. It now runs with -t <chroot> and the
config path inside it.

The real-named test now sends signed AXFR, as SecondDNS does: after an
ACL-only rewrite it still passes (the include survives); after a rewrite
that also drops the include it is refused until restore. README says the
same.
@0kaba0

0kaba0 commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator Author

APPROVED at f34f7bc.

Both points are closed, and the first one corrects my claim: after an ACL-only rewrite the key stays known through the include in the custom block and our IP is back in the ACL, so the signed request passes. The refusal only happens when the include goes too. Rows 2 and 3 of test_tsig_plesk_named.sh now cover both cases with the signed AXFR, and README/PR body say exactly that.

named-checkconf -t <chroot> /etc/named.conf for the Plesk target: check_args derives the in-chroot path from the realpath of named.conf, the stub test asserts the exact arguments on every check, and test_tsig_plesk_chroot.sh shows with the real binary that the include resolves only under -t. The gate at this head runs all five Plesk steps green. No attribution lines in the three commits.

Not verified on a live Plesk host, as recorded in the PR. Ready for the owner's merge.

@0kaba0
0kaba0 merged commit adc97f4 into develop Oct 13, 2026
1 check passed
@0kaba0
0kaba0 deleted the feat/tsig-plesk branch October 13, 2026 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant