/*! \file */
+#include <isc/netmgr.h>
+#include <isc/ratelimiter.h>
#include <isc/result.h>
+#include <dns/adb.h>
#include <dns/notify.h>
+#include <dns/peer.h>
+#include <dns/rcode.h>
+#include <dns/rdatalist.h>
+#include <dns/request.h>
+#include <dns/stats.h>
+#include <dns/tsig.h>
+#include <dns/zone.h>
+
+#include "zone_p.h"
+
+static void
+notify_log(dns_notify_t *notify, int level, const char *fmt, ...) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ dns_zone_logv(notify->zone, DNS_LOGCATEGORY_NOTIFY, level, NULL, fmt,
+ ap);
+ va_end(ap);
+}
void
dns_notify_create(isc_mem_t *mctx, unsigned int flags, dns_notify_t **notifyp) {
notify->magic = NOTIFY_MAGIC;
*notifyp = notify;
}
+
+void
+dns_notify_destroy(dns_notify_t *notify, bool locked) {
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+
+ isc_mem_t *mctx;
+ dns_notifyctx_t *nctx;
+
+ if (notify->zone != NULL) {
+ if (!locked) {
+ dns__zone_lock(notify->zone);
+ }
+ REQUIRE(dns__zone_locked(notify->zone));
+ nctx = dns__zone_getnotifyctx(notify->zone);
+ if (ISC_LINK_LINKED(notify, link)) {
+ ISC_LIST_UNLINK(nctx->notifies, notify, link);
+ }
+ if (!locked) {
+ dns__zone_unlock(notify->zone);
+ }
+ if (locked) {
+ dns__zone_idetach_locked(¬ify->zone);
+ } else {
+ dns_zone_idetach(¬ify->zone);
+ }
+ }
+ if (notify->find != NULL) {
+ dns_adb_destroyfind(¬ify->find);
+ }
+ if (notify->request != NULL) {
+ dns_request_destroy(¬ify->request);
+ }
+ if (dns_name_dynamic(¬ify->ns)) {
+ dns_name_free(¬ify->ns, notify->mctx);
+ }
+ if (notify->key != NULL) {
+ dns_tsigkey_detach(¬ify->key);
+ }
+ if (notify->transport != NULL) {
+ dns_transport_detach(¬ify->transport);
+ }
+ mctx = notify->mctx;
+ isc_mem_put(notify->mctx, notify, sizeof(*notify));
+ isc_mem_detach(&mctx);
+}
+
+static void
+notify_done(void *arg) {
+ dns_request_t *request = (dns_request_t *)arg;
+ dns_notify_t *notify = dns_request_getarg(request);
+ isc_result_t result;
+ dns_message_t *message = NULL;
+ isc_buffer_t buf;
+ char rcode[128];
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+
+ isc_buffer_init(&buf, rcode, sizeof(rcode));
+ isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf));
+ /* WMM: This is changing the mctx from zone to notify. */
+ dns_message_create(notify->mctx, NULL, NULL, DNS_MESSAGE_INTENTPARSE,
+ &message);
+
+ result = dns_request_getresult(request);
+ if (result != ISC_R_SUCCESS) {
+ goto fail;
+ }
+
+ result = dns_request_getresponse(request, message,
+ DNS_MESSAGEPARSE_PRESERVEORDER);
+ if (result != ISC_R_SUCCESS) {
+ goto fail;
+ }
+
+ result = dns_rcode_totext(message->rcode, &buf);
+ if (result == ISC_R_SUCCESS) {
+ notify_log(notify, ISC_LOG_DEBUG(3),
+ "notify response from %s: %.*s", addrbuf,
+ (int)buf.used, rcode);
+ }
+fail:
+ dns_message_detach(&message);
+
+ if (result == ISC_R_SUCCESS) {
+ notify_log(notify, ISC_LOG_DEBUG(1), "notify to %s successful",
+ addrbuf);
+ } else if (result == ISC_R_SHUTTINGDOWN || result == ISC_R_CANCELED) {
+ /* just destroy the notify */
+ } else if ((notify->flags & DNS_NOTIFY_TCP) == 0) {
+ notify_log(notify, ISC_LOG_NOTICE,
+ "notify to %s failed: %s: retrying over TCP",
+ addrbuf, isc_result_totext(result));
+ notify->flags |= DNS_NOTIFY_TCP;
+ dns_request_destroy(¬ify->request);
+ dns_notify_queue(notify, notify->flags & DNS_NOTIFY_STARTUP);
+ return;
+ } else if (result == ISC_R_TIMEDOUT) {
+ notify_log(notify, ISC_LOG_WARNING,
+ "notify to %s failed: %s: retries exceeded", addrbuf,
+ isc_result_totext(result));
+ } else {
+ notify_log(notify, ISC_LOG_WARNING, "notify to %s failed: %s",
+ addrbuf, isc_result_totext(result));
+ }
+ dns_notify_destroy(notify, false);
+}
+
+static isc_result_t
+notify_createmessage(dns_notify_t *notify, dns_message_t **messagep) {
+ dns_db_t *zonedb = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_message_t *message = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ dns_name_t *tempname = NULL;
+ dns_rdata_t *temprdata = NULL;
+ dns_rdatalist_t *temprdatalist = NULL;
+ dns_rdataset_t *temprdataset = NULL;
+
+ isc_result_t result;
+ isc_region_t r;
+ isc_buffer_t *b = NULL;
+
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+ REQUIRE(messagep != NULL && *messagep == NULL);
+
+ /* WMM: This is changing the mctx from zone to notify. */
+ dns_message_create(notify->mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
+ &message);
+
+ message->opcode = dns_opcode_notify;
+ message->flags |= DNS_MESSAGEFLAG_AA;
+ message->rdclass = dns_zone_getrdclass(notify->zone);
+
+ dns_message_gettempname(message, &tempname);
+ dns_message_gettemprdataset(message, &temprdataset);
+
+ /*
+ * Make question.
+ */
+ dns_name_clone(dns_zone_getorigin(notify->zone), tempname);
+ dns_rdataset_makequestion(temprdataset,
+ dns_zone_getrdclass(notify->zone),
+ dns_rdatatype_soa);
+ ISC_LIST_APPEND(tempname->list, temprdataset, link);
+ dns_message_addname(message, tempname, DNS_SECTION_QUESTION);
+ tempname = NULL;
+ temprdataset = NULL;
+
+ if ((notify->flags & DNS_NOTIFY_NOSOA) != 0) {
+ goto done;
+ }
+
+ dns_message_gettempname(message, &tempname);
+ dns_message_gettemprdata(message, &temprdata);
+ dns_message_gettemprdataset(message, &temprdataset);
+ dns_message_gettemprdatalist(message, &temprdatalist);
+
+ result = dns_zone_getdb(notify->zone, &zonedb);
+ INSIST(result == ISC_R_SUCCESS);
+ INSIST(zonedb != NULL); /* XXXJT: is this assumption correct? */
+
+ dns_name_clone(dns_zone_getorigin(notify->zone), tempname);
+ dns_db_currentversion(zonedb, &version);
+ result = dns_db_findnode(zonedb, tempname, false, &node);
+ if (result != ISC_R_SUCCESS) {
+ goto soa_cleanup;
+ }
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(zonedb, node, version, dns_rdatatype_soa,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS) {
+ goto soa_cleanup;
+ }
+ result = dns_rdataset_first(&rdataset);
+ if (result != ISC_R_SUCCESS) {
+ goto soa_cleanup;
+ }
+ dns_rdataset_current(&rdataset, &rdata);
+ dns_rdata_toregion(&rdata, &r);
+ /* WMM: This is changing the mctx from zone to notify. */
+ isc_buffer_allocate(notify->mctx, &b, r.length);
+ isc_buffer_putmem(b, r.base, r.length);
+ isc_buffer_usedregion(b, &r);
+ dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r);
+ dns_message_takebuffer(message, &b);
+ result = dns_rdataset_next(&rdataset);
+ dns_rdataset_disassociate(&rdataset);
+ if (result != ISC_R_NOMORE) {
+ goto soa_cleanup;
+ }
+ temprdatalist->rdclass = rdata.rdclass;
+ temprdatalist->type = rdata.type;
+ temprdatalist->ttl = rdataset.ttl;
+ ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link);
+
+ dns_rdatalist_tordataset(temprdatalist, temprdataset);
+
+ ISC_LIST_APPEND(tempname->list, temprdataset, link);
+ dns_message_addname(message, tempname, DNS_SECTION_ANSWER);
+ temprdatalist = NULL;
+ temprdataset = NULL;
+ temprdata = NULL;
+ tempname = NULL;
+
+soa_cleanup:
+ if (node != NULL) {
+ dns_db_detachnode(&node);
+ }
+ if (version != NULL) {
+ dns_db_closeversion(zonedb, &version, false);
+ }
+ if (zonedb != NULL) {
+ dns_db_detach(&zonedb);
+ }
+ if (tempname != NULL) {
+ dns_message_puttempname(message, &tempname);
+ }
+ if (temprdata != NULL) {
+ dns_message_puttemprdata(message, &temprdata);
+ }
+ if (temprdataset != NULL) {
+ dns_message_puttemprdataset(message, &temprdataset);
+ }
+ if (temprdatalist != NULL) {
+ dns_message_puttemprdatalist(message, &temprdatalist);
+ }
+
+done:
+ *messagep = message;
+ return ISC_R_SUCCESS;
+}
+
+static void
+notify_send_toaddr(void *arg) {
+ dns_notify_t *notify = (dns_notify_t *)arg;
+ dns_notifyctx_t *notifyctx = NULL;
+ isc_result_t result;
+ dns_db_t *zonedb = NULL;
+ dns_view_t *view = NULL;
+ isc_loop_t *loop = NULL;
+ dns_zonemgr_t *zmgr = NULL;
+ dns_message_t *message = NULL;
+ isc_netaddr_t dstip;
+ dns_tsigkey_t *key = NULL;
+ char addrbuf[ISC_SOCKADDR_FORMATSIZE];
+ isc_sockaddr_t src;
+ unsigned int options;
+ bool have_notifysource = false;
+ isc_tlsctx_cache_t *zmgr_tlsctx_cache = NULL;
+
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+
+ dns__zone_lock(notify->zone);
+
+ notifyctx = dns__zone_getnotifyctx(notify->zone);
+ zmgr = dns_zone_getmgr(notify->zone);
+ view = dns_zone_getview(notify->zone);
+ loop = dns_zone_getloop(notify->zone);
+ result = dns_zone_getdb(notify->zone, &zonedb);
+ isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf));
+
+ if (!dns__zone_loaded(notify->zone) || notify->rlevent->canceled ||
+ dns__zone_exiting(notify->zone) || zmgr == NULL || view == NULL ||
+ view->requestmgr == NULL || loop == NULL || zonedb == NULL ||
+ result != ISC_R_SUCCESS)
+ {
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ /*
+ * The raw IPv4 address should also exist. Don't send to the
+ * mapped form.
+ */
+ if (isc_sockaddr_pf(¬ify->dst) == PF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED(¬ify->dst.type.sin6.sin6_addr))
+ {
+ notify_log(notify, ISC_LOG_DEBUG(3),
+ "notify: ignoring IPv6 mapped IPV4 address: %s",
+ addrbuf);
+ result = ISC_R_CANCELED;
+ goto cleanup;
+ }
+
+ result = notify_createmessage(notify, &message);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+
+ if (notify->key != NULL) {
+ /* Transfer ownership of key */
+ key = notify->key;
+ notify->key = NULL;
+ } else {
+ isc_netaddr_fromsockaddr(&dstip, ¬ify->dst);
+ result = dns_view_getpeertsig(view, &dstip, &key);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
+ notify_log(notify, ISC_LOG_ERROR,
+ "NOTIFY to %s not sent. "
+ "Peer TSIG key lookup failure.",
+ addrbuf);
+ goto cleanup_message;
+ }
+ }
+
+ if (key != NULL) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+
+ dns_name_format(key->name, namebuf, sizeof(namebuf));
+ notify_log(notify, ISC_LOG_INFO,
+ "sending notify to %s : TSIG (%s)", addrbuf,
+ namebuf);
+ } else {
+ notify_log(notify, ISC_LOG_INFO, "sending notify to %s",
+ addrbuf);
+ }
+ options = 0;
+ if (view->peers != NULL) {
+ dns_peer_t *peer = NULL;
+ bool usetcp = false;
+ result = dns_peerlist_peerbyaddr(view->peers, &dstip, &peer);
+ if (result == ISC_R_SUCCESS) {
+ result = dns_peer_getnotifysource(peer, &src);
+ if (result == ISC_R_SUCCESS) {
+ have_notifysource = true;
+ }
+ result = dns_peer_getforcetcp(peer, &usetcp);
+ if (result == ISC_R_SUCCESS && usetcp) {
+ options |= DNS_FETCHOPT_TCP;
+ }
+ }
+ }
+ switch (isc_sockaddr_pf(¬ify->dst)) {
+ case PF_INET:
+ if (!have_notifysource) {
+ isc_sockaddr_t any;
+ isc_sockaddr_any(&any);
+
+ src = notify->src;
+ if (isc_sockaddr_equal(&src, &any)) {
+ src = notifyctx->notifysrc4;
+ }
+ }
+ break;
+ case PF_INET6:
+ if (!have_notifysource) {
+ isc_sockaddr_t any;
+ isc_sockaddr_any6(&any);
+
+ src = notify->src;
+ if (isc_sockaddr_equal(&src, &any)) {
+ src = notifyctx->notifysrc6;
+ }
+ }
+ break;
+ default:
+ result = ISC_R_NOTIMPLEMENTED;
+ goto cleanup_key;
+ }
+
+again:
+ if ((notify->flags & DNS_NOTIFY_TCP) != 0) {
+ options |= DNS_REQUESTOPT_TCP;
+ }
+
+ dns__zonemgr_tlsctx_attach(zmgr, &zmgr_tlsctx_cache);
+
+ const unsigned int connect_timeout = isc_nm_getinitialtimeout() /
+ MS_PER_SEC;
+ result = dns_request_create(
+ view->requestmgr, message, &src, ¬ify->dst,
+ notify->transport, zmgr_tlsctx_cache, options, key,
+ connect_timeout, TCP_REQUEST_TIMEOUT, UDP_REQUEST_TIMEOUT,
+ UDP_REQUEST_RETRIES, loop, notify_done, notify,
+ ¬ify->request);
+
+ isc_tlsctx_cache_detach(&zmgr_tlsctx_cache);
+
+ if (result == ISC_R_SUCCESS) {
+ if (isc_sockaddr_pf(¬ify->dst) == AF_INET) {
+ dns__zone_stats_increment(
+ notify->zone, dns_zonestatscounter_notifyoutv4);
+ } else {
+ dns__zone_stats_increment(
+ notify->zone, dns_zonestatscounter_notifyoutv6);
+ }
+ } else if (result == ISC_R_SHUTTINGDOWN || result == ISC_R_CANCELED) {
+ goto cleanup_key;
+ } else if ((notify->flags & DNS_NOTIFY_TCP) == 0) {
+ notify_log(notify, ISC_LOG_NOTICE,
+ "notify to %s failed: %s: retrying over TCP",
+ addrbuf, isc_result_totext(result));
+ notify->flags |= DNS_NOTIFY_TCP;
+ goto again;
+ }
+
+cleanup_key:
+ if (key != NULL) {
+ dns_tsigkey_detach(&key);
+ }
+cleanup_message:
+ dns_message_detach(&message);
+cleanup:
+ dns__zone_unlock(notify->zone);
+
+ if (zonedb != NULL) {
+ dns_db_detach(&zonedb);
+ }
+
+ if (notify->rlevent != NULL) {
+ isc_rlevent_free(¬ify->rlevent);
+ }
+
+ if (result != ISC_R_SUCCESS) {
+ isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf));
+ notify_log(notify, ISC_LOG_WARNING, "notify to %s failed: %s",
+ addrbuf, isc_result_totext(result));
+ dns_notify_destroy(notify, false);
+ }
+}
+
+static isc_result_t
+notify_queue(dns_notify_t *notify, bool startup, bool dequeue) {
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+
+ isc_loop_t *loop = dns_zone_getloop(notify->zone);
+ dns_zonemgr_t *zmgr = dns_zone_getmgr(notify->zone);
+ isc_ratelimiter_t *notifyrl = NULL;
+ isc_ratelimiter_t *startupnotifyrl = NULL;
+
+ INSIST(loop != NULL);
+ INSIST(zmgr != NULL);
+
+ dns__zonemgr_getnotifyrl(zmgr, ¬ifyrl);
+ dns__zonemgr_getstartupnotifyrl(zmgr, &startupnotifyrl);
+
+ if (dequeue) {
+ return isc_ratelimiter_dequeue(
+ startup ? startupnotifyrl : notifyrl, ¬ify->rlevent);
+ }
+
+ return isc_ratelimiter_enqueue(startup ? startupnotifyrl : notifyrl,
+ loop, notify_send_toaddr, notify,
+ ¬ify->rlevent);
+}
+
+isc_result_t
+dns_notify_dequeue(dns_notify_t *notify, bool startup) {
+ return notify_queue(notify, startup, true);
+}
+
+isc_result_t
+dns_notify_queue(dns_notify_t *notify, bool startup) {
+ return notify_queue(notify, startup, false);
+}
+
+bool
+dns_notify_isqueued(dns_notifyctx_t *nctx, unsigned int flags, dns_name_t *name,
+ isc_sockaddr_t *addr, dns_tsigkey_t *key,
+ dns_transport_t *transport) {
+ dns_notify_t *notify = NULL;
+ isc_result_t result;
+
+ REQUIRE(nctx != NULL);
+
+ ISC_LIST_FOREACH(nctx->notifies, n, link) {
+ if (n->request != NULL) {
+ continue;
+ }
+ if ((name != NULL && dns_name_dynamic(&n->ns) &&
+ dns_name_equal(name, &n->ns)) ||
+ (addr != NULL && isc_sockaddr_equal(addr, &n->dst) &&
+ n->key == key && n->transport == transport))
+ {
+ notify = n;
+ goto requeue;
+ }
+ }
+ return false;
+requeue:
+ /*
+ * If we are enqueued on the startup ratelimiter and this is
+ * not a startup notify, re-enqueue on the normal notify
+ * ratelimiter.
+ */
+ if (notify->rlevent != NULL && (flags & DNS_NOTIFY_STARTUP) == 0 &&
+ (notify->flags & DNS_NOTIFY_STARTUP) != 0)
+ {
+ result = notify_queue(notify, true, true);
+ if (result != ISC_R_SUCCESS) {
+ return true;
+ }
+
+ notify->flags &= ~DNS_NOTIFY_STARTUP;
+ result = notify_queue(notify, false, false);
+ if (result != ISC_R_SUCCESS) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool
+notify_isself(dns_notify_t *notify, isc_sockaddr_t *dst) {
+ dns_tsigkey_t *key = NULL;
+ isc_sockaddr_t src;
+ isc_sockaddr_t any;
+ bool isself;
+ isc_netaddr_t dstaddr;
+ isc_result_t result;
+ dns_notifyctx_t *notifyctx = NULL;
+ dns_view_t *view = NULL;
+ dns_isselffunc_t isselffunc;
+ void *isselfarg = NULL;
+
+ notifyctx = dns__zone_getnotifyctx(notify->zone);
+ view = dns_zone_getview(notify->zone);
+ dns__zone_getisself(notify->zone, &isselffunc, &isselfarg);
+ if (view == NULL || isselffunc == NULL) {
+ return false;
+ }
+
+ switch (isc_sockaddr_pf(dst)) {
+ case PF_INET:
+ src = notifyctx->notifysrc4;
+ isc_sockaddr_any(&any);
+ break;
+ case PF_INET6:
+ src = notifyctx->notifysrc6;
+ isc_sockaddr_any6(&any);
+ break;
+ default:
+ return false;
+ }
+
+ /*
+ * When sending from any the kernel will assign a source address
+ * that matches the destination address.
+ */
+ if (isc_sockaddr_eqaddr(&any, &src)) {
+ src = *dst;
+ }
+
+ isc_netaddr_fromsockaddr(&dstaddr, dst);
+ result = dns_view_getpeertsig(view, &dstaddr, &key);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
+ return false;
+ }
+ isself = (isselffunc)(view, key, &src, dst,
+ dns_zone_getrdclass(notify->zone), isselfarg);
+ if (key != NULL) {
+ dns_tsigkey_detach(&key);
+ }
+ return isself;
+}
+
+static void
+notify_send(dns_notify_t *notify) {
+ isc_sockaddr_t dst;
+ isc_result_t result;
+ dns_notify_t *newnotify = NULL;
+ dns_notifyctx_t *notifyctx = NULL;
+ unsigned int flags;
+ bool startup;
+
+ /*
+ * Zone lock held by caller.
+ */
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+ REQUIRE(dns__zone_locked(notify->zone));
+ if (dns__zone_exiting(notify->zone)) {
+ return;
+ }
+ notifyctx = dns__zone_getnotifyctx(notify->zone);
+
+ ISC_LIST_FOREACH(notify->find->list, ai, publink) {
+ dst = ai->sockaddr;
+ if (dns_notify_isqueued(notifyctx, notify->flags, NULL, &dst,
+ NULL, NULL))
+ {
+ continue;
+ }
+ if (notify_isself(notify, &dst)) {
+ continue;
+ }
+ newnotify = NULL;
+ flags = notify->flags & DNS_NOTIFY_NOSOA;
+ dns_notify_create(notify->mctx, flags, &newnotify);
+ dns__zone_iattach_locked(notify->zone, &newnotify->zone);
+ ISC_LIST_APPEND(notifyctx->notifies, newnotify, link);
+ newnotify->dst = dst;
+ if (isc_sockaddr_pf(&dst) == AF_INET6) {
+ isc_sockaddr_any6(&newnotify->src);
+ }
+ startup = ((notify->flags & DNS_NOTIFY_STARTUP) != 0);
+ result = dns_notify_queue(newnotify, startup);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+ newnotify = NULL;
+ }
+
+cleanup:
+ if (newnotify != NULL) {
+ dns_notify_destroy(newnotify, true);
+ }
+}
+
+/*
+ * XXXAG should check for DNS_ZONEFLG_EXITING
+ */
+static void
+process_notify_adb_event(void *arg) {
+ dns_adbfind_t *find = (dns_adbfind_t *)arg;
+ dns_notify_t *notify = (dns_notify_t *)find->cbarg;
+ dns_adbstatus_t astat = find->status;
+
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+ REQUIRE(find == notify->find);
+
+ switch (astat) {
+ case DNS_ADB_MOREADDRESSES:
+ dns_adb_destroyfind(¬ify->find);
+ dns_notify_find_address(notify);
+ return;
+
+ case DNS_ADB_NOMOREADDRESSES:
+ dns__zone_lock(notify->zone);
+ notify_send(notify);
+ dns__zone_unlock(notify->zone);
+ break;
+
+ default:
+ break;
+ }
+
+ dns_notify_destroy(notify, false);
+}
+
+void
+dns_notify_find_address(dns_notify_t *notify) {
+ isc_result_t result;
+ unsigned int options;
+ dns_adb_t *adb = NULL;
+ dns_view_t *view = NULL;
+ isc_loop_t *loop = NULL;
+
+ REQUIRE(DNS_NOTIFY_VALID(notify));
+
+ options = DNS_ADBFIND_WANTEVENT;
+ if (isc_net_probeipv4() != ISC_R_DISABLED) {
+ options |= DNS_ADBFIND_INET;
+ }
+ if (isc_net_probeipv6() != ISC_R_DISABLED) {
+ options |= DNS_ADBFIND_INET6;
+ }
+
+ loop = dns_zone_getloop(notify->zone);
+ view = dns_zone_getview(notify->zone);
+ dns_view_getadb(view, &adb);
+ if (loop == NULL || view == NULL || adb == NULL) {
+ goto destroy;
+ }
+
+ result = dns_adb_createfind(adb, loop, process_notify_adb_event, notify,
+ ¬ify->ns, options, 0, view->dstport, 0,
+ NULL, NULL, ¬ify->find);
+ dns_adb_detach(&adb);
+
+ /* Something failed? */
+ if (result != ISC_R_SUCCESS) {
+ goto destroy;
+ }
+
+ /* More addresses pending? */
+ if ((notify->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
+ return;
+ }
+
+ /* We have as many addresses as we can get. */
+ dns__zone_lock(notify->zone);
+ notify_send(notify);
+ dns__zone_unlock(notify->zone);
+destroy:
+ dns_notify_destroy(notify, false);
+}
+
+void
+dns_notify_cancel(dns_notifyctx_t *nctx) {
+ ISC_LIST_FOREACH(nctx->notifies, notify, link) {
+ INSIST(dns__zone_locked(notify->zone));
+ if (notify->find != NULL) {
+ dns_adb_cancelfind(notify->find);
+ }
+ if (notify->request != NULL) {
+ dns_request_cancel(notify->request);
+ }
+ }
+}
zone_debuglog(dns_zone_t *zone, const char *, int debuglevel, const char *msg,
...) ISC_FORMAT_PRINTF(4, 5);
static void
-notify_log(dns_zone_t *zone, int level, const char *fmt, ...)
- ISC_FORMAT_PRINTF(3, 4);
-static void
dnssec_log(dns_zone_t *zone, int level, const char *fmt, ...)
ISC_FORMAT_PRINTF(3, 4);
static void
checkds_send_toaddr(void *arg);
static void
nsfetch_levelup(dns_nsfetch_t *nsfetch);
-static void
-notify_cancel(dns_zone_t *zone);
-static void
-notify_find_address(dns_notify_t *notify);
-static void
-notify_send(dns_notify_t *notify);
-static isc_result_t
-notify_createmessage(dns_zone_t *zone, unsigned int flags,
- dns_message_t **messagep);
-static void
-notify_done(void *arg);
-static void
-notify_send_toaddr(void *arg);
static isc_result_t
zone_dump(dns_zone_t *, bool);
static void
UNLOCK_ZONE(zone);
}
-static void
-notify_cancel(dns_zone_t *zone) {
- /*
- * 'zone' locked by caller.
- */
-
- REQUIRE(LOCKED_ZONE(zone));
-
- ISC_LIST_FOREACH(zone->notifyctx.notifies, notify, link) {
- if (notify->find != NULL) {
- dns_adb_cancelfind(notify->find);
- }
- if (notify->request != NULL) {
- dns_request_cancel(notify->request);
- }
- }
-}
-
static void
checkds_cancel(dns_zone_t *zone) {
/*
}
}
-static bool
-notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name,
- isc_sockaddr_t *addr, dns_tsigkey_t *key,
- dns_transport_t *transport) {
- dns_notify_t *notify = NULL;
- dns_zonemgr_t *zmgr = NULL;
- isc_result_t result;
-
- ISC_LIST_FOREACH(zone->notifyctx.notifies, n, link) {
- if (n->request != NULL) {
- continue;
- }
- if ((name != NULL && dns_name_dynamic(&n->ns) &&
- dns_name_equal(name, &n->ns)) ||
- (addr != NULL && isc_sockaddr_equal(addr, &n->dst) &&
- n->key == key && n->transport == transport))
- {
- notify = n;
- goto requeue;
- }
- }
- return false;
-
-requeue:
- /*
- * If we are enqueued on the startup ratelimiter and this is
- * not a startup notify, re-enqueue on the normal notify
- * ratelimiter.
- */
- if (notify->rlevent != NULL && (flags & DNS_NOTIFY_STARTUP) == 0 &&
- (notify->flags & DNS_NOTIFY_STARTUP) != 0)
- {
- zmgr = notify->zone->zmgr;
- result = isc_ratelimiter_dequeue(zmgr->startupnotifyrl,
- ¬ify->rlevent);
- if (result != ISC_R_SUCCESS) {
- return true;
- }
-
- notify->flags &= ~DNS_NOTIFY_STARTUP;
- result = isc_ratelimiter_enqueue(
- notify->zone->zmgr->notifyrl, notify->zone->loop,
- notify_send_toaddr, notify, ¬ify->rlevent);
- if (result != ISC_R_SUCCESS) {
- return false;
- }
- }
-
- return true;
-}
-
-static bool
-notify_isself(dns_zone_t *zone, isc_sockaddr_t *dst) {
- dns_tsigkey_t *key = NULL;
- isc_sockaddr_t src;
- isc_sockaddr_t any;
- bool isself;
- isc_netaddr_t dstaddr;
- isc_result_t result;
-
- if (zone->view == NULL || zone->isself == NULL) {
- return false;
- }
-
- switch (isc_sockaddr_pf(dst)) {
- case PF_INET:
- src = zone->notifyctx.notifysrc4;
- isc_sockaddr_any(&any);
- break;
- case PF_INET6:
- src = zone->notifyctx.notifysrc6;
- isc_sockaddr_any6(&any);
- break;
- default:
- return false;
- }
-
- /*
- * When sending from any the kernel will assign a source address
- * that matches the destination address.
- */
- if (isc_sockaddr_eqaddr(&any, &src)) {
- src = *dst;
- }
-
- isc_netaddr_fromsockaddr(&dstaddr, dst);
- result = dns_view_getpeertsig(zone->view, &dstaddr, &key);
- if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
- return false;
- }
- isself = (zone->isself)(zone->view, key, &src, dst, zone->rdclass,
- zone->isselfarg);
- if (key != NULL) {
- dns_tsigkey_detach(&key);
- }
- return isself;
-}
-
-static void
-notify_destroy(dns_notify_t *notify, bool locked) {
- isc_mem_t *mctx;
-
- REQUIRE(DNS_NOTIFY_VALID(notify));
-
- if (notify->zone != NULL) {
- if (!locked) {
- LOCK_ZONE(notify->zone);
- }
- REQUIRE(LOCKED_ZONE(notify->zone));
- if (ISC_LINK_LINKED(notify, link)) {
- ISC_LIST_UNLINK(notify->zone->notifyctx.notifies,
- notify, link);
- }
- if (!locked) {
- UNLOCK_ZONE(notify->zone);
- }
- dns_zone_idetach(¬ify->zone, locked);
- }
- if (notify->find != NULL) {
- dns_adb_destroyfind(¬ify->find);
- }
- if (notify->request != NULL) {
- dns_request_destroy(¬ify->request);
- }
- if (dns_name_dynamic(¬ify->ns)) {
- dns_name_free(¬ify->ns, notify->mctx);
- }
- if (notify->key != NULL) {
- dns_tsigkey_detach(¬ify->key);
- }
- if (notify->transport != NULL) {
- dns_transport_detach(¬ify->transport);
- }
- mctx = notify->mctx;
- isc_mem_put(notify->mctx, notify, sizeof(*notify));
- isc_mem_detach(&mctx);
-}
-
-/*
- * XXXAG should check for DNS_ZONEFLG_EXITING
- */
-static void
-process_notify_adb_event(void *arg) {
- dns_adbfind_t *find = (dns_adbfind_t *)arg;
- dns_notify_t *notify = (dns_notify_t *)find->cbarg;
- dns_adbstatus_t astat = find->status;
-
- REQUIRE(DNS_NOTIFY_VALID(notify));
- REQUIRE(find == notify->find);
-
- switch (astat) {
- case DNS_ADB_MOREADDRESSES:
- dns_adb_destroyfind(¬ify->find);
- notify_find_address(notify);
- return;
-
- case DNS_ADB_NOMOREADDRESSES:
- LOCK_ZONE(notify->zone);
- notify_send(notify);
- UNLOCK_ZONE(notify->zone);
- break;
-
- default:
- break;
- }
-
- notify_destroy(notify, false);
-}
-
-static void
-notify_find_address(dns_notify_t *notify) {
- isc_result_t result;
- unsigned int options;
- dns_adb_t *adb = NULL;
-
- REQUIRE(DNS_NOTIFY_VALID(notify));
-
- options = DNS_ADBFIND_WANTEVENT;
- if (isc_net_probeipv4() != ISC_R_DISABLED) {
- options |= DNS_ADBFIND_INET;
- }
- if (isc_net_probeipv6() != ISC_R_DISABLED) {
- options |= DNS_ADBFIND_INET6;
- }
-
- dns_view_getadb(notify->zone->view, &adb);
- if (adb == NULL) {
- goto destroy;
- }
-
- result = dns_adb_createfind(
- adb, notify->zone->loop, process_notify_adb_event, notify,
- ¬ify->ns, options, 0, notify->zone->view->dstport, 0, NULL,
- NULL, ¬ify->find);
- dns_adb_detach(&adb);
-
- /* Something failed? */
- if (result != ISC_R_SUCCESS) {
- goto destroy;
- }
-
- /* More addresses pending? */
- if ((notify->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
- return;
- }
-
- /* We have as many addresses as we can get. */
- LOCK_ZONE(notify->zone);
- notify_send(notify);
- UNLOCK_ZONE(notify->zone);
-
-destroy:
- notify_destroy(notify, false);
-}
-
-static isc_result_t
-notify_send_queue(dns_notify_t *notify, bool startup) {
- return isc_ratelimiter_enqueue(
- startup ? notify->zone->zmgr->startupnotifyrl
- : notify->zone->zmgr->notifyrl,
- notify->zone->loop, notify_send_toaddr, notify,
- ¬ify->rlevent);
-}
-
-static void
-notify_send_toaddr(void *arg) {
- dns_notify_t *notify = (dns_notify_t *)arg;
- isc_result_t result;
- dns_message_t *message = NULL;
- isc_netaddr_t dstip;
- dns_tsigkey_t *key = NULL;
- char addrbuf[ISC_SOCKADDR_FORMATSIZE];
- isc_sockaddr_t src;
- unsigned int options;
- bool have_notifysource = false;
- isc_tlsctx_cache_t *zmgr_tlsctx_cache = NULL;
-
- REQUIRE(DNS_NOTIFY_VALID(notify));
-
- LOCK_ZONE(notify->zone);
-
- isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf));
-
- if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0 ||
- notify->rlevent->canceled ||
- DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING) ||
- notify->zone->view->requestmgr == NULL || notify->zone->db == NULL)
- {
- result = ISC_R_CANCELED;
- goto cleanup;
- }
-
- /*
- * The raw IPv4 address should also exist. Don't send to the
- * mapped form.
- */
- if (isc_sockaddr_pf(¬ify->dst) == PF_INET6 &&
- IN6_IS_ADDR_V4MAPPED(¬ify->dst.type.sin6.sin6_addr))
- {
- notify_log(notify->zone, ISC_LOG_DEBUG(3),
- "notify: ignoring IPv6 mapped IPV4 address: %s",
- addrbuf);
- result = ISC_R_CANCELED;
- goto cleanup;
- }
-
- result = notify_createmessage(notify->zone, notify->flags, &message);
- if (result != ISC_R_SUCCESS) {
- goto cleanup;
- }
-
- if (notify->key != NULL) {
- /* Transfer ownership of key */
- key = notify->key;
- notify->key = NULL;
- } else {
- isc_netaddr_fromsockaddr(&dstip, ¬ify->dst);
- result = dns_view_getpeertsig(notify->zone->view, &dstip, &key);
- if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
- notify_log(notify->zone, ISC_LOG_ERROR,
- "NOTIFY to %s not sent. "
- "Peer TSIG key lookup failure.",
- addrbuf);
- goto cleanup_message;
- }
- }
-
- if (key != NULL) {
- char namebuf[DNS_NAME_FORMATSIZE];
-
- dns_name_format(key->name, namebuf, sizeof(namebuf));
- notify_log(notify->zone, ISC_LOG_INFO,
- "sending notify to %s : TSIG (%s)", addrbuf,
- namebuf);
- } else {
- notify_log(notify->zone, ISC_LOG_INFO, "sending notify to %s",
- addrbuf);
- }
- options = 0;
- if (notify->zone->view->peers != NULL) {
- dns_peer_t *peer = NULL;
- bool usetcp = false;
- result = dns_peerlist_peerbyaddr(notify->zone->view->peers,
- &dstip, &peer);
- if (result == ISC_R_SUCCESS) {
- result = dns_peer_getnotifysource(peer, &src);
- if (result == ISC_R_SUCCESS) {
- have_notifysource = true;
- }
- result = dns_peer_getforcetcp(peer, &usetcp);
- if (result == ISC_R_SUCCESS && usetcp) {
- options |= DNS_FETCHOPT_TCP;
- }
- }
- }
- switch (isc_sockaddr_pf(¬ify->dst)) {
- case PF_INET:
- if (!have_notifysource) {
- isc_sockaddr_t any;
- isc_sockaddr_any(&any);
-
- src = notify->src;
- if (isc_sockaddr_equal(&src, &any)) {
- src = notify->zone->notifyctx.notifysrc4;
- }
- }
- break;
- case PF_INET6:
- if (!have_notifysource) {
- isc_sockaddr_t any;
- isc_sockaddr_any6(&any);
-
- src = notify->src;
- if (isc_sockaddr_equal(&src, &any)) {
- src = notify->zone->notifyctx.notifysrc6;
- }
- }
- break;
- default:
- result = ISC_R_NOTIMPLEMENTED;
- goto cleanup_key;
- }
-
-again:
- if ((notify->flags & DNS_NOTIFY_TCP) != 0) {
- options |= DNS_REQUESTOPT_TCP;
- }
-
- dns_zonemgr_tlsctx_attach(notify->zone->zmgr, &zmgr_tlsctx_cache);
-
- const unsigned int connect_timeout = isc_nm_getinitialtimeout() /
- MS_PER_SEC;
- result = dns_request_create(
- notify->zone->view->requestmgr, message, &src, ¬ify->dst,
- notify->transport, zmgr_tlsctx_cache, options, key,
- connect_timeout, TCP_REQUEST_TIMEOUT, UDP_REQUEST_TIMEOUT,
- UDP_REQUEST_RETRIES, notify->zone->loop, notify_done, notify,
- ¬ify->request);
-
- isc_tlsctx_cache_detach(&zmgr_tlsctx_cache);
-
- if (result == ISC_R_SUCCESS) {
- if (isc_sockaddr_pf(¬ify->dst) == AF_INET) {
- inc_stats(notify->zone,
- dns_zonestatscounter_notifyoutv4);
- } else {
- inc_stats(notify->zone,
- dns_zonestatscounter_notifyoutv6);
- }
- } else if (result == ISC_R_SHUTTINGDOWN || result == ISC_R_CANCELED) {
- goto cleanup_key;
- } else if ((notify->flags & DNS_NOTIFY_TCP) == 0) {
- notify_log(notify->zone, ISC_LOG_NOTICE,
- "notify to %s failed: %s: retrying over TCP",
- addrbuf, isc_result_totext(result));
- notify->flags |= DNS_NOTIFY_TCP;
- goto again;
- }
-
-cleanup_key:
- if (key != NULL) {
- dns_tsigkey_detach(&key);
- }
-cleanup_message:
- dns_message_detach(&message);
-cleanup:
- UNLOCK_ZONE(notify->zone);
- if (notify->rlevent != NULL) {
- isc_rlevent_free(¬ify->rlevent);
- }
-
- if (result != ISC_R_SUCCESS) {
- isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf));
- notify_log(notify->zone, ISC_LOG_WARNING,
- "notify to %s failed: %s", addrbuf,
- isc_result_totext(result));
- notify_destroy(notify, false);
- }
-}
-
-static void
-notify_send(dns_notify_t *notify) {
- isc_sockaddr_t dst;
- isc_result_t result;
- dns_notify_t *newnotify = NULL;
- unsigned int flags;
- bool startup;
-
- /*
- * Zone lock held by caller.
- */
- REQUIRE(DNS_NOTIFY_VALID(notify));
- REQUIRE(LOCKED_ZONE(notify->zone));
-
- if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_EXITING)) {
- return;
- }
-
- ISC_LIST_FOREACH(notify->find->list, ai, publink) {
- dst = ai->sockaddr;
- if (notify_isqueued(notify->zone, notify->flags, NULL, &dst,
- NULL, NULL))
- {
- continue;
- }
- if (notify_isself(notify->zone, &dst)) {
- continue;
- }
- newnotify = NULL;
- flags = notify->flags & DNS_NOTIFY_NOSOA;
- dns_notify_create(notify->mctx, flags, &newnotify);
- zone_iattach(notify->zone, &newnotify->zone);
- ISC_LIST_APPEND(newnotify->zone->notifyctx.notifies, newnotify,
- link);
- newnotify->dst = dst;
- if (isc_sockaddr_pf(&dst) == AF_INET6) {
- isc_sockaddr_any6(&newnotify->src);
- }
- startup = ((notify->flags & DNS_NOTIFY_STARTUP) != 0);
- result = notify_send_queue(newnotify, startup);
- if (result != ISC_R_SUCCESS) {
- goto cleanup;
- }
- newnotify = NULL;
- }
-
-cleanup:
- if (newnotify != NULL) {
- notify_destroy(newnotify, true);
- }
-}
-
void
dns_zone_notify(dns_zone_t *zone, bool nodefer) {
isc_time_t now;
tlsname, &transport);
if (result == ISC_R_SUCCESS) {
- notify_log(
- zone, ISC_LOG_INFO,
+ dns_zone_logc(
+ zone, DNS_LOGCATEGORY_NOTIFY,
+ ISC_LOG_INFO,
"got TLS configuration for a notify");
} else {
dns_zone_logc(zone, DNS_LOGCATEGORY_XFER_IN,
goto next;
}
- if (notify_isqueued(zone, flags, NULL, &dst, key, transport)) {
+ if (dns_notify_isqueued(&zone->notifyctx, flags, NULL, &dst,
+ key, transport))
+ {
if (key != NULL) {
dns_tsigkey_detach(&key);
}
}
ISC_LIST_APPEND(zone->notifyctx.notifies, notify, link);
- result = notify_send_queue(notify, startup);
+ result = dns_notify_queue(notify, startup);
if (result != ISC_R_SUCCESS) {
- notify_destroy(notify, true);
+ dns_notify_destroy(notify, true);
}
if (!loggednotify) {
- notify_log(zone, ISC_LOG_INFO,
- "sending notifies (serial %u)", serial);
+ dns_zone_logc(zone, DNS_LOGCATEGORY_NOTIFY,
+ ISC_LOG_INFO,
+ "sending notifies (serial %u)", serial);
loggednotify = true;
}
next:
}
if (!loggednotify) {
- notify_log(zone, ISC_LOG_INFO,
- "sending notifies (serial %u)", serial);
+ dns_zone_logc(zone, DNS_LOGCATEGORY_NOTIFY,
+ ISC_LOG_INFO,
+ "sending notifies (serial %u)", serial);
loggednotify = true;
}
LOCK_ZONE(zone);
- isqueued = notify_isqueued(zone, flags, &ns.name, NULL, NULL,
- NULL);
+ isqueued = dns_notify_isqueued(&zone->notifyctx, flags,
+ &ns.name, NULL, NULL, NULL);
UNLOCK_ZONE(zone);
if (isqueued) {
continue;
LOCK_ZONE(zone);
ISC_LIST_APPEND(zone->notifyctx.notifies, notify, link);
UNLOCK_ZONE(zone);
- notify_find_address(notify);
+ dns_notify_find_address(notify);
}
dns_rdataset_disassociate(&nsrdset);
checkds_cancel(zone);
- notify_cancel(zone);
+ dns_notify_cancel(&zone->notifyctx);
forward_cancel(zone);
zone_settimer(zone, &now);
}
-static isc_result_t
-notify_createmessage(dns_zone_t *zone, unsigned int flags,
- dns_message_t **messagep) {
- dns_db_t *zonedb = NULL;
- dns_dbnode_t *node = NULL;
- dns_dbversion_t *version = NULL;
- dns_message_t *message = NULL;
- dns_rdataset_t rdataset;
- dns_rdata_t rdata = DNS_RDATA_INIT;
-
- dns_name_t *tempname = NULL;
- dns_rdata_t *temprdata = NULL;
- dns_rdatalist_t *temprdatalist = NULL;
- dns_rdataset_t *temprdataset = NULL;
-
- isc_result_t result;
- isc_region_t r;
- isc_buffer_t *b = NULL;
-
- REQUIRE(DNS_ZONE_VALID(zone));
- REQUIRE(messagep != NULL && *messagep == NULL);
-
- dns_message_create(zone->mctx, NULL, NULL, DNS_MESSAGE_INTENTRENDER,
- &message);
-
- message->opcode = dns_opcode_notify;
- message->flags |= DNS_MESSAGEFLAG_AA;
- message->rdclass = zone->rdclass;
-
- dns_message_gettempname(message, &tempname);
-
- dns_message_gettemprdataset(message, &temprdataset);
-
- /*
- * Make question.
- */
- dns_name_clone(&zone->origin, tempname);
- dns_rdataset_makequestion(temprdataset, zone->rdclass,
- dns_rdatatype_soa);
- ISC_LIST_APPEND(tempname->list, temprdataset, link);
- dns_message_addname(message, tempname, DNS_SECTION_QUESTION);
- tempname = NULL;
- temprdataset = NULL;
-
- if ((flags & DNS_NOTIFY_NOSOA) != 0) {
- goto done;
- }
-
- dns_message_gettempname(message, &tempname);
- dns_message_gettemprdata(message, &temprdata);
- dns_message_gettemprdataset(message, &temprdataset);
- dns_message_gettemprdatalist(message, &temprdatalist);
-
- ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
- INSIST(zone->db != NULL); /* XXXJT: is this assumption correct? */
- dns_db_attach(zone->db, &zonedb);
- ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
-
- dns_name_clone(&zone->origin, tempname);
- dns_db_currentversion(zonedb, &version);
- result = dns_db_findnode(zonedb, tempname, false, &node);
- if (result != ISC_R_SUCCESS) {
- goto soa_cleanup;
- }
-
- dns_rdataset_init(&rdataset);
- result = dns_db_findrdataset(zonedb, node, version, dns_rdatatype_soa,
- dns_rdatatype_none, 0, &rdataset, NULL);
- if (result != ISC_R_SUCCESS) {
- goto soa_cleanup;
- }
- result = dns_rdataset_first(&rdataset);
- if (result != ISC_R_SUCCESS) {
- goto soa_cleanup;
- }
- dns_rdataset_current(&rdataset, &rdata);
- dns_rdata_toregion(&rdata, &r);
- isc_buffer_allocate(zone->mctx, &b, r.length);
- isc_buffer_putmem(b, r.base, r.length);
- isc_buffer_usedregion(b, &r);
- dns_rdata_fromregion(temprdata, rdata.rdclass, rdata.type, &r);
- dns_message_takebuffer(message, &b);
- result = dns_rdataset_next(&rdataset);
- dns_rdataset_disassociate(&rdataset);
- if (result != ISC_R_NOMORE) {
- goto soa_cleanup;
- }
- temprdatalist->rdclass = rdata.rdclass;
- temprdatalist->type = rdata.type;
- temprdatalist->ttl = rdataset.ttl;
- ISC_LIST_APPEND(temprdatalist->rdata, temprdata, link);
-
- dns_rdatalist_tordataset(temprdatalist, temprdataset);
-
- ISC_LIST_APPEND(tempname->list, temprdataset, link);
- dns_message_addname(message, tempname, DNS_SECTION_ANSWER);
- temprdatalist = NULL;
- temprdataset = NULL;
- temprdata = NULL;
- tempname = NULL;
-
-soa_cleanup:
- if (node != NULL) {
- dns_db_detachnode(&node);
- }
- if (version != NULL) {
- dns_db_closeversion(zonedb, &version, false);
- }
- if (zonedb != NULL) {
- dns_db_detach(&zonedb);
- }
- if (tempname != NULL) {
- dns_message_puttempname(message, &tempname);
- }
- if (temprdata != NULL) {
- dns_message_puttemprdata(message, &temprdata);
- }
- if (temprdataset != NULL) {
- dns_message_puttemprdataset(message, &temprdataset);
- }
- if (temprdatalist != NULL) {
- dns_message_puttemprdatalist(message, &temprdatalist);
- }
-
-done:
- *messagep = message;
- return ISC_R_SUCCESS;
-}
-
isc_result_t
dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
isc_sockaddr_t *to, dns_message_t *msg) {
zstr, zone->strnamerd, message);
}
-static void
-notify_log(dns_zone_t *zone, int level, const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
- dns_zone_logv(zone, DNS_LOGCATEGORY_NOTIFY, level, NULL, fmt, ap);
- va_end(ap);
-}
-
void
dns_zone_logc(dns_zone_t *zone, isc_logcategory_t category, int level,
const char *fmt, ...) {
return DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) != 0;
}
-static void
-notify_done(void *arg) {
- dns_request_t *request = (dns_request_t *)arg;
- dns_notify_t *notify = dns_request_getarg(request);
- isc_result_t result;
- dns_message_t *message = NULL;
- isc_buffer_t buf;
- char rcode[128];
- char addrbuf[ISC_SOCKADDR_FORMATSIZE];
-
- REQUIRE(DNS_NOTIFY_VALID(notify));
-
- isc_buffer_init(&buf, rcode, sizeof(rcode));
- isc_sockaddr_format(¬ify->dst, addrbuf, sizeof(addrbuf));
- dns_message_create(notify->zone->mctx, NULL, NULL,
- DNS_MESSAGE_INTENTPARSE, &message);
-
- result = dns_request_getresult(request);
- if (result != ISC_R_SUCCESS) {
- goto fail;
- }
-
- result = dns_request_getresponse(request, message,
- DNS_MESSAGEPARSE_PRESERVEORDER);
- if (result != ISC_R_SUCCESS) {
- goto fail;
- }
-
- result = dns_rcode_totext(message->rcode, &buf);
- if (result == ISC_R_SUCCESS) {
- notify_log(notify->zone, ISC_LOG_DEBUG(3),
- "notify response from %s: %.*s", addrbuf,
- (int)buf.used, rcode);
- }
-
-fail:
- dns_message_detach(&message);
-
- if (result == ISC_R_SUCCESS) {
- notify_log(notify->zone, ISC_LOG_DEBUG(1),
- "notify to %s successful", addrbuf);
- } else if (result == ISC_R_SHUTTINGDOWN || result == ISC_R_CANCELED) {
- /* just destroy the notify */
- } else if ((notify->flags & DNS_NOTIFY_TCP) == 0) {
- notify_log(notify->zone, ISC_LOG_NOTICE,
- "notify to %s failed: %s: retrying over TCP",
- addrbuf, isc_result_totext(result));
- notify->flags |= DNS_NOTIFY_TCP;
- dns_request_destroy(¬ify->request);
- notify_send_queue(notify, notify->flags & DNS_NOTIFY_STARTUP);
- return;
- } else if (result == ISC_R_TIMEDOUT) {
- notify_log(notify->zone, ISC_LOG_WARNING,
- "notify to %s failed: %s: retries exceeded", addrbuf,
- isc_result_totext(result));
- } else {
- notify_log(notify->zone, ISC_LOG_WARNING,
- "notify to %s failed: %s", addrbuf,
- isc_result_totext(result));
- }
- notify_destroy(notify, false);
-}
-
struct rss {
dns_zone_t *zone;
dns_db_t *db;