zones->p.nsip_wait_recurse = false;
}
+ sub_obj = cfg_tuple_get(rpz_obj, "servfail-until-ready");
+ if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
+ zones->p.servfail_until_ready = true;
+ } else {
+ zones->p.servfail_until_ready = false;
+ }
+
if (pview != NULL) {
old = pview->rpzs;
} else {
RPZ to delete answers that would otherwise contain :rfc:`1918` values on
the externally visible name server or view.
+Also by default, when :iscman:`named` is started it may start answering to
+queries before the response policy zones are completely loaded and processed.
+This can be changed with the ``servfail-until-ready yes`` option, in which case
+incoming requests will result in SERVFAIL answer, until all the response policy
+zones are ready. Note that if one or more response policy zones fail to load,
+:iscman:`named` starts responding to queries according to those zones that did
+load.
+
Also by default, RPZ actions are applied only to DNS requests that
either do not request DNSSEC metadata (DO=0) or when no DNSSEC records
are available for the requested name in the original zone (not the response
resolver-query-timeout <integer>;
resolver-use-dns64 <boolean>;
response-padding { <address_match_element>; ... } block-size <integer>;
- response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
+ response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ servfail-until-ready <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
responselog <boolean>;
reuseport <boolean>;
root-key-sentinel <boolean>;
resolver-query-timeout <integer>;
resolver-use-dns64 <boolean>;
response-padding { <address_match_element>; ... } block-size <integer>;
- response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
+ response-policy { zone <string> [ add-soa <boolean> ] [ log <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ policy ( cname | disabled | drop | given | no-op | nodata | nxdomain | passthru | tcp-only <quoted_string> ) ] [ recursive-only <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ ede <string> ]; ... } [ add-soa <boolean> ] [ break-dnssec <boolean> ] [ max-policy-ttl <duration> ] [ min-update-interval <duration> ] [ min-ns-dots <integer> ] [ nsip-wait-recurse <boolean> ] [ nsdname-wait-recurse <boolean> ] [ qname-wait-recurse <boolean> ] [ recursive-only <boolean> ] [ servfail-until-ready <boolean> ] [ nsip-enable <boolean> ] [ nsdname-enable <boolean> ] [ dnsrps-enable <boolean> ] [ dnsrps-options { <unspecified-text> } ];
root-key-sentinel <boolean>;
rrset-order { [ class <string> ] [ type <string> ] [ name <quoted_string> ] <string> <string>; ... };
send-cookie <boolean>;
#include <inttypes.h>
#include <stdbool.h>
+#include <isc/atomic.h>
#include <isc/ht.h>
#include <isc/refcount.h>
#include <isc/rwlock.h>
dns_rpz_zones_t *rpzs; /* owner */
isc_time_t lastupdated; /* last time the zone was processed
* */
+ bool processed; /* the zone is processed. */
+ bool dbregistered; /* db callback notify is registered. */
bool updatepending; /* there is an update pending */
bool updaterunning; /* there is an update running */
isc_result_t updateresult; /* result from the offloaded work */
bool qname_wait_recurse;
bool nsip_wait_recurse;
bool nsdname_wait_recurse;
+ bool servfail_until_ready;
unsigned int min_ns_labels;
dns_rpz_num_t num_zones;
};
dns_rpz_zone_t *zones[DNS_RPZ_MAX_ZONES];
dns_rpz_triggers_t triggers[DNS_RPZ_MAX_ZONES];
+ _Atomic(dns_rpz_num_t) zones_registered;
+ _Atomic(dns_rpz_num_t) zones_processed;
+
/*
* RPZ policy version number.
* It is initially 0 and it increases whenever the server is
REQUIRE(DNS_DB_VALID(db));
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
+ LOCK(&rpz->rpzs->maint_lock);
dns_db_updatenotify_unregister(db, dns_rpz_dbupdate_callback, rpz);
+ if (rpz->processed) {
+ rpz->processed = false;
+ INSIST(atomic_fetch_sub_acq_rel(&rpz->rpzs->zones_processed,
+ 1) > 0);
+ }
+ if (rpz->dbregistered) {
+ rpz->dbregistered = false;
+ INSIST(atomic_fetch_sub_acq_rel(&rpz->rpzs->zones_registered,
+ 1) > 0);
+ }
+ UNLOCK(&rpz->rpzs->maint_lock);
}
void
REQUIRE(DNS_DB_VALID(db));
REQUIRE(DNS_RPZ_ZONE_VALID(rpz));
+ LOCK(&rpz->rpzs->maint_lock);
+ if (!rpz->dbregistered) {
+ rpz->dbregistered = true;
+ atomic_fetch_add_acq_rel(&rpz->rpzs->zones_registered, 1);
+ }
dns_db_updatenotify_register(db, dns_rpz_dbupdate_callback, rpz);
+ UNLOCK(&rpz->rpzs->maint_lock);
}
+
static void
dns__rpz_timer_start(dns_rpz_zone_t *rpz) {
uint64_t tdiff;
dns_db_closeversion(rpz->updb, &rpz->updbversion, false);
dns_db_detach(&rpz->updb);
+ if (rpz->dbregistered && !rpz->processed) {
+ rpz->processed = true;
+ atomic_fetch_add_acq_rel(&rpz->rpzs->zones_processed, 1);
+ }
+
UNLOCK(&rpz->rpzs->maint_lock);
isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_RPZ, ISC_LOG_INFO,
* } [ recursive-only yes|no ] [ max-policy-ttl number ]
* [ min-update-interval number ]
* [ break-dnssec yes|no ] [ min-ns-dots number ]
- * [ qname-wait-recurse yes|no ]
+ * [ qname-wait-recurse yes|no ] [ servfail-until-ready yes|no ]
* [ nsip-enable yes|no ] [ nsdname-enable yes|no ]
*/
{ "nsdname-wait-recurse", &cfg_type_boolean, 0 },
{ "qname-wait-recurse", &cfg_type_boolean, 0 },
{ "recursive-only", &cfg_type_boolean, 0 },
+ { "servfail-until-ready", &cfg_type_boolean, 0 },
{ "nsip-enable", &cfg_type_boolean, 0 },
{ "nsdname-enable", &cfg_type_boolean, 0 },
{ "dnsrps-enable", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE },
bool resuming, dns_rdataset_t *ordataset, dns_rdataset_t *osigset) {
dns_rpz_zones_t *rpzs;
dns_rpz_st_t *st;
- dns_rdataset_t *rdataset;
+ dns_rdataset_t *rdataset = NULL;
dns_fixedname_t nsnamef;
dns_name_t *nsname;
qresult_type_t qresult_type;
isc_result_t result = ISC_R_SUCCESS;
dns_rpz_have_t have;
dns_rpz_popt_t popt;
+ bool first_time;
+ dns_rpz_num_t zones_registered;
+ dns_rpz_num_t zones_processed;
+
int rpz_ver;
unsigned int options;
}
have = rpzs->have;
popt = rpzs->p;
+ first_time = rpzs->first_time;
+ zones_registered = atomic_load_acquire(&rpzs->zones_registered);
+ zones_processed = atomic_load_acquire(&rpzs->zones_processed);
rpz_ver = rpzs->rpz_ver;
RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
client->query.rpz_st = st;
}
+ /* Check if the initial loading of RPZ is complete. */
+ if (first_time && popt.servfail_until_ready &&
+ zones_processed < zones_registered)
+ {
+ rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, NULL,
+ DNS_RPZ_TYPE_QNAME, "RPZ not ready yet", result);
+ st->m.policy = DNS_RPZ_POLICY_ERROR;
+ goto cleanup;
+ }
+
/*
* There is nothing to rewrite if the main query failed.
*/
return ISC_R_SUCCESS;
}
- rdataset = NULL;
-
if ((st->state & (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) !=
(DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME))
{