Home | History | Annotate | Line # | Download | only in ns
      1  1.25  christos /*	$NetBSD: query.c,v 1.26 2026/01/29 18:37:56 christos Exp $	*/
      2   1.1  christos 
      3   1.1  christos /*
      4   1.1  christos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5   1.1  christos  *
      6  1.15  christos  * SPDX-License-Identifier: MPL-2.0
      7  1.15  christos  *
      8   1.1  christos  * This Source Code Form is subject to the terms of the Mozilla Public
      9   1.1  christos  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  1.11  christos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11   1.1  christos  *
     12   1.1  christos  * See the COPYRIGHT file distributed with this work for additional
     13   1.1  christos  * information regarding copyright ownership.
     14   1.1  christos  */
     15   1.1  christos 
     16   1.1  christos /*! \file */
     17   1.1  christos 
     18  1.14  christos #include <ctype.h>
     19   1.3  christos #include <inttypes.h>
     20   1.3  christos #include <stdbool.h>
     21  1.23  christos #include <stdint.h>
     22   1.1  christos #include <string.h>
     23   1.1  christos 
     24  1.23  christos #include <isc/async.h>
     25  1.26  christos #include <isc/atomic.h>
     26  1.24  christos #include <isc/counter.h>
     27   1.1  christos #include <isc/hex.h>
     28   1.1  christos #include <isc/mem.h>
     29   1.9  christos #include <isc/once.h>
     30   1.1  christos #include <isc/random.h>
     31  1.20  christos #include <isc/result.h>
     32   1.1  christos #include <isc/rwlock.h>
     33   1.1  christos #include <isc/serial.h>
     34   1.1  christos #include <isc/stats.h>
     35   1.1  christos #include <isc/string.h>
     36   1.1  christos #include <isc/thread.h>
     37   1.1  christos #include <isc/util.h>
     38   1.1  christos 
     39   1.1  christos #include <dns/adb.h>
     40   1.1  christos #include <dns/badcache.h>
     41   1.1  christos #include <dns/byaddr.h>
     42   1.1  christos #include <dns/cache.h>
     43   1.1  christos #include <dns/db.h>
     44   1.1  christos #include <dns/dlz.h>
     45   1.1  christos #include <dns/dns64.h>
     46   1.1  christos #include <dns/dnsrps.h>
     47   1.1  christos #include <dns/dnssec.h>
     48  1.24  christos #include <dns/ede.h>
     49   1.1  christos #include <dns/keytable.h>
     50   1.1  christos #include <dns/message.h>
     51   1.1  christos #include <dns/ncache.h>
     52   1.1  christos #include <dns/nsec.h>
     53   1.1  christos #include <dns/nsec3.h>
     54   1.1  christos #include <dns/order.h>
     55  1.20  christos #include <dns/rbt.h>
     56  1.23  christos #include <dns/rcode.h>
     57   1.1  christos #include <dns/rdata.h>
     58   1.1  christos #include <dns/rdataclass.h>
     59   1.1  christos #include <dns/rdatalist.h>
     60   1.1  christos #include <dns/rdataset.h>
     61   1.1  christos #include <dns/rdatasetiter.h>
     62   1.1  christos #include <dns/rdatastruct.h>
     63   1.1  christos #include <dns/rdatatype.h>
     64   1.1  christos #include <dns/resolver.h>
     65   1.1  christos #include <dns/result.h>
     66   1.1  christos #include <dns/stats.h>
     67   1.1  christos #include <dns/tkey.h>
     68   1.1  christos #include <dns/types.h>
     69   1.1  christos #include <dns/view.h>
     70   1.1  christos #include <dns/zone.h>
     71   1.1  christos #include <dns/zt.h>
     72   1.1  christos 
     73   1.1  christos #include <ns/client.h>
     74   1.9  christos #include <ns/hooks.h>
     75   1.1  christos #include <ns/interfacemgr.h>
     76   1.1  christos #include <ns/log.h>
     77   1.1  christos #include <ns/server.h>
     78   1.1  christos #include <ns/sortlist.h>
     79   1.1  christos #include <ns/stats.h>
     80   1.1  christos #include <ns/xfrout.h>
     81   1.1  christos 
     82  1.23  christos #include "probes.h"
     83   1.7  christos 
     84   1.1  christos #if 0
     85   1.1  christos /*
     86   1.1  christos  * It has been recommended that DNS64 be changed to return excluded
     87   1.1  christos  * AAAA addresses if DNS64 synthesis does not occur.  This minimises
     88   1.1  christos  * the impact on the lookup results.  While most DNS AAAA lookups are
     89   1.1  christos  * done to send IP packets to a host, not all of them are and filtering
     90   1.1  christos  * excluded addresses has a negative impact on those uses.
     91   1.1  christos  */
     92   1.1  christos #define dns64_bis_return_excluded_addresses 1
     93   1.9  christos #endif /* if 0 */
     94   1.1  christos 
     95  1.11  christos #define QUERY_ERROR(qctx, r)                  \
     96  1.11  christos 	do {                                  \
     97  1.11  christos 		(qctx)->result = r;           \
     98  1.11  christos 		(qctx)->want_restart = false; \
     99  1.11  christos 		(qctx)->line = __LINE__;      \
    100  1.12    rillig 	} while (0)
    101   1.1  christos 
    102   1.1  christos /*% Partial answer? */
    103   1.9  christos #define PARTIALANSWER(c) \
    104   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_PARTIALANSWER) != 0)
    105   1.1  christos /*% Use Cache? */
    106   1.9  christos #define USECACHE(c) (((c)->query.attributes & NS_QUERYATTR_CACHEOK) != 0)
    107   1.1  christos /*% Recursion OK? */
    108   1.9  christos #define RECURSIONOK(c) (((c)->query.attributes & NS_QUERYATTR_RECURSIONOK) != 0)
    109   1.1  christos /*% Recursing? */
    110   1.9  christos #define RECURSING(c) (((c)->query.attributes & NS_QUERYATTR_RECURSING) != 0)
    111   1.1  christos /*% Want Recursion? */
    112   1.9  christos #define WANTRECURSION(c) \
    113   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_WANTRECURSION) != 0)
    114   1.1  christos /*% Is TCP? */
    115   1.9  christos #define TCP(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0)
    116   1.1  christos 
    117   1.1  christos /*% Want DNSSEC? */
    118   1.9  christos #define WANTDNSSEC(c) (((c)->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0)
    119   1.1  christos /*% Want WANTAD? */
    120   1.9  christos #define WANTAD(c) (((c)->attributes & NS_CLIENTATTR_WANTAD) != 0)
    121  1.23  christos /*% Client presented a bad COOKIE. */
    122  1.23  christos #define BADCOOKIE(c) (((c)->attributes & NS_CLIENTATTR_BADCOOKIE) != 0)
    123   1.1  christos /*% Client presented a valid COOKIE. */
    124   1.9  christos #define HAVECOOKIE(c) (((c)->attributes & NS_CLIENTATTR_HAVECOOKIE) != 0)
    125   1.1  christos /*% Client presented a COOKIE. */
    126   1.9  christos #define WANTCOOKIE(c) (((c)->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0)
    127   1.1  christos /*% Client presented a CLIENT-SUBNET option. */
    128   1.9  christos #define HAVEECS(c) (((c)->attributes & NS_CLIENTATTR_HAVEECS) != 0)
    129   1.1  christos /*% No authority? */
    130   1.9  christos #define NOAUTHORITY(c) (((c)->query.attributes & NS_QUERYATTR_NOAUTHORITY) != 0)
    131   1.1  christos /*% No additional? */
    132   1.9  christos #define NOADDITIONAL(c) \
    133   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_NOADDITIONAL) != 0)
    134   1.1  christos /*% Secure? */
    135   1.9  christos #define SECURE(c) (((c)->query.attributes & NS_QUERYATTR_SECURE) != 0)
    136   1.1  christos /*% DNS64 A lookup? */
    137   1.9  christos #define DNS64(c) (((c)->query.attributes & NS_QUERYATTR_DNS64) != 0)
    138   1.1  christos 
    139   1.9  christos #define DNS64EXCLUDE(c) \
    140   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_DNS64EXCLUDE) != 0)
    141   1.1  christos 
    142   1.9  christos #define REDIRECT(c) (((c)->query.attributes & NS_QUERYATTR_REDIRECT) != 0)
    143   1.1  christos 
    144  1.14  christos /*% Was the client already sent a response? */
    145  1.11  christos #define QUERY_ANSWERED(q) (((q)->attributes & NS_QUERYATTR_ANSWERED) != 0)
    146  1.11  christos 
    147  1.13  christos /*% Does the query wants to check for stale RRset due to a timeout? */
    148  1.13  christos #define QUERY_STALETIMEOUT(q) (((q)->dboptions & DNS_DBFIND_STALETIMEOUT) != 0)
    149  1.11  christos 
    150   1.1  christos /*% Does the rdataset 'r' have an attached 'No QNAME Proof'? */
    151   1.9  christos #define NOQNAME(r) (((r)->attributes & DNS_RDATASETATTR_NOQNAME) != 0)
    152   1.1  christos 
    153   1.4  christos /*% Does the rdataset 'r' contain a stale answer? */
    154   1.9  christos #define STALE(r) (((r)->attributes & DNS_RDATASETATTR_STALE) != 0)
    155   1.1  christos 
    156  1.11  christos /*% Does the rdataset 'r' is stale and within stale-refresh-time? */
    157  1.11  christos #define STALE_WINDOW(r) (((r)->attributes & DNS_RDATASETATTR_STALE_WINDOW) != 0)
    158  1.11  christos 
    159   1.1  christos #ifdef WANT_QUERYTRACE
    160  1.15  christos static void
    161   1.1  christos client_trace(ns_client_t *client, int level, const char *message) {
    162   1.1  christos 	if (client != NULL && client->query.qname != NULL) {
    163   1.1  christos 		if (isc_log_wouldlog(ns_lctx, level)) {
    164   1.1  christos 			char qbuf[DNS_NAME_FORMATSIZE];
    165   1.1  christos 			char tbuf[DNS_RDATATYPE_FORMATSIZE];
    166   1.9  christos 			dns_name_format(client->query.qname, qbuf,
    167   1.9  christos 					sizeof(qbuf));
    168   1.9  christos 			dns_rdatatype_format(client->query.qtype, tbuf,
    169   1.9  christos 					     sizeof(tbuf));
    170   1.9  christos 			isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT,
    171   1.1  christos 				      NS_LOGMODULE_QUERY, level,
    172  1.13  christos 				      "query client=%p thread=0x%" PRIxPTR
    173   1.1  christos 				      "(%s/%s): %s",
    174  1.13  christos 				      client, isc_thread_self(), qbuf, tbuf,
    175  1.13  christos 				      message);
    176   1.1  christos 		}
    177   1.9  christos 	} else {
    178   1.9  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT,
    179   1.1  christos 			      NS_LOGMODULE_QUERY, level,
    180  1.13  christos 			      "query client=%p thread=0x%" PRIxPTR
    181   1.1  christos 			      "(<unknown-query>): %s",
    182  1.13  christos 			      client, isc_thread_self(), message);
    183   1.1  christos 	}
    184   1.1  christos }
    185   1.9  christos #define CTRACE(l, m)  client_trace(client, l, m)
    186   1.9  christos #define CCTRACE(l, m) client_trace(qctx->client, l, m)
    187   1.9  christos #else /* ifdef WANT_QUERYTRACE */
    188   1.9  christos #define CTRACE(l, m)  ((void)m)
    189   1.9  christos #define CCTRACE(l, m) ((void)m)
    190   1.1  christos #endif /* WANT_QUERYTRACE */
    191   1.1  christos 
    192  1.20  christos #define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0)
    193   1.1  christos 
    194   1.1  christos #define SFCACHE_CDFLAG 0x1
    195   1.1  christos 
    196   1.1  christos /*
    197  1.20  christos  * SAVE and RESTORE have the same semantics as:
    198   1.1  christos  *
    199  1.20  christos  * 	foo_attach(b, &a);
    200  1.20  christos  *	foo_detach(&b);
    201   1.1  christos  *
    202   1.1  christos  * without the locking and magic testing.
    203   1.1  christos  *
    204  1.20  christos  * We use the names SAVE and RESTORE to show the operation being performed,
    205  1.20  christos  * even though the two macros are identical.
    206   1.1  christos  */
    207   1.9  christos #define SAVE(a, b)                 \
    208   1.9  christos 	do {                       \
    209   1.9  christos 		INSIST(a == NULL); \
    210   1.9  christos 		a = b;             \
    211   1.9  christos 		b = NULL;          \
    212  1.12    rillig 	} while (0)
    213   1.1  christos #define RESTORE(a, b) SAVE(a, b)
    214   1.1  christos 
    215  1.26  christos static atomic_uint_fast32_t last_rpznotready_log = 0;
    216  1.26  christos 
    217  1.26  christos static bool
    218  1.26  christos can_log_rpznotready(void) {
    219  1.26  christos 	isc_stdtime_t last;
    220  1.26  christos 	isc_stdtime_t now = isc_stdtime_now();
    221  1.26  christos 	last = atomic_exchange_relaxed(&last_rpznotready_log, now);
    222  1.26  christos 	if (now != last) {
    223  1.26  christos 		return true;
    224  1.26  christos 	}
    225  1.26  christos 
    226  1.26  christos 	return false;
    227  1.26  christos }
    228  1.26  christos 
    229   1.3  christos static bool
    230   1.1  christos validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
    231   1.1  christos 	 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
    232   1.1  christos 
    233   1.1  christos static void
    234   1.1  christos query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
    235   1.1  christos 		       dns_dbversion_t *version, ns_client_t *client,
    236   1.1  christos 		       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
    237   1.9  christos 		       dns_name_t *fname, bool exact, dns_name_t *found);
    238   1.1  christos 
    239  1.15  christos static void
    240   1.1  christos log_queryerror(ns_client_t *client, isc_result_t result, int line, int level);
    241   1.1  christos 
    242   1.1  christos static void
    243   1.1  christos rpz_st_clear(ns_client_t *client);
    244   1.1  christos 
    245   1.3  christos static bool
    246   1.1  christos rpz_ck_dnssec(ns_client_t *client, isc_result_t qresult,
    247   1.1  christos 	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
    248   1.1  christos 
    249   1.1  christos static void
    250   1.1  christos log_noexistnodata(void *val, int level, const char *fmt, ...)
    251   1.1  christos 	ISC_FORMAT_PRINTF(3, 4);
    252   1.1  christos 
    253  1.20  christos static isc_result_t
    254  1.20  christos query_addanswer(query_ctx_t *qctx);
    255  1.20  christos 
    256  1.20  christos static isc_result_t
    257  1.20  christos query_prepare_delegation_response(query_ctx_t *qctx);
    258  1.20  christos 
    259  1.23  christos static isc_result_t
    260  1.23  christos acquire_recursionquota(ns_client_t *client);
    261  1.23  christos 
    262  1.23  christos static void
    263  1.23  christos release_recursionquota(ns_client_t *client);
    264  1.23  christos 
    265   1.3  christos /*
    266   1.3  christos  * Return the hooktable in use with 'qctx', or if there isn't one
    267   1.3  christos  * set, return the default hooktable.
    268   1.3  christos  */
    269  1.15  christos static ns_hooktable_t *
    270   1.3  christos get_hooktab(query_ctx_t *qctx) {
    271   1.9  christos 	if (qctx == NULL || qctx->view == NULL || qctx->view->hooktable == NULL)
    272   1.3  christos 	{
    273  1.23  christos 		return ns__hook_table;
    274   1.3  christos 	}
    275   1.1  christos 
    276  1.23  christos 	return qctx->view->hooktable;
    277   1.3  christos }
    278   1.1  christos 
    279   1.3  christos /*
    280   1.3  christos  * Call the specified hook function in every configured module that implements
    281   1.3  christos  * that function. If any hook function returns NS_HOOK_RETURN, we
    282   1.3  christos  * set 'result' and terminate processing by jumping to the 'cleanup' tag.
    283   1.3  christos  *
    284   1.3  christos  * (Note that a hook function may set the 'result' to ISC_R_SUCCESS but
    285   1.3  christos  * still terminate processing within the calling function. That's why this
    286  1.15  christos  * is a macro instead of a static function; it needs to be able to use
    287   1.3  christos  * 'goto cleanup' regardless of the return value.)
    288   1.3  christos  */
    289   1.9  christos #define CALL_HOOK(_id, _qctx)                                       \
    290   1.9  christos 	do {                                                        \
    291  1.20  christos 		isc_result_t _res = result;                         \
    292   1.9  christos 		ns_hooktable_t *_tab = get_hooktab(_qctx);          \
    293   1.9  christos 		ns_hook_t *_hook;                                   \
    294   1.9  christos 		_hook = ISC_LIST_HEAD((*_tab)[_id]);                \
    295   1.9  christos 		while (_hook != NULL) {                             \
    296   1.9  christos 			ns_hook_action_t _func = _hook->action;     \
    297   1.9  christos 			void *_data = _hook->action_data;           \
    298   1.9  christos 			INSIST(_func != NULL);                      \
    299   1.9  christos 			switch (_func(_qctx, _data, &_res)) {       \
    300   1.9  christos 			case NS_HOOK_CONTINUE:                      \
    301   1.9  christos 				_hook = ISC_LIST_NEXT(_hook, link); \
    302   1.9  christos 				break;                              \
    303   1.9  christos 			case NS_HOOK_RETURN:                        \
    304   1.9  christos 				result = _res;                      \
    305   1.9  christos 				goto cleanup;                       \
    306   1.9  christos 			default:                                    \
    307  1.15  christos 				UNREACHABLE();                      \
    308   1.9  christos 			}                                           \
    309   1.9  christos 		}                                                   \
    310   1.3  christos 	} while (false)
    311   1.1  christos 
    312   1.3  christos /*
    313   1.3  christos  * Call the specified hook function in every configured module that
    314   1.3  christos  * implements that function. All modules are called; hook function return
    315   1.3  christos  * codes are ignored. This is intended for use with initialization and
    316   1.3  christos  * destruction calls which *must* run in every configured module.
    317   1.3  christos  *
    318  1.15  christos  * (This could be implemented as a static void function, but is left as a
    319   1.3  christos  * macro for symmetry with CALL_HOOK above.)
    320   1.3  christos  */
    321   1.9  christos #define CALL_HOOK_NORETURN(_id, _qctx)                          \
    322   1.9  christos 	do {                                                    \
    323   1.9  christos 		isc_result_t _res;                              \
    324   1.9  christos 		ns_hooktable_t *_tab = get_hooktab(_qctx);      \
    325   1.9  christos 		ns_hook_t *_hook;                               \
    326   1.9  christos 		_hook = ISC_LIST_HEAD((*_tab)[_id]);            \
    327   1.9  christos 		while (_hook != NULL) {                         \
    328   1.9  christos 			ns_hook_action_t _func = _hook->action; \
    329   1.9  christos 			void *_data = _hook->action_data;       \
    330   1.9  christos 			INSIST(_func != NULL);                  \
    331   1.9  christos 			_func(_qctx, _data, &_res);             \
    332   1.9  christos 			_hook = ISC_LIST_NEXT(_hook, link);     \
    333   1.9  christos 		}                                               \
    334   1.3  christos 	} while (false)
    335   1.1  christos 
    336   1.1  christos /*
    337   1.1  christos  * The functions defined below implement the query logic that previously lived
    338   1.1  christos  * in the single very complex function query_find().  The query_ctx_t structure
    339   1.1  christos  * defined in <ns/query.h> maintains state from function to function.  The call
    340   1.1  christos  * flow for the general query processing algorithm is described below:
    341   1.1  christos  *
    342   1.1  christos  * 1. Set up query context and other resources for a client
    343   1.1  christos  *    query (query_setup())
    344   1.1  christos  *
    345   1.1  christos  * 2. Start the search (ns__query_start())
    346   1.1  christos  *
    347   1.1  christos  * 3. Identify authoritative data sources which may have an answer;
    348   1.1  christos  *    search them (query_lookup()). If an answer is found, go to 7.
    349   1.1  christos  *
    350   1.1  christos  * 4. If recursion or cache access are allowed, search the cache
    351   1.1  christos  *    (query_lookup() again, using the cache database) to find a better
    352   1.1  christos  *    answer. If an answer is found, go to 7.
    353   1.1  christos  *
    354   1.3  christos  * 5. If recursion is allowed, begin recursion (ns_query_recurse()).
    355   1.1  christos  *    Go to 15 to clean up this phase of the query. When recursion
    356   1.1  christos  *    is complete, processing will resume at 6.
    357   1.1  christos  *
    358   1.1  christos  * 6. Resume from recursion; set up query context for resumed processing.
    359   1.1  christos  *
    360   1.1  christos  * 7. Determine what sort of answer we've found (query_gotanswer())
    361   1.1  christos  *    and call other functions accordingly:
    362   1.1  christos  *      - not found (auth or cache), go to 8
    363   1.1  christos  *      - delegation, go to 9
    364   1.1  christos  *      - no such domain (auth), go to 10
    365   1.1  christos  *      - empty answer (auth), go to 11
    366   1.1  christos  *      - negative response (cache), go to 12
    367   1.1  christos  *      - answer found, go to 13
    368   1.1  christos  *
    369   1.1  christos  * 8. The answer was not found in the database (query_notfound().
    370   1.1  christos  *    Set up a referral and go to 9.
    371   1.1  christos  *
    372   1.3  christos  * 9. Handle a delegation response (query_delegation()). If we need
    373   1.3  christos  *    to and are allowed to recurse (query_delegation_recurse()), go to 5,
    374   1.3  christos  *    otherwise go to 15 to clean up and return the delegation to the client.
    375   1.1  christos  *
    376   1.1  christos  * 10. No such domain (query_nxdomain()). Attempt redirection; if
    377   1.1  christos  *     unsuccessful, add authority section records (query_addsoa(),
    378   1.1  christos  *     query_addauth()), then go to 15 to return NXDOMAIN to client.
    379   1.1  christos  *
    380   1.1  christos  * 11. Empty answer (query_nodata()). Add authority section records
    381   1.1  christos  *     (query_addsoa(), query_addauth()) and signatures if authoritative
    382   1.1  christos  *     (query_sign_nodata()) then go to 15 and return
    383   1.1  christos  *     NOERROR/ANCOUNT=0 to client.
    384   1.1  christos  *
    385   1.1  christos  * 12. No such domain or empty answer returned from cache (query_ncache()).
    386   1.1  christos  *     Set response code appropriately, go to 11.
    387   1.1  christos  *
    388   1.1  christos  * 13. Prepare a response (query_prepresponse()) and then fill it
    389   1.1  christos  *     appropriately (query_respond(), or for type ANY,
    390   1.1  christos  *     query_respond_any()).
    391   1.1  christos  *
    392   1.1  christos  * 14. If a restart is needed due to CNAME/DNAME chaining, go to 2.
    393   1.1  christos  *
    394   1.1  christos  * 15. Clean up resources. If recursing, stop and wait for the event
    395   1.1  christos  *     handler to be called back (step 6).  If an answer is ready,
    396   1.1  christos  *     return it to the client.
    397   1.1  christos  *
    398   1.1  christos  * (XXX: This description omits several special cases including
    399   1.3  christos  * DNS64, RPZ, RRL, and the SERVFAIL cache. It also doesn't discuss
    400   1.3  christos  * plugins.)
    401   1.1  christos  */
    402   1.1  christos 
    403   1.1  christos static void
    404   1.1  christos query_trace(query_ctx_t *qctx);
    405   1.1  christos 
    406   1.1  christos static void
    407  1.23  christos qctx_init(ns_client_t *client, dns_fetchresponse_t **respp,
    408  1.23  christos 	  dns_rdatatype_t qtype, query_ctx_t *qctx);
    409   1.1  christos 
    410   1.1  christos static isc_result_t
    411  1.23  christos qctx_prepare_buffers(query_ctx_t *qctx, isc_buffer_t *buffer);
    412  1.23  christos 
    413  1.23  christos static void
    414  1.23  christos qctx_freedata(query_ctx_t *qctx);
    415  1.23  christos 
    416  1.23  christos static void
    417  1.23  christos qctx_destroy(query_ctx_t *qctx);
    418  1.23  christos 
    419  1.23  christos static void
    420   1.1  christos query_setup(ns_client_t *client, dns_rdatatype_t qtype);
    421   1.1  christos 
    422   1.1  christos static isc_result_t
    423   1.1  christos query_lookup(query_ctx_t *qctx);
    424   1.1  christos 
    425   1.1  christos static void
    426  1.23  christos fetch_callback(void *arg);
    427   1.1  christos 
    428   1.1  christos static void
    429   1.1  christos recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
    430   1.1  christos 		const dns_name_t *qname, const dns_name_t *qdomain);
    431   1.1  christos 
    432   1.1  christos static isc_result_t
    433   1.1  christos query_resume(query_ctx_t *qctx);
    434   1.1  christos 
    435   1.1  christos static isc_result_t
    436   1.1  christos query_checkrrl(query_ctx_t *qctx, isc_result_t result);
    437   1.1  christos 
    438   1.1  christos static isc_result_t
    439   1.1  christos query_checkrpz(query_ctx_t *qctx, isc_result_t result);
    440   1.1  christos 
    441   1.1  christos static isc_result_t
    442   1.1  christos query_rpzcname(query_ctx_t *qctx, dns_name_t *cname);
    443   1.1  christos 
    444   1.1  christos static isc_result_t
    445   1.1  christos query_gotanswer(query_ctx_t *qctx, isc_result_t result);
    446   1.1  christos 
    447   1.1  christos static void
    448   1.1  christos query_addnoqnameproof(query_ctx_t *qctx);
    449   1.1  christos 
    450   1.1  christos static isc_result_t
    451   1.1  christos query_respond_any(query_ctx_t *qctx);
    452   1.1  christos 
    453   1.1  christos static isc_result_t
    454   1.1  christos query_respond(query_ctx_t *qctx);
    455   1.1  christos 
    456   1.1  christos static isc_result_t
    457   1.1  christos query_dns64(query_ctx_t *qctx);
    458   1.1  christos 
    459   1.1  christos static void
    460   1.1  christos query_filter64(query_ctx_t *qctx);
    461   1.1  christos 
    462   1.1  christos static isc_result_t
    463   1.1  christos query_notfound(query_ctx_t *qctx);
    464   1.1  christos 
    465   1.1  christos static isc_result_t
    466   1.1  christos query_zone_delegation(query_ctx_t *qctx);
    467   1.1  christos 
    468   1.1  christos static isc_result_t
    469   1.1  christos query_delegation(query_ctx_t *qctx);
    470   1.1  christos 
    471   1.3  christos static isc_result_t
    472   1.3  christos query_delegation_recurse(query_ctx_t *qctx);
    473   1.3  christos 
    474   1.1  christos static void
    475   1.1  christos query_addds(query_ctx_t *qctx);
    476   1.1  christos 
    477   1.1  christos static isc_result_t
    478   1.1  christos query_nodata(query_ctx_t *qctx, isc_result_t result);
    479   1.1  christos 
    480   1.1  christos static isc_result_t
    481   1.1  christos query_sign_nodata(query_ctx_t *qctx);
    482   1.1  christos 
    483   1.1  christos static void
    484   1.1  christos query_addnxrrsetnsec(query_ctx_t *qctx);
    485   1.1  christos 
    486   1.1  christos static isc_result_t
    487  1.18  christos query_nxdomain(query_ctx_t *qctx, isc_result_t result);
    488   1.1  christos 
    489   1.1  christos static isc_result_t
    490  1.18  christos query_redirect(query_ctx_t *qctx, isc_result_t result);
    491   1.1  christos 
    492   1.1  christos static isc_result_t
    493   1.1  christos query_ncache(query_ctx_t *qctx, isc_result_t result);
    494   1.1  christos 
    495   1.1  christos static isc_result_t
    496   1.1  christos query_coveringnsec(query_ctx_t *qctx);
    497   1.1  christos 
    498   1.1  christos static isc_result_t
    499   1.3  christos query_zerottl_refetch(query_ctx_t *qctx);
    500   1.3  christos 
    501   1.3  christos static isc_result_t
    502   1.1  christos query_cname(query_ctx_t *qctx);
    503   1.1  christos 
    504   1.1  christos static isc_result_t
    505   1.1  christos query_dname(query_ctx_t *qctx);
    506   1.1  christos 
    507  1.23  christos static void
    508   1.1  christos query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl);
    509   1.1  christos 
    510   1.1  christos static isc_result_t
    511   1.1  christos query_prepresponse(query_ctx_t *qctx);
    512   1.1  christos 
    513   1.1  christos static isc_result_t
    514   1.1  christos query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
    515   1.1  christos 	     dns_section_t section);
    516   1.1  christos 
    517   1.1  christos static isc_result_t
    518   1.1  christos query_addns(query_ctx_t *qctx);
    519   1.1  christos 
    520   1.1  christos static void
    521   1.1  christos query_addbestns(query_ctx_t *qctx);
    522   1.1  christos 
    523   1.1  christos static void
    524   1.3  christos query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata);
    525   1.1  christos 
    526   1.1  christos static void
    527   1.1  christos query_addauth(query_ctx_t *qctx);
    528   1.1  christos 
    529   1.3  christos /*
    530   1.1  christos  * Increment query statistics counters.
    531   1.1  christos  */
    532  1.15  christos static void
    533   1.1  christos inc_stats(ns_client_t *client, isc_statscounter_t counter) {
    534   1.1  christos 	dns_zone_t *zone = client->query.authzone;
    535   1.1  christos 	dns_rdatatype_t qtype;
    536   1.1  christos 	dns_rdataset_t *rdataset;
    537   1.1  christos 	isc_stats_t *zonestats;
    538   1.1  christos 	dns_stats_t *querystats = NULL;
    539   1.1  christos 
    540  1.23  christos 	ns_stats_increment(client->manager->sctx->nsstats, counter);
    541   1.1  christos 
    542   1.9  christos 	if (zone == NULL) {
    543   1.1  christos 		return;
    544   1.9  christos 	}
    545   1.1  christos 
    546   1.1  christos 	/* Do regular response type stats */
    547   1.1  christos 	zonestats = dns_zone_getrequeststats(zone);
    548   1.1  christos 
    549   1.9  christos 	if (zonestats != NULL) {
    550   1.1  christos 		isc_stats_increment(zonestats, counter);
    551   1.9  christos 	}
    552   1.1  christos 
    553   1.1  christos 	/* Do query type statistics
    554   1.1  christos 	 *
    555   1.1  christos 	 * We only increment per-type if we're using the authoritative
    556   1.1  christos 	 * answer counter, preventing double-counting.
    557   1.1  christos 	 */
    558   1.1  christos 	if (counter == ns_statscounter_authans) {
    559   1.1  christos 		querystats = dns_zone_getrcvquerystats(zone);
    560   1.1  christos 		if (querystats != NULL) {
    561   1.1  christos 			rdataset = ISC_LIST_HEAD(client->query.qname->list);
    562   1.1  christos 			if (rdataset != NULL) {
    563   1.1  christos 				qtype = rdataset->type;
    564   1.1  christos 				dns_rdatatypestats_increment(querystats, qtype);
    565   1.1  christos 			}
    566   1.1  christos 		}
    567   1.1  christos 	}
    568   1.1  christos }
    569   1.1  christos 
    570  1.23  christos #define NS_CLIENT_FLAGS_FORMATSIZE sizeof("+E(255)STDCV")
    571  1.23  christos 
    572  1.23  christos static inline void
    573  1.23  christos ns_client_log_flags(ns_client_t *client, unsigned int flags,
    574  1.23  christos 		    unsigned int extflags, char *buf, size_t len) {
    575  1.23  christos 	isc_buffer_t b;
    576  1.23  christos 
    577  1.23  christos 	isc_buffer_init(&b, buf, len);
    578  1.23  christos 	isc_buffer_putuint8(&b, WANTRECURSION(client) ? '+' : '-');
    579  1.23  christos 	if (client->ednsversion >= 0) {
    580  1.23  christos 		char ednsbuf[sizeof("E(255)")] = { 0 };
    581  1.23  christos 
    582  1.23  christos 		snprintf(ednsbuf, sizeof(ednsbuf), "E(%hhu)",
    583  1.23  christos 			 (unsigned char)client->ednsversion);
    584  1.23  christos 		isc_buffer_putstr(&b, ednsbuf);
    585  1.23  christos 	}
    586  1.23  christos 	if (client->signer != NULL) {
    587  1.23  christos 		isc_buffer_putuint8(&b, 'S');
    588  1.23  christos 	}
    589  1.23  christos 	if (TCP(client)) {
    590  1.23  christos 		isc_buffer_putuint8(&b, 'T');
    591  1.23  christos 	}
    592  1.23  christos 	if ((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) {
    593  1.23  christos 		isc_buffer_putuint8(&b, 'D');
    594  1.23  christos 	}
    595  1.23  christos 	if ((flags & DNS_MESSAGEFLAG_CD) != 0) {
    596  1.23  christos 		isc_buffer_putuint8(&b, 'C');
    597  1.23  christos 	}
    598  1.23  christos 	if (HAVECOOKIE(client)) {
    599  1.23  christos 		isc_buffer_putuint8(&b, 'V');
    600  1.23  christos 	} else if (WANTCOOKIE(client)) {
    601  1.23  christos 		isc_buffer_putuint8(&b, 'K');
    602  1.23  christos 	}
    603  1.23  christos 	isc_buffer_putuint8(&b, 0);
    604  1.23  christos }
    605  1.23  christos 
    606  1.23  christos #define NS_CLIENT_ECS_FORMATSIZE (DNS_ECS_FORMATSIZE + sizeof(" [ECS ]") - 1)
    607  1.23  christos 
    608  1.23  christos static inline void
    609  1.23  christos ns_client_log_ecs(ns_client_t *client, char *ecsbuf, size_t len) {
    610  1.23  christos 	strlcpy(ecsbuf, " [ECS ", len);
    611  1.23  christos 	dns_ecs_format(&client->ecs, ecsbuf + 6, len - 6);
    612  1.23  christos 	strlcat(ecsbuf, "]", len);
    613  1.23  christos }
    614  1.23  christos 
    615  1.23  christos static inline void
    616  1.23  christos log_response(ns_client_t *client, dns_rcode_t rcode) {
    617  1.23  christos 	char namebuf[DNS_NAME_FORMATSIZE];
    618  1.23  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
    619  1.23  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
    620  1.23  christos 	char rcodebuf[20];
    621  1.23  christos 	char onbuf[ISC_NETADDR_FORMATSIZE];
    622  1.23  christos 	char ecsbuf[NS_CLIENT_ECS_FORMATSIZE] = { 0 };
    623  1.23  christos 	char flagsbuf[NS_CLIENT_FLAGS_FORMATSIZE] = { 0 };
    624  1.23  christos 	isc_buffer_t b;
    625  1.23  christos 	int level = ISC_LOG_INFO;
    626  1.23  christos 
    627  1.23  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
    628  1.23  christos 		return;
    629  1.23  christos 	}
    630  1.23  christos 
    631  1.23  christos 	dns_name_format(client->query.origqname, namebuf, sizeof(namebuf));
    632  1.23  christos 	dns_rdataclass_format(client->message->rdclass, classbuf,
    633  1.23  christos 			      sizeof(classbuf));
    634  1.23  christos 	dns_rdatatype_format(client->query.qtype, typebuf, sizeof(typebuf));
    635  1.23  christos 	isc_buffer_init(&b, rcodebuf, sizeof(rcodebuf));
    636  1.23  christos 	dns_rcode_totext(rcode, &b);
    637  1.23  christos 	isc_buffer_putuint8(&b, 0);
    638  1.23  christos 	isc_netaddr_format(&client->destaddr, onbuf, sizeof(onbuf));
    639  1.23  christos 
    640  1.23  christos 	if (HAVEECS(client)) {
    641  1.23  christos 		ns_client_log_ecs(client, ecsbuf, sizeof(ecsbuf));
    642  1.23  christos 	}
    643  1.23  christos 
    644  1.23  christos 	ns_client_log_flags(client, client->message->flags, client->extflags,
    645  1.23  christos 			    flagsbuf, sizeof(flagsbuf));
    646  1.23  christos 	ns_client_log(client, NS_LOGCATEGORY_RESPONSES, NS_LOGMODULE_QUERY,
    647  1.23  christos 		      level, "response: %s %s %s %s %u %u %u %s (%s)%s",
    648  1.23  christos 		      namebuf, classbuf, typebuf, rcodebuf,
    649  1.23  christos 		      client->message->counts[DNS_SECTION_ANSWER],
    650  1.23  christos 		      client->message->counts[DNS_SECTION_AUTHORITY],
    651  1.23  christos 		      client->message->counts[DNS_SECTION_ADDITIONAL], flagsbuf,
    652  1.23  christos 		      onbuf, ecsbuf);
    653  1.23  christos }
    654  1.23  christos 
    655   1.1  christos static void
    656   1.1  christos query_send(ns_client_t *client) {
    657   1.1  christos 	isc_statscounter_t counter;
    658   1.1  christos 
    659   1.9  christos 	if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0) {
    660   1.1  christos 		inc_stats(client, ns_statscounter_nonauthans);
    661   1.9  christos 	} else {
    662   1.1  christos 		inc_stats(client, ns_statscounter_authans);
    663   1.9  christos 	}
    664   1.1  christos 
    665   1.1  christos 	if (client->message->rcode == dns_rcode_noerror) {
    666   1.1  christos 		dns_section_t answer = DNS_SECTION_ANSWER;
    667   1.1  christos 		if (ISC_LIST_EMPTY(client->message->sections[answer])) {
    668   1.9  christos 			if (client->query.isreferral) {
    669   1.1  christos 				counter = ns_statscounter_referral;
    670   1.9  christos 			} else {
    671   1.1  christos 				counter = ns_statscounter_nxrrset;
    672   1.9  christos 			}
    673   1.9  christos 		} else {
    674   1.1  christos 			counter = ns_statscounter_success;
    675   1.9  christos 		}
    676   1.9  christos 	} else if (client->message->rcode == dns_rcode_nxdomain) {
    677   1.1  christos 		counter = ns_statscounter_nxdomain;
    678   1.9  christos 	} else if (client->message->rcode == dns_rcode_badcookie) {
    679   1.1  christos 		counter = ns_statscounter_badcookie;
    680   1.9  christos 	} else { /* We end up here in case of YXDOMAIN, and maybe others */
    681   1.1  christos 		counter = ns_statscounter_failure;
    682   1.9  christos 	}
    683   1.1  christos 
    684   1.1  christos 	inc_stats(client, counter);
    685   1.1  christos 	ns_client_send(client);
    686  1.11  christos 
    687  1.23  christos 	if ((client->manager->sctx->options & NS_SERVER_LOGRESPONSES) != 0) {
    688  1.23  christos 		log_response(client, client->message->rcode);
    689  1.11  christos 	}
    690  1.23  christos 
    691  1.23  christos 	isc_nmhandle_detach(&client->reqhandle);
    692   1.1  christos }
    693   1.1  christos 
    694   1.1  christos static void
    695   1.1  christos query_error(ns_client_t *client, isc_result_t result, int line) {
    696   1.1  christos 	int loglevel = ISC_LOG_DEBUG(3);
    697  1.23  christos 	dns_rcode_t rcode;
    698   1.1  christos 
    699  1.23  christos 	rcode = dns_result_torcode(result);
    700  1.23  christos 	switch (rcode) {
    701   1.3  christos 	case dns_rcode_servfail:
    702   1.1  christos 		loglevel = ISC_LOG_DEBUG(1);
    703   1.1  christos 		inc_stats(client, ns_statscounter_servfail);
    704   1.1  christos 		break;
    705   1.3  christos 	case dns_rcode_formerr:
    706   1.1  christos 		inc_stats(client, ns_statscounter_formerr);
    707   1.1  christos 		break;
    708   1.1  christos 	default:
    709   1.1  christos 		inc_stats(client, ns_statscounter_failure);
    710   1.1  christos 		break;
    711   1.1  christos 	}
    712   1.1  christos 
    713  1.23  christos 	if ((client->manager->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
    714   1.1  christos 		loglevel = ISC_LOG_INFO;
    715   1.9  christos 	}
    716   1.1  christos 
    717   1.1  christos 	log_queryerror(client, result, line, loglevel);
    718   1.1  christos 
    719   1.1  christos 	ns_client_error(client, result);
    720  1.11  christos 
    721  1.23  christos 	if (client->query.origqname != NULL &&
    722  1.23  christos 	    (client->manager->sctx->options & NS_SERVER_LOGRESPONSES) != 0)
    723  1.23  christos 	{
    724  1.23  christos 		log_response(client, rcode);
    725  1.11  christos 	}
    726  1.23  christos 
    727  1.23  christos 	isc_nmhandle_detach(&client->reqhandle);
    728   1.1  christos }
    729   1.1  christos 
    730   1.1  christos static void
    731   1.1  christos query_next(ns_client_t *client, isc_result_t result) {
    732   1.9  christos 	if (result == DNS_R_DUPLICATE) {
    733   1.1  christos 		inc_stats(client, ns_statscounter_duplicate);
    734   1.9  christos 	} else if (result == DNS_R_DROP) {
    735   1.1  christos 		inc_stats(client, ns_statscounter_dropped);
    736   1.9  christos 	} else {
    737   1.1  christos 		inc_stats(client, ns_statscounter_failure);
    738   1.9  christos 	}
    739   1.9  christos 	ns_client_drop(client, result);
    740  1.23  christos 	isc_nmhandle_detach(&client->reqhandle);
    741   1.1  christos }
    742   1.1  christos 
    743  1.15  christos static void
    744   1.3  christos query_freefreeversions(ns_client_t *client, bool everything) {
    745   1.1  christos 	ns_dbversion_t *dbversion, *dbversion_next;
    746   1.1  christos 	unsigned int i;
    747   1.1  christos 
    748   1.1  christos 	for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
    749   1.9  christos 	     dbversion != NULL; dbversion = dbversion_next, i++)
    750   1.1  christos 	{
    751   1.1  christos 		dbversion_next = ISC_LIST_NEXT(dbversion, link);
    752   1.1  christos 		/*
    753   1.1  christos 		 * If we're not freeing everything, we keep the first three
    754   1.1  christos 		 * dbversions structures around.
    755   1.1  christos 		 */
    756   1.1  christos 		if (i > 3 || everything) {
    757   1.1  christos 			ISC_LIST_UNLINK(client->query.freeversions, dbversion,
    758   1.1  christos 					link);
    759  1.23  christos 			isc_mem_put(client->manager->mctx, dbversion,
    760   1.1  christos 				    sizeof(*dbversion));
    761   1.1  christos 		}
    762   1.1  christos 	}
    763   1.1  christos }
    764   1.1  christos 
    765   1.1  christos void
    766   1.1  christos ns_query_cancel(ns_client_t *client) {
    767   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
    768   1.1  christos 
    769   1.1  christos 	LOCK(&client->query.fetchlock);
    770  1.23  christos 	for (int i = 0; i < RECTYPE_COUNT; i++) {
    771  1.23  christos 		dns_fetch_t **fetchp = &client->query.recursions[i].fetch;
    772  1.23  christos 		if (*fetchp != NULL) {
    773  1.23  christos 			dns_resolver_cancelfetch(*fetchp);
    774  1.23  christos 			*fetchp = NULL;
    775  1.23  christos 		}
    776   1.1  christos 	}
    777  1.20  christos 	if (client->query.hookactx != NULL) {
    778  1.20  christos 		client->query.hookactx->cancel(client->query.hookactx);
    779  1.20  christos 		client->query.hookactx = NULL;
    780  1.20  christos 	}
    781   1.1  christos 	UNLOCK(&client->query.fetchlock);
    782   1.1  christos }
    783   1.1  christos 
    784  1.15  christos static void
    785   1.3  christos query_reset(ns_client_t *client, bool everything) {
    786   1.1  christos 	isc_buffer_t *dbuf, *dbuf_next;
    787   1.1  christos 	ns_dbversion_t *dbversion, *dbversion_next;
    788   1.1  christos 
    789   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_reset");
    790   1.1  christos 
    791   1.1  christos 	/*%
    792   1.1  christos 	 * Reset the query state of a client to its default state.
    793   1.1  christos 	 */
    794   1.1  christos 
    795   1.1  christos 	/*
    796   1.1  christos 	 * Cancel the fetch if it's running.
    797   1.1  christos 	 */
    798   1.1  christos 	ns_query_cancel(client);
    799   1.1  christos 
    800   1.1  christos 	/*
    801   1.1  christos 	 * Cleanup any active versions.
    802   1.1  christos 	 */
    803   1.1  christos 	for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
    804   1.9  christos 	     dbversion != NULL; dbversion = dbversion_next)
    805   1.9  christos 	{
    806   1.1  christos 		dbversion_next = ISC_LIST_NEXT(dbversion, link);
    807   1.9  christos 		dns_db_closeversion(dbversion->db, &dbversion->version, false);
    808   1.1  christos 		dns_db_detach(&dbversion->db);
    809   1.9  christos 		ISC_LIST_INITANDAPPEND(client->query.freeversions, dbversion,
    810   1.9  christos 				       link);
    811   1.1  christos 	}
    812   1.1  christos 	ISC_LIST_INIT(client->query.activeversions);
    813   1.1  christos 
    814   1.9  christos 	if (client->query.authdb != NULL) {
    815   1.1  christos 		dns_db_detach(&client->query.authdb);
    816   1.9  christos 	}
    817   1.9  christos 	if (client->query.authzone != NULL) {
    818   1.1  christos 		dns_zone_detach(&client->query.authzone);
    819   1.9  christos 	}
    820   1.1  christos 
    821   1.9  christos 	if (client->query.dns64_aaaa != NULL) {
    822   1.3  christos 		ns_client_putrdataset(client, &client->query.dns64_aaaa);
    823   1.9  christos 	}
    824   1.9  christos 	if (client->query.dns64_sigaaaa != NULL) {
    825   1.3  christos 		ns_client_putrdataset(client, &client->query.dns64_sigaaaa);
    826   1.9  christos 	}
    827   1.1  christos 	if (client->query.dns64_aaaaok != NULL) {
    828  1.23  christos 		isc_mem_cput(client->manager->mctx, client->query.dns64_aaaaok,
    829  1.23  christos 			     client->query.dns64_aaaaoklen, sizeof(bool));
    830   1.9  christos 		client->query.dns64_aaaaok = NULL;
    831   1.9  christos 		client->query.dns64_aaaaoklen = 0;
    832   1.1  christos 	}
    833   1.1  christos 
    834   1.3  christos 	ns_client_putrdataset(client, &client->query.redirect.rdataset);
    835   1.3  christos 	ns_client_putrdataset(client, &client->query.redirect.sigrdataset);
    836   1.1  christos 	if (client->query.redirect.db != NULL) {
    837   1.9  christos 		if (client->query.redirect.node != NULL) {
    838   1.1  christos 			dns_db_detachnode(client->query.redirect.db,
    839   1.1  christos 					  &client->query.redirect.node);
    840   1.9  christos 		}
    841   1.1  christos 		dns_db_detach(&client->query.redirect.db);
    842   1.1  christos 	}
    843   1.9  christos 	if (client->query.redirect.zone != NULL) {
    844   1.1  christos 		dns_zone_detach(&client->query.redirect.zone);
    845   1.9  christos 	}
    846   1.1  christos 
    847   1.1  christos 	query_freefreeversions(client, everything);
    848   1.1  christos 
    849   1.9  christos 	for (dbuf = ISC_LIST_HEAD(client->query.namebufs); dbuf != NULL;
    850   1.9  christos 	     dbuf = dbuf_next)
    851   1.9  christos 	{
    852   1.1  christos 		dbuf_next = ISC_LIST_NEXT(dbuf, link);
    853   1.1  christos 		if (dbuf_next != NULL || everything) {
    854   1.1  christos 			ISC_LIST_UNLINK(client->query.namebufs, dbuf, link);
    855   1.1  christos 			isc_buffer_free(&dbuf);
    856   1.1  christos 		}
    857   1.1  christos 	}
    858   1.1  christos 
    859   1.1  christos 	if (client->query.restarts > 0) {
    860   1.1  christos 		/*
    861   1.1  christos 		 * client->query.qname was dynamically allocated.
    862   1.1  christos 		 */
    863   1.9  christos 		dns_message_puttempname(client->message, &client->query.qname);
    864   1.1  christos 	}
    865   1.1  christos 	client->query.qname = NULL;
    866   1.1  christos 	client->query.attributes = (NS_QUERYATTR_RECURSIONOK |
    867   1.9  christos 				    NS_QUERYATTR_CACHEOK | NS_QUERYATTR_SECURE);
    868   1.1  christos 	client->query.restarts = 0;
    869   1.3  christos 	client->query.timerset = false;
    870   1.1  christos 	if (client->query.rpz_st != NULL) {
    871   1.1  christos 		rpz_st_clear(client);
    872   1.1  christos 		if (everything) {
    873   1.1  christos 			INSIST(client->query.rpz_st->rpsdb == NULL);
    874  1.23  christos 			isc_mem_put(client->manager->mctx, client->query.rpz_st,
    875   1.1  christos 				    sizeof(*client->query.rpz_st));
    876   1.1  christos 			client->query.rpz_st = NULL;
    877   1.1  christos 		}
    878   1.1  christos 	}
    879  1.24  christos 	if (client->query.qc != NULL) {
    880  1.24  christos 		isc_counter_detach(&client->query.qc);
    881  1.24  christos 	}
    882   1.1  christos 	client->query.origqname = NULL;
    883   1.1  christos 	client->query.dboptions = 0;
    884   1.1  christos 	client->query.fetchoptions = 0;
    885   1.1  christos 	client->query.gluedb = NULL;
    886   1.3  christos 	client->query.authdbset = false;
    887   1.3  christos 	client->query.isreferral = false;
    888   1.1  christos 	client->query.dns64_options = 0;
    889   1.3  christos 	client->query.dns64_ttl = UINT32_MAX;
    890   1.3  christos 	recparam_update(&client->query.recparam, 0, NULL, NULL);
    891   1.1  christos 	client->query.root_key_sentinel_keyid = 0;
    892   1.3  christos 	client->query.root_key_sentinel_is_ta = false;
    893   1.3  christos 	client->query.root_key_sentinel_not_ta = false;
    894   1.1  christos }
    895   1.1  christos 
    896   1.1  christos static void
    897   1.9  christos query_cleanup(ns_client_t *client) {
    898   1.3  christos 	query_reset(client, false);
    899   1.1  christos }
    900   1.1  christos 
    901   1.1  christos void
    902   1.1  christos ns_query_free(ns_client_t *client) {
    903   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
    904   1.1  christos 
    905   1.3  christos 	query_reset(client, true);
    906   1.1  christos }
    907   1.1  christos 
    908  1.23  christos void
    909   1.1  christos ns_query_init(ns_client_t *client) {
    910  1.23  christos 	REQUIRE(NS_CLIENT_VALID(client));
    911   1.1  christos 
    912  1.23  christos 	client->query = (ns_query_t){ 0 };
    913   1.1  christos 
    914   1.1  christos 	ISC_LIST_INIT(client->query.namebufs);
    915   1.1  christos 	ISC_LIST_INIT(client->query.activeversions);
    916   1.1  christos 	ISC_LIST_INIT(client->query.freeversions);
    917  1.24  christos 
    918   1.1  christos 	/*
    919   1.1  christos 	 * This mutex is destroyed when the client is destroyed in
    920   1.1  christos 	 * exit_check().
    921   1.1  christos 	 */
    922   1.3  christos 	isc_mutex_init(&client->query.fetchlock);
    923   1.1  christos 	client->query.redirect.fname =
    924   1.1  christos 		dns_fixedname_initname(&client->query.redirect.fixed);
    925   1.3  christos 	query_reset(client, false);
    926  1.14  christos 	ns_client_newdbversion(client, 3);
    927  1.14  christos 	ns_client_newnamebuf(client);
    928   1.1  christos }
    929   1.1  christos 
    930   1.3  christos /*%
    931   1.3  christos  * Check if 'client' is allowed to query the cache of its associated view.
    932  1.23  christos  * Unless 'options' has the 'nolog' flag set, log the result of cache ACL
    933   1.3  christos  * evaluation using the appropriate level, along with 'name' and 'qtype'.
    934   1.3  christos  *
    935   1.3  christos  * The cache ACL is only evaluated once for each client and then the result is
    936   1.3  christos  * cached: if NS_QUERYATTR_CACHEACLOKVALID is set in client->query.attributes,
    937   1.3  christos  * cache ACL evaluation has already been performed.  The evaluation result is
    938   1.3  christos  * also stored in client->query.attributes: if NS_QUERYATTR_CACHEACLOK is set,
    939   1.3  christos  * the client is allowed cache access.
    940   1.3  christos  *
    941   1.3  christos  * Returns:
    942   1.3  christos  *
    943   1.3  christos  *\li	#ISC_R_SUCCESS	'client' is allowed to access cache
    944   1.3  christos  *\li	#DNS_R_REFUSED	'client' is not allowed to access cache
    945   1.3  christos  */
    946   1.3  christos static isc_result_t
    947   1.3  christos query_checkcacheaccess(ns_client_t *client, const dns_name_t *name,
    948  1.23  christos 		       dns_rdatatype_t qtype, dns_getdb_options_t options) {
    949   1.3  christos 	isc_result_t result;
    950   1.3  christos 
    951   1.3  christos 	if ((client->query.attributes & NS_QUERYATTR_CACHEACLOKVALID) == 0) {
    952  1.20  christos 		enum refusal_reasons {
    953  1.20  christos 			ALLOW_QUERY_CACHE,
    954  1.20  christos 			ALLOW_QUERY_CACHE_ON
    955  1.20  christos 		};
    956  1.20  christos 		static const char *acl_desc[] = {
    957  1.20  christos 			"allow-query-cache did not match",
    958  1.20  christos 			"allow-query-cache-on did not match",
    959  1.20  christos 		};
    960  1.20  christos 
    961   1.3  christos 		/*
    962   1.3  christos 		 * The view's cache ACLs have not yet been evaluated.
    963   1.3  christos 		 * Do it now. Both allow-query-cache and
    964  1.20  christos 		 * allow-query-cache-on must be satisfied.
    965   1.3  christos 		 */
    966   1.3  christos 		char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")];
    967   1.1  christos 
    968  1.20  christos 		enum refusal_reasons refusal_reason = ALLOW_QUERY_CACHE;
    969   1.3  christos 		result = ns_client_checkaclsilent(client, NULL,
    970   1.9  christos 						  client->view->cacheacl, true);
    971   1.3  christos 		if (result == ISC_R_SUCCESS) {
    972  1.20  christos 			refusal_reason = ALLOW_QUERY_CACHE_ON;
    973   1.9  christos 			result = ns_client_checkaclsilent(
    974   1.9  christos 				client, &client->destaddr,
    975   1.9  christos 				client->view->cacheonacl, true);
    976   1.9  christos 		}
    977   1.3  christos 		if (result == ISC_R_SUCCESS) {
    978   1.3  christos 			/*
    979   1.3  christos 			 * We were allowed by the "allow-query-cache" ACL.
    980   1.3  christos 			 */
    981   1.3  christos 			client->query.attributes |= NS_QUERYATTR_CACHEACLOK;
    982  1.23  christos 			if (!options.nolog &&
    983  1.23  christos 			    isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(3)))
    984   1.3  christos 			{
    985   1.3  christos 				ns_client_aclmsg("query (cache)", name, qtype,
    986   1.3  christos 						 client->view->rdclass, msg,
    987   1.3  christos 						 sizeof(msg));
    988   1.3  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
    989   1.3  christos 					      NS_LOGMODULE_QUERY,
    990   1.3  christos 					      ISC_LOG_DEBUG(3), "%s approved",
    991   1.3  christos 					      msg);
    992   1.3  christos 			}
    993  1.20  christos 		} else {
    994   1.3  christos 			/*
    995   1.3  christos 			 * We were denied by the "allow-query-cache" ACL.
    996   1.3  christos 			 * There is no need to clear NS_QUERYATTR_CACHEACLOK
    997   1.3  christos 			 * since it is cleared by query_reset(), before query
    998   1.3  christos 			 * processing starts.
    999   1.3  christos 			 */
   1000  1.24  christos 			dns_ede_add(&client->edectx, DNS_EDE_PROHIBITED, NULL);
   1001  1.20  christos 
   1002  1.23  christos 			if (!options.nolog) {
   1003  1.20  christos 				ns_client_aclmsg("query (cache)", name, qtype,
   1004  1.20  christos 						 client->view->rdclass, msg,
   1005  1.20  christos 						 sizeof(msg));
   1006  1.20  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1007  1.20  christos 					      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   1008  1.20  christos 					      "%s denied (%s)", msg,
   1009  1.20  christos 					      acl_desc[refusal_reason]);
   1010  1.20  christos 			}
   1011   1.3  christos 		}
   1012   1.1  christos 
   1013   1.1  christos 		/*
   1014   1.3  christos 		 * Evaluation has been finished; make sure we will just consult
   1015   1.3  christos 		 * NS_QUERYATTR_CACHEACLOK for this client from now on.
   1016   1.1  christos 		 */
   1017   1.3  christos 		client->query.attributes |= NS_QUERYATTR_CACHEACLOKVALID;
   1018   1.1  christos 	}
   1019   1.1  christos 
   1020  1.23  christos 	return (client->query.attributes & NS_QUERYATTR_CACHEACLOK) != 0
   1021  1.23  christos 		       ? ISC_R_SUCCESS
   1022  1.23  christos 		       : DNS_R_REFUSED;
   1023   1.1  christos }
   1024   1.1  christos 
   1025  1.15  christos static isc_result_t
   1026   1.1  christos query_validatezonedb(ns_client_t *client, const dns_name_t *name,
   1027  1.23  christos 		     dns_rdatatype_t qtype, dns_getdb_options_t options,
   1028   1.1  christos 		     dns_zone_t *zone, dns_db_t *db,
   1029   1.9  christos 		     dns_dbversion_t **versionp) {
   1030   1.1  christos 	isc_result_t result;
   1031   1.1  christos 	dns_acl_t *queryacl, *queryonacl;
   1032   1.1  christos 	ns_dbversion_t *dbversion;
   1033   1.1  christos 
   1034   1.1  christos 	REQUIRE(zone != NULL);
   1035   1.1  christos 	REQUIRE(db != NULL);
   1036   1.1  christos 
   1037   1.1  christos 	/*
   1038   1.3  christos 	 * Mirror zone data is treated as cache data.
   1039   1.3  christos 	 */
   1040   1.3  christos 	if (dns_zone_gettype(zone) == dns_zone_mirror) {
   1041  1.23  christos 		return query_checkcacheaccess(client, name, qtype, options);
   1042   1.3  christos 	}
   1043   1.3  christos 
   1044   1.3  christos 	/*
   1045   1.1  christos 	 * This limits our searching to the zone where the first name
   1046   1.1  christos 	 * (the query target) was looked for.  This prevents following
   1047   1.1  christos 	 * CNAMES or DNAMES into other zones and prevents returning
   1048   1.1  christos 	 * additional data from other zones. This does not apply if we're
   1049   1.1  christos 	 * answering a query where recursion is requested and allowed.
   1050   1.1  christos 	 */
   1051   1.1  christos 	if (client->query.rpz_st == NULL &&
   1052   1.1  christos 	    !(WANTRECURSION(client) && RECURSIONOK(client)) &&
   1053   1.1  christos 	    client->query.authdbset && db != client->query.authdb)
   1054   1.1  christos 	{
   1055  1.23  christos 		return DNS_R_REFUSED;
   1056   1.1  christos 	}
   1057   1.1  christos 
   1058   1.1  christos 	/*
   1059   1.1  christos 	 * Non recursive query to a static-stub zone is prohibited; its
   1060   1.1  christos 	 * zone content is not public data, but a part of local configuration
   1061   1.1  christos 	 * and should not be disclosed.
   1062   1.1  christos 	 */
   1063   1.1  christos 	if (dns_zone_gettype(zone) == dns_zone_staticstub &&
   1064  1.16  christos 	    !RECURSIONOK(client))
   1065  1.16  christos 	{
   1066  1.23  christos 		return DNS_R_REFUSED;
   1067   1.1  christos 	}
   1068   1.1  christos 
   1069   1.1  christos 	/*
   1070   1.1  christos 	 * If the zone has an ACL, we'll check it, otherwise
   1071   1.1  christos 	 * we use the view's "allow-query" ACL.  Each ACL is only checked
   1072   1.1  christos 	 * once per query.
   1073   1.1  christos 	 *
   1074   1.1  christos 	 * Also, get the database version to use.
   1075   1.1  christos 	 */
   1076   1.1  christos 
   1077   1.1  christos 	/*
   1078   1.1  christos 	 * Get the current version of this database.
   1079   1.1  christos 	 */
   1080   1.3  christos 	dbversion = ns_client_findversion(client, db);
   1081   1.1  christos 	if (dbversion == NULL) {
   1082   1.1  christos 		CTRACE(ISC_LOG_ERROR, "unable to get db version");
   1083  1.23  christos 		return DNS_R_SERVFAIL;
   1084   1.1  christos 	}
   1085   1.1  christos 
   1086  1.23  christos 	if (options.ignoreacl) {
   1087   1.1  christos 		goto approved;
   1088   1.9  christos 	}
   1089   1.1  christos 	if (dbversion->acl_checked) {
   1090   1.9  christos 		if (!dbversion->queryok) {
   1091  1.23  christos 			return DNS_R_REFUSED;
   1092   1.9  christos 		}
   1093   1.1  christos 		goto approved;
   1094   1.1  christos 	}
   1095   1.1  christos 
   1096   1.1  christos 	queryacl = dns_zone_getqueryacl(zone);
   1097   1.1  christos 	if (queryacl == NULL) {
   1098   1.1  christos 		queryacl = client->view->queryacl;
   1099   1.9  christos 		if ((client->query.attributes & NS_QUERYATTR_QUERYOKVALID) != 0)
   1100   1.9  christos 		{
   1101   1.1  christos 			/*
   1102   1.1  christos 			 * We've evaluated the view's queryacl already.  If
   1103   1.1  christos 			 * NS_QUERYATTR_QUERYOK is set, then the client is
   1104   1.1  christos 			 * allowed to make queries, otherwise the query should
   1105   1.1  christos 			 * be refused.
   1106   1.1  christos 			 */
   1107   1.3  christos 			dbversion->acl_checked = true;
   1108   1.9  christos 			if ((client->query.attributes & NS_QUERYATTR_QUERYOK) ==
   1109  1.16  christos 			    0)
   1110  1.16  christos 			{
   1111   1.3  christos 				dbversion->queryok = false;
   1112  1.23  christos 				return DNS_R_REFUSED;
   1113   1.1  christos 			}
   1114   1.3  christos 			dbversion->queryok = true;
   1115   1.1  christos 			goto approved;
   1116   1.1  christos 		}
   1117   1.1  christos 	}
   1118   1.1  christos 
   1119   1.3  christos 	result = ns_client_checkaclsilent(client, NULL, queryacl, true);
   1120  1.23  christos 	if (!options.nolog) {
   1121   1.1  christos 		char msg[NS_CLIENT_ACLMSGSIZE("query")];
   1122   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1123   1.1  christos 			if (isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(3))) {
   1124   1.1  christos 				ns_client_aclmsg("query", name, qtype,
   1125   1.9  christos 						 client->view->rdclass, msg,
   1126   1.9  christos 						 sizeof(msg));
   1127   1.9  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1128   1.1  christos 					      NS_LOGMODULE_QUERY,
   1129   1.9  christos 					      ISC_LOG_DEBUG(3), "%s approved",
   1130   1.9  christos 					      msg);
   1131   1.1  christos 			}
   1132   1.1  christos 		} else {
   1133   1.1  christos 			ns_client_aclmsg("query", name, qtype,
   1134   1.9  christos 					 client->view->rdclass, msg,
   1135   1.9  christos 					 sizeof(msg));
   1136   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1137   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   1138   1.1  christos 				      "%s denied", msg);
   1139  1.24  christos 			dns_ede_add(&client->edectx, DNS_EDE_PROHIBITED, NULL);
   1140   1.1  christos 		}
   1141   1.1  christos 	}
   1142   1.1  christos 
   1143   1.1  christos 	if (queryacl == client->view->queryacl) {
   1144   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1145   1.1  christos 			/*
   1146   1.1  christos 			 * We were allowed by the default
   1147   1.1  christos 			 * "allow-query" ACL.  Remember this so we
   1148   1.1  christos 			 * don't have to check again.
   1149   1.1  christos 			 */
   1150   1.1  christos 			client->query.attributes |= NS_QUERYATTR_QUERYOK;
   1151   1.1  christos 		}
   1152   1.1  christos 		/*
   1153   1.1  christos 		 * We've now evaluated the view's query ACL, and
   1154   1.1  christos 		 * the NS_QUERYATTR_QUERYOK attribute is now valid.
   1155   1.1  christos 		 */
   1156   1.1  christos 		client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
   1157   1.1  christos 	}
   1158   1.1  christos 
   1159   1.1  christos 	/* If and only if we've gotten this far, check allow-query-on too */
   1160   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1161   1.1  christos 		queryonacl = dns_zone_getqueryonacl(zone);
   1162   1.9  christos 		if (queryonacl == NULL) {
   1163   1.1  christos 			queryonacl = client->view->queryonacl;
   1164   1.9  christos 		}
   1165   1.1  christos 
   1166   1.1  christos 		result = ns_client_checkaclsilent(client, &client->destaddr,
   1167   1.3  christos 						  queryonacl, true);
   1168  1.20  christos 		if (result != ISC_R_SUCCESS) {
   1169  1.24  christos 			dns_ede_add(&client->edectx, DNS_EDE_PROHIBITED, NULL);
   1170  1.20  christos 		}
   1171  1.23  christos 		if (!options.nolog && result != ISC_R_SUCCESS) {
   1172   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1173   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   1174   1.1  christos 				      "query-on denied");
   1175   1.9  christos 		}
   1176   1.1  christos 	}
   1177   1.1  christos 
   1178   1.3  christos 	dbversion->acl_checked = true;
   1179   1.1  christos 	if (result != ISC_R_SUCCESS) {
   1180   1.3  christos 		dbversion->queryok = false;
   1181  1.23  christos 		return DNS_R_REFUSED;
   1182   1.1  christos 	}
   1183   1.3  christos 	dbversion->queryok = true;
   1184   1.1  christos 
   1185   1.9  christos approved:
   1186   1.1  christos 	/* Transfer ownership, if necessary. */
   1187  1.23  christos 	SET_IF_NOT_NULL(versionp, dbversion->version);
   1188  1.23  christos 	return ISC_R_SUCCESS;
   1189   1.1  christos }
   1190   1.1  christos 
   1191  1.15  christos static isc_result_t
   1192   1.1  christos query_getzonedb(ns_client_t *client, const dns_name_t *name,
   1193  1.23  christos 		dns_rdatatype_t qtype, dns_getdb_options_t options,
   1194  1.23  christos 		dns_zone_t **zonep, dns_db_t **dbp,
   1195  1.23  christos 		dns_dbversion_t **versionp) {
   1196   1.1  christos 	isc_result_t result;
   1197   1.1  christos 	unsigned int ztoptions;
   1198   1.1  christos 	dns_zone_t *zone = NULL;
   1199   1.1  christos 	dns_db_t *db = NULL;
   1200   1.3  christos 	bool partial = false;
   1201   1.1  christos 
   1202   1.1  christos 	REQUIRE(zonep != NULL && *zonep == NULL);
   1203   1.1  christos 	REQUIRE(dbp != NULL && *dbp == NULL);
   1204   1.1  christos 
   1205   1.1  christos 	/*%
   1206   1.1  christos 	 * Find a zone database to answer the query.
   1207   1.1  christos 	 */
   1208   1.3  christos 	ztoptions = DNS_ZTFIND_MIRROR;
   1209  1.23  christos 	if (options.noexact) {
   1210   1.3  christos 		ztoptions |= DNS_ZTFIND_NOEXACT;
   1211   1.3  christos 	}
   1212   1.1  christos 
   1213  1.23  christos 	result = dns_view_findzone(client->view, name, ztoptions, &zone);
   1214   1.1  christos 
   1215   1.9  christos 	if (result == DNS_R_PARTIALMATCH) {
   1216   1.3  christos 		partial = true;
   1217   1.9  christos 	}
   1218   1.9  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
   1219   1.1  christos 		result = dns_zone_getdb(zone, &db);
   1220   1.9  christos 	}
   1221   1.1  christos 
   1222   1.9  christos 	if (result != ISC_R_SUCCESS) {
   1223   1.1  christos 		goto fail;
   1224   1.9  christos 	}
   1225   1.1  christos 
   1226   1.1  christos 	result = query_validatezonedb(client, name, qtype, options, zone, db,
   1227   1.1  christos 				      versionp);
   1228   1.1  christos 
   1229   1.9  christos 	if (result != ISC_R_SUCCESS) {
   1230   1.1  christos 		goto fail;
   1231   1.9  christos 	}
   1232   1.1  christos 
   1233   1.1  christos 	/* Transfer ownership. */
   1234   1.1  christos 	*zonep = zone;
   1235   1.1  christos 	*dbp = db;
   1236   1.1  christos 
   1237  1.23  christos 	if (partial && options.partial) {
   1238  1.23  christos 		return DNS_R_PARTIALMATCH;
   1239   1.9  christos 	}
   1240  1.23  christos 	return ISC_R_SUCCESS;
   1241   1.1  christos 
   1242   1.9  christos fail:
   1243   1.9  christos 	if (zone != NULL) {
   1244   1.1  christos 		dns_zone_detach(&zone);
   1245   1.9  christos 	}
   1246   1.9  christos 	if (db != NULL) {
   1247   1.1  christos 		dns_db_detach(&db);
   1248   1.9  christos 	}
   1249   1.1  christos 
   1250  1.23  christos 	return result;
   1251   1.1  christos }
   1252   1.1  christos 
   1253   1.1  christos static void
   1254   1.9  christos rpz_log_rewrite(ns_client_t *client, bool disabled, dns_rpz_policy_t policy,
   1255   1.9  christos 		dns_rpz_type_t type, dns_zone_t *p_zone, dns_name_t *p_name,
   1256   1.9  christos 		dns_name_t *cname, dns_rpz_num_t rpz_num) {
   1257   1.3  christos 	char cname_buf[DNS_NAME_FORMATSIZE] = { 0 };
   1258   1.3  christos 	char p_name_buf[DNS_NAME_FORMATSIZE];
   1259   1.1  christos 	char qname_buf[DNS_NAME_FORMATSIZE];
   1260   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   1261   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   1262   1.1  christos 	const char *s1 = cname_buf, *s2 = cname_buf;
   1263   1.3  christos 	dns_rdataset_t *rdataset;
   1264   1.1  christos 	dns_rpz_st_t *st;
   1265   1.3  christos 	isc_stats_t *zonestats;
   1266   1.1  christos 
   1267   1.1  christos 	/*
   1268   1.1  christos 	 * Count enabled rewrites in the global counter.
   1269   1.1  christos 	 * Count both enabled and disabled rewrites for each zone.
   1270   1.1  christos 	 */
   1271   1.1  christos 	if (!disabled && policy != DNS_RPZ_POLICY_PASSTHRU) {
   1272  1.23  christos 		ns_stats_increment(client->manager->sctx->nsstats,
   1273   1.1  christos 				   ns_statscounter_rpz_rewrites);
   1274   1.1  christos 	}
   1275   1.1  christos 	if (p_zone != NULL) {
   1276   1.1  christos 		zonestats = dns_zone_getrequeststats(p_zone);
   1277   1.9  christos 		if (zonestats != NULL) {
   1278   1.1  christos 			isc_stats_increment(zonestats,
   1279   1.1  christos 					    ns_statscounter_rpz_rewrites);
   1280   1.9  christos 		}
   1281   1.1  christos 	}
   1282   1.1  christos 
   1283   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, DNS_RPZ_INFO_LEVEL)) {
   1284   1.1  christos 		return;
   1285   1.9  christos 	}
   1286   1.1  christos 
   1287   1.1  christos 	st = client->query.rpz_st;
   1288   1.9  christos 	if ((st->popt.no_log & DNS_RPZ_ZBIT(rpz_num)) != 0) {
   1289   1.1  christos 		return;
   1290   1.9  christos 	}
   1291   1.1  christos 
   1292   1.1  christos 	dns_name_format(client->query.qname, qname_buf, sizeof(qname_buf));
   1293   1.1  christos 	dns_name_format(p_name, p_name_buf, sizeof(p_name_buf));
   1294   1.1  christos 	if (cname != NULL) {
   1295   1.1  christos 		s1 = " (CNAME to: ";
   1296   1.1  christos 		dns_name_format(cname, cname_buf, sizeof(cname_buf));
   1297   1.1  christos 		s2 = ")";
   1298   1.1  christos 	}
   1299   1.1  christos 
   1300   1.3  christos 	/*
   1301   1.3  christos 	 *  Log Qclass and Qtype in addition to existing
   1302   1.3  christos 	 *  fields.
   1303   1.3  christos 	 */
   1304   1.3  christos 	rdataset = ISC_LIST_HEAD(client->query.origqname->list);
   1305   1.3  christos 	INSIST(rdataset != NULL);
   1306   1.3  christos 	dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf));
   1307   1.3  christos 	dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
   1308   1.3  christos 
   1309  1.20  christos 	/* It's possible to have a separate log channel for rpz passthru. */
   1310  1.20  christos 	isc_logcategory_t *log_cat = (policy == DNS_RPZ_POLICY_PASSTHRU)
   1311  1.20  christos 					     ? DNS_LOGCATEGORY_RPZ_PASSTHRU
   1312  1.20  christos 					     : DNS_LOGCATEGORY_RPZ;
   1313  1.20  christos 
   1314  1.20  christos 	ns_client_log(client, log_cat, NS_LOGMODULE_QUERY, DNS_RPZ_INFO_LEVEL,
   1315   1.3  christos 		      "%srpz %s %s rewrite %s/%s/%s via %s%s%s%s",
   1316   1.9  christos 		      disabled ? "disabled " : "", dns_rpz_type2str(type),
   1317   1.9  christos 		      dns_rpz_policy2str(policy), qname_buf, typebuf, classbuf,
   1318   1.3  christos 		      p_name_buf, s1, cname_buf, s2);
   1319   1.1  christos }
   1320   1.1  christos 
   1321   1.1  christos static void
   1322   1.1  christos rpz_log_fail_helper(ns_client_t *client, int level, dns_name_t *p_name,
   1323   1.1  christos 		    dns_rpz_type_t rpz_type1, dns_rpz_type_t rpz_type2,
   1324   1.9  christos 		    const char *str, isc_result_t result) {
   1325   1.1  christos 	char qnamebuf[DNS_NAME_FORMATSIZE];
   1326   1.1  christos 	char p_namebuf[DNS_NAME_FORMATSIZE];
   1327   1.1  christos 	const char *failed, *via, *slash, *str_blank;
   1328   1.1  christos 	const char *rpztypestr1;
   1329   1.1  christos 	const char *rpztypestr2;
   1330   1.1  christos 
   1331   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   1332   1.1  christos 		return;
   1333   1.9  christos 	}
   1334   1.1  christos 
   1335   1.1  christos 	/*
   1336   1.1  christos 	 * bin/tests/system/rpz/tests.sh looks for "rpz.*failed" for problems.
   1337   1.1  christos 	 */
   1338   1.9  christos 	if (level <= DNS_RPZ_DEBUG_LEVEL1) {
   1339   1.3  christos 		failed = " failed: ";
   1340   1.9  christos 	} else {
   1341   1.1  christos 		failed = ": ";
   1342   1.9  christos 	}
   1343   1.1  christos 
   1344   1.1  christos 	rpztypestr1 = dns_rpz_type2str(rpz_type1);
   1345   1.1  christos 	if (rpz_type2 != DNS_RPZ_TYPE_BAD) {
   1346   1.1  christos 		slash = "/";
   1347   1.1  christos 		rpztypestr2 = dns_rpz_type2str(rpz_type2);
   1348   1.1  christos 	} else {
   1349   1.1  christos 		slash = "";
   1350   1.1  christos 		rpztypestr2 = "";
   1351   1.1  christos 	}
   1352   1.1  christos 
   1353   1.1  christos 	str_blank = (*str != ' ' && *str != '\0') ? " " : "";
   1354   1.1  christos 
   1355   1.1  christos 	dns_name_format(client->query.qname, qnamebuf, sizeof(qnamebuf));
   1356   1.1  christos 
   1357   1.1  christos 	if (p_name != NULL) {
   1358   1.1  christos 		via = " via ";
   1359   1.1  christos 		dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
   1360   1.1  christos 	} else {
   1361   1.1  christos 		via = "";
   1362   1.1  christos 		p_namebuf[0] = '\0';
   1363   1.1  christos 	}
   1364   1.1  christos 
   1365   1.9  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS, NS_LOGMODULE_QUERY,
   1366   1.9  christos 		      level, "rpz %s%s%s rewrite %s%s%s%s%s%s%s", rpztypestr1,
   1367   1.9  christos 		      slash, rpztypestr2, qnamebuf, via, p_namebuf, str_blank,
   1368   1.1  christos 		      str, failed, isc_result_totext(result));
   1369   1.1  christos }
   1370   1.1  christos 
   1371   1.1  christos static void
   1372   1.1  christos rpz_log_fail(ns_client_t *client, int level, dns_name_t *p_name,
   1373   1.9  christos 	     dns_rpz_type_t rpz_type, const char *str, isc_result_t result) {
   1374   1.9  christos 	rpz_log_fail_helper(client, level, p_name, rpz_type, DNS_RPZ_TYPE_BAD,
   1375   1.9  christos 			    str, result);
   1376   1.1  christos }
   1377   1.1  christos 
   1378   1.1  christos /*
   1379   1.1  christos  * Get a policy rewrite zone database.
   1380   1.1  christos  */
   1381   1.1  christos static isc_result_t
   1382   1.1  christos rpz_getdb(ns_client_t *client, dns_name_t *p_name, dns_rpz_type_t rpz_type,
   1383   1.9  christos 	  dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp) {
   1384   1.1  christos 	char qnamebuf[DNS_NAME_FORMATSIZE];
   1385   1.1  christos 	char p_namebuf[DNS_NAME_FORMATSIZE];
   1386   1.1  christos 	dns_dbversion_t *rpz_version = NULL;
   1387   1.1  christos 	isc_result_t result;
   1388   1.1  christos 
   1389   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_getdb");
   1390   1.1  christos 
   1391  1.23  christos 	dns_getdb_options_t options = { .ignoreacl = true };
   1392  1.23  christos 	result = query_getzonedb(client, p_name, dns_rdatatype_any, options,
   1393  1.23  christos 				 zonep, dbp, &rpz_version);
   1394   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1395   1.1  christos 		dns_rpz_st_t *st = client->query.rpz_st;
   1396   1.1  christos 
   1397   1.1  christos 		/*
   1398   1.1  christos 		 * It isn't meaningful to log this message when
   1399   1.1  christos 		 * logging is disabled for some policy zones.
   1400   1.1  christos 		 */
   1401   1.1  christos 		if (st->popt.no_log == 0 &&
   1402  1.16  christos 		    isc_log_wouldlog(ns_lctx, DNS_RPZ_DEBUG_LEVEL2))
   1403  1.16  christos 		{
   1404   1.1  christos 			dns_name_format(client->query.qname, qnamebuf,
   1405   1.1  christos 					sizeof(qnamebuf));
   1406   1.1  christos 			dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
   1407   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_RPZ,
   1408   1.1  christos 				      NS_LOGMODULE_QUERY, DNS_RPZ_DEBUG_LEVEL2,
   1409   1.1  christos 				      "try rpz %s rewrite %s via %s",
   1410   1.9  christos 				      dns_rpz_type2str(rpz_type), qnamebuf,
   1411   1.9  christos 				      p_namebuf);
   1412   1.1  christos 		}
   1413   1.1  christos 		*versionp = rpz_version;
   1414  1.23  christos 		return ISC_R_SUCCESS;
   1415   1.1  christos 	}
   1416   1.1  christos 	rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type,
   1417   1.3  christos 		     "query_getzonedb()", result);
   1418  1.23  christos 	return result;
   1419   1.1  christos }
   1420   1.1  christos 
   1421   1.3  christos /*%
   1422   1.3  christos  * Find a cache database to answer the query.  This may fail with DNS_R_REFUSED
   1423   1.3  christos  * if the client is not allowed to use the cache.
   1424   1.3  christos  */
   1425  1.15  christos static isc_result_t
   1426   1.1  christos query_getcachedb(ns_client_t *client, const dns_name_t *name,
   1427  1.23  christos 		 dns_rdatatype_t qtype, dns_db_t **dbp,
   1428  1.23  christos 		 dns_getdb_options_t options) {
   1429   1.1  christos 	isc_result_t result;
   1430   1.1  christos 	dns_db_t *db = NULL;
   1431   1.1  christos 
   1432   1.1  christos 	REQUIRE(dbp != NULL && *dbp == NULL);
   1433   1.1  christos 
   1434   1.3  christos 	if (!USECACHE(client)) {
   1435  1.23  christos 		return DNS_R_REFUSED;
   1436   1.1  christos 	}
   1437   1.1  christos 
   1438   1.3  christos 	dns_db_attach(client->view->cachedb, &db);
   1439   1.1  christos 
   1440   1.3  christos 	result = query_checkcacheaccess(client, name, qtype, options);
   1441   1.3  christos 	if (result != ISC_R_SUCCESS) {
   1442   1.3  christos 		dns_db_detach(&db);
   1443   1.1  christos 	}
   1444   1.1  christos 
   1445   1.3  christos 	/*
   1446   1.3  christos 	 * If query_checkcacheaccess() succeeded, transfer ownership of 'db'.
   1447   1.3  christos 	 * Otherwise, 'db' will be NULL due to the dns_db_detach() call above.
   1448   1.3  christos 	 */
   1449   1.1  christos 	*dbp = db;
   1450   1.1  christos 
   1451  1.23  christos 	return result;
   1452   1.3  christos }
   1453   1.1  christos 
   1454  1.15  christos static isc_result_t
   1455   1.3  christos query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
   1456  1.23  christos 	    dns_getdb_options_t options, dns_zone_t **zonep, dns_db_t **dbp,
   1457   1.9  christos 	    dns_dbversion_t **versionp, bool *is_zonep) {
   1458   1.1  christos 	isc_result_t result;
   1459   1.1  christos 	isc_result_t tresult;
   1460   1.1  christos 	unsigned int namelabels;
   1461   1.1  christos 	unsigned int zonelabels;
   1462   1.1  christos 	dns_zone_t *zone = NULL;
   1463   1.1  christos 
   1464   1.1  christos 	REQUIRE(zonep != NULL && *zonep == NULL);
   1465   1.1  christos 
   1466   1.1  christos 	/* Calculate how many labels are in name. */
   1467   1.1  christos 	namelabels = dns_name_countlabels(name);
   1468   1.1  christos 	zonelabels = 0;
   1469   1.1  christos 
   1470   1.1  christos 	/* Try to find name in bind's standard database. */
   1471   1.9  christos 	result = query_getzonedb(client, name, qtype, options, &zone, dbp,
   1472   1.9  christos 				 versionp);
   1473   1.1  christos 
   1474   1.1  christos 	/* See how many labels are in the zone's name.	  */
   1475   1.5  christos 	if (result == ISC_R_SUCCESS && zone != NULL) {
   1476   1.1  christos 		zonelabels = dns_name_countlabels(dns_zone_getorigin(zone));
   1477   1.5  christos 	}
   1478   1.1  christos 
   1479   1.1  christos 	/*
   1480   1.1  christos 	 * If # zone labels < # name labels, try to find an even better match
   1481   1.1  christos 	 * Only try if DLZ drivers are loaded for this view
   1482   1.1  christos 	 */
   1483  1.20  christos 	if (zonelabels < namelabels &&
   1484  1.20  christos 	    !ISC_LIST_EMPTY(client->view->dlz_searched))
   1485   1.1  christos 	{
   1486   1.1  christos 		dns_clientinfomethods_t cm;
   1487   1.1  christos 		dns_clientinfo_t ci;
   1488   1.1  christos 		dns_db_t *tdbp;
   1489   1.1  christos 
   1490   1.1  christos 		dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1491  1.20  christos 		dns_clientinfo_init(&ci, client, NULL);
   1492  1.20  christos 		dns_clientinfo_setecs(&ci, &client->ecs);
   1493   1.1  christos 
   1494   1.1  christos 		tdbp = NULL;
   1495   1.9  christos 		tresult = dns_view_searchdlz(client->view, name, zonelabels,
   1496   1.9  christos 					     &cm, &ci, &tdbp);
   1497   1.9  christos 		/* If we successful, we found a better match. */
   1498   1.1  christos 		if (tresult == ISC_R_SUCCESS) {
   1499   1.1  christos 			ns_dbversion_t *dbversion;
   1500   1.1  christos 
   1501   1.1  christos 			/*
   1502   1.1  christos 			 * If the previous search returned a zone, detach it.
   1503   1.1  christos 			 */
   1504   1.9  christos 			if (zone != NULL) {
   1505   1.1  christos 				dns_zone_detach(&zone);
   1506   1.9  christos 			}
   1507   1.1  christos 
   1508   1.1  christos 			/*
   1509   1.1  christos 			 * If the previous search returned a database,
   1510   1.1  christos 			 * detach it.
   1511   1.1  christos 			 */
   1512   1.9  christos 			if (*dbp != NULL) {
   1513   1.1  christos 				dns_db_detach(dbp);
   1514   1.9  christos 			}
   1515   1.1  christos 
   1516   1.1  christos 			/*
   1517   1.1  christos 			 * If the previous search returned a version, clear it.
   1518   1.1  christos 			 */
   1519   1.1  christos 			*versionp = NULL;
   1520   1.1  christos 
   1521   1.3  christos 			dbversion = ns_client_findversion(client, tdbp);
   1522   1.1  christos 			if (dbversion == NULL) {
   1523   1.1  christos 				tresult = ISC_R_NOMEMORY;
   1524   1.1  christos 			} else {
   1525   1.1  christos 				/*
   1526   1.1  christos 				 * Be sure to return our database.
   1527   1.1  christos 				 */
   1528   1.1  christos 				*dbp = tdbp;
   1529   1.1  christos 				*versionp = dbversion->version;
   1530   1.1  christos 			}
   1531   1.1  christos 
   1532   1.1  christos 			/*
   1533   1.1  christos 			 * We return a null zone, No stats for DLZ zones.
   1534   1.1  christos 			 */
   1535   1.1  christos 			zone = NULL;
   1536   1.1  christos 			result = tresult;
   1537   1.1  christos 		}
   1538   1.1  christos 	}
   1539   1.1  christos 
   1540   1.1  christos 	/* If successful, Transfer ownership of zone. */
   1541   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1542   1.1  christos 		*zonep = zone;
   1543   1.1  christos 		/*
   1544   1.1  christos 		 * If neither attempt above succeeded, return the cache instead
   1545   1.1  christos 		 */
   1546   1.3  christos 		*is_zonep = true;
   1547   1.5  christos 	} else {
   1548   1.5  christos 		if (result == ISC_R_NOTFOUND) {
   1549   1.5  christos 			result = query_getcachedb(client, name, qtype, dbp,
   1550   1.5  christos 						  options);
   1551   1.5  christos 		}
   1552   1.3  christos 		*is_zonep = false;
   1553   1.1  christos 	}
   1554  1.23  christos 	return result;
   1555   1.1  christos }
   1556   1.1  christos 
   1557  1.15  christos static bool
   1558   1.9  christos query_isduplicate(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
   1559   1.9  christos 		  dns_name_t **mnamep) {
   1560   1.1  christos 	dns_section_t section;
   1561   1.1  christos 	dns_name_t *mname = NULL;
   1562   1.1  christos 	isc_result_t result;
   1563   1.1  christos 
   1564   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate");
   1565   1.1  christos 
   1566   1.9  christos 	for (section = DNS_SECTION_ANSWER; section <= DNS_SECTION_ADDITIONAL;
   1567  1.16  christos 	     section++)
   1568  1.16  christos 	{
   1569   1.9  christos 		result = dns_message_findname(client->message, section, name,
   1570   1.9  christos 					      type, 0, &mname, NULL);
   1571   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1572   1.1  christos 			/*
   1573   1.1  christos 			 * We've already got this RRset in the response.
   1574   1.1  christos 			 */
   1575   1.9  christos 			CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: true: "
   1576   1.9  christos 						 "done");
   1577  1.23  christos 			return true;
   1578   1.1  christos 		} else if (result == DNS_R_NXRRSET) {
   1579   1.1  christos 			/*
   1580   1.1  christos 			 * The name exists, but the rdataset does not.
   1581   1.1  christos 			 */
   1582   1.9  christos 			if (section == DNS_SECTION_ADDITIONAL) {
   1583   1.1  christos 				break;
   1584   1.9  christos 			}
   1585   1.9  christos 		} else {
   1586   1.1  christos 			RUNTIME_CHECK(result == DNS_R_NXDOMAIN);
   1587   1.9  christos 		}
   1588   1.1  christos 		mname = NULL;
   1589   1.1  christos 	}
   1590   1.1  christos 
   1591  1.23  christos 	SET_IF_NOT_NULL(mnamep, mname);
   1592   1.1  christos 
   1593   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: false: done");
   1594  1.23  christos 	return false;
   1595   1.1  christos }
   1596   1.1  christos 
   1597   1.6  christos /*
   1598   1.6  christos  * Look up data for given 'name' and 'type' in given 'version' of 'db' for
   1599   1.6  christos  * 'client'. Called from query_additionalauth().
   1600   1.6  christos  *
   1601   1.6  christos  * If the lookup is successful:
   1602   1.6  christos  *
   1603   1.6  christos  *   - store the node containing the result at 'nodep',
   1604   1.6  christos  *
   1605   1.6  christos  *   - store the owner name of the returned node in 'fname',
   1606   1.6  christos  *
   1607   1.6  christos  *   - if 'type' is not ANY, dns_db_findext() will put the exact rdataset being
   1608   1.6  christos  *     looked for in 'rdataset' and its signatures (if any) in 'sigrdataset',
   1609   1.6  christos  *
   1610   1.6  christos  *   - if 'type' is ANY, dns_db_findext() will leave 'rdataset' and
   1611   1.6  christos  *     'sigrdataset' disassociated and the returned node will be iterated in
   1612   1.6  christos  *     query_additional_cb().
   1613   1.6  christos  *
   1614   1.6  christos  * If the lookup is not successful:
   1615   1.6  christos  *
   1616   1.6  christos  *   - 'nodep' will not be written to,
   1617   1.6  christos  *   - 'fname' may still be modified as it is passed to dns_db_findext(),
   1618   1.6  christos  *   - 'rdataset' and 'sigrdataset' will remain disassociated.
   1619   1.6  christos  */
   1620   1.6  christos static isc_result_t
   1621   1.6  christos query_additionalauthfind(dns_db_t *db, dns_dbversion_t *version,
   1622   1.6  christos 			 const dns_name_t *name, dns_rdatatype_t type,
   1623   1.6  christos 			 ns_client_t *client, dns_dbnode_t **nodep,
   1624   1.6  christos 			 dns_name_t *fname, dns_rdataset_t *rdataset,
   1625   1.9  christos 			 dns_rdataset_t *sigrdataset) {
   1626   1.6  christos 	dns_clientinfomethods_t cm;
   1627   1.6  christos 	dns_dbnode_t *node = NULL;
   1628   1.6  christos 	dns_clientinfo_t ci;
   1629   1.6  christos 	isc_result_t result;
   1630   1.6  christos 
   1631   1.6  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1632  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   1633   1.6  christos 
   1634   1.6  christos 	/*
   1635   1.6  christos 	 * Since we are looking for authoritative data, we do not set
   1636   1.6  christos 	 * the GLUEOK flag.  Glue will be looked for later, but not
   1637   1.6  christos 	 * necessarily in the same database.
   1638   1.6  christos 	 */
   1639   1.6  christos 	result = dns_db_findext(db, name, version, type,
   1640   1.6  christos 				client->query.dboptions, client->now, &node,
   1641   1.6  christos 				fname, &cm, &ci, rdataset, sigrdataset);
   1642   1.6  christos 	if (result != ISC_R_SUCCESS) {
   1643   1.6  christos 		if (dns_rdataset_isassociated(rdataset)) {
   1644   1.6  christos 			dns_rdataset_disassociate(rdataset);
   1645   1.6  christos 		}
   1646   1.6  christos 
   1647   1.6  christos 		if (sigrdataset != NULL &&
   1648  1.16  christos 		    dns_rdataset_isassociated(sigrdataset))
   1649  1.16  christos 		{
   1650   1.6  christos 			dns_rdataset_disassociate(sigrdataset);
   1651   1.6  christos 		}
   1652   1.6  christos 
   1653   1.6  christos 		if (node != NULL) {
   1654   1.6  christos 			dns_db_detachnode(db, &node);
   1655   1.6  christos 		}
   1656   1.6  christos 
   1657  1.23  christos 		return result;
   1658   1.6  christos 	}
   1659   1.6  christos 
   1660   1.6  christos 	/*
   1661   1.6  christos 	 * Do not return signatures if the zone is not fully signed.
   1662   1.6  christos 	 */
   1663   1.6  christos 	if (sigrdataset != NULL && !dns_db_issecure(db) &&
   1664   1.6  christos 	    dns_rdataset_isassociated(sigrdataset))
   1665   1.6  christos 	{
   1666   1.6  christos 		dns_rdataset_disassociate(sigrdataset);
   1667   1.6  christos 	}
   1668   1.6  christos 
   1669   1.6  christos 	*nodep = node;
   1670   1.6  christos 
   1671  1.23  christos 	return ISC_R_SUCCESS;
   1672   1.6  christos }
   1673   1.6  christos 
   1674   1.6  christos /*
   1675   1.6  christos  * For query context 'qctx', try finding authoritative additional data for
   1676   1.6  christos  * given 'name' and 'type'. Called from query_additional_cb().
   1677   1.6  christos  *
   1678   1.6  christos  * If successful:
   1679   1.6  christos  *
   1680   1.6  christos  *   - store pointers to the database and node which contain the result in
   1681   1.6  christos  *     'dbp' and 'nodep', respectively,
   1682   1.6  christos  *
   1683   1.6  christos  *   - store the owner name of the returned node in 'fname',
   1684   1.6  christos  *
   1685   1.6  christos  *   - potentially bind 'rdataset' and 'sigrdataset', as explained in the
   1686   1.6  christos  *     comment for query_additionalauthfind().
   1687   1.6  christos  *
   1688   1.6  christos  * If unsuccessful:
   1689   1.6  christos  *
   1690   1.6  christos  *   - 'dbp' and 'nodep' will not be written to,
   1691   1.6  christos  *   - 'fname' may still be modified as it is passed to dns_db_findext(),
   1692   1.6  christos  *   - 'rdataset' and 'sigrdataset' will remain disassociated.
   1693   1.6  christos  */
   1694   1.6  christos static isc_result_t
   1695   1.6  christos query_additionalauth(query_ctx_t *qctx, const dns_name_t *name,
   1696   1.9  christos 		     dns_rdatatype_t type, dns_db_t **dbp, dns_dbnode_t **nodep,
   1697   1.9  christos 		     dns_name_t *fname, dns_rdataset_t *rdataset,
   1698   1.9  christos 		     dns_rdataset_t *sigrdataset) {
   1699   1.6  christos 	ns_client_t *client = qctx->client;
   1700   1.6  christos 	ns_dbversion_t *dbversion = NULL;
   1701   1.6  christos 	dns_dbversion_t *version = NULL;
   1702   1.6  christos 	dns_dbnode_t *node = NULL;
   1703   1.6  christos 	dns_zone_t *zone = NULL;
   1704   1.6  christos 	dns_db_t *db = NULL;
   1705   1.6  christos 	isc_result_t result;
   1706   1.6  christos 
   1707   1.6  christos 	/*
   1708   1.6  christos 	 * First, look within the same zone database for authoritative
   1709   1.6  christos 	 * additional data.
   1710   1.6  christos 	 */
   1711   1.6  christos 	if (!client->query.authdbset || client->query.authdb == NULL) {
   1712  1.23  christos 		return ISC_R_NOTFOUND;
   1713   1.6  christos 	}
   1714   1.6  christos 
   1715   1.6  christos 	dbversion = ns_client_findversion(client, client->query.authdb);
   1716   1.6  christos 	if (dbversion == NULL) {
   1717  1.23  christos 		return ISC_R_NOTFOUND;
   1718   1.6  christos 	}
   1719   1.6  christos 
   1720   1.6  christos 	dns_db_attach(client->query.authdb, &db);
   1721   1.6  christos 	version = dbversion->version;
   1722   1.6  christos 
   1723   1.6  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: same zone");
   1724   1.6  christos 
   1725   1.6  christos 	result = query_additionalauthfind(db, version, name, type, client,
   1726   1.6  christos 					  &node, fname, rdataset, sigrdataset);
   1727   1.6  christos 	if (result != ISC_R_SUCCESS &&
   1728   1.6  christos 	    qctx->view->minimalresponses == dns_minimal_no &&
   1729   1.6  christos 	    RECURSIONOK(client))
   1730   1.6  christos 	{
   1731   1.6  christos 		/*
   1732   1.6  christos 		 * If we aren't doing response minimization and recursion is
   1733   1.6  christos 		 * allowed, we can try and see if any other zone matches.
   1734   1.6  christos 		 */
   1735   1.6  christos 		version = NULL;
   1736   1.6  christos 		dns_db_detach(&db);
   1737  1.23  christos 		dns_getdb_options_t options = { .nolog = true };
   1738  1.23  christos 		result = query_getzonedb(client, name, type, options, &zone,
   1739  1.23  christos 					 &db, &version);
   1740   1.6  christos 		if (result != ISC_R_SUCCESS) {
   1741  1.23  christos 			return result;
   1742   1.6  christos 		}
   1743   1.6  christos 		dns_zone_detach(&zone);
   1744   1.6  christos 
   1745   1.6  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: other zone");
   1746   1.6  christos 
   1747   1.6  christos 		result = query_additionalauthfind(db, version, name, type,
   1748   1.6  christos 						  client, &node, fname,
   1749   1.6  christos 						  rdataset, sigrdataset);
   1750   1.6  christos 	}
   1751   1.6  christos 
   1752   1.6  christos 	if (result != ISC_R_SUCCESS) {
   1753   1.6  christos 		dns_db_detach(&db);
   1754   1.6  christos 	} else {
   1755   1.6  christos 		*nodep = node;
   1756   1.6  christos 		node = NULL;
   1757   1.6  christos 
   1758   1.6  christos 		*dbp = db;
   1759   1.6  christos 		db = NULL;
   1760   1.6  christos 	}
   1761   1.6  christos 
   1762  1.23  christos 	return result;
   1763   1.6  christos }
   1764   1.6  christos 
   1765   1.1  christos static isc_result_t
   1766  1.20  christos query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
   1767  1.23  christos 		    dns_rdataset_t *found DNS__DB_FLARG) {
   1768   1.3  christos 	query_ctx_t *qctx = arg;
   1769   1.3  christos 	ns_client_t *client = qctx->client;
   1770   1.3  christos 	isc_result_t result, eresult = ISC_R_SUCCESS;
   1771   1.3  christos 	dns_dbnode_t *node = NULL;
   1772   1.3  christos 	dns_db_t *db = NULL;
   1773   1.3  christos 	dns_name_t *fname = NULL, *mname = NULL;
   1774   1.3  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   1775   1.3  christos 	dns_rdataset_t *trdataset = NULL;
   1776   1.3  christos 	isc_buffer_t *dbuf = NULL;
   1777   1.1  christos 	isc_buffer_t b;
   1778   1.3  christos 	ns_dbversion_t *dbversion = NULL;
   1779   1.3  christos 	dns_dbversion_t *version = NULL;
   1780   1.3  christos 	bool added_something = false, need_addname = false;
   1781   1.1  christos 	dns_rdatatype_t type;
   1782   1.1  christos 	dns_clientinfomethods_t cm;
   1783   1.1  christos 	dns_clientinfo_t ci;
   1784   1.3  christos 	dns_rdatasetadditional_t additionaltype =
   1785   1.3  christos 		dns_rdatasetadditional_fromauth;
   1786   1.1  christos 
   1787   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   1788   1.1  christos 	REQUIRE(qtype != dns_rdatatype_any);
   1789   1.1  christos 
   1790   1.3  christos 	if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) {
   1791  1.23  christos 		return ISC_R_SUCCESS;
   1792   1.3  christos 	}
   1793   1.1  christos 
   1794   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb");
   1795   1.1  christos 
   1796   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1797  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   1798   1.1  christos 
   1799   1.1  christos 	/*
   1800   1.1  christos 	 * We treat type A additional section processing as if it
   1801   1.1  christos 	 * were "any address type" additional section processing.
   1802   1.1  christos 	 * To avoid multiple lookups, we do an 'any' database
   1803   1.1  christos 	 * lookup and iterate over the node.
   1804   1.1  christos 	 */
   1805   1.3  christos 	if (qtype == dns_rdatatype_a) {
   1806   1.1  christos 		type = dns_rdatatype_any;
   1807   1.3  christos 	} else {
   1808   1.1  christos 		type = qtype;
   1809   1.3  christos 	}
   1810   1.1  christos 
   1811   1.1  christos 	/*
   1812   1.1  christos 	 * Get some resources.
   1813   1.1  christos 	 */
   1814   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   1815   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   1816   1.3  christos 	rdataset = ns_client_newrdataset(client);
   1817   1.1  christos 	if (WANTDNSSEC(client)) {
   1818   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   1819   1.1  christos 	}
   1820   1.1  christos 
   1821   1.1  christos 	/*
   1822   1.1  christos 	 * If we want only minimal responses and are here, then it must
   1823   1.1  christos 	 * be for glue.
   1824   1.1  christos 	 */
   1825  1.11  christos 	if (qctx->view->minimalresponses == dns_minimal_yes &&
   1826  1.11  christos 	    client->query.qtype != dns_rdatatype_ns)
   1827  1.11  christos 	{
   1828   1.1  christos 		goto try_glue;
   1829   1.3  christos 	}
   1830   1.1  christos 
   1831   1.1  christos 	/*
   1832   1.6  christos 	 * First, look for authoritative additional data.
   1833   1.1  christos 	 */
   1834   1.6  christos 	result = query_additionalauth(qctx, name, type, &db, &node, fname,
   1835   1.6  christos 				      rdataset, sigrdataset);
   1836   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1837   1.1  christos 		goto found;
   1838   1.1  christos 	}
   1839   1.1  christos 
   1840   1.1  christos 	/*
   1841   1.1  christos 	 * No authoritative data was found.  The cache is our next best bet.
   1842   1.1  christos 	 */
   1843   1.3  christos 	if (!qctx->view->recursion) {
   1844   1.1  christos 		goto try_glue;
   1845   1.3  christos 	}
   1846   1.1  christos 
   1847   1.1  christos 	additionaltype = dns_rdatasetadditional_fromcache;
   1848  1.23  christos 	dns_getdb_options_t options = { .nolog = true };
   1849  1.23  christos 	result = query_getcachedb(client, name, qtype, &db, options);
   1850   1.1  christos 	if (result != ISC_R_SUCCESS) {
   1851   1.1  christos 		/*
   1852   1.1  christos 		 * Most likely the client isn't allowed to query the cache.
   1853   1.1  christos 		 */
   1854   1.1  christos 		goto try_glue;
   1855   1.1  christos 	}
   1856   1.1  christos 	/*
   1857   1.1  christos 	 * Attempt to validate glue.
   1858   1.1  christos 	 */
   1859   1.1  christos 	if (sigrdataset == NULL) {
   1860   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   1861   1.1  christos 	}
   1862   1.1  christos 
   1863   1.1  christos 	version = NULL;
   1864   1.1  christos 	result = dns_db_findext(db, name, version, type,
   1865   1.9  christos 				client->query.dboptions | DNS_DBFIND_GLUEOK |
   1866   1.9  christos 					DNS_DBFIND_ADDITIONALOK,
   1867   1.9  christos 				client->now, &node, fname, &cm, &ci, rdataset,
   1868   1.9  christos 				sigrdataset);
   1869   1.1  christos 
   1870   1.3  christos 	dns_cache_updatestats(qctx->view->cache, result);
   1871   1.3  christos 	if (!WANTDNSSEC(client)) {
   1872   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   1873   1.3  christos 	}
   1874   1.9  christos 	if (result == ISC_R_SUCCESS) {
   1875   1.1  christos 		goto found;
   1876   1.9  christos 	}
   1877   1.1  christos 
   1878   1.3  christos 	if (dns_rdataset_isassociated(rdataset)) {
   1879   1.1  christos 		dns_rdataset_disassociate(rdataset);
   1880   1.3  christos 	}
   1881   1.3  christos 	if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
   1882   1.1  christos 		dns_rdataset_disassociate(sigrdataset);
   1883   1.3  christos 	}
   1884   1.3  christos 	if (node != NULL) {
   1885   1.1  christos 		dns_db_detachnode(db, &node);
   1886   1.3  christos 	}
   1887   1.1  christos 	dns_db_detach(&db);
   1888   1.1  christos 
   1889   1.9  christos try_glue:
   1890   1.1  christos 	/*
   1891   1.1  christos 	 * No cached data was found.  Glue is our last chance.
   1892   1.1  christos 	 * RFC1035 sayeth:
   1893   1.1  christos 	 *
   1894   1.1  christos 	 *	NS records cause both the usual additional section
   1895   1.1  christos 	 *	processing to locate a type A record, and, when used
   1896   1.1  christos 	 *	in a referral, a special search of the zone in which
   1897   1.1  christos 	 *	they reside for glue information.
   1898   1.1  christos 	 *
   1899   1.1  christos 	 * This is the "special search".  Note that we must search
   1900   1.1  christos 	 * the zone where the NS record resides, not the zone it
   1901   1.1  christos 	 * points to, and that we only do the search in the delegation
   1902   1.1  christos 	 * case (identified by client->query.gluedb being set).
   1903   1.1  christos 	 */
   1904   1.1  christos 
   1905   1.3  christos 	if (client->query.gluedb == NULL) {
   1906   1.1  christos 		goto cleanup;
   1907   1.3  christos 	}
   1908   1.1  christos 
   1909   1.1  christos 	/*
   1910   1.1  christos 	 * Don't poison caches using the bailiwick protection model.
   1911   1.1  christos 	 */
   1912   1.3  christos 	if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) {
   1913   1.1  christos 		goto cleanup;
   1914   1.3  christos 	}
   1915   1.1  christos 
   1916   1.3  christos 	dbversion = ns_client_findversion(client, client->query.gluedb);
   1917   1.3  christos 	if (dbversion == NULL) {
   1918   1.1  christos 		goto cleanup;
   1919   1.3  christos 	}
   1920   1.1  christos 
   1921   1.1  christos 	dns_db_attach(client->query.gluedb, &db);
   1922   1.1  christos 	version = dbversion->version;
   1923   1.1  christos 	additionaltype = dns_rdatasetadditional_fromglue;
   1924   1.1  christos 	result = dns_db_findext(db, name, version, type,
   1925   1.1  christos 				client->query.dboptions | DNS_DBFIND_GLUEOK,
   1926   1.9  christos 				client->now, &node, fname, &cm, &ci, rdataset,
   1927   1.9  christos 				sigrdataset);
   1928   1.9  christos 	if (result != ISC_R_SUCCESS && result != DNS_R_ZONECUT &&
   1929  1.16  christos 	    result != DNS_R_GLUE)
   1930  1.16  christos 	{
   1931   1.1  christos 		goto cleanup;
   1932   1.3  christos 	}
   1933   1.1  christos 
   1934   1.9  christos found:
   1935   1.1  christos 	/*
   1936   1.1  christos 	 * We have found a potential additional data rdataset, or
   1937   1.1  christos 	 * at least a node to iterate over.
   1938   1.1  christos 	 */
   1939   1.3  christos 	ns_client_keepname(client, fname, dbuf);
   1940   1.1  christos 
   1941   1.1  christos 	/*
   1942  1.20  christos 	 * Does the caller want the found rdataset?
   1943  1.20  christos 	 */
   1944  1.20  christos 	if (found != NULL && dns_rdataset_isassociated(rdataset)) {
   1945  1.20  christos 		dns_rdataset_clone(rdataset, found);
   1946  1.20  christos 	}
   1947  1.20  christos 
   1948  1.20  christos 	/*
   1949   1.1  christos 	 * If we have an rdataset, add it to the additional data
   1950   1.1  christos 	 * section.
   1951   1.1  christos 	 */
   1952   1.1  christos 	mname = NULL;
   1953   1.1  christos 	if (dns_rdataset_isassociated(rdataset) &&
   1954   1.3  christos 	    !query_isduplicate(client, fname, type, &mname))
   1955   1.3  christos 	{
   1956   1.1  christos 		if (mname != NULL) {
   1957   1.1  christos 			INSIST(mname != fname);
   1958   1.3  christos 			ns_client_releasename(client, &fname);
   1959   1.1  christos 			fname = mname;
   1960   1.3  christos 		} else {
   1961   1.3  christos 			need_addname = true;
   1962   1.3  christos 		}
   1963   1.1  christos 		ISC_LIST_APPEND(fname->list, rdataset, link);
   1964   1.1  christos 		trdataset = rdataset;
   1965   1.1  christos 		rdataset = NULL;
   1966   1.3  christos 		added_something = true;
   1967   1.1  christos 		/*
   1968   1.1  christos 		 * Note: we only add SIGs if we've added the type they cover,
   1969   1.1  christos 		 * so we do not need to check if the SIG rdataset is already
   1970   1.1  christos 		 * in the response.
   1971   1.1  christos 		 */
   1972   1.1  christos 		if (sigrdataset != NULL &&
   1973  1.16  christos 		    dns_rdataset_isassociated(sigrdataset))
   1974  1.16  christos 		{
   1975   1.1  christos 			ISC_LIST_APPEND(fname->list, sigrdataset, link);
   1976   1.1  christos 			sigrdataset = NULL;
   1977   1.1  christos 		}
   1978   1.1  christos 	}
   1979   1.1  christos 
   1980   1.1  christos 	if (qtype == dns_rdatatype_a) {
   1981   1.1  christos 		/*
   1982   1.1  christos 		 * We now go looking for A and AAAA records, along with
   1983   1.1  christos 		 * their signatures.
   1984   1.1  christos 		 *
   1985   1.1  christos 		 * XXXRTH  This code could be more efficient.
   1986   1.1  christos 		 */
   1987   1.1  christos 		if (rdataset != NULL) {
   1988   1.3  christos 			if (dns_rdataset_isassociated(rdataset)) {
   1989   1.1  christos 				dns_rdataset_disassociate(rdataset);
   1990   1.3  christos 			}
   1991   1.1  christos 		} else {
   1992   1.3  christos 			rdataset = ns_client_newrdataset(client);
   1993   1.1  christos 		}
   1994   1.1  christos 		if (sigrdataset != NULL) {
   1995   1.3  christos 			if (dns_rdataset_isassociated(sigrdataset)) {
   1996   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   1997   1.3  christos 			}
   1998   1.1  christos 		} else if (WANTDNSSEC(client)) {
   1999   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   2000   1.1  christos 		}
   2001   1.3  christos 		if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) {
   2002   1.1  christos 			goto aaaa_lookup;
   2003   1.3  christos 		}
   2004   1.9  christos 		result = dns_db_findrdataset(db, node, version, dns_rdatatype_a,
   2005   1.9  christos 					     0, client->now, rdataset,
   2006   1.9  christos 					     sigrdataset);
   2007   1.1  christos 		if (result == DNS_R_NCACHENXDOMAIN) {
   2008   1.1  christos 			goto addname;
   2009   1.1  christos 		} else if (result == DNS_R_NCACHENXRRSET) {
   2010   1.1  christos 			dns_rdataset_disassociate(rdataset);
   2011   1.1  christos 			if (sigrdataset != NULL &&
   2012  1.16  christos 			    dns_rdataset_isassociated(sigrdataset))
   2013  1.16  christos 			{
   2014   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   2015   1.3  christos 			}
   2016   1.1  christos 		} else if (result == ISC_R_SUCCESS) {
   2017   1.3  christos 			bool invalid = false;
   2018   1.1  christos 			mname = NULL;
   2019   1.1  christos 			if (additionaltype ==
   2020   1.9  christos 				    dns_rdatasetadditional_fromcache &&
   2021   1.1  christos 			    (DNS_TRUST_PENDING(rdataset->trust) ||
   2022   1.1  christos 			     DNS_TRUST_GLUE(rdataset->trust)))
   2023   1.1  christos 			{
   2024   1.1  christos 				/* validate() may change rdataset->trust */
   2025   1.9  christos 				invalid = !validate(client, db, fname, rdataset,
   2026   1.9  christos 						    sigrdataset);
   2027   1.1  christos 			}
   2028   1.1  christos 			if (invalid && DNS_TRUST_PENDING(rdataset->trust)) {
   2029   1.1  christos 				dns_rdataset_disassociate(rdataset);
   2030   1.1  christos 				if (sigrdataset != NULL &&
   2031  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2032  1.16  christos 				{
   2033   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   2034   1.3  christos 				}
   2035   1.1  christos 			} else if (!query_isduplicate(client, fname,
   2036   1.9  christos 						      dns_rdatatype_a, &mname))
   2037   1.9  christos 			{
   2038   1.1  christos 				if (mname != fname) {
   2039   1.1  christos 					if (mname != NULL) {
   2040   1.3  christos 						ns_client_releasename(client,
   2041   1.3  christos 								      &fname);
   2042   1.1  christos 						fname = mname;
   2043   1.3  christos 					} else {
   2044   1.3  christos 						need_addname = true;
   2045   1.3  christos 					}
   2046   1.1  christos 				}
   2047   1.1  christos 				ISC_LIST_APPEND(fname->list, rdataset, link);
   2048   1.3  christos 				added_something = true;
   2049   1.1  christos 				if (sigrdataset != NULL &&
   2050  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2051  1.16  christos 				{
   2052   1.1  christos 					ISC_LIST_APPEND(fname->list,
   2053   1.1  christos 							sigrdataset, link);
   2054   1.1  christos 					sigrdataset =
   2055   1.3  christos 						ns_client_newrdataset(client);
   2056   1.1  christos 				}
   2057   1.3  christos 				rdataset = ns_client_newrdataset(client);
   2058   1.1  christos 			} else {
   2059   1.1  christos 				dns_rdataset_disassociate(rdataset);
   2060   1.1  christos 				if (sigrdataset != NULL &&
   2061  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2062  1.16  christos 				{
   2063   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   2064   1.3  christos 				}
   2065   1.1  christos 			}
   2066   1.1  christos 		}
   2067   1.9  christos 	aaaa_lookup:
   2068   1.1  christos 		if (query_isduplicate(client, fname, dns_rdatatype_aaaa, NULL))
   2069   1.3  christos 		{
   2070   1.1  christos 			goto addname;
   2071   1.3  christos 		}
   2072   1.1  christos 		result = dns_db_findrdataset(db, node, version,
   2073   1.9  christos 					     dns_rdatatype_aaaa, 0, client->now,
   2074   1.1  christos 					     rdataset, sigrdataset);
   2075   1.1  christos 		if (result == DNS_R_NCACHENXDOMAIN) {
   2076   1.1  christos 			goto addname;
   2077   1.1  christos 		} else if (result == DNS_R_NCACHENXRRSET) {
   2078   1.1  christos 			dns_rdataset_disassociate(rdataset);
   2079   1.1  christos 			if (sigrdataset != NULL &&
   2080  1.16  christos 			    dns_rdataset_isassociated(sigrdataset))
   2081  1.16  christos 			{
   2082   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   2083   1.3  christos 			}
   2084   1.1  christos 		} else if (result == ISC_R_SUCCESS) {
   2085   1.3  christos 			bool invalid = false;
   2086   1.1  christos 			mname = NULL;
   2087   1.3  christos 
   2088   1.1  christos 			if (additionaltype ==
   2089   1.9  christos 				    dns_rdatasetadditional_fromcache &&
   2090   1.1  christos 			    (DNS_TRUST_PENDING(rdataset->trust) ||
   2091   1.1  christos 			     DNS_TRUST_GLUE(rdataset->trust)))
   2092   1.1  christos 			{
   2093   1.1  christos 				/* validate() may change rdataset->trust */
   2094   1.9  christos 				invalid = !validate(client, db, fname, rdataset,
   2095   1.9  christos 						    sigrdataset);
   2096   1.1  christos 			}
   2097   1.1  christos 
   2098   1.1  christos 			if (invalid && DNS_TRUST_PENDING(rdataset->trust)) {
   2099   1.1  christos 				dns_rdataset_disassociate(rdataset);
   2100   1.1  christos 				if (sigrdataset != NULL &&
   2101  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2102  1.16  christos 				{
   2103   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   2104   1.3  christos 				}
   2105   1.1  christos 			} else if (!query_isduplicate(client, fname,
   2106   1.9  christos 						      dns_rdatatype_aaaa,
   2107  1.16  christos 						      &mname))
   2108  1.16  christos 			{
   2109   1.1  christos 				if (mname != fname) {
   2110   1.1  christos 					if (mname != NULL) {
   2111   1.3  christos 						ns_client_releasename(client,
   2112   1.3  christos 								      &fname);
   2113   1.1  christos 						fname = mname;
   2114   1.3  christos 					} else {
   2115   1.3  christos 						need_addname = true;
   2116   1.3  christos 					}
   2117   1.1  christos 				}
   2118   1.1  christos 				ISC_LIST_APPEND(fname->list, rdataset, link);
   2119   1.3  christos 				added_something = true;
   2120   1.1  christos 				if (sigrdataset != NULL &&
   2121  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2122  1.16  christos 				{
   2123   1.1  christos 					ISC_LIST_APPEND(fname->list,
   2124   1.1  christos 							sigrdataset, link);
   2125   1.1  christos 					sigrdataset = NULL;
   2126   1.1  christos 				}
   2127   1.1  christos 				rdataset = NULL;
   2128   1.1  christos 			}
   2129   1.1  christos 		}
   2130   1.1  christos 	}
   2131   1.1  christos 
   2132   1.9  christos addname:
   2133   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: addname");
   2134   1.1  christos 	/*
   2135   1.1  christos 	 * If we haven't added anything, then we're done.
   2136   1.1  christos 	 */
   2137   1.3  christos 	if (!added_something) {
   2138   1.1  christos 		goto cleanup;
   2139   1.3  christos 	}
   2140   1.1  christos 
   2141   1.1  christos 	/*
   2142   1.1  christos 	 * We may have added our rdatasets to an existing name, if so, then
   2143   1.3  christos 	 * need_addname will be false.  Whether we used an existing name
   2144   1.1  christos 	 * or a new one, we must set fname to NULL to prevent cleanup.
   2145   1.1  christos 	 */
   2146   1.3  christos 	if (need_addname) {
   2147   1.1  christos 		dns_message_addname(client->message, fname,
   2148   1.1  christos 				    DNS_SECTION_ADDITIONAL);
   2149   1.3  christos 	}
   2150   1.1  christos 
   2151   1.1  christos 	/*
   2152  1.15  christos 	 * In some cases, a record that has been added as additional
   2153  1.15  christos 	 * data may *also* trigger the addition of additional data.
   2154  1.22  christos 	 * This cannot go more than 'max-restarts' levels deep.
   2155  1.15  christos 	 */
   2156  1.15  christos 	if (trdataset != NULL && dns_rdatatype_followadditional(type)) {
   2157  1.22  christos 		if (client->additionaldepth++ < client->view->max_restarts) {
   2158  1.20  christos 			eresult = dns_rdataset_additionaldata(
   2159  1.24  christos 				trdataset, fname, query_additional_cb, qctx,
   2160  1.24  christos 				DNS_RDATASET_MAXADDITIONAL);
   2161  1.20  christos 		}
   2162  1.20  christos 		client->additionaldepth--;
   2163   1.1  christos 	}
   2164   1.1  christos 
   2165  1.20  christos 	/*
   2166  1.20  christos 	 * Don't release fname.
   2167  1.20  christos 	 */
   2168  1.20  christos 	fname = NULL;
   2169  1.20  christos 
   2170   1.9  christos cleanup:
   2171   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup");
   2172   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   2173   1.3  christos 	if (sigrdataset != NULL) {
   2174   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   2175   1.3  christos 	}
   2176   1.3  christos 	if (fname != NULL) {
   2177   1.3  christos 		ns_client_releasename(client, &fname);
   2178   1.3  christos 	}
   2179   1.3  christos 	if (node != NULL) {
   2180   1.1  christos 		dns_db_detachnode(db, &node);
   2181   1.3  christos 	}
   2182   1.3  christos 	if (db != NULL) {
   2183   1.1  christos 		dns_db_detach(&db);
   2184   1.3  christos 	}
   2185   1.1  christos 
   2186   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: done");
   2187  1.23  christos 	return eresult;
   2188   1.1  christos }
   2189   1.1  christos 
   2190   1.3  christos /*
   2191   1.3  christos  * Add 'rdataset' to 'name'.
   2192   1.3  christos  */
   2193  1.15  christos static void
   2194   1.3  christos query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) {
   2195   1.3  christos 	ISC_LIST_APPEND(name->list, rdataset, link);
   2196   1.3  christos }
   2197   1.3  christos 
   2198   1.3  christos /*
   2199   1.3  christos  * Set the ordering for 'rdataset'.
   2200   1.3  christos  */
   2201   1.1  christos static void
   2202   1.3  christos query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) {
   2203   1.3  christos 	ns_client_t *client = qctx->client;
   2204   1.3  christos 	dns_order_t *order = client->view->order;
   2205   1.1  christos 
   2206   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_setorder");
   2207   1.1  christos 
   2208   1.3  christos 	UNUSED(client);
   2209   1.1  christos 
   2210   1.3  christos 	if (order != NULL) {
   2211   1.9  christos 		rdataset->attributes |= dns_order_find(
   2212   1.9  christos 			order, name, rdataset->type, rdataset->rdclass);
   2213   1.3  christos 	}
   2214   1.1  christos 	rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
   2215   1.9  christos }
   2216   1.3  christos 
   2217   1.3  christos /*
   2218   1.3  christos  * Handle glue and fetch any other needed additional data for 'rdataset'.
   2219   1.3  christos  */
   2220   1.3  christos static void
   2221  1.20  christos query_additional(query_ctx_t *qctx, dns_name_t *name,
   2222  1.20  christos 		 dns_rdataset_t *rdataset) {
   2223   1.3  christos 	ns_client_t *client = qctx->client;
   2224   1.3  christos 	isc_result_t result;
   2225   1.3  christos 
   2226   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional");
   2227   1.1  christos 
   2228   1.3  christos 	if (NOADDITIONAL(client)) {
   2229   1.1  christos 		return;
   2230   1.3  christos 	}
   2231   1.1  christos 
   2232   1.1  christos 	/*
   2233   1.1  christos 	 * Try to process glue directly.
   2234   1.1  christos 	 */
   2235  1.23  christos 	if (rdataset->type == dns_rdatatype_ns &&
   2236  1.23  christos 	    client->query.gluedb != NULL && dns_db_iszone(client->query.gluedb))
   2237   1.1  christos 	{
   2238  1.23  christos 		ns_dbversion_t *dbversion = NULL;
   2239   1.1  christos 
   2240   1.3  christos 		dbversion = ns_client_findversion(client, client->query.gluedb);
   2241   1.3  christos 		if (dbversion == NULL) {
   2242   1.1  christos 			goto regular;
   2243   1.1  christos 		}
   2244   1.1  christos 
   2245  1.23  christos 		result = dns_db_addglue(qctx->db, dbversion->version, rdataset,
   2246  1.23  christos 					client->message);
   2247   1.3  christos 		if (result == ISC_R_SUCCESS) {
   2248   1.1  christos 			return;
   2249   1.3  christos 		}
   2250   1.1  christos 	}
   2251   1.1  christos 
   2252   1.9  christos regular:
   2253   1.1  christos 	/*
   2254   1.3  christos 	 * Add other additional data if needed.
   2255   1.1  christos 	 * We don't care if dns_rdataset_additionaldata() fails.
   2256   1.1  christos 	 */
   2257  1.20  christos 	(void)dns_rdataset_additionaldata(rdataset, name, query_additional_cb,
   2258  1.24  christos 					  qctx, DNS_RDATASET_MAXADDITIONAL);
   2259   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional: done");
   2260   1.1  christos }
   2261   1.1  christos 
   2262   1.1  christos static void
   2263   1.3  christos query_addrrset(query_ctx_t *qctx, dns_name_t **namep,
   2264   1.1  christos 	       dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,
   2265   1.9  christos 	       isc_buffer_t *dbuf, dns_section_t section) {
   2266   1.3  christos 	isc_result_t result;
   2267   1.3  christos 	ns_client_t *client = qctx->client;
   2268   1.1  christos 	dns_name_t *name = *namep, *mname = NULL;
   2269   1.1  christos 	dns_rdataset_t *rdataset = *rdatasetp, *mrdataset = NULL;
   2270   1.1  christos 	dns_rdataset_t *sigrdataset = NULL;
   2271   1.1  christos 
   2272   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addrrset");
   2273   1.1  christos 
   2274   1.3  christos 	REQUIRE(name != NULL);
   2275   1.3  christos 
   2276   1.3  christos 	if (sigrdatasetp != NULL) {
   2277   1.1  christos 		sigrdataset = *sigrdatasetp;
   2278   1.3  christos 	}
   2279   1.1  christos 
   2280   1.1  christos 	/*%
   2281   1.1  christos 	 * To the current response for 'client', add the answer RRset
   2282   1.1  christos 	 * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
   2283   1.1  christos 	 * owner name '*namep', to section 'section', unless they are
   2284  1.24  christos 	 * already there.  Also add any pertinent additional data, unless
   2285  1.24  christos 	 * the query was for type ANY.
   2286   1.1  christos 	 *
   2287   1.1  christos 	 * If 'dbuf' is not NULL, then '*namep' is the name whose data is
   2288   1.1  christos 	 * stored in 'dbuf'.  In this case, query_addrrset() guarantees that
   2289   1.1  christos 	 * when it returns the name will either have been kept or released.
   2290   1.1  christos 	 */
   2291   1.9  christos 	result = dns_message_findname(client->message, section, name,
   2292   1.9  christos 				      rdataset->type, rdataset->covers, &mname,
   2293   1.9  christos 				      &mrdataset);
   2294   1.1  christos 	if (result == ISC_R_SUCCESS) {
   2295   1.1  christos 		/*
   2296   1.1  christos 		 * We've already got an RRset of the given name and type.
   2297   1.1  christos 		 */
   2298   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: dns_message_findname "
   2299   1.9  christos 					 "succeeded: done");
   2300   1.3  christos 		if (dbuf != NULL) {
   2301   1.3  christos 			ns_client_releasename(client, namep);
   2302   1.3  christos 		}
   2303   1.3  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) {
   2304   1.1  christos 			mrdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   2305   1.3  christos 		}
   2306   1.1  christos 		return;
   2307   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   2308   1.1  christos 		/*
   2309   1.1  christos 		 * The name doesn't exist.
   2310   1.1  christos 		 */
   2311   1.3  christos 		if (dbuf != NULL) {
   2312   1.3  christos 			ns_client_keepname(client, name, dbuf);
   2313   1.3  christos 		}
   2314   1.1  christos 		dns_message_addname(client->message, name, section);
   2315   1.1  christos 		*namep = NULL;
   2316   1.1  christos 		mname = name;
   2317   1.1  christos 	} else {
   2318   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   2319   1.3  christos 		if (dbuf != NULL) {
   2320   1.3  christos 			ns_client_releasename(client, namep);
   2321   1.3  christos 		}
   2322   1.1  christos 	}
   2323   1.1  christos 
   2324   1.1  christos 	if (rdataset->trust != dns_trust_secure &&
   2325   1.9  christos 	    (section == DNS_SECTION_ANSWER || section == DNS_SECTION_AUTHORITY))
   2326   1.3  christos 	{
   2327   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   2328   1.3  christos 	}
   2329   1.3  christos 
   2330   1.3  christos 	/*
   2331   1.3  christos 	 * Update message name, set rdataset order, and do additional
   2332   1.3  christos 	 * section processing if needed.
   2333   1.3  christos 	 */
   2334   1.3  christos 	query_addtoname(mname, rdataset);
   2335   1.3  christos 	query_setorder(qctx, mname, rdataset);
   2336  1.26  christos 	if (qctx->qtype != dns_rdatatype_any ||
   2337  1.26  christos 	    (!qctx->authoritative && section == DNS_SECTION_AUTHORITY &&
   2338  1.26  christos 	     rdataset->type == dns_rdatatype_ns))
   2339  1.26  christos 	{
   2340  1.24  christos 		query_additional(qctx, mname, rdataset);
   2341  1.24  christos 	}
   2342   1.1  christos 
   2343   1.1  christos 	/*
   2344   1.1  christos 	 * Note: we only add SIGs if we've added the type they cover, so
   2345   1.1  christos 	 * we do not need to check if the SIG rdataset is already in the
   2346   1.1  christos 	 * response.
   2347   1.1  christos 	 */
   2348   1.1  christos 	*rdatasetp = NULL;
   2349   1.1  christos 	if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
   2350   1.1  christos 		/*
   2351   1.1  christos 		 * We have a signature.  Add it to the response.
   2352   1.1  christos 		 */
   2353   1.1  christos 		ISC_LIST_APPEND(mname->list, sigrdataset, link);
   2354   1.1  christos 		*sigrdatasetp = NULL;
   2355   1.1  christos 	}
   2356   1.1  christos 
   2357   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: done");
   2358   1.1  christos }
   2359   1.1  christos 
   2360   1.1  christos /*
   2361   1.1  christos  * Mark the RRsets as secure.  Update the cache (db) to reflect the
   2362   1.1  christos  * change in trust level.
   2363   1.1  christos  */
   2364   1.1  christos static void
   2365   1.1  christos mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
   2366   1.1  christos 	    dns_rdata_rrsig_t *rrsig, dns_rdataset_t *rdataset,
   2367   1.9  christos 	    dns_rdataset_t *sigrdataset) {
   2368   1.1  christos 	isc_result_t result;
   2369   1.1  christos 	dns_dbnode_t *node = NULL;
   2370   1.1  christos 	dns_clientinfomethods_t cm;
   2371   1.1  christos 	dns_clientinfo_t ci;
   2372   1.1  christos 	isc_stdtime_t now;
   2373   1.1  christos 
   2374   1.1  christos 	rdataset->trust = dns_trust_secure;
   2375   1.1  christos 	sigrdataset->trust = dns_trust_secure;
   2376   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2377  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   2378   1.1  christos 
   2379   1.1  christos 	/*
   2380   1.1  christos 	 * Save the updated secure state.  Ignore failures.
   2381   1.1  christos 	 */
   2382   1.3  christos 	result = dns_db_findnodeext(db, name, true, &cm, &ci, &node);
   2383   1.9  christos 	if (result != ISC_R_SUCCESS) {
   2384   1.1  christos 		return;
   2385   1.9  christos 	}
   2386   1.1  christos 
   2387  1.23  christos 	now = isc_stdtime_now();
   2388   1.1  christos 	dns_rdataset_trimttl(rdataset, sigrdataset, rrsig, now,
   2389   1.1  christos 			     client->view->acceptexpired);
   2390   1.1  christos 
   2391   1.9  christos 	(void)dns_db_addrdataset(db, node, NULL, client->now, rdataset, 0,
   2392   1.9  christos 				 NULL);
   2393   1.9  christos 	(void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset, 0,
   2394   1.9  christos 				 NULL);
   2395   1.1  christos 	dns_db_detachnode(db, &node);
   2396   1.1  christos }
   2397   1.1  christos 
   2398   1.1  christos /*
   2399   1.1  christos  * Find the secure key that corresponds to rrsig.
   2400   1.1  christos  * Note: 'keyrdataset' maintains state between successive calls,
   2401   1.1  christos  * there may be multiple keys with the same keyid.
   2402   1.3  christos  * Return false if we have exhausted all the possible keys.
   2403   1.1  christos  */
   2404   1.3  christos static bool
   2405   1.1  christos get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
   2406   1.9  christos 	dns_rdataset_t *keyrdataset, dst_key_t **keyp) {
   2407   1.1  christos 	isc_result_t result;
   2408   1.1  christos 	dns_dbnode_t *node = NULL;
   2409   1.3  christos 	bool secure = false;
   2410   1.1  christos 	dns_clientinfomethods_t cm;
   2411   1.1  christos 	dns_clientinfo_t ci;
   2412   1.1  christos 
   2413   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2414  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   2415   1.1  christos 
   2416   1.1  christos 	if (!dns_rdataset_isassociated(keyrdataset)) {
   2417   1.9  christos 		result = dns_db_findnodeext(db, &rrsig->signer, false, &cm, &ci,
   2418   1.9  christos 					    &node);
   2419   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2420  1.23  christos 			return false;
   2421   1.9  christos 		}
   2422   1.1  christos 
   2423   1.1  christos 		result = dns_db_findrdataset(db, node, NULL,
   2424   1.1  christos 					     dns_rdatatype_dnskey, 0,
   2425   1.1  christos 					     client->now, keyrdataset, NULL);
   2426   1.1  christos 		dns_db_detachnode(db, &node);
   2427   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2428  1.23  christos 			return false;
   2429   1.9  christos 		}
   2430   1.1  christos 
   2431   1.9  christos 		if (keyrdataset->trust != dns_trust_secure) {
   2432  1.23  christos 			return false;
   2433   1.9  christos 		}
   2434   1.1  christos 
   2435   1.1  christos 		result = dns_rdataset_first(keyrdataset);
   2436   1.9  christos 	} else {
   2437   1.1  christos 		result = dns_rdataset_next(keyrdataset);
   2438   1.9  christos 	}
   2439   1.1  christos 
   2440   1.9  christos 	for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(keyrdataset))
   2441   1.9  christos 	{
   2442   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   2443   1.1  christos 		isc_buffer_t b;
   2444   1.1  christos 
   2445   1.1  christos 		dns_rdataset_current(keyrdataset, &rdata);
   2446   1.1  christos 		isc_buffer_init(&b, rdata.data, rdata.length);
   2447   1.1  christos 		isc_buffer_add(&b, rdata.length);
   2448   1.1  christos 		result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
   2449  1.23  christos 					 client->manager->mctx, keyp);
   2450   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2451   1.1  christos 			continue;
   2452   1.9  christos 		}
   2453   1.1  christos 		if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
   2454   1.1  christos 		    rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
   2455   1.9  christos 		    dst_key_iszonekey(*keyp))
   2456   1.9  christos 		{
   2457   1.3  christos 			secure = true;
   2458   1.1  christos 			break;
   2459   1.1  christos 		}
   2460   1.1  christos 		dst_key_free(keyp);
   2461   1.1  christos 	}
   2462  1.23  christos 	return secure;
   2463   1.1  christos }
   2464   1.1  christos 
   2465   1.3  christos static bool
   2466   1.1  christos verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset,
   2467   1.9  christos        dns_rdata_t *rdata, ns_client_t *client) {
   2468   1.1  christos 	isc_result_t result;
   2469   1.1  christos 	dns_fixedname_t fixed;
   2470   1.3  christos 	bool ignore = false;
   2471   1.1  christos 
   2472   1.1  christos 	dns_fixedname_init(&fixed);
   2473   1.1  christos 
   2474   1.1  christos again:
   2475   1.3  christos 	result = dns_dnssec_verify(name, rdataset, key, ignore,
   2476  1.23  christos 				   client->view->maxbits, client->manager->mctx,
   2477  1.23  christos 				   rdata, NULL);
   2478   1.1  christos 	if (result == DNS_R_SIGEXPIRED && client->view->acceptexpired) {
   2479   1.3  christos 		ignore = true;
   2480   1.1  christos 		goto again;
   2481   1.1  christos 	}
   2482   1.9  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
   2483  1.23  christos 		return true;
   2484   1.9  christos 	}
   2485  1.23  christos 	return false;
   2486   1.1  christos }
   2487   1.1  christos 
   2488   1.1  christos /*
   2489   1.1  christos  * Validate the rdataset if possible with available records.
   2490   1.1  christos  */
   2491   1.3  christos static bool
   2492   1.1  christos validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
   2493   1.9  christos 	 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
   2494   1.1  christos 	isc_result_t result;
   2495   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2496   1.1  christos 	dns_rdata_rrsig_t rrsig;
   2497   1.1  christos 	dst_key_t *key = NULL;
   2498   1.1  christos 	dns_rdataset_t keyrdataset;
   2499   1.1  christos 
   2500   1.9  christos 	if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)) {
   2501  1.23  christos 		return false;
   2502   1.9  christos 	}
   2503   1.1  christos 
   2504   1.9  christos 	for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
   2505   1.9  christos 	     result = dns_rdataset_next(sigrdataset))
   2506   1.9  christos 	{
   2507   1.1  christos 		dns_rdata_reset(&rdata);
   2508   1.1  christos 		dns_rdataset_current(sigrdataset, &rdata);
   2509   1.1  christos 		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
   2510   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2511   1.1  christos 		if (!dns_resolver_algorithm_supported(client->view->resolver,
   2512  1.26  christos 						      &rrsig.signer,
   2513  1.26  christos 						      rrsig.algorithm))
   2514   1.9  christos 		{
   2515  1.24  christos 			char txt[DNS_NAME_FORMATSIZE + 32];
   2516  1.24  christos 			isc_buffer_t buffer;
   2517  1.24  christos 
   2518  1.24  christos 			isc_buffer_init(&buffer, txt, sizeof(txt));
   2519  1.24  christos 			dns_secalg_totext(rrsig.algorithm, &buffer);
   2520  1.24  christos 			isc_buffer_putstr(&buffer, " ");
   2521  1.24  christos 			dns_name_totext(name, DNS_NAME_OMITFINALDOT, &buffer);
   2522  1.24  christos 			isc_buffer_putstr(&buffer, " (cached)");
   2523  1.24  christos 			isc_buffer_putuint8(&buffer, 0);
   2524  1.24  christos 
   2525  1.24  christos 			dns_ede_add(&client->edectx, DNS_EDE_DNSKEYALG,
   2526  1.24  christos 				    isc_buffer_base(&buffer));
   2527   1.1  christos 			continue;
   2528   1.9  christos 		}
   2529   1.9  christos 		if (!dns_name_issubdomain(name, &rrsig.signer)) {
   2530   1.1  christos 			continue;
   2531   1.9  christos 		}
   2532   1.1  christos 		dns_rdataset_init(&keyrdataset);
   2533   1.1  christos 		do {
   2534   1.9  christos 			if (!get_key(client, db, &rrsig, &keyrdataset, &key)) {
   2535   1.1  christos 				break;
   2536   1.9  christos 			}
   2537   1.1  christos 			if (verify(key, name, rdataset, &rdata, client)) {
   2538   1.1  christos 				dst_key_free(&key);
   2539   1.1  christos 				dns_rdataset_disassociate(&keyrdataset);
   2540   1.9  christos 				mark_secure(client, db, name, &rrsig, rdataset,
   2541   1.9  christos 					    sigrdataset);
   2542  1.23  christos 				return true;
   2543   1.1  christos 			}
   2544   1.1  christos 			dst_key_free(&key);
   2545   1.1  christos 		} while (1);
   2546   1.9  christos 		if (dns_rdataset_isassociated(&keyrdataset)) {
   2547   1.1  christos 			dns_rdataset_disassociate(&keyrdataset);
   2548   1.9  christos 		}
   2549   1.1  christos 	}
   2550  1.23  christos 	return false;
   2551   1.1  christos }
   2552   1.1  christos 
   2553   1.1  christos static void
   2554   1.1  christos fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) {
   2555   1.9  christos 	if (*rdataset == NULL) {
   2556   1.3  christos 		*rdataset = ns_client_newrdataset(client);
   2557   1.9  christos 	} else if (dns_rdataset_isassociated(*rdataset)) {
   2558   1.1  christos 		dns_rdataset_disassociate(*rdataset);
   2559   1.9  christos 	}
   2560   1.1  christos }
   2561   1.1  christos 
   2562   1.1  christos static void
   2563   1.1  christos fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf,
   2564   1.9  christos 	 isc_buffer_t *nbuf) {
   2565   1.1  christos 	if (*fname == NULL) {
   2566   1.3  christos 		*dbuf = ns_client_getnamebuf(client);
   2567   1.3  christos 		*fname = ns_client_newname(client, *dbuf, nbuf);
   2568   1.1  christos 	}
   2569   1.1  christos }
   2570   1.1  christos 
   2571   1.1  christos static void
   2572  1.23  christos free_fresp(ns_client_t *client, dns_fetchresponse_t **frespp) {
   2573  1.23  christos 	dns_fetchresponse_t *fresp = *frespp;
   2574   1.1  christos 
   2575  1.23  christos 	CTRACE(ISC_LOG_DEBUG(3), "free_fresp");
   2576   1.9  christos 
   2577  1.23  christos 	if (fresp->fetch != NULL) {
   2578  1.23  christos 		dns_resolver_destroyfetch(&fresp->fetch);
   2579  1.23  christos 	}
   2580  1.23  christos 	if (fresp->node != NULL) {
   2581  1.23  christos 		dns_db_detachnode(fresp->db, &fresp->node);
   2582   1.3  christos 	}
   2583  1.23  christos 	if (fresp->db != NULL) {
   2584  1.23  christos 		dns_db_detach(&fresp->db);
   2585   1.3  christos 	}
   2586  1.23  christos 	if (fresp->rdataset != NULL) {
   2587  1.23  christos 		ns_client_putrdataset(client, &fresp->rdataset);
   2588   1.3  christos 	}
   2589  1.23  christos 	if (fresp->sigrdataset != NULL) {
   2590  1.23  christos 		ns_client_putrdataset(client, &fresp->sigrdataset);
   2591   1.3  christos 	}
   2592  1.23  christos 
   2593  1.24  christos 	dns_resolver_freefresp(frespp);
   2594  1.23  christos }
   2595  1.23  christos 
   2596  1.23  christos static isc_result_t
   2597  1.23  christos recursionquotatype_attach(ns_client_t *client, bool soft_limit) {
   2598  1.23  christos 	isc_statscounter_t recurscount;
   2599  1.23  christos 	isc_result_t result;
   2600  1.23  christos 
   2601  1.23  christos 	result = isc_quota_acquire(&client->manager->sctx->recursionquota);
   2602  1.23  christos 	switch (result) {
   2603  1.23  christos 	case ISC_R_SUCCESS:
   2604  1.23  christos 		break;
   2605  1.23  christos 	case ISC_R_SOFTQUOTA:
   2606  1.23  christos 		if (soft_limit) {
   2607  1.23  christos 			/*
   2608  1.23  christos 			 * Exceeding soft quota was allowed, so continue as if
   2609  1.23  christos 			 * 'result' was ISC_R_SUCCESS while retaining the
   2610  1.23  christos 			 * original result code.
   2611  1.23  christos 			 */
   2612  1.23  christos 			break;
   2613  1.23  christos 		}
   2614  1.23  christos 
   2615  1.23  christos 		isc_quota_release(&client->manager->sctx->recursionquota);
   2616  1.23  christos 		FALLTHROUGH;
   2617  1.23  christos 	default:
   2618  1.23  christos 		return result;
   2619   1.3  christos 	}
   2620   1.9  christos 
   2621  1.23  christos 	recurscount = ns_stats_increment(client->manager->sctx->nsstats,
   2622  1.23  christos 					 ns_statscounter_recursclients);
   2623  1.23  christos 
   2624  1.23  christos 	ns_stats_update_if_greater(client->manager->sctx->nsstats,
   2625  1.23  christos 				   ns_statscounter_recurshighwater,
   2626  1.23  christos 				   recurscount + 1);
   2627  1.23  christos 
   2628  1.23  christos 	return result;
   2629  1.23  christos }
   2630  1.23  christos 
   2631  1.23  christos static isc_result_t
   2632  1.23  christos recursionquotatype_attach_hard(ns_client_t *client) {
   2633  1.23  christos 	return recursionquotatype_attach(client, false);
   2634  1.23  christos }
   2635  1.23  christos 
   2636  1.23  christos static isc_result_t
   2637  1.23  christos recursionquotatype_attach_soft(ns_client_t *client) {
   2638  1.23  christos 	return recursionquotatype_attach(client, true);
   2639  1.23  christos }
   2640  1.23  christos 
   2641  1.23  christos static void
   2642  1.23  christos recursionquotatype_detach(ns_client_t *client) {
   2643  1.23  christos 	isc_quota_release(&client->manager->sctx->recursionquota);
   2644  1.23  christos 	ns_stats_decrement(client->manager->sctx->nsstats,
   2645  1.23  christos 			   ns_statscounter_recursclients);
   2646  1.23  christos }
   2647  1.23  christos 
   2648  1.23  christos static void
   2649  1.23  christos stale_refresh_aftermath(ns_client_t *client, isc_result_t result) {
   2650  1.23  christos 	dns_db_t *db = NULL;
   2651  1.23  christos 	unsigned int dboptions;
   2652  1.23  christos 	isc_buffer_t buffer;
   2653  1.23  christos 	query_ctx_t qctx;
   2654  1.23  christos 	dns_clientinfomethods_t cm;
   2655  1.23  christos 	dns_clientinfo_t ci;
   2656  1.23  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   2657  1.23  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   2658  1.23  christos 
   2659   1.1  christos 	/*
   2660  1.23  christos 	 * If refreshing a stale RRset failed, we need to set the
   2661  1.23  christos 	 * stale-refresh-time window, so that on future requests for this
   2662  1.23  christos 	 * RRset the stale entry may be used immediately.
   2663   1.1  christos 	 */
   2664  1.23  christos 	switch (result) {
   2665  1.23  christos 	case ISC_R_SUCCESS:
   2666  1.23  christos 	case DNS_R_GLUE:
   2667  1.23  christos 	case DNS_R_ZONECUT:
   2668  1.23  christos 	case ISC_R_NOTFOUND:
   2669  1.23  christos 	case DNS_R_DELEGATION:
   2670  1.23  christos 	case DNS_R_EMPTYNAME:
   2671  1.23  christos 	case DNS_R_NXRRSET:
   2672  1.23  christos 	case DNS_R_EMPTYWILD:
   2673  1.23  christos 	case DNS_R_NXDOMAIN:
   2674  1.23  christos 	case DNS_R_COVERINGNSEC:
   2675  1.23  christos 	case DNS_R_NCACHENXDOMAIN:
   2676  1.23  christos 	case DNS_R_NCACHENXRRSET:
   2677  1.23  christos 	case DNS_R_CNAME:
   2678  1.23  christos 	case DNS_R_DNAME:
   2679  1.23  christos 		break;
   2680  1.23  christos 	default:
   2681  1.23  christos 		dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
   2682  1.23  christos 		dns_rdatatype_format(client->query.qtype, typebuf,
   2683  1.23  christos 				     sizeof(typebuf));
   2684  1.23  christos 		ns_client_log(client, NS_LOGCATEGORY_SERVE_STALE,
   2685  1.23  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_NOTICE,
   2686  1.23  christos 			      "%s/%s stale refresh failed: timed out", namebuf,
   2687  1.23  christos 			      typebuf);
   2688  1.23  christos 
   2689  1.23  christos 		/*
   2690  1.23  christos 		 * Set up a short lived query context, solely to set the
   2691  1.23  christos 		 * last refresh failure time on the RRset in the cache
   2692  1.23  christos 		 * database, starting the stale-refresh-time window for it.
   2693  1.23  christos 		 * This is a condensed form of query_lookup().
   2694  1.23  christos 		 */
   2695  1.23  christos 		client->now = isc_stdtime_now();
   2696  1.23  christos 		client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
   2697  1.23  christos 		qctx_init(client, NULL, 0, &qctx);
   2698  1.23  christos 
   2699  1.23  christos 		dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2700  1.23  christos 		dns_clientinfo_init(&ci, qctx.client, NULL);
   2701  1.23  christos 		if (HAVEECS(qctx.client)) {
   2702  1.23  christos 			dns_clientinfo_setecs(&ci, &qctx.client->ecs);
   2703  1.23  christos 		}
   2704  1.23  christos 
   2705  1.23  christos 		result = qctx_prepare_buffers(&qctx, &buffer);
   2706  1.23  christos 		if (result != ISC_R_SUCCESS) {
   2707  1.23  christos 			goto cleanup;
   2708  1.23  christos 		}
   2709  1.23  christos 
   2710  1.23  christos 		dboptions = qctx.client->query.dboptions;
   2711  1.23  christos 		dboptions |= DNS_DBFIND_STALEOK;
   2712  1.23  christos 		dboptions |= DNS_DBFIND_STALESTART;
   2713  1.23  christos 
   2714  1.23  christos 		dns_db_attach(qctx.client->view->cachedb, &db);
   2715  1.23  christos 		(void)dns_db_findext(db, qctx.client->query.qname, NULL,
   2716  1.23  christos 				     qctx.client->query.qtype, dboptions,
   2717  1.23  christos 				     qctx.client->now, &qctx.node, qctx.fname,
   2718  1.23  christos 				     &cm, &ci, qctx.rdataset, qctx.sigrdataset);
   2719  1.23  christos 		if (qctx.node != NULL) {
   2720  1.23  christos 			dns_db_detachnode(db, &qctx.node);
   2721  1.23  christos 		}
   2722  1.23  christos 		dns_db_detach(&db);
   2723  1.23  christos 
   2724  1.23  christos 	cleanup:
   2725  1.23  christos 		qctx_freedata(&qctx);
   2726  1.23  christos 		qctx_destroy(&qctx);
   2727   1.9  christos 	}
   2728   1.1  christos }
   2729   1.1  christos 
   2730   1.1  christos static void
   2731  1.23  christos cleanup_after_fetch(dns_fetchresponse_t *resp, const char *ctracestr,
   2732  1.23  christos 		    ns_query_rectype_t recursion_type) {
   2733  1.23  christos 	ns_client_t *client = resp->arg;
   2734  1.23  christos 	isc_nmhandle_t **handlep = NULL;
   2735  1.23  christos 	dns_fetch_t **fetchp = NULL;
   2736  1.23  christos 	isc_result_t result;
   2737   1.1  christos 
   2738  1.23  christos 	REQUIRE(NS_CLIENT_VALID(client));
   2739   1.1  christos 
   2740  1.23  christos 	CTRACE(ISC_LOG_DEBUG(3), ctracestr);
   2741   1.1  christos 
   2742  1.23  christos 	handlep = &client->query.recursions[recursion_type].handle;
   2743  1.23  christos 	fetchp = &client->query.recursions[recursion_type].fetch;
   2744  1.23  christos 	result = resp->result;
   2745   1.9  christos 
   2746   1.1  christos 	LOCK(&client->query.fetchlock);
   2747  1.23  christos 	if (*fetchp != NULL) {
   2748  1.23  christos 		INSIST(resp->fetch == *fetchp);
   2749  1.23  christos 		*fetchp = NULL;
   2750   1.1  christos 	}
   2751   1.1  christos 	UNLOCK(&client->query.fetchlock);
   2752   1.9  christos 
   2753  1.23  christos 	/* Some type of recursions require a bit of aftermath. */
   2754  1.23  christos 	if (recursion_type == RECTYPE_STALE_REFRESH) {
   2755  1.23  christos 		stale_refresh_aftermath(client, result);
   2756   1.9  christos 	}
   2757   1.9  christos 
   2758  1.23  christos 	recursionquotatype_detach(client);
   2759  1.23  christos 	free_fresp(client, &resp);
   2760  1.23  christos 	isc_nmhandle_detach(handlep);
   2761  1.23  christos }
   2762  1.23  christos 
   2763  1.23  christos static void
   2764  1.23  christos prefetch_done(void *arg) {
   2765  1.23  christos 	cleanup_after_fetch(arg, "prefetch_done", RECTYPE_PREFETCH);
   2766   1.1  christos }
   2767   1.1  christos 
   2768   1.1  christos static void
   2769  1.23  christos rpzfetch_done(void *arg) {
   2770  1.23  christos 	cleanup_after_fetch(arg, "rpzfetch_done", RECTYPE_RPZ);
   2771  1.23  christos }
   2772  1.23  christos 
   2773  1.23  christos static void
   2774  1.23  christos stale_refresh_done(void *arg) {
   2775  1.23  christos 	cleanup_after_fetch(arg, "stale_refresh_done", RECTYPE_STALE_REFRESH);
   2776  1.23  christos }
   2777  1.23  christos 
   2778  1.23  christos /*
   2779  1.23  christos  * Try initiating a fetch for the given 'qname' and 'qtype' (using the slot in
   2780  1.23  christos  * the 'recursions' array indicated by 'recursion_type') that will be
   2781  1.23  christos  * associated with 'client'.  If the recursive clients quota (or even soft
   2782  1.23  christos  * quota) is reached or some other error occurs, just return without starting
   2783  1.23  christos  * the fetch.  If a fetch is successfully created, its results will be cached
   2784  1.23  christos  * upon successful completion, but no further actions will be taken afterwards.
   2785  1.23  christos  */
   2786  1.23  christos static void
   2787  1.23  christos fetch_and_forget(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t qtype,
   2788  1.23  christos 		 ns_query_rectype_t recursion_type) {
   2789  1.23  christos 	dns_rdataset_t *tmprdataset;
   2790   1.1  christos 	isc_sockaddr_t *peeraddr;
   2791   1.1  christos 	unsigned int options;
   2792  1.23  christos 	isc_job_cb cb;
   2793  1.23  christos 	isc_nmhandle_t **handlep;
   2794  1.23  christos 	dns_fetch_t **fetchp;
   2795  1.23  christos 	isc_result_t result;
   2796   1.1  christos 
   2797  1.23  christos 	result = recursionquotatype_attach_hard(client);
   2798  1.23  christos 	if (result != ISC_R_SUCCESS) {
   2799   1.1  christos 		return;
   2800   1.9  christos 	}
   2801   1.1  christos 
   2802   1.3  christos 	tmprdataset = ns_client_newrdataset(client);
   2803   1.9  christos 
   2804   1.9  christos 	if (!TCP(client)) {
   2805   1.1  christos 		peeraddr = &client->peeraddr;
   2806   1.9  christos 	} else {
   2807   1.1  christos 		peeraddr = NULL;
   2808   1.9  christos 	}
   2809   1.9  christos 
   2810  1.23  christos 	switch (recursion_type) {
   2811  1.23  christos 	case RECTYPE_PREFETCH:
   2812  1.23  christos 		options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH;
   2813  1.23  christos 		cb = prefetch_done;
   2814  1.23  christos 		break;
   2815  1.23  christos 	case RECTYPE_RPZ:
   2816  1.23  christos 		options = client->query.fetchoptions;
   2817  1.23  christos 		cb = rpzfetch_done;
   2818  1.23  christos 		break;
   2819  1.23  christos 	case RECTYPE_STALE_REFRESH:
   2820  1.23  christos 		options = client->query.fetchoptions;
   2821  1.23  christos 		cb = stale_refresh_done;
   2822  1.23  christos 		break;
   2823  1.23  christos 	default:
   2824  1.23  christos 		UNREACHABLE();
   2825  1.23  christos 	}
   2826  1.23  christos 
   2827  1.23  christos 	handlep = &client->query.recursions[recursion_type].handle;
   2828  1.23  christos 	fetchp = &client->query.recursions[recursion_type].fetch;
   2829  1.23  christos 
   2830  1.23  christos 	isc_nmhandle_attach(client->handle, handlep);
   2831   1.9  christos 	result = dns_resolver_createfetch(
   2832  1.23  christos 		client->view->resolver, qname, qtype, NULL, NULL, NULL,
   2833  1.23  christos 		peeraddr, client->message->id, options, 0, NULL,
   2834  1.26  christos 		client->query.qc, NULL, client->manager->loop, cb, client, NULL,
   2835  1.24  christos 		tmprdataset, NULL, fetchp);
   2836   1.1  christos 	if (result != ISC_R_SUCCESS) {
   2837   1.3  christos 		ns_client_putrdataset(client, &tmprdataset);
   2838  1.23  christos 		isc_nmhandle_detach(handlep);
   2839  1.23  christos 		recursionquotatype_detach(client);
   2840   1.1  christos 	}
   2841  1.23  christos }
   2842  1.23  christos 
   2843  1.23  christos static void
   2844  1.26  christos query_stale_refresh(ns_client_t *client, dns_name_t *qname,
   2845  1.26  christos 		    dns_rdataset_t *rdataset) {
   2846  1.26  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_stale_refresh");
   2847  1.26  christos 
   2848  1.26  christos 	bool stale_refresh_window = false;
   2849  1.26  christos 	bool stale_rrset = true;
   2850  1.26  christos 
   2851  1.26  christos 	if (rdataset != NULL) {
   2852  1.26  christos 		stale_refresh_window = (STALE_WINDOW(rdataset) &&
   2853  1.26  christos 					(client->query.dboptions &
   2854  1.26  christos 					 DNS_DBFIND_STALEENABLED) != 0);
   2855  1.26  christos 		stale_rrset = STALE(rdataset);
   2856  1.26  christos 	}
   2857  1.26  christos 
   2858  1.26  christos 	if (FETCH_RECTYPE_STALE_REFRESH(client) != NULL ||
   2859  1.26  christos 	    (client->query.dboptions & DNS_DBFIND_STALETIMEOUT) == 0 ||
   2860  1.26  christos 	    !stale_rrset || stale_refresh_window)
   2861  1.26  christos 	{
   2862  1.26  christos 		return;
   2863  1.26  christos 	}
   2864  1.26  christos 
   2865  1.26  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   2866  1.26  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   2867  1.26  christos 	dns_name_format(qname, namebuf, sizeof(namebuf));
   2868  1.26  christos 	dns_rdatatype_format(client->query.qtype, typebuf, sizeof(typebuf));
   2869  1.26  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE, NS_LOGMODULE_QUERY,
   2870  1.26  christos 		      ISC_LOG_INFO,
   2871  1.26  christos 		      "%s %s stale answer used, an attempt "
   2872  1.26  christos 		      "to refresh the RRset will still be "
   2873  1.26  christos 		      "made",
   2874  1.26  christos 		      namebuf, typebuf);
   2875  1.26  christos 
   2876  1.26  christos 	client->query.dboptions &= ~(DNS_DBFIND_STALETIMEOUT |
   2877  1.26  christos 				     DNS_DBFIND_STALEOK |
   2878  1.26  christos 				     DNS_DBFIND_STALEENABLED);
   2879  1.26  christos 
   2880  1.26  christos 	fetch_and_forget(client, qname, client->query.qtype,
   2881  1.26  christos 			 RECTYPE_STALE_REFRESH);
   2882  1.26  christos }
   2883  1.26  christos 
   2884  1.26  christos static void
   2885  1.26  christos query_stale_refresh_ncache(ns_client_t *client) {
   2886  1.26  christos 	dns_name_t *qname;
   2887  1.26  christos 
   2888  1.26  christos 	if (client->query.origqname != NULL) {
   2889  1.26  christos 		qname = client->query.origqname;
   2890  1.26  christos 	} else {
   2891  1.26  christos 		qname = client->query.qname;
   2892  1.26  christos 	}
   2893  1.26  christos 	query_stale_refresh(client, qname, NULL);
   2894  1.26  christos }
   2895  1.26  christos 
   2896  1.26  christos static void
   2897  1.23  christos query_prefetch(ns_client_t *client, dns_name_t *qname,
   2898  1.23  christos 	       dns_rdataset_t *rdataset) {
   2899  1.23  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_prefetch");
   2900  1.23  christos 
   2901  1.23  christos 	if (FETCH_RECTYPE_PREFETCH(client) != NULL ||
   2902  1.23  christos 	    client->view->prefetch_trigger == 0U ||
   2903  1.23  christos 	    rdataset->ttl > client->view->prefetch_trigger ||
   2904  1.23  christos 	    (rdataset->attributes & DNS_RDATASETATTR_PREFETCH) == 0)
   2905  1.23  christos 	{
   2906  1.26  christos 		/* maybe refresh stale data */
   2907  1.26  christos 		query_stale_refresh(client, qname, rdataset);
   2908  1.23  christos 		return;
   2909  1.23  christos 	}
   2910  1.23  christos 
   2911  1.23  christos 	fetch_and_forget(client, qname, rdataset->type, RECTYPE_PREFETCH);
   2912   1.9  christos 
   2913   1.1  christos 	dns_rdataset_clearprefetch(rdataset);
   2914  1.23  christos 	ns_stats_increment(client->manager->sctx->nsstats,
   2915  1.23  christos 			   ns_statscounter_prefetch);
   2916  1.23  christos 
   2917  1.26  christos 	return;
   2918   1.1  christos }
   2919   1.1  christos 
   2920  1.15  christos static void
   2921   1.1  christos rpz_clean(dns_zone_t **zonep, dns_db_t **dbp, dns_dbnode_t **nodep,
   2922   1.9  christos 	  dns_rdataset_t **rdatasetp) {
   2923   1.1  christos 	if (nodep != NULL && *nodep != NULL) {
   2924   1.1  christos 		REQUIRE(dbp != NULL && *dbp != NULL);
   2925   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   2926   1.1  christos 	}
   2927   1.9  christos 	if (dbp != NULL && *dbp != NULL) {
   2928   1.1  christos 		dns_db_detach(dbp);
   2929   1.9  christos 	}
   2930   1.9  christos 	if (zonep != NULL && *zonep != NULL) {
   2931   1.1  christos 		dns_zone_detach(zonep);
   2932   1.9  christos 	}
   2933   1.1  christos 	if (rdatasetp != NULL && *rdatasetp != NULL &&
   2934   1.1  christos 	    dns_rdataset_isassociated(*rdatasetp))
   2935   1.9  christos 	{
   2936   1.1  christos 		dns_rdataset_disassociate(*rdatasetp);
   2937   1.9  christos 	}
   2938   1.1  christos }
   2939   1.1  christos 
   2940  1.15  christos static void
   2941   1.1  christos rpz_match_clear(dns_rpz_st_t *st) {
   2942   1.1  christos 	rpz_clean(&st->m.zone, &st->m.db, &st->m.node, &st->m.rdataset);
   2943   1.1  christos 	st->m.version = NULL;
   2944   1.1  christos }
   2945   1.1  christos 
   2946  1.15  christos static isc_result_t
   2947   1.1  christos rpz_ready(ns_client_t *client, dns_rdataset_t **rdatasetp) {
   2948   1.1  christos 	REQUIRE(rdatasetp != NULL);
   2949   1.1  christos 
   2950   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_ready");
   2951   1.1  christos 
   2952   1.1  christos 	if (*rdatasetp == NULL) {
   2953   1.3  christos 		*rdatasetp = ns_client_newrdataset(client);
   2954   1.1  christos 	} else if (dns_rdataset_isassociated(*rdatasetp)) {
   2955   1.1  christos 		dns_rdataset_disassociate(*rdatasetp);
   2956   1.1  christos 	}
   2957  1.23  christos 	return ISC_R_SUCCESS;
   2958   1.1  christos }
   2959   1.1  christos 
   2960   1.1  christos static void
   2961   1.1  christos rpz_st_clear(ns_client_t *client) {
   2962   1.1  christos 	dns_rpz_st_t *st = client->query.rpz_st;
   2963   1.1  christos 
   2964   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_st_clear");
   2965   1.1  christos 
   2966   1.1  christos 	if (st->m.rdataset != NULL) {
   2967   1.3  christos 		ns_client_putrdataset(client, &st->m.rdataset);
   2968   1.1  christos 	}
   2969   1.1  christos 	rpz_match_clear(st);
   2970   1.1  christos 
   2971   1.1  christos 	rpz_clean(NULL, &st->r.db, NULL, NULL);
   2972   1.1  christos 	if (st->r.ns_rdataset != NULL) {
   2973   1.3  christos 		ns_client_putrdataset(client, &st->r.ns_rdataset);
   2974   1.1  christos 	}
   2975   1.1  christos 	if (st->r.r_rdataset != NULL) {
   2976   1.3  christos 		ns_client_putrdataset(client, &st->r.r_rdataset);
   2977   1.1  christos 	}
   2978   1.1  christos 
   2979   1.1  christos 	rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL);
   2980   1.1  christos 	if (st->q.rdataset != NULL) {
   2981   1.3  christos 		ns_client_putrdataset(client, &st->q.rdataset);
   2982   1.1  christos 	}
   2983   1.1  christos 	if (st->q.sigrdataset != NULL) {
   2984   1.3  christos 		ns_client_putrdataset(client, &st->q.sigrdataset);
   2985   1.1  christos 	}
   2986   1.1  christos 	st->state = 0;
   2987   1.1  christos 	st->m.type = DNS_RPZ_TYPE_BAD;
   2988   1.1  christos 	st->m.policy = DNS_RPZ_POLICY_MISS;
   2989   1.1  christos 	if (st->rpsdb != NULL) {
   2990   1.1  christos 		dns_db_detach(&st->rpsdb);
   2991   1.1  christos 	}
   2992   1.1  christos }
   2993   1.1  christos 
   2994   1.1  christos static dns_rpz_zbits_t
   2995   1.9  christos rpz_get_zbits(ns_client_t *client, dns_rdatatype_t ip_type,
   2996   1.9  christos 	      dns_rpz_type_t rpz_type) {
   2997   1.1  christos 	dns_rpz_st_t *st;
   2998   1.3  christos 	dns_rpz_zbits_t zbits = 0;
   2999   1.1  christos 
   3000   1.1  christos 	REQUIRE(client != NULL);
   3001   1.1  christos 	REQUIRE(client->query.rpz_st != NULL);
   3002   1.1  christos 
   3003   1.1  christos 	st = client->query.rpz_st;
   3004   1.1  christos 
   3005   1.1  christos #ifdef USE_DNSRPS
   3006   1.1  christos 	if (st->popt.dnsrps_enabled) {
   3007   1.1  christos 		if (st->rpsdb == NULL ||
   3008   1.1  christos 		    librpz->have_trig(dns_dnsrps_type2trig(rpz_type),
   3009   1.1  christos 				      ip_type == dns_rdatatype_aaaa,
   3010  1.23  christos 				      ((dns_rpsdb_t *)st->rpsdb)->rsp))
   3011   1.1  christos 		{
   3012  1.23  christos 			return DNS_RPZ_ALL_ZBITS;
   3013   1.1  christos 		}
   3014  1.23  christos 		return 0;
   3015   1.1  christos 	}
   3016   1.9  christos #endif /* ifdef USE_DNSRPS */
   3017   1.1  christos 
   3018   1.1  christos 	switch (rpz_type) {
   3019   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   3020   1.1  christos 		zbits = st->have.client_ip;
   3021   1.1  christos 		break;
   3022   1.1  christos 	case DNS_RPZ_TYPE_QNAME:
   3023   1.1  christos 		zbits = st->have.qname;
   3024   1.1  christos 		break;
   3025   1.1  christos 	case DNS_RPZ_TYPE_IP:
   3026   1.1  christos 		if (ip_type == dns_rdatatype_a) {
   3027   1.1  christos 			zbits = st->have.ipv4;
   3028   1.1  christos 		} else if (ip_type == dns_rdatatype_aaaa) {
   3029   1.1  christos 			zbits = st->have.ipv6;
   3030   1.1  christos 		} else {
   3031   1.1  christos 			zbits = st->have.ip;
   3032   1.1  christos 		}
   3033   1.1  christos 		break;
   3034   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   3035   1.1  christos 		zbits = st->have.nsdname;
   3036   1.1  christos 		break;
   3037   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   3038   1.1  christos 		if (ip_type == dns_rdatatype_a) {
   3039   1.1  christos 			zbits = st->have.nsipv4;
   3040   1.1  christos 		} else if (ip_type == dns_rdatatype_aaaa) {
   3041   1.1  christos 			zbits = st->have.nsipv6;
   3042   1.1  christos 		} else {
   3043   1.1  christos 			zbits = st->have.nsip;
   3044   1.1  christos 		}
   3045   1.1  christos 		break;
   3046   1.1  christos 	default:
   3047  1.15  christos 		UNREACHABLE();
   3048   1.1  christos 	}
   3049   1.1  christos 
   3050   1.1  christos 	/*
   3051   1.1  christos 	 * Choose
   3052   1.1  christos 	 *	the earliest configured policy zone (rpz->num)
   3053   1.1  christos 	 *	QNAME over IP over NSDNAME over NSIP (rpz_type)
   3054   1.1  christos 	 *	the smallest name,
   3055   1.1  christos 	 *	the longest IP address prefix,
   3056   1.1  christos 	 *	the lexically smallest address.
   3057   1.1  christos 	 */
   3058   1.1  christos 	if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   3059   1.1  christos 		if (st->m.type >= rpz_type) {
   3060   1.1  christos 			zbits &= DNS_RPZ_ZMASK(st->m.rpz->num);
   3061   1.9  christos 		} else {
   3062   1.1  christos 			zbits &= DNS_RPZ_ZMASK(st->m.rpz->num) >> 1;
   3063   1.1  christos 		}
   3064   1.1  christos 	}
   3065   1.1  christos 
   3066   1.1  christos 	/*
   3067   1.1  christos 	 * If the client wants recursion, allow only compatible policies.
   3068   1.1  christos 	 */
   3069   1.9  christos 	if (!RECURSIONOK(client)) {
   3070   1.1  christos 		zbits &= st->popt.no_rd_ok;
   3071   1.9  christos 	}
   3072   1.1  christos 
   3073  1.23  christos 	return zbits;
   3074   1.1  christos }
   3075   1.1  christos 
   3076   1.1  christos static void
   3077   1.1  christos query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) {
   3078   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_rpzfetch");
   3079   1.9  christos 
   3080  1.23  christos 	if (FETCH_RECTYPE_RPZ(client) != NULL) {
   3081   1.1  christos 		return;
   3082   1.9  christos 	}
   3083   1.9  christos 
   3084  1.23  christos 	fetch_and_forget(client, qname, type, RECTYPE_RPZ);
   3085   1.1  christos }
   3086   1.1  christos 
   3087   1.1  christos /*
   3088   1.1  christos  * Get an NS, A, or AAAA rrset related to the response for the client
   3089   1.1  christos  * to check the contents of that rrset for hits by eligible policy zones.
   3090   1.1  christos  */
   3091   1.1  christos static isc_result_t
   3092   1.1  christos rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
   3093  1.15  christos 	       unsigned int options, dns_rpz_type_t rpz_type, dns_db_t **dbp,
   3094   1.1  christos 	       dns_dbversion_t *version, dns_rdataset_t **rdatasetp,
   3095   1.9  christos 	       bool resuming) {
   3096   1.1  christos 	dns_rpz_st_t *st;
   3097   1.3  christos 	bool is_zone;
   3098   1.1  christos 	dns_dbnode_t *node;
   3099   1.1  christos 	dns_fixedname_t fixed;
   3100   1.1  christos 	dns_name_t *found;
   3101   1.1  christos 	isc_result_t result;
   3102   1.1  christos 	dns_clientinfomethods_t cm;
   3103   1.1  christos 	dns_clientinfo_t ci;
   3104   1.1  christos 
   3105   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rrset_find");
   3106   1.1  christos 
   3107   1.1  christos 	st = client->query.rpz_st;
   3108   1.1  christos 	if ((st->state & DNS_RPZ_RECURSING) != 0) {
   3109   1.1  christos 		INSIST(st->r.r_type == type);
   3110   1.1  christos 		INSIST(dns_name_equal(name, st->r_name));
   3111   1.1  christos 		INSIST(*rdatasetp == NULL ||
   3112   1.1  christos 		       !dns_rdataset_isassociated(*rdatasetp));
   3113   1.1  christos 		st->state &= ~DNS_RPZ_RECURSING;
   3114   1.1  christos 		RESTORE(*dbp, st->r.db);
   3115   1.3  christos 		if (*rdatasetp != NULL) {
   3116   1.3  christos 			ns_client_putrdataset(client, rdatasetp);
   3117   1.3  christos 		}
   3118   1.1  christos 		RESTORE(*rdatasetp, st->r.r_rdataset);
   3119   1.1  christos 		result = st->r.r_result;
   3120   1.1  christos 		if (result == DNS_R_DELEGATION) {
   3121   1.1  christos 			CTRACE(ISC_LOG_ERROR, "RPZ recursing");
   3122   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   3123   1.3  christos 				     rpz_type, "rpz_rrset_find(1)", result);
   3124   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3125   1.1  christos 			result = DNS_R_SERVFAIL;
   3126   1.1  christos 		}
   3127  1.23  christos 		return result;
   3128   1.1  christos 	}
   3129   1.1  christos 
   3130   1.1  christos 	result = rpz_ready(client, rdatasetp);
   3131   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3132   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   3133  1.23  christos 		return result;
   3134   1.1  christos 	}
   3135   1.1  christos 	if (*dbp != NULL) {
   3136   1.3  christos 		is_zone = false;
   3137   1.1  christos 	} else {
   3138   1.1  christos 		dns_zone_t *zone;
   3139   1.1  christos 
   3140   1.1  christos 		version = NULL;
   3141   1.1  christos 		zone = NULL;
   3142  1.23  christos 		result = query_getdb(client, name, type,
   3143  1.23  christos 				     (dns_getdb_options_t){ 0 }, &zone, dbp,
   3144   1.1  christos 				     &version, &is_zone);
   3145   1.1  christos 		if (result != ISC_R_SUCCESS) {
   3146   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   3147   1.3  christos 				     rpz_type, "rpz_rrset_find(2)", result);
   3148   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3149   1.9  christos 			if (zone != NULL) {
   3150   1.1  christos 				dns_zone_detach(&zone);
   3151   1.9  christos 			}
   3152  1.23  christos 			return result;
   3153   1.1  christos 		}
   3154   1.9  christos 		if (zone != NULL) {
   3155   1.1  christos 			dns_zone_detach(&zone);
   3156   1.9  christos 		}
   3157   1.1  christos 	}
   3158   1.1  christos 
   3159   1.1  christos 	node = NULL;
   3160   1.1  christos 	found = dns_fixedname_initname(&fixed);
   3161   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   3162  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   3163  1.15  christos 	result = dns_db_findext(*dbp, name, version, type, options, client->now,
   3164  1.15  christos 				&node, found, &cm, &ci, *rdatasetp, NULL);
   3165   1.1  christos 	if (result == DNS_R_DELEGATION && is_zone && USECACHE(client)) {
   3166   1.1  christos 		/*
   3167   1.1  christos 		 * Try the cache if we're authoritative for an
   3168   1.1  christos 		 * ancestor but not the domain itself.
   3169   1.1  christos 		 */
   3170   1.1  christos 		rpz_clean(NULL, dbp, &node, rdatasetp);
   3171   1.1  christos 		version = NULL;
   3172   1.1  christos 		dns_db_attach(client->view->cachedb, dbp);
   3173   1.9  christos 		result = dns_db_findext(*dbp, name, version, type, 0,
   3174   1.9  christos 					client->now, &node, found, &cm, &ci,
   3175   1.9  christos 					*rdatasetp, NULL);
   3176   1.1  christos 	}
   3177   1.1  christos 	rpz_clean(NULL, dbp, &node, NULL);
   3178   1.1  christos 	if (result == DNS_R_DELEGATION) {
   3179   1.1  christos 		rpz_clean(NULL, NULL, NULL, rdatasetp);
   3180   1.1  christos 		/*
   3181   1.1  christos 		 * Recurse for NS rrset or A or AAAA rrset for an NS.
   3182   1.1  christos 		 * Do not recurse for addresses for the query name.
   3183   1.1  christos 		 */
   3184   1.1  christos 		if (rpz_type == DNS_RPZ_TYPE_IP) {
   3185   1.1  christos 			result = DNS_R_NXRRSET;
   3186  1.20  christos 		} else if (!client->view->rpzs->p.nsip_wait_recurse ||
   3187  1.20  christos 			   (!client->view->rpzs->p.nsdname_wait_recurse &&
   3188  1.20  christos 			    rpz_type == DNS_RPZ_TYPE_NSDNAME))
   3189  1.20  christos 		{
   3190   1.1  christos 			query_rpzfetch(client, name, type);
   3191   1.1  christos 			result = DNS_R_NXRRSET;
   3192   1.1  christos 		} else {
   3193  1.20  christos 			dns_name_copy(name, st->r_name);
   3194   1.3  christos 			result = ns_query_recurse(client, type, st->r_name,
   3195   1.3  christos 						  NULL, NULL, resuming);
   3196   1.1  christos 			if (result == ISC_R_SUCCESS) {
   3197   1.1  christos 				st->state |= DNS_RPZ_RECURSING;
   3198   1.1  christos 				result = DNS_R_DELEGATION;
   3199   1.1  christos 			}
   3200   1.1  christos 		}
   3201   1.1  christos 	}
   3202  1.23  christos 	return result;
   3203   1.1  christos }
   3204   1.1  christos 
   3205   1.1  christos /*
   3206   1.1  christos  * Compute a policy owner name, p_name, in a policy zone given the needed
   3207   1.1  christos  * policy type and the trigger name.
   3208   1.1  christos  */
   3209   1.1  christos static isc_result_t
   3210   1.9  christos rpz_get_p_name(ns_client_t *client, dns_name_t *p_name, dns_rpz_zone_t *rpz,
   3211   1.9  christos 	       dns_rpz_type_t rpz_type, dns_name_t *trig_name) {
   3212   1.1  christos 	dns_offsets_t prefix_offsets;
   3213   1.1  christos 	dns_name_t prefix, *suffix;
   3214   1.1  christos 	unsigned int first, labels;
   3215   1.1  christos 	isc_result_t result;
   3216   1.1  christos 
   3217   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_get_p_name");
   3218   1.1  christos 
   3219   1.1  christos 	/*
   3220   1.1  christos 	 * The policy owner name consists of a suffix depending on the type
   3221   1.1  christos 	 * and policy zone and a prefix that is the longest possible string
   3222   1.1  christos 	 * from the trigger name that keesp the resulting policy owner name
   3223   1.1  christos 	 * from being too long.
   3224   1.1  christos 	 */
   3225   1.1  christos 	switch (rpz_type) {
   3226   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   3227   1.1  christos 		suffix = &rpz->client_ip;
   3228   1.1  christos 		break;
   3229   1.1  christos 	case DNS_RPZ_TYPE_QNAME:
   3230   1.1  christos 		suffix = &rpz->origin;
   3231   1.1  christos 		break;
   3232   1.1  christos 	case DNS_RPZ_TYPE_IP:
   3233   1.1  christos 		suffix = &rpz->ip;
   3234   1.1  christos 		break;
   3235   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   3236   1.1  christos 		suffix = &rpz->nsdname;
   3237   1.1  christos 		break;
   3238   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   3239   1.1  christos 		suffix = &rpz->nsip;
   3240   1.1  christos 		break;
   3241   1.1  christos 	default:
   3242  1.15  christos 		UNREACHABLE();
   3243   1.1  christos 	}
   3244   1.1  christos 
   3245   1.1  christos 	/*
   3246   1.1  christos 	 * Start with relative version of the full trigger name,
   3247   1.1  christos 	 * and trim enough allow the addition of the suffix.
   3248   1.1  christos 	 */
   3249   1.1  christos 	dns_name_init(&prefix, prefix_offsets);
   3250   1.1  christos 	labels = dns_name_countlabels(trig_name);
   3251   1.1  christos 	first = 0;
   3252   1.1  christos 	for (;;) {
   3253   1.9  christos 		dns_name_getlabelsequence(trig_name, first, labels - first - 1,
   3254   1.1  christos 					  &prefix);
   3255   1.1  christos 		result = dns_name_concatenate(&prefix, suffix, p_name, NULL);
   3256   1.9  christos 		if (result == ISC_R_SUCCESS) {
   3257   1.1  christos 			break;
   3258   1.9  christos 		}
   3259   1.1  christos 		INSIST(result == DNS_R_NAMETOOLONG);
   3260   1.1  christos 		/*
   3261   1.1  christos 		 * Trim the trigger name until the combination is not too long.
   3262   1.1  christos 		 */
   3263   1.9  christos 		if (labels - first < 2) {
   3264   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, suffix,
   3265   1.9  christos 				     rpz_type, "concatenate()", result);
   3266  1.23  christos 			return ISC_R_FAILURE;
   3267   1.1  christos 		}
   3268   1.1  christos 		/*
   3269   1.1  christos 		 * Complain once about trimming the trigger name.
   3270   1.1  christos 		 */
   3271   1.1  christos 		if (first == 0) {
   3272   1.1  christos 			rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, suffix,
   3273   1.9  christos 				     rpz_type, "concatenate()", result);
   3274   1.1  christos 		}
   3275   1.1  christos 		++first;
   3276   1.1  christos 	}
   3277  1.23  christos 	return ISC_R_SUCCESS;
   3278   1.1  christos }
   3279   1.1  christos 
   3280   1.1  christos /*
   3281   1.1  christos  * Look in policy zone rpz for a policy of rpz_type by p_name.
   3282   1.1  christos  * The self-name (usually the client qname or an NS name) is compared with
   3283   1.1  christos  * the target of a CNAME policy for the old style passthru encoding.
   3284   1.1  christos  * If found, the policy is recorded in *zonep, *dbp, *versionp, *nodep,
   3285   1.1  christos  * *rdatasetp, and *policyp.
   3286   1.1  christos  * The target DNS type, qtype, chooses the best rdataset for *rdatasetp.
   3287   1.1  christos  * The caller must decide if the found policy is most suitable, including
   3288   1.1  christos  * better than a previously found policy.
   3289   1.1  christos  * If it is best, the caller records it in client->query.rpz_st->m.
   3290   1.1  christos  */
   3291   1.1  christos static isc_result_t
   3292   1.1  christos rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
   3293   1.1  christos 	   dns_name_t *p_name, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
   3294   1.1  christos 	   dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp,
   3295   1.1  christos 	   dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp,
   3296   1.9  christos 	   dns_rpz_policy_t *policyp) {
   3297   1.1  christos 	dns_fixedname_t foundf;
   3298   1.1  christos 	dns_name_t *found;
   3299   1.1  christos 	isc_result_t result;
   3300   1.1  christos 	dns_clientinfomethods_t cm;
   3301   1.1  christos 	dns_clientinfo_t ci;
   3302   1.6  christos 	bool found_a = false;
   3303   1.1  christos 
   3304   1.1  christos 	REQUIRE(nodep != NULL);
   3305   1.1  christos 
   3306   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_find_p");
   3307   1.1  christos 
   3308   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   3309  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   3310   1.1  christos 
   3311   1.1  christos 	/*
   3312   1.1  christos 	 * Try to find either a CNAME or the type of record demanded by the
   3313   1.1  christos 	 * request from the policy zone.
   3314   1.1  christos 	 */
   3315   1.1  christos 	rpz_clean(zonep, dbp, nodep, rdatasetp);
   3316   1.1  christos 	result = rpz_ready(client, rdatasetp);
   3317   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3318   1.1  christos 		CTRACE(ISC_LOG_ERROR, "rpz_ready() failed");
   3319  1.23  christos 		return DNS_R_SERVFAIL;
   3320   1.1  christos 	}
   3321   1.1  christos 	*versionp = NULL;
   3322   1.1  christos 	result = rpz_getdb(client, p_name, rpz_type, zonep, dbp, versionp);
   3323   1.9  christos 	if (result != ISC_R_SUCCESS) {
   3324  1.23  christos 		return DNS_R_NXDOMAIN;
   3325   1.9  christos 	}
   3326   1.1  christos 	found = dns_fixedname_initname(&foundf);
   3327   1.1  christos 
   3328   1.1  christos 	result = dns_db_findext(*dbp, p_name, *versionp, dns_rdatatype_any, 0,
   3329   1.9  christos 				client->now, nodep, found, &cm, &ci, *rdatasetp,
   3330   1.9  christos 				NULL);
   3331   1.1  christos 	/*
   3332   1.1  christos 	 * Choose the best rdataset if we found something.
   3333   1.1  christos 	 */
   3334   1.1  christos 	if (result == ISC_R_SUCCESS) {
   3335   1.1  christos 		dns_rdatasetiter_t *rdsiter;
   3336   1.1  christos 
   3337   1.1  christos 		rdsiter = NULL;
   3338  1.16  christos 		result = dns_db_allrdatasets(*dbp, *nodep, *versionp, 0, 0,
   3339   1.1  christos 					     &rdsiter);
   3340   1.1  christos 		if (result != ISC_R_SUCCESS) {
   3341   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name,
   3342   1.3  christos 				     rpz_type, "allrdatasets()", result);
   3343   1.1  christos 			CTRACE(ISC_LOG_ERROR,
   3344   1.1  christos 			       "rpz_find_p: allrdatasets failed");
   3345  1.23  christos 			return DNS_R_SERVFAIL;
   3346   1.1  christos 		}
   3347   1.6  christos 		if (qtype == dns_rdatatype_aaaa &&
   3348  1.16  christos 		    !ISC_LIST_EMPTY(client->view->dns64))
   3349  1.16  christos 		{
   3350   1.6  christos 			for (result = dns_rdatasetiter_first(rdsiter);
   3351   1.6  christos 			     result == ISC_R_SUCCESS;
   3352   1.9  christos 			     result = dns_rdatasetiter_next(rdsiter))
   3353   1.9  christos 			{
   3354   1.6  christos 				dns_rdatasetiter_current(rdsiter, *rdatasetp);
   3355   1.6  christos 				if ((*rdatasetp)->type == dns_rdatatype_a) {
   3356   1.6  christos 					found_a = true;
   3357   1.6  christos 				}
   3358   1.6  christos 				dns_rdataset_disassociate(*rdatasetp);
   3359   1.6  christos 			}
   3360   1.6  christos 		}
   3361   1.1  christos 		for (result = dns_rdatasetiter_first(rdsiter);
   3362   1.1  christos 		     result == ISC_R_SUCCESS;
   3363   1.9  christos 		     result = dns_rdatasetiter_next(rdsiter))
   3364   1.9  christos 		{
   3365   1.1  christos 			dns_rdatasetiter_current(rdsiter, *rdatasetp);
   3366   1.1  christos 			if ((*rdatasetp)->type == dns_rdatatype_cname ||
   3367  1.16  christos 			    (*rdatasetp)->type == qtype)
   3368  1.16  christos 			{
   3369   1.1  christos 				break;
   3370   1.9  christos 			}
   3371   1.1  christos 			dns_rdataset_disassociate(*rdatasetp);
   3372   1.1  christos 		}
   3373   1.1  christos 		dns_rdatasetiter_destroy(&rdsiter);
   3374   1.1  christos 		if (result != ISC_R_SUCCESS) {
   3375   1.1  christos 			if (result != ISC_R_NOMORE) {
   3376   1.1  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
   3377   1.9  christos 					     p_name, rpz_type, "rdatasetiter",
   3378   1.9  christos 					     result);
   3379   1.9  christos 				CTRACE(ISC_LOG_ERROR, "rpz_find_p: "
   3380   1.9  christos 						      "rdatasetiter failed");
   3381  1.23  christos 				return DNS_R_SERVFAIL;
   3382   1.1  christos 			}
   3383   1.1  christos 			/*
   3384   1.1  christos 			 * Ask again to get the right DNS_R_DNAME/NXRRSET/...
   3385   1.1  christos 			 * result if there is neither a CNAME nor target type.
   3386   1.1  christos 			 */
   3387   1.9  christos 			if (dns_rdataset_isassociated(*rdatasetp)) {
   3388   1.1  christos 				dns_rdataset_disassociate(*rdatasetp);
   3389   1.9  christos 			}
   3390   1.1  christos 			dns_db_detachnode(*dbp, nodep);
   3391   1.1  christos 
   3392   1.1  christos 			if (qtype == dns_rdatatype_rrsig ||
   3393  1.16  christos 			    qtype == dns_rdatatype_sig)
   3394  1.16  christos 			{
   3395   1.1  christos 				result = DNS_R_NXRRSET;
   3396   1.9  christos 			} else {
   3397   1.1  christos 				result = dns_db_findext(*dbp, p_name, *versionp,
   3398   1.1  christos 							qtype, 0, client->now,
   3399   1.1  christos 							nodep, found, &cm, &ci,
   3400   1.1  christos 							*rdatasetp, NULL);
   3401   1.9  christos 			}
   3402   1.1  christos 		}
   3403   1.1  christos 	}
   3404   1.1  christos 	switch (result) {
   3405   1.1  christos 	case ISC_R_SUCCESS:
   3406   1.1  christos 		if ((*rdatasetp)->type != dns_rdatatype_cname) {
   3407   1.1  christos 			*policyp = DNS_RPZ_POLICY_RECORD;
   3408   1.1  christos 		} else {
   3409   1.1  christos 			*policyp = dns_rpz_decode_cname(rpz, *rdatasetp,
   3410   1.1  christos 							self_name);
   3411   1.1  christos 			if ((*policyp == DNS_RPZ_POLICY_RECORD ||
   3412   1.1  christos 			     *policyp == DNS_RPZ_POLICY_WILDCNAME) &&
   3413   1.1  christos 			    qtype != dns_rdatatype_cname &&
   3414   1.1  christos 			    qtype != dns_rdatatype_any)
   3415   1.9  christos 			{
   3416  1.23  christos 				return DNS_R_CNAME;
   3417   1.9  christos 			}
   3418   1.1  christos 		}
   3419  1.23  christos 		return ISC_R_SUCCESS;
   3420   1.1  christos 	case DNS_R_NXRRSET:
   3421   1.6  christos 		if (found_a) {
   3422   1.6  christos 			*policyp = DNS_RPZ_POLICY_DNS64;
   3423   1.6  christos 		} else {
   3424   1.6  christos 			*policyp = DNS_RPZ_POLICY_NODATA;
   3425   1.6  christos 		}
   3426  1.23  christos 		return result;
   3427   1.1  christos 	case DNS_R_DNAME:
   3428   1.9  christos 	/*
   3429   1.9  christos 	 * DNAME policy RRs have very few if any uses that are not
   3430   1.9  christos 	 * better served with simple wildcards.  Making them work would
   3431   1.9  christos 	 * require complications to get the number of labels matched
   3432   1.9  christos 	 * in the name or the found name to the main DNS_R_DNAME case
   3433   1.9  christos 	 * in query_dname().  The domain also does not appear in the
   3434   1.9  christos 	 * summary database at the right level, so this happens only
   3435   1.9  christos 	 * with a single policy zone when we have no summary database.
   3436   1.9  christos 	 * Treat it as a miss.
   3437   1.9  christos 	 */
   3438   1.1  christos 	case DNS_R_NXDOMAIN:
   3439   1.1  christos 	case DNS_R_EMPTYNAME:
   3440  1.23  christos 		return DNS_R_NXDOMAIN;
   3441   1.1  christos 	default:
   3442   1.9  christos 		rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type, "",
   3443   1.9  christos 			     result);
   3444   1.9  christos 		CTRACE(ISC_LOG_ERROR, "rpz_find_p: unexpected result");
   3445  1.23  christos 		return DNS_R_SERVFAIL;
   3446   1.1  christos 	}
   3447   1.1  christos }
   3448   1.1  christos 
   3449   1.1  christos static void
   3450   1.1  christos rpz_save_p(dns_rpz_st_t *st, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
   3451   1.1  christos 	   dns_rpz_policy_t policy, dns_name_t *p_name, dns_rpz_prefix_t prefix,
   3452   1.1  christos 	   isc_result_t result, dns_zone_t **zonep, dns_db_t **dbp,
   3453   1.1  christos 	   dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp,
   3454   1.9  christos 	   dns_dbversion_t *version) {
   3455   1.1  christos 	dns_rdataset_t *trdataset = NULL;
   3456   1.1  christos 
   3457   1.1  christos 	rpz_match_clear(st);
   3458   1.1  christos 	st->m.rpz = rpz;
   3459   1.1  christos 	st->m.type = rpz_type;
   3460   1.1  christos 	st->m.policy = policy;
   3461  1.20  christos 	dns_name_copy(p_name, st->p_name);
   3462   1.1  christos 	st->m.prefix = prefix;
   3463   1.1  christos 	st->m.result = result;
   3464   1.1  christos 	SAVE(st->m.zone, *zonep);
   3465   1.1  christos 	SAVE(st->m.db, *dbp);
   3466   1.1  christos 	SAVE(st->m.node, *nodep);
   3467   1.1  christos 	if (*rdatasetp != NULL && dns_rdataset_isassociated(*rdatasetp)) {
   3468   1.1  christos 		/*
   3469   1.1  christos 		 * Save the replacement rdataset from the policy
   3470   1.1  christos 		 * and make the previous replacement rdataset scratch.
   3471   1.1  christos 		 */
   3472   1.1  christos 		SAVE(trdataset, st->m.rdataset);
   3473   1.1  christos 		SAVE(st->m.rdataset, *rdatasetp);
   3474   1.1  christos 		SAVE(*rdatasetp, trdataset);
   3475   1.1  christos 		st->m.ttl = ISC_MIN(st->m.rdataset->ttl, rpz->max_policy_ttl);
   3476   1.1  christos 	} else {
   3477   1.1  christos 		st->m.ttl = ISC_MIN(DNS_RPZ_TTL_DEFAULT, rpz->max_policy_ttl);
   3478   1.1  christos 	}
   3479   1.1  christos 	SAVE(st->m.version, version);
   3480   1.1  christos }
   3481   1.1  christos 
   3482   1.1  christos #ifdef USE_DNSRPS
   3483   1.1  christos /*
   3484   1.1  christos  * Check the results of a RPZ service interface lookup.
   3485   1.1  christos  * Stop after an error (<0) or not a hit on a disabled zone (0).
   3486   1.1  christos  * Continue after a hit on a disabled zone (>0).
   3487   1.1  christos  */
   3488   1.1  christos static int
   3489  1.23  christos dnsrps_ck(librpz_emsg_t *emsg, ns_client_t *client, dns_rpsdb_t *rpsdb,
   3490   1.9  christos 	  bool recursed) {
   3491   1.1  christos 	isc_region_t region;
   3492   1.1  christos 	librpz_domain_buf_t pname_buf;
   3493   1.1  christos 
   3494  1.23  christos 	CTRACE(ISC_LOG_DEBUG(3), "dnsrps_ck");
   3495  1.23  christos 
   3496   1.1  christos 	if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
   3497  1.23  christos 		return -1;
   3498   1.1  christos 	}
   3499   1.1  christos 
   3500   1.1  christos 	/*
   3501   1.1  christos 	 * Forget the state from before the IP address or domain check
   3502   1.1  christos 	 * if the lookup hit nothing.
   3503   1.1  christos 	 */
   3504   1.1  christos 	if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED ||
   3505   1.1  christos 	    rpsdb->result.hit_id != rpsdb->hit_id ||
   3506   1.1  christos 	    rpsdb->result.policy != LIBRPZ_POLICY_DISABLED)
   3507   1.1  christos 	{
   3508   1.1  christos 		if (!librpz->rsp_pop_discard(emsg, rpsdb->rsp)) {
   3509  1.23  christos 			return -1;
   3510   1.1  christos 		}
   3511  1.23  christos 		return 0;
   3512   1.1  christos 	}
   3513   1.1  christos 
   3514   1.1  christos 	/*
   3515   1.1  christos 	 * Log a hit on a disabled zone.
   3516   1.1  christos 	 * Forget the zone to not try it again, and restore the pre-hit state.
   3517   1.1  christos 	 */
   3518   1.1  christos 	if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
   3519  1.23  christos 		return -1;
   3520   1.1  christos 	}
   3521   1.1  christos 	region.base = pname_buf.d;
   3522   1.1  christos 	region.length = pname_buf.size;
   3523   1.1  christos 	dns_name_fromregion(client->query.rpz_st->p_name, &region);
   3524   1.9  christos 	rpz_log_rewrite(client, true, dns_dnsrps_2policy(rpsdb->result.zpolicy),
   3525   1.1  christos 			dns_dnsrps_trig2type(rpsdb->result.trig), NULL,
   3526   1.1  christos 			client->query.rpz_st->p_name, NULL,
   3527   1.1  christos 			rpsdb->result.cznum);
   3528   1.1  christos 
   3529   1.1  christos 	if (!librpz->rsp_forget_zone(emsg, rpsdb->result.cznum, rpsdb->rsp) ||
   3530   1.1  christos 	    !librpz->rsp_pop(emsg, &rpsdb->result, rpsdb->rsp))
   3531   1.1  christos 	{
   3532  1.23  christos 		return -1;
   3533   1.1  christos 	}
   3534  1.23  christos 	return 1;
   3535   1.1  christos }
   3536   1.1  christos 
   3537   1.1  christos /*
   3538   1.1  christos  * Ready the shim database and rdataset for a DNSRPS hit.
   3539   1.1  christos  */
   3540   1.3  christos static bool
   3541   1.1  christos dnsrps_set_p(librpz_emsg_t *emsg, ns_client_t *client, dns_rpz_st_t *st,
   3542   1.1  christos 	     dns_rdatatype_t qtype, dns_rdataset_t **p_rdatasetp,
   3543   1.9  christos 	     bool recursed) {
   3544  1.23  christos 	dns_rpsdb_t *rpsdb = NULL;
   3545   1.1  christos 	librpz_domain_buf_t pname_buf;
   3546   1.1  christos 	isc_region_t region;
   3547  1.23  christos 	dns_zone_t *p_zone = NULL;
   3548  1.23  christos 	dns_db_t *p_db = NULL;
   3549  1.23  christos 	dns_dbnode_t *p_node = NULL;
   3550   1.1  christos 	dns_rpz_policy_t policy;
   3551   1.1  christos 	dns_rdatatype_t foundtype, searchtype;
   3552   1.1  christos 	isc_result_t result;
   3553   1.1  christos 
   3554  1.23  christos 	CTRACE(ISC_LOG_DEBUG(3), "dnsrps_set_p");
   3555  1.23  christos 
   3556  1.23  christos 	rpsdb = (dns_rpsdb_t *)st->rpsdb;
   3557   1.1  christos 
   3558   1.1  christos 	if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
   3559  1.23  christos 		return false;
   3560   1.1  christos 	}
   3561   1.1  christos 
   3562   1.1  christos 	if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED) {
   3563  1.23  christos 		return true;
   3564   1.1  christos 	}
   3565   1.1  christos 
   3566   1.1  christos 	/*
   3567   1.1  christos 	 * Give the fake or shim DNSRPS database its new origin.
   3568   1.1  christos 	 */
   3569   1.1  christos 	if (!librpz->rsp_soa(emsg, NULL, NULL, &rpsdb->origin_buf,
   3570   1.1  christos 			     &rpsdb->result, rpsdb->rsp))
   3571   1.1  christos 	{
   3572  1.23  christos 		return false;
   3573   1.1  christos 	}
   3574   1.1  christos 	region.base = rpsdb->origin_buf.d;
   3575   1.1  christos 	region.length = rpsdb->origin_buf.size;
   3576   1.1  christos 	dns_name_fromregion(&rpsdb->common.origin, &region);
   3577   1.1  christos 
   3578   1.1  christos 	if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
   3579  1.23  christos 		return false;
   3580   1.1  christos 	}
   3581   1.1  christos 	region.base = pname_buf.d;
   3582   1.1  christos 	region.length = pname_buf.size;
   3583   1.1  christos 	dns_name_fromregion(st->p_name, &region);
   3584   1.1  christos 
   3585  1.23  christos 	result = rpz_ready(client, p_rdatasetp);
   3586  1.23  christos 	if (result != ISC_R_SUCCESS) {
   3587  1.23  christos 		return false;
   3588  1.23  christos 	}
   3589   1.1  christos 	dns_db_attach(st->rpsdb, &p_db);
   3590   1.1  christos 	policy = dns_dnsrps_2policy(rpsdb->result.policy);
   3591   1.1  christos 	if (policy != DNS_RPZ_POLICY_RECORD) {
   3592   1.1  christos 		result = ISC_R_SUCCESS;
   3593   1.1  christos 	} else if (qtype == dns_rdatatype_rrsig) {
   3594   1.1  christos 		/*
   3595   1.1  christos 		 * dns_find_db() refuses to look for and fail to
   3596   1.1  christos 		 * find dns_rdatatype_rrsig.
   3597   1.1  christos 		 */
   3598   1.1  christos 		result = DNS_R_NXRRSET;
   3599   1.1  christos 		policy = DNS_RPZ_POLICY_NODATA;
   3600   1.1  christos 	} else {
   3601  1.23  christos 		dns_fixedname_t foundf;
   3602  1.23  christos 		dns_name_t *found = NULL;
   3603  1.23  christos 
   3604   1.1  christos 		/*
   3605   1.1  christos 		 * Get the next (and so first) RR from the policy node.
   3606   1.1  christos 		 * If it is a CNAME, then look for it regardless of the
   3607   1.1  christos 		 * query type.
   3608   1.1  christos 		 */
   3609   1.1  christos 		if (!librpz->rsp_rr(emsg, &foundtype, NULL, NULL, NULL,
   3610   1.1  christos 				    &rpsdb->result, rpsdb->qname->ndata,
   3611   1.1  christos 				    rpsdb->qname->length, rpsdb->rsp))
   3612   1.1  christos 		{
   3613  1.23  christos 			return false;
   3614   1.1  christos 		}
   3615  1.23  christos 
   3616   1.1  christos 		if (foundtype == dns_rdatatype_cname) {
   3617   1.1  christos 			searchtype = dns_rdatatype_cname;
   3618   1.1  christos 		} else {
   3619   1.1  christos 			searchtype = qtype;
   3620   1.1  christos 		}
   3621   1.1  christos 		/*
   3622   1.1  christos 		 * Get the DNSPRS imitation rdataset.
   3623   1.1  christos 		 */
   3624   1.1  christos 		found = dns_fixedname_initname(&foundf);
   3625   1.9  christos 		result = dns_db_find(p_db, st->p_name, NULL, searchtype, 0, 0,
   3626   1.9  christos 				     &p_node, found, *p_rdatasetp, NULL);
   3627   1.1  christos 
   3628   1.1  christos 		if (result == ISC_R_SUCCESS) {
   3629   1.1  christos 			if (searchtype == dns_rdatatype_cname &&
   3630  1.16  christos 			    qtype != dns_rdatatype_cname)
   3631  1.16  christos 			{
   3632   1.1  christos 				result = DNS_R_CNAME;
   3633   1.1  christos 			}
   3634   1.1  christos 		} else if (result == DNS_R_NXRRSET) {
   3635   1.1  christos 			policy = DNS_RPZ_POLICY_NODATA;
   3636   1.1  christos 		} else {
   3637   1.1  christos 			snprintf(emsg->c, sizeof(emsg->c), "dns_db_find(): %s",
   3638   1.1  christos 				 isc_result_totext(result));
   3639  1.23  christos 			return false;
   3640   1.1  christos 		}
   3641   1.1  christos 	}
   3642   1.1  christos 
   3643   1.1  christos 	rpz_save_p(st, client->view->rpzs->zones[rpsdb->result.cznum],
   3644   1.9  christos 		   dns_dnsrps_trig2type(rpsdb->result.trig), policy, st->p_name,
   3645   1.9  christos 		   0, result, &p_zone, &p_db, &p_node, p_rdatasetp, NULL);
   3646   1.1  christos 
   3647   1.1  christos 	rpz_clean(NULL, NULL, NULL, p_rdatasetp);
   3648   1.1  christos 
   3649  1.23  christos 	return true;
   3650   1.1  christos }
   3651   1.1  christos 
   3652   1.1  christos static isc_result_t
   3653   1.1  christos dnsrps_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
   3654   1.9  christos 		  dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp) {
   3655   1.1  christos 	dns_rpz_st_t *st;
   3656  1.23  christos 	dns_rpsdb_t *rpsdb;
   3657   1.1  christos 	librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
   3658   1.3  christos 	bool recursed = false;
   3659   1.1  christos 	int res;
   3660   1.1  christos 	librpz_emsg_t emsg;
   3661   1.1  christos 	isc_result_t result;
   3662   1.1  christos 
   3663  1.23  christos 	CTRACE(ISC_LOG_DEBUG(3), "dnsrps_rewrite_ip");
   3664  1.23  christos 
   3665   1.1  christos 	st = client->query.rpz_st;
   3666  1.23  christos 	rpsdb = (dns_rpsdb_t *)st->rpsdb;
   3667   1.1  christos 
   3668   1.1  christos 	result = rpz_ready(client, p_rdatasetp);
   3669   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3670   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   3671  1.23  christos 		return result;
   3672   1.1  christos 	}
   3673   1.1  christos 
   3674   1.1  christos 	switch (rpz_type) {
   3675   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   3676   1.1  christos 		trig = LIBRPZ_TRIG_CLIENT_IP;
   3677   1.3  christos 		recursed = false;
   3678   1.1  christos 		break;
   3679   1.1  christos 	case DNS_RPZ_TYPE_IP:
   3680   1.1  christos 		trig = LIBRPZ_TRIG_IP;
   3681   1.3  christos 		recursed = true;
   3682   1.1  christos 		break;
   3683   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   3684   1.1  christos 		trig = LIBRPZ_TRIG_NSIP;
   3685   1.3  christos 		recursed = true;
   3686   1.1  christos 		break;
   3687   1.1  christos 	default:
   3688  1.15  christos 		UNREACHABLE();
   3689   1.1  christos 	}
   3690   1.1  christos 
   3691   1.1  christos 	do {
   3692   1.1  christos 		if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
   3693   1.1  christos 		    !librpz->ck_ip(&emsg,
   3694   1.1  christos 				   netaddr->family == AF_INET
   3695   1.9  christos 					   ? (const void *)&netaddr->type.in
   3696   1.9  christos 					   : (const void *)&netaddr->type.in6,
   3697   1.1  christos 				   netaddr->family, trig, ++rpsdb->hit_id,
   3698   1.1  christos 				   recursed, rpsdb->rsp) ||
   3699   1.1  christos 		    (res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
   3700   1.1  christos 		{
   3701   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   3702   1.1  christos 				     rpz_type, emsg.c, DNS_R_SERVFAIL);
   3703   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3704  1.23  christos 			return DNS_R_SERVFAIL;
   3705   1.1  christos 		}
   3706   1.1  christos 	} while (res != 0);
   3707  1.23  christos 	return ISC_R_SUCCESS;
   3708   1.1  christos }
   3709   1.1  christos 
   3710   1.1  christos static isc_result_t
   3711   1.9  christos dnsrps_rewrite_name(ns_client_t *client, dns_name_t *trig_name, bool recursed,
   3712   1.9  christos 		    dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp) {
   3713   1.1  christos 	dns_rpz_st_t *st;
   3714  1.23  christos 	dns_rpsdb_t *rpsdb;
   3715   1.1  christos 	librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
   3716   1.1  christos 	isc_region_t r;
   3717   1.1  christos 	int res;
   3718   1.1  christos 	librpz_emsg_t emsg;
   3719   1.1  christos 	isc_result_t result;
   3720   1.1  christos 
   3721  1.23  christos 	CTRACE(ISC_LOG_DEBUG(3), "dnsrps_rewrite_name");
   3722  1.23  christos 
   3723   1.1  christos 	st = client->query.rpz_st;
   3724  1.23  christos 	rpsdb = (dns_rpsdb_t *)st->rpsdb;
   3725   1.1  christos 
   3726   1.1  christos 	result = rpz_ready(client, p_rdatasetp);
   3727   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3728   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   3729  1.23  christos 		return result;
   3730   1.1  christos 	}
   3731   1.1  christos 
   3732   1.1  christos 	switch (rpz_type) {
   3733   1.1  christos 	case DNS_RPZ_TYPE_QNAME:
   3734   1.1  christos 		trig = LIBRPZ_TRIG_QNAME;
   3735   1.1  christos 		break;
   3736   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   3737   1.1  christos 		trig = LIBRPZ_TRIG_NSDNAME;
   3738   1.1  christos 		break;
   3739   1.1  christos 	default:
   3740  1.15  christos 		UNREACHABLE();
   3741   1.1  christos 	}
   3742   1.1  christos 
   3743   1.1  christos 	dns_name_toregion(trig_name, &r);
   3744   1.1  christos 	do {
   3745   1.1  christos 		if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
   3746   1.9  christos 		    !librpz->ck_domain(&emsg, r.base, r.length, trig,
   3747   1.9  christos 				       ++rpsdb->hit_id, recursed, rpsdb->rsp) ||
   3748   1.1  christos 		    (res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
   3749   1.1  christos 		{
   3750   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   3751   1.1  christos 				     rpz_type, emsg.c, DNS_R_SERVFAIL);
   3752   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3753  1.23  christos 			return DNS_R_SERVFAIL;
   3754   1.1  christos 		}
   3755   1.1  christos 	} while (res != 0);
   3756  1.23  christos 	return ISC_R_SUCCESS;
   3757   1.1  christos }
   3758   1.1  christos #endif /* USE_DNSRPS */
   3759   1.1  christos 
   3760   1.1  christos /*
   3761   1.1  christos  * Check this address in every eligible policy zone.
   3762   1.1  christos  */
   3763   1.1  christos static isc_result_t
   3764   1.1  christos rpz_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
   3765   1.1  christos 	       dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3766   1.9  christos 	       dns_rpz_zbits_t zbits, dns_rdataset_t **p_rdatasetp) {
   3767   1.1  christos 	dns_rpz_zones_t *rpzs;
   3768   1.1  christos 	dns_rpz_st_t *st;
   3769   1.1  christos 	dns_rpz_zone_t *rpz;
   3770   1.1  christos 	dns_rpz_prefix_t prefix;
   3771   1.1  christos 	dns_rpz_num_t rpz_num;
   3772   1.1  christos 	dns_fixedname_t ip_namef, p_namef;
   3773   1.1  christos 	dns_name_t *ip_name, *p_name;
   3774   1.1  christos 	dns_zone_t *p_zone;
   3775   1.1  christos 	dns_db_t *p_db;
   3776   1.1  christos 	dns_dbversion_t *p_version;
   3777   1.1  christos 	dns_dbnode_t *p_node;
   3778   1.1  christos 	dns_rpz_policy_t policy;
   3779   1.1  christos 	isc_result_t result;
   3780   1.1  christos 
   3781   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip");
   3782   1.1  christos 
   3783   1.1  christos 	rpzs = client->view->rpzs;
   3784   1.1  christos 	st = client->query.rpz_st;
   3785   1.1  christos #ifdef USE_DNSRPS
   3786   1.1  christos 	if (st->popt.dnsrps_enabled) {
   3787  1.23  christos 		return dnsrps_rewrite_ip(client, netaddr, rpz_type,
   3788  1.23  christos 					 p_rdatasetp);
   3789   1.1  christos 	}
   3790   1.9  christos #endif /* ifdef USE_DNSRPS */
   3791   1.1  christos 
   3792   1.1  christos 	ip_name = dns_fixedname_initname(&ip_namef);
   3793   1.1  christos 
   3794   1.1  christos 	p_zone = NULL;
   3795   1.1  christos 	p_db = NULL;
   3796   1.1  christos 	p_node = NULL;
   3797   1.1  christos 
   3798   1.1  christos 	while (zbits != 0) {
   3799   1.1  christos 		rpz_num = dns_rpz_find_ip(rpzs, rpz_type, zbits, netaddr,
   3800   1.1  christos 					  ip_name, &prefix);
   3801   1.9  christos 		if (rpz_num == DNS_RPZ_INVALID_NUM) {
   3802   1.1  christos 			break;
   3803   1.9  christos 		}
   3804   1.1  christos 		zbits &= (DNS_RPZ_ZMASK(rpz_num) >> 1);
   3805   1.1  christos 
   3806   1.1  christos 		/*
   3807   1.1  christos 		 * Do not try applying policy zones that cannot replace a
   3808   1.1  christos 		 * previously found policy zone.
   3809   1.1  christos 		 * Stop looking if the next best choice cannot
   3810   1.1  christos 		 * replace what we already have.
   3811   1.1  christos 		 */
   3812   1.1  christos 		rpz = rpzs->zones[rpz_num];
   3813   1.1  christos 		if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   3814   1.9  christos 			if (st->m.rpz->num < rpz->num) {
   3815   1.1  christos 				break;
   3816   1.9  christos 			}
   3817   1.1  christos 			if (st->m.rpz->num == rpz->num &&
   3818   1.9  christos 			    (st->m.type < rpz_type || st->m.prefix > prefix))
   3819   1.9  christos 			{
   3820   1.1  christos 				break;
   3821   1.9  christos 			}
   3822   1.1  christos 		}
   3823   1.1  christos 
   3824   1.1  christos 		/*
   3825   1.1  christos 		 * Get the policy for a prefix at least as long
   3826   1.1  christos 		 * as the prefix of the entry we had before.
   3827   1.1  christos 		 */
   3828   1.1  christos 		p_name = dns_fixedname_initname(&p_namef);
   3829   1.1  christos 		result = rpz_get_p_name(client, p_name, rpz, rpz_type, ip_name);
   3830   1.9  christos 		if (result != ISC_R_SUCCESS) {
   3831   1.1  christos 			continue;
   3832   1.9  christos 		}
   3833   1.9  christos 		result = rpz_find_p(client, ip_name, qtype, p_name, rpz,
   3834   1.9  christos 				    rpz_type, &p_zone, &p_db, &p_version,
   3835   1.9  christos 				    &p_node, p_rdatasetp, &policy);
   3836   1.1  christos 		switch (result) {
   3837   1.1  christos 		case DNS_R_NXDOMAIN:
   3838   1.1  christos 			/*
   3839   1.1  christos 			 * Continue after a policy record that is missing
   3840   1.1  christos 			 * contrary to the summary data.  The summary
   3841   1.1  christos 			 * data can out of date during races with and among
   3842   1.1  christos 			 * policy zone updates.
   3843   1.1  christos 			 */
   3844   1.9  christos 			CTRACE(ISC_LOG_ERROR, "rpz_rewrite_ip: mismatched "
   3845   1.9  christos 					      "summary data; "
   3846   1.9  christos 					      "continuing");
   3847   1.1  christos 			continue;
   3848   1.1  christos 		case DNS_R_SERVFAIL:
   3849   1.1  christos 			rpz_clean(&p_zone, &p_db, &p_node, p_rdatasetp);
   3850   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3851  1.23  christos 			return DNS_R_SERVFAIL;
   3852   1.1  christos 		default:
   3853   1.1  christos 			/*
   3854   1.1  christos 			 * Forget this policy if it is not preferable
   3855   1.1  christos 			 * to the previously found policy.
   3856   1.1  christos 			 * If this policy is not good, then stop looking
   3857   1.1  christos 			 * because none of the later policy zones would work.
   3858   1.1  christos 			 *
   3859   1.1  christos 			 * With more than one applicable policy, prefer
   3860   1.1  christos 			 * the earliest configured policy,
   3861   1.1  christos 			 * client-IP over QNAME over IP over NSDNAME over NSIP,
   3862   1.1  christos 			 * the longest prefix
   3863   1.1  christos 			 * the lexically smallest address.
   3864   1.1  christos 			 * dns_rpz_find_ip() ensures st->m.rpz->num >= rpz->num.
   3865   1.1  christos 			 * We can compare new and current p_name because
   3866   1.1  christos 			 * both are of the same type and in the same zone.
   3867   1.1  christos 			 * The tests above eliminate other reasons to
   3868   1.1  christos 			 * reject this policy.  If this policy can't work,
   3869   1.1  christos 			 * then neither can later zones.
   3870   1.1  christos 			 */
   3871   1.1  christos 			if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   3872   1.1  christos 			    rpz->num == st->m.rpz->num &&
   3873   1.9  christos 			    (st->m.type == rpz_type && st->m.prefix == prefix &&
   3874   1.9  christos 			     0 > dns_name_rdatacompare(st->p_name, p_name)))
   3875   1.9  christos 			{
   3876   1.1  christos 				break;
   3877   1.9  christos 			}
   3878   1.1  christos 
   3879   1.1  christos 			/*
   3880   1.1  christos 			 * Stop checking after saving an enabled hit in this
   3881   1.1  christos 			 * policy zone.  The radix tree in the policy zone
   3882   1.1  christos 			 * ensures that we found the longest match.
   3883   1.1  christos 			 */
   3884   1.1  christos 			if (rpz->policy != DNS_RPZ_POLICY_DISABLED) {
   3885   1.9  christos 				CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip: "
   3886   1.9  christos 							 "rpz_save_p");
   3887   1.9  christos 				rpz_save_p(st, rpz, rpz_type, policy, p_name,
   3888   1.9  christos 					   prefix, result, &p_zone, &p_db,
   3889   1.9  christos 					   &p_node, p_rdatasetp, p_version);
   3890   1.1  christos 				break;
   3891   1.1  christos 			}
   3892   1.1  christos 
   3893   1.1  christos 			/*
   3894   1.1  christos 			 * Log DNS_RPZ_POLICY_DISABLED zones
   3895   1.1  christos 			 * and try the next eligible policy zone.
   3896   1.1  christos 			 */
   3897   1.9  christos 			rpz_log_rewrite(client, true, policy, rpz_type, p_zone,
   3898   1.9  christos 					p_name, NULL, rpz_num);
   3899   1.1  christos 		}
   3900   1.1  christos 	}
   3901   1.1  christos 
   3902   1.1  christos 	rpz_clean(&p_zone, &p_db, &p_node, p_rdatasetp);
   3903  1.23  christos 	return ISC_R_SUCCESS;
   3904   1.1  christos }
   3905   1.1  christos 
   3906   1.1  christos /*
   3907   1.1  christos  * Check the IP addresses in the A or AAAA rrsets for name against
   3908   1.1  christos  * all eligible rpz_type (IP or NSIP) response policy rewrite rules.
   3909   1.1  christos  */
   3910   1.1  christos static isc_result_t
   3911   1.9  christos rpz_rewrite_ip_rrset(ns_client_t *client, dns_name_t *name,
   3912   1.9  christos 		     dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3913   1.9  christos 		     dns_rdatatype_t ip_type, dns_db_t **ip_dbp,
   3914   1.9  christos 		     dns_dbversion_t *ip_version, dns_rdataset_t **ip_rdatasetp,
   3915   1.9  christos 		     dns_rdataset_t **p_rdatasetp, bool resuming) {
   3916   1.1  christos 	dns_rpz_zbits_t zbits;
   3917   1.1  christos 	isc_netaddr_t netaddr;
   3918   1.1  christos 	struct in_addr ina;
   3919   1.1  christos 	struct in6_addr in6a;
   3920   1.1  christos 	isc_result_t result;
   3921  1.16  christos 	unsigned int options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   3922  1.15  christos 	bool done = false;
   3923   1.1  christos 
   3924   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip_rrset");
   3925   1.1  christos 
   3926  1.15  christos 	do {
   3927  1.15  christos 		zbits = rpz_get_zbits(client, ip_type, rpz_type);
   3928  1.15  christos 		if (zbits == 0) {
   3929  1.23  christos 			return ISC_R_SUCCESS;
   3930  1.15  christos 		}
   3931   1.1  christos 
   3932  1.15  christos 		/*
   3933  1.15  christos 		 * Get the A or AAAA rdataset.
   3934  1.15  christos 		 */
   3935  1.15  christos 		result = rpz_rrset_find(client, name, ip_type, options,
   3936  1.15  christos 					rpz_type, ip_dbp, ip_version,
   3937  1.15  christos 					ip_rdatasetp, resuming);
   3938  1.15  christos 		switch (result) {
   3939  1.15  christos 		case ISC_R_SUCCESS:
   3940  1.15  christos 		case DNS_R_GLUE:
   3941  1.15  christos 		case DNS_R_ZONECUT:
   3942  1.15  christos 			break;
   3943  1.15  christos 		case DNS_R_EMPTYNAME:
   3944  1.15  christos 		case DNS_R_EMPTYWILD:
   3945  1.15  christos 		case DNS_R_NXDOMAIN:
   3946  1.15  christos 		case DNS_R_NCACHENXDOMAIN:
   3947  1.15  christos 		case DNS_R_NXRRSET:
   3948  1.15  christos 		case DNS_R_NCACHENXRRSET:
   3949  1.15  christos 		case ISC_R_NOTFOUND:
   3950  1.23  christos 			return ISC_R_SUCCESS;
   3951  1.15  christos 		case DNS_R_DELEGATION:
   3952  1.15  christos 		case DNS_R_DUPLICATE:
   3953  1.15  christos 		case DNS_R_DROP:
   3954  1.23  christos 			return result;
   3955  1.15  christos 		case DNS_R_CNAME:
   3956  1.15  christos 		case DNS_R_DNAME:
   3957  1.15  christos 			rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, name,
   3958   1.3  christos 				     rpz_type, "NS address rewrite rrset",
   3959   1.1  christos 				     result);
   3960  1.23  christos 			return ISC_R_SUCCESS;
   3961  1.15  christos 		default:
   3962  1.15  christos 			if (client->query.rpz_st->m.policy !=
   3963  1.16  christos 			    DNS_RPZ_POLICY_ERROR)
   3964  1.16  christos 			{
   3965  1.15  christos 				client->query.rpz_st->m.policy =
   3966  1.15  christos 					DNS_RPZ_POLICY_ERROR;
   3967  1.15  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   3968  1.15  christos 					     rpz_type,
   3969  1.15  christos 					     "NS address rewrite rrset",
   3970  1.15  christos 					     result);
   3971  1.15  christos 			}
   3972  1.15  christos 			CTRACE(ISC_LOG_ERROR,
   3973  1.15  christos 			       "rpz_rewrite_ip_rrset: unexpected "
   3974  1.15  christos 			       "result");
   3975  1.23  christos 			return DNS_R_SERVFAIL;
   3976   1.1  christos 		}
   3977   1.1  christos 
   3978  1.15  christos 		/*
   3979  1.15  christos 		 * If we are processing glue setup for the next loop
   3980  1.15  christos 		 * otherwise we are done.
   3981  1.15  christos 		 */
   3982  1.15  christos 		if (result == DNS_R_GLUE) {
   3983  1.16  christos 			options = client->query.dboptions;
   3984  1.15  christos 		} else {
   3985  1.16  christos 			options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   3986  1.15  christos 			done = true;
   3987   1.1  christos 		}
   3988   1.1  christos 
   3989  1.15  christos 		/*
   3990  1.15  christos 		 * Check all of the IP addresses in the rdataset.
   3991  1.15  christos 		 */
   3992  1.15  christos 		for (result = dns_rdataset_first(*ip_rdatasetp);
   3993  1.15  christos 		     result == ISC_R_SUCCESS;
   3994  1.15  christos 		     result = dns_rdataset_next(*ip_rdatasetp))
   3995  1.15  christos 		{
   3996  1.15  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   3997  1.15  christos 			dns_rdataset_current(*ip_rdatasetp, &rdata);
   3998  1.15  christos 			switch (rdata.type) {
   3999  1.15  christos 			case dns_rdatatype_a:
   4000  1.15  christos 				INSIST(rdata.length == 4);
   4001  1.15  christos 				memmove(&ina.s_addr, rdata.data, 4);
   4002  1.15  christos 				isc_netaddr_fromin(&netaddr, &ina);
   4003  1.15  christos 				break;
   4004  1.15  christos 			case dns_rdatatype_aaaa:
   4005  1.15  christos 				INSIST(rdata.length == 16);
   4006  1.15  christos 				memmove(in6a.s6_addr, rdata.data, 16);
   4007  1.15  christos 				isc_netaddr_fromin6(&netaddr, &in6a);
   4008  1.15  christos 				break;
   4009  1.15  christos 			default:
   4010  1.15  christos 				continue;
   4011  1.15  christos 			}
   4012  1.15  christos 
   4013  1.15  christos 			result = rpz_rewrite_ip(client, &netaddr, qtype,
   4014  1.15  christos 						rpz_type, zbits, p_rdatasetp);
   4015  1.15  christos 			if (result != ISC_R_SUCCESS) {
   4016  1.23  christos 				return result;
   4017  1.15  christos 			}
   4018   1.9  christos 		}
   4019  1.15  christos 	} while (!done &&
   4020  1.15  christos 		 client->query.rpz_st->m.policy == DNS_RPZ_POLICY_MISS);
   4021   1.1  christos 
   4022  1.23  christos 	return ISC_R_SUCCESS;
   4023   1.1  christos }
   4024   1.1  christos 
   4025   1.1  christos /*
   4026   1.1  christos  * Look for IP addresses in A and AAAA rdatasets
   4027   1.1  christos  * that trigger all eligible IP or NSIP policy rules.
   4028   1.1  christos  */
   4029   1.1  christos static isc_result_t
   4030   1.1  christos rpz_rewrite_ip_rrsets(ns_client_t *client, dns_name_t *name,
   4031   1.1  christos 		      dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   4032   1.9  christos 		      dns_rdataset_t **ip_rdatasetp, bool resuming) {
   4033   1.1  christos 	dns_rpz_st_t *st;
   4034   1.1  christos 	dns_dbversion_t *ip_version;
   4035   1.1  christos 	dns_db_t *ip_db;
   4036   1.1  christos 	dns_rdataset_t *p_rdataset;
   4037   1.1  christos 	isc_result_t result;
   4038   1.1  christos 
   4039   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip_rrsets");
   4040   1.1  christos 
   4041   1.1  christos 	st = client->query.rpz_st;
   4042   1.1  christos 	ip_version = NULL;
   4043   1.1  christos 	ip_db = NULL;
   4044   1.1  christos 	p_rdataset = NULL;
   4045   1.1  christos 	if ((st->state & DNS_RPZ_DONE_IPv4) == 0 &&
   4046   1.9  christos 	    (qtype == dns_rdatatype_a || qtype == dns_rdatatype_any ||
   4047   1.9  christos 	     rpz_type == DNS_RPZ_TYPE_NSIP))
   4048   1.9  christos 	{
   4049   1.1  christos 		/*
   4050   1.1  christos 		 * Rewrite based on an IPv4 address that will appear
   4051   1.1  christos 		 * in the ANSWER section or if we are checking IP addresses.
   4052   1.1  christos 		 */
   4053   1.9  christos 		result = rpz_rewrite_ip_rrset(
   4054   1.9  christos 			client, name, qtype, rpz_type, dns_rdatatype_a, &ip_db,
   4055   1.9  christos 			ip_version, ip_rdatasetp, &p_rdataset, resuming);
   4056   1.9  christos 		if (result == ISC_R_SUCCESS) {
   4057   1.1  christos 			st->state |= DNS_RPZ_DONE_IPv4;
   4058   1.9  christos 		}
   4059   1.1  christos 	} else {
   4060   1.1  christos 		result = ISC_R_SUCCESS;
   4061   1.1  christos 	}
   4062   1.1  christos 	if (result == ISC_R_SUCCESS &&
   4063   1.9  christos 	    (qtype == dns_rdatatype_aaaa || qtype == dns_rdatatype_any ||
   4064   1.9  christos 	     rpz_type == DNS_RPZ_TYPE_NSIP))
   4065   1.9  christos 	{
   4066   1.1  christos 		/*
   4067   1.1  christos 		 * Rewrite based on IPv6 addresses that will appear
   4068   1.1  christos 		 * in the ANSWER section or if we are checking IP addresses.
   4069   1.1  christos 		 */
   4070   1.9  christos 		result = rpz_rewrite_ip_rrset(client, name, qtype, rpz_type,
   4071   1.9  christos 					      dns_rdatatype_aaaa, &ip_db,
   4072   1.9  christos 					      ip_version, ip_rdatasetp,
   4073   1.1  christos 					      &p_rdataset, resuming);
   4074   1.1  christos 	}
   4075   1.9  christos 	if (ip_db != NULL) {
   4076   1.1  christos 		dns_db_detach(&ip_db);
   4077   1.9  christos 	}
   4078   1.3  christos 	ns_client_putrdataset(client, &p_rdataset);
   4079  1.23  christos 	return result;
   4080   1.1  christos }
   4081   1.1  christos 
   4082   1.1  christos /*
   4083   1.1  christos  * Try to rewrite a request for a qtype rdataset based on the trigger name
   4084   1.1  christos  * trig_name and rpz_type (DNS_RPZ_TYPE_QNAME or DNS_RPZ_TYPE_NSDNAME).
   4085   1.1  christos  * Record the results including the replacement rdataset if any
   4086   1.1  christos  * in client->query.rpz_st.
   4087   1.1  christos  * *rdatasetp is a scratch rdataset.
   4088   1.1  christos  */
   4089   1.1  christos static isc_result_t
   4090   1.1  christos rpz_rewrite_name(ns_client_t *client, dns_name_t *trig_name,
   4091   1.1  christos 		 dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   4092   1.3  christos 		 dns_rpz_zbits_t allowed_zbits, bool recursed,
   4093   1.9  christos 		 dns_rdataset_t **rdatasetp) {
   4094   1.1  christos 	dns_rpz_zones_t *rpzs;
   4095   1.1  christos 	dns_rpz_zone_t *rpz;
   4096   1.1  christos 	dns_rpz_st_t *st;
   4097   1.1  christos 	dns_fixedname_t p_namef;
   4098   1.1  christos 	dns_name_t *p_name;
   4099   1.1  christos 	dns_rpz_zbits_t zbits;
   4100   1.1  christos 	dns_rpz_num_t rpz_num;
   4101   1.1  christos 	dns_zone_t *p_zone;
   4102   1.1  christos 	dns_db_t *p_db;
   4103   1.1  christos 	dns_dbversion_t *p_version;
   4104   1.1  christos 	dns_dbnode_t *p_node;
   4105   1.1  christos 	dns_rpz_policy_t policy;
   4106   1.1  christos 	isc_result_t result;
   4107   1.1  christos 
   4108   1.1  christos #ifndef USE_DNSRPS
   4109   1.1  christos 	UNUSED(recursed);
   4110   1.9  christos #endif /* ifndef USE_DNSRPS */
   4111   1.1  christos 
   4112   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name");
   4113   1.1  christos 
   4114   1.1  christos 	rpzs = client->view->rpzs;
   4115   1.1  christos 	st = client->query.rpz_st;
   4116   1.1  christos 
   4117   1.1  christos #ifdef USE_DNSRPS
   4118   1.1  christos 	if (st->popt.dnsrps_enabled) {
   4119  1.23  christos 		return dnsrps_rewrite_name(client, trig_name, recursed,
   4120  1.23  christos 					   rpz_type, rdatasetp);
   4121   1.1  christos 	}
   4122   1.9  christos #endif /* ifdef USE_DNSRPS */
   4123   1.1  christos 
   4124   1.1  christos 	zbits = rpz_get_zbits(client, qtype, rpz_type);
   4125   1.1  christos 	zbits &= allowed_zbits;
   4126   1.9  christos 	if (zbits == 0) {
   4127  1.23  christos 		return ISC_R_SUCCESS;
   4128   1.9  christos 	}
   4129   1.1  christos 
   4130   1.1  christos 	/*
   4131   1.1  christos 	 * Use the summary database to find the bit mask of policy zones
   4132   1.1  christos 	 * with policies for this trigger name. We do this even if there
   4133   1.1  christos 	 * is only one eligible policy zone so that wildcard triggers
   4134   1.1  christos 	 * are matched correctly, and not into their parent.
   4135   1.1  christos 	 */
   4136   1.1  christos 	zbits = dns_rpz_find_name(rpzs, rpz_type, zbits, trig_name);
   4137   1.9  christos 	if (zbits == 0) {
   4138  1.23  christos 		return ISC_R_SUCCESS;
   4139   1.9  christos 	}
   4140   1.1  christos 
   4141   1.1  christos 	p_name = dns_fixedname_initname(&p_namef);
   4142   1.1  christos 
   4143   1.1  christos 	p_zone = NULL;
   4144   1.1  christos 	p_db = NULL;
   4145   1.1  christos 	p_node = NULL;
   4146   1.1  christos 
   4147   1.1  christos 	/*
   4148   1.1  christos 	 * Check the trigger name in every policy zone that the summary data
   4149   1.1  christos 	 * says has a hit for the trigger name.
   4150   1.1  christos 	 * Most of the time there are no eligible zones and the summary data
   4151   1.1  christos 	 * keeps us from getting this far.
   4152   1.1  christos 	 * We check the most eligible zone first and so usually check only
   4153   1.1  christos 	 * one policy zone.
   4154   1.1  christos 	 */
   4155   1.1  christos 	for (rpz_num = 0; zbits != 0; ++rpz_num, zbits >>= 1) {
   4156   1.9  christos 		if ((zbits & 1) == 0) {
   4157   1.1  christos 			continue;
   4158   1.9  christos 		}
   4159   1.1  christos 
   4160   1.1  christos 		/*
   4161   1.1  christos 		 * Do not check policy zones that cannot replace a previously
   4162   1.1  christos 		 * found policy.
   4163   1.1  christos 		 */
   4164   1.1  christos 		rpz = rpzs->zones[rpz_num];
   4165   1.1  christos 		if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   4166   1.9  christos 			if (st->m.rpz->num < rpz->num) {
   4167   1.1  christos 				break;
   4168   1.9  christos 			}
   4169   1.9  christos 			if (st->m.rpz->num == rpz->num && st->m.type < rpz_type)
   4170   1.9  christos 			{
   4171   1.1  christos 				break;
   4172   1.9  christos 			}
   4173   1.1  christos 		}
   4174   1.1  christos 
   4175   1.1  christos 		/*
   4176   1.1  christos 		 * Get the next policy zone's record for this trigger name.
   4177   1.1  christos 		 */
   4178   1.1  christos 		result = rpz_get_p_name(client, p_name, rpz, rpz_type,
   4179   1.1  christos 					trig_name);
   4180   1.9  christos 		if (result != ISC_R_SUCCESS) {
   4181   1.1  christos 			continue;
   4182   1.9  christos 		}
   4183   1.9  christos 		result = rpz_find_p(client, trig_name, qtype, p_name, rpz,
   4184   1.9  christos 				    rpz_type, &p_zone, &p_db, &p_version,
   4185   1.9  christos 				    &p_node, rdatasetp, &policy);
   4186   1.1  christos 		switch (result) {
   4187   1.1  christos 		case DNS_R_NXDOMAIN:
   4188   1.1  christos 			/*
   4189   1.1  christos 			 * Continue after a missing policy record
   4190   1.1  christos 			 * contrary to the summary data.  The summary
   4191   1.1  christos 			 * data can out of date during races with and among
   4192   1.1  christos 			 * policy zone updates.
   4193   1.1  christos 			 */
   4194   1.9  christos 			CTRACE(ISC_LOG_ERROR, "rpz_rewrite_name: mismatched "
   4195   1.9  christos 					      "summary data; "
   4196   1.9  christos 					      "continuing");
   4197   1.1  christos 			continue;
   4198   1.1  christos 		case DNS_R_SERVFAIL:
   4199   1.1  christos 			rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   4200   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   4201  1.23  christos 			return DNS_R_SERVFAIL;
   4202   1.1  christos 		default:
   4203   1.1  christos 			/*
   4204   1.1  christos 			 * With more than one applicable policy, prefer
   4205   1.1  christos 			 * the earliest configured policy,
   4206   1.1  christos 			 * client-IP over QNAME over IP over NSDNAME over NSIP,
   4207   1.1  christos 			 * and the smallest name.
   4208   1.1  christos 			 * We known st->m.rpz->num >= rpz->num  and either
   4209   1.1  christos 			 * st->m.rpz->num > rpz->num or st->m.type >= rpz_type
   4210   1.1  christos 			 */
   4211   1.1  christos 			if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   4212   1.1  christos 			    rpz->num == st->m.rpz->num &&
   4213   1.1  christos 			    (st->m.type < rpz_type ||
   4214   1.1  christos 			     (st->m.type == rpz_type &&
   4215   1.1  christos 			      0 >= dns_name_compare(p_name, st->p_name))))
   4216   1.9  christos 			{
   4217   1.1  christos 				continue;
   4218   1.9  christos 			}
   4219   1.4  christos 
   4220   1.1  christos 			if (rpz->policy != DNS_RPZ_POLICY_DISABLED) {
   4221   1.9  christos 				CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name: "
   4222   1.9  christos 							 "rpz_save_p");
   4223   1.9  christos 				rpz_save_p(st, rpz, rpz_type, policy, p_name, 0,
   4224   1.9  christos 					   result, &p_zone, &p_db, &p_node,
   4225   1.1  christos 					   rdatasetp, p_version);
   4226   1.1  christos 				/*
   4227   1.1  christos 				 * After a hit, higher numbered policy zones
   4228   1.1  christos 				 * are irrelevant
   4229   1.1  christos 				 */
   4230   1.1  christos 				rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   4231  1.23  christos 				return ISC_R_SUCCESS;
   4232   1.1  christos 			}
   4233   1.1  christos 			/*
   4234   1.1  christos 			 * Log DNS_RPZ_POLICY_DISABLED zones
   4235   1.1  christos 			 * and try the next eligible policy zone.
   4236   1.1  christos 			 */
   4237   1.9  christos 			rpz_log_rewrite(client, true, policy, rpz_type, p_zone,
   4238   1.9  christos 					p_name, NULL, rpz_num);
   4239   1.1  christos 			break;
   4240   1.1  christos 		}
   4241   1.1  christos 	}
   4242   1.1  christos 
   4243   1.1  christos 	rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   4244  1.23  christos 	return ISC_R_SUCCESS;
   4245   1.1  christos }
   4246   1.1  christos 
   4247   1.1  christos static void
   4248   1.1  christos rpz_rewrite_ns_skip(ns_client_t *client, dns_name_t *nsname,
   4249   1.9  christos 		    isc_result_t result, int level, const char *str) {
   4250   1.1  christos 	dns_rpz_st_t *st;
   4251   1.1  christos 
   4252   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ns_skip");
   4253   1.1  christos 
   4254   1.1  christos 	st = client->query.rpz_st;
   4255   1.1  christos 
   4256   1.9  christos 	if (str != NULL) {
   4257   1.9  christos 		rpz_log_fail_helper(client, level, nsname, DNS_RPZ_TYPE_NSIP,
   4258   1.9  christos 				    DNS_RPZ_TYPE_NSDNAME, str, result);
   4259   1.9  christos 	}
   4260   1.1  christos 	if (st->r.ns_rdataset != NULL &&
   4261  1.16  christos 	    dns_rdataset_isassociated(st->r.ns_rdataset))
   4262  1.16  christos 	{
   4263   1.1  christos 		dns_rdataset_disassociate(st->r.ns_rdataset);
   4264   1.9  christos 	}
   4265   1.1  christos 
   4266   1.1  christos 	st->r.label--;
   4267   1.1  christos }
   4268   1.1  christos 
   4269   1.1  christos /*
   4270   1.1  christos  * RPZ query result types
   4271   1.1  christos  */
   4272   1.1  christos typedef enum {
   4273   1.1  christos 	qresult_type_done = 0,
   4274   1.1  christos 	qresult_type_restart = 1,
   4275   1.1  christos 	qresult_type_recurse = 2
   4276   1.1  christos } qresult_type_t;
   4277   1.1  christos 
   4278   1.1  christos /*
   4279   1.1  christos  * Look for response policy zone QNAME, NSIP, and NSDNAME rewriting.
   4280   1.1  christos  */
   4281   1.1  christos static isc_result_t
   4282   1.9  christos rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype, isc_result_t qresult,
   4283   1.9  christos 	    bool resuming, dns_rdataset_t *ordataset, dns_rdataset_t *osigset) {
   4284   1.1  christos 	dns_rpz_zones_t *rpzs;
   4285   1.1  christos 	dns_rpz_st_t *st;
   4286  1.26  christos 	dns_rdataset_t *rdataset = NULL;
   4287   1.1  christos 	dns_fixedname_t nsnamef;
   4288   1.1  christos 	dns_name_t *nsname;
   4289  1.26  christos 	qresult_type_t qresult_type = qresult_type_done;
   4290   1.1  christos 	dns_rpz_zbits_t zbits;
   4291   1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   4292   1.1  christos 	dns_rpz_have_t have;
   4293   1.1  christos 	dns_rpz_popt_t popt;
   4294  1.26  christos 	bool first_time;
   4295  1.26  christos 	dns_rpz_num_t zones_registered;
   4296  1.26  christos 	dns_rpz_num_t zones_processed;
   4297  1.26  christos 
   4298   1.1  christos 	int rpz_ver;
   4299  1.15  christos 	unsigned int options;
   4300   1.1  christos #ifdef USE_DNSRPS
   4301   1.1  christos 	librpz_emsg_t emsg;
   4302   1.9  christos #endif /* ifdef USE_DNSRPS */
   4303   1.1  christos 
   4304   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite");
   4305   1.1  christos 
   4306   1.1  christos 	rpzs = client->view->rpzs;
   4307   1.1  christos 	st = client->query.rpz_st;
   4308   1.1  christos 
   4309  1.13  christos 	if (rpzs == NULL) {
   4310  1.23  christos 		return ISC_R_NOTFOUND;
   4311  1.13  christos 	}
   4312  1.13  christos 	if (st != NULL && (st->state & DNS_RPZ_REWRITTEN) != 0) {
   4313  1.23  christos 		return DNS_R_DISALLOWED;
   4314  1.13  christos 	}
   4315  1.13  christos 	if (RECURSING(client)) {
   4316  1.23  christos 		return DNS_R_DISALLOWED;
   4317   1.9  christos 	}
   4318   1.1  christos 
   4319   1.1  christos 	RWLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4320   1.1  christos 	if ((rpzs->p.num_zones == 0 && !rpzs->p.dnsrps_enabled) ||
   4321   1.1  christos 	    (!RECURSIONOK(client) && rpzs->p.no_rd_ok == 0) ||
   4322   1.1  christos 	    !rpz_ck_dnssec(client, qresult, ordataset, osigset))
   4323   1.1  christos 	{
   4324   1.1  christos 		RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4325  1.23  christos 		return DNS_R_DISALLOWED;
   4326   1.1  christos 	}
   4327   1.1  christos 	have = rpzs->have;
   4328   1.1  christos 	popt = rpzs->p;
   4329  1.26  christos 	first_time = rpzs->first_time;
   4330  1.26  christos 	zones_registered = atomic_load_acquire(&rpzs->zones_registered);
   4331  1.26  christos 	zones_processed = atomic_load_acquire(&rpzs->zones_processed);
   4332   1.1  christos 	rpz_ver = rpzs->rpz_ver;
   4333   1.1  christos 	RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4334   1.1  christos 
   4335   1.1  christos #ifndef USE_DNSRPS
   4336   1.1  christos 	INSIST(!popt.dnsrps_enabled);
   4337   1.9  christos #endif /* ifndef USE_DNSRPS */
   4338   1.1  christos 
   4339   1.1  christos 	if (st == NULL) {
   4340  1.23  christos 		st = isc_mem_get(client->manager->mctx, sizeof(*st));
   4341   1.1  christos 		st->state = 0;
   4342   1.1  christos 		st->rpsdb = NULL;
   4343   1.1  christos 	}
   4344   1.1  christos 	if (st->state == 0) {
   4345   1.1  christos 		st->state |= DNS_RPZ_ACTIVE;
   4346   1.1  christos 		memset(&st->m, 0, sizeof(st->m));
   4347   1.1  christos 		st->m.type = DNS_RPZ_TYPE_BAD;
   4348   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_MISS;
   4349   1.1  christos 		st->m.ttl = ~0;
   4350   1.1  christos 		memset(&st->r, 0, sizeof(st->r));
   4351   1.1  christos 		memset(&st->q, 0, sizeof(st->q));
   4352   1.1  christos 		st->p_name = dns_fixedname_initname(&st->_p_namef);
   4353   1.1  christos 		st->r_name = dns_fixedname_initname(&st->_r_namef);
   4354   1.1  christos 		st->fname = dns_fixedname_initname(&st->_fnamef);
   4355   1.1  christos 		st->have = have;
   4356   1.1  christos 		st->popt = popt;
   4357   1.1  christos 		st->rpz_ver = rpz_ver;
   4358   1.1  christos 		client->query.rpz_st = st;
   4359   1.1  christos #ifdef USE_DNSRPS
   4360   1.1  christos 		if (popt.dnsrps_enabled) {
   4361   1.1  christos 			if (st->rpsdb != NULL) {
   4362   1.1  christos 				dns_db_detach(&st->rpsdb);
   4363   1.1  christos 			}
   4364  1.23  christos 			CTRACE(ISC_LOG_DEBUG(3), "dns_dnsrps_rewrite_init");
   4365   1.9  christos 			result = dns_dnsrps_rewrite_init(
   4366   1.9  christos 				&emsg, st, rpzs, client->query.qname,
   4367  1.23  christos 				client->manager->mctx, RECURSIONOK(client));
   4368   1.1  christos 			if (result != ISC_R_SUCCESS) {
   4369   1.9  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   4370   1.9  christos 					     DNS_RPZ_TYPE_QNAME, emsg.c,
   4371   1.9  christos 					     result);
   4372   1.1  christos 				st->m.policy = DNS_RPZ_POLICY_ERROR;
   4373  1.23  christos 				return ISC_R_SUCCESS;
   4374   1.1  christos 			}
   4375   1.1  christos 		}
   4376   1.9  christos #endif /* ifdef USE_DNSRPS */
   4377   1.1  christos 	}
   4378   1.1  christos 
   4379  1.26  christos 	/* Check if the initial loading of RPZ is complete. */
   4380  1.26  christos 	if (first_time && popt.servfail_until_ready &&
   4381  1.26  christos 	    zones_processed < zones_registered)
   4382  1.26  christos 	{
   4383  1.26  christos 		/* Do not pollute SERVFAIL cache  */
   4384  1.26  christos 		client->attributes |= NS_CLIENTATTR_NOSETFC;
   4385  1.26  christos 
   4386  1.26  christos 		if (can_log_rpznotready()) {
   4387  1.26  christos 			rpz_log_fail(client, DNS_RPZ_INFO_LEVEL, NULL,
   4388  1.26  christos 				     DNS_RPZ_TYPE_QNAME,
   4389  1.26  christos 				     "RPZ servfail-until-ready", DNS_R_WAIT);
   4390  1.26  christos 		}
   4391  1.26  christos 
   4392  1.26  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   4393  1.26  christos 		goto cleanup;
   4394  1.26  christos 	}
   4395  1.26  christos 
   4396   1.1  christos 	/*
   4397   1.1  christos 	 * There is nothing to rewrite if the main query failed.
   4398   1.1  christos 	 */
   4399   1.1  christos 	switch (qresult) {
   4400   1.1  christos 	case ISC_R_SUCCESS:
   4401   1.1  christos 	case DNS_R_GLUE:
   4402   1.1  christos 	case DNS_R_ZONECUT:
   4403   1.1  christos 		qresult_type = qresult_type_done;
   4404   1.1  christos 		break;
   4405   1.1  christos 	case DNS_R_EMPTYNAME:
   4406   1.1  christos 	case DNS_R_NXRRSET:
   4407   1.1  christos 	case DNS_R_NXDOMAIN:
   4408   1.1  christos 	case DNS_R_EMPTYWILD:
   4409   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   4410   1.1  christos 	case DNS_R_NCACHENXRRSET:
   4411   1.3  christos 	case DNS_R_COVERINGNSEC:
   4412   1.1  christos 	case DNS_R_CNAME:
   4413   1.1  christos 	case DNS_R_DNAME:
   4414   1.1  christos 		qresult_type = qresult_type_restart;
   4415   1.1  christos 		break;
   4416   1.1  christos 	case DNS_R_DELEGATION:
   4417   1.1  christos 	case ISC_R_NOTFOUND:
   4418   1.1  christos 		/*
   4419   1.1  christos 		 * If recursion is on, do only tentative rewriting.
   4420   1.1  christos 		 * If recursion is off, this the normal and only time we
   4421   1.1  christos 		 * can rewrite.
   4422   1.1  christos 		 */
   4423   1.9  christos 		if (RECURSIONOK(client)) {
   4424   1.1  christos 			qresult_type = qresult_type_recurse;
   4425   1.9  christos 		} else {
   4426   1.1  christos 			qresult_type = qresult_type_restart;
   4427   1.9  christos 		}
   4428   1.1  christos 		break;
   4429   1.1  christos 	case ISC_R_FAILURE:
   4430   1.1  christos 	case ISC_R_TIMEDOUT:
   4431  1.22  christos 	case ISC_R_CANCELED:
   4432   1.1  christos 	case DNS_R_BROKENCHAIN:
   4433   1.1  christos 		rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, NULL,
   4434   1.1  christos 			     DNS_RPZ_TYPE_QNAME,
   4435   1.3  christos 			     "stop on qresult in rpz_rewrite()", qresult);
   4436  1.23  christos 		return ISC_R_SUCCESS;
   4437   1.1  christos 	default:
   4438   1.1  christos 		rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, NULL,
   4439   1.1  christos 			     DNS_RPZ_TYPE_QNAME,
   4440   1.3  christos 			     "stop on unrecognized qresult in rpz_rewrite()",
   4441   1.1  christos 			     qresult);
   4442  1.23  christos 		return ISC_R_SUCCESS;
   4443   1.1  christos 	}
   4444   1.1  christos 
   4445   1.1  christos 	if ((st->state & (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) !=
   4446   1.1  christos 	    (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME))
   4447   1.1  christos 	{
   4448   1.1  christos 		isc_netaddr_t netaddr;
   4449   1.1  christos 		dns_rpz_zbits_t allowed;
   4450   1.1  christos 
   4451   1.1  christos 		if (!st->popt.dnsrps_enabled &&
   4452  1.16  christos 		    qresult_type == qresult_type_recurse)
   4453  1.16  christos 		{
   4454   1.1  christos 			/*
   4455   1.1  christos 			 * This request needs recursion that has not been done.
   4456   1.1  christos 			 * Get bits for the policy zones that do not need
   4457   1.1  christos 			 * to wait for the results of recursion.
   4458   1.1  christos 			 */
   4459   1.1  christos 			allowed = st->have.qname_skip_recurse;
   4460   1.1  christos 			if (allowed == 0) {
   4461  1.23  christos 				return ISC_R_SUCCESS;
   4462   1.1  christos 			}
   4463   1.1  christos 		} else {
   4464   1.1  christos 			allowed = DNS_RPZ_ALL_ZBITS;
   4465   1.1  christos 		}
   4466   1.1  christos 
   4467   1.1  christos 		/*
   4468   1.1  christos 		 * Check once for triggers for the client IP address.
   4469   1.1  christos 		 */
   4470   1.1  christos 		if ((st->state & DNS_RPZ_DONE_CLIENT_IP) == 0) {
   4471   1.1  christos 			zbits = rpz_get_zbits(client, dns_rdatatype_none,
   4472   1.1  christos 					      DNS_RPZ_TYPE_CLIENT_IP);
   4473   1.1  christos 			zbits &= allowed;
   4474   1.1  christos 			if (zbits != 0) {
   4475   1.1  christos 				isc_netaddr_fromsockaddr(&netaddr,
   4476   1.1  christos 							 &client->peeraddr);
   4477   1.1  christos 				result = rpz_rewrite_ip(client, &netaddr, qtype,
   4478   1.1  christos 							DNS_RPZ_TYPE_CLIENT_IP,
   4479   1.1  christos 							zbits, &rdataset);
   4480   1.9  christos 				if (result != ISC_R_SUCCESS) {
   4481   1.1  christos 					goto cleanup;
   4482   1.9  christos 				}
   4483   1.1  christos 			}
   4484   1.1  christos 		}
   4485   1.1  christos 
   4486   1.1  christos 		/*
   4487   1.1  christos 		 * Check triggers for the query name if this is the first time
   4488   1.1  christos 		 * for the current qname.
   4489   1.1  christos 		 * There is a first time for each name in a CNAME chain
   4490   1.1  christos 		 */
   4491   1.1  christos 		if ((st->state & DNS_RPZ_DONE_QNAME) == 0) {
   4492   1.3  christos 			bool norec = (qresult_type != qresult_type_recurse);
   4493   1.1  christos 			result = rpz_rewrite_name(client, client->query.qname,
   4494   1.1  christos 						  qtype, DNS_RPZ_TYPE_QNAME,
   4495   1.9  christos 						  allowed, norec, &rdataset);
   4496   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4497   1.1  christos 				goto cleanup;
   4498   1.9  christos 			}
   4499   1.1  christos 
   4500   1.1  christos 			/*
   4501   1.1  christos 			 * Check IPv4 addresses in A RRs next.
   4502   1.1  christos 			 * Reset to the start of the NS names.
   4503   1.1  christos 			 */
   4504   1.1  christos 			st->r.label = dns_name_countlabels(client->query.qname);
   4505   1.1  christos 			st->state &= ~(DNS_RPZ_DONE_QNAME_IP |
   4506   1.1  christos 				       DNS_RPZ_DONE_IPv4);
   4507   1.1  christos 		}
   4508   1.1  christos 
   4509   1.1  christos 		/*
   4510   1.1  christos 		 * Quit if this was an attempt to find a qname or
   4511   1.1  christos 		 * client-IP trigger before recursion.
   4512   1.1  christos 		 * We will be back if no pre-recursion triggers hit.
   4513   1.1  christos 		 * For example, consider 2 policy zones, both with qname and
   4514   1.1  christos 		 * IP address triggers.  If the qname misses the 1st zone,
   4515   1.1  christos 		 * then we cannot know whether a hit for the qname in the
   4516   1.1  christos 		 * 2nd zone matters until after recursing to get the A RRs and
   4517   1.1  christos 		 * testing them in the first zone.
   4518   1.1  christos 		 * Do not bother saving the work from this attempt,
   4519   1.9  christos 		 * because recursion is so slow.
   4520   1.1  christos 		 */
   4521   1.9  christos 		if (qresult_type == qresult_type_recurse) {
   4522   1.1  christos 			goto cleanup;
   4523   1.9  christos 		}
   4524   1.1  christos 
   4525   1.1  christos 		/*
   4526   1.1  christos 		 * DNS_RPZ_DONE_QNAME but not DNS_RPZ_DONE_CLIENT_IP
   4527   1.1  christos 		 * is reset at the end of dealing with each CNAME.
   4528   1.1  christos 		 */
   4529   1.1  christos 		st->state |= (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME);
   4530   1.1  christos 	}
   4531   1.1  christos 
   4532   1.1  christos 	/*
   4533   1.1  christos 	 * Check known IP addresses for the query name if the database lookup
   4534   1.1  christos 	 * resulted in some addresses (qresult_type == qresult_type_done)
   4535   1.1  christos 	 * and if we have not already checked them.
   4536   1.1  christos 	 * Any recursion required for the query has already happened.
   4537   1.1  christos 	 * Do not check addresses that will not be in the ANSWER section.
   4538   1.1  christos 	 */
   4539   1.1  christos 	if ((st->state & DNS_RPZ_DONE_QNAME_IP) == 0 &&
   4540   1.1  christos 	    qresult_type == qresult_type_done &&
   4541   1.9  christos 	    rpz_get_zbits(client, qtype, DNS_RPZ_TYPE_IP) != 0)
   4542   1.9  christos 	{
   4543   1.9  christos 		result = rpz_rewrite_ip_rrsets(client, client->query.qname,
   4544   1.9  christos 					       qtype, DNS_RPZ_TYPE_IP,
   4545   1.1  christos 					       &rdataset, resuming);
   4546   1.9  christos 		if (result != ISC_R_SUCCESS) {
   4547   1.1  christos 			goto cleanup;
   4548   1.9  christos 		}
   4549   1.1  christos 		/*
   4550   1.1  christos 		 * We are finished checking the IP addresses for the qname.
   4551   1.9  christos 		 * Start with IPv4 if we will check NS IP addresses.
   4552   1.1  christos 		 */
   4553   1.1  christos 		st->state |= DNS_RPZ_DONE_QNAME_IP;
   4554   1.1  christos 		st->state &= ~DNS_RPZ_DONE_IPv4;
   4555   1.1  christos 	}
   4556   1.1  christos 
   4557   1.1  christos 	/*
   4558   1.1  christos 	 * Stop looking for rules if there are none of the other kinds
   4559   1.1  christos 	 * that could override what we already have.
   4560   1.1  christos 	 */
   4561   1.9  christos 	if (rpz_get_zbits(client, dns_rdatatype_any, DNS_RPZ_TYPE_NSDNAME) ==
   4562   1.9  christos 		    0 &&
   4563   1.9  christos 	    rpz_get_zbits(client, dns_rdatatype_any, DNS_RPZ_TYPE_NSIP) == 0)
   4564   1.9  christos 	{
   4565   1.1  christos 		result = ISC_R_SUCCESS;
   4566   1.1  christos 		goto cleanup;
   4567   1.1  christos 	}
   4568   1.1  christos 
   4569   1.1  christos 	dns_fixedname_init(&nsnamef);
   4570   1.1  christos 	dns_name_clone(client->query.qname, dns_fixedname_name(&nsnamef));
   4571  1.16  christos 	options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   4572   1.1  christos 	while (st->r.label > st->popt.min_ns_labels) {
   4573  1.15  christos 		bool was_glue = false;
   4574   1.1  christos 		/*
   4575   1.1  christos 		 * Get NS rrset for each domain in the current qname.
   4576   1.1  christos 		 */
   4577   1.1  christos 		if (st->r.label == dns_name_countlabels(client->query.qname)) {
   4578   1.1  christos 			nsname = client->query.qname;
   4579   1.1  christos 		} else {
   4580   1.1  christos 			nsname = dns_fixedname_name(&nsnamef);
   4581   1.9  christos 			dns_name_split(client->query.qname, st->r.label, NULL,
   4582   1.9  christos 				       nsname);
   4583   1.1  christos 		}
   4584   1.1  christos 		if (st->r.ns_rdataset == NULL ||
   4585  1.16  christos 		    !dns_rdataset_isassociated(st->r.ns_rdataset))
   4586  1.16  christos 		{
   4587   1.1  christos 			dns_db_t *db = NULL;
   4588   1.1  christos 			result = rpz_rrset_find(client, nsname,
   4589  1.15  christos 						dns_rdatatype_ns, options,
   4590   1.9  christos 						DNS_RPZ_TYPE_NSDNAME, &db, NULL,
   4591   1.9  christos 						&st->r.ns_rdataset, resuming);
   4592   1.9  christos 			if (db != NULL) {
   4593   1.1  christos 				dns_db_detach(&db);
   4594   1.9  christos 			}
   4595   1.9  christos 			if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
   4596   1.1  christos 				goto cleanup;
   4597   1.9  christos 			}
   4598   1.1  christos 			switch (result) {
   4599  1.15  christos 			case DNS_R_GLUE:
   4600  1.15  christos 				was_glue = true;
   4601  1.15  christos 				FALLTHROUGH;
   4602   1.1  christos 			case ISC_R_SUCCESS:
   4603   1.1  christos 				result = dns_rdataset_first(st->r.ns_rdataset);
   4604   1.9  christos 				if (result != ISC_R_SUCCESS) {
   4605   1.1  christos 					goto cleanup;
   4606   1.9  christos 				}
   4607   1.1  christos 				st->state &= ~(DNS_RPZ_DONE_NSDNAME |
   4608   1.1  christos 					       DNS_RPZ_DONE_IPv4);
   4609   1.1  christos 				break;
   4610   1.1  christos 			case DNS_R_DELEGATION:
   4611   1.1  christos 			case DNS_R_DUPLICATE:
   4612   1.1  christos 			case DNS_R_DROP:
   4613   1.1  christos 				goto cleanup;
   4614   1.1  christos 			case DNS_R_EMPTYNAME:
   4615   1.1  christos 			case DNS_R_NXRRSET:
   4616   1.1  christos 			case DNS_R_EMPTYWILD:
   4617   1.1  christos 			case DNS_R_NXDOMAIN:
   4618   1.1  christos 			case DNS_R_NCACHENXDOMAIN:
   4619   1.1  christos 			case DNS_R_NCACHENXRRSET:
   4620   1.1  christos 			case ISC_R_NOTFOUND:
   4621   1.1  christos 			case DNS_R_CNAME:
   4622   1.1  christos 			case DNS_R_DNAME:
   4623   1.9  christos 				rpz_rewrite_ns_skip(client, nsname, result, 0,
   4624   1.9  christos 						    NULL);
   4625   1.1  christos 				continue;
   4626   1.1  christos 			case ISC_R_TIMEDOUT:
   4627   1.1  christos 			case DNS_R_BROKENCHAIN:
   4628   1.1  christos 			case ISC_R_FAILURE:
   4629   1.1  christos 				rpz_rewrite_ns_skip(client, nsname, result,
   4630   1.9  christos 						    DNS_RPZ_DEBUG_LEVEL3,
   4631   1.9  christos 						    " NS rpz_rrset_find()");
   4632   1.1  christos 				continue;
   4633   1.1  christos 			default:
   4634   1.1  christos 				rpz_rewrite_ns_skip(client, nsname, result,
   4635   1.9  christos 						    DNS_RPZ_INFO_LEVEL,
   4636   1.9  christos 						    " unrecognized NS"
   4637   1.9  christos 						    " rpz_rrset_find()");
   4638   1.1  christos 				continue;
   4639   1.1  christos 			}
   4640   1.1  christos 		}
   4641  1.15  christos 
   4642   1.1  christos 		/*
   4643   1.1  christos 		 * Check all NS names.
   4644   1.1  christos 		 */
   4645   1.1  christos 		do {
   4646   1.1  christos 			dns_rdata_ns_t ns;
   4647   1.1  christos 			dns_rdata_t nsrdata = DNS_RDATA_INIT;
   4648   1.1  christos 
   4649   1.1  christos 			dns_rdataset_current(st->r.ns_rdataset, &nsrdata);
   4650   1.1  christos 			result = dns_rdata_tostruct(&nsrdata, &ns, NULL);
   4651   1.3  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4652   1.1  christos 			dns_rdata_reset(&nsrdata);
   4653   1.3  christos 
   4654   1.1  christos 			/*
   4655   1.1  christos 			 * Do nothing about "NS ."
   4656   1.1  christos 			 */
   4657   1.1  christos 			if (dns_name_equal(&ns.name, dns_rootname)) {
   4658   1.1  christos 				dns_rdata_freestruct(&ns);
   4659   1.1  christos 				result = dns_rdataset_next(st->r.ns_rdataset);
   4660   1.1  christos 				continue;
   4661   1.1  christos 			}
   4662   1.1  christos 			/*
   4663   1.1  christos 			 * Check this NS name if we did not handle it
   4664   1.1  christos 			 * during a previous recursion.
   4665   1.1  christos 			 */
   4666   1.1  christos 			if ((st->state & DNS_RPZ_DONE_NSDNAME) == 0) {
   4667   1.9  christos 				result = rpz_rewrite_name(
   4668   1.9  christos 					client, &ns.name, qtype,
   4669   1.9  christos 					DNS_RPZ_TYPE_NSDNAME, DNS_RPZ_ALL_ZBITS,
   4670   1.9  christos 					true, &rdataset);
   4671   1.1  christos 				if (result != ISC_R_SUCCESS) {
   4672   1.1  christos 					dns_rdata_freestruct(&ns);
   4673   1.1  christos 					goto cleanup;
   4674   1.1  christos 				}
   4675   1.1  christos 				st->state |= DNS_RPZ_DONE_NSDNAME;
   4676   1.1  christos 			}
   4677   1.1  christos 			/*
   4678   1.1  christos 			 * Check all IP addresses for this NS name.
   4679   1.1  christos 			 */
   4680   1.1  christos 			result = rpz_rewrite_ip_rrsets(client, &ns.name, qtype,
   4681   1.1  christos 						       DNS_RPZ_TYPE_NSIP,
   4682   1.1  christos 						       &rdataset, resuming);
   4683   1.1  christos 			dns_rdata_freestruct(&ns);
   4684   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4685   1.1  christos 				goto cleanup;
   4686   1.9  christos 			}
   4687   1.1  christos 			st->state &= ~(DNS_RPZ_DONE_NSDNAME |
   4688   1.1  christos 				       DNS_RPZ_DONE_IPv4);
   4689   1.1  christos 			result = dns_rdataset_next(st->r.ns_rdataset);
   4690   1.1  christos 		} while (result == ISC_R_SUCCESS);
   4691   1.1  christos 		dns_rdataset_disassociate(st->r.ns_rdataset);
   4692  1.15  christos 
   4693  1.15  christos 		/*
   4694  1.15  christos 		 * If we just checked a glue NS RRset retry without allowing
   4695  1.15  christos 		 * glue responses, otherwise setup for the next name.
   4696  1.15  christos 		 */
   4697  1.15  christos 		if (was_glue) {
   4698  1.16  christos 			options = client->query.dboptions;
   4699  1.15  christos 		} else {
   4700  1.16  christos 			options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   4701  1.15  christos 			st->r.label--;
   4702  1.15  christos 		}
   4703   1.1  christos 
   4704   1.1  christos 		if (rpz_get_zbits(client, dns_rdatatype_any,
   4705   1.1  christos 				  DNS_RPZ_TYPE_NSDNAME) == 0 &&
   4706   1.1  christos 		    rpz_get_zbits(client, dns_rdatatype_any,
   4707   1.1  christos 				  DNS_RPZ_TYPE_NSIP) == 0)
   4708   1.9  christos 		{
   4709   1.1  christos 			break;
   4710   1.9  christos 		}
   4711   1.1  christos 	}
   4712   1.1  christos 
   4713   1.1  christos 	/*
   4714   1.1  christos 	 * Use the best hit, if any.
   4715   1.1  christos 	 */
   4716   1.1  christos 	result = ISC_R_SUCCESS;
   4717   1.1  christos 
   4718   1.1  christos cleanup:
   4719   1.1  christos #ifdef USE_DNSRPS
   4720   1.9  christos 	if (st->popt.dnsrps_enabled && st->m.policy != DNS_RPZ_POLICY_ERROR &&
   4721   1.1  christos 	    !dnsrps_set_p(&emsg, client, st, qtype, &rdataset,
   4722  1.25  christos 			  qresult_type != qresult_type_recurse))
   4723   1.1  christos 	{
   4724   1.1  christos 		rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   4725   1.1  christos 			     DNS_RPZ_TYPE_BAD, emsg.c, DNS_R_SERVFAIL);
   4726   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   4727   1.1  christos 	}
   4728   1.9  christos #endif /* ifdef USE_DNSRPS */
   4729   1.1  christos 	if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   4730   1.1  christos 	    st->m.policy != DNS_RPZ_POLICY_ERROR &&
   4731   1.1  christos 	    st->m.rpz->policy != DNS_RPZ_POLICY_GIVEN)
   4732   1.9  christos 	{
   4733   1.1  christos 		st->m.policy = st->m.rpz->policy;
   4734   1.9  christos 	}
   4735   1.1  christos 	if (st->m.policy == DNS_RPZ_POLICY_MISS ||
   4736   1.1  christos 	    st->m.policy == DNS_RPZ_POLICY_PASSTHRU ||
   4737   1.9  christos 	    st->m.policy == DNS_RPZ_POLICY_ERROR)
   4738   1.9  christos 	{
   4739   1.1  christos 		if (st->m.policy == DNS_RPZ_POLICY_PASSTHRU &&
   4740  1.16  christos 		    result != DNS_R_DELEGATION)
   4741  1.16  christos 		{
   4742   1.9  christos 			rpz_log_rewrite(client, false, st->m.policy, st->m.type,
   4743   1.9  christos 					st->m.zone, st->p_name, NULL,
   4744   1.9  christos 					st->m.rpz->num);
   4745   1.9  christos 		}
   4746   1.1  christos 		rpz_match_clear(st);
   4747   1.1  christos 	}
   4748   1.1  christos 	if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
   4749   1.1  christos 		CTRACE(ISC_LOG_ERROR, "SERVFAIL due to RPZ policy");
   4750   1.1  christos 		st->m.type = DNS_RPZ_TYPE_BAD;
   4751   1.1  christos 		result = DNS_R_SERVFAIL;
   4752   1.1  christos 	}
   4753   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   4754   1.9  christos 	if ((st->state & DNS_RPZ_RECURSING) == 0) {
   4755   1.1  christos 		rpz_clean(NULL, &st->r.db, NULL, &st->r.ns_rdataset);
   4756   1.9  christos 	}
   4757   1.1  christos 
   4758  1.23  christos 	return result;
   4759   1.1  christos }
   4760   1.1  christos 
   4761   1.1  christos /*
   4762   1.1  christos  * See if response policy zone rewriting is allowed by a lack of interest
   4763   1.1  christos  * by the client in DNSSEC or a lack of signatures.
   4764   1.1  christos  */
   4765   1.3  christos static bool
   4766   1.1  christos rpz_ck_dnssec(ns_client_t *client, isc_result_t qresult,
   4767   1.9  christos 	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
   4768   1.1  christos 	dns_fixedname_t fixed;
   4769   1.1  christos 	dns_name_t *found;
   4770   1.1  christos 	dns_rdataset_t trdataset;
   4771   1.1  christos 	dns_rdatatype_t type;
   4772   1.1  christos 	isc_result_t result;
   4773   1.1  christos 
   4774   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_ck_dnssec");
   4775   1.1  christos 
   4776   1.9  christos 	if (client->view->rpzs->p.break_dnssec || !WANTDNSSEC(client)) {
   4777  1.23  christos 		return true;
   4778   1.9  christos 	}
   4779   1.1  christos 
   4780   1.1  christos 	/*
   4781   1.1  christos 	 * We do not know if there are signatures if we have not recursed
   4782   1.1  christos 	 * for them.
   4783   1.1  christos 	 */
   4784   1.9  christos 	if (qresult == DNS_R_DELEGATION || qresult == ISC_R_NOTFOUND) {
   4785  1.23  christos 		return false;
   4786   1.9  christos 	}
   4787   1.1  christos 
   4788   1.9  christos 	if (sigrdataset == NULL) {
   4789  1.23  christos 		return true;
   4790   1.9  christos 	}
   4791   1.9  christos 	if (dns_rdataset_isassociated(sigrdataset)) {
   4792  1.23  christos 		return false;
   4793   1.9  christos 	}
   4794   1.1  christos 
   4795   1.1  christos 	/*
   4796   1.1  christos 	 * We are happy to rewrite nothing.
   4797   1.1  christos 	 */
   4798   1.9  christos 	if (rdataset == NULL || !dns_rdataset_isassociated(rdataset)) {
   4799  1.23  christos 		return true;
   4800   1.9  christos 	}
   4801   1.1  christos 	/*
   4802   1.1  christos 	 * Do not rewrite if there is any sign of signatures.
   4803   1.1  christos 	 */
   4804   1.1  christos 	if (rdataset->type == dns_rdatatype_nsec ||
   4805   1.1  christos 	    rdataset->type == dns_rdatatype_nsec3 ||
   4806   1.1  christos 	    rdataset->type == dns_rdatatype_rrsig)
   4807   1.9  christos 	{
   4808  1.23  christos 		return false;
   4809   1.9  christos 	}
   4810   1.1  christos 
   4811   1.1  christos 	/*
   4812   1.1  christos 	 * Look for a signature in a negative cache rdataset.
   4813   1.1  christos 	 */
   4814   1.9  christos 	if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) == 0) {
   4815  1.23  christos 		return true;
   4816   1.9  christos 	}
   4817   1.1  christos 	found = dns_fixedname_initname(&fixed);
   4818   1.1  christos 	dns_rdataset_init(&trdataset);
   4819   1.9  christos 	for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
   4820   1.9  christos 	     result = dns_rdataset_next(rdataset))
   4821   1.9  christos 	{
   4822   1.1  christos 		dns_ncache_current(rdataset, found, &trdataset);
   4823   1.1  christos 		type = trdataset.type;
   4824   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   4825   1.9  christos 		if (type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3 ||
   4826   1.1  christos 		    type == dns_rdatatype_rrsig)
   4827   1.9  christos 		{
   4828  1.23  christos 			return false;
   4829   1.9  christos 		}
   4830   1.1  christos 	}
   4831  1.23  christos 	return true;
   4832   1.1  christos }
   4833   1.1  christos 
   4834   1.1  christos /*
   4835   1.1  christos  * Extract a network address from the RDATA of an A or AAAA
   4836   1.1  christos  * record.
   4837   1.1  christos  *
   4838   1.1  christos  * Returns:
   4839   1.1  christos  *	ISC_R_SUCCESS
   4840   1.1  christos  *	ISC_R_NOTIMPLEMENTED	The rdata is not a known address type.
   4841   1.1  christos  */
   4842   1.1  christos static isc_result_t
   4843   1.1  christos rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
   4844   1.1  christos 	struct in_addr ina;
   4845   1.1  christos 	struct in6_addr in6a;
   4846   1.1  christos 
   4847   1.1  christos 	switch (rdata->type) {
   4848   1.1  christos 	case dns_rdatatype_a:
   4849   1.1  christos 		INSIST(rdata->length == 4);
   4850   1.1  christos 		memmove(&ina.s_addr, rdata->data, 4);
   4851   1.1  christos 		isc_netaddr_fromin(netaddr, &ina);
   4852  1.23  christos 		return ISC_R_SUCCESS;
   4853   1.1  christos 	case dns_rdatatype_aaaa:
   4854   1.1  christos 		INSIST(rdata->length == 16);
   4855   1.1  christos 		memmove(in6a.s6_addr, rdata->data, 16);
   4856   1.1  christos 		isc_netaddr_fromin6(netaddr, &in6a);
   4857  1.23  christos 		return ISC_R_SUCCESS;
   4858   1.1  christos 	default:
   4859  1.23  christos 		return ISC_R_NOTIMPLEMENTED;
   4860   1.1  christos 	}
   4861   1.1  christos }
   4862   1.1  christos 
   4863   1.1  christos static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
   4864   1.1  christos static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
   4865   1.1  christos static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
   4866   1.1  christos 
   4867   1.1  christos static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
   4868   1.1  christos 
   4869   1.1  christos static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
   4870   1.1  christos static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
   4871   1.1  christos static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
   4872   1.1  christos static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
   4873   1.1  christos static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
   4874   1.1  christos static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
   4875   1.1  christos static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
   4876   1.1  christos static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
   4877   1.1  christos static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
   4878   1.1  christos static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
   4879   1.1  christos static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
   4880   1.1  christos static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
   4881   1.1  christos static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
   4882   1.1  christos static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
   4883   1.1  christos static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
   4884   1.1  christos static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
   4885   1.1  christos 
   4886   1.1  christos static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
   4887   1.1  christos 
   4888   1.1  christos static dns_name_t rfc1918names[] = {
   4889   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr10, inaddr10_offsets),
   4890   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr16172, inaddr172_offsets),
   4891   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr17172, inaddr172_offsets),
   4892   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr18172, inaddr172_offsets),
   4893   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr19172, inaddr172_offsets),
   4894   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr20172, inaddr172_offsets),
   4895   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr21172, inaddr172_offsets),
   4896   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr22172, inaddr172_offsets),
   4897   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr23172, inaddr172_offsets),
   4898   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr24172, inaddr172_offsets),
   4899   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr25172, inaddr172_offsets),
   4900   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr26172, inaddr172_offsets),
   4901   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr27172, inaddr172_offsets),
   4902   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr28172, inaddr172_offsets),
   4903   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr29172, inaddr172_offsets),
   4904   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr30172, inaddr172_offsets),
   4905   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr31172, inaddr172_offsets),
   4906   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets)
   4907   1.1  christos };
   4908   1.1  christos 
   4909   1.1  christos static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
   4910   1.9  christos static unsigned char hostmaster_data[] = "\012hostmaster\014root-"
   4911   1.9  christos 					 "servers\003org";
   4912   1.1  christos 
   4913   1.1  christos static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 };
   4914   1.1  christos static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 };
   4915   1.1  christos 
   4916   1.9  christos static dns_name_t const prisoner = DNS_NAME_INITABSOLUTE(prisoner_data,
   4917   1.9  christos 							 prisoner_offsets);
   4918   1.9  christos static dns_name_t const hostmaster = DNS_NAME_INITABSOLUTE(hostmaster_data,
   4919   1.9  christos 							   hostmaster_offsets);
   4920   1.1  christos 
   4921   1.1  christos static void
   4922   1.1  christos warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) {
   4923   1.1  christos 	unsigned int i;
   4924   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   4925   1.1  christos 	dns_rdata_soa_t soa;
   4926   1.1  christos 	dns_rdataset_t found;
   4927   1.1  christos 	isc_result_t result;
   4928   1.1  christos 
   4929   1.9  christos 	for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) {
   4930   1.1  christos 		if (dns_name_issubdomain(fname, &rfc1918names[i])) {
   4931   1.1  christos 			dns_rdataset_init(&found);
   4932   1.9  christos 			result = dns_ncache_getrdataset(
   4933   1.9  christos 				rdataset, &rfc1918names[i], dns_rdatatype_soa,
   4934   1.9  christos 				&found);
   4935   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4936   1.1  christos 				return;
   4937   1.9  christos 			}
   4938   1.1  christos 
   4939   1.1  christos 			result = dns_rdataset_first(&found);
   4940   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4941   1.1  christos 			dns_rdataset_current(&found, &rdata);
   4942   1.1  christos 			result = dns_rdata_tostruct(&rdata, &soa, NULL);
   4943   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4944   1.1  christos 			if (dns_name_equal(&soa.origin, &prisoner) &&
   4945   1.9  christos 			    dns_name_equal(&soa.contact, &hostmaster))
   4946   1.9  christos 			{
   4947   1.1  christos 				char buf[DNS_NAME_FORMATSIZE];
   4948   1.1  christos 				dns_name_format(fname, buf, sizeof(buf));
   4949   1.1  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   4950   1.1  christos 					      NS_LOGMODULE_QUERY,
   4951   1.1  christos 					      ISC_LOG_WARNING,
   4952   1.1  christos 					      "RFC 1918 response from "
   4953   1.9  christos 					      "Internet for %s",
   4954   1.9  christos 					      buf);
   4955   1.1  christos 			}
   4956   1.1  christos 			dns_rdataset_disassociate(&found);
   4957   1.1  christos 			return;
   4958   1.1  christos 		}
   4959   1.1  christos 	}
   4960   1.1  christos }
   4961   1.1  christos 
   4962   1.1  christos static void
   4963   1.1  christos query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
   4964   1.1  christos 		       dns_dbversion_t *version, ns_client_t *client,
   4965   1.1  christos 		       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
   4966   1.9  christos 		       dns_name_t *fname, bool exact, dns_name_t *found) {
   4967   1.1  christos 	unsigned char salt[256];
   4968   1.1  christos 	size_t salt_length;
   4969   1.3  christos 	uint16_t iterations;
   4970   1.1  christos 	isc_result_t result;
   4971   1.1  christos 	unsigned int dboptions;
   4972   1.1  christos 	dns_fixedname_t fixed;
   4973   1.1  christos 	dns_hash_t hash;
   4974   1.1  christos 	dns_name_t name;
   4975   1.1  christos 	unsigned int skip = 0, labels;
   4976   1.1  christos 	dns_rdata_nsec3_t nsec3;
   4977   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   4978   1.3  christos 	bool optout;
   4979   1.1  christos 	dns_clientinfomethods_t cm;
   4980   1.1  christos 	dns_clientinfo_t ci;
   4981   1.1  christos 
   4982   1.1  christos 	salt_length = sizeof(salt);
   4983   1.1  christos 	result = dns_db_getnsec3parameters(db, version, &hash, NULL,
   4984   1.1  christos 					   &iterations, salt, &salt_length);
   4985   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4986   1.1  christos 		return;
   4987   1.9  christos 	}
   4988   1.1  christos 
   4989   1.1  christos 	dns_name_init(&name, NULL);
   4990   1.1  christos 	dns_name_clone(qname, &name);
   4991   1.1  christos 	labels = dns_name_countlabels(&name);
   4992   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   4993  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   4994   1.1  christos 
   4995   1.1  christos 	/*
   4996   1.1  christos 	 * Map unknown algorithm to known value.
   4997   1.1  christos 	 */
   4998   1.9  christos 	if (hash == DNS_NSEC3_UNKNOWNALG) {
   4999   1.1  christos 		hash = 1;
   5000   1.9  christos 	}
   5001   1.1  christos 
   5002   1.9  christos again:
   5003   1.1  christos 	dns_fixedname_init(&fixed);
   5004   1.1  christos 	result = dns_nsec3_hashname(&fixed, NULL, NULL, &name,
   5005   1.9  christos 				    dns_db_origin(db), hash, iterations, salt,
   5006   1.9  christos 				    salt_length);
   5007   1.9  christos 	if (result != ISC_R_SUCCESS) {
   5008   1.1  christos 		return;
   5009   1.9  christos 	}
   5010   1.1  christos 
   5011   1.1  christos 	dboptions = client->query.dboptions | DNS_DBFIND_FORCENSEC3;
   5012   1.1  christos 	result = dns_db_findext(db, dns_fixedname_name(&fixed), version,
   5013   1.1  christos 				dns_rdatatype_nsec3, dboptions, client->now,
   5014   1.1  christos 				NULL, fname, &cm, &ci, rdataset, sigrdataset);
   5015   1.1  christos 
   5016   1.1  christos 	if (result == DNS_R_NXDOMAIN) {
   5017   1.1  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   5018   1.1  christos 			return;
   5019   1.1  christos 		}
   5020   1.1  christos 		result = dns_rdataset_first(rdataset);
   5021   1.1  christos 		INSIST(result == ISC_R_SUCCESS);
   5022   1.1  christos 		dns_rdataset_current(rdataset, &rdata);
   5023   1.3  christos 		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
   5024   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   5025   1.1  christos 		dns_rdata_reset(&rdata);
   5026   1.3  christos 		optout = ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
   5027   1.1  christos 		if (found != NULL && optout &&
   5028  1.16  christos 		    dns_name_issubdomain(&name, dns_db_origin(db)))
   5029  1.16  christos 		{
   5030   1.1  christos 			dns_rdataset_disassociate(rdataset);
   5031   1.9  christos 			if (dns_rdataset_isassociated(sigrdataset)) {
   5032   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   5033   1.9  christos 			}
   5034   1.1  christos 			skip++;
   5035   1.1  christos 			dns_name_getlabelsequence(qname, skip, labels - skip,
   5036   1.1  christos 						  &name);
   5037   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   5038   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3),
   5039   1.1  christos 				      "looking for closest provable encloser");
   5040   1.1  christos 			goto again;
   5041   1.1  christos 		}
   5042   1.9  christos 		if (exact) {
   5043   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   5044   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   5045   1.1  christos 				      "expected a exact match NSEC3, got "
   5046   1.1  christos 				      "a covering record");
   5047   1.9  christos 		}
   5048   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   5049   1.1  christos 		return;
   5050   1.9  christos 	} else if (!exact) {
   5051   1.1  christos 		ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   5052   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   5053   1.1  christos 			      "expected covering NSEC3, got an exact match");
   5054   1.9  christos 	}
   5055   1.1  christos 	if (found == qname) {
   5056   1.9  christos 		if (skip != 0U) {
   5057   1.1  christos 			dns_name_getlabelsequence(qname, skip, labels - skip,
   5058   1.1  christos 						  found);
   5059   1.9  christos 		}
   5060   1.9  christos 	} else if (found != NULL) {
   5061  1.20  christos 		dns_name_copy(&name, found);
   5062   1.9  christos 	}
   5063   1.1  christos 	return;
   5064   1.1  christos }
   5065   1.1  christos 
   5066   1.3  christos static uint32_t
   5067   1.1  christos dns64_ttl(dns_db_t *db, dns_dbversion_t *version) {
   5068   1.1  christos 	dns_dbnode_t *node = NULL;
   5069   1.1  christos 	dns_rdata_soa_t soa;
   5070   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   5071   1.1  christos 	dns_rdataset_t rdataset;
   5072   1.1  christos 	isc_result_t result;
   5073   1.3  christos 	uint32_t ttl = UINT32_MAX;
   5074   1.1  christos 
   5075   1.1  christos 	dns_rdataset_init(&rdataset);
   5076   1.1  christos 
   5077   1.1  christos 	result = dns_db_getoriginnode(db, &node);
   5078   1.9  christos 	if (result != ISC_R_SUCCESS) {
   5079   1.1  christos 		goto cleanup;
   5080   1.9  christos 	}
   5081   1.1  christos 
   5082   1.9  christos 	result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, 0, 0,
   5083   1.9  christos 				     &rdataset, NULL);
   5084   1.9  christos 	if (result != ISC_R_SUCCESS) {
   5085   1.1  christos 		goto cleanup;
   5086   1.9  christos 	}
   5087   1.1  christos 	result = dns_rdataset_first(&rdataset);
   5088   1.9  christos 	if (result != ISC_R_SUCCESS) {
   5089   1.1  christos 		goto cleanup;
   5090   1.9  christos 	}
   5091   1.1  christos 
   5092   1.1  christos 	dns_rdataset_current(&rdataset, &rdata);
   5093   1.1  christos 	result = dns_rdata_tostruct(&rdata, &soa, NULL);
   5094   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   5095   1.1  christos 	ttl = ISC_MIN(rdataset.ttl, soa.minimum);
   5096   1.1  christos 
   5097   1.1  christos cleanup:
   5098   1.9  christos 	if (dns_rdataset_isassociated(&rdataset)) {
   5099   1.1  christos 		dns_rdataset_disassociate(&rdataset);
   5100   1.9  christos 	}
   5101   1.9  christos 	if (node != NULL) {
   5102   1.1  christos 		dns_db_detachnode(db, &node);
   5103   1.9  christos 	}
   5104  1.23  christos 	return ttl;
   5105   1.1  christos }
   5106   1.1  christos 
   5107   1.3  christos static bool
   5108   1.1  christos dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset,
   5109   1.9  christos 	     dns_rdataset_t *sigrdataset) {
   5110   1.1  christos 	isc_netaddr_t netaddr;
   5111  1.20  christos 	dns_aclenv_t *env = client->manager->aclenv;
   5112   1.1  christos 	dns_dns64_t *dns64 = ISC_LIST_HEAD(client->view->dns64);
   5113   1.1  christos 	unsigned int flags = 0;
   5114   1.1  christos 	unsigned int i, count;
   5115   1.3  christos 	bool *aaaaok;
   5116   1.1  christos 
   5117   1.1  christos 	INSIST(client->query.dns64_aaaaok == NULL);
   5118   1.1  christos 	INSIST(client->query.dns64_aaaaoklen == 0);
   5119   1.1  christos 	INSIST(client->query.dns64_aaaa == NULL);
   5120   1.1  christos 	INSIST(client->query.dns64_sigaaaa == NULL);
   5121   1.1  christos 
   5122   1.9  christos 	if (dns64 == NULL) {
   5123  1.23  christos 		return true;
   5124   1.9  christos 	}
   5125   1.1  christos 
   5126   1.9  christos 	if (RECURSIONOK(client)) {
   5127   1.1  christos 		flags |= DNS_DNS64_RECURSIVE;
   5128   1.9  christos 	}
   5129   1.1  christos 
   5130   1.1  christos 	if (WANTDNSSEC(client) && sigrdataset != NULL &&
   5131   1.1  christos 	    dns_rdataset_isassociated(sigrdataset))
   5132   1.9  christos 	{
   5133   1.1  christos 		flags |= DNS_DNS64_DNSSEC;
   5134   1.9  christos 	}
   5135   1.1  christos 
   5136   1.1  christos 	count = dns_rdataset_count(rdataset);
   5137  1.23  christos 	aaaaok = isc_mem_cget(client->manager->mctx, count, sizeof(bool));
   5138   1.1  christos 
   5139   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   5140   1.9  christos 	if (dns_dns64_aaaaok(dns64, &netaddr, client->signer, env, flags,
   5141   1.9  christos 			     rdataset, aaaaok, count))
   5142   1.1  christos 	{
   5143   1.1  christos 		for (i = 0; i < count; i++) {
   5144   1.1  christos 			if (aaaaok != NULL && !aaaaok[i]) {
   5145   1.1  christos 				SAVE(client->query.dns64_aaaaok, aaaaok);
   5146   1.1  christos 				client->query.dns64_aaaaoklen = count;
   5147   1.1  christos 				break;
   5148   1.1  christos 			}
   5149   1.1  christos 		}
   5150   1.9  christos 		if (aaaaok != NULL) {
   5151  1.23  christos 			isc_mem_cput(client->manager->mctx, aaaaok, count,
   5152  1.23  christos 				     sizeof(bool));
   5153   1.9  christos 		}
   5154  1.23  christos 		return true;
   5155   1.1  christos 	}
   5156   1.9  christos 	if (aaaaok != NULL) {
   5157  1.23  christos 		isc_mem_cput(client->manager->mctx, aaaaok, count,
   5158  1.23  christos 			     sizeof(bool));
   5159   1.9  christos 	}
   5160  1.23  christos 	return false;
   5161   1.1  christos }
   5162   1.1  christos 
   5163   1.1  christos /*
   5164   1.1  christos  * Look for the name and type in the redirection zone.  If found update
   5165   1.3  christos  * the arguments as appropriate.  Return true if a update was
   5166   1.1  christos  * performed.
   5167   1.1  christos  *
   5168   1.1  christos  * Only perform the update if the client is in the allow query acl and
   5169   1.1  christos  * returning the update would not cause a DNSSEC validation failure.
   5170   1.1  christos  */
   5171   1.1  christos static isc_result_t
   5172   1.1  christos redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
   5173   1.1  christos 	 dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
   5174   1.9  christos 	 dns_rdatatype_t qtype) {
   5175   1.1  christos 	dns_db_t *db = NULL;
   5176   1.1  christos 	dns_dbnode_t *node = NULL;
   5177   1.1  christos 	dns_fixedname_t fixed;
   5178   1.1  christos 	dns_name_t *found;
   5179   1.1  christos 	dns_rdataset_t trdataset;
   5180   1.1  christos 	isc_result_t result;
   5181   1.1  christos 	dns_rdatatype_t type;
   5182   1.1  christos 	dns_clientinfomethods_t cm;
   5183   1.1  christos 	dns_clientinfo_t ci;
   5184   1.1  christos 	ns_dbversion_t *dbversion;
   5185   1.1  christos 
   5186   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect");
   5187   1.1  christos 
   5188   1.9  christos 	if (client->view->redirect == NULL) {
   5189  1.23  christos 		return ISC_R_NOTFOUND;
   5190   1.9  christos 	}
   5191   1.1  christos 
   5192   1.1  christos 	found = dns_fixedname_initname(&fixed);
   5193   1.1  christos 	dns_rdataset_init(&trdataset);
   5194   1.1  christos 
   5195   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   5196  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   5197  1.20  christos 	dns_clientinfo_setecs(&ci, &client->ecs);
   5198   1.1  christos 
   5199   1.1  christos 	if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
   5200   1.9  christos 	{
   5201  1.23  christos 		return ISC_R_NOTFOUND;
   5202   1.9  christos 	}
   5203   1.1  christos 
   5204   1.1  christos 	if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
   5205   1.9  christos 		if (rdataset->trust == dns_trust_secure) {
   5206  1.23  christos 			return ISC_R_NOTFOUND;
   5207   1.9  christos 		}
   5208   1.1  christos 		if (rdataset->trust == dns_trust_ultimate &&
   5209   1.1  christos 		    (rdataset->type == dns_rdatatype_nsec ||
   5210   1.1  christos 		     rdataset->type == dns_rdatatype_nsec3))
   5211   1.9  christos 		{
   5212  1.23  christos 			return ISC_R_NOTFOUND;
   5213   1.9  christos 		}
   5214   1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
   5215   1.1  christos 			for (result = dns_rdataset_first(rdataset);
   5216   1.1  christos 			     result == ISC_R_SUCCESS;
   5217   1.9  christos 			     result = dns_rdataset_next(rdataset))
   5218   1.9  christos 			{
   5219   1.1  christos 				dns_ncache_current(rdataset, found, &trdataset);
   5220   1.1  christos 				type = trdataset.type;
   5221   1.1  christos 				dns_rdataset_disassociate(&trdataset);
   5222   1.1  christos 				if (type == dns_rdatatype_nsec ||
   5223   1.1  christos 				    type == dns_rdatatype_nsec3 ||
   5224   1.1  christos 				    type == dns_rdatatype_rrsig)
   5225   1.9  christos 				{
   5226  1.23  christos 					return ISC_R_NOTFOUND;
   5227   1.9  christos 				}
   5228   1.1  christos 			}
   5229   1.1  christos 		}
   5230   1.1  christos 	}
   5231   1.1  christos 
   5232   1.9  christos 	result = ns_client_checkaclsilent(
   5233   1.9  christos 		client, NULL, dns_zone_getqueryacl(client->view->redirect),
   5234   1.9  christos 		true);
   5235   1.9  christos 	if (result != ISC_R_SUCCESS) {
   5236  1.23  christos 		return ISC_R_NOTFOUND;
   5237   1.9  christos 	}
   5238   1.1  christos 
   5239   1.1  christos 	result = dns_zone_getdb(client->view->redirect, &db);
   5240   1.9  christos 	if (result != ISC_R_SUCCESS) {
   5241  1.23  christos 		return ISC_R_NOTFOUND;
   5242   1.9  christos 	}
   5243   1.1  christos 
   5244   1.3  christos 	dbversion = ns_client_findversion(client, db);
   5245   1.1  christos 	if (dbversion == NULL) {
   5246   1.1  christos 		dns_db_detach(&db);
   5247  1.23  christos 		return ISC_R_NOTFOUND;
   5248   1.1  christos 	}
   5249   1.1  christos 
   5250   1.1  christos 	/*
   5251   1.1  christos 	 * Lookup the requested data in the redirect zone.
   5252   1.1  christos 	 */
   5253   1.1  christos 	result = dns_db_findext(db, client->query.qname, dbversion->version,
   5254   1.9  christos 				qtype, DNS_DBFIND_NOZONECUT, client->now, &node,
   5255   1.9  christos 				found, &cm, &ci, &trdataset, NULL);
   5256   1.1  christos 	if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
   5257   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   5258   1.1  christos 			dns_rdataset_disassociate(rdataset);
   5259   1.9  christos 		}
   5260   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5261   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5262   1.9  christos 		}
   5263   1.1  christos 		goto nxrrset;
   5264   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   5265   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5266   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5267   1.9  christos 		}
   5268   1.9  christos 		if (node != NULL) {
   5269   1.1  christos 			dns_db_detachnode(db, &node);
   5270   1.9  christos 		}
   5271   1.1  christos 		dns_db_detach(&db);
   5272  1.23  christos 		return ISC_R_NOTFOUND;
   5273   1.1  christos 	}
   5274   1.1  christos 
   5275   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect: found data: done");
   5276  1.20  christos 	dns_name_copy(found, name);
   5277   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   5278   1.1  christos 		dns_rdataset_disassociate(rdataset);
   5279   1.9  christos 	}
   5280   1.1  christos 	if (dns_rdataset_isassociated(&trdataset)) {
   5281   1.1  christos 		dns_rdataset_clone(&trdataset, rdataset);
   5282   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   5283   1.1  christos 	}
   5284   1.9  christos nxrrset:
   5285   1.9  christos 	if (*nodep != NULL) {
   5286   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   5287   1.9  christos 	}
   5288   1.1  christos 	dns_db_detach(dbp);
   5289   1.1  christos 	dns_db_attachnode(db, node, nodep);
   5290   1.1  christos 	dns_db_attach(db, dbp);
   5291   1.1  christos 	dns_db_detachnode(db, &node);
   5292   1.1  christos 	dns_db_detach(&db);
   5293   1.1  christos 	*versionp = dbversion->version;
   5294   1.1  christos 
   5295   1.1  christos 	client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   5296   1.1  christos 				     NS_QUERYATTR_NOADDITIONAL);
   5297   1.1  christos 
   5298  1.23  christos 	return result;
   5299   1.1  christos }
   5300   1.1  christos 
   5301   1.1  christos static isc_result_t
   5302   1.1  christos redirect2(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
   5303   1.1  christos 	  dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
   5304   1.9  christos 	  dns_rdatatype_t qtype, bool *is_zonep) {
   5305   1.1  christos 	dns_db_t *db = NULL;
   5306   1.1  christos 	dns_dbnode_t *node = NULL;
   5307   1.1  christos 	dns_fixedname_t fixed;
   5308   1.1  christos 	dns_fixedname_t fixedredirect;
   5309   1.1  christos 	dns_name_t *found, *redirectname;
   5310   1.1  christos 	dns_rdataset_t trdataset;
   5311   1.1  christos 	isc_result_t result;
   5312   1.1  christos 	dns_rdatatype_t type;
   5313   1.1  christos 	dns_clientinfomethods_t cm;
   5314   1.1  christos 	dns_clientinfo_t ci;
   5315   1.1  christos 	dns_dbversion_t *version = NULL;
   5316   1.1  christos 	dns_zone_t *zone = NULL;
   5317   1.3  christos 	bool is_zone;
   5318   1.5  christos 	unsigned int labels;
   5319   1.1  christos 
   5320   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect2");
   5321   1.1  christos 
   5322   1.5  christos 	if (client->view->redirectzone == NULL) {
   5323  1.23  christos 		return ISC_R_NOTFOUND;
   5324   1.5  christos 	}
   5325   1.1  christos 
   5326   1.5  christos 	if (dns_name_issubdomain(name, client->view->redirectzone)) {
   5327  1.23  christos 		return ISC_R_NOTFOUND;
   5328   1.5  christos 	}
   5329   1.1  christos 
   5330   1.1  christos 	found = dns_fixedname_initname(&fixed);
   5331   1.1  christos 	dns_rdataset_init(&trdataset);
   5332   1.1  christos 
   5333   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   5334  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   5335  1.20  christos 	dns_clientinfo_setecs(&ci, &client->ecs);
   5336   1.1  christos 
   5337   1.9  christos 	if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
   5338   1.9  christos 	{
   5339  1.23  christos 		return ISC_R_NOTFOUND;
   5340   1.5  christos 	}
   5341   1.1  christos 
   5342   1.1  christos 	if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
   5343   1.9  christos 		if (rdataset->trust == dns_trust_secure) {
   5344  1.23  christos 			return ISC_R_NOTFOUND;
   5345   1.9  christos 		}
   5346   1.1  christos 		if (rdataset->trust == dns_trust_ultimate &&
   5347   1.1  christos 		    (rdataset->type == dns_rdatatype_nsec ||
   5348   1.1  christos 		     rdataset->type == dns_rdatatype_nsec3))
   5349   1.9  christos 		{
   5350  1.23  christos 			return ISC_R_NOTFOUND;
   5351   1.9  christos 		}
   5352   1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
   5353   1.1  christos 			for (result = dns_rdataset_first(rdataset);
   5354   1.1  christos 			     result == ISC_R_SUCCESS;
   5355   1.9  christos 			     result = dns_rdataset_next(rdataset))
   5356   1.9  christos 			{
   5357   1.1  christos 				dns_ncache_current(rdataset, found, &trdataset);
   5358   1.1  christos 				type = trdataset.type;
   5359   1.1  christos 				dns_rdataset_disassociate(&trdataset);
   5360   1.1  christos 				if (type == dns_rdatatype_nsec ||
   5361   1.1  christos 				    type == dns_rdatatype_nsec3 ||
   5362   1.1  christos 				    type == dns_rdatatype_rrsig)
   5363   1.9  christos 				{
   5364  1.23  christos 					return ISC_R_NOTFOUND;
   5365   1.9  christos 				}
   5366   1.1  christos 			}
   5367   1.1  christos 		}
   5368   1.1  christos 	}
   5369   1.1  christos 
   5370   1.1  christos 	redirectname = dns_fixedname_initname(&fixedredirect);
   5371   1.5  christos 	labels = dns_name_countlabels(client->query.qname);
   5372   1.5  christos 	if (labels > 1U) {
   5373   1.1  christos 		dns_name_t prefix;
   5374   1.1  christos 
   5375   1.1  christos 		dns_name_init(&prefix, NULL);
   5376   1.5  christos 		dns_name_getlabelsequence(client->query.qname, 0, labels - 1,
   5377   1.5  christos 					  &prefix);
   5378   1.1  christos 		result = dns_name_concatenate(&prefix,
   5379   1.1  christos 					      client->view->redirectzone,
   5380   1.1  christos 					      redirectname, NULL);
   5381   1.9  christos 		if (result != ISC_R_SUCCESS) {
   5382  1.23  christos 			return ISC_R_NOTFOUND;
   5383   1.9  christos 		}
   5384   1.5  christos 	} else {
   5385  1.20  christos 		dns_name_copy(redirectname, client->view->redirectzone);
   5386   1.5  christos 	}
   5387   1.1  christos 
   5388  1.23  christos 	result = query_getdb(client, redirectname, qtype,
   5389  1.23  christos 			     (dns_getdb_options_t){ 0 }, &zone, &db, &version,
   5390  1.23  christos 			     &is_zone);
   5391   1.5  christos 	if (result != ISC_R_SUCCESS) {
   5392  1.23  christos 		return ISC_R_NOTFOUND;
   5393   1.5  christos 	}
   5394   1.5  christos 	if (zone != NULL) {
   5395   1.1  christos 		dns_zone_detach(&zone);
   5396   1.5  christos 	}
   5397   1.1  christos 
   5398   1.1  christos 	/*
   5399   1.1  christos 	 * Lookup the requested data in the redirect zone.
   5400   1.1  christos 	 */
   5401   1.9  christos 	result = dns_db_findext(db, redirectname, version, qtype, 0,
   5402   1.9  christos 				client->now, &node, found, &cm, &ci, &trdataset,
   5403   1.9  christos 				NULL);
   5404   1.1  christos 	if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
   5405   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   5406   1.1  christos 			dns_rdataset_disassociate(rdataset);
   5407   1.9  christos 		}
   5408   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5409   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5410   1.9  christos 		}
   5411   1.1  christos 		goto nxrrset;
   5412   1.1  christos 	} else if (result == ISC_R_NOTFOUND || result == DNS_R_DELEGATION) {
   5413   1.1  christos 		/*
   5414   1.1  christos 		 * Cleanup.
   5415   1.1  christos 		 */
   5416   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5417   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5418   1.9  christos 		}
   5419   1.9  christos 		if (node != NULL) {
   5420   1.1  christos 			dns_db_detachnode(db, &node);
   5421   1.9  christos 		}
   5422   1.1  christos 		dns_db_detach(&db);
   5423   1.1  christos 		/*
   5424   1.1  christos 		 * Don't loop forever if the lookup failed last time.
   5425   1.1  christos 		 */
   5426   1.1  christos 		if (!REDIRECT(client)) {
   5427   1.3  christos 			result = ns_query_recurse(client, qtype, redirectname,
   5428   1.3  christos 						  NULL, NULL, true);
   5429   1.1  christos 			if (result == ISC_R_SUCCESS) {
   5430   1.1  christos 				client->query.attributes |=
   5431   1.9  christos 					NS_QUERYATTR_RECURSING;
   5432   1.1  christos 				client->query.attributes |=
   5433   1.9  christos 					NS_QUERYATTR_REDIRECT;
   5434  1.23  christos 				return DNS_R_CONTINUE;
   5435   1.1  christos 			}
   5436   1.1  christos 		}
   5437  1.23  christos 		return ISC_R_NOTFOUND;
   5438   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   5439   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5440   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5441   1.9  christos 		}
   5442   1.9  christos 		if (node != NULL) {
   5443   1.1  christos 			dns_db_detachnode(db, &node);
   5444   1.9  christos 		}
   5445   1.1  christos 		dns_db_detach(&db);
   5446  1.23  christos 		return ISC_R_NOTFOUND;
   5447   1.1  christos 	}
   5448   1.1  christos 
   5449   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect2: found data: done");
   5450   1.1  christos 	/*
   5451   1.1  christos 	 * Adjust the found name to not include the redirectzone suffix.
   5452   1.1  christos 	 */
   5453   1.1  christos 	dns_name_split(found, dns_name_countlabels(client->view->redirectzone),
   5454   1.1  christos 		       found, NULL);
   5455   1.1  christos 	/*
   5456   1.1  christos 	 * Make the name absolute.
   5457   1.1  christos 	 */
   5458   1.1  christos 	result = dns_name_concatenate(found, dns_rootname, found, NULL);
   5459   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   5460   1.1  christos 
   5461  1.20  christos 	dns_name_copy(found, name);
   5462   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   5463   1.1  christos 		dns_rdataset_disassociate(rdataset);
   5464   1.9  christos 	}
   5465   1.1  christos 	if (dns_rdataset_isassociated(&trdataset)) {
   5466   1.1  christos 		dns_rdataset_clone(&trdataset, rdataset);
   5467   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   5468   1.1  christos 	}
   5469   1.9  christos nxrrset:
   5470   1.9  christos 	if (*nodep != NULL) {
   5471   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   5472   1.9  christos 	}
   5473   1.1  christos 	dns_db_detach(dbp);
   5474   1.1  christos 	dns_db_attachnode(db, node, nodep);
   5475   1.1  christos 	dns_db_attach(db, dbp);
   5476   1.1  christos 	dns_db_detachnode(db, &node);
   5477   1.1  christos 	dns_db_detach(&db);
   5478   1.1  christos 	*is_zonep = is_zone;
   5479   1.1  christos 	*versionp = version;
   5480   1.1  christos 
   5481   1.1  christos 	client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   5482   1.1  christos 				     NS_QUERYATTR_NOADDITIONAL);
   5483   1.1  christos 
   5484  1.23  christos 	return result;
   5485   1.1  christos }
   5486   1.1  christos 
   5487   1.1  christos /*%
   5488   1.1  christos  * Initialize query context 'qctx'. Run by query_setup() when
   5489   1.1  christos  * first handling a client query, and by query_resume() when
   5490   1.1  christos  * returning from recursion.
   5491   1.3  christos  *
   5492   1.3  christos  * Whenever this function is called, qctx_destroy() must be called
   5493   1.3  christos  * when leaving the scope or freeing the qctx.
   5494   1.1  christos  */
   5495   1.1  christos static void
   5496  1.23  christos qctx_init(ns_client_t *client, dns_fetchresponse_t **frespp,
   5497  1.23  christos 	  dns_rdatatype_t qtype, query_ctx_t *qctx) {
   5498   1.1  christos 	REQUIRE(qctx != NULL);
   5499   1.1  christos 	REQUIRE(client != NULL);
   5500   1.1  christos 
   5501   1.3  christos 	memset(qctx, 0, sizeof(*qctx));
   5502   1.3  christos 
   5503   1.1  christos 	/* Set this first so CCTRACE will work */
   5504   1.1  christos 	qctx->client = client;
   5505   1.9  christos 
   5506   1.3  christos 	dns_view_attach(client->view, &qctx->view);
   5507   1.1  christos 
   5508   1.3  christos 	CCTRACE(ISC_LOG_DEBUG(3), "qctx_init");
   5509   1.1  christos 
   5510  1.23  christos 	if (frespp != NULL) {
   5511  1.23  christos 		qctx->fresp = *frespp;
   5512  1.23  christos 		*frespp = NULL;
   5513  1.11  christos 	} else {
   5514  1.23  christos 		qctx->fresp = NULL;
   5515  1.11  christos 	}
   5516   1.1  christos 	qctx->qtype = qctx->type = qtype;
   5517   1.1  christos 	qctx->result = ISC_R_SUCCESS;
   5518   1.3  christos 	qctx->findcoveringnsec = qctx->view->synthfromdnssec;
   5519   1.3  christos 
   5520  1.16  christos 	/*
   5521  1.16  christos 	 * If it's an RRSIG or SIG query, we'll iterate the node.
   5522  1.16  christos 	 */
   5523  1.16  christos 	if (qctx->qtype == dns_rdatatype_rrsig ||
   5524  1.16  christos 	    qctx->qtype == dns_rdatatype_sig)
   5525  1.16  christos 	{
   5526  1.16  christos 		qctx->type = dns_rdatatype_any;
   5527  1.16  christos 	}
   5528  1.16  christos 
   5529   1.3  christos 	CALL_HOOK_NORETURN(NS_QUERY_QCTX_INITIALIZED, qctx);
   5530   1.1  christos }
   5531   1.1  christos 
   5532   1.1  christos /*%
   5533   1.1  christos  * Clean up and disassociate the rdataset and node pointers in qctx.
   5534   1.1  christos  */
   5535   1.1  christos static void
   5536   1.1  christos qctx_clean(query_ctx_t *qctx) {
   5537   1.9  christos 	if (qctx->rdataset != NULL && dns_rdataset_isassociated(qctx->rdataset))
   5538   1.1  christos 	{
   5539   1.1  christos 		dns_rdataset_disassociate(qctx->rdataset);
   5540   1.1  christos 	}
   5541   1.1  christos 	if (qctx->sigrdataset != NULL &&
   5542  1.16  christos 	    dns_rdataset_isassociated(qctx->sigrdataset))
   5543  1.16  christos 	{
   5544   1.1  christos 		dns_rdataset_disassociate(qctx->sigrdataset);
   5545   1.1  christos 	}
   5546   1.1  christos 	if (qctx->db != NULL && qctx->node != NULL) {
   5547   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   5548   1.1  christos 	}
   5549  1.24  christos 	if (qctx->client != NULL && qctx->client->query.gluedb != NULL) {
   5550  1.24  christos 		dns_db_detach(&qctx->client->query.gluedb);
   5551  1.24  christos 	}
   5552   1.1  christos }
   5553   1.1  christos 
   5554   1.1  christos /*%
   5555   1.1  christos  * Free any allocated memory associated with qctx.
   5556   1.1  christos  */
   5557   1.1  christos static void
   5558   1.1  christos qctx_freedata(query_ctx_t *qctx) {
   5559   1.1  christos 	if (qctx->rdataset != NULL) {
   5560   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   5561   1.1  christos 	}
   5562   1.1  christos 
   5563   1.1  christos 	if (qctx->sigrdataset != NULL) {
   5564   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   5565   1.1  christos 	}
   5566   1.1  christos 
   5567   1.1  christos 	if (qctx->fname != NULL) {
   5568   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   5569   1.1  christos 	}
   5570   1.1  christos 
   5571   1.1  christos 	if (qctx->db != NULL) {
   5572   1.1  christos 		INSIST(qctx->node == NULL);
   5573   1.1  christos 		dns_db_detach(&qctx->db);
   5574   1.1  christos 	}
   5575   1.1  christos 
   5576   1.1  christos 	if (qctx->zone != NULL) {
   5577   1.1  christos 		dns_zone_detach(&qctx->zone);
   5578   1.1  christos 	}
   5579   1.1  christos 
   5580   1.1  christos 	if (qctx->zdb != NULL) {
   5581   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->zsigrdataset);
   5582   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->zrdataset);
   5583   1.3  christos 		ns_client_releasename(qctx->client, &qctx->zfname);
   5584   1.3  christos 		dns_db_detachnode(qctx->zdb, &qctx->znode);
   5585   1.1  christos 		dns_db_detach(&qctx->zdb);
   5586  1.22  christos 		qctx->zversion = NULL;
   5587   1.1  christos 	}
   5588   1.1  christos 
   5589  1.23  christos 	if (qctx->fresp != NULL) {
   5590  1.23  christos 		free_fresp(qctx->client, &qctx->fresp);
   5591   1.1  christos 	}
   5592   1.1  christos }
   5593   1.1  christos 
   5594   1.3  christos static void
   5595   1.3  christos qctx_destroy(query_ctx_t *qctx) {
   5596   1.3  christos 	CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx);
   5597   1.3  christos 
   5598   1.3  christos 	dns_view_detach(&qctx->view);
   5599   1.3  christos }
   5600   1.3  christos 
   5601  1.20  christos /*
   5602  1.20  christos  * Call SAVE but set 'a' to NULL first so as not to assert.
   5603  1.20  christos  */
   5604  1.20  christos #define INITANDSAVE(a, b)   \
   5605  1.20  christos 	do {                \
   5606  1.20  christos 		a = NULL;   \
   5607  1.20  christos 		SAVE(a, b); \
   5608  1.20  christos 	} while (0)
   5609  1.20  christos 
   5610  1.20  christos /*
   5611  1.20  christos  * "save" qctx data from 'src' to 'tgt'.
   5612  1.20  christos  * It essentially moves ownership of the data from src to tgt, so the former
   5613  1.20  christos  * becomes unusable except for final cleanup (such as by qctx_destroy).
   5614  1.20  christos  * Note: this function doesn't attach to the client's handle.  It's the caller's
   5615  1.20  christos  * responsibility to do it if it's necessary.
   5616  1.20  christos  */
   5617  1.20  christos static void
   5618  1.20  christos qctx_save(query_ctx_t *src, query_ctx_t *tgt) {
   5619  1.20  christos 	/* First copy all fields in a straightforward way */
   5620  1.20  christos 	*tgt = *src;
   5621  1.20  christos 
   5622  1.20  christos 	/* Then "move" pointers (except client and view) */
   5623  1.20  christos 	INITANDSAVE(tgt->dbuf, src->dbuf);
   5624  1.20  christos 	INITANDSAVE(tgt->fname, src->fname);
   5625  1.20  christos 	INITANDSAVE(tgt->tname, src->tname);
   5626  1.20  christos 	INITANDSAVE(tgt->rdataset, src->rdataset);
   5627  1.20  christos 	INITANDSAVE(tgt->sigrdataset, src->sigrdataset);
   5628  1.20  christos 	INITANDSAVE(tgt->noqname, src->noqname);
   5629  1.23  christos 	INITANDSAVE(tgt->fresp, src->fresp);
   5630  1.20  christos 	INITANDSAVE(tgt->db, src->db);
   5631  1.20  christos 	INITANDSAVE(tgt->version, src->version);
   5632  1.20  christos 	INITANDSAVE(tgt->node, src->node);
   5633  1.20  christos 	INITANDSAVE(tgt->zdb, src->zdb);
   5634  1.20  christos 	INITANDSAVE(tgt->znode, src->znode);
   5635  1.20  christos 	INITANDSAVE(tgt->zfname, src->zfname);
   5636  1.20  christos 	INITANDSAVE(tgt->zversion, src->zversion);
   5637  1.20  christos 	INITANDSAVE(tgt->zrdataset, src->zrdataset);
   5638  1.20  christos 	INITANDSAVE(tgt->zsigrdataset, src->zsigrdataset);
   5639  1.20  christos 	INITANDSAVE(tgt->rpz_st, src->rpz_st);
   5640  1.20  christos 	INITANDSAVE(tgt->zone, src->zone);
   5641  1.20  christos 
   5642  1.20  christos 	/* View has to stay in 'src' for qctx_destroy. */
   5643  1.20  christos 	tgt->view = NULL;
   5644  1.20  christos 	dns_view_attach(src->view, &tgt->view);
   5645  1.20  christos }
   5646  1.20  christos 
   5647   1.1  christos /*%
   5648   1.1  christos  * Log detailed information about the query immediately after
   5649   1.1  christos  * the client request or a return from recursion.
   5650   1.1  christos  */
   5651   1.1  christos static void
   5652   1.1  christos query_trace(query_ctx_t *qctx) {
   5653   1.1  christos #ifdef WANT_QUERYTRACE
   5654   1.6  christos 	char mbuf[2 * DNS_NAME_FORMATSIZE];
   5655   1.1  christos 	char qbuf[DNS_NAME_FORMATSIZE];
   5656   1.1  christos 
   5657   1.9  christos 	if (qctx->client->query.origqname != NULL) {
   5658   1.1  christos 		dns_name_format(qctx->client->query.origqname, qbuf,
   5659   1.1  christos 				sizeof(qbuf));
   5660   1.9  christos 	} else {
   5661   1.1  christos 		snprintf(qbuf, sizeof(qbuf), "<unset>");
   5662   1.9  christos 	}
   5663   1.1  christos 
   5664   1.1  christos 	snprintf(mbuf, sizeof(mbuf) - 1,
   5665   1.1  christos 		 "client attr:0x%x, query attr:0x%X, restarts:%u, "
   5666   1.1  christos 		 "origqname:%s, timer:%d, authdb:%d, referral:%d",
   5667   1.9  christos 		 qctx->client->attributes, qctx->client->query.attributes,
   5668   1.1  christos 		 qctx->client->query.restarts, qbuf,
   5669   1.9  christos 		 (int)qctx->client->query.timerset,
   5670   1.9  christos 		 (int)qctx->client->query.authdbset,
   5671   1.9  christos 		 (int)qctx->client->query.isreferral);
   5672   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   5673   1.9  christos #else  /* ifdef WANT_QUERYTRACE */
   5674   1.1  christos 	UNUSED(qctx);
   5675   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   5676   1.1  christos }
   5677   1.1  christos 
   5678   1.1  christos /*
   5679   1.1  christos  * Set up query processing for the current query of 'client'.
   5680   1.1  christos  * Calls qctx_init() to initialize a query context, checks
   5681   1.1  christos  * the SERVFAIL cache, then hands off processing to ns__query_start().
   5682   1.1  christos  *
   5683   1.1  christos  * This is called only from ns_query_start(), to begin a query
   5684   1.1  christos  * for the first time.  Restarting an existing query (for
   5685   1.1  christos  * instance, to handle CNAME lookups), is done by calling
   5686   1.1  christos  * ns__query_start() again with the same query context. Resuming from
   5687   1.1  christos  * recursion is handled by query_resume().
   5688   1.1  christos  */
   5689  1.23  christos static void
   5690   1.1  christos query_setup(ns_client_t *client, dns_rdatatype_t qtype) {
   5691  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   5692   1.1  christos 	query_ctx_t qctx;
   5693   1.1  christos 
   5694   1.1  christos 	qctx_init(client, NULL, qtype, &qctx);
   5695   1.1  christos 	query_trace(&qctx);
   5696   1.1  christos 
   5697   1.3  christos 	CALL_HOOK(NS_QUERY_SETUP, &qctx);
   5698   1.3  christos 
   5699   1.1  christos 	/*
   5700   1.1  christos 	 * Check SERVFAIL cache
   5701   1.1  christos 	 */
   5702   1.1  christos 	result = ns__query_sfcache(&qctx);
   5703   1.1  christos 	if (result != ISC_R_COMPLETE) {
   5704  1.23  christos 		goto cleanup;
   5705   1.1  christos 	}
   5706   1.1  christos 
   5707  1.23  christos 	(void)ns__query_start(&qctx);
   5708   1.3  christos 
   5709   1.9  christos cleanup:
   5710   1.3  christos 	qctx_destroy(&qctx);
   5711   1.1  christos }
   5712   1.1  christos 
   5713   1.3  christos static bool
   5714   1.1  christos get_root_key_sentinel_id(query_ctx_t *qctx, const char *ndata) {
   5715   1.1  christos 	unsigned int v = 0;
   5716   1.1  christos 	int i;
   5717   1.1  christos 
   5718   1.1  christos 	for (i = 0; i < 5; i++) {
   5719  1.14  christos 		if (!isdigit((unsigned char)ndata[i])) {
   5720  1.23  christos 			return false;
   5721   1.1  christos 		}
   5722   1.1  christos 		v *= 10;
   5723   1.1  christos 		v += ndata[i] - '0';
   5724   1.1  christos 	}
   5725   1.1  christos 	if (v > 65535U) {
   5726  1.23  christos 		return false;
   5727   1.1  christos 	}
   5728   1.1  christos 	qctx->client->query.root_key_sentinel_keyid = v;
   5729  1.23  christos 	return true;
   5730   1.1  christos }
   5731   1.1  christos 
   5732   1.1  christos /*%
   5733   1.1  christos  * Find out if the query is for a root key sentinel and if so, record the type
   5734   1.1  christos  * of root key sentinel query and the key id that is being checked for.
   5735   1.1  christos  *
   5736   1.1  christos  * The code is assuming a zero padded decimal field of width 5.
   5737   1.1  christos  */
   5738   1.1  christos static void
   5739   1.1  christos root_key_sentinel_detect(query_ctx_t *qctx) {
   5740   1.1  christos 	const char *ndata = (const char *)qctx->client->query.qname->ndata;
   5741   1.1  christos 
   5742   1.1  christos 	if (qctx->client->query.qname->length > 30 && ndata[0] == 29 &&
   5743   1.1  christos 	    strncasecmp(ndata + 1, "root-key-sentinel-is-ta-", 24) == 0)
   5744   1.1  christos 	{
   5745   1.1  christos 		if (!get_root_key_sentinel_id(qctx, ndata + 25)) {
   5746   1.1  christos 			return;
   5747   1.1  christos 		}
   5748   1.3  christos 		qctx->client->query.root_key_sentinel_is_ta = true;
   5749   1.1  christos 		/*
   5750   1.9  christos 		 * Simplify processing by disabling aggressive
   5751   1.1  christos 		 * negative caching.
   5752   1.1  christos 		 */
   5753   1.3  christos 		qctx->findcoveringnsec = false;
   5754   1.1  christos 		ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
   5755   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5756   1.1  christos 			      "root-key-sentinel-is-ta query label found");
   5757   1.1  christos 	} else if (qctx->client->query.qname->length > 31 && ndata[0] == 30 &&
   5758   1.1  christos 		   strncasecmp(ndata + 1, "root-key-sentinel-not-ta-", 25) == 0)
   5759   1.1  christos 	{
   5760   1.1  christos 		if (!get_root_key_sentinel_id(qctx, ndata + 26)) {
   5761   1.1  christos 			return;
   5762   1.1  christos 		}
   5763   1.3  christos 		qctx->client->query.root_key_sentinel_not_ta = true;
   5764   1.1  christos 		/*
   5765   1.9  christos 		 * Simplify processing by disabling aggressive
   5766   1.1  christos 		 * negative caching.
   5767   1.1  christos 		 */
   5768   1.3  christos 		qctx->findcoveringnsec = false;
   5769   1.1  christos 		ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
   5770   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5771   1.1  christos 			      "root-key-sentinel-not-ta query label found");
   5772   1.1  christos 	}
   5773   1.1  christos }
   5774   1.1  christos 
   5775   1.1  christos /*%
   5776   1.1  christos  * Starting point for a client query or a chaining query.
   5777   1.1  christos  *
   5778   1.1  christos  * Called first by query_setup(), and then again as often as needed to
   5779   1.1  christos  * follow a CNAME chain.  Determines which authoritative database to
   5780   1.1  christos  * search, then hands off processing to query_lookup().
   5781   1.1  christos  */
   5782   1.1  christos isc_result_t
   5783   1.1  christos ns__query_start(query_ctx_t *qctx) {
   5784  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   5785   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "ns__query_start");
   5786   1.3  christos 	qctx->want_restart = false;
   5787   1.3  christos 	qctx->authoritative = false;
   5788   1.1  christos 	qctx->version = NULL;
   5789   1.1  christos 	qctx->zversion = NULL;
   5790   1.3  christos 	qctx->need_wildcardproof = false;
   5791   1.3  christos 	qctx->rpz = false;
   5792   1.3  christos 
   5793   1.3  christos 	CALL_HOOK(NS_QUERY_START_BEGIN, qctx);
   5794   1.3  christos 
   5795   1.3  christos 	/*
   5796  1.23  christos 	 * If we require a server cookie or the presented server
   5797  1.23  christos 	 * cookie was bad then send back BADCOOKIE before we have
   5798  1.23  christos 	 * done too much work.
   5799  1.23  christos 	 */
   5800  1.23  christos 	if (!TCP(qctx->client) &&
   5801  1.23  christos 	    (BADCOOKIE(qctx->client) ||
   5802  1.23  christos 	     (qctx->view->requireservercookie && WANTCOOKIE(qctx->client) &&
   5803  1.23  christos 	      !HAVECOOKIE(qctx->client))))
   5804   1.3  christos 	{
   5805   1.3  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
   5806   1.3  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
   5807   1.3  christos 		qctx->client->message->rcode = dns_rcode_badcookie;
   5808  1.23  christos 		return ns_query_done(qctx);
   5809   1.3  christos 	}
   5810   1.1  christos 
   5811   1.3  christos 	if (qctx->view->checknames &&
   5812   1.1  christos 	    !dns_rdata_checkowner(qctx->client->query.qname,
   5813   1.9  christos 				  qctx->client->message->rdclass, qctx->qtype,
   5814   1.9  christos 				  false))
   5815   1.1  christos 	{
   5816   1.1  christos 		char namebuf[DNS_NAME_FORMATSIZE];
   5817   1.3  christos 		char typebuf[DNS_RDATATYPE_FORMATSIZE];
   5818   1.3  christos 		char classbuf[DNS_RDATACLASS_FORMATSIZE];
   5819   1.1  christos 
   5820   1.9  christos 		dns_name_format(qctx->client->query.qname, namebuf,
   5821   1.9  christos 				sizeof(namebuf));
   5822   1.3  christos 		dns_rdatatype_format(qctx->qtype, typebuf, sizeof(typebuf));
   5823   1.9  christos 		dns_rdataclass_format(qctx->client->message->rdclass, classbuf,
   5824   1.9  christos 				      sizeof(classbuf));
   5825   1.1  christos 		ns_client_log(qctx->client, DNS_LOGCATEGORY_SECURITY,
   5826   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_ERROR,
   5827   1.9  christos 			      "check-names failure %s/%s/%s", namebuf, typebuf,
   5828   1.9  christos 			      classbuf);
   5829   1.1  christos 		QUERY_ERROR(qctx, DNS_R_REFUSED);
   5830  1.23  christos 		return ns_query_done(qctx);
   5831   1.1  christos 	}
   5832   1.1  christos 
   5833   1.1  christos 	/*
   5834   1.1  christos 	 * Setup for root key sentinel processing.
   5835   1.1  christos 	 */
   5836   1.3  christos 	if (qctx->view->root_key_sentinel &&
   5837   1.1  christos 	    qctx->client->query.restarts == 0 &&
   5838   1.1  christos 	    (qctx->qtype == dns_rdatatype_a ||
   5839   1.1  christos 	     qctx->qtype == dns_rdatatype_aaaa) &&
   5840   1.1  christos 	    (qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)
   5841   1.1  christos 	{
   5842   1.9  christos 		root_key_sentinel_detect(qctx);
   5843   1.1  christos 	}
   5844   1.1  christos 
   5845   1.1  christos 	/*
   5846  1.23  christos 	 * First we must find the right database. Reset the options but preserve
   5847  1.23  christos 	 * the 'nolog' flag.
   5848   1.1  christos 	 */
   5849  1.23  christos 	qctx->options = (dns_getdb_options_t){ .nolog = qctx->options.nolog };
   5850   1.1  christos 	if (dns_rdatatype_atparent(qctx->qtype) &&
   5851   1.1  christos 	    !dns_name_equal(qctx->client->query.qname, dns_rootname))
   5852   1.1  christos 	{
   5853   1.1  christos 		/*
   5854   1.1  christos 		 * If authoritative data for this QTYPE is supposed to live in
   5855   1.1  christos 		 * the parent zone, do not look for an exact match for QNAME,
   5856   1.1  christos 		 * but rather for its containing zone (unless the QNAME is
   5857   1.1  christos 		 * root).
   5858   1.1  christos 		 */
   5859  1.23  christos 		qctx->options.noexact = true;
   5860   1.1  christos 	}
   5861   1.1  christos 
   5862   1.1  christos 	result = query_getdb(qctx->client, qctx->client->query.qname,
   5863   1.9  christos 			     qctx->qtype, qctx->options, &qctx->zone, &qctx->db,
   5864   1.9  christos 			     &qctx->version, &qctx->is_zone);
   5865  1.20  christos 	if ((result != ISC_R_SUCCESS || !qctx->is_zone) &&
   5866  1.20  christos 	    qctx->qtype == dns_rdatatype_ds && !RECURSIONOK(qctx->client) &&
   5867  1.23  christos 	    qctx->options.noexact)
   5868   1.1  christos 	{
   5869   1.1  christos 		/*
   5870   1.1  christos 		 * This is a non-recursive QTYPE=DS query with QNAME whose
   5871   1.1  christos 		 * parent we are not authoritative for.  Check whether we are
   5872   1.1  christos 		 * authoritative for QNAME, because if so, we need to send a
   5873   1.1  christos 		 * "no data" response as required by RFC 4035, section 3.1.4.1.
   5874   1.1  christos 		 */
   5875   1.1  christos 		dns_db_t *tdb = NULL;
   5876   1.1  christos 		dns_zone_t *tzone = NULL;
   5877   1.1  christos 		dns_dbversion_t *tversion = NULL;
   5878   1.1  christos 		isc_result_t tresult;
   5879   1.1  christos 
   5880  1.23  christos 		dns_getdb_options_t options = { .partial = true };
   5881   1.9  christos 		tresult = query_getzonedb(
   5882   1.9  christos 			qctx->client, qctx->client->query.qname, qctx->qtype,
   5883  1.23  christos 			options, &tzone, &tdb, &tversion);
   5884   1.1  christos 		if (tresult == ISC_R_SUCCESS) {
   5885   1.1  christos 			/*
   5886   1.1  christos 			 * We are authoritative for QNAME.  Attach the relevant
   5887   1.1  christos 			 * zone to query context, set result to ISC_R_SUCCESS.
   5888   1.1  christos 			 */
   5889  1.23  christos 			qctx->options.noexact = false;
   5890   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   5891   1.1  christos 			if (qctx->db != NULL) {
   5892   1.1  christos 				dns_db_detach(&qctx->db);
   5893   1.1  christos 			}
   5894   1.1  christos 			if (qctx->zone != NULL) {
   5895   1.1  christos 				dns_zone_detach(&qctx->zone);
   5896   1.1  christos 			}
   5897   1.1  christos 			qctx->version = NULL;
   5898   1.1  christos 			RESTORE(qctx->version, tversion);
   5899   1.1  christos 			RESTORE(qctx->db, tdb);
   5900   1.1  christos 			RESTORE(qctx->zone, tzone);
   5901   1.3  christos 			qctx->is_zone = true;
   5902   1.1  christos 			result = ISC_R_SUCCESS;
   5903   1.1  christos 		} else {
   5904   1.1  christos 			/*
   5905   1.1  christos 			 * We are not authoritative for QNAME.  Clean up and
   5906   1.1  christos 			 * leave result as it was.
   5907   1.1  christos 			 */
   5908   1.1  christos 			if (tdb != NULL) {
   5909   1.1  christos 				dns_db_detach(&tdb);
   5910   1.1  christos 			}
   5911   1.1  christos 			if (tzone != NULL) {
   5912   1.1  christos 				dns_zone_detach(&tzone);
   5913   1.1  christos 			}
   5914   1.1  christos 		}
   5915   1.1  christos 	}
   5916   1.1  christos 	/*
   5917   1.1  christos 	 * If we did not find a database from which we can answer the query,
   5918   1.1  christos 	 * respond with either REFUSED or SERVFAIL, depending on what the
   5919   1.1  christos 	 * result of query_getdb() was.
   5920   1.1  christos 	 */
   5921   1.1  christos 	if (result != ISC_R_SUCCESS) {
   5922   1.1  christos 		if (result == DNS_R_REFUSED) {
   5923   1.1  christos 			if (WANTRECURSION(qctx->client)) {
   5924  1.24  christos 				dns_ede_add(&qctx->client->edectx,
   5925  1.24  christos 					    DNS_EDE_NOTAUTH,
   5926  1.24  christos 					    "recursion disabled");
   5927   1.1  christos 				inc_stats(qctx->client,
   5928   1.1  christos 					  ns_statscounter_recurserej);
   5929   1.1  christos 			} else {
   5930   1.1  christos 				inc_stats(qctx->client,
   5931   1.1  christos 					  ns_statscounter_authrej);
   5932   1.1  christos 			}
   5933   1.1  christos 			if (!PARTIALANSWER(qctx->client)) {
   5934   1.1  christos 				QUERY_ERROR(qctx, DNS_R_REFUSED);
   5935   1.1  christos 			}
   5936   1.1  christos 		} else {
   5937   1.9  christos 			CCTRACE(ISC_LOG_ERROR, "ns__query_start: query_getdb "
   5938   1.9  christos 					       "failed");
   5939   1.3  christos 			QUERY_ERROR(qctx, result);
   5940   1.1  christos 		}
   5941  1.23  christos 		return ns_query_done(qctx);
   5942   1.1  christos 	}
   5943   1.1  christos 
   5944   1.1  christos 	/*
   5945   1.1  christos 	 * We found a database from which we can answer the query.  Update
   5946   1.1  christos 	 * relevant query context flags if the answer is to be prepared using
   5947   1.1  christos 	 * authoritative data.
   5948   1.1  christos 	 */
   5949   1.3  christos 	qctx->is_staticstub_zone = false;
   5950   1.1  christos 	if (qctx->is_zone) {
   5951   1.3  christos 		qctx->authoritative = true;
   5952   1.3  christos 		if (qctx->zone != NULL) {
   5953   1.3  christos 			if (dns_zone_gettype(qctx->zone) == dns_zone_mirror) {
   5954   1.3  christos 				qctx->authoritative = false;
   5955   1.3  christos 			}
   5956   1.9  christos 			if (dns_zone_gettype(qctx->zone) == dns_zone_staticstub)
   5957   1.3  christos 			{
   5958   1.3  christos 				qctx->is_staticstub_zone = true;
   5959   1.3  christos 			}
   5960   1.1  christos 		}
   5961   1.1  christos 	}
   5962   1.1  christos 
   5963   1.1  christos 	/*
   5964   1.1  christos 	 * Attach to the database which will be used to prepare the answer.
   5965   1.1  christos 	 * Update query statistics.
   5966   1.1  christos 	 */
   5967  1.23  christos 	if (qctx->fresp == NULL && qctx->client->query.restarts == 0) {
   5968   1.1  christos 		if (qctx->is_zone) {
   5969   1.1  christos 			if (qctx->zone != NULL) {
   5970   1.1  christos 				/*
   5971   1.1  christos 				 * if is_zone = true, zone = NULL then this is
   5972   1.1  christos 				 * a DLZ zone.  Don't attempt to attach zone.
   5973   1.1  christos 				 */
   5974   1.1  christos 				dns_zone_attach(qctx->zone,
   5975   1.1  christos 						&qctx->client->query.authzone);
   5976   1.1  christos 			}
   5977   1.1  christos 			dns_db_attach(qctx->db, &qctx->client->query.authdb);
   5978   1.1  christos 		}
   5979   1.3  christos 		qctx->client->query.authdbset = true;
   5980   1.1  christos 
   5981   1.1  christos 		/* Track TCP vs UDP stats per zone */
   5982   1.1  christos 		if (TCP(qctx->client)) {
   5983   1.1  christos 			inc_stats(qctx->client, ns_statscounter_tcp);
   5984   1.1  christos 		} else {
   5985   1.1  christos 			inc_stats(qctx->client, ns_statscounter_udp);
   5986   1.1  christos 		}
   5987   1.1  christos 	}
   5988   1.1  christos 
   5989  1.25  christos 	/*
   5990  1.25  christos 	 * If stale answers are enabled and stale-answer-client-timeout is zero,
   5991  1.25  christos 	 * then we can promptly answer with a stale RRset if one is available in
   5992  1.25  christos 	 * cache.
   5993  1.25  christos 	 */
   5994  1.25  christos 	qctx->options.stalefirst = (!qctx->is_zone &&
   5995  1.25  christos 				    qctx->view->staleanswerclienttimeout == 0 &&
   5996  1.25  christos 				    dns_view_staleanswerenabled(qctx->view));
   5997  1.11  christos 
   5998  1.11  christos 	result = query_lookup(qctx);
   5999  1.11  christos 
   6000  1.11  christos 	/*
   6001  1.11  christos 	 * Clear "look-also-for-stale-data" flag.
   6002  1.11  christos 	 * If a fetch is created to resolve this query, then,
   6003  1.11  christos 	 * when it completes, this option is not expected to be set.
   6004  1.11  christos 	 */
   6005  1.23  christos 	qctx->options.stalefirst = false;
   6006   1.3  christos 
   6007   1.9  christos cleanup:
   6008  1.23  christos 	return result;
   6009  1.23  christos }
   6010  1.23  christos 
   6011  1.23  christos static void
   6012  1.23  christos async_restart(void *arg) {
   6013  1.23  christos 	query_ctx_t *qctx = arg;
   6014  1.23  christos 	ns_client_t *client = qctx->client;
   6015  1.23  christos 	isc_nmhandle_t *handle = client->restarthandle;
   6016  1.23  christos 
   6017  1.23  christos 	client->restarthandle = NULL;
   6018  1.23  christos 
   6019  1.23  christos 	ns__query_start(qctx);
   6020  1.23  christos 
   6021  1.23  christos 	qctx_clean(qctx);
   6022  1.23  christos 	qctx_freedata(qctx);
   6023  1.23  christos 	qctx_destroy(qctx);
   6024  1.23  christos 	isc_mem_put(client->manager->mctx, qctx, sizeof(*qctx));
   6025  1.23  christos 	isc_nmhandle_detach(&handle);
   6026   1.1  christos }
   6027   1.1  christos 
   6028  1.11  christos /*
   6029  1.11  christos  * Allocate buffers in 'qctx' used to store query results.
   6030  1.11  christos  *
   6031  1.11  christos  * 'buffer' must be a pointer to an object whose lifetime
   6032  1.11  christos  * doesn't expire while 'qctx' is in use.
   6033  1.11  christos  */
   6034  1.11  christos static isc_result_t
   6035  1.11  christos qctx_prepare_buffers(query_ctx_t *qctx, isc_buffer_t *buffer) {
   6036  1.11  christos 	REQUIRE(qctx != NULL);
   6037  1.11  christos 	REQUIRE(qctx->client != NULL);
   6038  1.11  christos 	REQUIRE(buffer != NULL);
   6039  1.11  christos 
   6040  1.11  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   6041  1.11  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, buffer);
   6042  1.11  christos 	qctx->rdataset = ns_client_newrdataset(qctx->client);
   6043  1.11  christos 
   6044  1.11  christos 	if ((WANTDNSSEC(qctx->client) || qctx->findcoveringnsec) &&
   6045  1.11  christos 	    (!qctx->is_zone || dns_db_issecure(qctx->db)))
   6046  1.11  christos 	{
   6047  1.11  christos 		qctx->sigrdataset = ns_client_newrdataset(qctx->client);
   6048  1.11  christos 	}
   6049  1.11  christos 
   6050  1.23  christos 	return ISC_R_SUCCESS;
   6051  1.11  christos }
   6052  1.11  christos 
   6053   1.1  christos /*%
   6054  1.17  christos  * Depending on the db lookup result, we can respond to the
   6055  1.17  christos  * client this stale answer.
   6056  1.17  christos  */
   6057  1.17  christos static bool
   6058  1.17  christos stale_client_answer(isc_result_t result) {
   6059  1.17  christos 	switch (result) {
   6060  1.17  christos 	case ISC_R_SUCCESS:
   6061  1.17  christos 	case DNS_R_EMPTYNAME:
   6062  1.17  christos 	case DNS_R_NXRRSET:
   6063  1.17  christos 	case DNS_R_NCACHENXRRSET:
   6064  1.17  christos 	case DNS_R_CNAME:
   6065  1.17  christos 	case DNS_R_DNAME:
   6066  1.23  christos 		return true;
   6067  1.17  christos 	default:
   6068  1.23  christos 		return false;
   6069  1.17  christos 	}
   6070  1.17  christos 
   6071  1.17  christos 	UNREACHABLE();
   6072  1.17  christos }
   6073  1.17  christos 
   6074  1.17  christos /*%
   6075   1.1  christos  * Perform a local database lookup, in either an authoritative or
   6076   1.3  christos  * cache database. If unable to answer, call ns_query_done(); otherwise
   6077   1.1  christos  * hand off processing to query_gotanswer().
   6078   1.1  christos  */
   6079   1.1  christos static isc_result_t
   6080   1.1  christos query_lookup(query_ctx_t *qctx) {
   6081  1.11  christos 	isc_buffer_t buffer;
   6082  1.11  christos 	isc_result_t result = ISC_R_UNSET;
   6083   1.1  christos 	dns_clientinfomethods_t cm;
   6084   1.1  christos 	dns_clientinfo_t ci;
   6085   1.1  christos 	dns_name_t *rpzqname = NULL;
   6086  1.13  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   6087  1.23  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   6088   1.1  christos 	unsigned int dboptions;
   6089  1.11  christos 	dns_ttl_t stale_refresh = 0;
   6090  1.11  christos 	bool dbfind_stale = false;
   6091  1.13  christos 	bool stale_timeout = false;
   6092  1.16  christos 	bool answer_found = false;
   6093  1.11  christos 	bool stale_found = false;
   6094  1.11  christos 	bool stale_refresh_window = false;
   6095  1.20  christos 	uint16_t ede = 0;
   6096   1.1  christos 
   6097   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_lookup");
   6098   1.1  christos 
   6099   1.3  christos 	CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx);
   6100   1.1  christos 
   6101   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   6102  1.20  christos 	dns_clientinfo_init(&ci, qctx->client, NULL);
   6103  1.20  christos 	if (HAVEECS(qctx->client)) {
   6104  1.20  christos 		dns_clientinfo_setecs(&ci, &qctx->client->ecs);
   6105  1.20  christos 	}
   6106   1.1  christos 
   6107   1.1  christos 	/*
   6108   1.1  christos 	 * We'll need some resources...
   6109   1.1  christos 	 */
   6110  1.11  christos 	result = qctx_prepare_buffers(qctx, &buffer);
   6111  1.11  christos 	if (result != ISC_R_SUCCESS) {
   6112  1.11  christos 		QUERY_ERROR(qctx, result);
   6113  1.23  christos 		return ns_query_done(qctx);
   6114   1.1  christos 	}
   6115   1.1  christos 
   6116   1.1  christos 	/*
   6117   1.1  christos 	 * Now look for an answer in the database.
   6118   1.1  christos 	 */
   6119   1.1  christos 	if (qctx->dns64 && qctx->rpz) {
   6120   1.1  christos 		rpzqname = qctx->client->query.rpz_st->p_name;
   6121   1.1  christos 	} else {
   6122   1.1  christos 		rpzqname = qctx->client->query.qname;
   6123   1.1  christos 	}
   6124   1.1  christos 
   6125  1.25  christos 	qctx->client->query.dboptions &= ~DNS_DBFIND_STALETIMEOUT;
   6126  1.25  christos 
   6127  1.25  christos 	if (qctx->options.stalefirst && !qctx->is_zone) {
   6128  1.11  christos 		/*
   6129  1.23  christos 		 * If the 'stalefirst' flag is set, it means that a stale
   6130  1.11  christos 		 * RRset may be returned as part of this lookup. An attempt
   6131  1.11  christos 		 * to refresh the RRset will still take place if an
   6132  1.11  christos 		 * active RRset is not available.
   6133  1.11  christos 		 */
   6134  1.13  christos 		qctx->client->query.dboptions |= DNS_DBFIND_STALETIMEOUT;
   6135  1.11  christos 	}
   6136  1.11  christos 
   6137  1.26  christos 	(void)dns_db_getservestalerefresh(qctx->client->view->cachedb,
   6138  1.26  christos 					  &stale_refresh);
   6139  1.26  christos 	if (stale_refresh > 0 &&
   6140  1.26  christos 	    dns_view_staleanswerenabled(qctx->client->view))
   6141  1.26  christos 	{
   6142  1.26  christos 		qctx->client->query.dboptions |= DNS_DBFIND_STALEENABLED;
   6143  1.26  christos 	}
   6144  1.26  christos 
   6145   1.1  christos 	dboptions = qctx->client->query.dboptions;
   6146   1.1  christos 	if (!qctx->is_zone && qctx->findcoveringnsec &&
   6147   1.1  christos 	    (qctx->type != dns_rdatatype_null || !dns_name_istat(rpzqname)))
   6148   1.9  christos 	{
   6149   1.1  christos 		dboptions |= DNS_DBFIND_COVERINGNSEC;
   6150   1.9  christos 	}
   6151   1.1  christos 
   6152   1.1  christos 	result = dns_db_findext(qctx->db, rpzqname, qctx->version, qctx->type,
   6153   1.1  christos 				dboptions, qctx->client->now, &qctx->node,
   6154   1.9  christos 				qctx->fname, &cm, &ci, qctx->rdataset,
   6155   1.9  christos 				qctx->sigrdataset);
   6156   1.1  christos 
   6157   1.1  christos 	/*
   6158   1.1  christos 	 * Fixup fname and sigrdataset.
   6159   1.1  christos 	 */
   6160   1.1  christos 	if (qctx->dns64 && qctx->rpz) {
   6161  1.20  christos 		dns_name_copy(qctx->client->query.qname, qctx->fname);
   6162   1.1  christos 		if (qctx->sigrdataset != NULL &&
   6163  1.16  christos 		    dns_rdataset_isassociated(qctx->sigrdataset))
   6164  1.16  christos 		{
   6165   1.1  christos 			dns_rdataset_disassociate(qctx->sigrdataset);
   6166   1.1  christos 		}
   6167   1.1  christos 	}
   6168   1.1  christos 
   6169   1.1  christos 	if (!qctx->is_zone) {
   6170   1.3  christos 		dns_cache_updatestats(qctx->view->cache, result);
   6171   1.1  christos 	}
   6172   1.1  christos 
   6173  1.11  christos 	/*
   6174  1.11  christos 	 * If DNS_DBFIND_STALEOK is set this means we are dealing with a
   6175  1.11  christos 	 * lookup following a failed lookup and it is okay to serve a stale
   6176  1.11  christos 	 * answer. This will (re)start the 'stale-refresh-time' window in
   6177  1.11  christos 	 * rbtdb, tracking the last time the RRset lookup failed.
   6178  1.11  christos 	 */
   6179  1.11  christos 	dbfind_stale = ((dboptions & DNS_DBFIND_STALEOK) != 0);
   6180  1.11  christos 
   6181  1.11  christos 	/*
   6182  1.11  christos 	 * If DNS_DBFIND_STALEENABLED is set, this may be a normal lookup, but
   6183  1.11  christos 	 * we are allowed to immediately respond with a stale answer if the
   6184  1.11  christos 	 * request is within the 'stale-refresh-time' window.
   6185  1.11  christos 	 */
   6186  1.11  christos 	stale_refresh_window = (STALE_WINDOW(qctx->rdataset) &&
   6187  1.11  christos 				(dboptions & DNS_DBFIND_STALEENABLED) != 0);
   6188  1.11  christos 
   6189  1.11  christos 	/*
   6190  1.13  christos 	 * If DNS_DBFIND_STALETIMEOUT is set, a stale answer is requested.
   6191  1.11  christos 	 * This can happen if 'stale-answer-client-timeout' is enabled.
   6192  1.11  christos 	 *
   6193  1.23  christos 	 * If a stale answer is found, send it to the client, and try to refresh
   6194  1.23  christos 	 * the RRset.
   6195  1.11  christos 	 */
   6196  1.13  christos 	stale_timeout = ((dboptions & DNS_DBFIND_STALETIMEOUT) != 0);
   6197  1.11  christos 
   6198  1.16  christos 	if (dns_rdataset_isassociated(qctx->rdataset) &&
   6199  1.16  christos 	    dns_rdataset_count(qctx->rdataset) > 0 && !STALE(qctx->rdataset))
   6200  1.16  christos 	{
   6201  1.16  christos 		/* Found non-stale usable rdataset. */
   6202  1.16  christos 		answer_found = true;
   6203  1.16  christos 	}
   6204  1.16  christos 
   6205  1.13  christos 	if (dbfind_stale || stale_refresh_window || stale_timeout) {
   6206  1.13  christos 		dns_name_format(qctx->client->query.qname, namebuf,
   6207  1.13  christos 				sizeof(namebuf));
   6208  1.23  christos 		dns_rdatatype_format(qctx->qtype, typebuf, sizeof(typebuf));
   6209   1.1  christos 
   6210  1.11  christos 		inc_stats(qctx->client, ns_statscounter_trystale);
   6211  1.11  christos 
   6212   1.1  christos 		if (dns_rdataset_isassociated(qctx->rdataset) &&
   6213   1.1  christos 		    dns_rdataset_count(qctx->rdataset) > 0 &&
   6214   1.9  christos 		    STALE(qctx->rdataset))
   6215   1.9  christos 		{
   6216  1.20  christos 			stale_found = true;
   6217  1.20  christos 			if (result == DNS_R_NCACHENXDOMAIN ||
   6218  1.20  christos 			    result == DNS_R_NXDOMAIN)
   6219  1.20  christos 			{
   6220  1.20  christos 				ede = DNS_EDE_STALENXANSWER;
   6221  1.20  christos 			} else {
   6222  1.20  christos 				ede = DNS_EDE_STALEANSWER;
   6223  1.20  christos 			}
   6224   1.3  christos 			qctx->rdataset->ttl = qctx->view->staleanswerttl;
   6225  1.14  christos 			inc_stats(qctx->client, ns_statscounter_usedstale);
   6226   1.1  christos 		} else {
   6227  1.11  christos 			stale_found = false;
   6228   1.1  christos 		}
   6229  1.13  christos 	}
   6230   1.1  christos 
   6231  1.13  christos 	if (dbfind_stale) {
   6232  1.13  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   6233  1.13  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   6234  1.23  christos 			      "%s %s resolver failure, stale answer %s (%s)",
   6235  1.23  christos 			      namebuf, typebuf,
   6236  1.23  christos 			      stale_found ? "used" : "unavailable",
   6237  1.23  christos 			      isc_result_totext(result));
   6238  1.20  christos 		if (stale_found) {
   6239  1.24  christos 			dns_ede_add(&qctx->client->edectx, ede,
   6240  1.24  christos 				    "resolver failure");
   6241  1.20  christos 		} else if (!answer_found) {
   6242  1.13  christos 			/*
   6243  1.13  christos 			 * Resolver failure, no stale data, nothing more we
   6244  1.13  christos 			 * can do, return SERVFAIL.
   6245  1.13  christos 			 */
   6246  1.13  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   6247  1.23  christos 			return ns_query_done(qctx);
   6248  1.13  christos 		}
   6249  1.13  christos 	} else if (stale_refresh_window) {
   6250  1.13  christos 		/*
   6251  1.13  christos 		 * A recent lookup failed, so during this time window we are
   6252  1.13  christos 		 * allowed to return stale data immediately.
   6253  1.13  christos 		 */
   6254  1.13  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   6255  1.13  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   6256  1.23  christos 			      "%s %s query within stale refresh time, stale "
   6257  1.23  christos 			      "answer %s (%s)",
   6258  1.23  christos 			      namebuf, typebuf,
   6259  1.23  christos 			      stale_found ? "used" : "unavailable",
   6260  1.23  christos 			      isc_result_totext(result));
   6261  1.11  christos 
   6262  1.20  christos 		if (stale_found) {
   6263  1.24  christos 			dns_ede_add(&qctx->client->edectx, ede,
   6264  1.24  christos 				    "query within stale refresh time window");
   6265  1.20  christos 		} else if (!answer_found) {
   6266  1.11  christos 			/*
   6267  1.13  christos 			 * During the stale refresh window explicitly do not try
   6268  1.13  christos 			 * to refresh the data, because a recent lookup failed.
   6269  1.11  christos 			 */
   6270  1.13  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   6271  1.23  christos 			return ns_query_done(qctx);
   6272  1.13  christos 		}
   6273  1.13  christos 	} else if (stale_timeout) {
   6274  1.23  christos 		if (qctx->options.stalefirst) {
   6275  1.24  christos 			/*
   6276  1.24  christos 			 * If 'qctx->zdb' is set, this was a cache lookup after
   6277  1.24  christos 			 * an authoritative lookup returned a delegation (in
   6278  1.24  christos 			 * order to find a better answer). But we still can
   6279  1.24  christos 			 * return without getting any usable answer here, as
   6280  1.24  christos 			 * query_notfound() should handle it from here.
   6281  1.24  christos 			 * Otherwise, if nothing useful was found in cache then
   6282  1.24  christos 			 * recursively call query_lookup() again without the
   6283  1.24  christos 			 * 'stalefirst' option set.
   6284  1.24  christos 			 */
   6285  1.24  christos 			if (!stale_found && !answer_found && qctx->zdb == NULL)
   6286  1.24  christos 			{
   6287  1.13  christos 				qctx_clean(qctx);
   6288  1.13  christos 				qctx_freedata(qctx);
   6289  1.13  christos 				dns_db_attach(qctx->client->view->cachedb,
   6290  1.13  christos 					      &qctx->db);
   6291  1.23  christos 				qctx->options.stalefirst = false;
   6292  1.23  christos 				if (FETCH_RECTYPE_NORMAL(qctx->client) != NULL)
   6293  1.23  christos 				{
   6294  1.13  christos 					dns_resolver_destroyfetch(
   6295  1.23  christos 						&FETCH_RECTYPE_NORMAL(
   6296  1.23  christos 							qctx->client));
   6297  1.11  christos 				}
   6298  1.23  christos 				return query_lookup(qctx);
   6299  1.17  christos 			} else if (stale_client_answer(result)) {
   6300  1.11  christos 				/*
   6301  1.13  christos 				 * Immediately return the stale answer, start a
   6302  1.13  christos 				 * resolver fetch to refresh the data in cache.
   6303  1.11  christos 				 */
   6304  1.20  christos 				if (stale_found) {
   6305  1.24  christos 					dns_ede_add(
   6306  1.24  christos 						&qctx->client->edectx, ede,
   6307  1.20  christos 						"stale data prioritized over "
   6308  1.20  christos 						"lookup");
   6309  1.20  christos 				}
   6310  1.13  christos 			}
   6311  1.13  christos 		} else {
   6312  1.23  christos 			UNREACHABLE();
   6313   1.1  christos 		}
   6314  1.11  christos 	}
   6315  1.11  christos 
   6316  1.11  christos 	result = query_gotanswer(qctx, result);
   6317  1.11  christos 
   6318   1.9  christos cleanup:
   6319  1.23  christos 	return result;
   6320   1.1  christos }
   6321   1.1  christos 
   6322   1.1  christos /*
   6323  1.11  christos  * Event handler to resume processing a query after recursion, or when a
   6324  1.11  christos  * client timeout is triggered. If the query has timed out or been cancelled
   6325  1.11  christos  * or the system is shutting down, clean up and exit. If a client timeout is
   6326  1.11  christos  * triggered, see if we can respond with a stale answer from cache. Otherwise,
   6327  1.11  christos  * call query_resume() to continue the ongoing work.
   6328   1.1  christos  */
   6329   1.1  christos static void
   6330  1.23  christos fetch_callback(void *arg) {
   6331  1.23  christos 	dns_fetchresponse_t *resp = (dns_fetchresponse_t *)arg;
   6332  1.23  christos 	ns_client_t *client = resp->arg;
   6333   1.1  christos 	dns_fetch_t *fetch = NULL;
   6334  1.14  christos 	bool fetch_canceled = false;
   6335  1.14  christos 	isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_ERRORS;
   6336   1.1  christos 	isc_result_t result;
   6337   1.1  christos 	int errorloglevel;
   6338  1.11  christos 	query_ctx_t qctx;
   6339   1.1  christos 
   6340   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   6341   1.1  christos 	REQUIRE(RECURSING(client));
   6342   1.1  christos 
   6343   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "fetch_callback");
   6344   1.9  christos 
   6345  1.13  christos 	/*
   6346  1.13  christos 	 * We are resuming from recursion. Reset any attributes, options
   6347  1.13  christos 	 * that a lookup due to stale-answer-client-timeout may have set.
   6348  1.13  christos 	 */
   6349  1.13  christos 	if (client->view->cachedb != NULL && client->view->recursion) {
   6350  1.13  christos 		client->query.attributes |= NS_QUERYATTR_RECURSIONOK;
   6351  1.13  christos 	}
   6352  1.13  christos 	client->query.dboptions &= ~DNS_DBFIND_STALETIMEOUT;
   6353  1.26  christos 	client->query.dboptions &= ~DNS_DBFIND_STALEENABLED;
   6354  1.13  christos 
   6355   1.1  christos 	LOCK(&client->query.fetchlock);
   6356  1.23  christos 	INSIST(FETCH_RECTYPE_NORMAL(client) == resp->fetch ||
   6357  1.23  christos 	       FETCH_RECTYPE_NORMAL(client) == NULL);
   6358  1.23  christos 	if (FETCH_RECTYPE_NORMAL(client) != NULL) {
   6359   1.1  christos 		/*
   6360   1.1  christos 		 * This is the fetch we've been waiting for.
   6361   1.1  christos 		 */
   6362  1.23  christos 		INSIST(FETCH_RECTYPE_NORMAL(client) == resp->fetch);
   6363  1.23  christos 		FETCH_RECTYPE_NORMAL(client) = NULL;
   6364  1.14  christos 
   6365   1.1  christos 		/*
   6366   1.1  christos 		 * Update client->now.
   6367   1.1  christos 		 */
   6368  1.23  christos 		client->now = isc_stdtime_now();
   6369   1.1  christos 	} else {
   6370   1.1  christos 		/*
   6371   1.1  christos 		 * This is a fetch completion event for a canceled fetch.
   6372   1.1  christos 		 * Clean up and don't resume the find.
   6373   1.1  christos 		 */
   6374   1.3  christos 		fetch_canceled = true;
   6375   1.1  christos 	}
   6376   1.1  christos 	UNLOCK(&client->query.fetchlock);
   6377   1.1  christos 
   6378  1.23  christos 	SAVE(fetch, resp->fetch);
   6379   1.9  christos 
   6380   1.9  christos 	/*
   6381   1.9  christos 	 * We're done recursing, detach from quota and unlink from
   6382   1.9  christos 	 * the manager's recursing-clients list.
   6383   1.9  christos 	 */
   6384  1.23  christos 	release_recursionquota(client);
   6385   1.9  christos 
   6386  1.23  christos 	isc_nmhandle_detach(&HANDLE_RECTYPE_NORMAL(client));
   6387  1.11  christos 
   6388   1.1  christos 	client->query.attributes &= ~NS_QUERYATTR_RECURSING;
   6389   1.9  christos 	client->state = NS_CLIENTSTATE_WORKING;
   6390   1.1  christos 
   6391   1.1  christos 	/*
   6392  1.11  christos 	 * Initialize a new qctx and use it to either resume from
   6393  1.11  christos 	 * recursion or clean up after cancelation.  Transfer
   6394  1.23  christos 	 * ownership of resp to the new qctx in the process.
   6395   1.1  christos 	 */
   6396  1.23  christos 	qctx_init(client, &resp, 0, &qctx);
   6397  1.11  christos 
   6398  1.23  christos 	if (fetch_canceled) {
   6399  1.11  christos 		/*
   6400  1.11  christos 		 * We've timed out or are shutting down. We can now
   6401  1.11  christos 		 * free the event and other resources held by qctx, but
   6402  1.11  christos 		 * don't call qctx_destroy() yet: it might destroy the
   6403  1.11  christos 		 * client, which we still need for a moment.
   6404  1.11  christos 		 */
   6405  1.11  christos 		qctx_freedata(&qctx);
   6406  1.11  christos 
   6407  1.11  christos 		/*
   6408  1.23  christos 		 * Return an error to the client.
   6409  1.11  christos 		 */
   6410  1.23  christos 		CTRACE(ISC_LOG_ERROR, "fetch cancelled");
   6411  1.23  christos 		query_error(client, DNS_R_SERVFAIL, __LINE__);
   6412  1.11  christos 
   6413  1.11  christos 		/*
   6414  1.11  christos 		 * Free any persistent plugin data that was allocated to
   6415  1.11  christos 		 * service the client, then detach the client object.
   6416  1.11  christos 		 */
   6417  1.11  christos 		qctx.detach_client = true;
   6418  1.11  christos 		qctx_destroy(&qctx);
   6419   1.1  christos 	} else {
   6420   1.3  christos 		/*
   6421  1.11  christos 		 * Resume the find process.
   6422   1.3  christos 		 */
   6423   1.1  christos 		query_trace(&qctx);
   6424   1.1  christos 
   6425   1.1  christos 		result = query_resume(&qctx);
   6426   1.1  christos 		if (result != ISC_R_SUCCESS) {
   6427   1.1  christos 			if (result == DNS_R_SERVFAIL) {
   6428   1.1  christos 				errorloglevel = ISC_LOG_DEBUG(2);
   6429   1.1  christos 			} else {
   6430   1.1  christos 				errorloglevel = ISC_LOG_DEBUG(4);
   6431   1.1  christos 			}
   6432   1.1  christos 			if (isc_log_wouldlog(ns_lctx, errorloglevel)) {
   6433   1.1  christos 				dns_resolver_logfetch(fetch, ns_lctx,
   6434   1.1  christos 						      logcategory,
   6435   1.1  christos 						      NS_LOGMODULE_QUERY,
   6436   1.3  christos 						      errorloglevel, false);
   6437   1.1  christos 			}
   6438   1.1  christos 		}
   6439   1.3  christos 
   6440   1.3  christos 		qctx_destroy(&qctx);
   6441   1.1  christos 	}
   6442   1.1  christos 
   6443   1.1  christos 	dns_resolver_destroyfetch(&fetch);
   6444   1.1  christos }
   6445   1.1  christos 
   6446   1.1  christos /*%
   6447   1.1  christos  * Check whether the recursion parameters in 'param' match the current query's
   6448   1.1  christos  * recursion parameters provided in 'qtype', 'qname', and 'qdomain'.
   6449   1.1  christos  */
   6450   1.3  christos static bool
   6451   1.1  christos recparam_match(const ns_query_recparam_t *param, dns_rdatatype_t qtype,
   6452   1.9  christos 	       const dns_name_t *qname, const dns_name_t *qdomain) {
   6453   1.1  christos 	REQUIRE(param != NULL);
   6454   1.1  christos 
   6455  1.23  christos 	return param->qtype == qtype && param->qname != NULL && qname != NULL &&
   6456  1.23  christos 	       param->qdomain != NULL && qdomain != NULL &&
   6457  1.23  christos 	       dns_name_equal(param->qname, qname) &&
   6458  1.23  christos 	       dns_name_equal(param->qdomain, qdomain);
   6459   1.1  christos }
   6460   1.1  christos 
   6461   1.1  christos /*%
   6462   1.1  christos  * Update 'param' with current query's recursion parameters provided in
   6463   1.1  christos  * 'qtype', 'qname', and 'qdomain'.
   6464   1.1  christos  */
   6465   1.1  christos static void
   6466   1.1  christos recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
   6467   1.9  christos 		const dns_name_t *qname, const dns_name_t *qdomain) {
   6468   1.1  christos 	REQUIRE(param != NULL);
   6469   1.1  christos 
   6470   1.1  christos 	param->qtype = qtype;
   6471   1.1  christos 
   6472   1.1  christos 	if (qname == NULL) {
   6473   1.1  christos 		param->qname = NULL;
   6474   1.1  christos 	} else {
   6475   1.3  christos 		param->qname = dns_fixedname_initname(&param->fqname);
   6476  1.20  christos 		dns_name_copy(qname, param->qname);
   6477   1.1  christos 	}
   6478   1.1  christos 
   6479   1.1  christos 	if (qdomain == NULL) {
   6480   1.1  christos 		param->qdomain = NULL;
   6481   1.1  christos 	} else {
   6482   1.3  christos 		param->qdomain = dns_fixedname_initname(&param->fqdomain);
   6483  1.20  christos 		dns_name_copy(qdomain, param->qdomain);
   6484   1.1  christos 	}
   6485   1.1  christos }
   6486  1.23  christos 
   6487  1.23  christos static void
   6488  1.23  christos recursionquota_log(ns_client_t *client, atomic_uint_fast32_t *last_log_time,
   6489  1.23  christos 		   const char *format, isc_quota_t *quota) {
   6490  1.23  christos 	isc_stdtime_t now = isc_stdtime_now();
   6491  1.23  christos 	if (now == atomic_load_relaxed(last_log_time)) {
   6492  1.23  christos 		return;
   6493  1.23  christos 	}
   6494  1.23  christos 
   6495  1.23  christos 	atomic_store_relaxed(last_log_time, now);
   6496  1.23  christos 	ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
   6497  1.23  christos 		      ISC_LOG_WARNING, format, isc_quota_getused(quota),
   6498  1.23  christos 		      isc_quota_getsoft(quota), isc_quota_getmax(quota));
   6499  1.23  christos }
   6500  1.23  christos 
   6501   1.9  christos static atomic_uint_fast32_t last_soft, last_hard;
   6502   1.1  christos 
   6503  1.20  christos /*%
   6504  1.23  christos  * Acquire recursion quota before making the current client "recursing".
   6505  1.20  christos  */
   6506  1.20  christos static isc_result_t
   6507  1.23  christos acquire_recursionquota(ns_client_t *client) {
   6508  1.23  christos 	isc_result_t result;
   6509  1.23  christos 
   6510  1.23  christos 	result = recursionquotatype_attach_soft(client);
   6511  1.23  christos 	switch (result) {
   6512  1.23  christos 	case ISC_R_SOFTQUOTA:
   6513  1.23  christos 		recursionquota_log(client, &last_soft,
   6514  1.23  christos 				   "recursive-clients soft limit exceeded "
   6515  1.23  christos 				   "(%u/%u/%u), aborting oldest query",
   6516  1.23  christos 				   &client->manager->sctx->recursionquota);
   6517  1.23  christos 		ns_client_killoldestquery(client);
   6518  1.23  christos 		FALLTHROUGH;
   6519  1.23  christos 	case ISC_R_SUCCESS:
   6520  1.23  christos 		break;
   6521  1.23  christos 	case ISC_R_QUOTA:
   6522  1.23  christos 		recursionquota_log(client, &last_hard,
   6523  1.23  christos 				   "no more recursive clients (%u/%u/%u)",
   6524  1.23  christos 				   &client->manager->sctx->recursionquota);
   6525  1.23  christos 		ns_client_killoldestquery(client);
   6526  1.23  christos 		return result;
   6527  1.23  christos 	default:
   6528  1.23  christos 		UNREACHABLE();
   6529  1.23  christos 	}
   6530  1.23  christos 
   6531  1.23  christos 	dns_message_clonebuffer(client->message);
   6532  1.23  christos 	ns_client_recursing(client);
   6533  1.23  christos 
   6534  1.23  christos 	return ISC_R_SUCCESS;
   6535  1.23  christos }
   6536   1.1  christos 
   6537  1.23  christos /*%
   6538  1.23  christos  * Release recursion quota and remove the client from the "recursing" list.
   6539  1.23  christos  */
   6540  1.23  christos static void
   6541  1.23  christos release_recursionquota(ns_client_t *client) {
   6542  1.23  christos 	recursionquotatype_detach(client);
   6543   1.9  christos 
   6544  1.23  christos 	LOCK(&client->manager->reclock);
   6545  1.23  christos 	if (ISC_LINK_LINKED(client, rlink)) {
   6546  1.23  christos 		ISC_LIST_UNLINK(client->manager->recursing, client, rlink);
   6547   1.1  christos 	}
   6548  1.23  christos 	UNLOCK(&client->manager->reclock);
   6549  1.20  christos }
   6550  1.20  christos 
   6551  1.20  christos isc_result_t
   6552  1.20  christos ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
   6553  1.20  christos 		 dns_name_t *qdomain, dns_rdataset_t *nameservers,
   6554  1.20  christos 		 bool resuming) {
   6555  1.20  christos 	isc_result_t result;
   6556  1.20  christos 	dns_rdataset_t *rdataset, *sigrdataset;
   6557  1.20  christos 	isc_sockaddr_t *peeraddr = NULL;
   6558  1.20  christos 
   6559  1.20  christos 	CTRACE(ISC_LOG_DEBUG(3), "ns_query_recurse");
   6560  1.20  christos 
   6561  1.20  christos 	/*
   6562  1.20  christos 	 * Check recursion parameters from the previous query to see if they
   6563  1.20  christos 	 * match.  If not, update recursion parameters and proceed.
   6564  1.20  christos 	 */
   6565  1.20  christos 	if (recparam_match(&client->query.recparam, qtype, qname, qdomain)) {
   6566  1.20  christos 		ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
   6567  1.20  christos 			      ISC_LOG_INFO, "recursion loop detected");
   6568  1.23  christos 		return ISC_R_FAILURE;
   6569  1.20  christos 	}
   6570  1.20  christos 
   6571  1.20  christos 	recparam_update(&client->query.recparam, qtype, qname, qdomain);
   6572  1.20  christos 
   6573  1.20  christos 	if (!resuming) {
   6574  1.20  christos 		inc_stats(client, ns_statscounter_recursion);
   6575  1.20  christos 	}
   6576  1.20  christos 
   6577  1.23  christos 	result = acquire_recursionquota(client);
   6578  1.20  christos 	if (result != ISC_R_SUCCESS) {
   6579  1.23  christos 		return result;
   6580  1.20  christos 	}
   6581  1.20  christos 
   6582   1.1  christos 	/*
   6583   1.1  christos 	 * Invoke the resolver.
   6584   1.1  christos 	 */
   6585   1.1  christos 	REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
   6586  1.23  christos 	REQUIRE(FETCH_RECTYPE_NORMAL(client) == NULL);
   6587   1.1  christos 
   6588   1.3  christos 	rdataset = ns_client_newrdataset(client);
   6589   1.1  christos 
   6590   1.1  christos 	if (WANTDNSSEC(client)) {
   6591   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   6592   1.1  christos 	} else {
   6593   1.1  christos 		sigrdataset = NULL;
   6594   1.1  christos 	}
   6595   1.1  christos 
   6596  1.10  christos 	if (!client->query.timerset) {
   6597   1.1  christos 		ns_client_settimeout(client, 60);
   6598   1.1  christos 	}
   6599   1.1  christos 
   6600   1.1  christos 	if (!TCP(client)) {
   6601   1.1  christos 		peeraddr = &client->peeraddr;
   6602   1.1  christos 	}
   6603   1.1  christos 
   6604  1.23  christos 	isc_nmhandle_attach(client->handle, &HANDLE_RECTYPE_NORMAL(client));
   6605   1.9  christos 	result = dns_resolver_createfetch(
   6606   1.9  christos 		client->view->resolver, qname, qtype, qdomain, nameservers,
   6607   1.9  christos 		NULL, peeraddr, client->message->id, client->query.fetchoptions,
   6608  1.26  christos 		0, NULL, client->query.qc, NULL, client->manager->loop,
   6609  1.24  christos 		fetch_callback, client, &client->edectx, rdataset, sigrdataset,
   6610  1.24  christos 		&FETCH_RECTYPE_NORMAL(client));
   6611   1.1  christos 	if (result != ISC_R_SUCCESS) {
   6612  1.23  christos 		release_recursionquota(client);
   6613  1.23  christos 
   6614   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   6615   1.1  christos 		if (sigrdataset != NULL) {
   6616   1.3  christos 			ns_client_putrdataset(client, &sigrdataset);
   6617   1.1  christos 		}
   6618  1.23  christos 
   6619  1.23  christos 		isc_nmhandle_detach(&HANDLE_RECTYPE_NORMAL(client));
   6620   1.1  christos 	}
   6621   1.1  christos 
   6622   1.1  christos 	/*
   6623   1.1  christos 	 * We're now waiting for a fetch event. A client which is
   6624   1.1  christos 	 * shutting down will not be destroyed until all the events
   6625   1.1  christos 	 * have been received.
   6626   1.1  christos 	 */
   6627   1.1  christos 
   6628  1.23  christos 	return result;
   6629   1.1  christos }
   6630   1.1  christos 
   6631   1.1  christos /*%
   6632   1.1  christos  * Restores the query context after resuming from recursion, and
   6633   1.1  christos  * continues the query processing if needed.
   6634   1.1  christos  */
   6635   1.1  christos static isc_result_t
   6636   1.1  christos query_resume(query_ctx_t *qctx) {
   6637  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   6638   1.1  christos 	dns_name_t *tname;
   6639   1.1  christos 	isc_buffer_t b;
   6640   1.1  christos #ifdef WANT_QUERYTRACE
   6641   1.6  christos 	char mbuf[4 * DNS_NAME_FORMATSIZE];
   6642   1.1  christos 	char qbuf[DNS_NAME_FORMATSIZE];
   6643   1.1  christos 	char tbuf[DNS_RDATATYPE_FORMATSIZE];
   6644   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6645   1.9  christos 
   6646   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_resume");
   6647   1.1  christos 
   6648   1.3  christos 	CALL_HOOK(NS_QUERY_RESUME_BEGIN, qctx);
   6649   1.3  christos 
   6650   1.3  christos 	qctx->want_restart = false;
   6651   1.1  christos 
   6652   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   6653   1.1  christos 	if (qctx->rpz_st != NULL &&
   6654  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6655  1.16  christos 	{
   6656   1.1  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from RPZ recursion");
   6657   1.1  christos #ifdef WANT_QUERYTRACE
   6658   1.1  christos 		{
   6659   1.1  christos 			char pbuf[DNS_NAME_FORMATSIZE] = "<unset>";
   6660   1.1  christos 			char fbuf[DNS_NAME_FORMATSIZE] = "<unset>";
   6661   1.9  christos 			if (qctx->rpz_st->r_name != NULL) {
   6662   1.9  christos 				dns_name_format(qctx->rpz_st->r_name, qbuf,
   6663   1.9  christos 						sizeof(qbuf));
   6664   1.9  christos 			} else {
   6665   1.9  christos 				snprintf(qbuf, sizeof(qbuf), "<unset>");
   6666   1.9  christos 			}
   6667   1.9  christos 			if (qctx->rpz_st->p_name != NULL) {
   6668   1.9  christos 				dns_name_format(qctx->rpz_st->p_name, pbuf,
   6669   1.9  christos 						sizeof(pbuf));
   6670   1.9  christos 			}
   6671   1.9  christos 			if (qctx->rpz_st->fname != NULL) {
   6672   1.9  christos 				dns_name_format(qctx->rpz_st->fname, fbuf,
   6673   1.9  christos 						sizeof(fbuf));
   6674   1.9  christos 			}
   6675   1.1  christos 
   6676   1.1  christos 			snprintf(mbuf, sizeof(mbuf) - 1,
   6677   1.9  christos 				 "rpz rname:%s, pname:%s, qctx->fname:%s", qbuf,
   6678   1.9  christos 				 pbuf, fbuf);
   6679   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   6680   1.1  christos 		}
   6681   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6682   1.1  christos 
   6683   1.1  christos 		qctx->is_zone = qctx->rpz_st->q.is_zone;
   6684   1.1  christos 		qctx->authoritative = qctx->rpz_st->q.authoritative;
   6685   1.1  christos 		RESTORE(qctx->zone, qctx->rpz_st->q.zone);
   6686   1.1  christos 		RESTORE(qctx->node, qctx->rpz_st->q.node);
   6687   1.1  christos 		RESTORE(qctx->db, qctx->rpz_st->q.db);
   6688   1.1  christos 		RESTORE(qctx->rdataset, qctx->rpz_st->q.rdataset);
   6689   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->rpz_st->q.sigrdataset);
   6690   1.1  christos 		qctx->qtype = qctx->rpz_st->q.qtype;
   6691   1.1  christos 
   6692  1.23  christos 		if (qctx->fresp->node != NULL) {
   6693  1.23  christos 			dns_db_detachnode(qctx->fresp->db, &qctx->fresp->node);
   6694   1.9  christos 		}
   6695  1.23  christos 		SAVE(qctx->rpz_st->r.db, qctx->fresp->db);
   6696  1.23  christos 		qctx->rpz_st->r.r_type = qctx->fresp->qtype;
   6697  1.23  christos 		SAVE(qctx->rpz_st->r.r_rdataset, qctx->fresp->rdataset);
   6698  1.23  christos 		ns_client_putrdataset(qctx->client, &qctx->fresp->sigrdataset);
   6699   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6700   1.1  christos 		/*
   6701   1.1  christos 		 * Restore saved state.
   6702   1.1  christos 		 */
   6703   1.9  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from redirect recursion");
   6704   1.1  christos #ifdef WANT_QUERYTRACE
   6705   1.9  christos 		dns_name_format(qctx->client->query.redirect.fname, qbuf,
   6706   1.9  christos 				sizeof(qbuf));
   6707   1.9  christos 		dns_rdatatype_format(qctx->client->query.redirect.qtype, tbuf,
   6708   1.9  christos 				     sizeof(tbuf));
   6709   1.1  christos 		snprintf(mbuf, sizeof(mbuf) - 1,
   6710   1.9  christos 			 "redirect qctx->fname:%s, qtype:%s, auth:%d", qbuf,
   6711   1.9  christos 			 tbuf, qctx->client->query.redirect.authoritative);
   6712   1.1  christos 		CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   6713   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6714   1.1  christos 		qctx->qtype = qctx->client->query.redirect.qtype;
   6715   1.1  christos 		INSIST(qctx->client->query.redirect.rdataset != NULL);
   6716   1.1  christos 		RESTORE(qctx->rdataset, qctx->client->query.redirect.rdataset);
   6717   1.1  christos 		RESTORE(qctx->sigrdataset,
   6718   1.1  christos 			qctx->client->query.redirect.sigrdataset);
   6719   1.1  christos 		RESTORE(qctx->db, qctx->client->query.redirect.db);
   6720   1.1  christos 		RESTORE(qctx->node, qctx->client->query.redirect.node);
   6721   1.1  christos 		RESTORE(qctx->zone, qctx->client->query.redirect.zone);
   6722   1.1  christos 		qctx->authoritative =
   6723   1.1  christos 			qctx->client->query.redirect.authoritative;
   6724   1.1  christos 
   6725   1.1  christos 		/*
   6726   1.1  christos 		 * Free resources used while recursing.
   6727   1.1  christos 		 */
   6728  1.23  christos 		ns_client_putrdataset(qctx->client, &qctx->fresp->rdataset);
   6729  1.23  christos 		ns_client_putrdataset(qctx->client, &qctx->fresp->sigrdataset);
   6730  1.23  christos 		if (qctx->fresp->node != NULL) {
   6731  1.23  christos 			dns_db_detachnode(qctx->fresp->db, &qctx->fresp->node);
   6732   1.9  christos 		}
   6733  1.23  christos 		if (qctx->fresp->db != NULL) {
   6734  1.23  christos 			dns_db_detach(&qctx->fresp->db);
   6735   1.9  christos 		}
   6736   1.1  christos 	} else {
   6737   1.9  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from normal recursion");
   6738   1.3  christos 		qctx->authoritative = false;
   6739   1.1  christos 
   6740  1.23  christos 		qctx->qtype = qctx->fresp->qtype;
   6741  1.23  christos 		SAVE(qctx->db, qctx->fresp->db);
   6742  1.23  christos 		SAVE(qctx->node, qctx->fresp->node);
   6743  1.23  christos 		SAVE(qctx->rdataset, qctx->fresp->rdataset);
   6744  1.23  christos 		SAVE(qctx->sigrdataset, qctx->fresp->sigrdataset);
   6745   1.1  christos 	}
   6746   1.1  christos 	INSIST(qctx->rdataset != NULL);
   6747   1.1  christos 
   6748   1.1  christos 	if (qctx->qtype == dns_rdatatype_rrsig ||
   6749  1.16  christos 	    qctx->qtype == dns_rdatatype_sig)
   6750  1.16  christos 	{
   6751   1.1  christos 		qctx->type = dns_rdatatype_any;
   6752   1.1  christos 	} else {
   6753   1.1  christos 		qctx->type = qctx->qtype;
   6754   1.1  christos 	}
   6755   1.1  christos 
   6756   1.3  christos 	CALL_HOOK(NS_QUERY_RESUME_RESTORED, qctx);
   6757   1.3  christos 
   6758   1.1  christos 	if (DNS64(qctx->client)) {
   6759   1.1  christos 		qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64;
   6760   1.3  christos 		qctx->dns64 = true;
   6761   1.1  christos 	}
   6762   1.1  christos 
   6763   1.1  christos 	if (DNS64EXCLUDE(qctx->client)) {
   6764   1.1  christos 		qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64EXCLUDE;
   6765   1.3  christos 		qctx->dns64_exclude = true;
   6766   1.1  christos 	}
   6767   1.1  christos 
   6768   1.1  christos 	if (qctx->rpz_st != NULL &&
   6769  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6770  1.16  christos 	{
   6771   1.1  christos 		/*
   6772   1.1  christos 		 * Has response policy changed out from under us?
   6773   1.1  christos 		 */
   6774  1.24  christos 		if (qctx->view->rpzs == NULL ||
   6775  1.24  christos 		    qctx->rpz_st->rpz_ver != qctx->view->rpzs->rpz_ver)
   6776  1.24  christos 		{
   6777   1.1  christos 			ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
   6778   1.9  christos 				      NS_LOGMODULE_QUERY, DNS_RPZ_INFO_LEVEL,
   6779  1.24  christos 				      "query_resume: RPZ settings out of date "
   6780  1.24  christos 				      "after of a reconfiguration");
   6781   1.1  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   6782  1.23  christos 			return ns_query_done(qctx);
   6783   1.1  christos 		}
   6784   1.1  christos 	}
   6785   1.1  christos 
   6786   1.1  christos 	/*
   6787   1.1  christos 	 * We'll need some resources...
   6788   1.1  christos 	 */
   6789   1.3  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   6790   1.3  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   6791   1.1  christos 
   6792   1.1  christos 	if (qctx->rpz_st != NULL &&
   6793  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6794  1.16  christos 	{
   6795   1.1  christos 		tname = qctx->rpz_st->fname;
   6796   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6797   1.1  christos 		tname = qctx->client->query.redirect.fname;
   6798   1.1  christos 	} else {
   6799  1.23  christos 		tname = qctx->fresp->foundname;
   6800   1.1  christos 	}
   6801   1.1  christos 
   6802  1.20  christos 	dns_name_copy(tname, qctx->fname);
   6803   1.1  christos 
   6804   1.1  christos 	if (qctx->rpz_st != NULL &&
   6805  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6806  1.16  christos 	{
   6807  1.23  christos 		qctx->rpz_st->r.r_result = qctx->fresp->result;
   6808   1.1  christos 		result = qctx->rpz_st->q.result;
   6809  1.23  christos 		free_fresp(qctx->client, &qctx->fresp);
   6810   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6811   1.1  christos 		result = qctx->client->query.redirect.result;
   6812   1.1  christos 	} else {
   6813  1.23  christos 		result = qctx->fresp->result;
   6814   1.1  christos 	}
   6815   1.1  christos 
   6816   1.3  christos 	qctx->resuming = true;
   6817   1.1  christos 
   6818  1.23  christos 	return query_gotanswer(qctx, result);
   6819   1.3  christos 
   6820   1.9  christos cleanup:
   6821  1.23  christos 	return result;
   6822   1.1  christos }
   6823   1.1  christos 
   6824  1.20  christos static void
   6825  1.23  christos query_hookresume(void *arg) {
   6826  1.23  christos 	ns_hook_resume_t *rev = (ns_hook_resume_t *)arg;
   6827  1.20  christos 	ns_hookasync_t *hctx = NULL;
   6828  1.23  christos 	ns_client_t *client = rev->arg;
   6829  1.20  christos 	query_ctx_t *qctx = rev->saved_qctx;
   6830  1.20  christos 	bool canceled;
   6831  1.20  christos 
   6832  1.20  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_hookresume");
   6833  1.20  christos 
   6834  1.20  christos 	REQUIRE(NS_CLIENT_VALID(client));
   6835  1.20  christos 
   6836  1.20  christos 	LOCK(&client->query.fetchlock);
   6837  1.20  christos 	if (client->query.hookactx != NULL) {
   6838  1.20  christos 		INSIST(rev->ctx == client->query.hookactx);
   6839  1.20  christos 		client->query.hookactx = NULL;
   6840  1.20  christos 		canceled = false;
   6841  1.23  christos 		client->now = isc_stdtime_now();
   6842  1.20  christos 	} else {
   6843  1.20  christos 		canceled = true;
   6844  1.20  christos 	}
   6845  1.20  christos 	UNLOCK(&client->query.fetchlock);
   6846  1.20  christos 	SAVE(hctx, rev->ctx);
   6847  1.20  christos 
   6848  1.23  christos 	release_recursionquota(client);
   6849  1.20  christos 
   6850  1.20  christos 	/*
   6851  1.23  christos 	 * The fetch handle should be detached before resuming query processing
   6852  1.23  christos 	 * below, since that may trigger another recursion or asynchronous hook
   6853  1.23  christos 	 * event.
   6854  1.20  christos 	 */
   6855  1.23  christos 	isc_nmhandle_detach(&HANDLE_RECTYPE_HOOK(client));
   6856  1.20  christos 
   6857  1.20  christos 	client->state = NS_CLIENTSTATE_WORKING;
   6858  1.20  christos 
   6859  1.20  christos 	if (canceled) {
   6860  1.20  christos 		/*
   6861  1.20  christos 		 * Note: unlike fetch_callback, this function doesn't bother
   6862  1.20  christos 		 * to check the 'shutdown' condition, as that doesn't seem to
   6863  1.20  christos 		 * happen in the latest implementation.
   6864  1.20  christos 		 */
   6865  1.20  christos 		query_error(client, DNS_R_SERVFAIL, __LINE__);
   6866  1.20  christos 
   6867  1.20  christos 		/*
   6868  1.20  christos 		 * There's no other place to free/release any data maintained
   6869  1.20  christos 		 * in qctx.  We need to do it here to prevent leak.
   6870  1.20  christos 		 */
   6871  1.20  christos 		qctx_clean(qctx);
   6872  1.20  christos 		qctx_freedata(qctx);
   6873  1.20  christos 
   6874  1.20  christos 		/*
   6875  1.20  christos 		 * As we're almost done with this client, make sure any internal
   6876  1.20  christos 		 * resource for hooks will be released (if necessary) via the
   6877  1.20  christos 		 * QCTX_DESTROYED hook.
   6878  1.20  christos 		 */
   6879  1.20  christos 		qctx->detach_client = true;
   6880  1.20  christos 	} else {
   6881  1.20  christos 		switch (rev->hookpoint) {
   6882  1.20  christos 		case NS_QUERY_SETUP:
   6883  1.23  christos 			query_setup(client, qctx->qtype);
   6884  1.20  christos 			break;
   6885  1.20  christos 		case NS_QUERY_START_BEGIN:
   6886  1.20  christos 			(void)ns__query_start(qctx);
   6887  1.20  christos 			break;
   6888  1.20  christos 		case NS_QUERY_LOOKUP_BEGIN:
   6889  1.20  christos 			(void)query_lookup(qctx);
   6890  1.20  christos 			break;
   6891  1.20  christos 		case NS_QUERY_RESUME_BEGIN:
   6892  1.20  christos 		case NS_QUERY_RESUME_RESTORED:
   6893  1.20  christos 			(void)query_resume(qctx);
   6894  1.20  christos 			break;
   6895  1.20  christos 		case NS_QUERY_GOT_ANSWER_BEGIN:
   6896  1.20  christos 			(void)query_gotanswer(qctx, rev->origresult);
   6897  1.20  christos 			break;
   6898  1.20  christos 		case NS_QUERY_RESPOND_ANY_BEGIN:
   6899  1.20  christos 			(void)query_respond_any(qctx);
   6900  1.20  christos 			break;
   6901  1.20  christos 		case NS_QUERY_ADDANSWER_BEGIN:
   6902  1.20  christos 			(void)query_addanswer(qctx);
   6903  1.20  christos 			break;
   6904  1.20  christos 		case NS_QUERY_NOTFOUND_BEGIN:
   6905  1.20  christos 			(void)query_notfound(qctx);
   6906  1.20  christos 			break;
   6907  1.20  christos 		case NS_QUERY_PREP_DELEGATION_BEGIN:
   6908  1.20  christos 			(void)query_prepare_delegation_response(qctx);
   6909  1.20  christos 			break;
   6910  1.20  christos 		case NS_QUERY_ZONE_DELEGATION_BEGIN:
   6911  1.20  christos 			(void)query_zone_delegation(qctx);
   6912  1.20  christos 			break;
   6913  1.20  christos 		case NS_QUERY_DELEGATION_BEGIN:
   6914  1.20  christos 			(void)query_delegation(qctx);
   6915  1.20  christos 			break;
   6916  1.20  christos 		case NS_QUERY_DELEGATION_RECURSE_BEGIN:
   6917  1.20  christos 			(void)query_delegation_recurse(qctx);
   6918  1.20  christos 			break;
   6919  1.20  christos 		case NS_QUERY_NODATA_BEGIN:
   6920  1.20  christos 			(void)query_nodata(qctx, rev->origresult);
   6921  1.20  christos 			break;
   6922  1.20  christos 		case NS_QUERY_NXDOMAIN_BEGIN:
   6923  1.20  christos 			(void)query_nxdomain(qctx, rev->origresult);
   6924  1.20  christos 			break;
   6925  1.20  christos 		case NS_QUERY_NCACHE_BEGIN:
   6926  1.20  christos 			(void)query_ncache(qctx, rev->origresult);
   6927  1.20  christos 			break;
   6928  1.20  christos 		case NS_QUERY_CNAME_BEGIN:
   6929  1.20  christos 			(void)query_cname(qctx);
   6930  1.20  christos 			break;
   6931  1.20  christos 		case NS_QUERY_DNAME_BEGIN:
   6932  1.20  christos 			(void)query_dname(qctx);
   6933  1.20  christos 			break;
   6934  1.20  christos 		case NS_QUERY_RESPOND_BEGIN:
   6935  1.20  christos 			(void)query_respond(qctx);
   6936  1.20  christos 			break;
   6937  1.20  christos 		case NS_QUERY_PREP_RESPONSE_BEGIN:
   6938  1.20  christos 			(void)query_prepresponse(qctx);
   6939  1.20  christos 			break;
   6940  1.20  christos 		case NS_QUERY_DONE_BEGIN:
   6941  1.20  christos 		case NS_QUERY_DONE_SEND:
   6942  1.20  christos 			(void)ns_query_done(qctx);
   6943  1.20  christos 			break;
   6944  1.20  christos 
   6945  1.20  christos 		/* Not all hookpoints can use recursion.  Catch violations */
   6946  1.20  christos 		case NS_QUERY_RESPOND_ANY_FOUND: /* due to side effect */
   6947  1.20  christos 		case NS_QUERY_NOTFOUND_RECURSE:	 /* in recursion */
   6948  1.20  christos 		case NS_QUERY_ZEROTTL_RECURSE:	 /* in recursion */
   6949  1.20  christos 		default:			 /* catch-all just in case */
   6950  1.20  christos 			INSIST(false);
   6951  1.20  christos 		}
   6952  1.20  christos 	}
   6953  1.20  christos 
   6954  1.23  christos 	isc_mem_put(hctx->mctx, rev, sizeof(*rev));
   6955  1.20  christos 	hctx->destroy(&hctx);
   6956  1.20  christos 	qctx_destroy(qctx);
   6957  1.23  christos 	isc_mem_put(client->manager->mctx, qctx, sizeof(*qctx));
   6958  1.20  christos }
   6959  1.20  christos 
   6960  1.20  christos isc_result_t
   6961  1.20  christos ns_query_hookasync(query_ctx_t *qctx, ns_query_starthookasync_t runasync,
   6962  1.20  christos 		   void *arg) {
   6963  1.20  christos 	isc_result_t result;
   6964  1.20  christos 	ns_client_t *client = qctx->client;
   6965  1.20  christos 	query_ctx_t *saved_qctx = NULL;
   6966  1.20  christos 
   6967  1.20  christos 	CTRACE(ISC_LOG_DEBUG(3), "ns_query_hookasync");
   6968  1.20  christos 
   6969  1.20  christos 	REQUIRE(NS_CLIENT_VALID(client));
   6970  1.20  christos 	REQUIRE(client->query.hookactx == NULL);
   6971  1.23  christos 	REQUIRE(FETCH_RECTYPE_NORMAL(client) == NULL);
   6972  1.20  christos 
   6973  1.23  christos 	result = acquire_recursionquota(client);
   6974  1.20  christos 	if (result != ISC_R_SUCCESS) {
   6975  1.20  christos 		goto cleanup;
   6976  1.20  christos 	}
   6977  1.20  christos 
   6978  1.23  christos 	saved_qctx = isc_mem_get(client->manager->mctx, sizeof(*saved_qctx));
   6979  1.20  christos 	qctx_save(qctx, saved_qctx);
   6980  1.23  christos 	result = runasync(saved_qctx, client->manager->mctx, arg,
   6981  1.23  christos 			  client->manager->loop, query_hookresume, client,
   6982  1.23  christos 			  &client->query.hookactx);
   6983  1.20  christos 	if (result != ISC_R_SUCCESS) {
   6984  1.23  christos 		goto cleanup_and_detach_from_quota;
   6985  1.20  christos 	}
   6986  1.20  christos 
   6987  1.24  christos 	/* Record that an asynchronous copy of the qctx has been started */
   6988  1.24  christos 	qctx->async = true;
   6989  1.24  christos 
   6990  1.20  christos 	/*
   6991  1.20  christos 	 * Typically the runasync() function will trigger recursion, but
   6992  1.20  christos 	 * there is no need to set NS_QUERYATTR_RECURSING. The calling hook
   6993  1.20  christos 	 * is expected to return NS_HOOK_RETURN, and the RECURSING
   6994  1.20  christos 	 * attribute won't be checked anywhere.
   6995  1.20  christos 	 *
   6996  1.20  christos 	 * Hook-based asynchronous processing cannot coincide with normal
   6997  1.23  christos 	 * recursion.  Unlike in ns_query_recurse(), we attach to the handle
   6998  1.23  christos 	 * only if 'runasync' succeeds. It should be safe since we're either in
   6999  1.23  christos 	 * the client task or pausing it.
   7000  1.20  christos 	 */
   7001  1.23  christos 	isc_nmhandle_attach(client->handle, &HANDLE_RECTYPE_HOOK(client));
   7002  1.23  christos 	return ISC_R_SUCCESS;
   7003  1.20  christos 
   7004  1.23  christos cleanup_and_detach_from_quota:
   7005  1.23  christos 	release_recursionquota(client);
   7006  1.20  christos cleanup:
   7007  1.20  christos 	/*
   7008  1.20  christos 	 * If we fail, send SERVFAIL now.  It may be better to let the caller
   7009  1.20  christos 	 * decide what to do on failure of this function, but hooks don't have
   7010  1.20  christos 	 * access to query_error().
   7011  1.20  christos 	 */
   7012  1.20  christos 	query_error(client, DNS_R_SERVFAIL, __LINE__);
   7013  1.20  christos 
   7014  1.20  christos 	/*
   7015  1.20  christos 	 * Free all resource related to the query and set detach_client,
   7016  1.20  christos 	 * similar to the cancel case of query_hookresume; the callers will
   7017  1.20  christos 	 * simply return on failure of this function, so there's no other
   7018  1.20  christos 	 * place for this to prevent leak.
   7019  1.20  christos 	 */
   7020  1.20  christos 	if (saved_qctx != NULL) {
   7021  1.20  christos 		qctx_clean(saved_qctx);
   7022  1.20  christos 		qctx_freedata(saved_qctx);
   7023  1.20  christos 		qctx_destroy(saved_qctx);
   7024  1.23  christos 		isc_mem_put(client->manager->mctx, saved_qctx,
   7025  1.23  christos 			    sizeof(*saved_qctx));
   7026  1.20  christos 	}
   7027  1.20  christos 	qctx->detach_client = true;
   7028  1.23  christos 	return result;
   7029  1.20  christos }
   7030  1.20  christos 
   7031   1.1  christos /*%
   7032   1.1  christos  * If the query is recursive, check the SERVFAIL cache to see whether
   7033   1.1  christos  * identical queries have failed recently.  If we find a match, and it was
   7034   1.1  christos  * from a query with CD=1, *or* if the current query has CD=0, then we just
   7035   1.1  christos  * return SERVFAIL again.  This prevents a validation failure from eliciting a
   7036   1.1  christos  * SERVFAIL response to a CD=1 query.
   7037   1.1  christos  */
   7038   1.1  christos isc_result_t
   7039   1.1  christos ns__query_sfcache(query_ctx_t *qctx) {
   7040  1.23  christos 	isc_result_t failcache;
   7041   1.3  christos 	uint32_t flags;
   7042   1.1  christos 
   7043   1.1  christos 	/*
   7044   1.1  christos 	 * The SERVFAIL cache doesn't apply to authoritative queries.
   7045   1.1  christos 	 */
   7046   1.1  christos 	if (!RECURSIONOK(qctx->client)) {
   7047  1.23  christos 		return ISC_R_COMPLETE;
   7048   1.1  christos 	}
   7049   1.1  christos 
   7050   1.1  christos 	flags = 0;
   7051   1.1  christos #ifdef ENABLE_AFL
   7052  1.23  christos 	if (qctx->client->manager->sctx->fuzztype == isc_fuzz_resolver) {
   7053  1.23  christos 		failcache = ISC_R_NOTFOUND;
   7054  1.23  christos 	} else
   7055  1.23  christos #endif /* ifdef ENABLE_AFL */
   7056  1.23  christos 	{
   7057   1.9  christos 		failcache = dns_badcache_find(
   7058   1.9  christos 			qctx->view->failcache, qctx->client->query.qname,
   7059  1.23  christos 			qctx->qtype, &flags,
   7060  1.23  christos 			isc_time_seconds(&qctx->client->tnow));
   7061  1.23  christos 	}
   7062  1.23  christos 
   7063  1.23  christos 	if (failcache != ISC_R_SUCCESS) {
   7064  1.23  christos 		return ISC_R_COMPLETE;
   7065   1.1  christos 	}
   7066  1.23  christos 
   7067  1.23  christos 	if (((flags & NS_FAILCACHE_CD) != 0) ||
   7068  1.23  christos 	    ((qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0))
   7069   1.1  christos 	{
   7070   1.1  christos 		if (isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1))) {
   7071   1.1  christos 			char namebuf[DNS_NAME_FORMATSIZE];
   7072   1.3  christos 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
   7073   1.1  christos 
   7074   1.9  christos 			dns_name_format(qctx->client->query.qname, namebuf,
   7075   1.9  christos 					sizeof(namebuf));
   7076   1.3  christos 			dns_rdatatype_format(qctx->qtype, typebuf,
   7077   1.3  christos 					     sizeof(typebuf));
   7078   1.9  christos 			ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
   7079   1.9  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(1),
   7080   1.9  christos 				      "servfail cache hit %s/%s (%s)", namebuf,
   7081   1.9  christos 				      typebuf,
   7082   1.9  christos 				      ((flags & NS_FAILCACHE_CD) != 0) ? "CD=1"
   7083   1.9  christos 								       : "CD="
   7084   1.9  christos 									 "0");
   7085   1.1  christos 		}
   7086   1.1  christos 
   7087   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
   7088   1.1  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   7089  1.23  christos 		return ns_query_done(qctx);
   7090  1.23  christos 	}
   7091  1.23  christos 
   7092  1.23  christos 	return ISC_R_COMPLETE;
   7093  1.23  christos }
   7094  1.23  christos 
   7095  1.23  christos static void
   7096  1.23  christos query_trace_rrldrop(query_ctx_t *qctx,
   7097  1.23  christos 		    dns_rrl_result_t rrl_result ISC_ATTR_UNUSED) {
   7098  1.23  christos 	if (!LIBNS_RRL_DROP_ENABLED()) {
   7099  1.23  christos 		return;
   7100   1.1  christos 	}
   7101   1.1  christos 
   7102  1.23  christos 	char peerbuf[ISC_SOCKADDR_FORMATSIZE];
   7103  1.23  christos 	isc_netaddr_t peer;
   7104  1.23  christos 	isc_netaddr_fromsockaddr(&peer, &qctx->client->peeraddr);
   7105  1.23  christos 	isc_netaddr_format(&peer, peerbuf, sizeof(peerbuf));
   7106  1.23  christos 
   7107  1.23  christos 	char qnamebuf[DNS_NAME_FORMATSIZE];
   7108  1.23  christos 	char fnamebuf[DNS_NAME_FORMATSIZE];
   7109  1.23  christos 	dns_name_format(qctx->client->query.qname, qnamebuf, sizeof(qnamebuf));
   7110  1.23  christos 	dns_name_format(qctx->fname, fnamebuf, sizeof(fnamebuf));
   7111  1.23  christos 	LIBNS_RRL_DROP(peerbuf, qnamebuf, fnamebuf, rrl_result);
   7112   1.1  christos }
   7113   1.1  christos 
   7114   1.1  christos /*%
   7115   1.1  christos  * Handle response rate limiting (RRL).
   7116   1.1  christos  */
   7117   1.1  christos static isc_result_t
   7118   1.1  christos query_checkrrl(query_ctx_t *qctx, isc_result_t result) {
   7119   1.1  christos 	/*
   7120   1.1  christos 	 * Rate limit these responses to this client.
   7121   1.1  christos 	 * Do not delay counting and handling obvious referrals,
   7122   1.1  christos 	 *	since those won't come here again.
   7123   1.1  christos 	 * Delay handling delegations for which we are certain to recurse and
   7124   1.1  christos 	 *	return here (DNS_R_DELEGATION, not a child of one of our
   7125   1.1  christos 	 *	own zones, and recursion enabled)
   7126   1.1  christos 	 * Don't mess with responses rewritten by RPZ
   7127   1.1  christos 	 * Count each response at most once.
   7128   1.1  christos 	 */
   7129   1.3  christos 
   7130   1.3  christos 	/*
   7131   1.3  christos 	 * XXXMPA the rrl system tests fails sometimes and RRL_CHECKED
   7132   1.3  christos 	 * is set when we are called the second time preventing the
   7133   1.3  christos 	 * response being dropped.
   7134   1.3  christos 	 */
   7135   1.9  christos 	ns_client_log(
   7136   1.9  christos 		qctx->client, DNS_LOGCATEGORY_RRL, NS_LOGMODULE_QUERY,
   7137   1.9  christos 		ISC_LOG_DEBUG(99),
   7138   1.9  christos 		"rrl=%p, HAVECOOKIE=%u, result=%s, "
   7139   1.9  christos 		"fname=%p(%u), is_zone=%u, RECURSIONOK=%u, "
   7140  1.23  christos 		"query.rpz_st=%p(%u), RRL_CHECKED=%u",
   7141   1.9  christos 		qctx->client->view->rrl, HAVECOOKIE(qctx->client),
   7142   1.9  christos 		isc_result_toid(result), qctx->fname,
   7143   1.9  christos 		qctx->fname != NULL ? dns_name_isabsolute(qctx->fname) : 0,
   7144   1.9  christos 		qctx->is_zone, RECURSIONOK(qctx->client),
   7145   1.9  christos 		qctx->client->query.rpz_st,
   7146   1.9  christos 		qctx->client->query.rpz_st != NULL
   7147   1.9  christos 			? ((qctx->client->query.rpz_st->state &
   7148   1.9  christos 			    DNS_RPZ_REWRITTEN) != 0)
   7149   1.9  christos 			: 0,
   7150   1.9  christos 		(qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) !=
   7151   1.9  christos 			0);
   7152   1.3  christos 
   7153   1.9  christos 	if (qctx->view->rrl != NULL && !HAVECOOKIE(qctx->client) &&
   7154   1.1  christos 	    ((qctx->fname != NULL && dns_name_isabsolute(qctx->fname)) ||
   7155   1.1  christos 	     (result == ISC_R_NOTFOUND && !RECURSIONOK(qctx->client))) &&
   7156   1.9  christos 	    !(result == DNS_R_DELEGATION && !qctx->is_zone &&
   7157   1.9  christos 	      RECURSIONOK(qctx->client)) &&
   7158   1.1  christos 	    (qctx->client->query.rpz_st == NULL ||
   7159   1.1  christos 	     (qctx->client->query.rpz_st->state & DNS_RPZ_REWRITTEN) == 0) &&
   7160   1.1  christos 	    (qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) == 0)
   7161   1.1  christos 	{
   7162   1.1  christos 		dns_rdataset_t nc_rdataset;
   7163   1.3  christos 		bool wouldlog;
   7164   1.1  christos 		dns_fixedname_t fixed;
   7165   1.1  christos 		const dns_name_t *constname;
   7166   1.1  christos 		char log_buf[DNS_RRL_LOG_BUF_LEN];
   7167   1.1  christos 		isc_result_t nc_result, resp_result;
   7168   1.1  christos 		dns_rrl_result_t rrl_result;
   7169   1.1  christos 
   7170   1.1  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RRL_CHECKED;
   7171   1.1  christos 
   7172   1.1  christos 		wouldlog = isc_log_wouldlog(ns_lctx, DNS_RRL_LOG_DROP);
   7173   1.1  christos 		constname = qctx->fname;
   7174   1.1  christos 		if (result == DNS_R_NXDOMAIN) {
   7175   1.1  christos 			/*
   7176   1.1  christos 			 * Use the database origin name to rate limit NXDOMAIN
   7177   1.1  christos 			 */
   7178   1.9  christos 			if (qctx->db != NULL) {
   7179   1.1  christos 				constname = dns_db_origin(qctx->db);
   7180   1.9  christos 			}
   7181   1.1  christos 			resp_result = result;
   7182   1.1  christos 		} else if (result == DNS_R_NCACHENXDOMAIN &&
   7183   1.1  christos 			   qctx->rdataset != NULL &&
   7184   1.1  christos 			   dns_rdataset_isassociated(qctx->rdataset) &&
   7185   1.1  christos 			   (qctx->rdataset->attributes &
   7186   1.9  christos 			    DNS_RDATASETATTR_NEGATIVE) != 0)
   7187   1.9  christos 		{
   7188   1.1  christos 			/*
   7189   1.1  christos 			 * Try to use owner name in the negative cache SOA.
   7190   1.1  christos 			 */
   7191   1.1  christos 			dns_fixedname_init(&fixed);
   7192   1.1  christos 			dns_rdataset_init(&nc_rdataset);
   7193   1.1  christos 			for (nc_result = dns_rdataset_first(qctx->rdataset);
   7194   1.1  christos 			     nc_result == ISC_R_SUCCESS;
   7195   1.1  christos 			     nc_result = dns_rdataset_next(qctx->rdataset))
   7196   1.1  christos 			{
   7197   1.1  christos 				dns_ncache_current(qctx->rdataset,
   7198   1.1  christos 						   dns_fixedname_name(&fixed),
   7199   1.1  christos 						   &nc_rdataset);
   7200   1.1  christos 				if (nc_rdataset.type == dns_rdatatype_soa) {
   7201   1.1  christos 					dns_rdataset_disassociate(&nc_rdataset);
   7202   1.1  christos 					constname = dns_fixedname_name(&fixed);
   7203   1.1  christos 					break;
   7204   1.1  christos 				}
   7205   1.1  christos 				dns_rdataset_disassociate(&nc_rdataset);
   7206   1.1  christos 			}
   7207   1.1  christos 			resp_result = DNS_R_NXDOMAIN;
   7208   1.9  christos 		} else if (result == DNS_R_NXRRSET || result == DNS_R_EMPTYNAME)
   7209   1.9  christos 		{
   7210   1.1  christos 			resp_result = DNS_R_NXRRSET;
   7211   1.1  christos 		} else if (result == DNS_R_DELEGATION) {
   7212   1.1  christos 			resp_result = result;
   7213   1.1  christos 		} else if (result == ISC_R_NOTFOUND) {
   7214   1.1  christos 			/*
   7215   1.1  christos 			 * Handle referral to ".", including when recursion
   7216   1.1  christos 			 * is off or not requested and the hints have not
   7217  1.20  christos 			 * been loaded.
   7218   1.1  christos 			 */
   7219   1.1  christos 			constname = dns_rootname;
   7220   1.1  christos 			resp_result = DNS_R_DELEGATION;
   7221   1.1  christos 		} else {
   7222   1.1  christos 			resp_result = ISC_R_SUCCESS;
   7223   1.1  christos 		}
   7224   1.1  christos 
   7225   1.9  christos 		rrl_result = dns_rrl(
   7226  1.15  christos 			qctx->view, qctx->zone, &qctx->client->peeraddr,
   7227  1.15  christos 			TCP(qctx->client), qctx->client->message->rdclass,
   7228  1.15  christos 			qctx->qtype, constname, resp_result, qctx->client->now,
   7229  1.15  christos 			wouldlog, log_buf, sizeof(log_buf));
   7230   1.1  christos 		if (rrl_result != DNS_RRL_RESULT_OK) {
   7231   1.1  christos 			/*
   7232  1.26  christos 			 * Log dropped or slipped responses in the query-errors
   7233   1.1  christos 			 * category so that requests are not silently lost.
   7234   1.1  christos 			 * Starts of rate-limited bursts are logged in
   7235   1.1  christos 			 * DNS_LOGCATEGORY_RRL.
   7236   1.1  christos 			 *
   7237   1.1  christos 			 * Dropped responses are counted with dropped queries
   7238   1.1  christos 			 * in QryDropped while slipped responses are counted
   7239   1.1  christos 			 * with other truncated responses in RespTruncated.
   7240   1.1  christos 			 */
   7241   1.1  christos 			if (wouldlog) {
   7242  1.26  christos 				ns_client_log(qctx->client,
   7243  1.26  christos 					      NS_LOGCATEGORY_QUERY_ERRORS,
   7244   1.1  christos 					      NS_LOGMODULE_QUERY,
   7245   1.9  christos 					      DNS_RRL_LOG_DROP, "%s", log_buf);
   7246   1.1  christos 			}
   7247   1.1  christos 
   7248  1.23  christos 			/*
   7249  1.23  christos 			 * If tracing is enabled, format some extra information
   7250  1.23  christos 			 * to pass along.
   7251  1.23  christos 			 */
   7252  1.23  christos 			query_trace_rrldrop(qctx, rrl_result);
   7253  1.23  christos 
   7254   1.3  christos 			if (!qctx->view->rrl->log_only) {
   7255   1.1  christos 				if (rrl_result == DNS_RRL_RESULT_DROP) {
   7256   1.1  christos 					/*
   7257   1.1  christos 					 * These will also be counted in
   7258   1.1  christos 					 * ns_statscounter_dropped
   7259   1.1  christos 					 */
   7260   1.1  christos 					inc_stats(qctx->client,
   7261   1.9  christos 						  ns_statscounter_ratedropped);
   7262   1.1  christos 					QUERY_ERROR(qctx, DNS_R_DROP);
   7263   1.1  christos 				} else {
   7264   1.1  christos 					/*
   7265   1.1  christos 					 * These will also be counted in
   7266   1.1  christos 					 * ns_statscounter_truncatedresp
   7267   1.1  christos 					 */
   7268   1.1  christos 					inc_stats(qctx->client,
   7269   1.9  christos 						  ns_statscounter_rateslipped);
   7270   1.1  christos 					if (WANTCOOKIE(qctx->client)) {
   7271   1.1  christos 						qctx->client->message->flags &=
   7272   1.1  christos 							~DNS_MESSAGEFLAG_AA;
   7273   1.1  christos 						qctx->client->message->flags &=
   7274   1.1  christos 							~DNS_MESSAGEFLAG_AD;
   7275   1.1  christos 						qctx->client->message->rcode =
   7276   1.9  christos 							dns_rcode_badcookie;
   7277   1.1  christos 					} else {
   7278   1.1  christos 						qctx->client->message->flags |=
   7279   1.1  christos 							DNS_MESSAGEFLAG_TC;
   7280   1.1  christos 						if (resp_result ==
   7281  1.16  christos 						    DNS_R_NXDOMAIN)
   7282  1.16  christos 						{
   7283   1.9  christos 							qctx->client->message
   7284   1.9  christos 								->rcode =
   7285   1.9  christos 								dns_rcode_nxdomain;
   7286   1.1  christos 						}
   7287   1.1  christos 					}
   7288   1.1  christos 				}
   7289  1.23  christos 				return DNS_R_DROP;
   7290   1.1  christos 			}
   7291   1.1  christos 		}
   7292   1.1  christos 	}
   7293   1.1  christos 
   7294  1.23  christos 	return ISC_R_SUCCESS;
   7295   1.1  christos }
   7296   1.1  christos 
   7297  1.26  christos static void
   7298  1.26  christos query_rpz_add_ede(query_ctx_t *qctx) {
   7299  1.26  christos 	if (qctx->rpz_st->m.rpz->ede != 0 &&
   7300  1.26  christos 	    qctx->rpz_st->m.rpz->ede != UINT16_MAX)
   7301  1.26  christos 	{
   7302  1.26  christos 		dns_ede_add(&qctx->client->edectx, qctx->rpz_st->m.rpz->ede,
   7303  1.26  christos 			    NULL);
   7304  1.26  christos 	}
   7305  1.26  christos }
   7306  1.26  christos 
   7307   1.1  christos /*%
   7308   1.1  christos  * Do any RPZ rewriting that may be needed for this query.
   7309   1.1  christos  */
   7310   1.1  christos static isc_result_t
   7311   1.1  christos query_checkrpz(query_ctx_t *qctx, isc_result_t result) {
   7312   1.1  christos 	isc_result_t rresult;
   7313   1.1  christos 
   7314   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_checkrpz");
   7315   1.9  christos 
   7316   1.9  christos 	rresult = rpz_rewrite(qctx->client, qctx->qtype, result, qctx->resuming,
   7317   1.1  christos 			      qctx->rdataset, qctx->sigrdataset);
   7318   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   7319   1.1  christos 	switch (rresult) {
   7320   1.1  christos 	case ISC_R_SUCCESS:
   7321   1.1  christos 		break;
   7322  1.13  christos 	case ISC_R_NOTFOUND:
   7323   1.1  christos 	case DNS_R_DISALLOWED:
   7324  1.23  christos 		return result;
   7325   1.1  christos 	case DNS_R_DELEGATION:
   7326   1.1  christos 		/*
   7327   1.1  christos 		 * recursing for NS names or addresses,
   7328   1.1  christos 		 * so save the main query state
   7329   1.1  christos 		 */
   7330  1.13  christos 		INSIST(!RECURSING(qctx->client));
   7331   1.1  christos 		qctx->rpz_st->q.qtype = qctx->qtype;
   7332   1.1  christos 		qctx->rpz_st->q.is_zone = qctx->is_zone;
   7333   1.1  christos 		qctx->rpz_st->q.authoritative = qctx->authoritative;
   7334   1.1  christos 		SAVE(qctx->rpz_st->q.zone, qctx->zone);
   7335   1.1  christos 		SAVE(qctx->rpz_st->q.db, qctx->db);
   7336   1.1  christos 		SAVE(qctx->rpz_st->q.node, qctx->node);
   7337   1.1  christos 		SAVE(qctx->rpz_st->q.rdataset, qctx->rdataset);
   7338   1.1  christos 		SAVE(qctx->rpz_st->q.sigrdataset, qctx->sigrdataset);
   7339  1.20  christos 		dns_name_copy(qctx->fname, qctx->rpz_st->fname);
   7340   1.1  christos 		qctx->rpz_st->q.result = result;
   7341   1.1  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   7342  1.23  christos 		return ISC_R_COMPLETE;
   7343   1.1  christos 	default:
   7344   1.3  christos 		QUERY_ERROR(qctx, rresult);
   7345  1.23  christos 		return ISC_R_COMPLETE;
   7346   1.1  christos 	}
   7347   1.1  christos 
   7348   1.1  christos 	if (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS) {
   7349   1.1  christos 		qctx->rpz_st->state |= DNS_RPZ_REWRITTEN;
   7350   1.1  christos 	}
   7351   1.1  christos 
   7352   1.1  christos 	if (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS &&
   7353   1.1  christos 	    qctx->rpz_st->m.policy != DNS_RPZ_POLICY_PASSTHRU &&
   7354   1.1  christos 	    (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_TCP_ONLY ||
   7355   1.1  christos 	     !TCP(qctx->client)) &&
   7356   1.1  christos 	    qctx->rpz_st->m.policy != DNS_RPZ_POLICY_ERROR)
   7357   1.1  christos 	{
   7358   1.1  christos 		/*
   7359   1.1  christos 		 * We got a hit and are going to answer with our
   7360   1.1  christos 		 * fiction. Ensure that we answer with the name
   7361   1.1  christos 		 * we looked up even if we were stopped short
   7362   1.1  christos 		 * in recursion or for a deferral.
   7363   1.1  christos 		 */
   7364  1.20  christos 		dns_name_copy(qctx->client->query.qname, qctx->fname);
   7365   1.1  christos 		rpz_clean(&qctx->zone, &qctx->db, &qctx->node, NULL);
   7366   1.1  christos 		if (qctx->rpz_st->m.rdataset != NULL) {
   7367   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   7368   1.1  christos 			RESTORE(qctx->rdataset, qctx->rpz_st->m.rdataset);
   7369   1.1  christos 		} else {
   7370   1.1  christos 			qctx_clean(qctx);
   7371   1.1  christos 		}
   7372   1.1  christos 		qctx->version = NULL;
   7373   1.1  christos 
   7374   1.1  christos 		RESTORE(qctx->node, qctx->rpz_st->m.node);
   7375   1.1  christos 		RESTORE(qctx->db, qctx->rpz_st->m.db);
   7376   1.1  christos 		RESTORE(qctx->version, qctx->rpz_st->m.version);
   7377   1.1  christos 		RESTORE(qctx->zone, qctx->rpz_st->m.zone);
   7378   1.1  christos 
   7379   1.1  christos 		/*
   7380   1.1  christos 		 * Add SOA record to additional section
   7381   1.1  christos 		 */
   7382   1.5  christos 		if (qctx->rpz_st->m.rpz->addsoa) {
   7383  1.22  christos 			rresult = query_addsoa(qctx, UINT32_MAX,
   7384   1.5  christos 					       DNS_SECTION_ADDITIONAL);
   7385   1.5  christos 			if (rresult != ISC_R_SUCCESS) {
   7386   1.5  christos 				QUERY_ERROR(qctx, result);
   7387  1.23  christos 				return ISC_R_COMPLETE;
   7388   1.5  christos 			}
   7389   1.1  christos 		}
   7390   1.1  christos 
   7391   1.1  christos 		switch (qctx->rpz_st->m.policy) {
   7392   1.1  christos 		case DNS_RPZ_POLICY_TCP_ONLY:
   7393   1.1  christos 			qctx->client->message->flags |= DNS_MESSAGEFLAG_TC;
   7394   1.1  christos 			if (result == DNS_R_NXDOMAIN ||
   7395  1.16  christos 			    result == DNS_R_NCACHENXDOMAIN)
   7396  1.16  christos 			{
   7397   1.1  christos 				qctx->client->message->rcode =
   7398   1.9  christos 					dns_rcode_nxdomain;
   7399   1.9  christos 			}
   7400   1.3  christos 			rpz_log_rewrite(qctx->client, false,
   7401   1.1  christos 					qctx->rpz_st->m.policy,
   7402   1.1  christos 					qctx->rpz_st->m.type, qctx->zone,
   7403   1.1  christos 					qctx->rpz_st->p_name, NULL,
   7404   1.1  christos 					qctx->rpz_st->m.rpz->num);
   7405  1.23  christos 			return ISC_R_COMPLETE;
   7406   1.1  christos 		case DNS_RPZ_POLICY_DROP:
   7407   1.1  christos 			QUERY_ERROR(qctx, DNS_R_DROP);
   7408   1.3  christos 			rpz_log_rewrite(qctx->client, false,
   7409   1.1  christos 					qctx->rpz_st->m.policy,
   7410   1.1  christos 					qctx->rpz_st->m.type, qctx->zone,
   7411   1.1  christos 					qctx->rpz_st->p_name, NULL,
   7412   1.1  christos 					qctx->rpz_st->m.rpz->num);
   7413  1.23  christos 			return ISC_R_COMPLETE;
   7414   1.1  christos 		case DNS_RPZ_POLICY_NXDOMAIN:
   7415   1.1  christos 			result = DNS_R_NXDOMAIN;
   7416   1.3  christos 			qctx->nxrewrite = true;
   7417   1.3  christos 			qctx->rpz = true;
   7418   1.1  christos 			break;
   7419   1.1  christos 		case DNS_RPZ_POLICY_NODATA:
   7420   1.6  christos 			qctx->nxrewrite = true;
   7421  1.15  christos 			FALLTHROUGH;
   7422   1.6  christos 		case DNS_RPZ_POLICY_DNS64:
   7423   1.1  christos 			result = DNS_R_NXRRSET;
   7424   1.3  christos 			qctx->rpz = true;
   7425   1.1  christos 			break;
   7426   1.1  christos 		case DNS_RPZ_POLICY_RECORD:
   7427   1.1  christos 			result = qctx->rpz_st->m.result;
   7428   1.1  christos 			if (qctx->qtype == dns_rdatatype_any &&
   7429  1.16  christos 			    result != DNS_R_CNAME)
   7430  1.16  christos 			{
   7431   1.1  christos 				/*
   7432   1.1  christos 				 * We will add all of the rdatasets of
   7433   1.1  christos 				 * the node by iterating later,
   7434   1.1  christos 				 * and set the TTL then.
   7435   1.1  christos 				 */
   7436   1.9  christos 				if (dns_rdataset_isassociated(qctx->rdataset)) {
   7437   1.9  christos 					dns_rdataset_disassociate(
   7438   1.9  christos 						qctx->rdataset);
   7439   1.9  christos 				}
   7440   1.1  christos 			} else {
   7441   1.1  christos 				/*
   7442   1.1  christos 				 * We will add this rdataset.
   7443   1.1  christos 				 */
   7444   1.1  christos 				qctx->rdataset->ttl =
   7445   1.1  christos 					ISC_MIN(qctx->rdataset->ttl,
   7446   1.1  christos 						qctx->rpz_st->m.ttl);
   7447   1.1  christos 			}
   7448   1.3  christos 			qctx->rpz = true;
   7449   1.1  christos 			break;
   7450   1.1  christos 		case DNS_RPZ_POLICY_WILDCNAME: {
   7451   1.1  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   7452   1.1  christos 			dns_rdata_cname_t cname;
   7453   1.1  christos 			result = dns_rdataset_first(qctx->rdataset);
   7454   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7455   1.1  christos 			dns_rdataset_current(qctx->rdataset, &rdata);
   7456   1.9  christos 			result = dns_rdata_tostruct(&rdata, &cname, NULL);
   7457   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7458   1.1  christos 			dns_rdata_reset(&rdata);
   7459  1.26  christos 
   7460  1.26  christos 			query_rpz_add_ede(qctx);
   7461   1.1  christos 			result = query_rpzcname(qctx, &cname.cname);
   7462   1.9  christos 			if (result != ISC_R_SUCCESS) {
   7463  1.23  christos 				return ISC_R_COMPLETE;
   7464   1.9  christos 			}
   7465   1.1  christos 			qctx->fname = NULL;
   7466   1.3  christos 			qctx->want_restart = true;
   7467  1.23  christos 			return ISC_R_COMPLETE;
   7468   1.1  christos 		}
   7469   1.1  christos 		case DNS_RPZ_POLICY_CNAME:
   7470   1.1  christos 			/*
   7471   1.9  christos 			 * Add overriding CNAME from a named.conf
   7472   1.1  christos 			 * response-policy statement
   7473   1.1  christos 			 */
   7474  1.26  christos 			query_rpz_add_ede(qctx);
   7475   1.1  christos 			result = query_rpzcname(qctx,
   7476   1.1  christos 						&qctx->rpz_st->m.rpz->cname);
   7477   1.9  christos 			if (result != ISC_R_SUCCESS) {
   7478  1.23  christos 				return ISC_R_COMPLETE;
   7479   1.9  christos 			}
   7480   1.1  christos 			qctx->fname = NULL;
   7481   1.3  christos 			qctx->want_restart = true;
   7482  1.23  christos 			return ISC_R_COMPLETE;
   7483   1.1  christos 		default:
   7484  1.15  christos 			UNREACHABLE();
   7485   1.1  christos 		}
   7486   1.1  christos 
   7487  1.26  christos 		query_rpz_add_ede(qctx);
   7488  1.23  christos 
   7489   1.1  christos 		/*
   7490   1.1  christos 		 * Turn off DNSSEC because the results of a
   7491   1.1  christos 		 * response policy zone cannot verify.
   7492   1.1  christos 		 */
   7493   1.1  christos 		qctx->client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC |
   7494   1.1  christos 					      NS_CLIENTATTR_WANTAD);
   7495   1.1  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
   7496   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   7497   1.1  christos 		qctx->rpz_st->q.is_zone = qctx->is_zone;
   7498   1.3  christos 		qctx->is_zone = true;
   7499   1.9  christos 		rpz_log_rewrite(qctx->client, false, qctx->rpz_st->m.policy,
   7500   1.1  christos 				qctx->rpz_st->m.type, qctx->zone,
   7501   1.1  christos 				qctx->rpz_st->p_name, NULL,
   7502   1.1  christos 				qctx->rpz_st->m.rpz->num);
   7503   1.1  christos 	}
   7504   1.1  christos 
   7505  1.23  christos 	return result;
   7506   1.1  christos }
   7507   1.1  christos 
   7508   1.1  christos /*%
   7509   1.1  christos  * Add a CNAME to a query response, including translating foo.evil.com and
   7510   1.1  christos  *	*.evil.com CNAME *.example.com
   7511   1.1  christos  * to
   7512   1.1  christos  *	foo.evil.com CNAME foo.evil.com.example.com
   7513   1.1  christos  */
   7514   1.1  christos static isc_result_t
   7515   1.1  christos query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) {
   7516   1.6  christos 	ns_client_t *client;
   7517   1.1  christos 	dns_fixedname_t prefix, suffix;
   7518   1.1  christos 	unsigned int labels;
   7519   1.1  christos 	isc_result_t result;
   7520   1.1  christos 
   7521   1.6  christos 	REQUIRE(qctx != NULL && qctx->client != NULL);
   7522   1.6  christos 
   7523   1.6  christos 	client = qctx->client;
   7524   1.6  christos 
   7525   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_rpzcname");
   7526   1.1  christos 
   7527   1.1  christos 	labels = dns_name_countlabels(cname);
   7528   1.1  christos 	if (labels > 2 && dns_name_iswildcard(cname)) {
   7529   1.1  christos 		dns_fixedname_init(&prefix);
   7530   1.1  christos 		dns_name_split(client->query.qname, 1,
   7531   1.1  christos 			       dns_fixedname_name(&prefix), NULL);
   7532   1.1  christos 		dns_fixedname_init(&suffix);
   7533   1.9  christos 		dns_name_split(cname, labels - 1, NULL,
   7534   1.9  christos 			       dns_fixedname_name(&suffix));
   7535   1.1  christos 		result = dns_name_concatenate(dns_fixedname_name(&prefix),
   7536   1.1  christos 					      dns_fixedname_name(&suffix),
   7537   1.1  christos 					      qctx->fname, NULL);
   7538   1.1  christos 		if (result == DNS_R_NAMETOOLONG) {
   7539   1.1  christos 			client->message->rcode = dns_rcode_yxdomain;
   7540   1.1  christos 		} else if (result != ISC_R_SUCCESS) {
   7541  1.23  christos 			return result;
   7542   1.1  christos 		}
   7543   1.1  christos 	} else {
   7544  1.20  christos 		dns_name_copy(cname, qctx->fname);
   7545   1.1  christos 	}
   7546   1.1  christos 
   7547   1.3  christos 	ns_client_keepname(client, qctx->fname, qctx->dbuf);
   7548  1.23  christos 	query_addcname(qctx, dns_trust_authanswer, qctx->rpz_st->m.ttl);
   7549   1.1  christos 
   7550   1.3  christos 	rpz_log_rewrite(client, false, qctx->rpz_st->m.policy,
   7551   1.1  christos 			qctx->rpz_st->m.type, qctx->rpz_st->m.zone,
   7552   1.1  christos 			qctx->rpz_st->p_name, qctx->fname,
   7553   1.1  christos 			qctx->rpz_st->m.rpz->num);
   7554   1.1  christos 
   7555   1.1  christos 	ns_client_qnamereplace(client, qctx->fname);
   7556   1.1  christos 
   7557   1.1  christos 	/*
   7558   1.1  christos 	 * Turn off DNSSEC because the results of a
   7559   1.1  christos 	 * response policy zone cannot verify.
   7560   1.1  christos 	 */
   7561   1.1  christos 	client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC |
   7562   1.1  christos 				NS_CLIENTATTR_WANTAD);
   7563   1.1  christos 
   7564  1.23  christos 	return ISC_R_SUCCESS;
   7565   1.1  christos }
   7566   1.1  christos 
   7567   1.1  christos /*%
   7568   1.1  christos  * Check the configured trust anchors for a root zone trust anchor
   7569   1.1  christos  * with a key id that matches qctx->client->query.root_key_sentinel_keyid.
   7570   1.1  christos  *
   7571   1.3  christos  * Return true when found, otherwise return false.
   7572   1.1  christos  */
   7573   1.3  christos static bool
   7574   1.1  christos has_ta(query_ctx_t *qctx) {
   7575   1.1  christos 	dns_keytable_t *keytable = NULL;
   7576   1.1  christos 	dns_keynode_t *keynode = NULL;
   7577  1.10  christos 	dns_rdataset_t dsset;
   7578   1.9  christos 	dns_keytag_t sentinel = qctx->client->query.root_key_sentinel_keyid;
   7579   1.1  christos 	isc_result_t result;
   7580   1.1  christos 
   7581   1.3  christos 	result = dns_view_getsecroots(qctx->view, &keytable);
   7582   1.1  christos 	if (result != ISC_R_SUCCESS) {
   7583  1.23  christos 		return false;
   7584   1.1  christos 	}
   7585   1.1  christos 
   7586   1.1  christos 	result = dns_keytable_find(keytable, dns_rootname, &keynode);
   7587   1.9  christos 	if (result != ISC_R_SUCCESS) {
   7588   1.9  christos 		if (keynode != NULL) {
   7589  1.23  christos 			dns_keynode_detach(&keynode);
   7590   1.1  christos 		}
   7591   1.9  christos 		dns_keytable_detach(&keytable);
   7592  1.23  christos 		return false;
   7593   1.9  christos 	}
   7594   1.9  christos 
   7595  1.10  christos 	dns_rdataset_init(&dsset);
   7596  1.10  christos 	if (dns_keynode_dsset(keynode, &dsset)) {
   7597  1.10  christos 		for (result = dns_rdataset_first(&dsset);
   7598  1.10  christos 		     result == ISC_R_SUCCESS;
   7599  1.10  christos 		     result = dns_rdataset_next(&dsset))
   7600   1.9  christos 		{
   7601   1.9  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   7602   1.9  christos 			dns_rdata_ds_t ds;
   7603   1.9  christos 
   7604   1.9  christos 			dns_rdata_reset(&rdata);
   7605  1.10  christos 			dns_rdataset_current(&dsset, &rdata);
   7606   1.9  christos 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
   7607   1.9  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7608   1.9  christos 			if (ds.key_tag == sentinel) {
   7609  1.23  christos 				dns_keynode_detach(&keynode);
   7610   1.9  christos 				dns_keytable_detach(&keytable);
   7611  1.10  christos 				dns_rdataset_disassociate(&dsset);
   7612  1.23  christos 				return true;
   7613   1.9  christos 			}
   7614   1.9  christos 		}
   7615  1.10  christos 		dns_rdataset_disassociate(&dsset);
   7616   1.9  christos 	}
   7617   1.9  christos 
   7618   1.9  christos 	if (keynode != NULL) {
   7619  1.23  christos 		dns_keynode_detach(&keynode);
   7620   1.1  christos 	}
   7621   1.9  christos 
   7622   1.1  christos 	dns_keytable_detach(&keytable);
   7623   1.1  christos 
   7624  1.23  christos 	return false;
   7625   1.1  christos }
   7626   1.1  christos 
   7627   1.1  christos /*%
   7628   1.1  christos  * Check if a root key sentinel SERVFAIL should be returned.
   7629   1.1  christos  */
   7630   1.3  christos static bool
   7631   1.1  christos root_key_sentinel_return_servfail(query_ctx_t *qctx, isc_result_t result) {
   7632   1.1  christos 	/*
   7633   1.1  christos 	 * Are we looking at a "root-key-sentinel" query?
   7634   1.1  christos 	 */
   7635   1.1  christos 	if (!qctx->client->query.root_key_sentinel_is_ta &&
   7636   1.1  christos 	    !qctx->client->query.root_key_sentinel_not_ta)
   7637   1.1  christos 	{
   7638  1.23  christos 		return false;
   7639   1.1  christos 	}
   7640   1.1  christos 
   7641   1.1  christos 	/*
   7642   1.1  christos 	 * We only care about the query if 'result' indicates we have a cached
   7643   1.1  christos 	 * answer.
   7644   1.1  christos 	 */
   7645   1.1  christos 	switch (result) {
   7646   1.1  christos 	case ISC_R_SUCCESS:
   7647   1.1  christos 	case DNS_R_CNAME:
   7648   1.1  christos 	case DNS_R_DNAME:
   7649   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   7650   1.1  christos 	case DNS_R_NCACHENXRRSET:
   7651   1.1  christos 		break;
   7652   1.1  christos 	default:
   7653  1.23  christos 		return false;
   7654   1.1  christos 	}
   7655   1.1  christos 
   7656   1.1  christos 	/*
   7657   1.1  christos 	 * Do we meet the specified conditions to return SERVFAIL?
   7658   1.1  christos 	 */
   7659   1.9  christos 	if (!qctx->is_zone && qctx->rdataset->trust == dns_trust_secure &&
   7660   1.1  christos 	    ((qctx->client->query.root_key_sentinel_is_ta && !has_ta(qctx)) ||
   7661   1.1  christos 	     (qctx->client->query.root_key_sentinel_not_ta && has_ta(qctx))))
   7662   1.1  christos 	{
   7663  1.23  christos 		return true;
   7664   1.1  christos 	}
   7665   1.1  christos 
   7666   1.1  christos 	/*
   7667   1.1  christos 	 * As special processing may only be triggered by the original QNAME,
   7668   1.1  christos 	 * disable it after following a CNAME/DNAME.
   7669   1.1  christos 	 */
   7670   1.3  christos 	qctx->client->query.root_key_sentinel_is_ta = false;
   7671   1.3  christos 	qctx->client->query.root_key_sentinel_not_ta = false;
   7672   1.1  christos 
   7673  1.23  christos 	return false;
   7674   1.1  christos }
   7675   1.1  christos 
   7676   1.1  christos /*%
   7677   1.3  christos  * If serving stale answers is allowed, set up 'qctx' to look for one and
   7678   1.3  christos  * return true; otherwise, return false.
   7679   1.3  christos  */
   7680   1.3  christos static bool
   7681  1.13  christos query_usestale(query_ctx_t *qctx, isc_result_t result) {
   7682  1.13  christos 	if ((qctx->client->query.dboptions & DNS_DBFIND_STALEOK) != 0) {
   7683  1.13  christos 		/*
   7684  1.13  christos 		 * Query was already using stale, if that didn't work the
   7685  1.13  christos 		 * last time, it won't work this time either.
   7686  1.13  christos 		 */
   7687  1.23  christos 		return false;
   7688  1.17  christos 	}
   7689  1.17  christos 
   7690  1.23  christos 	if (result == DNS_R_DUPLICATE || result == DNS_R_DROP) {
   7691  1.15  christos 		/*
   7692  1.15  christos 		 * Don't enable serve-stale if the result signals a duplicate
   7693  1.23  christos 		 * query or query that is being dropped.
   7694  1.15  christos 		 */
   7695  1.23  christos 		return false;
   7696  1.15  christos 	}
   7697  1.15  christos 
   7698   1.3  christos 	qctx_clean(qctx);
   7699   1.3  christos 	qctx_freedata(qctx);
   7700   1.3  christos 
   7701  1.11  christos 	if (dns_view_staleanswerenabled(qctx->client->view)) {
   7702  1.20  christos 		isc_result_t ret;
   7703  1.20  christos 		ret = query_getdb(qctx->client, qctx->client->query.qname,
   7704  1.20  christos 				  qctx->client->query.qtype, qctx->options,
   7705  1.20  christos 				  &qctx->zone, &qctx->db, &qctx->version,
   7706  1.20  christos 				  &qctx->is_zone);
   7707  1.20  christos 		if (ret != ISC_R_SUCCESS) {
   7708  1.20  christos 			/*
   7709  1.20  christos 			 * Failed to get the database, unexpected, but let us
   7710  1.20  christos 			 * at least abandon serve-stale.
   7711  1.20  christos 			 */
   7712  1.23  christos 			return false;
   7713  1.20  christos 		}
   7714  1.20  christos 
   7715   1.3  christos 		qctx->client->query.dboptions |= DNS_DBFIND_STALEOK;
   7716  1.23  christos 		if (FETCH_RECTYPE_NORMAL(qctx->client) != NULL) {
   7717  1.23  christos 			dns_resolver_destroyfetch(
   7718  1.23  christos 				&FETCH_RECTYPE_NORMAL(qctx->client));
   7719   1.3  christos 		}
   7720  1.11  christos 
   7721  1.13  christos 		/*
   7722  1.13  christos 		 * Start the stale-refresh-time window in case there was a
   7723  1.13  christos 		 * resolver query timeout.
   7724  1.13  christos 		 */
   7725  1.13  christos 		if (qctx->resuming && result == ISC_R_TIMEDOUT) {
   7726  1.13  christos 			qctx->client->query.dboptions |= DNS_DBFIND_STALESTART;
   7727  1.13  christos 		}
   7728  1.23  christos 		return true;
   7729   1.3  christos 	}
   7730   1.3  christos 
   7731  1.23  christos 	return false;
   7732   1.3  christos }
   7733   1.3  christos 
   7734   1.3  christos /*%
   7735   1.3  christos  * Continue after doing a database lookup or returning from
   7736   1.3  christos  * recursion, and call out to the next function depending on the
   7737   1.3  christos  * result from the search.
   7738   1.1  christos  */
   7739   1.1  christos static isc_result_t
   7740  1.18  christos query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
   7741   1.1  christos 	char errmsg[256];
   7742   1.1  christos 
   7743   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer");
   7744   1.1  christos 
   7745   1.3  christos 	CALL_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx);
   7746   1.3  christos 
   7747   1.1  christos 	if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) {
   7748  1.23  christos 		return ns_query_done(qctx);
   7749   1.1  christos 	}
   7750   1.1  christos 
   7751  1.13  christos 	if (!dns_name_equal(qctx->client->query.qname, dns_rootname)) {
   7752   1.1  christos 		result = query_checkrpz(qctx, result);
   7753  1.13  christos 		if (result == ISC_R_NOTFOUND) {
   7754  1.13  christos 			/*
   7755  1.13  christos 			 * RPZ not configured for this view.
   7756  1.13  christos 			 */
   7757  1.13  christos 			goto root_key_sentinel;
   7758  1.13  christos 		}
   7759  1.13  christos 		if (RECURSING(qctx->client) && result == DNS_R_DISALLOWED) {
   7760  1.13  christos 			/*
   7761  1.13  christos 			 * We are recursing, and thus RPZ processing is not
   7762  1.13  christos 			 * allowed at the moment. This could happen on a
   7763  1.13  christos 			 * "stale-answer-client-timeout" lookup. In this case,
   7764  1.13  christos 			 * bail out and wait for recursion to complete, as we
   7765  1.13  christos 			 * we can't perform the RPZ rewrite rules.
   7766  1.13  christos 			 */
   7767  1.23  christos 			return result;
   7768  1.13  christos 		}
   7769   1.3  christos 		if (result == ISC_R_COMPLETE) {
   7770  1.23  christos 			return ns_query_done(qctx);
   7771   1.3  christos 		}
   7772   1.1  christos 	}
   7773   1.1  christos 
   7774  1.13  christos root_key_sentinel:
   7775   1.1  christos 	/*
   7776   1.1  christos 	 * If required, handle special "root-key-sentinel-is-ta-<keyid>" and
   7777   1.1  christos 	 * "root-key-sentinel-not-ta-<keyid>" labels by returning SERVFAIL.
   7778   1.1  christos 	 */
   7779   1.1  christos 	if (root_key_sentinel_return_servfail(qctx, result)) {
   7780   1.1  christos 		/*
   7781   1.1  christos 		 * Don't record this response in the SERVFAIL cache.
   7782   1.1  christos 		 */
   7783   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
   7784   1.1  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   7785  1.23  christos 		return ns_query_done(qctx);
   7786   1.1  christos 	}
   7787   1.1  christos 
   7788   1.1  christos 	switch (result) {
   7789   1.1  christos 	case ISC_R_SUCCESS:
   7790  1.23  christos 		return query_prepresponse(qctx);
   7791   1.1  christos 
   7792   1.1  christos 	case DNS_R_GLUE:
   7793   1.1  christos 	case DNS_R_ZONECUT:
   7794   1.1  christos 		INSIST(qctx->is_zone);
   7795   1.3  christos 		qctx->authoritative = false;
   7796  1.23  christos 		return query_prepresponse(qctx);
   7797   1.1  christos 
   7798   1.1  christos 	case ISC_R_NOTFOUND:
   7799  1.23  christos 		return query_notfound(qctx);
   7800   1.1  christos 
   7801   1.1  christos 	case DNS_R_DELEGATION:
   7802  1.23  christos 		return query_delegation(qctx);
   7803   1.1  christos 
   7804   1.1  christos 	case DNS_R_EMPTYNAME:
   7805   1.1  christos 	case DNS_R_NXRRSET:
   7806  1.23  christos 		return query_nodata(qctx, result);
   7807   1.1  christos 
   7808   1.1  christos 	case DNS_R_EMPTYWILD:
   7809   1.1  christos 	case DNS_R_NXDOMAIN:
   7810  1.23  christos 		return query_nxdomain(qctx, result);
   7811   1.1  christos 
   7812   1.1  christos 	case DNS_R_COVERINGNSEC:
   7813  1.23  christos 		return query_coveringnsec(qctx);
   7814   1.1  christos 
   7815   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   7816  1.18  christos 		result = query_redirect(qctx, result);
   7817   1.9  christos 		if (result != ISC_R_COMPLETE) {
   7818  1.23  christos 			return result;
   7819   1.9  christos 		}
   7820  1.23  christos 		return query_ncache(qctx, DNS_R_NCACHENXDOMAIN);
   7821   1.1  christos 
   7822   1.1  christos 	case DNS_R_NCACHENXRRSET:
   7823  1.23  christos 		return query_ncache(qctx, DNS_R_NCACHENXRRSET);
   7824   1.1  christos 
   7825   1.1  christos 	case DNS_R_CNAME:
   7826  1.23  christos 		return query_cname(qctx);
   7827   1.1  christos 
   7828   1.1  christos 	case DNS_R_DNAME:
   7829  1.23  christos 		return query_dname(qctx);
   7830   1.1  christos 
   7831   1.1  christos 	default:
   7832   1.1  christos 		/*
   7833   1.1  christos 		 * Something has gone wrong.
   7834   1.1  christos 		 */
   7835   1.1  christos 		snprintf(errmsg, sizeof(errmsg) - 1,
   7836   1.1  christos 			 "query_gotanswer: unexpected error: %s",
   7837   1.1  christos 			 isc_result_totext(result));
   7838   1.1  christos 		CCTRACE(ISC_LOG_ERROR, errmsg);
   7839  1.13  christos 		if (query_usestale(qctx, result)) {
   7840   1.3  christos 			/*
   7841   1.3  christos 			 * If serve-stale is enabled, query_usestale() already
   7842   1.3  christos 			 * set up 'qctx' for looking up a stale response.
   7843   1.3  christos 			 */
   7844  1.23  christos 			return query_lookup(qctx);
   7845   1.1  christos 		}
   7846   1.6  christos 
   7847   1.6  christos 		/*
   7848   1.6  christos 		 * Regardless of the triggering result, we definitely
   7849   1.6  christos 		 * want to return SERVFAIL from here.
   7850   1.6  christos 		 */
   7851   1.6  christos 		qctx->client->rcode_override = dns_rcode_servfail;
   7852   1.6  christos 
   7853   1.3  christos 		QUERY_ERROR(qctx, result);
   7854  1.23  christos 		return ns_query_done(qctx);
   7855   1.1  christos 	}
   7856   1.3  christos 
   7857   1.9  christos cleanup:
   7858  1.23  christos 	return result;
   7859   1.1  christos }
   7860   1.1  christos 
   7861   1.1  christos static void
   7862   1.1  christos query_addnoqnameproof(query_ctx_t *qctx) {
   7863   1.1  christos 	ns_client_t *client = qctx->client;
   7864   1.1  christos 	isc_buffer_t *dbuf, b;
   7865   1.1  christos 	dns_name_t *fname = NULL;
   7866   1.1  christos 	dns_rdataset_t *neg = NULL, *negsig = NULL;
   7867   1.1  christos 	isc_result_t result = ISC_R_NOMEMORY;
   7868   1.1  christos 
   7869   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addnoqnameproof");
   7870   1.1  christos 
   7871   1.1  christos 	if (qctx->noqname == NULL) {
   7872   1.1  christos 		return;
   7873   1.1  christos 	}
   7874   1.1  christos 
   7875   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   7876   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   7877   1.3  christos 	neg = ns_client_newrdataset(client);
   7878   1.3  christos 	negsig = ns_client_newrdataset(client);
   7879   1.1  christos 
   7880   1.1  christos 	result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig);
   7881   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7882   1.1  christos 
   7883   1.3  christos 	query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
   7884   1.1  christos 		       DNS_SECTION_AUTHORITY);
   7885   1.1  christos 
   7886   1.1  christos 	if ((qctx->noqname->attributes & DNS_RDATASETATTR_CLOSEST) == 0) {
   7887   1.1  christos 		goto cleanup;
   7888   1.1  christos 	}
   7889   1.1  christos 
   7890   1.1  christos 	if (fname == NULL) {
   7891   1.3  christos 		dbuf = ns_client_getnamebuf(client);
   7892   1.3  christos 		fname = ns_client_newname(client, dbuf, &b);
   7893   1.1  christos 	}
   7894   1.1  christos 
   7895   1.1  christos 	if (neg == NULL) {
   7896   1.3  christos 		neg = ns_client_newrdataset(client);
   7897   1.1  christos 	} else if (dns_rdataset_isassociated(neg)) {
   7898   1.1  christos 		dns_rdataset_disassociate(neg);
   7899   1.1  christos 	}
   7900   1.1  christos 
   7901   1.1  christos 	if (negsig == NULL) {
   7902   1.3  christos 		negsig = ns_client_newrdataset(client);
   7903   1.1  christos 	} else if (dns_rdataset_isassociated(negsig)) {
   7904   1.1  christos 		dns_rdataset_disassociate(negsig);
   7905   1.1  christos 	}
   7906   1.1  christos 
   7907   1.1  christos 	result = dns_rdataset_getclosest(qctx->noqname, fname, neg, negsig);
   7908   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7909   1.1  christos 
   7910   1.3  christos 	query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
   7911   1.1  christos 		       DNS_SECTION_AUTHORITY);
   7912   1.1  christos 
   7913   1.9  christos cleanup:
   7914   1.1  christos 	if (neg != NULL) {
   7915   1.3  christos 		ns_client_putrdataset(client, &neg);
   7916   1.1  christos 	}
   7917   1.1  christos 	if (negsig != NULL) {
   7918   1.3  christos 		ns_client_putrdataset(client, &negsig);
   7919   1.1  christos 	}
   7920   1.1  christos 	if (fname != NULL) {
   7921   1.3  christos 		ns_client_releasename(client, &fname);
   7922   1.1  christos 	}
   7923   1.1  christos }
   7924   1.1  christos 
   7925   1.1  christos /*%
   7926   1.1  christos  * Build the response for a query for type ANY.
   7927   1.1  christos  */
   7928   1.1  christos static isc_result_t
   7929   1.1  christos query_respond_any(query_ctx_t *qctx) {
   7930   1.5  christos 	bool found = false, hidden = false;
   7931   1.1  christos 	dns_rdatasetiter_t *rdsiter = NULL;
   7932  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   7933   1.9  christos 	dns_rdatatype_t onetype = 0; /* type to use for minimal-any */
   7934   1.3  christos 	isc_buffer_t b;
   7935   1.1  christos 
   7936   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_respond_any");
   7937   1.9  christos 
   7938   1.3  christos 	CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx);
   7939   1.1  christos 
   7940  1.16  christos 	result = dns_db_allrdatasets(qctx->db, qctx->node, qctx->version, 0, 0,
   7941   1.9  christos 				     &rdsiter);
   7942   1.1  christos 	if (result != ISC_R_SUCCESS) {
   7943   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_respond_any: allrdatasets "
   7944   1.9  christos 				       "failed");
   7945   1.3  christos 		QUERY_ERROR(qctx, result);
   7946  1.23  christos 		return ns_query_done(qctx);
   7947   1.1  christos 	}
   7948   1.1  christos 
   7949   1.1  christos 	/*
   7950   1.1  christos 	 * Calling query_addrrset() with a non-NULL dbuf is going
   7951   1.1  christos 	 * to either keep or release the name.  We don't want it to
   7952   1.1  christos 	 * release fname, since we may have to call query_addrrset()
   7953   1.3  christos 	 * more than once.  That means we have to call ns_client_keepname()
   7954   1.1  christos 	 * now, and pass a NULL dbuf to query_addrrset().
   7955   1.1  christos 	 *
   7956   1.1  christos 	 * If we do a query_addrrset() below, we must set qctx->fname to
   7957   1.1  christos 	 * NULL before leaving this block, otherwise we might try to
   7958   1.1  christos 	 * cleanup qctx->fname even though we're using it!
   7959   1.1  christos 	 */
   7960   1.3  christos 	ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   7961   1.3  christos 	qctx->tname = qctx->fname;
   7962   1.1  christos 
   7963   1.1  christos 	result = dns_rdatasetiter_first(rdsiter);
   7964   1.1  christos 	while (result == ISC_R_SUCCESS) {
   7965   1.1  christos 		dns_rdatasetiter_current(rdsiter, qctx->rdataset);
   7966   1.1  christos 
   7967   1.1  christos 		/*
   7968   1.1  christos 		 * We found an NS RRset; no need to add one later.
   7969   1.1  christos 		 */
   7970   1.1  christos 		if (qctx->qtype == dns_rdatatype_any &&
   7971   1.1  christos 		    qctx->rdataset->type == dns_rdatatype_ns)
   7972   1.1  christos 		{
   7973   1.3  christos 			qctx->answer_has_ns = true;
   7974   1.1  christos 		}
   7975   1.1  christos 
   7976   1.1  christos 		/*
   7977   1.1  christos 		 * Note: if we're in this function, then qctx->type
   7978   1.1  christos 		 * is guaranteed to be ANY, but qctx->qtype (i.e. the
   7979   1.1  christos 		 * original type requested) might have been RRSIG or
   7980   1.1  christos 		 * SIG; we need to check for that.
   7981   1.1  christos 		 */
   7982   1.1  christos 		if (qctx->is_zone && qctx->qtype == dns_rdatatype_any &&
   7983   1.1  christos 		    !dns_db_issecure(qctx->db) &&
   7984   1.1  christos 		    dns_rdatatype_isdnssec(qctx->rdataset->type))
   7985   1.1  christos 		{
   7986   1.1  christos 			/*
   7987   1.5  christos 			 * The zone may be transitioning from insecure
   7988   1.5  christos 			 * to secure. Hide DNSSEC records from ANY queries.
   7989   1.1  christos 			 */
   7990   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   7991   1.5  christos 			hidden = true;
   7992   1.9  christos 		} else if (qctx->view->minimal_any && !TCP(qctx->client) &&
   7993   1.9  christos 			   !WANTDNSSEC(qctx->client) &&
   7994   1.1  christos 			   qctx->qtype == dns_rdatatype_any &&
   7995   1.1  christos 			   (qctx->rdataset->type == dns_rdatatype_sig ||
   7996   1.1  christos 			    qctx->rdataset->type == dns_rdatatype_rrsig))
   7997   1.1  christos 		{
   7998   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
   7999   1.9  christos 						  "minimal-any skip signature");
   8000   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   8001   1.9  christos 		} else if (qctx->view->minimal_any && !TCP(qctx->client) &&
   8002   1.9  christos 			   onetype != 0 && qctx->rdataset->type != onetype &&
   8003   1.1  christos 			   qctx->rdataset->covers != onetype)
   8004   1.1  christos 		{
   8005   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
   8006   1.9  christos 						  "minimal-any skip rdataset");
   8007   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   8008   1.1  christos 		} else if ((qctx->qtype == dns_rdatatype_any ||
   8009   1.1  christos 			    qctx->rdataset->type == qctx->qtype) &&
   8010   1.1  christos 			   qctx->rdataset->type != 0)
   8011   1.1  christos 		{
   8012   1.9  christos 			if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client))
   8013   1.1  christos 			{
   8014   1.1  christos 				qctx->noqname = qctx->rdataset;
   8015   1.1  christos 			} else {
   8016   1.1  christos 				qctx->noqname = NULL;
   8017   1.1  christos 			}
   8018   1.1  christos 
   8019   1.1  christos 			qctx->rpz_st = qctx->client->query.rpz_st;
   8020  1.24  christos 			if (qctx->rpz_st != NULL &&
   8021  1.24  christos 			    qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS &&
   8022  1.24  christos 			    qctx->rpz_st->m.policy != DNS_RPZ_POLICY_PASSTHRU)
   8023  1.24  christos 			{
   8024   1.1  christos 				qctx->rdataset->ttl =
   8025   1.1  christos 					ISC_MIN(qctx->rdataset->ttl,
   8026   1.1  christos 						qctx->rpz_st->m.ttl);
   8027   1.9  christos 			}
   8028   1.1  christos 
   8029   1.1  christos 			if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   8030   1.1  christos 				dns_name_t *name;
   8031   1.9  christos 				name = (qctx->fname != NULL) ? qctx->fname
   8032   1.9  christos 							     : qctx->tname;
   8033   1.1  christos 				query_prefetch(qctx->client, name,
   8034   1.1  christos 					       qctx->rdataset);
   8035   1.1  christos 			}
   8036   1.1  christos 
   8037   1.1  christos 			/*
   8038   1.1  christos 			 * Remember the first RRtype we find so we
   8039   1.1  christos 			 * can skip others with minimal-any.
   8040   1.1  christos 			 */
   8041   1.1  christos 			if (qctx->rdataset->type == dns_rdatatype_sig ||
   8042   1.1  christos 			    qctx->rdataset->type == dns_rdatatype_rrsig)
   8043   1.3  christos 			{
   8044   1.1  christos 				onetype = qctx->rdataset->covers;
   8045   1.3  christos 			} else {
   8046   1.1  christos 				onetype = qctx->rdataset->type;
   8047   1.3  christos 			}
   8048   1.1  christos 
   8049   1.3  christos 			query_addrrset(qctx,
   8050   1.9  christos 				       (qctx->fname != NULL) ? &qctx->fname
   8051   1.9  christos 							     : &qctx->tname,
   8052   1.9  christos 				       &qctx->rdataset, NULL, NULL,
   8053   1.9  christos 				       DNS_SECTION_ANSWER);
   8054   1.1  christos 
   8055   1.1  christos 			query_addnoqnameproof(qctx);
   8056   1.1  christos 
   8057   1.3  christos 			found = true;
   8058   1.3  christos 			INSIST(qctx->tname != NULL);
   8059   1.1  christos 
   8060   1.1  christos 			/*
   8061   1.1  christos 			 * rdataset is non-NULL only in certain
   8062   1.1  christos 			 * pathological cases involving DNAMEs.
   8063   1.1  christos 			 */
   8064   1.3  christos 			if (qctx->rdataset != NULL) {
   8065   1.3  christos 				ns_client_putrdataset(qctx->client,
   8066   1.3  christos 						      &qctx->rdataset);
   8067   1.3  christos 			}
   8068   1.1  christos 
   8069   1.3  christos 			qctx->rdataset = ns_client_newrdataset(qctx->client);
   8070   1.1  christos 		} else {
   8071   1.1  christos 			/*
   8072   1.1  christos 			 * We're not interested in this rdataset.
   8073   1.1  christos 			 */
   8074   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   8075   1.1  christos 		}
   8076   1.1  christos 
   8077   1.1  christos 		result = dns_rdatasetiter_next(rdsiter);
   8078   1.1  christos 	}
   8079   1.1  christos 
   8080   1.3  christos 	dns_rdatasetiter_destroy(&rdsiter);
   8081   1.3  christos 
   8082   1.3  christos 	if (result != ISC_R_NOMORE) {
   8083   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_respond_any: rdataset iterator "
   8084   1.9  christos 				       "failed");
   8085   1.3  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   8086  1.23  christos 		return ns_query_done(qctx);
   8087   1.3  christos 	}
   8088   1.3  christos 
   8089   1.3  christos 	if (found) {
   8090   1.5  christos 		/*
   8091   1.5  christos 		 * Call hook if any answers were found.
   8092   1.5  christos 		 * Do this before releasing qctx->fname, in case
   8093   1.5  christos 		 * the hook function needs it.
   8094   1.5  christos 		 */
   8095   1.3  christos 		CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx);
   8096   1.3  christos 	}
   8097   1.3  christos 
   8098   1.3  christos 	if (qctx->fname != NULL) {
   8099   1.5  christos 		dns_message_puttempname(qctx->client->message, &qctx->fname);
   8100   1.1  christos 	}
   8101   1.1  christos 
   8102   1.5  christos 	if (found) {
   8103   1.5  christos 		/*
   8104   1.5  christos 		 * At least one matching rdataset was found
   8105   1.5  christos 		 */
   8106   1.1  christos 		query_addauth(qctx);
   8107   1.5  christos 	} else if (qctx->qtype == dns_rdatatype_rrsig ||
   8108   1.5  christos 		   qctx->qtype == dns_rdatatype_sig)
   8109   1.5  christos 	{
   8110   1.5  christos 		/*
   8111   1.5  christos 		 * No matching rdatasets were found, but we got
   8112   1.5  christos 		 * here on a search for RRSIG/SIG, so that's okay.
   8113   1.5  christos 		 */
   8114   1.5  christos 		if (!qctx->is_zone) {
   8115   1.5  christos 			qctx->authoritative = false;
   8116   1.5  christos 			qctx->client->attributes &= ~NS_CLIENTATTR_RA;
   8117   1.5  christos 			query_addauth(qctx);
   8118  1.23  christos 			return ns_query_done(qctx);
   8119   1.5  christos 		}
   8120   1.5  christos 
   8121   1.5  christos 		if (qctx->qtype == dns_rdatatype_rrsig &&
   8122  1.16  christos 		    dns_db_issecure(qctx->db))
   8123  1.16  christos 		{
   8124   1.5  christos 			char namebuf[DNS_NAME_FORMATSIZE];
   8125   1.9  christos 			dns_name_format(qctx->client->query.qname, namebuf,
   8126   1.9  christos 					sizeof(namebuf));
   8127   1.5  christos 			ns_client_log(qctx->client, DNS_LOGCATEGORY_DNSSEC,
   8128   1.5  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   8129   1.5  christos 				      "missing signature for %s", namebuf);
   8130   1.5  christos 		}
   8131   1.1  christos 
   8132   1.5  christos 		qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   8133  1.23  christos 		return query_sign_nodata(qctx);
   8134   1.5  christos 	} else if (!hidden) {
   8135   1.5  christos 		/*
   8136   1.5  christos 		 * No matching rdatasets were found and nothing was
   8137   1.5  christos 		 * deliberately hidden: something must have gone wrong.
   8138   1.5  christos 		 */
   8139   1.5  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   8140   1.3  christos 	}
   8141   1.3  christos 
   8142  1.23  christos 	return ns_query_done(qctx);
   8143   1.3  christos 
   8144   1.9  christos cleanup:
   8145  1.23  christos 	return result;
   8146   1.1  christos }
   8147   1.1  christos 
   8148   1.1  christos /*
   8149  1.20  christos  * Set the expire time, if requested, when answering from a secondary,
   8150  1.20  christos  * mirror, or primary zone.
   8151   1.1  christos  */
   8152   1.1  christos static void
   8153   1.1  christos query_getexpire(query_ctx_t *qctx) {
   8154   1.1  christos 	dns_zone_t *raw = NULL, *mayberaw;
   8155   1.1  christos 
   8156   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_getexpire");
   8157   1.9  christos 
   8158   1.1  christos 	if (qctx->zone == NULL || !qctx->is_zone ||
   8159   1.1  christos 	    qctx->qtype != dns_rdatatype_soa ||
   8160   1.1  christos 	    qctx->client->query.restarts != 0 ||
   8161   1.1  christos 	    (qctx->client->attributes & NS_CLIENTATTR_WANTEXPIRE) == 0)
   8162   1.1  christos 	{
   8163   1.1  christos 		return;
   8164   1.1  christos 	}
   8165   1.1  christos 
   8166   1.1  christos 	dns_zone_getraw(qctx->zone, &raw);
   8167   1.1  christos 	mayberaw = (raw != NULL) ? raw : qctx->zone;
   8168   1.1  christos 
   8169  1.15  christos 	if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
   8170   1.3  christos 	    dns_zone_gettype(mayberaw) == dns_zone_mirror)
   8171   1.3  christos 	{
   8172   1.1  christos 		isc_time_t expiretime;
   8173   1.3  christos 		uint32_t secs;
   8174   1.1  christos 		dns_zone_getexpiretime(qctx->zone, &expiretime);
   8175   1.1  christos 		secs = isc_time_seconds(&expiretime);
   8176   1.9  christos 		if (secs >= qctx->client->now && qctx->result == ISC_R_SUCCESS)
   8177   1.1  christos 		{
   8178   1.9  christos 			qctx->client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
   8179   1.1  christos 			qctx->client->expire = secs - qctx->client->now;
   8180   1.1  christos 		}
   8181  1.15  christos 	} else if (dns_zone_gettype(mayberaw) == dns_zone_primary) {
   8182   1.1  christos 		isc_result_t result;
   8183   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   8184   1.1  christos 		dns_rdata_soa_t soa;
   8185   1.1  christos 
   8186   1.1  christos 		result = dns_rdataset_first(qctx->rdataset);
   8187   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   8188   1.1  christos 
   8189   1.1  christos 		dns_rdataset_current(qctx->rdataset, &rdata);
   8190   1.1  christos 		result = dns_rdata_tostruct(&rdata, &soa, NULL);
   8191   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   8192   1.1  christos 
   8193   1.1  christos 		qctx->client->expire = soa.expire;
   8194   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
   8195   1.1  christos 	}
   8196   1.1  christos 
   8197   1.1  christos 	if (raw != NULL) {
   8198   1.1  christos 		dns_zone_detach(&raw);
   8199   1.1  christos 	}
   8200   1.1  christos }
   8201   1.1  christos 
   8202   1.3  christos /*%
   8203   1.3  christos  * Fill the ANSWER section of a positive response.
   8204   1.1  christos  */
   8205   1.1  christos static isc_result_t
   8206   1.3  christos query_addanswer(query_ctx_t *qctx) {
   8207   1.3  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   8208  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8209   1.1  christos 
   8210   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_addanswer");
   8211   1.9  christos 
   8212   1.3  christos 	CALL_HOOK(NS_QUERY_ADDANSWER_BEGIN, qctx);
   8213   1.1  christos 
   8214   1.3  christos 	if (qctx->dns64) {
   8215   1.3  christos 		result = query_dns64(qctx);
   8216   1.3  christos 		qctx->noqname = NULL;
   8217   1.3  christos 		dns_rdataset_disassociate(qctx->rdataset);
   8218   1.3  christos 		dns_message_puttemprdataset(qctx->client->message,
   8219   1.3  christos 					    &qctx->rdataset);
   8220   1.3  christos 		if (result == ISC_R_NOMORE) {
   8221   1.3  christos #ifndef dns64_bis_return_excluded_addresses
   8222   1.3  christos 			if (qctx->dns64_exclude) {
   8223   1.9  christos 				if (!qctx->is_zone) {
   8224  1.23  christos 					return ns_query_done(qctx);
   8225   1.9  christos 				}
   8226   1.3  christos 				/*
   8227   1.3  christos 				 * Add a fake SOA record.
   8228   1.3  christos 				 */
   8229   1.3  christos 				(void)query_addsoa(qctx, 600,
   8230   1.3  christos 						   DNS_SECTION_AUTHORITY);
   8231  1.23  christos 				return ns_query_done(qctx);
   8232   1.3  christos 			}
   8233   1.9  christos #endif /* ifndef dns64_bis_return_excluded_addresses */
   8234   1.3  christos 			if (qctx->is_zone) {
   8235  1.23  christos 				return query_nodata(qctx, DNS_R_NXDOMAIN);
   8236   1.3  christos 			} else {
   8237  1.23  christos 				return query_ncache(qctx, DNS_R_NXDOMAIN);
   8238   1.1  christos 			}
   8239   1.3  christos 		} else if (result != ISC_R_SUCCESS) {
   8240   1.3  christos 			qctx->result = result;
   8241  1.23  christos 			return ns_query_done(qctx);
   8242   1.3  christos 		}
   8243   1.3  christos 	} else if (qctx->client->query.dns64_aaaaok != NULL) {
   8244   1.3  christos 		query_filter64(qctx);
   8245   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   8246   1.3  christos 	} else {
   8247  1.26  christos 		if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   8248   1.3  christos 			query_prefetch(qctx->client, qctx->fname,
   8249   1.3  christos 				       qctx->rdataset);
   8250   1.1  christos 		}
   8251   1.3  christos 		if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   8252   1.3  christos 			sigrdatasetp = &qctx->sigrdataset;
   8253   1.3  christos 		}
   8254   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   8255   1.9  christos 			       sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER);
   8256   1.1  christos 	}
   8257   1.1  christos 
   8258  1.23  christos 	return ISC_R_COMPLETE;
   8259   1.3  christos 
   8260   1.9  christos cleanup:
   8261  1.23  christos 	return result;
   8262   1.1  christos }
   8263   1.1  christos 
   8264   1.1  christos /*%
   8265   1.9  christos  * Build a response for a "normal" query, for a type other than ANY,
   8266   1.1  christos  * for which we have an answer (either positive or negative).
   8267   1.1  christos  */
   8268   1.1  christos static isc_result_t
   8269   1.1  christos query_respond(query_ctx_t *qctx) {
   8270  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8271   1.1  christos 
   8272   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_respond");
   8273   1.9  christos 
   8274   1.1  christos 	/*
   8275   1.1  christos 	 * Check to see if the AAAA RRset has non-excluded addresses
   8276   1.1  christos 	 * in it.  If not look for a A RRset.
   8277   1.1  christos 	 */
   8278   1.1  christos 	INSIST(qctx->client->query.dns64_aaaaok == NULL);
   8279   1.1  christos 
   8280   1.1  christos 	if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude &&
   8281   1.3  christos 	    !ISC_LIST_EMPTY(qctx->view->dns64) &&
   8282   1.1  christos 	    qctx->client->message->rdclass == dns_rdataclass_in &&
   8283   1.1  christos 	    !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset))
   8284   1.1  christos 	{
   8285   1.1  christos 		/*
   8286   1.1  christos 		 * Look to see if there are A records for this name.
   8287   1.1  christos 		 */
   8288   1.1  christos 		qctx->client->query.dns64_ttl = qctx->rdataset->ttl;
   8289   1.1  christos 		SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset);
   8290   1.1  christos 		SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset);
   8291   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   8292   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   8293   1.1  christos 		qctx->type = qctx->qtype = dns_rdatatype_a;
   8294   1.3  christos 		qctx->dns64_exclude = qctx->dns64 = true;
   8295   1.1  christos 
   8296  1.23  christos 		return query_lookup(qctx);
   8297   1.1  christos 	}
   8298   1.1  christos 
   8299   1.3  christos 	/*
   8300   1.3  christos 	 * XXX: This hook is meant to be at the top of this function,
   8301   1.3  christos 	 * but is postponed until after DNS64 in order to avoid an
   8302   1.3  christos 	 * assertion if the hook causes recursion. (When DNS64 also
   8303   1.3  christos 	 * becomes a plugin, it will be necessary to find some
   8304   1.3  christos 	 * other way to prevent that assertion, since the order in
   8305   1.3  christos 	 * which plugins are configured can't be enforced.)
   8306   1.3  christos 	 */
   8307   1.3  christos 	CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx);
   8308   1.1  christos 
   8309   1.1  christos 	if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) {
   8310   1.1  christos 		qctx->noqname = qctx->rdataset;
   8311   1.1  christos 	} else {
   8312   1.1  christos 		qctx->noqname = NULL;
   8313   1.1  christos 	}
   8314   1.1  christos 
   8315   1.1  christos 	/*
   8316   1.1  christos 	 * Special case NS handling
   8317   1.1  christos 	 */
   8318   1.1  christos 	if (qctx->is_zone && qctx->qtype == dns_rdatatype_ns) {
   8319   1.1  christos 		/*
   8320   1.1  christos 		 * We've already got an NS, no need to add one in
   8321   1.1  christos 		 * the authority section
   8322   1.1  christos 		 */
   8323   1.1  christos 		if (dns_name_equal(qctx->client->query.qname,
   8324  1.16  christos 				   dns_db_origin(qctx->db)))
   8325  1.16  christos 		{
   8326   1.3  christos 			qctx->answer_has_ns = true;
   8327   1.1  christos 		}
   8328   1.1  christos 
   8329   1.1  christos 		/*
   8330   1.6  christos 		 * Always add glue for root priming queries, regardless
   8331   1.6  christos 		 * of "minimal-responses" setting.
   8332   1.1  christos 		 */
   8333   1.1  christos 		if (dns_name_equal(qctx->client->query.qname, dns_rootname)) {
   8334   1.1  christos 			qctx->client->query.attributes &=
   8335   1.1  christos 				~NS_QUERYATTR_NOADDITIONAL;
   8336   1.6  christos 			dns_db_attach(qctx->db, &qctx->client->query.gluedb);
   8337   1.1  christos 		}
   8338   1.1  christos 	}
   8339   1.1  christos 
   8340   1.1  christos 	/*
   8341   1.1  christos 	 * Set expire time
   8342   1.1  christos 	 */
   8343   1.1  christos 	query_getexpire(qctx);
   8344   1.1  christos 
   8345   1.3  christos 	result = query_addanswer(qctx);
   8346   1.3  christos 	if (result != ISC_R_COMPLETE) {
   8347  1.23  christos 		return result;
   8348   1.1  christos 	}
   8349   1.1  christos 
   8350   1.1  christos 	query_addnoqnameproof(qctx);
   8351   1.1  christos 
   8352   1.1  christos 	/*
   8353  1.13  christos 	 * 'qctx->rdataset' will only be non-NULL here if the ANSWER section of
   8354  1.13  christos 	 * the message to be sent to the client already contains an RRset with
   8355  1.13  christos 	 * the same owner name and the same type as 'qctx->rdataset'.  This
   8356  1.13  christos 	 * should never happen, with one exception: when chasing DNAME records,
   8357  1.13  christos 	 * one of the DNAME records placed in the ANSWER section may turn out
   8358  1.13  christos 	 * to be the final answer to the client's query, but we have no way of
   8359  1.13  christos 	 * knowing that until now.  In such a case, 'qctx->rdataset' will be
   8360  1.13  christos 	 * freed later, so we do not need to free it here.
   8361   1.1  christos 	 */
   8362  1.13  christos 	INSIST(qctx->rdataset == NULL || qctx->qtype == dns_rdatatype_dname);
   8363   1.1  christos 
   8364   1.1  christos 	query_addauth(qctx);
   8365   1.1  christos 
   8366  1.23  christos 	return ns_query_done(qctx);
   8367   1.3  christos 
   8368   1.9  christos cleanup:
   8369  1.23  christos 	return result;
   8370   1.1  christos }
   8371   1.1  christos 
   8372   1.1  christos static isc_result_t
   8373   1.1  christos query_dns64(query_ctx_t *qctx) {
   8374   1.1  christos 	ns_client_t *client = qctx->client;
   8375  1.20  christos 	dns_aclenv_t *env = client->manager->aclenv;
   8376   1.1  christos 	dns_name_t *name, *mname;
   8377   1.1  christos 	dns_rdata_t *dns64_rdata;
   8378   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   8379   1.1  christos 	dns_rdatalist_t *dns64_rdatalist;
   8380   1.1  christos 	dns_rdataset_t *dns64_rdataset;
   8381   1.1  christos 	dns_rdataset_t *mrdataset;
   8382   1.1  christos 	isc_buffer_t *buffer;
   8383   1.1  christos 	isc_region_t r;
   8384   1.1  christos 	isc_result_t result;
   8385   1.1  christos 	dns_view_t *view = client->view;
   8386   1.1  christos 	isc_netaddr_t netaddr;
   8387   1.1  christos 	dns_dns64_t *dns64;
   8388   1.1  christos 	unsigned int flags = 0;
   8389   1.1  christos 	const dns_section_t section = DNS_SECTION_ANSWER;
   8390   1.1  christos 
   8391   1.1  christos 	/*%
   8392   1.1  christos 	 * To the current response for 'qctx->client', add the answer RRset
   8393   1.1  christos 	 * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
   8394   1.1  christos 	 * owner name '*namep', to the answer section, unless they are
   8395   1.1  christos 	 * already there.  Also add any pertinent additional data.
   8396   1.1  christos 	 *
   8397   1.1  christos 	 * If 'qctx->dbuf' is not NULL, then 'qctx->fname' is the name
   8398   1.1  christos 	 * whose data is stored 'qctx->dbuf'.  In this case,
   8399   1.1  christos 	 * query_addrrset() guarantees that when it returns the name
   8400   1.1  christos 	 * will either have been kept or released.
   8401   1.1  christos 	 */
   8402   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_dns64");
   8403   1.1  christos 
   8404   1.1  christos 	qctx->qtype = qctx->type = dns_rdatatype_aaaa;
   8405   1.1  christos 
   8406   1.1  christos 	name = qctx->fname;
   8407   1.1  christos 	mname = NULL;
   8408   1.1  christos 	mrdataset = NULL;
   8409   1.1  christos 	buffer = NULL;
   8410   1.1  christos 	dns64_rdata = NULL;
   8411   1.1  christos 	dns64_rdataset = NULL;
   8412   1.1  christos 	dns64_rdatalist = NULL;
   8413   1.9  christos 	result = dns_message_findname(
   8414   1.9  christos 		client->message, section, name, dns_rdatatype_aaaa,
   8415   1.9  christos 		qctx->rdataset->covers, &mname, &mrdataset);
   8416   1.1  christos 	if (result == ISC_R_SUCCESS) {
   8417   1.1  christos 		/*
   8418   1.1  christos 		 * We've already got an RRset of the given name and type.
   8419   1.1  christos 		 * There's nothing else to do;
   8420   1.1  christos 		 */
   8421   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_dns64: dns_message_findname "
   8422   1.9  christos 					 "succeeded: done");
   8423   1.3  christos 		if (qctx->dbuf != NULL) {
   8424   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8425   1.3  christos 		}
   8426  1.23  christos 		return ISC_R_SUCCESS;
   8427   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   8428   1.1  christos 		/*
   8429   1.1  christos 		 * The name doesn't exist.
   8430   1.1  christos 		 */
   8431   1.3  christos 		if (qctx->dbuf != NULL) {
   8432   1.3  christos 			ns_client_keepname(client, name, qctx->dbuf);
   8433   1.3  christos 		}
   8434   1.1  christos 		dns_message_addname(client->message, name, section);
   8435   1.1  christos 		qctx->fname = NULL;
   8436   1.1  christos 		mname = name;
   8437   1.1  christos 	} else {
   8438   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   8439   1.3  christos 		if (qctx->dbuf != NULL) {
   8440   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8441   1.3  christos 		}
   8442   1.1  christos 	}
   8443   1.1  christos 
   8444   1.1  christos 	if (qctx->rdataset->trust != dns_trust_secure) {
   8445   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   8446   1.1  christos 	}
   8447   1.1  christos 
   8448   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   8449   1.1  christos 
   8450  1.23  christos 	isc_buffer_allocate(client->manager->mctx, &buffer,
   8451   1.9  christos 			    view->dns64cnt * 16 *
   8452   1.9  christos 				    dns_rdataset_count(qctx->rdataset));
   8453  1.23  christos 	dns_message_gettemprdataset(client->message, &dns64_rdataset);
   8454  1.23  christos 	dns_message_gettemprdatalist(client->message, &dns64_rdatalist);
   8455   1.1  christos 
   8456   1.1  christos 	dns_rdatalist_init(dns64_rdatalist);
   8457   1.1  christos 	dns64_rdatalist->rdclass = dns_rdataclass_in;
   8458   1.1  christos 	dns64_rdatalist->type = dns_rdatatype_aaaa;
   8459   1.9  christos 	if (client->query.dns64_ttl != UINT32_MAX) {
   8460   1.1  christos 		dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl,
   8461   1.1  christos 					       client->query.dns64_ttl);
   8462   1.9  christos 	} else {
   8463   1.1  christos 		dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl, 600);
   8464   1.9  christos 	}
   8465   1.1  christos 
   8466   1.9  christos 	if (RECURSIONOK(client)) {
   8467   1.1  christos 		flags |= DNS_DNS64_RECURSIVE;
   8468   1.9  christos 	}
   8469   1.1  christos 
   8470   1.1  christos 	/*
   8471   1.1  christos 	 * We use the signatures from the A lookup to set DNS_DNS64_DNSSEC
   8472   1.1  christos 	 * as this provides a easy way to see if the answer was signed.
   8473   1.1  christos 	 */
   8474   1.1  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
   8475   1.1  christos 	    dns_rdataset_isassociated(qctx->sigrdataset))
   8476   1.9  christos 	{
   8477   1.1  christos 		flags |= DNS_DNS64_DNSSEC;
   8478   1.9  christos 	}
   8479   1.1  christos 
   8480   1.1  christos 	for (result = dns_rdataset_first(qctx->rdataset);
   8481   1.1  christos 	     result == ISC_R_SUCCESS;
   8482   1.9  christos 	     result = dns_rdataset_next(qctx->rdataset))
   8483   1.9  christos 	{
   8484   1.9  christos 		for (dns64 = ISC_LIST_HEAD(client->view->dns64); dns64 != NULL;
   8485   1.9  christos 		     dns64 = dns_dns64_next(dns64))
   8486   1.9  christos 		{
   8487   1.1  christos 			dns_rdataset_current(qctx->rdataset, &rdata);
   8488   1.1  christos 			isc_buffer_availableregion(buffer, &r);
   8489   1.1  christos 			INSIST(r.length >= 16);
   8490   1.1  christos 			result = dns_dns64_aaaafroma(dns64, &netaddr,
   8491   1.1  christos 						     client->signer, env, flags,
   8492   1.1  christos 						     rdata.data, r.base);
   8493   1.1  christos 			if (result != ISC_R_SUCCESS) {
   8494   1.1  christos 				dns_rdata_reset(&rdata);
   8495   1.1  christos 				continue;
   8496   1.1  christos 			}
   8497   1.1  christos 			isc_buffer_add(buffer, 16);
   8498   1.1  christos 			isc_buffer_remainingregion(buffer, &r);
   8499   1.1  christos 			isc_buffer_forward(buffer, 16);
   8500  1.23  christos 			dns_message_gettemprdata(client->message, &dns64_rdata);
   8501   1.1  christos 			dns_rdata_init(dns64_rdata);
   8502   1.1  christos 			dns_rdata_fromregion(dns64_rdata, dns_rdataclass_in,
   8503   1.1  christos 					     dns_rdatatype_aaaa, &r);
   8504   1.1  christos 			ISC_LIST_APPEND(dns64_rdatalist->rdata, dns64_rdata,
   8505   1.1  christos 					link);
   8506   1.1  christos 			dns64_rdata = NULL;
   8507   1.1  christos 			dns_rdata_reset(&rdata);
   8508   1.1  christos 		}
   8509   1.1  christos 	}
   8510   1.9  christos 	if (result != ISC_R_NOMORE) {
   8511   1.1  christos 		goto cleanup;
   8512   1.9  christos 	}
   8513   1.1  christos 
   8514   1.9  christos 	if (ISC_LIST_EMPTY(dns64_rdatalist->rdata)) {
   8515   1.1  christos 		goto cleanup;
   8516   1.9  christos 	}
   8517   1.1  christos 
   8518  1.23  christos 	dns_rdatalist_tordataset(dns64_rdatalist, dns64_rdataset);
   8519   1.1  christos 	dns_rdataset_setownercase(dns64_rdataset, mname);
   8520   1.1  christos 	client->query.attributes |= NS_QUERYATTR_NOADDITIONAL;
   8521   1.1  christos 	dns64_rdataset->trust = qctx->rdataset->trust;
   8522   1.3  christos 
   8523   1.3  christos 	query_addtoname(mname, dns64_rdataset);
   8524   1.3  christos 	query_setorder(qctx, mname, dns64_rdataset);
   8525   1.3  christos 
   8526   1.1  christos 	dns64_rdataset = NULL;
   8527   1.1  christos 	dns64_rdatalist = NULL;
   8528   1.1  christos 	dns_message_takebuffer(client->message, &buffer);
   8529   1.1  christos 	inc_stats(client, ns_statscounter_dns64);
   8530   1.1  christos 	result = ISC_R_SUCCESS;
   8531   1.1  christos 
   8532   1.9  christos cleanup:
   8533   1.9  christos 	if (buffer != NULL) {
   8534   1.1  christos 		isc_buffer_free(&buffer);
   8535   1.9  christos 	}
   8536   1.1  christos 
   8537   1.9  christos 	if (dns64_rdataset != NULL) {
   8538   1.1  christos 		dns_message_puttemprdataset(client->message, &dns64_rdataset);
   8539   1.9  christos 	}
   8540   1.1  christos 
   8541   1.1  christos 	if (dns64_rdatalist != NULL) {
   8542   1.1  christos 		for (dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata);
   8543   1.1  christos 		     dns64_rdata != NULL;
   8544   1.1  christos 		     dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata))
   8545   1.1  christos 		{
   8546   1.9  christos 			ISC_LIST_UNLINK(dns64_rdatalist->rdata, dns64_rdata,
   8547   1.9  christos 					link);
   8548   1.1  christos 			dns_message_puttemprdata(client->message, &dns64_rdata);
   8549   1.1  christos 		}
   8550   1.1  christos 		dns_message_puttemprdatalist(client->message, &dns64_rdatalist);
   8551   1.1  christos 	}
   8552   1.1  christos 
   8553   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_dns64: done");
   8554  1.23  christos 	return result;
   8555   1.1  christos }
   8556   1.1  christos 
   8557   1.1  christos static void
   8558   1.1  christos query_filter64(query_ctx_t *qctx) {
   8559   1.1  christos 	ns_client_t *client = qctx->client;
   8560   1.1  christos 	dns_name_t *name, *mname;
   8561   1.1  christos 	dns_rdata_t *myrdata;
   8562   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   8563   1.1  christos 	dns_rdatalist_t *myrdatalist;
   8564   1.1  christos 	dns_rdataset_t *myrdataset;
   8565   1.1  christos 	isc_buffer_t *buffer;
   8566   1.1  christos 	isc_region_t r;
   8567   1.1  christos 	isc_result_t result;
   8568   1.1  christos 	unsigned int i;
   8569   1.1  christos 	const dns_section_t section = DNS_SECTION_ANSWER;
   8570   1.1  christos 
   8571   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_filter64");
   8572   1.1  christos 
   8573   1.1  christos 	INSIST(client->query.dns64_aaaaok != NULL);
   8574   1.1  christos 	INSIST(client->query.dns64_aaaaoklen ==
   8575   1.1  christos 	       dns_rdataset_count(qctx->rdataset));
   8576   1.1  christos 
   8577   1.1  christos 	name = qctx->fname;
   8578   1.1  christos 	mname = NULL;
   8579   1.1  christos 	buffer = NULL;
   8580   1.1  christos 	myrdata = NULL;
   8581   1.1  christos 	myrdataset = NULL;
   8582   1.1  christos 	myrdatalist = NULL;
   8583   1.9  christos 	result = dns_message_findname(
   8584   1.9  christos 		client->message, section, name, dns_rdatatype_aaaa,
   8585   1.9  christos 		qctx->rdataset->covers, &mname, &myrdataset);
   8586   1.1  christos 	if (result == ISC_R_SUCCESS) {
   8587   1.1  christos 		/*
   8588   1.1  christos 		 * We've already got an RRset of the given name and type.
   8589   1.1  christos 		 * There's nothing else to do;
   8590   1.1  christos 		 */
   8591   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_filter64: dns_message_findname "
   8592   1.9  christos 					 "succeeded: done");
   8593   1.3  christos 		if (qctx->dbuf != NULL) {
   8594   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8595   1.3  christos 		}
   8596   1.1  christos 		return;
   8597   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   8598   1.1  christos 		mname = name;
   8599   1.1  christos 		qctx->fname = NULL;
   8600   1.1  christos 	} else {
   8601   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   8602   1.3  christos 		if (qctx->dbuf != NULL) {
   8603   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8604   1.3  christos 		}
   8605   1.1  christos 		qctx->dbuf = NULL;
   8606   1.1  christos 	}
   8607   1.1  christos 
   8608   1.1  christos 	if (qctx->rdataset->trust != dns_trust_secure) {
   8609   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   8610   1.1  christos 	}
   8611   1.1  christos 
   8612  1.23  christos 	isc_buffer_allocate(client->manager->mctx, &buffer,
   8613   1.9  christos 			    16 * dns_rdataset_count(qctx->rdataset));
   8614  1.23  christos 	dns_message_gettemprdataset(client->message, &myrdataset);
   8615  1.23  christos 	dns_message_gettemprdatalist(client->message, &myrdatalist);
   8616   1.1  christos 
   8617   1.1  christos 	dns_rdatalist_init(myrdatalist);
   8618   1.1  christos 	myrdatalist->rdclass = dns_rdataclass_in;
   8619   1.1  christos 	myrdatalist->type = dns_rdatatype_aaaa;
   8620   1.1  christos 	myrdatalist->ttl = qctx->rdataset->ttl;
   8621   1.1  christos 
   8622   1.1  christos 	i = 0;
   8623   1.1  christos 	for (result = dns_rdataset_first(qctx->rdataset);
   8624   1.1  christos 	     result == ISC_R_SUCCESS;
   8625   1.3  christos 	     result = dns_rdataset_next(qctx->rdataset))
   8626   1.3  christos 	{
   8627   1.9  christos 		if (!client->query.dns64_aaaaok[i++]) {
   8628   1.1  christos 			continue;
   8629   1.9  christos 		}
   8630   1.1  christos 		dns_rdataset_current(qctx->rdataset, &rdata);
   8631   1.1  christos 		INSIST(rdata.length == 16);
   8632   1.1  christos 		isc_buffer_putmem(buffer, rdata.data, rdata.length);
   8633   1.1  christos 		isc_buffer_remainingregion(buffer, &r);
   8634   1.1  christos 		isc_buffer_forward(buffer, rdata.length);
   8635  1.23  christos 		dns_message_gettemprdata(client->message, &myrdata);
   8636   1.1  christos 		dns_rdata_init(myrdata);
   8637   1.1  christos 		dns_rdata_fromregion(myrdata, dns_rdataclass_in,
   8638   1.1  christos 				     dns_rdatatype_aaaa, &r);
   8639   1.1  christos 		ISC_LIST_APPEND(myrdatalist->rdata, myrdata, link);
   8640   1.1  christos 		myrdata = NULL;
   8641   1.1  christos 		dns_rdata_reset(&rdata);
   8642   1.1  christos 	}
   8643   1.9  christos 	if (result != ISC_R_NOMORE) {
   8644   1.1  christos 		goto cleanup;
   8645   1.9  christos 	}
   8646   1.1  christos 
   8647  1.23  christos 	dns_rdatalist_tordataset(myrdatalist, myrdataset);
   8648   1.1  christos 	dns_rdataset_setownercase(myrdataset, name);
   8649   1.1  christos 	client->query.attributes |= NS_QUERYATTR_NOADDITIONAL;
   8650   1.1  christos 	if (mname == name) {
   8651   1.3  christos 		if (qctx->dbuf != NULL) {
   8652   1.3  christos 			ns_client_keepname(client, name, qctx->dbuf);
   8653   1.3  christos 		}
   8654   1.9  christos 		dns_message_addname(client->message, name, section);
   8655   1.1  christos 		qctx->dbuf = NULL;
   8656   1.1  christos 	}
   8657   1.1  christos 	myrdataset->trust = qctx->rdataset->trust;
   8658   1.3  christos 
   8659   1.3  christos 	query_addtoname(mname, myrdataset);
   8660   1.3  christos 	query_setorder(qctx, mname, myrdataset);
   8661   1.3  christos 
   8662   1.1  christos 	myrdataset = NULL;
   8663   1.1  christos 	myrdatalist = NULL;
   8664   1.1  christos 	dns_message_takebuffer(client->message, &buffer);
   8665   1.1  christos 
   8666   1.9  christos cleanup:
   8667   1.9  christos 	if (buffer != NULL) {
   8668   1.1  christos 		isc_buffer_free(&buffer);
   8669   1.9  christos 	}
   8670   1.1  christos 
   8671   1.9  christos 	if (myrdataset != NULL) {
   8672   1.1  christos 		dns_message_puttemprdataset(client->message, &myrdataset);
   8673   1.9  christos 	}
   8674   1.1  christos 
   8675   1.1  christos 	if (myrdatalist != NULL) {
   8676   1.1  christos 		for (myrdata = ISC_LIST_HEAD(myrdatalist->rdata);
   8677   1.1  christos 		     myrdata != NULL;
   8678   1.1  christos 		     myrdata = ISC_LIST_HEAD(myrdatalist->rdata))
   8679   1.1  christos 		{
   8680   1.1  christos 			ISC_LIST_UNLINK(myrdatalist->rdata, myrdata, link);
   8681   1.1  christos 			dns_message_puttemprdata(client->message, &myrdata);
   8682   1.1  christos 		}
   8683   1.1  christos 		dns_message_puttemprdatalist(client->message, &myrdatalist);
   8684   1.1  christos 	}
   8685  1.23  christos 
   8686   1.3  christos 	if (qctx->dbuf != NULL) {
   8687   1.3  christos 		ns_client_releasename(client, &name);
   8688   1.3  christos 	}
   8689   1.1  christos 
   8690   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done");
   8691   1.1  christos }
   8692   1.1  christos 
   8693   1.1  christos /*%
   8694   1.1  christos  * Handle the case of a name not being found in a database lookup.
   8695   1.1  christos  * Called from query_gotanswer(). Passes off processing to
   8696   1.1  christos  * query_delegation() for a root referral if appropriate.
   8697   1.1  christos  */
   8698   1.1  christos static isc_result_t
   8699   1.1  christos query_notfound(query_ctx_t *qctx) {
   8700  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8701   1.1  christos 
   8702   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_notfound");
   8703   1.9  christos 
   8704   1.3  christos 	CALL_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx);
   8705   1.3  christos 
   8706   1.1  christos 	INSIST(!qctx->is_zone);
   8707   1.1  christos 
   8708   1.9  christos 	if (qctx->db != NULL) {
   8709   1.1  christos 		dns_db_detach(&qctx->db);
   8710   1.9  christos 	}
   8711   1.1  christos 
   8712   1.1  christos 	/*
   8713   1.1  christos 	 * If the cache doesn't even have the root NS,
   8714   1.1  christos 	 * try to get that from the hints DB.
   8715   1.1  christos 	 */
   8716   1.3  christos 	if (qctx->view->hints != NULL) {
   8717   1.1  christos 		dns_clientinfomethods_t cm;
   8718   1.1  christos 		dns_clientinfo_t ci;
   8719   1.1  christos 
   8720   1.1  christos 		dns_clientinfomethods_init(&cm, ns_client_sourceip);
   8721  1.20  christos 		dns_clientinfo_init(&ci, qctx->client, NULL);
   8722   1.1  christos 
   8723   1.3  christos 		dns_db_attach(qctx->view->hints, &qctx->db);
   8724   1.9  christos 		result = dns_db_findext(qctx->db, dns_rootname, NULL,
   8725   1.9  christos 					dns_rdatatype_ns, 0, qctx->client->now,
   8726   1.9  christos 					&qctx->node, qctx->fname, &cm, &ci,
   8727   1.1  christos 					qctx->rdataset, qctx->sigrdataset);
   8728   1.1  christos 	} else {
   8729   1.1  christos 		/* We have no hints. */
   8730   1.1  christos 		result = ISC_R_FAILURE;
   8731   1.1  christos 	}
   8732   1.1  christos 	if (result != ISC_R_SUCCESS) {
   8733   1.1  christos 		/*
   8734   1.1  christos 		 * Nonsensical root hints may require cleanup.
   8735   1.1  christos 		 */
   8736   1.1  christos 		qctx_clean(qctx);
   8737   1.1  christos 
   8738   1.1  christos 		/*
   8739   1.1  christos 		 * We don't have any root server hints, but
   8740   1.1  christos 		 * we may have working forwarders, so try to
   8741   1.1  christos 		 * recurse anyway.
   8742   1.1  christos 		 */
   8743   1.1  christos 		if (RECURSIONOK(qctx->client)) {
   8744   1.1  christos 			INSIST(!REDIRECT(qctx->client));
   8745   1.3  christos 			result = ns_query_recurse(qctx->client, qctx->qtype,
   8746   1.3  christos 						  qctx->client->query.qname,
   8747   1.3  christos 						  NULL, NULL, qctx->resuming);
   8748   1.1  christos 			if (result == ISC_R_SUCCESS) {
   8749   1.3  christos 				CALL_HOOK(NS_QUERY_NOTFOUND_RECURSE, qctx);
   8750   1.1  christos 				qctx->client->query.attributes |=
   8751   1.9  christos 					NS_QUERYATTR_RECURSING;
   8752   1.3  christos 
   8753   1.3  christos 				if (qctx->dns64) {
   8754   1.1  christos 					qctx->client->query.attributes |=
   8755   1.1  christos 						NS_QUERYATTR_DNS64;
   8756   1.3  christos 				}
   8757   1.3  christos 				if (qctx->dns64_exclude) {
   8758   1.1  christos 					qctx->client->query.attributes |=
   8759   1.1  christos 						NS_QUERYATTR_DNS64EXCLUDE;
   8760   1.3  christos 				}
   8761  1.13  christos 			} else if (query_usestale(qctx, result)) {
   8762  1.13  christos 				/*
   8763  1.13  christos 				 * If serve-stale is enabled, query_usestale()
   8764  1.13  christos 				 * already set up 'qctx' for looking up a
   8765  1.13  christos 				 * stale response.
   8766  1.13  christos 				 */
   8767  1.23  christos 				return query_lookup(qctx);
   8768   1.3  christos 			} else {
   8769   1.3  christos 				QUERY_ERROR(qctx, result);
   8770   1.3  christos 			}
   8771  1.23  christos 			return ns_query_done(qctx);
   8772   1.1  christos 		} else {
   8773   1.1  christos 			/* Unable to give root server referral. */
   8774   1.9  christos 			CCTRACE(ISC_LOG_ERROR, "unable to give root server "
   8775   1.9  christos 					       "referral");
   8776   1.3  christos 			QUERY_ERROR(qctx, result);
   8777  1.23  christos 			return ns_query_done(qctx);
   8778   1.1  christos 		}
   8779   1.1  christos 	}
   8780   1.1  christos 
   8781  1.23  christos 	return query_delegation(qctx);
   8782   1.3  christos 
   8783   1.9  christos cleanup:
   8784  1.23  christos 	return result;
   8785   1.3  christos }
   8786   1.3  christos 
   8787   1.3  christos /*%
   8788   1.3  christos  * We have a delegation but recursion is not allowed, so return the delegation
   8789   1.3  christos  * to the client.
   8790   1.3  christos  */
   8791   1.3  christos static isc_result_t
   8792   1.3  christos query_prepare_delegation_response(query_ctx_t *qctx) {
   8793  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8794   1.3  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   8795   1.3  christos 	bool detach = false;
   8796   1.3  christos 
   8797   1.3  christos 	CALL_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx);
   8798   1.3  christos 
   8799   1.3  christos 	/*
   8800   1.3  christos 	 * qctx->fname could be released in query_addrrset(), so save a copy of
   8801   1.3  christos 	 * it here in case we need it.
   8802   1.3  christos 	 */
   8803   1.3  christos 	dns_fixedname_init(&qctx->dsname);
   8804  1.20  christos 	dns_name_copy(qctx->fname, dns_fixedname_name(&qctx->dsname));
   8805   1.3  christos 
   8806   1.3  christos 	/*
   8807   1.3  christos 	 * This is the best answer.
   8808   1.3  christos 	 */
   8809   1.3  christos 	qctx->client->query.isreferral = true;
   8810   1.3  christos 
   8811   1.3  christos 	if (!dns_db_iscache(qctx->db) && qctx->client->query.gluedb == NULL) {
   8812   1.3  christos 		dns_db_attach(qctx->db, &qctx->client->query.gluedb);
   8813   1.3  christos 		detach = true;
   8814   1.3  christos 	}
   8815   1.3  christos 
   8816   1.3  christos 	/*
   8817   1.3  christos 	 * We must ensure NOADDITIONAL is off, because the generation of
   8818   1.3  christos 	 * additional data is required in delegations.
   8819   1.3  christos 	 */
   8820   1.3  christos 	qctx->client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL;
   8821   1.3  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   8822   1.3  christos 		sigrdatasetp = &qctx->sigrdataset;
   8823   1.3  christos 	}
   8824   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   8825   1.9  christos 		       qctx->dbuf, DNS_SECTION_AUTHORITY);
   8826   1.3  christos 	if (detach) {
   8827   1.3  christos 		dns_db_detach(&qctx->client->query.gluedb);
   8828   1.3  christos 	}
   8829   1.3  christos 
   8830   1.3  christos 	/*
   8831  1.14  christos 	 * Add DS/NSEC(3) record(s) if needed.
   8832   1.3  christos 	 */
   8833   1.3  christos 	query_addds(qctx);
   8834   1.3  christos 
   8835  1.23  christos 	return ns_query_done(qctx);
   8836   1.3  christos 
   8837   1.9  christos cleanup:
   8838  1.23  christos 	return result;
   8839   1.1  christos }
   8840   1.1  christos 
   8841   1.1  christos /*%
   8842   1.1  christos  * Handle a delegation response from an authoritative lookup. This
   8843   1.1  christos  * may trigger additional lookups, e.g. from the cache database to
   8844   1.1  christos  * see if we have a better answer; if that is not allowed, return the
   8845   1.3  christos  * delegation to the client and call ns_query_done().
   8846   1.1  christos  */
   8847   1.1  christos static isc_result_t
   8848   1.1  christos query_zone_delegation(query_ctx_t *qctx) {
   8849  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8850   1.3  christos 
   8851   1.3  christos 	CALL_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx);
   8852   1.1  christos 
   8853   1.1  christos 	/*
   8854   1.1  christos 	 * If the query type is DS, look to see if we are
   8855   1.1  christos 	 * authoritative for the child zone
   8856   1.1  christos 	 */
   8857   1.1  christos 	if (!RECURSIONOK(qctx->client) &&
   8858  1.23  christos 	    (qctx->options.noexact && qctx->qtype == dns_rdatatype_ds))
   8859   1.1  christos 	{
   8860   1.1  christos 		dns_db_t *tdb = NULL;
   8861   1.1  christos 		dns_zone_t *tzone = NULL;
   8862   1.1  christos 		dns_dbversion_t *tversion = NULL;
   8863  1.23  christos 		dns_getdb_options_t options = { .partial = true };
   8864  1.23  christos 		result = query_getzonedb(qctx->client,
   8865  1.23  christos 					 qctx->client->query.qname, qctx->qtype,
   8866  1.23  christos 					 options, &tzone, &tdb, &tversion);
   8867   1.1  christos 		if (result != ISC_R_SUCCESS) {
   8868   1.9  christos 			if (tdb != NULL) {
   8869   1.1  christos 				dns_db_detach(&tdb);
   8870   1.9  christos 			}
   8871   1.9  christos 			if (tzone != NULL) {
   8872   1.1  christos 				dns_zone_detach(&tzone);
   8873   1.9  christos 			}
   8874   1.1  christos 		} else {
   8875  1.23  christos 			qctx->options.noexact = false;
   8876   1.9  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   8877   1.3  christos 			if (qctx->sigrdataset != NULL) {
   8878   1.3  christos 				ns_client_putrdataset(qctx->client,
   8879   1.3  christos 						      &qctx->sigrdataset);
   8880   1.3  christos 			}
   8881   1.3  christos 			if (qctx->fname != NULL) {
   8882   1.3  christos 				ns_client_releasename(qctx->client,
   8883   1.3  christos 						      &qctx->fname);
   8884   1.3  christos 			}
   8885   1.9  christos 			if (qctx->node != NULL) {
   8886   1.9  christos 				dns_db_detachnode(qctx->db, &qctx->node);
   8887   1.9  christos 			}
   8888   1.9  christos 			if (qctx->db != NULL) {
   8889   1.1  christos 				dns_db_detach(&qctx->db);
   8890   1.9  christos 			}
   8891   1.9  christos 			if (qctx->zone != NULL) {
   8892   1.1  christos 				dns_zone_detach(&qctx->zone);
   8893   1.9  christos 			}
   8894   1.1  christos 			qctx->version = NULL;
   8895   1.1  christos 			RESTORE(qctx->version, tversion);
   8896   1.1  christos 			RESTORE(qctx->db, tdb);
   8897   1.1  christos 			RESTORE(qctx->zone, tzone);
   8898   1.3  christos 			qctx->authoritative = true;
   8899   1.1  christos 
   8900  1.23  christos 			return query_lookup(qctx);
   8901   1.1  christos 		}
   8902   1.1  christos 	}
   8903   1.1  christos 
   8904   1.3  christos 	if (USECACHE(qctx->client) &&
   8905   1.3  christos 	    (RECURSIONOK(qctx->client) ||
   8906   1.3  christos 	     (qctx->zone != NULL &&
   8907   1.3  christos 	      dns_zone_gettype(qctx->zone) == dns_zone_mirror)))
   8908   1.3  christos 	{
   8909   1.1  christos 		/*
   8910   1.1  christos 		 * We might have a better answer or delegation in the
   8911   1.1  christos 		 * cache.  We'll remember the current values of fname,
   8912   1.1  christos 		 * rdataset, and sigrdataset.  We'll then go looking for
   8913   1.1  christos 		 * QNAME in the cache.  If we find something better, we'll
   8914   1.1  christos 		 * use it instead. If not, then query_lookup() calls
   8915   1.1  christos 		 * query_notfound() which calls query_delegation(), and
   8916   1.1  christos 		 * we'll restore these values there.
   8917   1.1  christos 		 */
   8918   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   8919   1.1  christos 		SAVE(qctx->zdb, qctx->db);
   8920   1.3  christos 		SAVE(qctx->znode, qctx->node);
   8921   1.1  christos 		SAVE(qctx->zfname, qctx->fname);
   8922   1.1  christos 		SAVE(qctx->zversion, qctx->version);
   8923   1.1  christos 		SAVE(qctx->zrdataset, qctx->rdataset);
   8924   1.1  christos 		SAVE(qctx->zsigrdataset, qctx->sigrdataset);
   8925   1.3  christos 		dns_db_attach(qctx->view->cachedb, &qctx->db);
   8926   1.3  christos 		qctx->is_zone = false;
   8927   1.1  christos 
   8928  1.24  christos 		/*
   8929  1.24  christos 		 * Since 'qctx->is_zone' is now false, we should reconsider
   8930  1.24  christos 		 * setting the 'stalefirst' option, which is usually set in
   8931  1.24  christos 		 * the beginning in ns__query_start().
   8932  1.24  christos 		 */
   8933  1.25  christos 		qctx->options.stalefirst =
   8934  1.25  christos 			(qctx->view->staleanswerclienttimeout == 0 &&
   8935  1.25  christos 			 dns_view_staleanswerenabled(qctx->view));
   8936  1.24  christos 
   8937  1.24  christos 		result = query_lookup(qctx);
   8938  1.24  christos 
   8939  1.24  christos 		/*
   8940  1.24  christos 		 * After fetch completes, this option is not expected to be set.
   8941  1.24  christos 		 */
   8942  1.24  christos 		qctx->options.stalefirst = false;
   8943  1.24  christos 
   8944  1.24  christos 		return result;
   8945   1.1  christos 	}
   8946   1.1  christos 
   8947  1.23  christos 	return query_prepare_delegation_response(qctx);
   8948   1.1  christos 
   8949   1.9  christos cleanup:
   8950  1.23  christos 	return result;
   8951   1.1  christos }
   8952   1.1  christos 
   8953   1.1  christos /*%
   8954   1.1  christos  * Handle delegation responses, including root referrals.
   8955   1.1  christos  *
   8956   1.1  christos  * If the delegation was returned from authoritative data,
   8957   1.1  christos  * call query_zone_delgation().  Otherwise, we can start
   8958   1.1  christos  * recursion if allowed; or else return the delegation to the
   8959   1.3  christos  * client and call ns_query_done().
   8960   1.1  christos  */
   8961   1.1  christos static isc_result_t
   8962   1.1  christos query_delegation(query_ctx_t *qctx) {
   8963  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8964   1.1  christos 
   8965   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_delegation");
   8966   1.9  christos 
   8967   1.3  christos 	CALL_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx);
   8968   1.3  christos 
   8969   1.3  christos 	qctx->authoritative = false;
   8970   1.1  christos 
   8971   1.1  christos 	if (qctx->is_zone) {
   8972  1.23  christos 		return query_zone_delegation(qctx);
   8973   1.1  christos 	}
   8974   1.1  christos 
   8975   1.1  christos 	if (qctx->zfname != NULL &&
   8976   1.1  christos 	    (!dns_name_issubdomain(qctx->fname, qctx->zfname) ||
   8977   1.1  christos 	     (qctx->is_staticstub_zone &&
   8978   1.1  christos 	      dns_name_equal(qctx->fname, qctx->zfname))))
   8979   1.1  christos 	{
   8980   1.1  christos 		/*
   8981   1.1  christos 		 * In the following cases use "authoritative"
   8982   1.1  christos 		 * data instead of the cache delegation:
   8983   1.1  christos 		 * 1. We've already got a delegation from
   8984   1.1  christos 		 *    authoritative data, and it is better
   8985   1.1  christos 		 *    than what we found in the cache.
   8986   1.1  christos 		 *    (See the comment above.)
   8987   1.1  christos 		 * 2. The query name matches the origin name
   8988   1.1  christos 		 *    of a static-stub zone.  This needs to be
   8989   1.1  christos 		 *    considered for the case where the NS of
   8990   1.1  christos 		 *    the static-stub zone and the cached NS
   8991   1.1  christos 		 *    are different.  We still need to contact
   8992   1.1  christos 		 *    the nameservers configured in the
   8993   1.1  christos 		 *    static-stub zone.
   8994   1.1  christos 		 */
   8995   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   8996   1.1  christos 
   8997   1.1  christos 		/*
   8998   1.3  christos 		 * We've already done ns_client_keepname() on
   8999   1.1  christos 		 * qctx->zfname, so we must set dbuf to NULL to
   9000   1.1  christos 		 * prevent query_addrrset() from trying to
   9001   1.3  christos 		 * call ns_client_keepname() again.
   9002   1.1  christos 		 */
   9003   1.1  christos 		qctx->dbuf = NULL;
   9004   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   9005   1.3  christos 		if (qctx->sigrdataset != NULL) {
   9006   1.9  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   9007   1.3  christos 		}
   9008   1.1  christos 		qctx->version = NULL;
   9009   1.1  christos 
   9010   1.3  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   9011   1.3  christos 		dns_db_detach(&qctx->db);
   9012   1.3  christos 		RESTORE(qctx->db, qctx->zdb);
   9013   1.3  christos 		RESTORE(qctx->node, qctx->znode);
   9014   1.1  christos 		RESTORE(qctx->fname, qctx->zfname);
   9015   1.1  christos 		RESTORE(qctx->version, qctx->zversion);
   9016   1.1  christos 		RESTORE(qctx->rdataset, qctx->zrdataset);
   9017   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->zsigrdataset);
   9018   1.3  christos 	}
   9019   1.1  christos 
   9020   1.3  christos 	result = query_delegation_recurse(qctx);
   9021   1.3  christos 	if (result != ISC_R_COMPLETE) {
   9022  1.23  christos 		return result;
   9023   1.1  christos 	}
   9024   1.1  christos 
   9025  1.23  christos 	return query_prepare_delegation_response(qctx);
   9026   1.1  christos 
   9027   1.9  christos cleanup:
   9028  1.23  christos 	return result;
   9029   1.3  christos }
   9030   1.1  christos 
   9031   1.3  christos /*%
   9032   1.3  christos  * Handle recursive queries that are triggered as part of the
   9033   1.3  christos  * delegation process.
   9034   1.3  christos  */
   9035   1.3  christos static isc_result_t
   9036   1.3  christos query_delegation_recurse(query_ctx_t *qctx) {
   9037  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   9038   1.3  christos 	dns_name_t *qname = qctx->client->query.qname;
   9039   1.1  christos 
   9040   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_delegation_recurse");
   9041   1.9  christos 
   9042   1.3  christos 	if (!RECURSIONOK(qctx->client)) {
   9043  1.23  christos 		return ISC_R_COMPLETE;
   9044   1.1  christos 	}
   9045   1.1  christos 
   9046   1.3  christos 	CALL_HOOK(NS_QUERY_DELEGATION_RECURSE_BEGIN, qctx);
   9047   1.3  christos 
   9048   1.1  christos 	/*
   9049   1.3  christos 	 * We have a delegation and recursion is allowed,
   9050   1.3  christos 	 * so we call ns_query_recurse() to follow it.
   9051   1.3  christos 	 * This phase of the query processing is done;
   9052   1.3  christos 	 * we'll resume via fetch_callback() and
   9053   1.3  christos 	 * query_resume() when the recursion is complete.
   9054   1.1  christos 	 */
   9055   1.1  christos 
   9056   1.3  christos 	INSIST(!REDIRECT(qctx->client));
   9057   1.1  christos 
   9058   1.3  christos 	if (dns_rdatatype_atparent(qctx->type)) {
   9059   1.3  christos 		/*
   9060   1.3  christos 		 * Parent is authoritative for this RDATA type (i.e. DS).
   9061   1.3  christos 		 */
   9062   1.3  christos 		result = ns_query_recurse(qctx->client, qctx->qtype, qname,
   9063   1.3  christos 					  NULL, NULL, qctx->resuming);
   9064   1.3  christos 	} else if (qctx->dns64) {
   9065   1.3  christos 		/*
   9066   1.3  christos 		 * Look up an A record so we can synthesize DNS64.
   9067   1.3  christos 		 */
   9068   1.3  christos 		result = ns_query_recurse(qctx->client, dns_rdatatype_a, qname,
   9069   1.3  christos 					  NULL, NULL, qctx->resuming);
   9070   1.3  christos 	} else {
   9071   1.3  christos 		/*
   9072   1.3  christos 		 * Any other recursion.
   9073   1.3  christos 		 */
   9074   1.3  christos 		result = ns_query_recurse(qctx->client, qctx->qtype, qname,
   9075   1.3  christos 					  qctx->fname, qctx->rdataset,
   9076   1.3  christos 					  qctx->resuming);
   9077   1.1  christos 	}
   9078   1.1  christos 
   9079   1.3  christos 	if (result == ISC_R_SUCCESS) {
   9080   1.3  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   9081   1.3  christos 		if (qctx->dns64) {
   9082   1.3  christos 			qctx->client->query.attributes |= NS_QUERYATTR_DNS64;
   9083   1.3  christos 		}
   9084   1.3  christos 		if (qctx->dns64_exclude) {
   9085   1.3  christos 			qctx->client->query.attributes |=
   9086   1.9  christos 				NS_QUERYATTR_DNS64EXCLUDE;
   9087   1.3  christos 		}
   9088  1.13  christos 	} else if (query_usestale(qctx, result)) {
   9089  1.13  christos 		/*
   9090  1.13  christos 		 * If serve-stale is enabled, query_usestale() already set up
   9091  1.13  christos 		 * 'qctx' for looking up a stale response.
   9092  1.13  christos 		 */
   9093  1.23  christos 		return query_lookup(qctx);
   9094   1.3  christos 	} else {
   9095   1.3  christos 		QUERY_ERROR(qctx, result);
   9096   1.1  christos 	}
   9097   1.1  christos 
   9098  1.23  christos 	return ns_query_done(qctx);
   9099   1.1  christos 
   9100   1.9  christos cleanup:
   9101  1.23  christos 	return result;
   9102   1.1  christos }
   9103   1.1  christos 
   9104   1.1  christos /*%
   9105  1.14  christos  * Add DS/NSEC(3) record(s) if needed.
   9106   1.1  christos  */
   9107   1.1  christos static void
   9108   1.1  christos query_addds(query_ctx_t *qctx) {
   9109   1.1  christos 	ns_client_t *client = qctx->client;
   9110   1.1  christos 	dns_fixedname_t fixed;
   9111   1.1  christos 	dns_name_t *fname = NULL;
   9112   1.1  christos 	dns_name_t *rname = NULL;
   9113   1.1  christos 	dns_name_t *name;
   9114   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   9115   1.1  christos 	isc_buffer_t *dbuf, b;
   9116   1.1  christos 	isc_result_t result;
   9117   1.1  christos 	unsigned int count;
   9118   1.1  christos 
   9119   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addds");
   9120   1.1  christos 
   9121   1.1  christos 	/*
   9122   1.1  christos 	 * DS not needed.
   9123   1.1  christos 	 */
   9124   1.1  christos 	if (!WANTDNSSEC(client)) {
   9125   1.1  christos 		return;
   9126   1.1  christos 	}
   9127   1.1  christos 
   9128   1.1  christos 	/*
   9129   1.1  christos 	 * We'll need some resources...
   9130   1.1  christos 	 */
   9131   1.3  christos 	rdataset = ns_client_newrdataset(client);
   9132   1.3  christos 	sigrdataset = ns_client_newrdataset(client);
   9133   1.1  christos 
   9134   1.1  christos 	/*
   9135   1.1  christos 	 * Look for the DS record, which may or may not be present.
   9136   1.1  christos 	 */
   9137   1.1  christos 	result = dns_db_findrdataset(qctx->db, qctx->node, qctx->version,
   9138   1.9  christos 				     dns_rdatatype_ds, 0, client->now, rdataset,
   9139   1.9  christos 				     sigrdataset);
   9140   1.1  christos 	/*
   9141   1.1  christos 	 * If we didn't find it, look for an NSEC.
   9142   1.1  christos 	 */
   9143   1.9  christos 	if (result == ISC_R_NOTFOUND) {
   9144   1.9  christos 		result = dns_db_findrdataset(
   9145   1.9  christos 			qctx->db, qctx->node, qctx->version, dns_rdatatype_nsec,
   9146   1.9  christos 			0, client->now, rdataset, sigrdataset);
   9147   1.9  christos 	}
   9148   1.9  christos 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
   9149   1.1  christos 		goto addnsec3;
   9150   1.9  christos 	}
   9151   1.1  christos 	if (!dns_rdataset_isassociated(rdataset) ||
   9152   1.1  christos 	    !dns_rdataset_isassociated(sigrdataset))
   9153   1.9  christos 	{
   9154   1.1  christos 		goto addnsec3;
   9155   1.9  christos 	}
   9156   1.1  christos 
   9157   1.1  christos 	/*
   9158   1.1  christos 	 * We've already added the NS record, so if the name's not there,
   9159  1.14  christos 	 * we have other problems.
   9160   1.1  christos 	 */
   9161   1.1  christos 	result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
   9162   1.9  christos 	if (result != ISC_R_SUCCESS) {
   9163   1.1  christos 		goto cleanup;
   9164   1.9  christos 	}
   9165   1.1  christos 
   9166  1.14  christos 	/*
   9167  1.14  christos 	 * Find the delegation in the response message - it is not necessarily
   9168  1.14  christos 	 * the first name in the AUTHORITY section when wildcard processing is
   9169  1.14  christos 	 * involved.
   9170  1.14  christos 	 */
   9171  1.14  christos 	while (result == ISC_R_SUCCESS) {
   9172  1.14  christos 		rname = NULL;
   9173  1.14  christos 		dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
   9174  1.14  christos 					&rname);
   9175  1.14  christos 		result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
   9176  1.14  christos 		if (result == ISC_R_SUCCESS) {
   9177  1.14  christos 			break;
   9178  1.14  christos 		}
   9179  1.14  christos 		result = dns_message_nextname(client->message,
   9180  1.14  christos 					      DNS_SECTION_AUTHORITY);
   9181  1.14  christos 	}
   9182  1.14  christos 
   9183   1.9  christos 	if (result != ISC_R_SUCCESS) {
   9184   1.1  christos 		goto cleanup;
   9185   1.9  christos 	}
   9186   1.1  christos 
   9187  1.14  christos 	/*
   9188  1.14  christos 	 * Add the relevant RRset (DS or NSEC) to the delegation.
   9189  1.14  christos 	 */
   9190  1.14  christos 	query_addrrset(qctx, &rname, &rdataset, &sigrdataset, NULL,
   9191  1.14  christos 		       DNS_SECTION_AUTHORITY);
   9192  1.14  christos 	goto cleanup;
   9193   1.1  christos 
   9194   1.9  christos addnsec3:
   9195   1.9  christos 	if (!dns_db_iszone(qctx->db)) {
   9196   1.1  christos 		goto cleanup;
   9197   1.9  christos 	}
   9198   1.1  christos 	/*
   9199   1.1  christos 	 * Add the NSEC3 which proves the DS does not exist.
   9200   1.1  christos 	 */
   9201   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   9202   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   9203   1.1  christos 	dns_fixedname_init(&fixed);
   9204   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   9205   1.1  christos 		dns_rdataset_disassociate(rdataset);
   9206   1.9  christos 	}
   9207   1.9  christos 	if (dns_rdataset_isassociated(sigrdataset)) {
   9208   1.1  christos 		dns_rdataset_disassociate(sigrdataset);
   9209   1.9  christos 	}
   9210   1.1  christos 	name = dns_fixedname_name(&qctx->dsname);
   9211   1.1  christos 	query_findclosestnsec3(name, qctx->db, qctx->version, client, rdataset,
   9212   1.3  christos 			       sigrdataset, fname, true,
   9213   1.1  christos 			       dns_fixedname_name(&fixed));
   9214   1.9  christos 	if (!dns_rdataset_isassociated(rdataset)) {
   9215   1.1  christos 		goto cleanup;
   9216   1.9  christos 	}
   9217   1.3  christos 	query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   9218   1.1  christos 		       DNS_SECTION_AUTHORITY);
   9219   1.1  christos 	/*
   9220   1.1  christos 	 * Did we find the closest provable encloser instead?
   9221   1.1  christos 	 * If so add the nearest to the closest provable encloser.
   9222   1.1  christos 	 */
   9223   1.1  christos 	if (!dns_name_equal(name, dns_fixedname_name(&fixed))) {
   9224   1.1  christos 		count = dns_name_countlabels(dns_fixedname_name(&fixed)) + 1;
   9225   1.1  christos 		dns_name_getlabelsequence(name,
   9226   1.1  christos 					  dns_name_countlabels(name) - count,
   9227   1.1  christos 					  count, dns_fixedname_name(&fixed));
   9228   1.1  christos 		fixfname(client, &fname, &dbuf, &b);
   9229   1.1  christos 		fixrdataset(client, &rdataset);
   9230   1.1  christos 		fixrdataset(client, &sigrdataset);
   9231   1.9  christos 		if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   9232   1.9  christos 			goto cleanup;
   9233   1.9  christos 		}
   9234   1.9  christos 		query_findclosestnsec3(dns_fixedname_name(&fixed), qctx->db,
   9235   1.9  christos 				       qctx->version, client, rdataset,
   9236   1.9  christos 				       sigrdataset, fname, false, NULL);
   9237   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   9238   1.1  christos 			goto cleanup;
   9239   1.9  christos 		}
   9240   1.3  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   9241   1.1  christos 			       DNS_SECTION_AUTHORITY);
   9242   1.1  christos 	}
   9243   1.1  christos 
   9244   1.9  christos cleanup:
   9245   1.3  christos 	if (rdataset != NULL) {
   9246   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   9247   1.3  christos 	}
   9248   1.3  christos 	if (sigrdataset != NULL) {
   9249   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   9250   1.3  christos 	}
   9251   1.3  christos 	if (fname != NULL) {
   9252   1.3  christos 		ns_client_releasename(client, &fname);
   9253   1.3  christos 	}
   9254   1.1  christos }
   9255   1.1  christos 
   9256   1.1  christos /*%
   9257   1.1  christos  * Handle authoritative NOERROR/NODATA responses.
   9258   1.1  christos  */
   9259   1.1  christos static isc_result_t
   9260   1.3  christos query_nodata(query_ctx_t *qctx, isc_result_t res) {
   9261   1.3  christos 	isc_result_t result = res;
   9262   1.3  christos 
   9263   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_nodata");
   9264   1.9  christos 
   9265   1.3  christos 	CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx);
   9266   1.3  christos 
   9267   1.1  christos #ifdef dns64_bis_return_excluded_addresses
   9268   1.1  christos 	if (qctx->dns64)
   9269   1.9  christos #else  /* ifdef dns64_bis_return_excluded_addresses */
   9270   1.1  christos 	if (qctx->dns64 && !qctx->dns64_exclude)
   9271   1.9  christos #endif /* ifdef dns64_bis_return_excluded_addresses */
   9272   1.1  christos 	{
   9273   1.1  christos 		isc_buffer_t b;
   9274   1.1  christos 		/*
   9275   1.1  christos 		 * Restore the answers from the previous AAAA lookup.
   9276   1.1  christos 		 */
   9277   1.9  christos 		if (qctx->rdataset != NULL) {
   9278   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   9279   1.9  christos 		}
   9280   1.9  christos 		if (qctx->sigrdataset != NULL) {
   9281   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   9282   1.9  christos 		}
   9283   1.1  christos 		RESTORE(qctx->rdataset, qctx->client->query.dns64_aaaa);
   9284   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->client->query.dns64_sigaaaa);
   9285   1.1  christos 		if (qctx->fname == NULL) {
   9286   1.3  christos 			qctx->dbuf = ns_client_getnamebuf(qctx->client);
   9287   1.3  christos 			qctx->fname = ns_client_newname(qctx->client,
   9288   1.3  christos 							qctx->dbuf, &b);
   9289   1.1  christos 		}
   9290  1.20  christos 		dns_name_copy(qctx->client->query.qname, qctx->fname);
   9291   1.3  christos 		qctx->dns64 = false;
   9292   1.1  christos #ifdef dns64_bis_return_excluded_addresses
   9293   1.1  christos 		/*
   9294   1.1  christos 		 * Resume the diverted processing of the AAAA response?
   9295   1.1  christos 		 */
   9296   1.9  christos 		if (qctx->dns64_exclude) {
   9297  1.23  christos 			return query_prepresponse(qctx);
   9298   1.9  christos 		}
   9299   1.9  christos #endif /* ifdef dns64_bis_return_excluded_addresses */
   9300   1.9  christos 	} else if ((result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) &&
   9301   1.9  christos 		   !ISC_LIST_EMPTY(qctx->view->dns64) && !qctx->nxrewrite &&
   9302   1.1  christos 		   qctx->client->message->rdclass == dns_rdataclass_in &&
   9303   1.1  christos 		   qctx->qtype == dns_rdatatype_aaaa)
   9304   1.1  christos 	{
   9305   1.1  christos 		/*
   9306   1.1  christos 		 * Look to see if there are A records for this name.
   9307   1.1  christos 		 */
   9308   1.1  christos 		switch (result) {
   9309   1.1  christos 		case DNS_R_NCACHENXRRSET:
   9310   1.1  christos 			/*
   9311   1.1  christos 			 * This is from the negative cache; if the ttl is
   9312   1.1  christos 			 * zero, we need to work out whether we have just
   9313   1.1  christos 			 * decremented to zero or there was no negative
   9314   1.1  christos 			 * cache ttl in the answer.
   9315   1.1  christos 			 */
   9316   1.1  christos 			if (qctx->rdataset->ttl != 0) {
   9317   1.1  christos 				qctx->client->query.dns64_ttl =
   9318   1.1  christos 					qctx->rdataset->ttl;
   9319   1.1  christos 				break;
   9320   1.1  christos 			}
   9321   1.1  christos 			if (dns_rdataset_first(qctx->rdataset) == ISC_R_SUCCESS)
   9322   1.9  christos 			{
   9323   1.1  christos 				qctx->client->query.dns64_ttl = 0;
   9324   1.9  christos 			}
   9325   1.1  christos 			break;
   9326   1.1  christos 		case DNS_R_NXRRSET:
   9327   1.1  christos 			qctx->client->query.dns64_ttl =
   9328   1.1  christos 				dns64_ttl(qctx->db, qctx->version);
   9329   1.1  christos 			break;
   9330   1.1  christos 		default:
   9331  1.15  christos 			UNREACHABLE();
   9332   1.1  christos 		}
   9333   1.1  christos 
   9334   1.1  christos 		SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset);
   9335   1.1  christos 		SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset);
   9336   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9337   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   9338   1.1  christos 		qctx->type = qctx->qtype = dns_rdatatype_a;
   9339   1.3  christos 		qctx->dns64 = true;
   9340  1.23  christos 		return query_lookup(qctx);
   9341   1.1  christos 	}
   9342   1.1  christos 
   9343   1.1  christos 	if (qctx->is_zone) {
   9344  1.23  christos 		return query_sign_nodata(qctx);
   9345   1.1  christos 	} else {
   9346   1.1  christos 		/*
   9347   1.1  christos 		 * We don't call query_addrrset() because we don't need any
   9348   1.1  christos 		 * of its extra features (and things would probably break!).
   9349   1.1  christos 		 */
   9350   1.1  christos 		if (dns_rdataset_isassociated(qctx->rdataset)) {
   9351   1.3  christos 			ns_client_keepname(qctx->client, qctx->fname,
   9352   1.3  christos 					   qctx->dbuf);
   9353   1.9  christos 			dns_message_addname(qctx->client->message, qctx->fname,
   9354   1.1  christos 					    DNS_SECTION_AUTHORITY);
   9355   1.9  christos 			ISC_LIST_APPEND(qctx->fname->list, qctx->rdataset,
   9356   1.9  christos 					link);
   9357   1.1  christos 			qctx->fname = NULL;
   9358   1.1  christos 			qctx->rdataset = NULL;
   9359   1.1  christos 		}
   9360   1.1  christos 	}
   9361   1.1  christos 
   9362  1.23  christos 	return ns_query_done(qctx);
   9363   1.3  christos 
   9364   1.9  christos cleanup:
   9365  1.23  christos 	return result;
   9366   1.1  christos }
   9367   1.1  christos 
   9368   1.1  christos /*%
   9369   1.1  christos  * Add RRSIGs for NOERROR/NODATA responses when answering authoritatively.
   9370   1.1  christos  */
   9371   1.1  christos isc_result_t
   9372   1.1  christos query_sign_nodata(query_ctx_t *qctx) {
   9373   1.1  christos 	isc_result_t result;
   9374   1.9  christos 
   9375   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_sign_nodata");
   9376   1.9  christos 
   9377   1.1  christos 	/*
   9378   1.1  christos 	 * Look for a NSEC3 record if we don't have a NSEC record.
   9379   1.1  christos 	 */
   9380   1.9  christos 	if (qctx->redirected) {
   9381  1.23  christos 		return ns_query_done(qctx);
   9382   1.9  christos 	}
   9383   1.1  christos 	if (!dns_rdataset_isassociated(qctx->rdataset) &&
   9384  1.16  christos 	    WANTDNSSEC(qctx->client))
   9385  1.16  christos 	{
   9386  1.23  christos 		if (!qctx->fname->attributes.wildcard) {
   9387   1.1  christos 			dns_name_t *found;
   9388   1.1  christos 			dns_name_t *qname;
   9389   1.1  christos 			dns_fixedname_t fixed;
   9390   1.1  christos 			isc_buffer_t b;
   9391   1.1  christos 
   9392   1.1  christos 			found = dns_fixedname_initname(&fixed);
   9393   1.1  christos 			qname = qctx->client->query.qname;
   9394   1.1  christos 
   9395   1.1  christos 			query_findclosestnsec3(qname, qctx->db, qctx->version,
   9396   1.1  christos 					       qctx->client, qctx->rdataset,
   9397   1.1  christos 					       qctx->sigrdataset, qctx->fname,
   9398   1.3  christos 					       true, found);
   9399   1.1  christos 			/*
   9400   1.1  christos 			 * Did we find the closest provable encloser
   9401   1.1  christos 			 * instead? If so add the nearest to the
   9402   1.1  christos 			 * closest provable encloser.
   9403   1.1  christos 			 */
   9404   1.1  christos 			if (dns_rdataset_isassociated(qctx->rdataset) &&
   9405   1.1  christos 			    !dns_name_equal(qname, found) &&
   9406  1.23  christos 			    (((qctx->client->manager->sctx->options &
   9407   1.1  christos 			       NS_SERVER_NONEAREST) == 0) ||
   9408   1.1  christos 			     qctx->qtype == dns_rdatatype_ds))
   9409   1.1  christos 			{
   9410   1.1  christos 				unsigned int count;
   9411   1.1  christos 				unsigned int skip;
   9412   1.1  christos 
   9413   1.1  christos 				/*
   9414   1.1  christos 				 * Add the closest provable encloser.
   9415   1.1  christos 				 */
   9416   1.3  christos 				query_addrrset(qctx, &qctx->fname,
   9417   1.1  christos 					       &qctx->rdataset,
   9418   1.9  christos 					       &qctx->sigrdataset, qctx->dbuf,
   9419   1.1  christos 					       DNS_SECTION_AUTHORITY);
   9420   1.1  christos 
   9421   1.9  christos 				count = dns_name_countlabels(found) + 1;
   9422   1.9  christos 				skip = dns_name_countlabels(qname) - count;
   9423   1.9  christos 				dns_name_getlabelsequence(qname, skip, count,
   9424   1.1  christos 							  found);
   9425   1.1  christos 
   9426   1.1  christos 				fixfname(qctx->client, &qctx->fname,
   9427   1.1  christos 					 &qctx->dbuf, &b);
   9428   1.1  christos 				fixrdataset(qctx->client, &qctx->rdataset);
   9429   1.1  christos 				fixrdataset(qctx->client, &qctx->sigrdataset);
   9430   1.1  christos 				if (qctx->fname == NULL ||
   9431   1.1  christos 				    qctx->rdataset == NULL ||
   9432  1.16  christos 				    qctx->sigrdataset == NULL)
   9433  1.16  christos 				{
   9434   1.9  christos 					CCTRACE(ISC_LOG_ERROR, "query_sign_"
   9435   1.9  christos 							       "nodata: "
   9436   1.9  christos 							       "failure "
   9437   1.9  christos 							       "getting "
   9438   1.9  christos 							       "closest "
   9439   1.9  christos 							       "encloser");
   9440   1.3  christos 					QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   9441  1.23  christos 					return ns_query_done(qctx);
   9442   1.1  christos 				}
   9443   1.1  christos 				/*
   9444   1.1  christos 				 * 'nearest' doesn't exist so
   9445   1.3  christos 				 * 'exist' is set to false.
   9446   1.1  christos 				 */
   9447   1.9  christos 				query_findclosestnsec3(
   9448   1.9  christos 					found, qctx->db, qctx->version,
   9449   1.9  christos 					qctx->client, qctx->rdataset,
   9450   1.9  christos 					qctx->sigrdataset, qctx->fname, false,
   9451   1.9  christos 					NULL);
   9452   1.1  christos 			}
   9453   1.1  christos 		} else {
   9454   1.3  christos 			ns_client_releasename(qctx->client, &qctx->fname);
   9455   1.3  christos 			query_addwildcardproof(qctx, false, true);
   9456   1.1  christos 		}
   9457   1.1  christos 	}
   9458   1.1  christos 	if (dns_rdataset_isassociated(qctx->rdataset)) {
   9459   1.1  christos 		/*
   9460   1.1  christos 		 * If we've got a NSEC record, we need to save the
   9461   1.1  christos 		 * name now because we're going call query_addsoa()
   9462   1.1  christos 		 * below, and it needs to use the name buffer.
   9463   1.1  christos 		 */
   9464   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9465   1.1  christos 	} else if (qctx->fname != NULL) {
   9466   1.1  christos 		/*
   9467   1.1  christos 		 * We're not going to use fname, and need to release
   9468   1.1  christos 		 * our hold on the name buffer so query_addsoa()
   9469   1.1  christos 		 * may use it.
   9470   1.1  christos 		 */
   9471   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9472   1.1  christos 	}
   9473   1.1  christos 
   9474   1.1  christos 	/*
   9475   1.1  christos 	 * The RPZ SOA has already been added to the additional section
   9476   1.1  christos 	 * if this was an RPZ rewrite, but if it wasn't, add it now.
   9477   1.1  christos 	 */
   9478   1.1  christos 	if (!qctx->nxrewrite) {
   9479   1.9  christos 		result = query_addsoa(qctx, UINT32_MAX, DNS_SECTION_AUTHORITY);
   9480   1.1  christos 		if (result != ISC_R_SUCCESS) {
   9481   1.1  christos 			QUERY_ERROR(qctx, result);
   9482  1.23  christos 			return ns_query_done(qctx);
   9483   1.1  christos 		}
   9484   1.1  christos 	}
   9485   1.1  christos 
   9486   1.1  christos 	/*
   9487   1.1  christos 	 * Add NSEC record if we found one.
   9488   1.1  christos 	 */
   9489   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   9490  1.16  christos 	    dns_rdataset_isassociated(qctx->rdataset))
   9491  1.16  christos 	{
   9492   1.1  christos 		query_addnxrrsetnsec(qctx);
   9493   1.1  christos 	}
   9494   1.1  christos 
   9495  1.23  christos 	return ns_query_done(qctx);
   9496   1.1  christos }
   9497   1.1  christos 
   9498   1.1  christos static void
   9499   1.1  christos query_addnxrrsetnsec(query_ctx_t *qctx) {
   9500   1.1  christos 	ns_client_t *client = qctx->client;
   9501   1.1  christos 	dns_rdata_t sigrdata;
   9502   1.1  christos 	dns_rdata_rrsig_t sig;
   9503   1.1  christos 	unsigned int labels;
   9504   1.1  christos 	isc_buffer_t *dbuf, b;
   9505   1.1  christos 	dns_name_t *fname;
   9506   1.3  christos 	isc_result_t result;
   9507   1.1  christos 
   9508   1.1  christos 	INSIST(qctx->fname != NULL);
   9509   1.1  christos 
   9510  1.23  christos 	if (!qctx->fname->attributes.wildcard) {
   9511   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9512   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9513   1.1  christos 		return;
   9514   1.1  christos 	}
   9515   1.1  christos 
   9516   1.1  christos 	if (qctx->sigrdataset == NULL ||
   9517  1.16  christos 	    !dns_rdataset_isassociated(qctx->sigrdataset))
   9518  1.16  christos 	{
   9519   1.1  christos 		return;
   9520   1.1  christos 	}
   9521   1.1  christos 
   9522   1.1  christos 	if (dns_rdataset_first(qctx->sigrdataset) != ISC_R_SUCCESS) {
   9523   1.1  christos 		return;
   9524   1.1  christos 	}
   9525   1.1  christos 
   9526   1.1  christos 	dns_rdata_init(&sigrdata);
   9527   1.1  christos 	dns_rdataset_current(qctx->sigrdataset, &sigrdata);
   9528   1.3  christos 	result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
   9529   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9530   1.1  christos 
   9531   1.1  christos 	labels = dns_name_countlabels(qctx->fname);
   9532   1.1  christos 	if ((unsigned int)sig.labels + 1 >= labels) {
   9533   1.1  christos 		return;
   9534   1.1  christos 	}
   9535   1.1  christos 
   9536   1.3  christos 	query_addwildcardproof(qctx, true, false);
   9537   1.1  christos 
   9538   1.1  christos 	/*
   9539   1.1  christos 	 * We'll need some resources...
   9540   1.1  christos 	 */
   9541   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   9542   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   9543   1.1  christos 
   9544   1.1  christos 	dns_name_split(qctx->fname, sig.labels + 1, NULL, fname);
   9545   1.1  christos 	/* This will succeed, since we've stripped labels. */
   9546   1.1  christos 	RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname,
   9547   1.1  christos 					   NULL) == ISC_R_SUCCESS);
   9548   1.9  christos 	query_addrrset(qctx, &fname, &qctx->rdataset, &qctx->sigrdataset, dbuf,
   9549   1.9  christos 		       DNS_SECTION_AUTHORITY);
   9550   1.1  christos }
   9551   1.1  christos 
   9552   1.1  christos /*%
   9553   1.1  christos  * Handle NXDOMAIN and empty wildcard responses.
   9554   1.1  christos  */
   9555   1.1  christos static isc_result_t
   9556  1.18  christos query_nxdomain(query_ctx_t *qctx, isc_result_t result) {
   9557   1.1  christos 	dns_section_t section;
   9558   1.3  christos 	uint32_t ttl;
   9559  1.18  christos 	bool empty_wild = (result == DNS_R_EMPTYWILD);
   9560   1.1  christos 
   9561   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain");
   9562   1.9  christos 
   9563   1.3  christos 	CALL_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx);
   9564   1.3  christos 
   9565   1.1  christos 	INSIST(qctx->is_zone || REDIRECT(qctx->client));
   9566   1.1  christos 
   9567   1.1  christos 	if (!empty_wild) {
   9568  1.18  christos 		result = query_redirect(qctx, result);
   9569   1.9  christos 		if (result != ISC_R_COMPLETE) {
   9570  1.23  christos 			return result;
   9571   1.9  christos 		}
   9572   1.1  christos 	}
   9573   1.1  christos 
   9574   1.1  christos 	if (dns_rdataset_isassociated(qctx->rdataset)) {
   9575   1.1  christos 		/*
   9576   1.1  christos 		 * If we've got a NSEC record, we need to save the
   9577   1.1  christos 		 * name now because we're going call query_addsoa()
   9578   1.1  christos 		 * below, and it needs to use the name buffer.
   9579   1.1  christos 		 */
   9580   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9581   1.1  christos 	} else if (qctx->fname != NULL) {
   9582   1.1  christos 		/*
   9583   1.1  christos 		 * We're not going to use fname, and need to release
   9584   1.1  christos 		 * our hold on the name buffer so query_addsoa()
   9585   1.1  christos 		 * may use it.
   9586   1.1  christos 		 */
   9587   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9588   1.1  christos 	}
   9589   1.1  christos 
   9590   1.1  christos 	/*
   9591   1.1  christos 	 * Add SOA to the additional section if generated by a
   9592   1.1  christos 	 * RPZ rewrite.
   9593   1.1  christos 	 *
   9594   1.1  christos 	 * If the query was for a SOA record force the
   9595   1.1  christos 	 * ttl to zero so that it is possible for clients to find
   9596   1.1  christos 	 * the containing zone of an arbitrary name with a stub
   9597   1.1  christos 	 * resolver and not have it cached.
   9598   1.1  christos 	 */
   9599   1.1  christos 	section = qctx->nxrewrite ? DNS_SECTION_ADDITIONAL
   9600   1.1  christos 				  : DNS_SECTION_AUTHORITY;
   9601   1.3  christos 	ttl = UINT32_MAX;
   9602   1.1  christos 	if (!qctx->nxrewrite && qctx->qtype == dns_rdatatype_soa &&
   9603   1.1  christos 	    qctx->zone != NULL && dns_zone_getzeronosoattl(qctx->zone))
   9604   1.1  christos 	{
   9605   1.1  christos 		ttl = 0;
   9606   1.1  christos 	}
   9607  1.16  christos 	if (!qctx->nxrewrite ||
   9608  1.16  christos 	    (qctx->rpz_st != NULL && qctx->rpz_st->m.rpz->addsoa))
   9609  1.16  christos 	{
   9610   1.5  christos 		result = query_addsoa(qctx, ttl, section);
   9611   1.5  christos 		if (result != ISC_R_SUCCESS) {
   9612   1.5  christos 			QUERY_ERROR(qctx, result);
   9613  1.23  christos 			return ns_query_done(qctx);
   9614   1.5  christos 		}
   9615   1.1  christos 	}
   9616   1.1  christos 
   9617   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9618   1.1  christos 		/*
   9619   1.1  christos 		 * Add NSEC record if we found one.
   9620   1.1  christos 		 */
   9621   1.9  christos 		if (dns_rdataset_isassociated(qctx->rdataset)) {
   9622   1.9  christos 			query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9623   1.9  christos 				       &qctx->sigrdataset, NULL,
   9624   1.9  christos 				       DNS_SECTION_AUTHORITY);
   9625   1.9  christos 		}
   9626   1.3  christos 		query_addwildcardproof(qctx, false, false);
   9627   1.1  christos 	}
   9628   1.1  christos 
   9629   1.1  christos 	/*
   9630   1.1  christos 	 * Set message rcode.
   9631   1.1  christos 	 */
   9632   1.9  christos 	if (empty_wild) {
   9633   1.1  christos 		qctx->client->message->rcode = dns_rcode_noerror;
   9634   1.9  christos 	} else {
   9635   1.1  christos 		qctx->client->message->rcode = dns_rcode_nxdomain;
   9636   1.9  christos 	}
   9637   1.1  christos 
   9638  1.23  christos 	return ns_query_done(qctx);
   9639   1.3  christos 
   9640   1.9  christos cleanup:
   9641  1.23  christos 	return result;
   9642   1.1  christos }
   9643   1.1  christos 
   9644   1.1  christos /*
   9645   1.1  christos  * Handle both types of NXDOMAIN redirection, calling redirect()
   9646   1.1  christos  * (which implements type redirect zones) and redirect2() (which
   9647   1.1  christos  * implements recursive nxdomain-redirect lookups).
   9648   1.1  christos  *
   9649   1.1  christos  * Any result code other than ISC_R_COMPLETE means redirection was
   9650   1.1  christos  * successful and the result code should be returned up the call stack.
   9651   1.1  christos  *
   9652   1.1  christos  * ISC_R_COMPLETE means we reached the end of this function without
   9653   1.1  christos  * redirecting, so query processing should continue past it.
   9654   1.1  christos  */
   9655   1.1  christos static isc_result_t
   9656  1.18  christos query_redirect(query_ctx_t *qctx, isc_result_t saved_result) {
   9657   1.1  christos 	isc_result_t result;
   9658   1.1  christos 
   9659   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_redirect");
   9660   1.9  christos 
   9661   1.1  christos 	result = redirect(qctx->client, qctx->fname, qctx->rdataset,
   9662   1.9  christos 			  &qctx->node, &qctx->db, &qctx->version, qctx->type);
   9663   1.1  christos 	switch (result) {
   9664   1.1  christos 	case ISC_R_SUCCESS:
   9665   1.9  christos 		inc_stats(qctx->client, ns_statscounter_nxdomainredirect);
   9666  1.23  christos 		return query_prepresponse(qctx);
   9667   1.1  christos 	case DNS_R_NXRRSET:
   9668   1.3  christos 		qctx->redirected = true;
   9669   1.3  christos 		qctx->is_zone = true;
   9670  1.23  christos 		return query_nodata(qctx, DNS_R_NXRRSET);
   9671   1.1  christos 	case DNS_R_NCACHENXRRSET:
   9672   1.3  christos 		qctx->redirected = true;
   9673   1.3  christos 		qctx->is_zone = false;
   9674  1.23  christos 		return query_ncache(qctx, DNS_R_NCACHENXRRSET);
   9675   1.1  christos 	default:
   9676   1.1  christos 		break;
   9677   1.1  christos 	}
   9678   1.1  christos 
   9679   1.1  christos 	result = redirect2(qctx->client, qctx->fname, qctx->rdataset,
   9680   1.9  christos 			   &qctx->node, &qctx->db, &qctx->version, qctx->type,
   9681   1.9  christos 			   &qctx->is_zone);
   9682   1.1  christos 	switch (result) {
   9683   1.1  christos 	case ISC_R_SUCCESS:
   9684   1.9  christos 		inc_stats(qctx->client, ns_statscounter_nxdomainredirect);
   9685  1.23  christos 		return query_prepresponse(qctx);
   9686   1.1  christos 	case DNS_R_CONTINUE:
   9687   1.1  christos 		inc_stats(qctx->client,
   9688   1.1  christos 			  ns_statscounter_nxdomainredirect_rlookup);
   9689   1.1  christos 		SAVE(qctx->client->query.redirect.db, qctx->db);
   9690   1.1  christos 		SAVE(qctx->client->query.redirect.node, qctx->node);
   9691   1.1  christos 		SAVE(qctx->client->query.redirect.zone, qctx->zone);
   9692   1.1  christos 		qctx->client->query.redirect.qtype = qctx->qtype;
   9693   1.1  christos 		INSIST(qctx->rdataset != NULL);
   9694   1.1  christos 		SAVE(qctx->client->query.redirect.rdataset, qctx->rdataset);
   9695   1.1  christos 		SAVE(qctx->client->query.redirect.sigrdataset,
   9696   1.1  christos 		     qctx->sigrdataset);
   9697  1.18  christos 		qctx->client->query.redirect.result = saved_result;
   9698  1.20  christos 		dns_name_copy(qctx->fname, qctx->client->query.redirect.fname);
   9699   1.1  christos 		qctx->client->query.redirect.authoritative =
   9700   1.1  christos 			qctx->authoritative;
   9701   1.1  christos 		qctx->client->query.redirect.is_zone = qctx->is_zone;
   9702  1.23  christos 		return ns_query_done(qctx);
   9703   1.1  christos 	case DNS_R_NXRRSET:
   9704   1.3  christos 		qctx->redirected = true;
   9705   1.3  christos 		qctx->is_zone = true;
   9706  1.23  christos 		return query_nodata(qctx, DNS_R_NXRRSET);
   9707   1.1  christos 	case DNS_R_NCACHENXRRSET:
   9708   1.3  christos 		qctx->redirected = true;
   9709   1.3  christos 		qctx->is_zone = false;
   9710  1.23  christos 		return query_ncache(qctx, DNS_R_NCACHENXRRSET);
   9711   1.1  christos 	default:
   9712   1.1  christos 		break;
   9713   1.1  christos 	}
   9714   1.1  christos 
   9715  1.23  christos 	return ISC_R_COMPLETE;
   9716   1.1  christos }
   9717   1.1  christos 
   9718   1.1  christos /*%
   9719   1.1  christos  * Logging function to be passed to dns_nsec_noexistnodata.
   9720   1.1  christos  */
   9721   1.1  christos static void
   9722   1.1  christos log_noexistnodata(void *val, int level, const char *fmt, ...) {
   9723   1.1  christos 	query_ctx_t *qctx = val;
   9724   1.1  christos 	va_list ap;
   9725   1.1  christos 
   9726   1.1  christos 	va_start(ap, fmt);
   9727   1.9  christos 	ns_client_logv(qctx->client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
   9728   1.9  christos 		       level, fmt, ap);
   9729   1.1  christos 	va_end(ap);
   9730   1.1  christos }
   9731   1.1  christos 
   9732   1.1  christos static dns_ttl_t
   9733   1.1  christos query_synthttl(dns_rdataset_t *soardataset, dns_rdataset_t *sigsoardataset,
   9734   1.1  christos 	       dns_rdataset_t *p1rdataset, dns_rdataset_t *sigp1rdataset,
   9735   1.9  christos 	       dns_rdataset_t *p2rdataset, dns_rdataset_t *sigp2rdataset) {
   9736   1.1  christos 	dns_rdata_soa_t soa;
   9737   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   9738   1.1  christos 	dns_ttl_t ttl;
   9739   1.1  christos 	isc_result_t result;
   9740   1.1  christos 
   9741   1.1  christos 	REQUIRE(soardataset != NULL);
   9742   1.1  christos 	REQUIRE(sigsoardataset != NULL);
   9743   1.1  christos 	REQUIRE(p1rdataset != NULL);
   9744   1.1  christos 	REQUIRE(sigp1rdataset != NULL);
   9745   1.1  christos 
   9746   1.1  christos 	result = dns_rdataset_first(soardataset);
   9747   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9748   1.1  christos 	dns_rdataset_current(soardataset, &rdata);
   9749   1.3  christos 	result = dns_rdata_tostruct(&rdata, &soa, NULL);
   9750   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9751   1.1  christos 
   9752   1.1  christos 	ttl = ISC_MIN(soa.minimum, soardataset->ttl);
   9753   1.1  christos 	ttl = ISC_MIN(ttl, sigsoardataset->ttl);
   9754   1.1  christos 	ttl = ISC_MIN(ttl, p1rdataset->ttl);
   9755   1.1  christos 	ttl = ISC_MIN(ttl, sigp1rdataset->ttl);
   9756   1.9  christos 	if (p2rdataset != NULL) {
   9757   1.1  christos 		ttl = ISC_MIN(ttl, p2rdataset->ttl);
   9758   1.9  christos 	}
   9759   1.9  christos 	if (sigp2rdataset != NULL) {
   9760   1.1  christos 		ttl = ISC_MIN(ttl, sigp2rdataset->ttl);
   9761   1.9  christos 	}
   9762   1.1  christos 
   9763  1.23  christos 	return ttl;
   9764   1.1  christos }
   9765   1.1  christos 
   9766   1.1  christos /*
   9767   1.1  christos  * Synthesize a NODATA response from the SOA and covering NSEC in cache.
   9768   1.1  christos  */
   9769   1.1  christos static isc_result_t
   9770   1.1  christos query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer,
   9771   1.1  christos 		  dns_rdataset_t **soardatasetp,
   9772   1.9  christos 		  dns_rdataset_t **sigsoardatasetp) {
   9773   1.1  christos 	dns_name_t *name = NULL;
   9774   1.1  christos 	dns_ttl_t ttl;
   9775   1.1  christos 	isc_buffer_t *dbuf, b;
   9776   1.1  christos 
   9777   1.1  christos 	/*
   9778   1.9  christos 	 * Determine the correct TTL to use for the SOA and RRSIG
   9779   1.1  christos 	 */
   9780   1.9  christos 	ttl = query_synthttl(*soardatasetp, *sigsoardatasetp, qctx->rdataset,
   9781   1.9  christos 			     qctx->sigrdataset, NULL, NULL);
   9782   1.1  christos 	(*soardatasetp)->ttl = (*sigsoardatasetp)->ttl = ttl;
   9783   1.1  christos 
   9784   1.1  christos 	/*
   9785   1.1  christos 	 * We want the SOA record to be first, so save the
   9786   1.1  christos 	 * NODATA proof's name now or else discard it.
   9787   1.1  christos 	 */
   9788   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9789   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9790   1.1  christos 	} else {
   9791   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9792   1.1  christos 	}
   9793   1.1  christos 
   9794   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   9795   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   9796  1.20  christos 	dns_name_copy(signer, name);
   9797   1.1  christos 
   9798   1.1  christos 	/*
   9799   1.1  christos 	 * Add SOA record. Omit the RRSIG if DNSSEC was not requested.
   9800   1.1  christos 	 */
   9801   1.1  christos 	if (!WANTDNSSEC(qctx->client)) {
   9802   1.1  christos 		sigsoardatasetp = NULL;
   9803   1.1  christos 	}
   9804   1.9  christos 	query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf,
   9805   1.9  christos 		       DNS_SECTION_AUTHORITY);
   9806   1.1  christos 
   9807   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9808   1.1  christos 		/*
   9809   1.1  christos 		 * Add NODATA proof.
   9810   1.1  christos 		 */
   9811   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9812   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9813   1.1  christos 	}
   9814   1.1  christos 
   9815   1.1  christos 	inc_stats(qctx->client, ns_statscounter_nodatasynth);
   9816   1.1  christos 
   9817   1.1  christos 	if (name != NULL) {
   9818   1.3  christos 		ns_client_releasename(qctx->client, &name);
   9819   1.1  christos 	}
   9820  1.23  christos 	return ISC_R_SUCCESS;
   9821   1.1  christos }
   9822   1.1  christos 
   9823   1.1  christos /*
   9824   1.1  christos  * Synthesize a wildcard answer using the contents of 'rdataset'.
   9825   1.1  christos  * qctx contains the NODATA proof.
   9826   1.1  christos  */
   9827   1.1  christos static isc_result_t
   9828   1.1  christos query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
   9829   1.9  christos 		    dns_rdataset_t *sigrdataset) {
   9830   1.1  christos 	dns_name_t *name = NULL;
   9831   1.1  christos 	isc_buffer_t *dbuf, b;
   9832   1.3  christos 	dns_rdataset_t *cloneset = NULL, *clonesigset = NULL;
   9833   1.1  christos 	dns_rdataset_t **sigrdatasetp;
   9834   1.1  christos 
   9835   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_synthwildcard");
   9836   1.9  christos 
   9837   1.1  christos 	/*
   9838   1.1  christos 	 * We want the answer to be first, so save the
   9839   1.1  christos 	 * NOQNAME proof's name now or else discard it.
   9840   1.1  christos 	 */
   9841   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9842   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9843   1.1  christos 	} else {
   9844   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9845   1.1  christos 	}
   9846   1.1  christos 
   9847   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   9848   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   9849  1.20  christos 	dns_name_copy(qctx->client->query.qname, name);
   9850   1.1  christos 
   9851   1.3  christos 	cloneset = ns_client_newrdataset(qctx->client);
   9852   1.3  christos 	dns_rdataset_clone(rdataset, cloneset);
   9853   1.1  christos 
   9854   1.1  christos 	/*
   9855   1.1  christos 	 * Add answer RRset. Omit the RRSIG if DNSSEC was not requested.
   9856   1.1  christos 	 */
   9857   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9858   1.3  christos 		clonesigset = ns_client_newrdataset(qctx->client);
   9859   1.3  christos 		dns_rdataset_clone(sigrdataset, clonesigset);
   9860   1.3  christos 		sigrdatasetp = &clonesigset;
   9861   1.1  christos 	} else {
   9862   1.1  christos 		sigrdatasetp = NULL;
   9863   1.1  christos 	}
   9864   1.1  christos 
   9865   1.9  christos 	query_addrrset(qctx, &name, &cloneset, sigrdatasetp, dbuf,
   9866   1.9  christos 		       DNS_SECTION_ANSWER);
   9867   1.1  christos 
   9868   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9869   1.1  christos 		/*
   9870   1.1  christos 		 * Add NOQNAME proof.
   9871   1.1  christos 		 */
   9872   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9873   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9874   1.1  christos 	}
   9875   1.1  christos 
   9876   1.1  christos 	inc_stats(qctx->client, ns_statscounter_wildcardsynth);
   9877   1.1  christos 
   9878   1.1  christos 	if (name != NULL) {
   9879   1.3  christos 		ns_client_releasename(qctx->client, &name);
   9880   1.1  christos 	}
   9881   1.3  christos 	if (cloneset != NULL) {
   9882   1.3  christos 		ns_client_putrdataset(qctx->client, &cloneset);
   9883   1.1  christos 	}
   9884   1.3  christos 	if (clonesigset != NULL) {
   9885   1.3  christos 		ns_client_putrdataset(qctx->client, &clonesigset);
   9886   1.1  christos 	}
   9887  1.23  christos 	return ISC_R_SUCCESS;
   9888   1.1  christos }
   9889   1.1  christos 
   9890   1.1  christos /*
   9891   1.1  christos  * Add a synthesized CNAME record from the wildard RRset (rdataset)
   9892   1.1  christos  * and NODATA proof by calling query_synthwildcard then setup to
   9893   1.1  christos  * follow the CNAME.
   9894   1.1  christos  */
   9895   1.1  christos static isc_result_t
   9896   1.1  christos query_synthcnamewildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
   9897   1.9  christos 			 dns_rdataset_t *sigrdataset) {
   9898   1.1  christos 	isc_result_t result;
   9899   1.1  christos 	dns_name_t *tname = NULL;
   9900   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   9901   1.1  christos 	dns_rdata_cname_t cname;
   9902   1.1  christos 
   9903   1.1  christos 	result = query_synthwildcard(qctx, rdataset, sigrdataset);
   9904   1.1  christos 	if (result != ISC_R_SUCCESS) {
   9905  1.23  christos 		return result;
   9906   1.1  christos 	}
   9907   1.1  christos 
   9908   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   9909   1.1  christos 
   9910   1.1  christos 	/*
   9911   1.1  christos 	 * Reset qname to be the target name of the CNAME and restart
   9912   1.1  christos 	 * the query.
   9913   1.1  christos 	 */
   9914  1.23  christos 	dns_message_gettempname(qctx->client->message, &tname);
   9915   1.1  christos 
   9916   1.1  christos 	result = dns_rdataset_first(rdataset);
   9917   1.1  christos 	if (result != ISC_R_SUCCESS) {
   9918   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   9919  1.23  christos 		return result;
   9920   1.1  christos 	}
   9921   1.1  christos 
   9922   1.1  christos 	dns_rdataset_current(rdataset, &rdata);
   9923   1.1  christos 	result = dns_rdata_tostruct(&rdata, &cname, NULL);
   9924   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9925   1.1  christos 	dns_rdata_reset(&rdata);
   9926   1.1  christos 
   9927  1.20  christos 	if (dns_name_equal(qctx->client->query.qname, &cname.cname)) {
   9928  1.20  christos 		dns_message_puttempname(qctx->client->message, &tname);
   9929  1.20  christos 		dns_rdata_freestruct(&cname);
   9930  1.23  christos 		return ISC_R_SUCCESS;
   9931  1.20  christos 	}
   9932  1.20  christos 
   9933  1.20  christos 	dns_name_copy(&cname.cname, tname);
   9934   1.1  christos 
   9935   1.1  christos 	dns_rdata_freestruct(&cname);
   9936   1.1  christos 	ns_client_qnamereplace(qctx->client, tname);
   9937   1.3  christos 	qctx->want_restart = true;
   9938   1.1  christos 	if (!WANTRECURSION(qctx->client)) {
   9939  1.23  christos 		qctx->options.nolog = true;
   9940   1.1  christos 	}
   9941   1.1  christos 
   9942  1.23  christos 	return result;
   9943   1.1  christos }
   9944   1.1  christos 
   9945   1.1  christos /*
   9946  1.20  christos  * Synthesize a NXDOMAIN or NODATA response from qctx (which contains the
   9947  1.20  christos  * NOQNAME proof), nowild + nowildrdataset + signowildrdataset (which
   9948  1.20  christos  * contains the NOWILDCARD proof or NODATA at wildcard) and
   9949  1.20  christos  * signer + soardatasetp + sigsoardatasetp which contain the
   9950  1.20  christos  * SOA record + RRSIG for the negative answer.
   9951   1.1  christos  */
   9952   1.1  christos static isc_result_t
   9953  1.20  christos query_synthnxdomainnodata(query_ctx_t *qctx, bool nodata, dns_name_t *nowild,
   9954  1.20  christos 			  dns_rdataset_t *nowildrdataset,
   9955  1.20  christos 			  dns_rdataset_t *signowildrdataset, dns_name_t *signer,
   9956  1.20  christos 			  dns_rdataset_t **soardatasetp,
   9957  1.20  christos 			  dns_rdataset_t **sigsoardatasetp) {
   9958   1.1  christos 	dns_name_t *name = NULL;
   9959   1.1  christos 	dns_ttl_t ttl;
   9960   1.1  christos 	isc_buffer_t *dbuf, b;
   9961   1.3  christos 	dns_rdataset_t *cloneset = NULL, *clonesigset = NULL;
   9962   1.1  christos 
   9963   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_synthnxdomain");
   9964   1.9  christos 
   9965   1.1  christos 	/*
   9966   1.9  christos 	 * Determine the correct TTL to use for the SOA and RRSIG
   9967   1.1  christos 	 */
   9968   1.9  christos 	ttl = query_synthttl(*soardatasetp, *sigsoardatasetp, qctx->rdataset,
   9969   1.9  christos 			     qctx->sigrdataset, nowildrdataset,
   9970   1.9  christos 			     signowildrdataset);
   9971   1.1  christos 	(*soardatasetp)->ttl = (*sigsoardatasetp)->ttl = ttl;
   9972   1.1  christos 
   9973   1.1  christos 	/*
   9974   1.1  christos 	 * We want the SOA record to be first, so save the
   9975   1.1  christos 	 * NOQNAME proof's name now or else discard it.
   9976   1.1  christos 	 */
   9977   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9978   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9979   1.1  christos 	} else {
   9980   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9981   1.1  christos 	}
   9982   1.1  christos 
   9983   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   9984   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   9985  1.20  christos 	dns_name_copy(signer, name);
   9986   1.1  christos 
   9987   1.1  christos 	/*
   9988   1.1  christos 	 * Add SOA record. Omit the RRSIG if DNSSEC was not requested.
   9989   1.1  christos 	 */
   9990   1.1  christos 	if (!WANTDNSSEC(qctx->client)) {
   9991   1.1  christos 		sigsoardatasetp = NULL;
   9992   1.1  christos 	}
   9993   1.9  christos 	query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf,
   9994   1.9  christos 		       DNS_SECTION_AUTHORITY);
   9995   1.1  christos 
   9996   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9997   1.1  christos 		/*
   9998   1.1  christos 		 * Add NOQNAME proof.
   9999   1.1  christos 		 */
   10000   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   10001   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   10002   1.1  christos 
   10003   1.3  christos 		dbuf = ns_client_getnamebuf(qctx->client);
   10004   1.3  christos 		name = ns_client_newname(qctx->client, dbuf, &b);
   10005  1.20  christos 		dns_name_copy(nowild, name);
   10006   1.1  christos 
   10007   1.3  christos 		cloneset = ns_client_newrdataset(qctx->client);
   10008   1.3  christos 		clonesigset = ns_client_newrdataset(qctx->client);
   10009   1.1  christos 
   10010   1.3  christos 		dns_rdataset_clone(nowildrdataset, cloneset);
   10011   1.3  christos 		dns_rdataset_clone(signowildrdataset, clonesigset);
   10012   1.1  christos 
   10013   1.1  christos 		/*
   10014   1.1  christos 		 * Add NOWILDCARD proof.
   10015   1.1  christos 		 */
   10016   1.9  christos 		query_addrrset(qctx, &name, &cloneset, &clonesigset, dbuf,
   10017   1.9  christos 			       DNS_SECTION_AUTHORITY);
   10018   1.1  christos 	}
   10019   1.1  christos 
   10020  1.20  christos 	if (nodata) {
   10021  1.20  christos 		inc_stats(qctx->client, ns_statscounter_nodatasynth);
   10022  1.20  christos 	} else {
   10023  1.20  christos 		qctx->client->message->rcode = dns_rcode_nxdomain;
   10024  1.20  christos 		inc_stats(qctx->client, ns_statscounter_nxdomainsynth);
   10025  1.20  christos 	}
   10026   1.1  christos 
   10027   1.1  christos 	if (name != NULL) {
   10028   1.3  christos 		ns_client_releasename(qctx->client, &name);
   10029   1.1  christos 	}
   10030   1.3  christos 	if (cloneset != NULL) {
   10031   1.3  christos 		ns_client_putrdataset(qctx->client, &cloneset);
   10032   1.1  christos 	}
   10033   1.3  christos 	if (clonesigset != NULL) {
   10034   1.3  christos 		ns_client_putrdataset(qctx->client, &clonesigset);
   10035   1.1  christos 	}
   10036  1.23  christos 	return ISC_R_SUCCESS;
   10037   1.1  christos }
   10038   1.1  christos 
   10039   1.1  christos /*
   10040   1.1  christos  * Check that all signer names in sigrdataset match the expected signer.
   10041   1.1  christos  */
   10042   1.1  christos static isc_result_t
   10043   1.1  christos checksignames(dns_name_t *signer, dns_rdataset_t *sigrdataset) {
   10044   1.1  christos 	isc_result_t result;
   10045   1.1  christos 
   10046   1.9  christos 	for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
   10047   1.9  christos 	     result = dns_rdataset_next(sigrdataset))
   10048   1.9  christos 	{
   10049   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   10050   1.1  christos 		dns_rdata_rrsig_t rrsig;
   10051   1.1  christos 
   10052   1.1  christos 		dns_rdataset_current(sigrdataset, &rdata);
   10053   1.1  christos 		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
   10054   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10055   1.1  christos 		if (dns_name_countlabels(signer) == 0) {
   10056  1.20  christos 			dns_name_copy(&rrsig.signer, signer);
   10057   1.1  christos 		} else if (!dns_name_equal(signer, &rrsig.signer)) {
   10058  1.23  christos 			return ISC_R_FAILURE;
   10059   1.1  christos 		}
   10060   1.1  christos 	}
   10061   1.1  christos 
   10062  1.23  christos 	return ISC_R_SUCCESS;
   10063   1.1  christos }
   10064   1.1  christos 
   10065   1.1  christos /*%
   10066   1.1  christos  * Handle covering NSEC responses.
   10067   1.1  christos  *
   10068   1.9  christos  * Verify the NSEC record is appropriate for the QNAME; if not,
   10069   1.1  christos  * redo the initial query without DNS_DBFIND_COVERINGNSEC.
   10070   1.1  christos  *
   10071   1.1  christos  * If the covering NSEC proves that the name exists but not the type,
   10072   1.1  christos  * synthesize a NODATA response.
   10073   1.1  christos  *
   10074   1.1  christos  * If the name doesn't exist, compute the wildcard record and check whether
   10075   1.1  christos  * the wildcard name exists or not.  If we can't determine this, redo the
   10076   1.1  christos  * initial query without DNS_DBFIND_COVERINGNSEC.
   10077   1.1  christos  *
   10078   1.1  christos  * If the wildcard name does not exist, compute the SOA name and look that
   10079   1.1  christos  * up.  If the SOA record does not exist, redo the initial query without
   10080   1.1  christos  * DNS_DBFIND_COVERINGNSEC.  If the SOA record exists, synthesize an
   10081   1.1  christos  * NXDOMAIN response from the found records.
   10082   1.1  christos  *
   10083   1.1  christos  * If the wildcard name does exist, perform a lookup for the requested
   10084   1.1  christos  * type at the wildcard name.
   10085   1.1  christos  */
   10086   1.1  christos static isc_result_t
   10087   1.1  christos query_coveringnsec(query_ctx_t *qctx) {
   10088   1.1  christos 	dns_db_t *db = NULL;
   10089   1.1  christos 	dns_clientinfo_t ci;
   10090   1.1  christos 	dns_clientinfomethods_t cm;
   10091   1.1  christos 	dns_dbnode_t *node = NULL;
   10092   1.1  christos 	dns_fixedname_t fixed;
   10093  1.20  christos 	dns_fixedname_t fnamespace;
   10094   1.1  christos 	dns_fixedname_t fnowild;
   10095   1.1  christos 	dns_fixedname_t fsigner;
   10096   1.1  christos 	dns_fixedname_t fwild;
   10097   1.1  christos 	dns_name_t *fname = NULL;
   10098  1.20  christos 	dns_name_t *namespace = NULL;
   10099   1.1  christos 	dns_name_t *nowild = NULL;
   10100   1.1  christos 	dns_name_t *signer = NULL;
   10101   1.1  christos 	dns_name_t *wild = NULL;
   10102  1.20  christos 	dns_name_t qname;
   10103   1.1  christos 	dns_rdataset_t *soardataset = NULL, *sigsoardataset = NULL;
   10104   1.1  christos 	dns_rdataset_t rdataset, sigrdataset;
   10105   1.3  christos 	bool done = false;
   10106   1.3  christos 	bool exists = true, data = true;
   10107   1.3  christos 	bool redirected = false;
   10108   1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   10109   1.1  christos 	unsigned int dboptions = qctx->client->query.dboptions;
   10110  1.20  christos 	unsigned int labels;
   10111   1.1  christos 
   10112   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_coveringnsec");
   10113   1.9  christos 
   10114  1.20  christos 	dns_name_init(&qname, NULL);
   10115   1.1  christos 	dns_rdataset_init(&rdataset);
   10116   1.1  christos 	dns_rdataset_init(&sigrdataset);
   10117  1.20  christos 	namespace = dns_fixedname_initname(&fnamespace);
   10118  1.20  christos 
   10119  1.20  christos 	/*
   10120  1.20  christos 	 * Check that the NSEC record is from the correct namespace.
   10121  1.20  christos 	 * For records that belong to the parent zone (i.e. DS),
   10122  1.20  christos 	 * remove a label to find the correct namespace.
   10123  1.20  christos 	 */
   10124  1.20  christos 	dns_name_clone(qctx->client->query.qname, &qname);
   10125  1.20  christos 	labels = dns_name_countlabels(&qname);
   10126  1.20  christos 	if (dns_rdatatype_atparent(qctx->qtype) && labels > 1) {
   10127  1.20  christos 		dns_name_getlabelsequence(&qname, 1, labels - 1, &qname);
   10128  1.20  christos 	}
   10129  1.20  christos 	dns_view_sfd_find(qctx->view, &qname, namespace);
   10130  1.20  christos 	if (!dns_name_issubdomain(qctx->fname, namespace)) {
   10131  1.20  christos 		goto cleanup;
   10132  1.20  christos 	}
   10133   1.1  christos 
   10134   1.1  christos 	/*
   10135   1.1  christos 	 * If we have no signer name, stop immediately.
   10136   1.1  christos 	 */
   10137   1.1  christos 	if (!dns_rdataset_isassociated(qctx->sigrdataset)) {
   10138   1.1  christos 		goto cleanup;
   10139   1.1  christos 	}
   10140   1.1  christos 
   10141   1.1  christos 	wild = dns_fixedname_initname(&fwild);
   10142   1.1  christos 	fname = dns_fixedname_initname(&fixed);
   10143   1.1  christos 	signer = dns_fixedname_initname(&fsigner);
   10144   1.1  christos 	nowild = dns_fixedname_initname(&fnowild);
   10145   1.1  christos 
   10146   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   10147  1.20  christos 	dns_clientinfo_init(&ci, qctx->client, NULL);
   10148   1.1  christos 
   10149   1.1  christos 	/*
   10150   1.1  christos 	 * All signer names must be the same to accept.
   10151   1.1  christos 	 */
   10152   1.1  christos 	result = checksignames(signer, qctx->sigrdataset);
   10153   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10154   1.1  christos 		result = ISC_R_SUCCESS;
   10155   1.1  christos 		goto cleanup;
   10156   1.1  christos 	}
   10157   1.1  christos 
   10158   1.1  christos 	/*
   10159  1.20  christos 	 * If NSEC or RRSIG are missing from the type map
   10160  1.20  christos 	 * reject the NSEC RRset.
   10161  1.20  christos 	 */
   10162  1.20  christos 	if (!dns_nsec_requiredtypespresent(qctx->rdataset)) {
   10163  1.20  christos 		goto cleanup;
   10164  1.20  christos 	}
   10165  1.20  christos 
   10166  1.20  christos 	/*
   10167   1.1  christos 	 * Check that we have the correct NOQNAME NSEC record.
   10168   1.1  christos 	 */
   10169   1.1  christos 	result = dns_nsec_noexistnodata(qctx->qtype, qctx->client->query.qname,
   10170   1.9  christos 					qctx->fname, qctx->rdataset, &exists,
   10171   1.9  christos 					&data, wild, log_noexistnodata, qctx);
   10172   1.1  christos 
   10173   1.1  christos 	if (result != ISC_R_SUCCESS || (exists && data)) {
   10174   1.1  christos 		goto cleanup;
   10175   1.1  christos 	}
   10176   1.1  christos 
   10177   1.1  christos 	if (exists) {
   10178   1.9  christos 		if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
   10179   1.1  christos 			goto cleanup;
   10180   1.1  christos 		}
   10181   1.3  christos 		if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
   10182   1.1  christos 		    (qctx->type == dns_rdatatype_a ||
   10183   1.1  christos 		     qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
   10184   1.1  christos 		{
   10185   1.1  christos 			goto cleanup;
   10186   1.1  christos 		}
   10187   1.1  christos 		if (!qctx->resuming && !STALE(qctx->rdataset) &&
   10188   1.1  christos 		    qctx->rdataset->ttl == 0 && RECURSIONOK(qctx->client))
   10189   1.1  christos 		{
   10190   1.1  christos 			goto cleanup;
   10191   1.1  christos 		}
   10192   1.1  christos 
   10193   1.3  christos 		soardataset = ns_client_newrdataset(qctx->client);
   10194   1.3  christos 		sigsoardataset = ns_client_newrdataset(qctx->client);
   10195   1.1  christos 
   10196   1.1  christos 		/*
   10197   1.1  christos 		 * Look for SOA record to construct NODATA response.
   10198   1.1  christos 		 */
   10199   1.1  christos 		dns_db_attach(qctx->db, &db);
   10200   1.1  christos 		result = dns_db_findext(db, signer, qctx->version,
   10201   1.1  christos 					dns_rdatatype_soa, dboptions,
   10202   1.9  christos 					qctx->client->now, &node, fname, &cm,
   10203   1.9  christos 					&ci, soardataset, sigsoardataset);
   10204   1.1  christos 
   10205   1.1  christos 		if (result != ISC_R_SUCCESS) {
   10206   1.1  christos 			goto cleanup;
   10207   1.1  christos 		}
   10208   1.9  christos 		(void)query_synthnodata(qctx, signer, &soardataset,
   10209   1.9  christos 					&sigsoardataset);
   10210   1.3  christos 		done = true;
   10211   1.1  christos 		goto cleanup;
   10212   1.1  christos 	}
   10213   1.1  christos 
   10214   1.1  christos 	/*
   10215   1.1  christos 	 * Look up the no-wildcard proof.
   10216   1.1  christos 	 */
   10217   1.1  christos 	dns_db_attach(qctx->db, &db);
   10218   1.1  christos 	result = dns_db_findext(db, wild, qctx->version, qctx->type,
   10219   1.1  christos 				dboptions | DNS_DBFIND_COVERINGNSEC,
   10220   1.9  christos 				qctx->client->now, &node, nowild, &cm, &ci,
   10221   1.9  christos 				&rdataset, &sigrdataset);
   10222   1.1  christos 
   10223   1.1  christos 	if (rdataset.trust != dns_trust_secure ||
   10224  1.16  christos 	    sigrdataset.trust != dns_trust_secure)
   10225  1.16  christos 	{
   10226   1.1  christos 		goto cleanup;
   10227   1.1  christos 	}
   10228   1.1  christos 
   10229   1.1  christos 	/*
   10230   1.1  christos 	 * Zero TTL handling of wildcard record.
   10231   1.1  christos 	 *
   10232   1.3  christos 	 * We don't yet have code to handle synthesis and type ANY or dns64
   10233   1.3  christos 	 * processing so we abort the synthesis here if there would be a
   10234   1.3  christos 	 * interaction.
   10235   1.1  christos 	 */
   10236   1.1  christos 	switch (result) {
   10237   1.1  christos 	case ISC_R_SUCCESS:
   10238   1.9  christos 		if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
   10239   1.1  christos 			goto cleanup;
   10240   1.1  christos 		}
   10241   1.3  christos 		if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
   10242   1.1  christos 		    (qctx->type == dns_rdatatype_a ||
   10243   1.1  christos 		     qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
   10244   1.1  christos 		{
   10245   1.1  christos 			goto cleanup;
   10246   1.1  christos 		}
   10247  1.15  christos 		FALLTHROUGH;
   10248   1.1  christos 	case DNS_R_CNAME:
   10249   1.9  christos 		if (!qctx->resuming && !STALE(&rdataset) && rdataset.ttl == 0 &&
   10250   1.9  christos 		    RECURSIONOK(qctx->client))
   10251   1.1  christos 		{
   10252   1.1  christos 			goto cleanup;
   10253   1.1  christos 		}
   10254   1.1  christos 	default:
   10255   1.1  christos 		break;
   10256   1.1  christos 	}
   10257   1.1  christos 
   10258   1.1  christos 	switch (result) {
   10259   1.1  christos 	case DNS_R_COVERINGNSEC:
   10260  1.20  christos 		/*
   10261  1.20  christos 		 * Check that the covering NSEC record is from the right
   10262  1.20  christos 		 * namespace.
   10263  1.20  christos 		 */
   10264  1.20  christos 		if (!dns_name_issubdomain(nowild, namespace)) {
   10265  1.20  christos 			goto cleanup;
   10266  1.20  christos 		}
   10267   1.9  christos 		result = dns_nsec_noexistnodata(qctx->qtype, wild, nowild,
   10268   1.9  christos 						&rdataset, &exists, &data, NULL,
   10269   1.1  christos 						log_noexistnodata, qctx);
   10270  1.20  christos 		if (result != ISC_R_SUCCESS || (exists && data)) {
   10271   1.1  christos 			goto cleanup;
   10272   1.1  christos 		}
   10273   1.1  christos 		break;
   10274   1.9  christos 	case ISC_R_SUCCESS: /* wild card match */
   10275   1.1  christos 		(void)query_synthwildcard(qctx, &rdataset, &sigrdataset);
   10276   1.3  christos 		done = true;
   10277   1.1  christos 		goto cleanup;
   10278   1.9  christos 	case DNS_R_CNAME: /* wild card cname */
   10279   1.1  christos 		(void)query_synthcnamewildcard(qctx, &rdataset, &sigrdataset);
   10280   1.3  christos 		done = true;
   10281   1.1  christos 		goto cleanup;
   10282   1.9  christos 	case DNS_R_NCACHENXRRSET:  /* wild card nodata */
   10283   1.9  christos 	case DNS_R_NCACHENXDOMAIN: /* direct nxdomain */
   10284   1.1  christos 	default:
   10285   1.1  christos 		goto cleanup;
   10286   1.1  christos 	}
   10287   1.1  christos 
   10288   1.1  christos 	/*
   10289   1.1  christos 	 * We now have the proof that we have an NXDOMAIN.  Apply
   10290   1.1  christos 	 * NXDOMAIN redirection if configured.
   10291   1.1  christos 	 */
   10292  1.18  christos 	result = query_redirect(qctx, DNS_R_COVERINGNSEC);
   10293   1.1  christos 	if (result != ISC_R_COMPLETE) {
   10294   1.3  christos 		redirected = true;
   10295   1.1  christos 		goto cleanup;
   10296   1.1  christos 	}
   10297   1.1  christos 
   10298   1.1  christos 	/*
   10299   1.1  christos 	 * Must be signed to accept.
   10300   1.1  christos 	 */
   10301   1.1  christos 	if (!dns_rdataset_isassociated(&sigrdataset)) {
   10302   1.1  christos 		goto cleanup;
   10303   1.1  christos 	}
   10304   1.1  christos 
   10305   1.1  christos 	/*
   10306   1.1  christos 	 * Check signer signer names again.
   10307   1.1  christos 	 */
   10308   1.1  christos 	result = checksignames(signer, &sigrdataset);
   10309   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10310   1.1  christos 		result = ISC_R_SUCCESS;
   10311   1.1  christos 		goto cleanup;
   10312   1.1  christos 	}
   10313   1.1  christos 
   10314   1.1  christos 	if (node != NULL) {
   10315   1.1  christos 		dns_db_detachnode(db, &node);
   10316   1.1  christos 	}
   10317   1.1  christos 
   10318   1.3  christos 	soardataset = ns_client_newrdataset(qctx->client);
   10319   1.3  christos 	sigsoardataset = ns_client_newrdataset(qctx->client);
   10320   1.1  christos 
   10321   1.1  christos 	/*
   10322   1.1  christos 	 * Look for SOA record to construct NXDOMAIN response.
   10323   1.1  christos 	 */
   10324   1.9  christos 	result = dns_db_findext(db, signer, qctx->version, dns_rdatatype_soa,
   10325   1.9  christos 				dboptions, qctx->client->now, &node, fname, &cm,
   10326   1.9  christos 				&ci, soardataset, sigsoardataset);
   10327   1.1  christos 
   10328   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10329   1.1  christos 		goto cleanup;
   10330   1.1  christos 	}
   10331  1.20  christos 	(void)query_synthnxdomainnodata(qctx, exists, nowild, &rdataset,
   10332  1.20  christos 					&sigrdataset, signer, &soardataset,
   10333  1.20  christos 					&sigsoardataset);
   10334   1.3  christos 	done = true;
   10335   1.1  christos 
   10336   1.9  christos cleanup:
   10337   1.1  christos 	if (dns_rdataset_isassociated(&rdataset)) {
   10338   1.1  christos 		dns_rdataset_disassociate(&rdataset);
   10339   1.1  christos 	}
   10340   1.1  christos 	if (dns_rdataset_isassociated(&sigrdataset)) {
   10341   1.1  christos 		dns_rdataset_disassociate(&sigrdataset);
   10342   1.1  christos 	}
   10343   1.1  christos 	if (soardataset != NULL) {
   10344   1.3  christos 		ns_client_putrdataset(qctx->client, &soardataset);
   10345   1.1  christos 	}
   10346   1.1  christos 	if (sigsoardataset != NULL) {
   10347   1.3  christos 		ns_client_putrdataset(qctx->client, &sigsoardataset);
   10348   1.1  christos 	}
   10349   1.1  christos 	if (db != NULL) {
   10350   1.1  christos 		if (node != NULL) {
   10351   1.1  christos 			dns_db_detachnode(db, &node);
   10352   1.1  christos 		}
   10353   1.1  christos 		dns_db_detach(&db);
   10354   1.1  christos 	}
   10355   1.1  christos 
   10356   1.1  christos 	if (redirected) {
   10357  1.23  christos 		return result;
   10358   1.1  christos 	}
   10359   1.1  christos 
   10360   1.1  christos 	if (!done) {
   10361   1.1  christos 		/*
   10362   1.1  christos 		 * No covering NSEC was found; proceed with recursion.
   10363   1.1  christos 		 */
   10364   1.3  christos 		qctx->findcoveringnsec = false;
   10365   1.1  christos 		if (qctx->fname != NULL) {
   10366   1.3  christos 			ns_client_releasename(qctx->client, &qctx->fname);
   10367   1.1  christos 		}
   10368   1.1  christos 		if (qctx->node != NULL) {
   10369   1.1  christos 			dns_db_detachnode(qctx->db, &qctx->node);
   10370   1.1  christos 		}
   10371   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   10372   1.1  christos 		if (qctx->sigrdataset != NULL) {
   10373   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   10374   1.1  christos 		}
   10375  1.23  christos 		return query_lookup(qctx);
   10376   1.1  christos 	}
   10377   1.1  christos 
   10378  1.23  christos 	return ns_query_done(qctx);
   10379   1.1  christos }
   10380   1.1  christos 
   10381   1.1  christos /*%
   10382   1.1  christos  * Handle negative cache responses, DNS_R_NCACHENXRRSET or
   10383   1.1  christos  * DNS_R_NCACHENXDOMAIN. (Note: may also be called with result
   10384   1.1  christos  * set to DNS_R_NXDOMAIN when handling DNS64 lookups.)
   10385   1.1  christos  */
   10386   1.1  christos static isc_result_t
   10387   1.1  christos query_ncache(query_ctx_t *qctx, isc_result_t result) {
   10388   1.1  christos 	INSIST(!qctx->is_zone);
   10389   1.1  christos 	INSIST(result == DNS_R_NCACHENXDOMAIN ||
   10390   1.9  christos 	       result == DNS_R_NCACHENXRRSET || result == DNS_R_NXDOMAIN);
   10391   1.9  christos 
   10392   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_ncache");
   10393   1.1  christos 
   10394   1.3  christos 	CALL_HOOK(NS_QUERY_NCACHE_BEGIN, qctx);
   10395   1.3  christos 
   10396   1.3  christos 	qctx->authoritative = false;
   10397   1.1  christos 
   10398   1.1  christos 	if (result == DNS_R_NCACHENXDOMAIN) {
   10399   1.1  christos 		/*
   10400   1.1  christos 		 * Set message rcode. (This is not done when
   10401   1.1  christos 		 * result == DNS_R_NXDOMAIN because that means we're
   10402   1.1  christos 		 * being called after a DNS64 lookup and don't want
   10403   1.1  christos 		 * to update the rcode now.)
   10404   1.1  christos 		 */
   10405   1.1  christos 		qctx->client->message->rcode = dns_rcode_nxdomain;
   10406   1.1  christos 
   10407   1.1  christos 		/* Look for RFC 1918 leakage from Internet. */
   10408   1.1  christos 		if (qctx->qtype == dns_rdatatype_ptr &&
   10409   1.1  christos 		    qctx->client->message->rdclass == dns_rdataclass_in &&
   10410   1.1  christos 		    dns_name_countlabels(qctx->fname) == 7)
   10411   1.1  christos 		{
   10412   1.1  christos 			warn_rfc1918(qctx->client, qctx->fname, qctx->rdataset);
   10413   1.1  christos 		}
   10414   1.1  christos 	}
   10415   1.1  christos 
   10416  1.26  christos 	if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   10417  1.26  christos 		query_stale_refresh_ncache(qctx->client);
   10418  1.26  christos 	}
   10419  1.26  christos 
   10420  1.23  christos 	return query_nodata(qctx, result);
   10421   1.3  christos 
   10422   1.9  christos cleanup:
   10423  1.23  christos 	return result;
   10424   1.3  christos }
   10425   1.3  christos 
   10426   1.3  christos /*
   10427   1.3  christos  * If we have a zero ttl from the cache, refetch.
   10428   1.3  christos  */
   10429   1.3  christos static isc_result_t
   10430   1.3  christos query_zerottl_refetch(query_ctx_t *qctx) {
   10431   1.3  christos 	isc_result_t result;
   10432   1.3  christos 
   10433   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_zerottl_refetch");
   10434   1.9  christos 
   10435   1.3  christos 	if (qctx->is_zone || qctx->resuming || STALE(qctx->rdataset) ||
   10436   1.3  christos 	    qctx->rdataset->ttl != 0 || !RECURSIONOK(qctx->client))
   10437   1.3  christos 	{
   10438  1.23  christos 		return ISC_R_COMPLETE;
   10439   1.3  christos 	}
   10440   1.3  christos 
   10441   1.3  christos 	qctx_clean(qctx);
   10442   1.3  christos 
   10443   1.3  christos 	INSIST(!REDIRECT(qctx->client));
   10444   1.3  christos 
   10445   1.3  christos 	result = ns_query_recurse(qctx->client, qctx->qtype,
   10446   1.9  christos 				  qctx->client->query.qname, NULL, NULL,
   10447   1.9  christos 				  qctx->resuming);
   10448   1.3  christos 	if (result == ISC_R_SUCCESS) {
   10449   1.3  christos 		CALL_HOOK(NS_QUERY_ZEROTTL_RECURSE, qctx);
   10450   1.9  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   10451   1.3  christos 
   10452   1.3  christos 		if (qctx->dns64) {
   10453   1.9  christos 			qctx->client->query.attributes |= NS_QUERYATTR_DNS64;
   10454   1.3  christos 		}
   10455   1.3  christos 		if (qctx->dns64_exclude) {
   10456   1.3  christos 			qctx->client->query.attributes |=
   10457   1.3  christos 				NS_QUERYATTR_DNS64EXCLUDE;
   10458   1.3  christos 		}
   10459   1.3  christos 	} else {
   10460  1.13  christos 		/*
   10461  1.13  christos 		 * There was a zero ttl from the cache, don't fallback to
   10462  1.13  christos 		 * serve-stale lookup.
   10463  1.13  christos 		 */
   10464   1.3  christos 		QUERY_ERROR(qctx, result);
   10465   1.3  christos 	}
   10466   1.3  christos 
   10467  1.23  christos 	return ns_query_done(qctx);
   10468   1.3  christos 
   10469   1.9  christos cleanup:
   10470  1.23  christos 	return result;
   10471   1.1  christos }
   10472   1.1  christos 
   10473   1.1  christos /*
   10474   1.1  christos  * Handle CNAME responses.
   10475   1.1  christos  */
   10476   1.1  christos static isc_result_t
   10477   1.1  christos query_cname(query_ctx_t *qctx) {
   10478  1.14  christos 	isc_result_t result = ISC_R_UNSET;
   10479  1.14  christos 	dns_name_t *tname = NULL;
   10480  1.14  christos 	dns_rdataset_t *trdataset = NULL;
   10481   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10482   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   10483   1.1  christos 	dns_rdata_cname_t cname;
   10484   1.1  christos 
   10485   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_cname");
   10486   1.9  christos 
   10487   1.3  christos 	CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx);
   10488   1.1  christos 
   10489   1.3  christos 	result = query_zerottl_refetch(qctx);
   10490   1.3  christos 	if (result != ISC_R_COMPLETE) {
   10491  1.23  christos 		goto cleanup;
   10492   1.1  christos 	}
   10493   1.1  christos 
   10494   1.1  christos 	/*
   10495   1.1  christos 	 * Keep a copy of the rdataset.  We have to do this because
   10496   1.1  christos 	 * query_addrrset may clear 'rdataset' (to prevent the
   10497   1.1  christos 	 * cleanup code from cleaning it up).
   10498   1.1  christos 	 */
   10499   1.1  christos 	trdataset = qctx->rdataset;
   10500   1.1  christos 
   10501   1.1  christos 	/*
   10502   1.1  christos 	 * Add the CNAME to the answer section.
   10503   1.1  christos 	 */
   10504   1.9  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   10505   1.1  christos 		sigrdatasetp = &qctx->sigrdataset;
   10506   1.9  christos 	}
   10507   1.1  christos 
   10508  1.23  christos 	if (WANTDNSSEC(qctx->client) && qctx->fname->attributes.wildcard) {
   10509   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10510  1.20  christos 		dns_name_copy(qctx->fname,
   10511  1.20  christos 			      dns_fixedname_name(&qctx->wildcardname));
   10512   1.3  christos 		qctx->need_wildcardproof = true;
   10513   1.1  christos 	}
   10514   1.1  christos 
   10515   1.1  christos 	if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) {
   10516   1.1  christos 		qctx->noqname = qctx->rdataset;
   10517   1.1  christos 	} else {
   10518   1.1  christos 		qctx->noqname = NULL;
   10519   1.1  christos 	}
   10520   1.1  christos 
   10521   1.9  christos 	if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   10522   1.1  christos 		query_prefetch(qctx->client, qctx->fname, qctx->rdataset);
   10523   1.9  christos 	}
   10524   1.1  christos 
   10525   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   10526   1.9  christos 		       qctx->dbuf, DNS_SECTION_ANSWER);
   10527   1.1  christos 
   10528   1.1  christos 	query_addnoqnameproof(qctx);
   10529   1.1  christos 
   10530   1.1  christos 	/*
   10531   1.1  christos 	 * We set the PARTIALANSWER attribute so that if anything goes
   10532   1.1  christos 	 * wrong later on, we'll return what we've got so far.
   10533   1.1  christos 	 */
   10534   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   10535   1.1  christos 
   10536   1.1  christos 	/*
   10537   1.1  christos 	 * Reset qname to be the target name of the CNAME and restart
   10538   1.1  christos 	 * the query.
   10539   1.1  christos 	 */
   10540  1.23  christos 	dns_message_gettempname(qctx->client->message, &tname);
   10541   1.1  christos 
   10542   1.1  christos 	result = dns_rdataset_first(trdataset);
   10543   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10544   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10545  1.23  christos 		(void)ns_query_done(qctx);
   10546  1.23  christos 		goto cleanup;
   10547   1.1  christos 	}
   10548   1.1  christos 
   10549   1.1  christos 	dns_rdataset_current(trdataset, &rdata);
   10550   1.1  christos 	result = dns_rdata_tostruct(&rdata, &cname, NULL);
   10551   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10552   1.1  christos 	dns_rdata_reset(&rdata);
   10553   1.1  christos 
   10554  1.20  christos 	dns_name_copy(&cname.cname, tname);
   10555   1.1  christos 
   10556   1.1  christos 	dns_rdata_freestruct(&cname);
   10557   1.1  christos 	ns_client_qnamereplace(qctx->client, tname);
   10558   1.3  christos 	qctx->want_restart = true;
   10559   1.9  christos 	if (!WANTRECURSION(qctx->client)) {
   10560  1.23  christos 		qctx->options.nolog = true;
   10561   1.9  christos 	}
   10562   1.1  christos 
   10563   1.1  christos 	query_addauth(qctx);
   10564   1.1  christos 
   10565  1.23  christos 	return ns_query_done(qctx);
   10566   1.3  christos 
   10567   1.9  christos cleanup:
   10568  1.23  christos 	return result;
   10569   1.1  christos }
   10570   1.1  christos 
   10571   1.1  christos /*
   10572   1.1  christos  * Handle DNAME responses.
   10573   1.1  christos  */
   10574   1.1  christos static isc_result_t
   10575   1.1  christos query_dname(query_ctx_t *qctx) {
   10576   1.1  christos 	dns_name_t *tname, *prefix;
   10577   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   10578   1.1  christos 	dns_rdata_dname_t dname;
   10579   1.1  christos 	dns_fixedname_t fixed;
   10580   1.1  christos 	dns_rdataset_t *trdataset;
   10581   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10582   1.1  christos 	dns_namereln_t namereln;
   10583   1.1  christos 	isc_buffer_t b;
   10584   1.1  christos 	int order;
   10585  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   10586   1.1  christos 	unsigned int nlabels;
   10587   1.1  christos 
   10588   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_dname");
   10589   1.9  christos 
   10590   1.3  christos 	CALL_HOOK(NS_QUERY_DNAME_BEGIN, qctx);
   10591   1.3  christos 
   10592   1.1  christos 	/*
   10593   1.1  christos 	 * Compare the current qname to the found name.  We need
   10594   1.1  christos 	 * to know how many labels and bits are in common because
   10595   1.1  christos 	 * we're going to have to split qname later on.
   10596   1.1  christos 	 */
   10597   1.1  christos 	namereln = dns_name_fullcompare(qctx->client->query.qname, qctx->fname,
   10598   1.1  christos 					&order, &nlabels);
   10599   1.1  christos 	INSIST(namereln == dns_namereln_subdomain);
   10600   1.1  christos 
   10601   1.1  christos 	/*
   10602   1.1  christos 	 * Keep a copy of the rdataset.  We have to do this because
   10603   1.1  christos 	 * query_addrrset may clear 'rdataset' (to prevent the
   10604   1.1  christos 	 * cleanup code from cleaning it up).
   10605   1.1  christos 	 */
   10606   1.1  christos 	trdataset = qctx->rdataset;
   10607   1.1  christos 
   10608   1.1  christos 	/*
   10609   1.1  christos 	 * Add the DNAME to the answer section.
   10610   1.1  christos 	 */
   10611   1.9  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   10612   1.1  christos 		sigrdatasetp = &qctx->sigrdataset;
   10613   1.9  christos 	}
   10614   1.1  christos 
   10615  1.23  christos 	if (WANTDNSSEC(qctx->client) && qctx->fname->attributes.wildcard) {
   10616   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10617  1.20  christos 		dns_name_copy(qctx->fname,
   10618  1.20  christos 			      dns_fixedname_name(&qctx->wildcardname));
   10619   1.3  christos 		qctx->need_wildcardproof = true;
   10620   1.1  christos 	}
   10621   1.1  christos 
   10622   1.9  christos 	if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   10623   1.1  christos 		query_prefetch(qctx->client, qctx->fname, qctx->rdataset);
   10624   1.9  christos 	}
   10625   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   10626   1.9  christos 		       qctx->dbuf, DNS_SECTION_ANSWER);
   10627   1.1  christos 
   10628   1.1  christos 	/*
   10629   1.1  christos 	 * We set the PARTIALANSWER attribute so that if anything goes
   10630   1.1  christos 	 * wrong later on, we'll return what we've got so far.
   10631   1.1  christos 	 */
   10632   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   10633   1.1  christos 
   10634   1.1  christos 	/*
   10635   1.1  christos 	 * Get the target name of the DNAME.
   10636   1.1  christos 	 */
   10637   1.1  christos 	tname = NULL;
   10638  1.23  christos 	dns_message_gettempname(qctx->client->message, &tname);
   10639   1.1  christos 
   10640   1.1  christos 	result = dns_rdataset_first(trdataset);
   10641   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10642   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10643  1.23  christos 		(void)ns_query_done(qctx);
   10644  1.23  christos 		goto cleanup;
   10645   1.1  christos 	}
   10646   1.1  christos 
   10647   1.1  christos 	dns_rdataset_current(trdataset, &rdata);
   10648   1.1  christos 	result = dns_rdata_tostruct(&rdata, &dname, NULL);
   10649   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10650   1.1  christos 	dns_rdata_reset(&rdata);
   10651   1.1  christos 
   10652  1.20  christos 	dns_name_copy(&dname.dname, tname);
   10653   1.1  christos 	dns_rdata_freestruct(&dname);
   10654   1.1  christos 
   10655   1.1  christos 	/*
   10656   1.1  christos 	 * Construct the new qname consisting of
   10657   1.1  christos 	 * <found name prefix>.<dname target>
   10658   1.1  christos 	 */
   10659   1.1  christos 	prefix = dns_fixedname_initname(&fixed);
   10660   1.1  christos 	dns_name_split(qctx->client->query.qname, nlabels, prefix, NULL);
   10661   1.1  christos 	INSIST(qctx->fname == NULL);
   10662   1.3  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   10663   1.3  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   10664   1.1  christos 	result = dns_name_concatenate(prefix, tname, qctx->fname, NULL);
   10665   1.1  christos 	dns_message_puttempname(qctx->client->message, &tname);
   10666   1.1  christos 
   10667   1.1  christos 	/*
   10668   1.1  christos 	 * RFC2672, section 4.1, subsection 3c says
   10669   1.1  christos 	 * we should return YXDOMAIN if the constructed
   10670   1.1  christos 	 * name would be too long.
   10671   1.1  christos 	 */
   10672   1.9  christos 	if (result == DNS_R_NAMETOOLONG) {
   10673   1.1  christos 		qctx->client->message->rcode = dns_rcode_yxdomain;
   10674   1.9  christos 	}
   10675   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10676  1.23  christos 		(void)ns_query_done(qctx);
   10677  1.23  christos 		goto cleanup;
   10678   1.9  christos 	}
   10679   1.1  christos 
   10680   1.3  christos 	ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   10681   1.1  christos 
   10682   1.1  christos 	/*
   10683   1.1  christos 	 * Synthesize a CNAME consisting of
   10684   1.1  christos 	 *   <old qname> <dname ttl> CNAME <new qname>
   10685   1.1  christos 	 *	    with <dname trust value>
   10686   1.1  christos 	 *
   10687   1.1  christos 	 * Synthesize a CNAME so old old clients that don't understand
   10688   1.1  christos 	 * DNAME can chain.
   10689   1.1  christos 	 *
   10690   1.1  christos 	 * We do not try to synthesize a signature because we hope
   10691   1.1  christos 	 * that security aware servers will understand DNAME.  Also,
   10692   1.1  christos 	 * even if we had an online key, making a signature
   10693   1.1  christos 	 * on-the-fly is costly, and not really legitimate anyway
   10694   1.1  christos 	 * since the synthesized CNAME is NOT in the zone.
   10695   1.1  christos 	 */
   10696  1.23  christos 	query_addcname(qctx, trdataset->trust, trdataset->ttl);
   10697   1.1  christos 
   10698   1.1  christos 	/*
   10699  1.11  christos 	 * If the original query was not for a CNAME or ANY then follow the
   10700  1.11  christos 	 * CNAME.
   10701   1.1  christos 	 */
   10702  1.11  christos 	if (qctx->qtype != dns_rdatatype_cname &&
   10703  1.16  christos 	    qctx->qtype != dns_rdatatype_any)
   10704  1.16  christos 	{
   10705  1.11  christos 		/*
   10706  1.11  christos 		 * Switch to the new qname and restart.
   10707  1.11  christos 		 */
   10708  1.11  christos 		ns_client_qnamereplace(qctx->client, qctx->fname);
   10709  1.11  christos 		qctx->fname = NULL;
   10710  1.11  christos 		qctx->want_restart = true;
   10711  1.11  christos 		if (!WANTRECURSION(qctx->client)) {
   10712  1.23  christos 			qctx->options.nolog = true;
   10713  1.11  christos 		}
   10714   1.9  christos 	}
   10715   1.1  christos 
   10716   1.1  christos 	query_addauth(qctx);
   10717   1.1  christos 
   10718  1.23  christos 	return ns_query_done(qctx);
   10719   1.3  christos 
   10720   1.9  christos cleanup:
   10721  1.23  christos 	return result;
   10722   1.1  christos }
   10723   1.1  christos 
   10724   1.1  christos /*%
   10725   1.9  christos  * Add CNAME to response.
   10726   1.1  christos  */
   10727  1.23  christos static void
   10728   1.1  christos query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) {
   10729   1.1  christos 	ns_client_t *client = qctx->client;
   10730   1.1  christos 	dns_rdataset_t *rdataset = NULL;
   10731   1.1  christos 	dns_rdatalist_t *rdatalist = NULL;
   10732   1.1  christos 	dns_rdata_t *rdata = NULL;
   10733   1.1  christos 	isc_region_t r;
   10734   1.1  christos 	dns_name_t *aname = NULL;
   10735   1.1  christos 
   10736  1.23  christos 	dns_message_gettempname(client->message, &aname);
   10737  1.14  christos 
   10738  1.20  christos 	dns_name_copy(client->query.qname, aname);
   10739   1.1  christos 
   10740  1.23  christos 	dns_message_gettemprdatalist(client->message, &rdatalist);
   10741   1.1  christos 
   10742  1.23  christos 	dns_message_gettemprdata(client->message, &rdata);
   10743   1.1  christos 
   10744  1.23  christos 	dns_message_gettemprdataset(client->message, &rdataset);
   10745   1.1  christos 
   10746   1.1  christos 	rdatalist->type = dns_rdatatype_cname;
   10747   1.1  christos 	rdatalist->rdclass = client->message->rdclass;
   10748   1.1  christos 	rdatalist->ttl = ttl;
   10749   1.1  christos 
   10750   1.1  christos 	dns_name_toregion(qctx->fname, &r);
   10751   1.1  christos 	rdata->data = r.base;
   10752   1.1  christos 	rdata->length = r.length;
   10753   1.1  christos 	rdata->rdclass = client->message->rdclass;
   10754   1.1  christos 	rdata->type = dns_rdatatype_cname;
   10755   1.1  christos 
   10756   1.1  christos 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
   10757  1.23  christos 	dns_rdatalist_tordataset(rdatalist, rdataset);
   10758   1.1  christos 	rdataset->trust = trust;
   10759   1.1  christos 	dns_rdataset_setownercase(rdataset, aname);
   10760   1.1  christos 
   10761   1.9  christos 	query_addrrset(qctx, &aname, &rdataset, NULL, NULL, DNS_SECTION_ANSWER);
   10762   1.1  christos 	if (rdataset != NULL) {
   10763   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   10764   1.1  christos 			dns_rdataset_disassociate(rdataset);
   10765   1.9  christos 		}
   10766   1.1  christos 		dns_message_puttemprdataset(client->message, &rdataset);
   10767   1.1  christos 	}
   10768   1.9  christos 	if (aname != NULL) {
   10769   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10770   1.9  christos 	}
   10771   1.1  christos }
   10772   1.1  christos 
   10773   1.1  christos /*%
   10774   1.1  christos  * Prepare to respond: determine whether a wildcard proof is needed,
   10775   1.3  christos  * then hand off to query_respond() or (for type ANY queries)
   10776   1.3  christos  * query_respond_any().
   10777   1.1  christos  */
   10778   1.1  christos static isc_result_t
   10779   1.1  christos query_prepresponse(query_ctx_t *qctx) {
   10780  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   10781   1.3  christos 
   10782   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_prepresponse");
   10783   1.9  christos 
   10784   1.3  christos 	CALL_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx);
   10785   1.3  christos 
   10786  1.23  christos 	if (WANTDNSSEC(qctx->client) && qctx->fname->attributes.wildcard) {
   10787   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10788  1.20  christos 		dns_name_copy(qctx->fname,
   10789  1.20  christos 			      dns_fixedname_name(&qctx->wildcardname));
   10790   1.3  christos 		qctx->need_wildcardproof = true;
   10791   1.3  christos 	}
   10792   1.3  christos 
   10793   1.3  christos 	if (qctx->type == dns_rdatatype_any) {
   10794  1.23  christos 		return query_respond_any(qctx);
   10795   1.1  christos 	}
   10796   1.1  christos 
   10797   1.3  christos 	result = query_zerottl_refetch(qctx);
   10798   1.3  christos 	if (result != ISC_R_COMPLETE) {
   10799  1.23  christos 		goto cleanup;
   10800   1.1  christos 	}
   10801   1.1  christos 
   10802  1.23  christos 	return query_respond(qctx);
   10803   1.1  christos 
   10804   1.9  christos cleanup:
   10805  1.23  christos 	return result;
   10806   1.1  christos }
   10807   1.1  christos 
   10808   1.1  christos /*%
   10809   1.1  christos  * Add SOA to the authority section when sending negative responses
   10810   1.1  christos  * (or to the additional section if sending negative responses triggered
   10811   1.1  christos  * by RPZ rewriting.)
   10812   1.1  christos  */
   10813   1.1  christos static isc_result_t
   10814   1.1  christos query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
   10815   1.9  christos 	     dns_section_t section) {
   10816   1.1  christos 	ns_client_t *client = qctx->client;
   10817  1.20  christos 	dns_name_t *name = NULL;
   10818  1.20  christos 	dns_dbnode_t *node = NULL;
   10819  1.20  christos 	isc_result_t result, eresult = ISC_R_SUCCESS;
   10820   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   10821   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10822   1.1  christos 	dns_clientinfomethods_t cm;
   10823   1.1  christos 	dns_clientinfo_t ci;
   10824   1.1  christos 
   10825   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addsoa");
   10826   1.1  christos 
   10827   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   10828  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   10829   1.1  christos 
   10830   1.1  christos 	/*
   10831   1.1  christos 	 * Don't add the SOA record for test which set "-T nosoa".
   10832   1.1  christos 	 */
   10833  1.23  christos 	if (((client->manager->sctx->options & NS_SERVER_NOSOA) != 0) &&
   10834   1.1  christos 	    (!WANTDNSSEC(client) || !dns_rdataset_isassociated(qctx->rdataset)))
   10835   1.1  christos 	{
   10836  1.23  christos 		return ISC_R_SUCCESS;
   10837   1.1  christos 	}
   10838   1.1  christos 
   10839   1.1  christos 	/*
   10840   1.1  christos 	 * Get resources and make 'name' be the database origin.
   10841   1.1  christos 	 */
   10842  1.23  christos 	dns_message_gettempname(client->message, &name);
   10843  1.14  christos 
   10844  1.14  christos 	/*
   10845  1.14  christos 	 * We'll be releasing 'name' before returning, so it's safe to
   10846  1.14  christos 	 * use clone instead of copying here.
   10847  1.14  christos 	 */
   10848   1.1  christos 	dns_name_clone(dns_db_origin(qctx->db), name);
   10849  1.14  christos 
   10850   1.3  christos 	rdataset = ns_client_newrdataset(client);
   10851   1.1  christos 	if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) {
   10852   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   10853   1.1  christos 	}
   10854   1.1  christos 
   10855   1.1  christos 	/*
   10856   1.1  christos 	 * Find the SOA.
   10857   1.1  christos 	 */
   10858   1.1  christos 	result = dns_db_getoriginnode(qctx->db, &node);
   10859   1.1  christos 	if (result == ISC_R_SUCCESS) {
   10860   1.1  christos 		result = dns_db_findrdataset(qctx->db, node, qctx->version,
   10861   1.9  christos 					     dns_rdatatype_soa, 0, client->now,
   10862   1.1  christos 					     rdataset, sigrdataset);
   10863   1.1  christos 	} else {
   10864   1.1  christos 		dns_fixedname_t foundname;
   10865   1.1  christos 		dns_name_t *fname;
   10866   1.1  christos 
   10867   1.1  christos 		fname = dns_fixedname_initname(&foundname);
   10868   1.1  christos 
   10869   1.1  christos 		result = dns_db_findext(qctx->db, name, qctx->version,
   10870   1.1  christos 					dns_rdatatype_soa,
   10871   1.9  christos 					client->query.dboptions, 0, &node,
   10872   1.9  christos 					fname, &cm, &ci, rdataset, sigrdataset);
   10873   1.1  christos 	}
   10874   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10875   1.1  christos 		/*
   10876   1.1  christos 		 * This is bad.  We tried to get the SOA RR at the zone top
   10877   1.1  christos 		 * and it didn't work!
   10878   1.1  christos 		 */
   10879   1.1  christos 		CTRACE(ISC_LOG_ERROR, "unable to find SOA RR at zone apex");
   10880   1.1  christos 		eresult = DNS_R_SERVFAIL;
   10881   1.1  christos 	} else {
   10882   1.1  christos 		/*
   10883   1.1  christos 		 * Extract the SOA MINIMUM.
   10884   1.1  christos 		 */
   10885   1.1  christos 		dns_rdata_soa_t soa;
   10886   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   10887   1.1  christos 		result = dns_rdataset_first(rdataset);
   10888   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10889   1.1  christos 		dns_rdataset_current(rdataset, &rdata);
   10890   1.1  christos 		result = dns_rdata_tostruct(&rdata, &soa, NULL);
   10891   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10892   1.1  christos 
   10893   1.9  christos 		if (override_ttl != UINT32_MAX && override_ttl < rdataset->ttl)
   10894   1.1  christos 		{
   10895   1.1  christos 			rdataset->ttl = override_ttl;
   10896   1.9  christos 			if (sigrdataset != NULL) {
   10897   1.1  christos 				sigrdataset->ttl = override_ttl;
   10898   1.9  christos 			}
   10899   1.1  christos 		}
   10900   1.1  christos 
   10901   1.1  christos 		/*
   10902   1.1  christos 		 * Add the SOA and its SIG to the response, with the
   10903   1.1  christos 		 * TTLs adjusted per RFC2308 section 3.
   10904   1.1  christos 		 */
   10905   1.9  christos 		if (rdataset->ttl > soa.minimum) {
   10906   1.1  christos 			rdataset->ttl = soa.minimum;
   10907   1.9  christos 		}
   10908   1.9  christos 		if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum) {
   10909   1.1  christos 			sigrdataset->ttl = soa.minimum;
   10910   1.9  christos 		}
   10911   1.1  christos 
   10912   1.9  christos 		if (sigrdataset != NULL) {
   10913   1.1  christos 			sigrdatasetp = &sigrdataset;
   10914   1.9  christos 		} else {
   10915   1.1  christos 			sigrdatasetp = NULL;
   10916   1.9  christos 		}
   10917   1.1  christos 
   10918   1.9  christos 		if (section == DNS_SECTION_ADDITIONAL) {
   10919   1.1  christos 			rdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   10920   1.9  christos 		}
   10921   1.9  christos 		query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL,
   10922   1.9  christos 			       section);
   10923   1.1  christos 	}
   10924   1.1  christos 
   10925   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   10926   1.9  christos 	if (sigrdataset != NULL) {
   10927   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   10928   1.9  christos 	}
   10929   1.9  christos 	if (name != NULL) {
   10930   1.3  christos 		ns_client_releasename(client, &name);
   10931   1.9  christos 	}
   10932   1.9  christos 	if (node != NULL) {
   10933   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   10934   1.9  christos 	}
   10935   1.1  christos 
   10936  1.23  christos 	return eresult;
   10937   1.1  christos }
   10938   1.1  christos 
   10939   1.1  christos /*%
   10940   1.1  christos  * Add NS to authority section (used when the zone apex is already known).
   10941   1.1  christos  */
   10942   1.1  christos static isc_result_t
   10943   1.1  christos query_addns(query_ctx_t *qctx) {
   10944   1.1  christos 	ns_client_t *client = qctx->client;
   10945   1.1  christos 	isc_result_t result, eresult;
   10946   1.1  christos 	dns_name_t *name = NULL, *fname;
   10947   1.1  christos 	dns_dbnode_t *node = NULL;
   10948   1.1  christos 	dns_fixedname_t foundname;
   10949   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   10950   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10951   1.1  christos 	dns_clientinfomethods_t cm;
   10952   1.1  christos 	dns_clientinfo_t ci;
   10953   1.1  christos 
   10954   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns");
   10955   1.1  christos 
   10956   1.1  christos 	/*
   10957   1.1  christos 	 * Initialization.
   10958   1.1  christos 	 */
   10959   1.1  christos 	eresult = ISC_R_SUCCESS;
   10960   1.1  christos 	fname = dns_fixedname_initname(&foundname);
   10961   1.1  christos 
   10962   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   10963  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   10964   1.1  christos 
   10965   1.1  christos 	/*
   10966   1.1  christos 	 * Get resources and make 'name' be the database origin.
   10967   1.1  christos 	 */
   10968  1.23  christos 	dns_message_gettempname(client->message, &name);
   10969   1.1  christos 	dns_name_clone(dns_db_origin(qctx->db), name);
   10970   1.3  christos 	rdataset = ns_client_newrdataset(client);
   10971   1.1  christos 
   10972   1.1  christos 	if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) {
   10973   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   10974   1.1  christos 	}
   10975   1.1  christos 
   10976   1.1  christos 	/*
   10977   1.1  christos 	 * Find the NS rdataset.
   10978   1.1  christos 	 */
   10979   1.1  christos 	result = dns_db_getoriginnode(qctx->db, &node);
   10980   1.1  christos 	if (result == ISC_R_SUCCESS) {
   10981   1.1  christos 		result = dns_db_findrdataset(qctx->db, node, qctx->version,
   10982   1.1  christos 					     dns_rdatatype_ns, 0, client->now,
   10983   1.1  christos 					     rdataset, sigrdataset);
   10984   1.1  christos 	} else {
   10985   1.1  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addns: calling dns_db_find");
   10986   1.1  christos 		result = dns_db_findext(qctx->db, name, NULL, dns_rdatatype_ns,
   10987   1.1  christos 					client->query.dboptions, 0, &node,
   10988   1.1  christos 					fname, &cm, &ci, rdataset, sigrdataset);
   10989   1.1  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addns: dns_db_find complete");
   10990   1.1  christos 	}
   10991   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10992   1.9  christos 		CTRACE(ISC_LOG_ERROR, "query_addns: "
   10993   1.9  christos 				      "dns_db_findrdataset or dns_db_find "
   10994   1.9  christos 				      "failed");
   10995   1.1  christos 		/*
   10996   1.1  christos 		 * This is bad.  We tried to get the NS rdataset at the zone
   10997   1.1  christos 		 * top and it didn't work!
   10998   1.1  christos 		 */
   10999   1.1  christos 		eresult = DNS_R_SERVFAIL;
   11000   1.1  christos 	} else {
   11001   1.1  christos 		if (sigrdataset != NULL) {
   11002   1.1  christos 			sigrdatasetp = &sigrdataset;
   11003   1.1  christos 		}
   11004   1.3  christos 		query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL,
   11005   1.1  christos 			       DNS_SECTION_AUTHORITY);
   11006   1.1  christos 	}
   11007   1.1  christos 
   11008   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns: cleanup");
   11009   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   11010   1.1  christos 	if (sigrdataset != NULL) {
   11011   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11012   1.1  christos 	}
   11013   1.1  christos 	if (name != NULL) {
   11014   1.3  christos 		ns_client_releasename(client, &name);
   11015   1.1  christos 	}
   11016   1.1  christos 	if (node != NULL) {
   11017   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   11018   1.1  christos 	}
   11019   1.1  christos 
   11020   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns: done");
   11021  1.23  christos 	return eresult;
   11022   1.1  christos }
   11023   1.1  christos 
   11024   1.1  christos /*%
   11025   1.1  christos  * Find the zone cut and add the best NS rrset to the authority section.
   11026   1.1  christos  */
   11027   1.1  christos static void
   11028   1.1  christos query_addbestns(query_ctx_t *qctx) {
   11029   1.1  christos 	ns_client_t *client = qctx->client;
   11030   1.1  christos 	dns_db_t *db = NULL, *zdb = NULL;
   11031   1.1  christos 	dns_dbnode_t *node = NULL;
   11032   1.1  christos 	dns_name_t *fname = NULL, *zfname = NULL;
   11033   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   11034   1.1  christos 	dns_rdataset_t *zrdataset = NULL, *zsigrdataset = NULL;
   11035   1.3  christos 	bool is_zone = false, use_zone = false;
   11036   1.1  christos 	isc_buffer_t *dbuf = NULL;
   11037   1.1  christos 	isc_result_t result;
   11038   1.1  christos 	dns_dbversion_t *version = NULL;
   11039   1.1  christos 	dns_zone_t *zone = NULL;
   11040   1.1  christos 	isc_buffer_t b;
   11041   1.1  christos 	dns_clientinfomethods_t cm;
   11042   1.1  christos 	dns_clientinfo_t ci;
   11043  1.22  christos 	dns_name_t qname;
   11044   1.1  christos 
   11045   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addbestns");
   11046   1.1  christos 
   11047   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   11048  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   11049   1.1  christos 
   11050  1.22  christos 	dns_name_init(&qname, NULL);
   11051  1.22  christos 	dns_name_clone(client->query.qname, &qname);
   11052  1.22  christos 
   11053   1.1  christos 	/*
   11054   1.1  christos 	 * Find the right database.
   11055   1.1  christos 	 */
   11056  1.22  christos 	do {
   11057  1.23  christos 		result = query_getdb(client, &qname, dns_rdatatype_ns,
   11058  1.23  christos 				     (dns_getdb_options_t){ 0 }, &zone, &db,
   11059  1.23  christos 				     &version, &is_zone);
   11060  1.22  christos 		if (result != ISC_R_SUCCESS) {
   11061  1.22  christos 			goto cleanup;
   11062  1.22  christos 		}
   11063  1.22  christos 
   11064  1.22  christos 		/*
   11065  1.22  christos 		 * If this is a static stub zone look for a parent zone.
   11066  1.22  christos 		 */
   11067  1.22  christos 		if (zone != NULL &&
   11068  1.22  christos 		    dns_zone_gettype(zone) == dns_zone_staticstub)
   11069  1.22  christos 		{
   11070  1.22  christos 			unsigned int labels = dns_name_countlabels(&qname);
   11071  1.22  christos 			dns_db_detach(&db);
   11072  1.22  christos 			dns_zone_detach(&zone);
   11073  1.22  christos 			version = NULL;
   11074  1.22  christos 			if (labels != 1) {
   11075  1.22  christos 				dns_name_split(&qname, labels - 1, NULL,
   11076  1.22  christos 					       &qname);
   11077  1.22  christos 				continue;
   11078  1.22  christos 			}
   11079  1.22  christos 			if (!USECACHE(client)) {
   11080  1.22  christos 				goto cleanup;
   11081  1.22  christos 			}
   11082  1.22  christos 			dns_db_attach(client->view->cachedb, &db);
   11083  1.22  christos 			is_zone = false;
   11084  1.22  christos 		}
   11085  1.22  christos 		break;
   11086  1.22  christos 	} while (true);
   11087   1.1  christos 
   11088   1.9  christos db_find:
   11089   1.1  christos 	/*
   11090   1.1  christos 	 * We'll need some resources...
   11091   1.1  christos 	 */
   11092   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   11093   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   11094   1.3  christos 	rdataset = ns_client_newrdataset(client);
   11095   1.1  christos 
   11096   1.1  christos 	/*
   11097   1.1  christos 	 * Get the RRSIGs if the client requested them or if we may
   11098   1.1  christos 	 * need to validate answers from the cache.
   11099   1.1  christos 	 */
   11100   1.1  christos 	if (WANTDNSSEC(client) || !is_zone) {
   11101   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   11102   1.1  christos 	}
   11103   1.1  christos 
   11104   1.1  christos 	/*
   11105   1.1  christos 	 * Now look for the zonecut.
   11106   1.1  christos 	 */
   11107   1.1  christos 	if (is_zone) {
   11108   1.9  christos 		result = dns_db_findext(
   11109   1.9  christos 			db, client->query.qname, version, dns_rdatatype_ns,
   11110   1.9  christos 			client->query.dboptions, client->now, &node, fname, &cm,
   11111   1.9  christos 			&ci, rdataset, sigrdataset);
   11112   1.1  christos 		if (result != DNS_R_DELEGATION) {
   11113   1.1  christos 			goto cleanup;
   11114   1.1  christos 		}
   11115   1.1  christos 		if (USECACHE(client)) {
   11116   1.3  christos 			ns_client_keepname(client, fname, dbuf);
   11117   1.1  christos 			dns_db_detachnode(db, &node);
   11118   1.1  christos 			SAVE(zdb, db);
   11119   1.1  christos 			SAVE(zfname, fname);
   11120   1.1  christos 			SAVE(zrdataset, rdataset);
   11121   1.1  christos 			SAVE(zsigrdataset, sigrdataset);
   11122   1.1  christos 			version = NULL;
   11123   1.1  christos 			dns_db_attach(client->view->cachedb, &db);
   11124   1.3  christos 			is_zone = false;
   11125   1.1  christos 			goto db_find;
   11126   1.1  christos 		}
   11127   1.1  christos 	} else {
   11128   1.9  christos 		result = dns_db_findzonecut(
   11129   1.9  christos 			db, client->query.qname, client->query.dboptions,
   11130   1.9  christos 			client->now, &node, fname, NULL, rdataset, sigrdataset);
   11131   1.1  christos 		if (result == ISC_R_SUCCESS) {
   11132   1.1  christos 			if (zfname != NULL &&
   11133  1.16  christos 			    !dns_name_issubdomain(fname, zfname))
   11134  1.16  christos 			{
   11135   1.1  christos 				/*
   11136   1.1  christos 				 * We found a zonecut in the cache, but our
   11137   1.1  christos 				 * zone delegation is better.
   11138   1.1  christos 				 */
   11139   1.3  christos 				use_zone = true;
   11140   1.1  christos 			}
   11141   1.1  christos 		} else if (result == ISC_R_NOTFOUND && zfname != NULL) {
   11142   1.1  christos 			/*
   11143   1.1  christos 			 * We didn't find anything in the cache, but we
   11144   1.1  christos 			 * have a zone delegation, so use it.
   11145   1.1  christos 			 */
   11146   1.3  christos 			use_zone = true;
   11147   1.1  christos 		} else {
   11148   1.1  christos 			goto cleanup;
   11149   1.1  christos 		}
   11150   1.1  christos 	}
   11151   1.1  christos 
   11152   1.1  christos 	if (use_zone) {
   11153   1.3  christos 		ns_client_releasename(client, &fname);
   11154   1.1  christos 		/*
   11155   1.3  christos 		 * We've already done ns_client_keepname() on
   11156   1.1  christos 		 * zfname, so we must set dbuf to NULL to
   11157   1.1  christos 		 * prevent query_addrrset() from trying to
   11158   1.3  christos 		 * call ns_client_keepname() again.
   11159   1.1  christos 		 */
   11160   1.1  christos 		dbuf = NULL;
   11161   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11162   1.1  christos 		if (sigrdataset != NULL) {
   11163   1.3  christos 			ns_client_putrdataset(client, &sigrdataset);
   11164   1.1  christos 		}
   11165   1.1  christos 
   11166   1.1  christos 		if (node != NULL) {
   11167   1.1  christos 			dns_db_detachnode(db, &node);
   11168   1.1  christos 		}
   11169   1.1  christos 		dns_db_detach(&db);
   11170   1.1  christos 
   11171   1.1  christos 		RESTORE(db, zdb);
   11172   1.1  christos 		RESTORE(fname, zfname);
   11173   1.1  christos 		RESTORE(rdataset, zrdataset);
   11174   1.1  christos 		RESTORE(sigrdataset, zsigrdataset);
   11175   1.1  christos 	}
   11176   1.1  christos 
   11177   1.1  christos 	/*
   11178   1.1  christos 	 * Attempt to validate RRsets that are pending or that are glue.
   11179   1.1  christos 	 */
   11180   1.1  christos 	if ((DNS_TRUST_PENDING(rdataset->trust) ||
   11181   1.1  christos 	     (sigrdataset != NULL && DNS_TRUST_PENDING(sigrdataset->trust))) &&
   11182   1.1  christos 	    !validate(client, db, fname, rdataset, sigrdataset) &&
   11183   1.1  christos 	    !PENDINGOK(client->query.dboptions))
   11184   1.1  christos 	{
   11185   1.1  christos 		goto cleanup;
   11186   1.1  christos 	}
   11187   1.1  christos 
   11188   1.1  christos 	if ((DNS_TRUST_GLUE(rdataset->trust) ||
   11189   1.1  christos 	     (sigrdataset != NULL && DNS_TRUST_GLUE(sigrdataset->trust))) &&
   11190   1.1  christos 	    !validate(client, db, fname, rdataset, sigrdataset) &&
   11191   1.1  christos 	    SECURE(client) && WANTDNSSEC(client))
   11192   1.1  christos 	{
   11193   1.1  christos 		goto cleanup;
   11194   1.1  christos 	}
   11195   1.1  christos 
   11196   1.1  christos 	/*
   11197   1.1  christos 	 * If the answer is secure only add NS records if they are secure
   11198   1.1  christos 	 * when the client may be looking for AD in the response.
   11199   1.1  christos 	 */
   11200   1.1  christos 	if (SECURE(client) && (WANTDNSSEC(client) || WANTAD(client)) &&
   11201   1.1  christos 	    ((rdataset->trust != dns_trust_secure) ||
   11202   1.9  christos 	     (sigrdataset != NULL && sigrdataset->trust != dns_trust_secure)))
   11203   1.1  christos 	{
   11204   1.1  christos 		goto cleanup;
   11205   1.1  christos 	}
   11206   1.1  christos 
   11207   1.1  christos 	/*
   11208   1.1  christos 	 * If the client doesn't want DNSSEC we can discard the sigrdataset
   11209   1.1  christos 	 * now.
   11210   1.1  christos 	 */
   11211   1.1  christos 	if (!WANTDNSSEC(client)) {
   11212   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11213   1.1  christos 	}
   11214   1.1  christos 
   11215   1.3  christos 	query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11216   1.1  christos 		       DNS_SECTION_AUTHORITY);
   11217   1.1  christos 
   11218   1.9  christos cleanup:
   11219   1.1  christos 	if (rdataset != NULL) {
   11220   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11221   1.1  christos 	}
   11222   1.1  christos 	if (sigrdataset != NULL) {
   11223   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11224   1.1  christos 	}
   11225   1.1  christos 	if (fname != NULL) {
   11226   1.3  christos 		ns_client_releasename(client, &fname);
   11227   1.1  christos 	}
   11228   1.1  christos 	if (node != NULL) {
   11229   1.1  christos 		dns_db_detachnode(db, &node);
   11230   1.1  christos 	}
   11231   1.1  christos 	if (db != NULL) {
   11232   1.1  christos 		dns_db_detach(&db);
   11233   1.1  christos 	}
   11234   1.1  christos 	if (zone != NULL) {
   11235   1.1  christos 		dns_zone_detach(&zone);
   11236   1.1  christos 	}
   11237   1.1  christos 	if (zdb != NULL) {
   11238   1.3  christos 		ns_client_putrdataset(client, &zrdataset);
   11239   1.3  christos 		if (zsigrdataset != NULL) {
   11240   1.3  christos 			ns_client_putrdataset(client, &zsigrdataset);
   11241   1.3  christos 		}
   11242   1.3  christos 		if (zfname != NULL) {
   11243   1.3  christos 			ns_client_releasename(client, &zfname);
   11244   1.3  christos 		}
   11245   1.1  christos 		dns_db_detach(&zdb);
   11246   1.1  christos 	}
   11247   1.1  christos }
   11248   1.1  christos 
   11249   1.1  christos static void
   11250   1.9  christos query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata) {
   11251   1.1  christos 	ns_client_t *client = qctx->client;
   11252   1.1  christos 	isc_buffer_t *dbuf, b;
   11253   1.1  christos 	dns_name_t *name;
   11254   1.1  christos 	dns_name_t *fname = NULL;
   11255   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   11256   1.1  christos 	dns_fixedname_t wfixed;
   11257   1.1  christos 	dns_name_t *wname;
   11258   1.1  christos 	dns_dbnode_t *node = NULL;
   11259   1.1  christos 	unsigned int options;
   11260   1.1  christos 	unsigned int olabels, nlabels, labels;
   11261   1.1  christos 	isc_result_t result;
   11262   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   11263   1.1  christos 	dns_rdata_nsec_t nsec;
   11264   1.3  christos 	bool have_wname;
   11265   1.1  christos 	int order;
   11266   1.1  christos 	dns_fixedname_t cfixed;
   11267   1.1  christos 	dns_name_t *cname;
   11268   1.1  christos 	dns_clientinfomethods_t cm;
   11269   1.1  christos 	dns_clientinfo_t ci;
   11270   1.1  christos 
   11271   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addwildcardproof");
   11272   1.1  christos 
   11273   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   11274  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   11275   1.1  christos 
   11276   1.1  christos 	/*
   11277   1.1  christos 	 * If a name has been specifically flagged as needing
   11278   1.1  christos 	 * a wildcard proof then it will have been copied to
   11279   1.1  christos 	 * qctx->wildcardname. Otherwise we just use the client
   11280   1.1  christos 	 * QNAME.
   11281   1.1  christos 	 */
   11282   1.1  christos 	if (qctx->need_wildcardproof) {
   11283   1.1  christos 		name = dns_fixedname_name(&qctx->wildcardname);
   11284   1.1  christos 	} else {
   11285   1.1  christos 		name = client->query.qname;
   11286   1.1  christos 	}
   11287   1.1  christos 
   11288   1.1  christos 	/*
   11289   1.1  christos 	 * Get the NOQNAME proof then if !ispositive
   11290   1.1  christos 	 * get the NOWILDCARD proof.
   11291   1.1  christos 	 *
   11292   1.1  christos 	 * DNS_DBFIND_NOWILD finds the NSEC records that covers the
   11293   1.1  christos 	 * name ignoring any wildcard.  From the owner and next names
   11294   1.1  christos 	 * of this record you can compute which wildcard (if it exists)
   11295   1.1  christos 	 * will match by finding the longest common suffix of the
   11296   1.1  christos 	 * owner name and next names with the qname and prefixing that
   11297   1.1  christos 	 * with the wildcard label.
   11298   1.1  christos 	 *
   11299   1.1  christos 	 * e.g.
   11300   1.1  christos 	 *   Given:
   11301   1.1  christos 	 *	example SOA
   11302   1.1  christos 	 *	example NSEC b.example
   11303   1.1  christos 	 *	b.example A
   11304   1.1  christos 	 *	b.example NSEC a.d.example
   11305   1.1  christos 	 *	a.d.example A
   11306   1.1  christos 	 *	a.d.example NSEC g.f.example
   11307   1.1  christos 	 *	g.f.example A
   11308   1.1  christos 	 *	g.f.example NSEC z.i.example
   11309   1.1  christos 	 *	z.i.example A
   11310   1.1  christos 	 *	z.i.example NSEC example
   11311   1.1  christos 	 *
   11312   1.1  christos 	 *   QNAME:
   11313   1.1  christos 	 *   a.example -> example NSEC b.example
   11314   1.1  christos 	 *	owner common example
   11315   1.1  christos 	 *	next common example
   11316   1.1  christos 	 *	wild *.example
   11317   1.1  christos 	 *   d.b.example -> b.example NSEC a.d.example
   11318   1.1  christos 	 *	owner common b.example
   11319   1.1  christos 	 *	next common example
   11320   1.1  christos 	 *	wild *.b.example
   11321   1.1  christos 	 *   a.f.example -> a.d.example NSEC g.f.example
   11322   1.1  christos 	 *	owner common example
   11323   1.1  christos 	 *	next common f.example
   11324   1.1  christos 	 *	wild *.f.example
   11325   1.1  christos 	 *  j.example -> z.i.example NSEC example
   11326   1.1  christos 	 *	owner common example
   11327   1.1  christos 	 *	next common example
   11328   1.1  christos 	 *	wild *.example
   11329   1.1  christos 	 */
   11330   1.1  christos 	options = client->query.dboptions | DNS_DBFIND_NOWILD;
   11331   1.1  christos 	wname = dns_fixedname_initname(&wfixed);
   11332   1.9  christos again:
   11333   1.3  christos 	have_wname = false;
   11334   1.1  christos 	/*
   11335   1.1  christos 	 * We'll need some resources...
   11336   1.1  christos 	 */
   11337   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   11338   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   11339   1.3  christos 	rdataset = ns_client_newrdataset(client);
   11340   1.3  christos 	sigrdataset = ns_client_newrdataset(client);
   11341   1.1  christos 
   11342   1.1  christos 	result = dns_db_findext(qctx->db, name, qctx->version,
   11343   1.9  christos 				dns_rdatatype_nsec, options, 0, &node, fname,
   11344   1.9  christos 				&cm, &ci, rdataset, sigrdataset);
   11345   1.9  christos 	if (node != NULL) {
   11346   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   11347   1.9  christos 	}
   11348   1.1  christos 
   11349   1.1  christos 	if (!dns_rdataset_isassociated(rdataset)) {
   11350   1.1  christos 		/*
   11351   1.1  christos 		 * No NSEC proof available, return NSEC3 proofs instead.
   11352   1.1  christos 		 */
   11353   1.1  christos 		cname = dns_fixedname_initname(&cfixed);
   11354   1.1  christos 		/*
   11355  1.24  christos 		 * Find the closest encloser.
   11356  1.24  christos 		 */
   11357  1.20  christos 		dns_name_copy(name, cname);
   11358  1.24  christos 		while (result == DNS_R_NXDOMAIN) {
   11359  1.24  christos 			labels = dns_name_countlabels(cname) - 1;
   11360  1.24  christos 			/*
   11361  1.24  christos 			 * Sanity check.
   11362  1.24  christos 			 */
   11363  1.24  christos 			if (labels == 0U) {
   11364  1.24  christos 				goto cleanup;
   11365   1.9  christos 			}
   11366  1.24  christos 			dns_name_split(cname, labels, NULL, cname);
   11367  1.23  christos 			result = dns_db_findext(qctx->db, cname, qctx->version,
   11368  1.23  christos 						dns_rdatatype_nsec, options, 0,
   11369  1.23  christos 						NULL, fname, &cm, &ci, NULL,
   11370  1.23  christos 						NULL);
   11371   1.1  christos 		}
   11372   1.1  christos 		/*
   11373   1.1  christos 		 * Add closest (provable) encloser NSEC3.
   11374   1.1  christos 		 */
   11375   1.9  christos 		query_findclosestnsec3(cname, qctx->db, qctx->version, client,
   11376   1.9  christos 				       rdataset, sigrdataset, fname, true,
   11377   1.9  christos 				       cname);
   11378   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11379   1.1  christos 			goto cleanup;
   11380   1.9  christos 		}
   11381   1.9  christos 		if (!ispositive) {
   11382   1.3  christos 			query_addrrset(qctx, &fname, &rdataset, &sigrdataset,
   11383   1.1  christos 				       dbuf, DNS_SECTION_AUTHORITY);
   11384   1.9  christos 		}
   11385   1.1  christos 
   11386   1.1  christos 		/*
   11387   1.1  christos 		 * Replace resources which were consumed by query_addrrset.
   11388   1.1  christos 		 */
   11389   1.1  christos 		if (fname == NULL) {
   11390   1.3  christos 			dbuf = ns_client_getnamebuf(client);
   11391   1.3  christos 			fname = ns_client_newname(client, dbuf, &b);
   11392   1.1  christos 		}
   11393   1.1  christos 
   11394   1.9  christos 		if (rdataset == NULL) {
   11395   1.3  christos 			rdataset = ns_client_newrdataset(client);
   11396   1.9  christos 		} else if (dns_rdataset_isassociated(rdataset)) {
   11397   1.1  christos 			dns_rdataset_disassociate(rdataset);
   11398   1.9  christos 		}
   11399   1.1  christos 
   11400   1.9  christos 		if (sigrdataset == NULL) {
   11401   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   11402   1.9  christos 		} else if (dns_rdataset_isassociated(sigrdataset)) {
   11403   1.1  christos 			dns_rdataset_disassociate(sigrdataset);
   11404   1.9  christos 		}
   11405   1.1  christos 
   11406   1.1  christos 		/*
   11407   1.1  christos 		 * Add no qname proof.
   11408   1.1  christos 		 */
   11409   1.1  christos 		labels = dns_name_countlabels(cname) + 1;
   11410   1.9  christos 		if (dns_name_countlabels(name) == labels) {
   11411  1.20  christos 			dns_name_copy(name, wname);
   11412   1.9  christos 		} else {
   11413   1.1  christos 			dns_name_split(name, labels, NULL, wname);
   11414   1.9  christos 		}
   11415   1.1  christos 
   11416   1.9  christos 		query_findclosestnsec3(wname, qctx->db, qctx->version, client,
   11417   1.9  christos 				       rdataset, sigrdataset, fname, false,
   11418   1.9  christos 				       NULL);
   11419   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11420   1.1  christos 			goto cleanup;
   11421   1.9  christos 		}
   11422   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11423   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11424   1.1  christos 
   11425   1.9  christos 		if (ispositive) {
   11426   1.1  christos 			goto cleanup;
   11427   1.9  christos 		}
   11428   1.1  christos 
   11429   1.1  christos 		/*
   11430   1.1  christos 		 * Replace resources which were consumed by query_addrrset.
   11431   1.1  christos 		 */
   11432   1.1  christos 		if (fname == NULL) {
   11433   1.3  christos 			dbuf = ns_client_getnamebuf(client);
   11434   1.3  christos 			fname = ns_client_newname(client, dbuf, &b);
   11435   1.1  christos 		}
   11436   1.1  christos 
   11437   1.9  christos 		if (rdataset == NULL) {
   11438   1.3  christos 			rdataset = ns_client_newrdataset(client);
   11439   1.9  christos 		} else if (dns_rdataset_isassociated(rdataset)) {
   11440   1.1  christos 			dns_rdataset_disassociate(rdataset);
   11441   1.9  christos 		}
   11442   1.1  christos 
   11443   1.9  christos 		if (sigrdataset == NULL) {
   11444   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   11445   1.9  christos 		} else if (dns_rdataset_isassociated(sigrdataset)) {
   11446   1.1  christos 			dns_rdataset_disassociate(sigrdataset);
   11447   1.9  christos 		}
   11448   1.1  christos 
   11449   1.1  christos 		/*
   11450   1.1  christos 		 * Add the no wildcard proof.
   11451   1.1  christos 		 */
   11452   1.9  christos 		result = dns_name_concatenate(dns_wildcardname, cname, wname,
   11453   1.9  christos 					      NULL);
   11454   1.9  christos 		if (result != ISC_R_SUCCESS) {
   11455   1.1  christos 			goto cleanup;
   11456   1.9  christos 		}
   11457   1.1  christos 
   11458   1.9  christos 		query_findclosestnsec3(wname, qctx->db, qctx->version, client,
   11459   1.9  christos 				       rdataset, sigrdataset, fname, nodata,
   11460   1.9  christos 				       NULL);
   11461   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11462   1.1  christos 			goto cleanup;
   11463   1.9  christos 		}
   11464   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11465   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11466   1.1  christos 
   11467   1.1  christos 		goto cleanup;
   11468   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   11469   1.9  christos 		if (!ispositive) {
   11470   1.1  christos 			result = dns_rdataset_first(rdataset);
   11471   1.9  christos 		}
   11472   1.1  christos 		if (result == ISC_R_SUCCESS) {
   11473   1.1  christos 			dns_rdataset_current(rdataset, &rdata);
   11474   1.1  christos 			result = dns_rdata_tostruct(&rdata, &nsec, NULL);
   11475   1.3  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   11476   1.1  christos 			(void)dns_name_fullcompare(name, fname, &order,
   11477   1.1  christos 						   &olabels);
   11478   1.1  christos 			(void)dns_name_fullcompare(name, &nsec.next, &order,
   11479   1.1  christos 						   &nlabels);
   11480   1.1  christos 			/*
   11481   1.1  christos 			 * Check for a pathological condition created when
   11482   1.1  christos 			 * serving some malformed signed zones and bail out.
   11483   1.1  christos 			 */
   11484   1.9  christos 			if (dns_name_countlabels(name) == nlabels) {
   11485   1.1  christos 				goto cleanup;
   11486   1.9  christos 			}
   11487   1.1  christos 
   11488   1.9  christos 			if (olabels > nlabels) {
   11489   1.1  christos 				dns_name_split(name, olabels, NULL, wname);
   11490   1.9  christos 			} else {
   11491   1.1  christos 				dns_name_split(name, nlabels, NULL, wname);
   11492   1.9  christos 			}
   11493   1.9  christos 			result = dns_name_concatenate(dns_wildcardname, wname,
   11494   1.9  christos 						      wname, NULL);
   11495   1.9  christos 			if (result == ISC_R_SUCCESS) {
   11496   1.3  christos 				have_wname = true;
   11497   1.9  christos 			}
   11498   1.1  christos 			dns_rdata_freestruct(&nsec);
   11499   1.1  christos 		}
   11500   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11501   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11502   1.1  christos 	}
   11503   1.3  christos 	if (rdataset != NULL) {
   11504   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11505   1.3  christos 	}
   11506   1.3  christos 	if (sigrdataset != NULL) {
   11507   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11508   1.3  christos 	}
   11509   1.3  christos 	if (fname != NULL) {
   11510   1.3  christos 		ns_client_releasename(client, &fname);
   11511   1.3  christos 	}
   11512   1.1  christos 	if (have_wname) {
   11513   1.9  christos 		ispositive = true; /* prevent loop */
   11514   1.1  christos 		if (!dns_name_equal(name, wname)) {
   11515   1.1  christos 			name = wname;
   11516   1.1  christos 			goto again;
   11517   1.1  christos 		}
   11518   1.1  christos 	}
   11519   1.9  christos cleanup:
   11520   1.3  christos 	if (rdataset != NULL) {
   11521   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11522   1.3  christos 	}
   11523   1.3  christos 	if (sigrdataset != NULL) {
   11524   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11525   1.3  christos 	}
   11526   1.3  christos 	if (fname != NULL) {
   11527   1.3  christos 		ns_client_releasename(client, &fname);
   11528   1.3  christos 	}
   11529   1.1  christos }
   11530   1.1  christos 
   11531   1.1  christos /*%
   11532   1.1  christos  * Add NS records, and NSEC/NSEC3 wildcard proof records if needed,
   11533   1.1  christos  * to the authority section.
   11534   1.1  christos  */
   11535   1.1  christos static void
   11536   1.1  christos query_addauth(query_ctx_t *qctx) {
   11537   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_addauth");
   11538   1.1  christos 	/*
   11539   1.1  christos 	 * Add NS records to the authority section (if we haven't already
   11540   1.1  christos 	 * added them to the answer section).
   11541   1.1  christos 	 */
   11542   1.1  christos 	if (!qctx->want_restart && !NOAUTHORITY(qctx->client)) {
   11543   1.1  christos 		if (qctx->is_zone) {
   11544   1.1  christos 			if (!qctx->answer_has_ns) {
   11545   1.1  christos 				(void)query_addns(qctx);
   11546   1.1  christos 			}
   11547   1.1  christos 		} else if (!qctx->answer_has_ns &&
   11548  1.16  christos 			   qctx->qtype != dns_rdatatype_ns)
   11549  1.16  christos 		{
   11550   1.1  christos 			if (qctx->fname != NULL) {
   11551   1.3  christos 				ns_client_releasename(qctx->client,
   11552   1.3  christos 						      &qctx->fname);
   11553   1.1  christos 			}
   11554   1.1  christos 			query_addbestns(qctx);
   11555   1.1  christos 		}
   11556   1.1  christos 	}
   11557   1.1  christos 
   11558   1.1  christos 	/*
   11559   1.1  christos 	 * Add NSEC records to the authority section if they're needed for
   11560   1.1  christos 	 * DNSSEC wildcard proofs.
   11561   1.1  christos 	 */
   11562   1.9  christos 	if (qctx->need_wildcardproof && dns_db_issecure(qctx->db)) {
   11563   1.3  christos 		query_addwildcardproof(qctx, true, false);
   11564   1.9  christos 	}
   11565   1.1  christos }
   11566   1.1  christos 
   11567   1.1  christos /*
   11568   1.1  christos  * Find the sort order of 'rdata' in the topology-like
   11569   1.1  christos  * ACL forming the second element in a 2-element top-level
   11570   1.1  christos  * sortlist statement.
   11571   1.1  christos  */
   11572   1.1  christos static int
   11573   1.1  christos query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) {
   11574   1.1  christos 	isc_netaddr_t netaddr;
   11575   1.1  christos 
   11576   1.9  christos 	if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) {
   11577  1.23  christos 		return INT_MAX;
   11578   1.9  christos 	}
   11579  1.23  christos 	return ns_sortlist_addrorder2(&netaddr, arg);
   11580   1.1  christos }
   11581   1.1  christos 
   11582   1.1  christos /*
   11583   1.1  christos  * Find the sort order of 'rdata' in the matching element
   11584   1.1  christos  * of a 1-element top-level sortlist statement.
   11585   1.1  christos  */
   11586   1.1  christos static int
   11587   1.1  christos query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) {
   11588   1.1  christos 	isc_netaddr_t netaddr;
   11589   1.1  christos 
   11590   1.9  christos 	if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) {
   11591  1.23  christos 		return INT_MAX;
   11592   1.9  christos 	}
   11593  1.23  christos 	return ns_sortlist_addrorder1(&netaddr, arg);
   11594   1.1  christos }
   11595   1.1  christos 
   11596   1.1  christos /*
   11597   1.1  christos  * Find the sortlist statement that applies to 'client' and set up
   11598   1.1  christos  * the sortlist info in in client->message appropriately.
   11599   1.1  christos  */
   11600   1.1  christos static void
   11601   1.1  christos query_setup_sortlist(query_ctx_t *qctx) {
   11602   1.1  christos 	isc_netaddr_t netaddr;
   11603   1.1  christos 	ns_client_t *client = qctx->client;
   11604  1.20  christos 	dns_aclenv_t *env = client->manager->aclenv;
   11605  1.20  christos 	dns_acl_t *acl = NULL;
   11606  1.20  christos 	dns_aclelement_t *elt = NULL;
   11607  1.20  christos 	void *order_arg = NULL;
   11608   1.1  christos 
   11609   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   11610   1.9  christos 	switch (ns_sortlist_setup(client->view->sortlist, env, &netaddr,
   11611  1.16  christos 				  &order_arg))
   11612  1.16  christos 	{
   11613   1.1  christos 	case NS_SORTLISTTYPE_1ELEMENT:
   11614  1.20  christos 		elt = order_arg;
   11615   1.1  christos 		dns_message_setsortorder(client->message,
   11616   1.9  christos 					 query_sortlist_order_1element, env,
   11617  1.20  christos 					 NULL, elt);
   11618   1.1  christos 		break;
   11619   1.1  christos 	case NS_SORTLISTTYPE_2ELEMENT:
   11620  1.20  christos 		acl = order_arg;
   11621   1.1  christos 		dns_message_setsortorder(client->message,
   11622   1.9  christos 					 query_sortlist_order_2element, env,
   11623  1.20  christos 					 acl, NULL);
   11624  1.20  christos 		dns_acl_detach(&acl);
   11625   1.1  christos 		break;
   11626   1.1  christos 	case NS_SORTLISTTYPE_NONE:
   11627   1.1  christos 		break;
   11628   1.1  christos 	default:
   11629  1.15  christos 		UNREACHABLE();
   11630   1.1  christos 	}
   11631   1.1  christos }
   11632   1.1  christos 
   11633   1.1  christos /*
   11634   1.1  christos  * When sending a referral, if the answer to the question is
   11635   1.1  christos  * in the glue, sort it to the start of the additional section.
   11636   1.1  christos  */
   11637  1.15  christos static void
   11638   1.1  christos query_glueanswer(query_ctx_t *qctx) {
   11639   1.1  christos 	const dns_namelist_t *secs = qctx->client->message->sections;
   11640   1.1  christos 	const dns_section_t section = DNS_SECTION_ADDITIONAL;
   11641   1.1  christos 	dns_name_t *name;
   11642   1.1  christos 	dns_message_t *msg;
   11643   1.1  christos 	dns_rdataset_t *rdataset = NULL;
   11644   1.1  christos 
   11645   1.1  christos 	if (!ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
   11646   1.1  christos 	    qctx->client->message->rcode != dns_rcode_noerror ||
   11647   1.1  christos 	    (qctx->qtype != dns_rdatatype_a &&
   11648   1.1  christos 	     qctx->qtype != dns_rdatatype_aaaa))
   11649   1.1  christos 	{
   11650   1.1  christos 		return;
   11651   1.1  christos 	}
   11652   1.1  christos 
   11653   1.1  christos 	msg = qctx->client->message;
   11654   1.9  christos 	for (name = ISC_LIST_HEAD(msg->sections[section]); name != NULL;
   11655   1.1  christos 	     name = ISC_LIST_NEXT(name, link))
   11656   1.9  christos 	{
   11657   1.1  christos 		if (dns_name_equal(name, qctx->client->query.qname)) {
   11658   1.1  christos 			for (rdataset = ISC_LIST_HEAD(name->list);
   11659   1.1  christos 			     rdataset != NULL;
   11660   1.1  christos 			     rdataset = ISC_LIST_NEXT(rdataset, link))
   11661   1.9  christos 			{
   11662   1.9  christos 				if (rdataset->type == qctx->qtype) {
   11663   1.1  christos 					break;
   11664   1.9  christos 				}
   11665   1.9  christos 			}
   11666   1.1  christos 			break;
   11667   1.1  christos 		}
   11668   1.9  christos 	}
   11669   1.1  christos 	if (rdataset != NULL) {
   11670   1.1  christos 		ISC_LIST_UNLINK(msg->sections[section], name, link);
   11671   1.1  christos 		ISC_LIST_PREPEND(msg->sections[section], name, link);
   11672   1.1  christos 		ISC_LIST_UNLINK(name->list, rdataset, link);
   11673   1.1  christos 		ISC_LIST_PREPEND(name->list, rdataset, link);
   11674   1.1  christos 		rdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   11675   1.1  christos 	}
   11676   1.1  christos }
   11677   1.1  christos 
   11678   1.3  christos isc_result_t
   11679   1.3  christos ns_query_done(query_ctx_t *qctx) {
   11680  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   11681   1.1  christos 	const dns_namelist_t *secs = qctx->client->message->sections;
   11682  1.23  christos 	bool partial_result_with_servfail = false;
   11683   1.1  christos 
   11684   1.3  christos 	CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done");
   11685   1.3  christos 
   11686   1.3  christos 	CALL_HOOK(NS_QUERY_DONE_BEGIN, qctx);
   11687   1.1  christos 
   11688   1.1  christos 	/*
   11689   1.1  christos 	 * General cleanup.
   11690   1.1  christos 	 */
   11691   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   11692   1.1  christos 	if (qctx->rpz_st != NULL &&
   11693  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) == 0)
   11694  1.16  christos 	{
   11695   1.1  christos 		rpz_match_clear(qctx->rpz_st);
   11696   1.1  christos 		qctx->rpz_st->state &= ~DNS_RPZ_DONE_QNAME;
   11697   1.1  christos 	}
   11698   1.1  christos 
   11699   1.1  christos 	qctx_clean(qctx);
   11700   1.1  christos 	qctx_freedata(qctx);
   11701   1.1  christos 
   11702   1.1  christos 	/*
   11703   1.1  christos 	 * Clear the AA bit if we're not authoritative.
   11704   1.1  christos 	 */
   11705   1.1  christos 	if (qctx->client->query.restarts == 0 && !qctx->authoritative) {
   11706   1.1  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
   11707   1.1  christos 	}
   11708   1.1  christos 
   11709   1.1  christos 	/*
   11710   1.1  christos 	 * Do we need to restart the query (e.g. for CNAME chaining)?
   11711   1.1  christos 	 */
   11712  1.22  christos 	if (qctx->want_restart) {
   11713  1.22  christos 		if (qctx->client->query.restarts <
   11714  1.22  christos 		    qctx->client->view->max_restarts)
   11715  1.22  christos 		{
   11716  1.23  christos 			query_ctx_t *saved_qctx = NULL;
   11717  1.22  christos 			qctx->client->query.restarts++;
   11718  1.23  christos 			saved_qctx = isc_mem_get(qctx->client->manager->mctx,
   11719  1.23  christos 						 sizeof(*saved_qctx));
   11720  1.23  christos 			qctx_save(qctx, saved_qctx);
   11721  1.23  christos 			isc_nmhandle_attach(qctx->client->handle,
   11722  1.23  christos 					    &qctx->client->restarthandle);
   11723  1.23  christos 			isc_async_run(qctx->client->manager->loop,
   11724  1.23  christos 				      async_restart, saved_qctx);
   11725  1.23  christos 			return DNS_R_CONTINUE;
   11726  1.22  christos 		} else {
   11727  1.22  christos 			/*
   11728  1.22  christos 			 * This is e.g. a long CNAME chain which we cut short.
   11729  1.22  christos 			 */
   11730  1.22  christos 			qctx->client->query.attributes |=
   11731  1.22  christos 				NS_QUERYATTR_PARTIALANSWER;
   11732  1.22  christos 			qctx->client->message->rcode = dns_rcode_servfail;
   11733  1.22  christos 			qctx->result = DNS_R_SERVFAIL;
   11734  1.22  christos 
   11735  1.22  christos 			/*
   11736  1.22  christos 			 * Send the answer back with a SERVFAIL result even
   11737  1.22  christos 			 * if recursion was requested.
   11738  1.22  christos 			 */
   11739  1.22  christos 			partial_result_with_servfail = true;
   11740  1.22  christos 
   11741  1.24  christos 			dns_ede_add(&qctx->client->edectx, DNS_EDE_OTHER,
   11742  1.24  christos 				    "max. restarts reached");
   11743  1.22  christos 			ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
   11744  1.22  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   11745  1.22  christos 				      "query iterations limit reached");
   11746  1.22  christos 		}
   11747   1.1  christos 	}
   11748   1.1  christos 
   11749   1.1  christos 	if (qctx->result != ISC_R_SUCCESS &&
   11750  1.22  christos 	    (!PARTIALANSWER(qctx->client) ||
   11751  1.22  christos 	     (WANTRECURSION(qctx->client) && !partial_result_with_servfail) ||
   11752   1.1  christos 	     qctx->result == DNS_R_DROP))
   11753   1.1  christos 	{
   11754   1.1  christos 		if (qctx->result == DNS_R_DUPLICATE ||
   11755  1.16  christos 		    qctx->result == DNS_R_DROP)
   11756  1.16  christos 		{
   11757   1.1  christos 			/*
   11758   1.1  christos 			 * This was a duplicate query that we are
   11759   1.1  christos 			 * recursing on or the result of rate limiting.
   11760   1.1  christos 			 * Don't send a response now for a duplicate query,
   11761   1.1  christos 			 * because the original will still cause a response.
   11762   1.1  christos 			 */
   11763   1.1  christos 			query_next(qctx->client, qctx->result);
   11764   1.1  christos 		} else {
   11765   1.1  christos 			/*
   11766   1.1  christos 			 * If we don't have any answer to give the client,
   11767   1.1  christos 			 * or if the client requested recursion and thus wanted
   11768   1.1  christos 			 * the complete answer, send an error response.
   11769   1.1  christos 			 */
   11770   1.1  christos 			INSIST(qctx->line >= 0);
   11771   1.1  christos 			query_error(qctx->client, qctx->result, qctx->line);
   11772   1.1  christos 		}
   11773   1.1  christos 
   11774   1.3  christos 		qctx->detach_client = true;
   11775  1.23  christos 		return qctx->result;
   11776   1.1  christos 	}
   11777   1.1  christos 
   11778   1.1  christos 	/*
   11779   1.1  christos 	 * If we're recursing then just return; the query will
   11780   1.1  christos 	 * resume when recursion ends.
   11781   1.1  christos 	 */
   11782  1.11  christos 	if (RECURSING(qctx->client) &&
   11783  1.13  christos 	    (!QUERY_STALETIMEOUT(&qctx->client->query) ||
   11784  1.23  christos 	     qctx->options.stalefirst))
   11785  1.11  christos 	{
   11786  1.23  christos 		return qctx->result;
   11787   1.1  christos 	}
   11788   1.1  christos 
   11789   1.1  christos 	/*
   11790   1.1  christos 	 * We are done.  Set up sortlist data for the message
   11791   1.1  christos 	 * rendering code, sort the answer to the front of the
   11792   1.1  christos 	 * additional section if necessary, make a final tweak
   11793   1.1  christos 	 * to the AA bit if the auth-nxdomain config option
   11794   1.1  christos 	 * says so, then render and send the response.
   11795   1.1  christos 	 */
   11796  1.13  christos 	query_setup_sortlist(qctx);
   11797  1.13  christos 	query_glueanswer(qctx);
   11798   1.1  christos 
   11799   1.1  christos 	if (qctx->client->message->rcode == dns_rcode_nxdomain &&
   11800  1.10  christos 	    qctx->view->auth_nxdomain)
   11801   1.1  christos 	{
   11802   1.1  christos 		qctx->client->message->flags |= DNS_MESSAGEFLAG_AA;
   11803   1.1  christos 	}
   11804   1.1  christos 
   11805   1.1  christos 	/*
   11806   1.1  christos 	 * If the response is somehow unexpected for the client and this
   11807   1.1  christos 	 * is a result of recursion, return an error to the caller
   11808   1.1  christos 	 * to indicate it may need to be logged.
   11809   1.1  christos 	 */
   11810   1.1  christos 	if (qctx->resuming &&
   11811   1.1  christos 	    (ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
   11812   1.1  christos 	     qctx->client->message->rcode != dns_rcode_noerror))
   11813   1.1  christos 	{
   11814   1.1  christos 		qctx->result = ISC_R_FAILURE;
   11815   1.1  christos 	}
   11816   1.1  christos 
   11817   1.3  christos 	CALL_HOOK(NS_QUERY_DONE_SEND, qctx);
   11818   1.3  christos 
   11819   1.1  christos 	query_send(qctx->client);
   11820  1.15  christos 
   11821  1.23  christos 	qctx->detach_client = true;
   11822  1.23  christos 
   11823  1.23  christos 	return qctx->result;
   11824   1.3  christos 
   11825   1.9  christos cleanup:
   11826  1.24  christos 	/*
   11827  1.24  christos 	 * We'd only get here if one of the hooks above
   11828  1.24  christos 	 * (NS_QUERY_DONE_BEGIN or NS_QUERY_DONE_SEND) returned
   11829  1.24  christos 	 * NS_HOOK_RETURN. Some housekeeping may be needed.
   11830  1.24  christos 	 */
   11831  1.24  christos 	qctx_clean(qctx);
   11832  1.24  christos 	qctx_freedata(qctx);
   11833  1.24  christos 	if (!qctx->async) {
   11834  1.24  christos 		qctx->detach_client = true;
   11835  1.24  christos 		query_error(qctx->client, DNS_R_SERVFAIL, __LINE__);
   11836  1.24  christos 	}
   11837  1.23  christos 	return result;
   11838   1.1  christos }
   11839   1.1  christos 
   11840  1.15  christos static void
   11841   1.1  christos log_tat(ns_client_t *client) {
   11842   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   11843   1.1  christos 	char clientbuf[ISC_NETADDR_FORMATSIZE];
   11844   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   11845   1.1  christos 	isc_netaddr_t netaddr;
   11846   1.1  christos 	char *tags = NULL;
   11847   1.1  christos 	size_t taglen = 0;
   11848   1.1  christos 
   11849   1.1  christos 	if (!isc_log_wouldlog(ns_lctx, ISC_LOG_INFO)) {
   11850   1.1  christos 		return;
   11851   1.1  christos 	}
   11852   1.1  christos 
   11853   1.1  christos 	if ((client->query.qtype != dns_rdatatype_null ||
   11854   1.1  christos 	     !dns_name_istat(client->query.qname)) &&
   11855   1.1  christos 	    (client->keytag == NULL ||
   11856   1.1  christos 	     client->query.qtype != dns_rdatatype_dnskey))
   11857   1.1  christos 	{
   11858   1.1  christos 		return;
   11859   1.1  christos 	}
   11860   1.1  christos 
   11861   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   11862   1.1  christos 	dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
   11863   1.3  christos 	isc_netaddr_format(&netaddr, clientbuf, sizeof(clientbuf));
   11864   1.3  christos 	dns_rdataclass_format(client->view->rdclass, classbuf,
   11865   1.3  christos 			      sizeof(classbuf));
   11866   1.1  christos 
   11867   1.1  christos 	if (client->query.qtype == dns_rdatatype_dnskey) {
   11868   1.3  christos 		uint16_t keytags = client->keytag_len / 2;
   11869   1.1  christos 		size_t len = taglen = sizeof("65000") * keytags + 1;
   11870  1.23  christos 		char *cp = tags = isc_mem_get(client->manager->mctx, taglen);
   11871   1.1  christos 		int i = 0;
   11872   1.1  christos 
   11873   1.1  christos 		INSIST(client->keytag != NULL);
   11874   1.1  christos 		if (tags != NULL) {
   11875   1.1  christos 			while (keytags-- > 0U) {
   11876   1.1  christos 				int n;
   11877   1.3  christos 				uint16_t keytag;
   11878   1.1  christos 				keytag = (client->keytag[i * 2] << 8) |
   11879   1.1  christos 					 client->keytag[i * 2 + 1];
   11880   1.1  christos 				n = snprintf(cp, len, " %u", keytag);
   11881   1.1  christos 				if (n > 0 && (size_t)n <= len) {
   11882   1.1  christos 					cp += n;
   11883   1.1  christos 					len -= n;
   11884   1.1  christos 					i++;
   11885   1.1  christos 				} else {
   11886   1.1  christos 					break;
   11887   1.1  christos 				}
   11888   1.1  christos 			}
   11889   1.1  christos 		}
   11890   1.1  christos 	}
   11891   1.1  christos 
   11892   1.1  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_TAT, NS_LOGMODULE_QUERY,
   11893   1.1  christos 		      ISC_LOG_INFO, "trust-anchor-telemetry '%s/%s' from %s%s",
   11894   1.9  christos 		      namebuf, classbuf, clientbuf, tags != NULL ? tags : "");
   11895   1.1  christos 	if (tags != NULL) {
   11896  1.23  christos 		isc_mem_put(client->manager->mctx, tags, taglen);
   11897   1.1  christos 	}
   11898   1.1  christos }
   11899   1.1  christos 
   11900  1.15  christos static void
   11901   1.1  christos log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) {
   11902   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   11903   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   11904   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   11905   1.1  christos 	char onbuf[ISC_NETADDR_FORMATSIZE];
   11906  1.23  christos 	char ecsbuf[NS_CLIENT_ECS_FORMATSIZE] = { 0 };
   11907  1.23  christos 	char flagsbuf[NS_CLIENT_FLAGS_FORMATSIZE] = { 0 };
   11908   1.1  christos 	dns_rdataset_t *rdataset;
   11909   1.1  christos 	int level = ISC_LOG_INFO;
   11910   1.1  christos 
   11911   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   11912   1.1  christos 		return;
   11913   1.9  christos 	}
   11914   1.1  christos 
   11915   1.1  christos 	rdataset = ISC_LIST_HEAD(client->query.qname->list);
   11916   1.1  christos 	INSIST(rdataset != NULL);
   11917   1.1  christos 	dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
   11918   1.3  christos 	dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf));
   11919   1.3  christos 	dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
   11920   1.1  christos 	isc_netaddr_format(&client->destaddr, onbuf, sizeof(onbuf));
   11921   1.1  christos 
   11922   1.1  christos 	if (HAVEECS(client)) {
   11923  1.23  christos 		ns_client_log_ecs(client, ecsbuf, sizeof(ecsbuf));
   11924   1.1  christos 	}
   11925  1.23  christos 	ns_client_log_flags(client, flags, extflags, flagsbuf,
   11926  1.23  christos 			    sizeof(flagsbuf));
   11927   1.1  christos 
   11928   1.9  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY, level,
   11929  1.23  christos 		      "query: %s %s %s %s (%s)%s", namebuf, classbuf, typebuf,
   11930  1.23  christos 		      flagsbuf, onbuf, ecsbuf);
   11931   1.1  christos }
   11932   1.1  christos 
   11933  1.15  christos static void
   11934   1.1  christos log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) {
   11935   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   11936   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   11937   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   11938   1.1  christos 	const char *namep, *typep, *classp, *sep1, *sep2;
   11939   1.1  christos 	dns_rdataset_t *rdataset;
   11940   1.1  christos 
   11941   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   11942   1.1  christos 		return;
   11943   1.9  christos 	}
   11944   1.1  christos 
   11945   1.1  christos 	namep = typep = classp = sep1 = sep2 = "";
   11946   1.1  christos 
   11947   1.1  christos 	/*
   11948   1.1  christos 	 * Query errors can happen for various reasons.  In some cases we cannot
   11949   1.1  christos 	 * even assume the query contains a valid question section, so we should
   11950   1.1  christos 	 * expect exceptional cases.
   11951   1.1  christos 	 */
   11952   1.1  christos 	if (client->query.origqname != NULL) {
   11953   1.1  christos 		dns_name_format(client->query.origqname, namebuf,
   11954   1.1  christos 				sizeof(namebuf));
   11955   1.1  christos 		namep = namebuf;
   11956   1.1  christos 		sep1 = " for ";
   11957   1.1  christos 
   11958   1.1  christos 		rdataset = ISC_LIST_HEAD(client->query.origqname->list);
   11959   1.1  christos 		if (rdataset != NULL) {
   11960   1.3  christos 			dns_rdataclass_format(rdataset->rdclass, classbuf,
   11961   1.3  christos 					      sizeof(classbuf));
   11962   1.3  christos 			classp = classbuf;
   11963   1.3  christos 			dns_rdatatype_format(rdataset->type, typebuf,
   11964   1.3  christos 					     sizeof(typebuf));
   11965   1.3  christos 			typep = typebuf;
   11966   1.1  christos 			sep2 = "/";
   11967   1.1  christos 		}
   11968   1.1  christos 	}
   11969   1.1  christos 
   11970   1.1  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS, NS_LOGMODULE_QUERY,
   11971   1.1  christos 		      level, "query failed (%s)%s%s%s%s%s%s at %s:%d",
   11972   1.9  christos 		      isc_result_totext(result), sep1, namep, sep2, classp,
   11973   1.9  christos 		      sep2, typep, __FILE__, line);
   11974   1.1  christos }
   11975   1.1  christos 
   11976   1.1  christos void
   11977  1.11  christos ns_query_start(ns_client_t *client, isc_nmhandle_t *handle) {
   11978   1.1  christos 	isc_result_t result;
   11979   1.8  christos 	dns_message_t *message;
   11980   1.1  christos 	dns_rdataset_t *rdataset;
   11981   1.1  christos 	dns_rdatatype_t qtype;
   11982   1.8  christos 	unsigned int saved_extflags;
   11983   1.8  christos 	unsigned int saved_flags;
   11984   1.1  christos 
   11985   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   11986   1.1  christos 
   11987  1.11  christos 	/*
   11988  1.11  christos 	 * Attach to the request handle
   11989  1.11  christos 	 */
   11990  1.11  christos 	isc_nmhandle_attach(handle, &client->reqhandle);
   11991  1.11  christos 
   11992   1.8  christos 	message = client->message;
   11993   1.8  christos 	saved_extflags = client->extflags;
   11994   1.8  christos 	saved_flags = client->message->flags;
   11995   1.8  christos 
   11996   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "ns_query_start");
   11997   1.1  christos 
   11998   1.1  christos 	/*
   11999   1.1  christos 	 * Ensure that appropriate cleanups occur.
   12000   1.1  christos 	 */
   12001   1.9  christos 	client->cleanup = query_cleanup;
   12002   1.1  christos 
   12003   1.9  christos 	if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) {
   12004   1.9  christos 		client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
   12005   1.1  christos 	}
   12006   1.1  christos 
   12007   1.9  christos 	if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0) {
   12008   1.1  christos 		client->attributes |= NS_CLIENTATTR_WANTDNSSEC;
   12009   1.9  christos 	}
   12010   1.1  christos 
   12011   1.1  christos 	switch (client->view->minimalresponses) {
   12012   1.1  christos 	case dns_minimal_no:
   12013   1.1  christos 		break;
   12014   1.1  christos 	case dns_minimal_yes:
   12015   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   12016   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   12017   1.1  christos 		break;
   12018   1.1  christos 	case dns_minimal_noauth:
   12019   1.1  christos 		client->query.attributes |= NS_QUERYATTR_NOAUTHORITY;
   12020   1.1  christos 		break;
   12021   1.1  christos 	case dns_minimal_noauthrec:
   12022   1.9  christos 		if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) {
   12023   1.1  christos 			client->query.attributes |= NS_QUERYATTR_NOAUTHORITY;
   12024   1.9  christos 		}
   12025   1.1  christos 		break;
   12026   1.1  christos 	}
   12027   1.1  christos 
   12028   1.1  christos 	if (client->view->cachedb == NULL || !client->view->recursion) {
   12029   1.1  christos 		/*
   12030   1.1  christos 		 * We don't have a cache.  Turn off cache support and
   12031   1.1  christos 		 * recursion.
   12032   1.1  christos 		 */
   12033   1.9  christos 		client->query.attributes &= ~(NS_QUERYATTR_RECURSIONOK |
   12034   1.9  christos 					      NS_QUERYATTR_CACHEOK);
   12035   1.1  christos 		client->attributes |= NS_CLIENTATTR_NOSETFC;
   12036   1.1  christos 	} else if ((client->attributes & NS_CLIENTATTR_RA) == 0 ||
   12037   1.9  christos 		   (message->flags & DNS_MESSAGEFLAG_RD) == 0)
   12038   1.9  christos 	{
   12039   1.1  christos 		/*
   12040   1.1  christos 		 * If the client isn't allowed to recurse (due to
   12041   1.1  christos 		 * "recursion no", the allow-recursion ACL, or the
   12042   1.1  christos 		 * lack of a resolver in this view), or if it
   12043   1.1  christos 		 * doesn't want recursion, turn recursion off.
   12044   1.1  christos 		 */
   12045   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
   12046   1.1  christos 		client->attributes |= NS_CLIENTATTR_NOSETFC;
   12047   1.1  christos 	}
   12048   1.1  christos 
   12049   1.1  christos 	/*
   12050   1.1  christos 	 * Check for multiple question queries, since edns1 is dead.
   12051   1.1  christos 	 */
   12052   1.1  christos 	if (message->counts[DNS_SECTION_QUESTION] > 1) {
   12053   1.1  christos 		query_error(client, DNS_R_FORMERR, __LINE__);
   12054   1.1  christos 		return;
   12055   1.1  christos 	}
   12056   1.1  christos 
   12057   1.1  christos 	/*
   12058   1.1  christos 	 * Get the question name.
   12059   1.1  christos 	 */
   12060   1.1  christos 	result = dns_message_firstname(message, DNS_SECTION_QUESTION);
   12061   1.1  christos 	if (result != ISC_R_SUCCESS) {
   12062   1.1  christos 		query_error(client, result, __LINE__);
   12063   1.1  christos 		return;
   12064   1.1  christos 	}
   12065   1.1  christos 	dns_message_currentname(message, DNS_SECTION_QUESTION,
   12066   1.1  christos 				&client->query.qname);
   12067   1.1  christos 	client->query.origqname = client->query.qname;
   12068   1.1  christos 	result = dns_message_nextname(message, DNS_SECTION_QUESTION);
   12069   1.1  christos 	if (result != ISC_R_NOMORE) {
   12070   1.1  christos 		if (result == ISC_R_SUCCESS) {
   12071   1.1  christos 			/*
   12072   1.1  christos 			 * There's more than one QNAME in the question
   12073   1.1  christos 			 * section.
   12074   1.1  christos 			 */
   12075   1.1  christos 			query_error(client, DNS_R_FORMERR, __LINE__);
   12076   1.9  christos 		} else {
   12077   1.1  christos 			query_error(client, result, __LINE__);
   12078   1.9  christos 		}
   12079   1.1  christos 		return;
   12080   1.1  christos 	}
   12081   1.1  christos 
   12082  1.23  christos 	if ((client->manager->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
   12083   1.1  christos 		log_query(client, saved_flags, saved_extflags);
   12084   1.9  christos 	}
   12085   1.1  christos 
   12086   1.1  christos 	/*
   12087   1.1  christos 	 * Check for meta-queries like IXFR and AXFR.
   12088   1.1  christos 	 */
   12089   1.1  christos 	rdataset = ISC_LIST_HEAD(client->query.qname->list);
   12090   1.1  christos 	INSIST(rdataset != NULL);
   12091   1.1  christos 	client->query.qtype = qtype = rdataset->type;
   12092  1.23  christos 	dns_rdatatypestats_increment(client->manager->sctx->rcvquerystats,
   12093  1.23  christos 				     qtype);
   12094   1.1  christos 
   12095   1.1  christos 	log_tat(client);
   12096   1.1  christos 
   12097   1.1  christos 	if (dns_rdatatype_ismeta(qtype)) {
   12098   1.1  christos 		switch (qtype) {
   12099   1.1  christos 		case dns_rdatatype_any:
   12100   1.1  christos 			break; /* Let the query logic handle it. */
   12101   1.1  christos 		case dns_rdatatype_ixfr:
   12102   1.1  christos 		case dns_rdatatype_axfr:
   12103  1.20  christos 			if (isc_nm_is_http_handle(handle)) {
   12104  1.20  christos 				/*
   12105  1.20  christos 				 * We cannot use DoH for zone transfers.
   12106  1.20  christos 				 * According to RFC 8484 a DoH request contains
   12107  1.20  christos 				 * exactly one DNS message (see Section 6:
   12108  1.20  christos 				 * Definition of the "application/dns-message"
   12109  1.20  christos 				 * Media Type).
   12110  1.20  christos 				 *
   12111  1.20  christos 				 * This makes DoH unsuitable for zone transfers
   12112  1.20  christos 				 * as often (and usually!) these need more than
   12113  1.20  christos 				 * one DNS message, especially for larger zones.
   12114  1.20  christos 				 * As zone transfers over DoH are not (yet)
   12115  1.20  christos 				 * standardised, nor discussed in RFC 8484,
   12116  1.20  christos 				 * the best thing we can do is to return "not
   12117  1.20  christos 				 * implemented".
   12118  1.20  christos 				 */
   12119  1.20  christos 				query_error(client, DNS_R_NOTIMP, __LINE__);
   12120  1.20  christos 				return;
   12121  1.20  christos 			}
   12122  1.23  christos 			if (isc_nm_socket_type(handle) ==
   12123  1.23  christos 			    isc_nm_streamdnssocket)
   12124  1.23  christos 			{
   12125  1.20  christos 				/*
   12126  1.20  christos 				 * Currently this code is here for DoT, which
   12127  1.20  christos 				 * has more complex requirements for zone
   12128  1.20  christos 				 * transfers compared to other stream
   12129  1.20  christos 				 * protocols. See RFC 9103 for details.
   12130  1.20  christos 				 */
   12131  1.20  christos 				switch (isc_nm_xfr_checkperm(handle)) {
   12132  1.20  christos 				case ISC_R_SUCCESS:
   12133  1.20  christos 					break;
   12134  1.20  christos 				case ISC_R_DOTALPNERROR:
   12135  1.20  christos 					query_error(client, DNS_R_NOALPN,
   12136  1.20  christos 						    __LINE__);
   12137  1.20  christos 					return;
   12138  1.20  christos 				default:
   12139  1.20  christos 					query_error(client, DNS_R_REFUSED,
   12140  1.20  christos 						    __LINE__);
   12141  1.20  christos 					return;
   12142  1.20  christos 				}
   12143  1.20  christos 			}
   12144   1.1  christos 			ns_xfr_start(client, rdataset->type);
   12145   1.1  christos 			return;
   12146   1.1  christos 		case dns_rdatatype_maila:
   12147   1.1  christos 		case dns_rdatatype_mailb:
   12148   1.1  christos 			query_error(client, DNS_R_NOTIMP, __LINE__);
   12149   1.1  christos 			return;
   12150   1.1  christos 		case dns_rdatatype_tkey:
   12151   1.9  christos 			result = dns_tkey_processquery(
   12152  1.23  christos 				client->message, client->manager->sctx->tkeyctx,
   12153   1.9  christos 				client->view->dynamickeys);
   12154   1.9  christos 			if (result == ISC_R_SUCCESS) {
   12155   1.1  christos 				query_send(client);
   12156   1.9  christos 			} else {
   12157   1.1  christos 				query_error(client, result, __LINE__);
   12158   1.9  christos 			}
   12159   1.1  christos 			return;
   12160   1.1  christos 		default: /* TSIG, etc. */
   12161   1.1  christos 			query_error(client, DNS_R_FORMERR, __LINE__);
   12162   1.1  christos 			return;
   12163   1.1  christos 		}
   12164   1.1  christos 	}
   12165   1.1  christos 
   12166   1.1  christos 	/*
   12167   1.1  christos 	 * Turn on minimal response for (C)DNSKEY and (C)DS queries.
   12168   1.1  christos 	 */
   12169  1.22  christos 	if (dns_rdatatype_iskeymaterial(qtype) || qtype == dns_rdatatype_ds) {
   12170   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   12171   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   12172  1.11  christos 	} else if (qtype == dns_rdatatype_ns) {
   12173  1.11  christos 		/*
   12174  1.11  christos 		 * Always turn on additional records for NS queries.
   12175  1.11  christos 		 */
   12176  1.11  christos 		client->query.attributes &= ~(NS_QUERYATTR_NOAUTHORITY |
   12177  1.11  christos 					      NS_QUERYATTR_NOADDITIONAL);
   12178   1.1  christos 	}
   12179   1.1  christos 
   12180   1.1  christos 	/*
   12181   1.1  christos 	 * Maybe turn on minimal responses for ANY queries.
   12182   1.1  christos 	 */
   12183   1.9  christos 	if (qtype == dns_rdatatype_any && client->view->minimal_any &&
   12184  1.16  christos 	    !TCP(client))
   12185  1.16  christos 	{
   12186   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   12187   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   12188   1.9  christos 	}
   12189   1.1  christos 
   12190   1.1  christos 	/*
   12191   1.1  christos 	 * Turn on minimal responses for EDNS/UDP bufsize 512 queries.
   12192   1.1  christos 	 */
   12193   1.1  christos 	if (client->ednsversion >= 0 && client->udpsize <= 512U && !TCP(client))
   12194   1.9  christos 	{
   12195   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   12196   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   12197   1.9  christos 	}
   12198   1.1  christos 
   12199   1.1  christos 	/*
   12200   1.1  christos 	 * If the client has requested that DNSSEC checking be disabled,
   12201   1.1  christos 	 * allow lookups to return pending data and instruct the resolver
   12202   1.1  christos 	 * to return data before validation has completed.
   12203   1.1  christos 	 *
   12204   1.1  christos 	 * We don't need to set DNS_DBFIND_PENDINGOK when validation is
   12205   1.1  christos 	 * disabled as there will be no pending data.
   12206   1.1  christos 	 */
   12207   1.3  christos 	if ((message->flags & DNS_MESSAGEFLAG_CD) != 0 ||
   12208  1.16  christos 	    qtype == dns_rdatatype_rrsig)
   12209  1.16  christos 	{
   12210   1.1  christos 		client->query.dboptions |= DNS_DBFIND_PENDINGOK;
   12211   1.1  christos 		client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
   12212   1.9  christos 	} else if (!client->view->enablevalidation) {
   12213   1.1  christos 		client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
   12214   1.9  christos 	}
   12215   1.1  christos 
   12216   1.3  christos 	if (client->view->qminimization) {
   12217   1.3  christos 		client->query.fetchoptions |= DNS_FETCHOPT_QMINIMIZE |
   12218   1.9  christos 					      DNS_FETCHOPT_QMIN_SKIP_IP6A;
   12219   1.3  christos 		if (client->view->qmin_strict) {
   12220   1.3  christos 			client->query.fetchoptions |= DNS_FETCHOPT_QMIN_STRICT;
   12221   1.3  christos 		}
   12222   1.3  christos 	}
   12223   1.3  christos 
   12224   1.1  christos 	/*
   12225   1.1  christos 	 * Allow glue NS records to be added to the authority section
   12226   1.1  christos 	 * if the answer is secure.
   12227   1.1  christos 	 */
   12228   1.3  christos 	if ((message->flags & DNS_MESSAGEFLAG_CD) != 0) {
   12229   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   12230   1.3  christos 	}
   12231   1.1  christos 
   12232   1.1  christos 	/*
   12233   1.1  christos 	 * Set NS_CLIENTATTR_WANTAD if the client has set AD in the query.
   12234   1.1  christos 	 * This allows AD to be returned on queries without DO set.
   12235   1.1  christos 	 */
   12236   1.9  christos 	if ((message->flags & DNS_MESSAGEFLAG_AD) != 0) {
   12237   1.1  christos 		client->attributes |= NS_CLIENTATTR_WANTAD;
   12238   1.9  christos 	}
   12239   1.1  christos 
   12240   1.1  christos 	/*
   12241   1.1  christos 	 * This is an ordinary query.
   12242   1.1  christos 	 */
   12243   1.3  christos 	result = dns_message_reply(message, true);
   12244   1.1  christos 	if (result != ISC_R_SUCCESS) {
   12245   1.1  christos 		query_next(client, result);
   12246   1.1  christos 		return;
   12247   1.1  christos 	}
   12248   1.1  christos 
   12249   1.1  christos 	/*
   12250   1.1  christos 	 * Assume authoritative response until it is known to be
   12251   1.1  christos 	 * otherwise.
   12252   1.1  christos 	 *
   12253   1.1  christos 	 * If "-T noaa" has been set on the command line don't set
   12254   1.1  christos 	 * AA on authoritative answers.
   12255   1.1  christos 	 */
   12256  1.23  christos 	if ((client->manager->sctx->options & NS_SERVER_NOAA) == 0) {
   12257   1.1  christos 		message->flags |= DNS_MESSAGEFLAG_AA;
   12258   1.9  christos 	}
   12259   1.1  christos 
   12260   1.1  christos 	/*
   12261   1.1  christos 	 * Set AD.  We must clear it if we add non-validated data to a
   12262   1.1  christos 	 * response.
   12263   1.1  christos 	 */
   12264   1.9  christos 	if (WANTDNSSEC(client) || WANTAD(client)) {
   12265   1.1  christos 		message->flags |= DNS_MESSAGEFLAG_AD;
   12266   1.9  christos 	}
   12267   1.1  christos 
   12268  1.24  christos 	/*
   12269  1.24  christos 	 * Start global outgoing query count.
   12270  1.24  christos 	 */
   12271  1.24  christos 	result = isc_counter_create(client->manager->mctx,
   12272  1.24  christos 				    client->view->max_queries,
   12273  1.24  christos 				    &client->query.qc);
   12274  1.24  christos 	if (result != ISC_R_SUCCESS) {
   12275  1.24  christos 		query_next(client, result);
   12276  1.24  christos 		return;
   12277  1.24  christos 	}
   12278  1.24  christos 
   12279  1.23  christos 	query_setup(client, qtype);
   12280   1.1  christos }
   12281