diff --git a/CHANGES b/CHANGES index cdcb77c501..30ee3ab7f7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4629. [bug] dns_client_startupdate could not be called with a + running client. [RT #45277] + 4628. [bug] Fixed a potential reference leak in query_getdb(). [RT #45247] diff --git a/bin/tests/system/nsupdate/tests.sh b/bin/tests/system/nsupdate/tests.sh index 7da54e2ce2..7620440967 100755 --- a/bin/tests/system/nsupdate/tests.sh +++ b/bin/tests/system/nsupdate/tests.sh @@ -793,7 +793,8 @@ grep "status: NOERROR" check.out.ns2.test$n > /dev/null || ret=1 n=`expr $n + 1` echo "I:check that dns_client_update handles prerequisite YXRRSET failure ($n)" -$SAMPLEUPDATE -P 5300 -a 10.53.0.1 -a 10.53.0.2 -p "yxrrset no-txt.sample TXT" \ +$SAMPLEUPDATE -s -P 5300 -a 10.53.0.1 -a 10.53.0.2 \ + -p "yxrrset no-txt.sample TXT" \ add "yxrrset-nxrrset.sample 0 in a 1.2.3.4" > update.out.test$n 2>&1 $SAMPLEUPDATE -P 5300 -a 10.53.0.2 -p "yxrrset no-txt.sample TXT" \ add "check-yxrrset-nxrrset.sample 0 in a 1.2.3.4" > update.out.check$n 2>&1 @@ -805,6 +806,7 @@ grep "update succeeded" update.out.check$n > /dev/null || ret=1 grep "status: NXDOMAIN" dig.out.ns1.test$n > /dev/null || ret=1 grep "status: NXDOMAIN" dig.out.ns2.test$n > /dev/null || ret=1 grep "status: NOERROR" check.out.ns2.test$n > /dev/null || ret=1 +grep "2nd update failed: NXRRSET" update.out.test$n > /dev/null || ret=1 [ $ret = 0 ] || { echo I:failed; status=1; } # diff --git a/lib/dns/client.c b/lib/dns/client.c index 557668167c..a7d7158997 100644 --- a/lib/dns/client.c +++ b/lib/dns/client.c @@ -2978,6 +2978,17 @@ dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass, *transp = (dns_clientupdatetrans_t *)uctx; result = isc_app_ctxonrun(client->actx, client->mctx, client->task, startupdate, uctx); + if (result == ISC_R_ALREADYRUNNING) { + isc_event_t *event; + event = isc_event_allocate(client->mctx, dns_client_startupdate, + DNS_EVENT_STARTUPDATE, startupdate, + uctx, sizeof(*event)); + if (event != NULL) { + result = ISC_R_SUCCESS; + isc_task_send(task, &event); + } else + result = ISC_R_NOMEMORY; + } if (result == ISC_R_SUCCESS) return (result); *transp = NULL; diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index db2d1a346f..f41c3c8c7b 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -76,6 +76,7 @@ #define DNS_EVENT_CATZMODZONE (ISC_EVENTCLASS_DNS + 55) #define DNS_EVENT_CATZDELZONE (ISC_EVENTCLASS_DNS + 56) #define DNS_EVENT_RPZUPDATED (ISC_EVENTCLASS_DNS + 57) +#define DNS_EVENT_STARTUPDATE (ISC_EVENTCLASS_DNS + 58) #define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0) #define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535) diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c index 29e79fae1c..b39a784092 100644 --- a/lib/isc/unix/app.c +++ b/lib/isc/unix/app.c @@ -416,6 +416,7 @@ isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task, event = isc_event_allocate(mctx, cloned_task, ISC_APPEVENT_SHUTDOWN, action, arg, sizeof(*event)); if (event == NULL) { + isc_task_detach(&cloned_task); result = ISC_R_NOMEMORY; goto unlock; } diff --git a/lib/samples/sample-update.c b/lib/samples/sample-update.c index aecf41d644..848d861e05 100644 --- a/lib/samples/sample-update.c +++ b/lib/samples/sample-update.c @@ -73,6 +73,7 @@ usage(void) ISC_PLATFORM_NORETURN_POST; static void usage(void) { fprintf(stderr, "sample-update " + "-s " "[-a auth_server] " "[-k keyfile] " "[-p prerequisite] " @@ -124,7 +125,7 @@ main(int argc, char *argv[]) { isc_sockaddr_t sa_auth[10], sa_recursive[10]; unsigned int nsa_auth = 0, nsa_recursive = 0; isc_sockaddrlist_t rec_servers; - isc_sockaddrlist_t auth_servers; + isc_sockaddrlist_t auth_servers, *auth_serversp = &auth_servers; isc_result_t result; isc_boolean_t isdelete; isc_buffer_t b, *buf; @@ -136,11 +137,12 @@ main(int argc, char *argv[]) { dns_rdata_t *rdata; dns_namelist_t updatelist, prereqlist, *prereqlistp = NULL; isc_mem_t *umctx = NULL; + isc_boolean_t sendtwice; ISC_LIST_INIT(auth_servers); ISC_LIST_INIT(rec_servers); - while ((ch = isc_commandline_parse(argc, argv, "a:k:p:P:r:z:")) != EOF) { + while ((ch = isc_commandline_parse(argc, argv, "a:k:p:P:r:sz:")) != EOF) { switch (ch) { case 'k': keyfilename = isc_commandline_argument; @@ -164,6 +166,9 @@ main(int argc, char *argv[]) { &sa_recursive[nsa_recursive])) nsa_recursive++; break; + case 's': + sendtwice = ISC_TRUE; + break; case 'z': zonenamestr = isc_commandline_argument; break; @@ -250,18 +255,33 @@ main(int argc, char *argv[]) { if (keyfilename != NULL) setup_tsec(keyfilename, umctx); + if (ISC_LIST_HEAD(auth_servers) == NULL) + auth_serversp = NULL; + /* Perform update */ result = dns_client_update(client, default_rdataclass, /* XXX: fixed */ zname, prereqlistp, &updatelist, - (ISC_LIST_HEAD(auth_servers) == NULL) ? - NULL : &auth_servers, tsec, 0); + auth_serversp, tsec, 0); if (result != ISC_R_SUCCESS) { fprintf(stderr, "update failed: %s\n", dns_result_totext(result)); } else fprintf(stderr, "update succeeded\n"); + if (sendtwice) { + /* Perform 2nd update */ + result = dns_client_update(client, + default_rdataclass, /* XXX: fixed */ + zname, prereqlistp, &updatelist, + auth_serversp, tsec, 0); + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "2nd update failed: %s\n", + dns_result_totext(result)); + } else + fprintf(stderr, "2nd update succeeded\n"); + } + /* Cleanup */ while ((pname = ISC_LIST_HEAD(prereqlist)) != NULL) { while ((rdataset = ISC_LIST_HEAD(pname->list)) != NULL) {