fix(dns): a forward record is named by its assignment - #412
Merged
Conversation
`PATCH /api/admin/v1/vm_ip_assignments/{id}` accepted `dns_forward`,
documented it as the forward FQDN, wrote it to the database and never
sent it to DNS. `BasicRecord::forward` derived the record name from the
VM id and never read the stored value, so the row and the nameserver
disagreed -- worse than refusing the change, because anything reading
`vm_ip_assignment.dns_forward` was then being told something false.
Reverse worked, because `reverse_to_fwd` does read its stored value.
Editing the record at the provider did not help either: the next forward
sync renamed it back, including `POST /ip_ranges/{id}/patch_dns`, which
re-applies a whole range.
`forward` now uses `dns_forward` when set and falls back to the derived
`vm-{id}` label when it is not, so clearing the field restores the old
name.
A stored name must be a full FQDN, as reverse names already must. This is
the wrinkle worth not guessing at: the derived name is a bare *label*
that Cloudflare expands against the zone, so accepting a label here would
turn `host` into `host.lnvps.cloud.lnvps.cloud` on live records for every
VM in a shared zone, not only the one being renamed. The fallback stays a
label because there is no stored name for the zone to disagree with.
Checked against production before changing it, rather than assuming: of
1787 assignments, 1348 have no forward name and 439 hold an FQDN. None
hold a bare label, so nothing starts failing validation. Of the 439, the
only rows whose name is not already `vm-{vm_id}.<zone>` are the six
belonging to the three route servers, which are exactly the rows this bug
was found on. For every other row the record produced is unchanged.
The test fails with `left: "vm-42", right: "ie-01.vpn.example.com"` when
the fix is reverted.
Fixes #410
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PATCH /api/admin/v1/vm_ip_assignments/{id}accepteddns_forward, documented it as the forward FQDN, wrote it to the database and never sent it to DNS.BasicRecord::forwardderived the record name from the VM id and never read the stored value, so the row and the nameserver disagreed. Reverse worked, becausereverse_to_fwddoes read its stored value.forwardnow usesdns_forwardwhen set, falling back to the derivedvm-{id}label when it is not, so clearing the field restores the old name.The FQDN question
The issue flagged this as the thing not to guess at, and it is the only real decision here. The derived name is a bare label that Cloudflare expands against the zone. Accepting a label as a stored name would turn
hostintohost.lnvps.cloud.lnvps.cloudon live records for every VM in a shared zone, not only the one being renamed.So a stored name must be a full FQDN, as reverse names already must. That is also what a create writes back, since providers return the record's resolved name. The fallback stays a label because there is no stored name for the zone to disagree with.
Checked against production rather than assumed
Of 1787 assignments: 1348 have no forward name, 439 hold an FQDN, none hold a bare label, so nothing starts failing validation.
Of the 439, the only rows whose name is not already
vm-{vm_id}.<zone>are the six belonging to the three route servers, which are the rows the bug was found on. For every other row the record produced is unchanged.Test
a_forward_record_is_named_by_the_assignmentcovers the derived name, the stored name (keeping its provider reference, so the record is renamed rather than duplicated), thevm-42.lnvps.cloudform every un-renamed row already holds, and the rejected bare label. Verified to fail withleft: "vm-42", right: "ie-01.vpn.example.com"when the fix is reverted.2052 pass, clippy clean.
Fixes #410