diff --git a/xCAT-server/lib/xcat/plugins/ddns.pm b/xCAT-server/lib/xcat/plugins/ddns.pm index 99c291d67..c46cf9686 100644 --- a/xCAT-server/lib/xcat/plugins/ddns.pm +++ b/xCAT-server/lib/xcat/plugins/ddns.pm @@ -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;