#define WANTNSID(x) (((x)->attributes & NS_CLIENTATTR_WANTNSID) != 0)
#define WANTPAD(x) (((x)->attributes & NS_CLIENTATTR_WANTPAD) != 0)
#define WANTRC(x) (((x)->attributes & NS_CLIENTATTR_WANTRC) != 0)
+#define WANTZONEVERSION(x) \
+ (((x)->attributes & NS_CLIENTATTR_WANTZONEVERSION) != 0)
#define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm')
#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC)
/* XXXWPK TODO use netmgr to set timeout */
}
+static void
+client_zoneversion_reset(ns_client_t *client) {
+ if (client->zoneversion == NULL) {
+ return;
+ }
+ isc_mem_put(client->manager->mctx, client->zoneversion,
+ client->zoneversionlength);
+ client->zoneversion = NULL;
+ client->zoneversionlength = 0;
+}
+
static void
ns_client_endrequest(ns_client_t *client) {
INSIST(client->state == NS_CLIENTSTATE_WORKING ||
dns_message_puttemprdataset(client->message, &client->opt);
}
+ client_zoneversion_reset(client);
client->signer = NULL;
client->udpsize = 512;
client->extflags = 0;
ednsopts[count].value = ede->value;
count++;
}
+ if ((client->attributes & NS_CLIENTATTR_HAVEZONEVERSION) != 0) {
+ INSIST(count < DNS_EDNSOPTIONS);
+ ednsopts[count].code = DNS_OPT_ZONEVERSION;
+ ednsopts[count].length = client->zoneversionlength;
+ ednsopts[count].value = client->zoneversion;
+ count++;
+ }
if (WANTRC(client)) {
dns_name_t *rad = NULL;
case DNS_OPT_CLIENT_SUBNET:
result = process_ecs(client, &optbuf, optlen);
if (result != ISC_R_SUCCESS) {
- ns_client_error(client, result);
- return result;
+ goto formerr;
}
ns_stats_increment(
client->manager->sctx->nsstats,
result = process_keytag(client, &optbuf,
optlen);
if (result != ISC_R_SUCCESS) {
- ns_client_error(client, result);
- return result;
+ goto formerr;
}
ns_stats_increment(
client->manager->sctx->nsstats,
ns_statscounter_keytagopt);
break;
+ case DNS_OPT_ZONEVERSION:
+ if (optlen != 0 || WANTZONEVERSION(client)) {
+ result = DNS_R_FORMERR;
+ goto formerr;
+ }
+ ns_stats_increment(
+ client->manager->sctx->nsstats,
+ ns_statscounter_zoneversionopt);
+ client->attributes |=
+ NS_CLIENTATTR_WANTZONEVERSION;
+ isc_buffer_forward(&optbuf, optlen);
+ break;
default:
ns_stats_increment(
client->manager->sctx->nsstats,
client->attributes |= NS_CLIENTATTR_WANTOPT;
return result;
+
+formerr:
+ if (result == DNS_R_FORMERR || result == DNS_R_OPTERR) {
+ result = ns_client_addopt(client, client->message,
+ &client->opt);
+ if (result == ISC_R_SUCCESS) {
+ result = DNS_R_FORMERR;
+ }
+ }
+ ns_client_error(client, result);
+ return result;
}
static void
*/
ns_query_free(client);
dns_ede_invalidate(&client->edectx);
+ client_zoneversion_reset(client);
client->magic = 0;
ISC_LINK(ns_client_t) rlink;
unsigned char cookie[8];
uint32_t expire;
+ unsigned char *zoneversion;
+ uint32_t zoneversionlength;
unsigned char *keytag;
uint16_t keytag_len;
#define NS_CLIENT_MAGIC ISC_MAGIC('N', 'S', 'C', 'c')
#define NS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, NS_CLIENT_MAGIC)
-#define NS_CLIENTATTR_TCP 0x00001
-#define NS_CLIENTATTR_RA 0x00002 /*%< Client gets recursive service */
-#define NS_CLIENTATTR_PKTINFO 0x00004 /*%< pktinfo is valid */
-#define NS_CLIENTATTR_MULTICAST 0x00008 /*%< recv'd from multicast */
-#define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */
-#define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */
+#define NS_CLIENTATTR_TCP 0x000001
+#define NS_CLIENTATTR_RA 0x000002 /*%< Client gets recursive service */
+#define NS_CLIENTATTR_PKTINFO 0x000004 /*%< pktinfo is valid */
+#define NS_CLIENTATTR_MULTICAST 0x000008 /*%< recv'd from multicast */
+#define NS_CLIENTATTR_WANTDNSSEC 0x000010 /*%< include dnssec records */
+#define NS_CLIENTATTR_WANTNSID 0x000020 /*%< include nameserver ID */
#define NS_CLIENTATTR_BADCOOKIE \
- 0x00040 /*%< Presented cookie is bad/out-of-date */
-#define NS_CLIENTATTR_WANTRC 0x00080 /*%< include Report-Channel */
-#define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */
-#define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */
-#define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */
-#define NS_CLIENTATTR_WANTEXPIRE 0x00800 /*%< return seconds to expire */
-#define NS_CLIENTATTR_HAVEEXPIRE 0x01000 /*%< return seconds to expire */
-#define NS_CLIENTATTR_WANTOPT 0x02000 /*%< add opt to reply */
-#define NS_CLIENTATTR_HAVEECS 0x04000 /*%< received an ECS option */
-#define NS_CLIENTATTR_WANTPAD 0x08000 /*%< pad reply */
-#define NS_CLIENTATTR_USEKEEPALIVE 0x10000 /*%< use TCP keepalive */
-#define NS_CLIENTATTR_NOSETFC 0x20000 /*%< don't set servfail cache */
-#define NS_CLIENTATTR_NEEDTCP 0x40000 /*%< send TC=1 */
+ 0x000040 /*%< Presented cookie is bad/out-of-date */
+#define NS_CLIENTATTR_WANTRC 0x000080 /*%< include Report-Channel */
+#define NS_CLIENTATTR_WANTAD 0x000100 /*%< want AD in response if possible */
+#define NS_CLIENTATTR_WANTCOOKIE 0x000200 /*%< return a COOKIE */
+#define NS_CLIENTATTR_HAVECOOKIE 0x000400 /*%< has a valid COOKIE */
+#define NS_CLIENTATTR_WANTEXPIRE 0x000800 /*%< return seconds to expire */
+#define NS_CLIENTATTR_HAVEEXPIRE 0x001000 /*%< return seconds to expire */
+#define NS_CLIENTATTR_WANTOPT 0x002000 /*%< add opt to reply */
+#define NS_CLIENTATTR_HAVEECS 0x004000 /*%< received an ECS option */
+#define NS_CLIENTATTR_WANTPAD 0x008000 /*%< pad reply */
+#define NS_CLIENTATTR_USEKEEPALIVE 0x010000 /*%< use TCP keepalive */
+#define NS_CLIENTATTR_NOSETFC 0x020000 /*%< don't set servfail cache */
+#define NS_CLIENTATTR_NEEDTCP 0x040000 /*%< send TC=1 */
+#define NS_CLIENTATTR_WANTZONEVERSION 0x100000 /*%< return zoneversion */
+#define NS_CLIENTATTR_HAVEZONEVERSION 0x200000 /*%< return zoneversion */
/*
* Flag to use with the SERVFAIL cache to indicate
}
}
+/*
+ * Set the zone version, if requested, when answering from a secondary,
+ * mirror, or primary zone.
+ */
+static void
+query_getzoneversion(query_ctx_t *qctx) {
+ CCTRACE(ISC_LOG_DEBUG(3), __func__);
+
+ if (qctx->zone == NULL || !qctx->is_zone ||
+ qctx->client->query.restarts != 0 ||
+ (qctx->client->attributes & NS_CLIENTATTR_WANTZONEVERSION) == 0 ||
+ (qctx->client->attributes & NS_CLIENTATTR_HAVEZONEVERSION) != 0)
+ {
+ return;
+ }
+
+ switch (dns_zone_gettype(qctx->zone)) {
+ case dns_zone_mirror:
+ case dns_zone_primary:
+ case dns_zone_secondary: {
+ isc_buffer_t b;
+ unsigned char buf[128];
+ isc_buffer_init(&b, buf, sizeof(buf));
+ isc_result_t result = dns_zone_getzoneversion(qctx->zone, &b);
+ if (result == ISC_R_SUCCESS) {
+ size_t len = isc_buffer_usedlength(&b);
+ /*
+ * Sanity check zone version from database
+ * implementations. Minimum length and type 0
+ * contraints.
+ */
+ if (len < 2 || (buf[1] == 0 && len != 6)) {
+ return;
+ }
+ qctx->client->attributes |=
+ NS_CLIENTATTR_HAVEZONEVERSION;
+ INSIST(qctx->client->zoneversion == NULL);
+ qctx->client->zoneversion =
+ isc_mem_get(qctx->client->manager->mctx, len);
+ qctx->client->zoneversionlength = len;
+ memmove(qctx->client->zoneversion, buf, len);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
/*%
* Fill the ANSWER section of a positive response.
*/
*/
query_getexpire(qctx);
+ /*
+ * Set the zone version
+ */
+ query_getzoneversion(qctx);
+
result = query_addanswer(qctx);
if (result != ISC_R_COMPLETE) {
return result;