feat: add PowerDNS reverse DNS (PTR) integration
Introduces an opt-in reverse DNS management subsystem backed by a PowerDNS
Authoritative HTTP API. Runs via a companion WHMCS addon module
(modules/addons/VirtFusionDns) that holds settings and a Test Connection
page; the server module reads those settings from tbladdonmodules and
short-circuits when the addon is absent or disabled, so provisioning is
unaffected for operators who don't use the feature.
Lifecycle hooks:
- createAccount creates PTRs for every assigned IP (forward DNS must
already resolve to the IP — FCrDNS enforcement)
- renameServer updates only PTRs whose content matched the old hostname,
preserving client-custom records
- terminateAccount deletes all PTRs before the local state is purged
- TestConnection merges PowerDNS health check with the existing VirtFusion
check
- A DailyCronJob hook reconciles missing PTRs additive-only (never
overwrites)
Client UI: new "Reverse DNS" panel on the service overview with one
editable PTR input per assigned IP, per-row status badges, and
forward-DNS rejection on save. Admin services tab gets a parallel
widget with Reconcile (additive) and Reconcile (force reset) buttons.
New subsystem at lib/PowerDns/:
- Client.php PowerDNS API wrapper (X-API-Key, listZones/getZone/
patchRRset/notifyZone), auto-NOTIFY on successful PATCH
- Config.php Loads + decrypts addon settings from tbladdonmodules
- IpUtil.php PTR-name generation (IPv4 + IPv6), zone matching,
RFC 2317 classless parsing
- Resolver.php FCrDNS verification via dns_get_record with CNAME-chain
following and per-(hostname,ip) caching
- PtrManager.php Orchestrator: syncServer, deleteForServer, listPtrs,
setPtr, reconcile, reconcileAll
Security hardening helpers added to Module and applied to the rDNS
endpoints:
- requirePost() HTTP method gate (405 on non-POST mutations)
- requireSameOrigin() Origin/Referer check against WHMCS host (CSRF
defence against cross-site form POST)
- requireServiceStatus() tblhosting.domainstatus filter (Active for
writes, Active+Suspended for reads)
RFC 2317 classless delegations (e.g. 64/64.113.0.203.in-addr.arpa.)
supported with alignment validation: rejects misaligned start addresses
that don't correspond to any real delegation boundary.
PowerDNS zone IDs containing '/' are URL-encoded as '=2F' per the
PowerDNS API convention. PATCH success triggers PUT /zones/{id}/notify
so slaves pick up the SOA-bumped serial immediately.
Includes IPv4 + IPv6 support, per-IP write rate limit (10s), fresh
IP-ownership re-verification on every client write (defends against
stale-ownership after IP reassignment), and audit logging of every
successful edit to the WHMCS module log.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -471,3 +471,77 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
Reverse DNS panel
|
||||
========================================================================= */
|
||||
.vf-rdns-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid rgba(0,0,0,.06);
|
||||
}
|
||||
.vf-rdns-row:last-child { border-bottom: none; }
|
||||
.vf-rdns-ip {
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
min-width: 180px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.vf-rdns-edit {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
min-width: 240px;
|
||||
}
|
||||
.vf-rdns-input {
|
||||
flex: 1 1 auto;
|
||||
min-width: 180px;
|
||||
max-width: 420px;
|
||||
font-family: monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
.vf-rdns-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .02em;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.vf-rdns-msg {
|
||||
flex-basis: 100%;
|
||||
font-size: 12px;
|
||||
display: none;
|
||||
padding-left: 180px;
|
||||
}
|
||||
.vf-rdns-admin-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 4px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
.vf-rdns-ip-admin {
|
||||
font-family: monospace;
|
||||
font-weight: 600;
|
||||
min-width: 180px;
|
||||
}
|
||||
.vf-rdns-ptr-admin {
|
||||
font-family: monospace;
|
||||
color: #333;
|
||||
flex: 1 1 auto;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.vf-rdns-row { flex-direction: column; align-items: stretch; }
|
||||
.vf-rdns-edit { flex-direction: column; align-items: stretch; }
|
||||
.vf-rdns-msg { padding-left: 0; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user