2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-21 16:39:30 +00:00

fix(xcat-core): the retried DNS update carries two TSIG records

makedns reports "error was FORMERR" for an update that named rejected with
NOTAUTH. The FORMERR is the answer to the retry, not to the first attempt.

send_ddns_update in ddns.pm signs the packet the caller built, and signs that
same packet again on each attempt. Net::DNS::Packet::sign_tsig appends the TSIG
to the additional section, so the second attempt sends two TSIG records and
named answers FORMERR. FORMERR is neither NOTAUTH nor SERVFAIL, so the routine
stops and reports it. The NOTAUTH and SERVFAIL retry can never be accepted, on
any algorithm.

Each attempt now signs a request of its own. A packet cannot be unsigned again,
so ddns_update_request copies the prerequisite and update records into a new
Net::DNS::Update instead, and the caller keeps the unsigned original.

ddns_update_retry.t fails before this change: the second attempt carries two
TSIG records, and an update that the retry answers with NOERROR still reports
failure.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
Daniel Hilst
2026-09-04 18:53:32 -03:00
parent 69be7872f2
commit 6a41acf2db
+25 -2
View File
@@ -1579,6 +1579,26 @@ sub update_namedconf {
}
}
#-------------------------------------------------------------------------------
=head3 ddns_update_request
Descriptions: Copy the records of one dynamic DNS update into a new, unsigned request.
Arguments: the update the caller built, the zone name
Returns: a Net::DNS::Update holding the same prerequisite and update records
=cut
#-------------------------------------------------------------------------------
sub ddns_update_request {
my ($update, $zone) = @_;
my $request = Net::DNS::Update->new($zone);
$request->push(pre => $_) for $update->answer;
$request->push(update => $_) for $update->authority;
return $request;
}
# Send a signed dynamic DNS update, retrying transient rejections. Right after a zone (re)load named
# can reply NOTAUTH, or SERVFAIL before the zone is ready to accept dynamic updates; both are
# recoverable, so retry a few times (pausing on SERVFAIL). Returns 0 only when the update was
@@ -1589,8 +1609,11 @@ sub send_ddns_update {
my ($ctx, $resolver, $update, $zone, $entry) = @_;
for my $attempt (1 .. 3) {
ddns_sign_update($ctx, $update);
my $reply = $resolver->send($update);
# sign_tsig appends the TSIG to the additional section. A second signature on the same
# packet sends two TSIG records, and named answers FORMERR. Sign a copy for each attempt.
my $request = ddns_update_request($update, $zone);
ddns_sign_update($ctx, $request);
my $reply = $resolver->send($request);
if (!$reply) {
xCAT::SvrUtils::sendmsg([ 1, "No reply received when sending DNS update to zone $zone" ], $callback);
return 1;