Skip to content

fix(transfer): accept external nameservers without registry validation (#525)#537

Open
msiouti wants to merge 2 commits into
openprovider:masterfrom
msiouti:patch-1
Open

fix(transfer): accept external nameservers without registry validation (#525)#537
msiouti wants to merge 2 commits into
openprovider:masterfrom
msiouti:patch-1

Conversation

@msiouti

@msiouti msiouti commented Apr 28, 2026

Copy link
Copy Markdown

Fixes #525.

Problem

APITools::createNameserversArray gated nameserver inclusion on the ability to resolve an IP for every NS — first via Openprovider's searchNsRequest registry lookup, then via gethostbyname. For out-of-bailiwick nameservers (the vast majority of real-world cases — ns1.cloudflare.com, dns.google, etc.) neither path is appropriate: the registry lookup is for glue records only, and gethostbyname can fail or return the input unchanged. When that happened the NS was silently dropped from the array, the truncated list was passed to transferDomainRequest, and the registry substituted the reseller's default nameservers — silently changing customer DNS delegation at the moment of transfer, with no exception or warning.

Fix

Scope IP resolution to in-bailiwick glue records only — i.e. NS that are the apex domain itself or a subdomain of the domain being registered/transferred. Out-of-bailiwick NS are now accepted by name alone and serialized without an ip field. Glue records still try the registry first, then DNS resolution; if neither produces a valid IPv4 the function throws with a clear message instead of dropping the NS.

The two code paths in the original (test_mode == 'on' and the default branch) collapsed into one because their differences were incidental to the fix and the new path is a strict superset.

Changes

  • OpenProvider/API/APITools.phpcreateNameserversArray rewritten; two new private helpers isGlueRecord and resolveGlueIp extracted.
  • tests/API/APIToolsTest.php — new PHPUnit cases:

Risk / verification

  • DomainNameServer::$ip already defaults to null, so omitting the key from the constructor array leaves the property null. The Symfony PropertyNormalizer used by ApiHelper will emit ip: null for external NS in the request body. If, in review, we'd rather suppress the null entirely, the smallest follow-up is to make DomainNameServer implement JsonSerializable and skip null fields — happy to add that in this PR if reviewers prefer.
  • All three callers (DomainController::transfer, DomainController::register, NameserverController::saveNameservers) use the return value as-is — no caller-side changes required.
  • PHP floor in composer.json resolves to >= 8.1 (per vendor/composer/platform_check.php), so str_ends_with is available natively.

Test plan

  • CI passes (PHPUnit + lint).
  • Manual: transfer a domain with external NS (e.g. Cloudflare) and confirm the registry receives those NS — not the reseller defaults.
  • Manual: transfer a domain using glue NS (ns1.<being-transferred>.tld) with explicit name/ip and confirm IP is preserved.
  • Manual: attempt transfer with glue NS missing IP and unresolvable hostname; confirm a clear error surfaces in WHMCS instead of a silent default-substitution.

msiouti added 2 commits April 28, 2026 11:31
openprovider#525)

APITools::createNameserversArray gated nameserver inclusion on the
ability to resolve an IP for every NS — first via Openprovider's
searchNsRequest registry lookup, then via gethostbyname. For
out-of-bailiwick nameservers (the vast majority of real-world cases —
ns1.cloudflare.com, dns.google, etc.) neither path is appropriate:
the registry lookup is for glue records only, and gethostbyname can
fail or return the input unchanged. When that happened the NS was
silently dropped from the array, the caller passed the truncated list
to transferDomainRequest, and the registry substituted reseller
defaults — silently changing customer DNS delegation at the moment of
transfer.

This change scopes IP resolution to in-bailiwick glue records (NS
that are the apex domain itself or a subdomain of the domain being
registered/transferred). External NS are accepted by name alone and
serialized without an ip field. Glue records still attempt the
registry then DNS resolution; if neither produces a valid IPv4 the
function now throws with a clear message instead of dropping the NS.

Fixes openprovider#525.
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.

[BUG] transferDomain silently replaces external nameservers with module defaults — APITools::createNameserversArray regression

1 participant