Home | History | Annotate | Line # | Download | only in ns
query.c revision 1.22
      1  1.21  christos /*	$NetBSD: query.c,v 1.22 2024/09/22 00:14:10 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.1  christos #include <string.h>
     22   1.1  christos 
     23   1.1  christos #include <isc/hex.h>
     24   1.1  christos #include <isc/mem.h>
     25   1.9  christos #include <isc/once.h>
     26   1.1  christos #include <isc/print.h>
     27   1.1  christos #include <isc/random.h>
     28  1.20  christos #include <isc/result.h>
     29   1.1  christos #include <isc/rwlock.h>
     30   1.1  christos #include <isc/serial.h>
     31   1.1  christos #include <isc/stats.h>
     32   1.1  christos #include <isc/string.h>
     33   1.1  christos #include <isc/thread.h>
     34   1.1  christos #include <isc/util.h>
     35   1.1  christos 
     36   1.1  christos #include <dns/adb.h>
     37   1.1  christos #include <dns/badcache.h>
     38   1.1  christos #include <dns/byaddr.h>
     39   1.1  christos #include <dns/cache.h>
     40   1.1  christos #include <dns/db.h>
     41   1.1  christos #include <dns/dlz.h>
     42   1.1  christos #include <dns/dns64.h>
     43   1.1  christos #include <dns/dnsrps.h>
     44   1.1  christos #include <dns/dnssec.h>
     45   1.1  christos #include <dns/events.h>
     46   1.1  christos #include <dns/keytable.h>
     47   1.1  christos #include <dns/message.h>
     48   1.1  christos #include <dns/ncache.h>
     49   1.1  christos #include <dns/nsec.h>
     50   1.1  christos #include <dns/nsec3.h>
     51   1.1  christos #include <dns/order.h>
     52  1.20  christos #include <dns/rbt.h>
     53   1.1  christos #include <dns/rdata.h>
     54   1.1  christos #include <dns/rdataclass.h>
     55   1.1  christos #include <dns/rdatalist.h>
     56   1.1  christos #include <dns/rdataset.h>
     57   1.1  christos #include <dns/rdatasetiter.h>
     58   1.1  christos #include <dns/rdatastruct.h>
     59   1.1  christos #include <dns/rdatatype.h>
     60   1.1  christos #include <dns/resolver.h>
     61   1.1  christos #include <dns/result.h>
     62   1.1  christos #include <dns/stats.h>
     63   1.1  christos #include <dns/tkey.h>
     64   1.1  christos #include <dns/types.h>
     65   1.1  christos #include <dns/view.h>
     66   1.1  christos #include <dns/zone.h>
     67   1.1  christos #include <dns/zt.h>
     68   1.1  christos 
     69   1.1  christos #include <ns/client.h>
     70  1.20  christos #include <ns/events.h>
     71   1.9  christos #include <ns/hooks.h>
     72   1.1  christos #include <ns/interfacemgr.h>
     73   1.1  christos #include <ns/log.h>
     74   1.1  christos #include <ns/server.h>
     75   1.1  christos #include <ns/sortlist.h>
     76   1.1  christos #include <ns/stats.h>
     77   1.1  christos #include <ns/xfrout.h>
     78   1.1  christos 
     79   1.7  christos #include <ns/pfilter.h>
     80   1.7  christos 
     81   1.1  christos #if 0
     82   1.1  christos /*
     83   1.1  christos  * It has been recommended that DNS64 be changed to return excluded
     84   1.1  christos  * AAAA addresses if DNS64 synthesis does not occur.  This minimises
     85   1.1  christos  * the impact on the lookup results.  While most DNS AAAA lookups are
     86   1.1  christos  * done to send IP packets to a host, not all of them are and filtering
     87   1.1  christos  * excluded addresses has a negative impact on those uses.
     88   1.1  christos  */
     89   1.1  christos #define dns64_bis_return_excluded_addresses 1
     90   1.9  christos #endif /* if 0 */
     91   1.1  christos 
     92  1.11  christos #define QUERY_ERROR(qctx, r)                  \
     93  1.11  christos 	do {                                  \
     94  1.11  christos 		(qctx)->result = r;           \
     95  1.11  christos 		(qctx)->want_restart = false; \
     96  1.11  christos 		(qctx)->line = __LINE__;      \
     97  1.12    rillig 	} while (0)
     98   1.1  christos 
     99   1.1  christos /*% Partial answer? */
    100   1.9  christos #define PARTIALANSWER(c) \
    101   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_PARTIALANSWER) != 0)
    102   1.1  christos /*% Use Cache? */
    103   1.9  christos #define USECACHE(c) (((c)->query.attributes & NS_QUERYATTR_CACHEOK) != 0)
    104   1.1  christos /*% Recursion OK? */
    105   1.9  christos #define RECURSIONOK(c) (((c)->query.attributes & NS_QUERYATTR_RECURSIONOK) != 0)
    106   1.1  christos /*% Recursing? */
    107   1.9  christos #define RECURSING(c) (((c)->query.attributes & NS_QUERYATTR_RECURSING) != 0)
    108   1.1  christos /*% Want Recursion? */
    109   1.9  christos #define WANTRECURSION(c) \
    110   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_WANTRECURSION) != 0)
    111   1.1  christos /*% Is TCP? */
    112   1.9  christos #define TCP(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0)
    113   1.1  christos 
    114   1.1  christos /*% Want DNSSEC? */
    115   1.9  christos #define WANTDNSSEC(c) (((c)->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0)
    116   1.1  christos /*% Want WANTAD? */
    117   1.9  christos #define WANTAD(c) (((c)->attributes & NS_CLIENTATTR_WANTAD) != 0)
    118   1.1  christos /*% Client presented a valid COOKIE. */
    119   1.9  christos #define HAVECOOKIE(c) (((c)->attributes & NS_CLIENTATTR_HAVECOOKIE) != 0)
    120   1.1  christos /*% Client presented a COOKIE. */
    121   1.9  christos #define WANTCOOKIE(c) (((c)->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0)
    122   1.1  christos /*% Client presented a CLIENT-SUBNET option. */
    123   1.9  christos #define HAVEECS(c) (((c)->attributes & NS_CLIENTATTR_HAVEECS) != 0)
    124   1.1  christos /*% No authority? */
    125   1.9  christos #define NOAUTHORITY(c) (((c)->query.attributes & NS_QUERYATTR_NOAUTHORITY) != 0)
    126   1.1  christos /*% No additional? */
    127   1.9  christos #define NOADDITIONAL(c) \
    128   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_NOADDITIONAL) != 0)
    129   1.1  christos /*% Secure? */
    130   1.9  christos #define SECURE(c) (((c)->query.attributes & NS_QUERYATTR_SECURE) != 0)
    131   1.1  christos /*% DNS64 A lookup? */
    132   1.9  christos #define DNS64(c) (((c)->query.attributes & NS_QUERYATTR_DNS64) != 0)
    133   1.1  christos 
    134   1.9  christos #define DNS64EXCLUDE(c) \
    135   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_DNS64EXCLUDE) != 0)
    136   1.1  christos 
    137   1.9  christos #define REDIRECT(c) (((c)->query.attributes & NS_QUERYATTR_REDIRECT) != 0)
    138   1.1  christos 
    139  1.14  christos /*% Was the client already sent a response? */
    140  1.11  christos #define QUERY_ANSWERED(q) (((q)->attributes & NS_QUERYATTR_ANSWERED) != 0)
    141  1.11  christos 
    142  1.14  christos /*% Have we already processed an answer via stale-answer-client-timeout? */
    143  1.14  christos #define QUERY_STALEPENDING(q) \
    144  1.14  christos 	(((q)->attributes & NS_QUERYATTR_STALEPENDING) != 0)
    145  1.14  christos 
    146  1.13  christos /*% Does the query allow stale data in the response? */
    147  1.13  christos #define QUERY_STALEOK(q) (((q)->attributes & NS_QUERYATTR_STALEOK) != 0)
    148  1.13  christos 
    149  1.13  christos /*% Does the query wants to check for stale RRset due to a timeout? */
    150  1.13  christos #define QUERY_STALETIMEOUT(q) (((q)->dboptions & DNS_DBFIND_STALETIMEOUT) != 0)
    151  1.11  christos 
    152   1.1  christos /*% Does the rdataset 'r' have an attached 'No QNAME Proof'? */
    153   1.9  christos #define NOQNAME(r) (((r)->attributes & DNS_RDATASETATTR_NOQNAME) != 0)
    154   1.1  christos 
    155   1.4  christos /*% Does the rdataset 'r' contain a stale answer? */
    156   1.9  christos #define STALE(r) (((r)->attributes & DNS_RDATASETATTR_STALE) != 0)
    157   1.1  christos 
    158  1.11  christos /*% Does the rdataset 'r' is stale and within stale-refresh-time? */
    159  1.11  christos #define STALE_WINDOW(r) (((r)->attributes & DNS_RDATASETATTR_STALE_WINDOW) != 0)
    160  1.11  christos 
    161   1.1  christos #ifdef WANT_QUERYTRACE
    162  1.15  christos static void
    163   1.1  christos client_trace(ns_client_t *client, int level, const char *message) {
    164   1.1  christos 	if (client != NULL && client->query.qname != NULL) {
    165   1.1  christos 		if (isc_log_wouldlog(ns_lctx, level)) {
    166   1.1  christos 			char qbuf[DNS_NAME_FORMATSIZE];
    167   1.1  christos 			char tbuf[DNS_RDATATYPE_FORMATSIZE];
    168   1.9  christos 			dns_name_format(client->query.qname, qbuf,
    169   1.9  christos 					sizeof(qbuf));
    170   1.9  christos 			dns_rdatatype_format(client->query.qtype, tbuf,
    171   1.9  christos 					     sizeof(tbuf));
    172   1.9  christos 			isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT,
    173   1.1  christos 				      NS_LOGMODULE_QUERY, level,
    174  1.13  christos 				      "query client=%p thread=0x%" PRIxPTR
    175   1.1  christos 				      "(%s/%s): %s",
    176  1.13  christos 				      client, isc_thread_self(), qbuf, tbuf,
    177  1.13  christos 				      message);
    178   1.1  christos 		}
    179   1.9  christos 	} else {
    180   1.9  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT,
    181   1.1  christos 			      NS_LOGMODULE_QUERY, level,
    182  1.13  christos 			      "query client=%p thread=0x%" PRIxPTR
    183   1.1  christos 			      "(<unknown-query>): %s",
    184  1.13  christos 			      client, isc_thread_self(), message);
    185   1.1  christos 	}
    186   1.1  christos }
    187   1.9  christos #define CTRACE(l, m)  client_trace(client, l, m)
    188   1.9  christos #define CCTRACE(l, m) client_trace(qctx->client, l, m)
    189   1.9  christos #else /* ifdef WANT_QUERYTRACE */
    190   1.9  christos #define CTRACE(l, m)  ((void)m)
    191   1.9  christos #define CCTRACE(l, m) ((void)m)
    192   1.1  christos #endif /* WANT_QUERYTRACE */
    193   1.1  christos 
    194  1.22  christos enum {
    195  1.22  christos 	DNS_GETDB_NOEXACT = 1 << 0,
    196  1.22  christos 	DNS_GETDB_NOLOG = 1 << 1,
    197  1.22  christos 	DNS_GETDB_PARTIAL = 1 << 2,
    198  1.22  christos 	DNS_GETDB_IGNOREACL = 1 << 3,
    199  1.22  christos 	DNS_GETDB_STALEFIRST = 1 << 4,
    200  1.22  christos };
    201   1.1  christos 
    202  1.20  christos #define PENDINGOK(x) (((x) & DNS_DBFIND_PENDINGOK) != 0)
    203   1.1  christos 
    204   1.1  christos #define SFCACHE_CDFLAG 0x1
    205   1.1  christos 
    206   1.1  christos /*
    207  1.20  christos  * SAVE and RESTORE have the same semantics as:
    208   1.1  christos  *
    209  1.20  christos  * 	foo_attach(b, &a);
    210  1.20  christos  *	foo_detach(&b);
    211   1.1  christos  *
    212   1.1  christos  * without the locking and magic testing.
    213   1.1  christos  *
    214  1.20  christos  * We use the names SAVE and RESTORE to show the operation being performed,
    215  1.20  christos  * even though the two macros are identical.
    216   1.1  christos  */
    217   1.9  christos #define SAVE(a, b)                 \
    218   1.9  christos 	do {                       \
    219   1.9  christos 		INSIST(a == NULL); \
    220   1.9  christos 		a = b;             \
    221   1.9  christos 		b = NULL;          \
    222  1.12    rillig 	} while (0)
    223   1.1  christos #define RESTORE(a, b) SAVE(a, b)
    224   1.1  christos 
    225   1.3  christos static bool
    226   1.1  christos validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
    227   1.1  christos 	 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
    228   1.1  christos 
    229   1.1  christos static void
    230   1.1  christos query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
    231   1.1  christos 		       dns_dbversion_t *version, ns_client_t *client,
    232   1.1  christos 		       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
    233   1.9  christos 		       dns_name_t *fname, bool exact, dns_name_t *found);
    234   1.1  christos 
    235  1.15  christos static void
    236   1.1  christos log_queryerror(ns_client_t *client, isc_result_t result, int line, int level);
    237   1.1  christos 
    238   1.1  christos static void
    239   1.1  christos rpz_st_clear(ns_client_t *client);
    240   1.1  christos 
    241   1.3  christos static bool
    242   1.1  christos rpz_ck_dnssec(ns_client_t *client, isc_result_t qresult,
    243   1.1  christos 	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
    244   1.1  christos 
    245   1.1  christos static void
    246   1.1  christos log_noexistnodata(void *val, int level, const char *fmt, ...)
    247   1.1  christos 	ISC_FORMAT_PRINTF(3, 4);
    248   1.1  christos 
    249  1.20  christos static isc_result_t
    250  1.20  christos query_addanswer(query_ctx_t *qctx);
    251  1.20  christos 
    252  1.20  christos static isc_result_t
    253  1.20  christos query_prepare_delegation_response(query_ctx_t *qctx);
    254  1.20  christos 
    255   1.3  christos /*
    256   1.3  christos  * Return the hooktable in use with 'qctx', or if there isn't one
    257   1.3  christos  * set, return the default hooktable.
    258   1.3  christos  */
    259  1.15  christos static ns_hooktable_t *
    260   1.3  christos get_hooktab(query_ctx_t *qctx) {
    261   1.9  christos 	if (qctx == NULL || qctx->view == NULL || qctx->view->hooktable == NULL)
    262   1.3  christos 	{
    263   1.3  christos 		return (ns__hook_table);
    264   1.3  christos 	}
    265   1.1  christos 
    266   1.3  christos 	return (qctx->view->hooktable);
    267   1.3  christos }
    268   1.1  christos 
    269   1.3  christos /*
    270   1.3  christos  * Call the specified hook function in every configured module that implements
    271   1.3  christos  * that function. If any hook function returns NS_HOOK_RETURN, we
    272   1.3  christos  * set 'result' and terminate processing by jumping to the 'cleanup' tag.
    273   1.3  christos  *
    274   1.3  christos  * (Note that a hook function may set the 'result' to ISC_R_SUCCESS but
    275   1.3  christos  * still terminate processing within the calling function. That's why this
    276  1.15  christos  * is a macro instead of a static function; it needs to be able to use
    277   1.3  christos  * 'goto cleanup' regardless of the return value.)
    278   1.3  christos  */
    279   1.9  christos #define CALL_HOOK(_id, _qctx)                                       \
    280   1.9  christos 	do {                                                        \
    281  1.20  christos 		isc_result_t _res = result;                         \
    282   1.9  christos 		ns_hooktable_t *_tab = get_hooktab(_qctx);          \
    283   1.9  christos 		ns_hook_t *_hook;                                   \
    284   1.9  christos 		_hook = ISC_LIST_HEAD((*_tab)[_id]);                \
    285   1.9  christos 		while (_hook != NULL) {                             \
    286   1.9  christos 			ns_hook_action_t _func = _hook->action;     \
    287   1.9  christos 			void *_data = _hook->action_data;           \
    288   1.9  christos 			INSIST(_func != NULL);                      \
    289   1.9  christos 			switch (_func(_qctx, _data, &_res)) {       \
    290   1.9  christos 			case NS_HOOK_CONTINUE:                      \
    291   1.9  christos 				_hook = ISC_LIST_NEXT(_hook, link); \
    292   1.9  christos 				break;                              \
    293   1.9  christos 			case NS_HOOK_RETURN:                        \
    294   1.9  christos 				result = _res;                      \
    295   1.9  christos 				goto cleanup;                       \
    296   1.9  christos 			default:                                    \
    297  1.15  christos 				UNREACHABLE();                      \
    298   1.9  christos 			}                                           \
    299   1.9  christos 		}                                                   \
    300   1.3  christos 	} while (false)
    301   1.1  christos 
    302   1.3  christos /*
    303   1.3  christos  * Call the specified hook function in every configured module that
    304   1.3  christos  * implements that function. All modules are called; hook function return
    305   1.3  christos  * codes are ignored. This is intended for use with initialization and
    306   1.3  christos  * destruction calls which *must* run in every configured module.
    307   1.3  christos  *
    308  1.15  christos  * (This could be implemented as a static void function, but is left as a
    309   1.3  christos  * macro for symmetry with CALL_HOOK above.)
    310   1.3  christos  */
    311   1.9  christos #define CALL_HOOK_NORETURN(_id, _qctx)                          \
    312   1.9  christos 	do {                                                    \
    313   1.9  christos 		isc_result_t _res;                              \
    314   1.9  christos 		ns_hooktable_t *_tab = get_hooktab(_qctx);      \
    315   1.9  christos 		ns_hook_t *_hook;                               \
    316   1.9  christos 		_hook = ISC_LIST_HEAD((*_tab)[_id]);            \
    317   1.9  christos 		while (_hook != NULL) {                         \
    318   1.9  christos 			ns_hook_action_t _func = _hook->action; \
    319   1.9  christos 			void *_data = _hook->action_data;       \
    320   1.9  christos 			INSIST(_func != NULL);                  \
    321   1.9  christos 			_func(_qctx, _data, &_res);             \
    322   1.9  christos 			_hook = ISC_LIST_NEXT(_hook, link);     \
    323   1.9  christos 		}                                               \
    324   1.3  christos 	} while (false)
    325   1.1  christos 
    326   1.1  christos /*
    327   1.1  christos  * The functions defined below implement the query logic that previously lived
    328   1.1  christos  * in the single very complex function query_find().  The query_ctx_t structure
    329   1.1  christos  * defined in <ns/query.h> maintains state from function to function.  The call
    330   1.1  christos  * flow for the general query processing algorithm is described below:
    331   1.1  christos  *
    332   1.1  christos  * 1. Set up query context and other resources for a client
    333   1.1  christos  *    query (query_setup())
    334   1.1  christos  *
    335   1.1  christos  * 2. Start the search (ns__query_start())
    336   1.1  christos  *
    337   1.1  christos  * 3. Identify authoritative data sources which may have an answer;
    338   1.1  christos  *    search them (query_lookup()). If an answer is found, go to 7.
    339   1.1  christos  *
    340   1.1  christos  * 4. If recursion or cache access are allowed, search the cache
    341   1.1  christos  *    (query_lookup() again, using the cache database) to find a better
    342   1.1  christos  *    answer. If an answer is found, go to 7.
    343   1.1  christos  *
    344   1.3  christos  * 5. If recursion is allowed, begin recursion (ns_query_recurse()).
    345   1.1  christos  *    Go to 15 to clean up this phase of the query. When recursion
    346   1.1  christos  *    is complete, processing will resume at 6.
    347   1.1  christos  *
    348   1.1  christos  * 6. Resume from recursion; set up query context for resumed processing.
    349   1.1  christos  *
    350   1.1  christos  * 7. Determine what sort of answer we've found (query_gotanswer())
    351   1.1  christos  *    and call other functions accordingly:
    352   1.1  christos  *      - not found (auth or cache), go to 8
    353   1.1  christos  *      - delegation, go to 9
    354   1.1  christos  *      - no such domain (auth), go to 10
    355   1.1  christos  *      - empty answer (auth), go to 11
    356   1.1  christos  *      - negative response (cache), go to 12
    357   1.1  christos  *      - answer found, go to 13
    358   1.1  christos  *
    359   1.1  christos  * 8. The answer was not found in the database (query_notfound().
    360   1.1  christos  *    Set up a referral and go to 9.
    361   1.1  christos  *
    362   1.3  christos  * 9. Handle a delegation response (query_delegation()). If we need
    363   1.3  christos  *    to and are allowed to recurse (query_delegation_recurse()), go to 5,
    364   1.3  christos  *    otherwise go to 15 to clean up and return the delegation to the client.
    365   1.1  christos  *
    366   1.1  christos  * 10. No such domain (query_nxdomain()). Attempt redirection; if
    367   1.1  christos  *     unsuccessful, add authority section records (query_addsoa(),
    368   1.1  christos  *     query_addauth()), then go to 15 to return NXDOMAIN to client.
    369   1.1  christos  *
    370   1.1  christos  * 11. Empty answer (query_nodata()). Add authority section records
    371   1.1  christos  *     (query_addsoa(), query_addauth()) and signatures if authoritative
    372   1.1  christos  *     (query_sign_nodata()) then go to 15 and return
    373   1.1  christos  *     NOERROR/ANCOUNT=0 to client.
    374   1.1  christos  *
    375   1.1  christos  * 12. No such domain or empty answer returned from cache (query_ncache()).
    376   1.1  christos  *     Set response code appropriately, go to 11.
    377   1.1  christos  *
    378   1.1  christos  * 13. Prepare a response (query_prepresponse()) and then fill it
    379   1.1  christos  *     appropriately (query_respond(), or for type ANY,
    380   1.1  christos  *     query_respond_any()).
    381   1.1  christos  *
    382   1.1  christos  * 14. If a restart is needed due to CNAME/DNAME chaining, go to 2.
    383   1.1  christos  *
    384   1.1  christos  * 15. Clean up resources. If recursing, stop and wait for the event
    385   1.1  christos  *     handler to be called back (step 6).  If an answer is ready,
    386   1.1  christos  *     return it to the client.
    387   1.1  christos  *
    388   1.1  christos  * (XXX: This description omits several special cases including
    389   1.3  christos  * DNS64, RPZ, RRL, and the SERVFAIL cache. It also doesn't discuss
    390   1.3  christos  * plugins.)
    391   1.1  christos  */
    392   1.1  christos 
    393   1.1  christos static void
    394   1.1  christos query_trace(query_ctx_t *qctx);
    395   1.1  christos 
    396   1.1  christos static void
    397  1.11  christos qctx_init(ns_client_t *client, dns_fetchevent_t **eventp, dns_rdatatype_t qtype,
    398   1.9  christos 	  query_ctx_t *qctx);
    399   1.1  christos 
    400   1.1  christos static isc_result_t
    401   1.1  christos query_setup(ns_client_t *client, dns_rdatatype_t qtype);
    402   1.1  christos 
    403   1.1  christos static isc_result_t
    404   1.1  christos query_lookup(query_ctx_t *qctx);
    405   1.1  christos 
    406   1.1  christos static void
    407   1.1  christos fetch_callback(isc_task_t *task, isc_event_t *event);
    408   1.1  christos 
    409   1.1  christos static void
    410   1.1  christos recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
    411   1.1  christos 		const dns_name_t *qname, const dns_name_t *qdomain);
    412   1.1  christos 
    413   1.1  christos static isc_result_t
    414   1.1  christos query_resume(query_ctx_t *qctx);
    415   1.1  christos 
    416   1.1  christos static isc_result_t
    417   1.1  christos query_checkrrl(query_ctx_t *qctx, isc_result_t result);
    418   1.1  christos 
    419   1.1  christos static isc_result_t
    420   1.1  christos query_checkrpz(query_ctx_t *qctx, isc_result_t result);
    421   1.1  christos 
    422   1.1  christos static isc_result_t
    423   1.1  christos query_rpzcname(query_ctx_t *qctx, dns_name_t *cname);
    424   1.1  christos 
    425   1.1  christos static isc_result_t
    426   1.1  christos query_gotanswer(query_ctx_t *qctx, isc_result_t result);
    427   1.1  christos 
    428   1.1  christos static void
    429   1.1  christos query_addnoqnameproof(query_ctx_t *qctx);
    430   1.1  christos 
    431   1.1  christos static isc_result_t
    432   1.1  christos query_respond_any(query_ctx_t *qctx);
    433   1.1  christos 
    434   1.1  christos static isc_result_t
    435   1.1  christos query_respond(query_ctx_t *qctx);
    436   1.1  christos 
    437   1.1  christos static isc_result_t
    438   1.1  christos query_dns64(query_ctx_t *qctx);
    439   1.1  christos 
    440   1.1  christos static void
    441   1.1  christos query_filter64(query_ctx_t *qctx);
    442   1.1  christos 
    443   1.1  christos static isc_result_t
    444   1.1  christos query_notfound(query_ctx_t *qctx);
    445   1.1  christos 
    446   1.1  christos static isc_result_t
    447   1.1  christos query_zone_delegation(query_ctx_t *qctx);
    448   1.1  christos 
    449   1.1  christos static isc_result_t
    450   1.1  christos query_delegation(query_ctx_t *qctx);
    451   1.1  christos 
    452   1.3  christos static isc_result_t
    453   1.3  christos query_delegation_recurse(query_ctx_t *qctx);
    454   1.3  christos 
    455   1.1  christos static void
    456   1.1  christos query_addds(query_ctx_t *qctx);
    457   1.1  christos 
    458   1.1  christos static isc_result_t
    459   1.1  christos query_nodata(query_ctx_t *qctx, isc_result_t result);
    460   1.1  christos 
    461   1.1  christos static isc_result_t
    462   1.1  christos query_sign_nodata(query_ctx_t *qctx);
    463   1.1  christos 
    464   1.1  christos static void
    465   1.1  christos query_addnxrrsetnsec(query_ctx_t *qctx);
    466   1.1  christos 
    467   1.1  christos static isc_result_t
    468  1.18  christos query_nxdomain(query_ctx_t *qctx, isc_result_t result);
    469   1.1  christos 
    470   1.1  christos static isc_result_t
    471  1.18  christos query_redirect(query_ctx_t *qctx, isc_result_t result);
    472   1.1  christos 
    473   1.1  christos static isc_result_t
    474   1.1  christos query_ncache(query_ctx_t *qctx, isc_result_t result);
    475   1.1  christos 
    476   1.1  christos static isc_result_t
    477   1.1  christos query_coveringnsec(query_ctx_t *qctx);
    478   1.1  christos 
    479   1.1  christos static isc_result_t
    480   1.3  christos query_zerottl_refetch(query_ctx_t *qctx);
    481   1.3  christos 
    482   1.3  christos static isc_result_t
    483   1.1  christos query_cname(query_ctx_t *qctx);
    484   1.1  christos 
    485   1.1  christos static isc_result_t
    486   1.1  christos query_dname(query_ctx_t *qctx);
    487   1.1  christos 
    488   1.1  christos static isc_result_t
    489   1.1  christos query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl);
    490   1.1  christos 
    491   1.1  christos static isc_result_t
    492   1.1  christos query_prepresponse(query_ctx_t *qctx);
    493   1.1  christos 
    494   1.1  christos static isc_result_t
    495   1.1  christos query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
    496   1.1  christos 	     dns_section_t section);
    497   1.1  christos 
    498   1.1  christos static isc_result_t
    499   1.1  christos query_addns(query_ctx_t *qctx);
    500   1.1  christos 
    501   1.1  christos static void
    502   1.1  christos query_addbestns(query_ctx_t *qctx);
    503   1.1  christos 
    504   1.1  christos static void
    505   1.3  christos query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata);
    506   1.1  christos 
    507   1.1  christos static void
    508   1.1  christos query_addauth(query_ctx_t *qctx);
    509   1.1  christos 
    510  1.13  christos static void
    511  1.13  christos query_clear_stale(ns_client_t *client);
    512  1.13  christos 
    513   1.3  christos /*
    514   1.1  christos  * Increment query statistics counters.
    515   1.1  christos  */
    516  1.15  christos static void
    517   1.1  christos inc_stats(ns_client_t *client, isc_statscounter_t counter) {
    518   1.1  christos 	dns_zone_t *zone = client->query.authzone;
    519   1.1  christos 	dns_rdatatype_t qtype;
    520   1.1  christos 	dns_rdataset_t *rdataset;
    521   1.1  christos 	isc_stats_t *zonestats;
    522   1.1  christos 	dns_stats_t *querystats = NULL;
    523   1.1  christos 
    524   1.1  christos 	ns_stats_increment(client->sctx->nsstats, counter);
    525   1.1  christos 
    526   1.9  christos 	if (zone == NULL) {
    527   1.1  christos 		return;
    528   1.9  christos 	}
    529   1.1  christos 
    530   1.1  christos 	/* Do regular response type stats */
    531   1.1  christos 	zonestats = dns_zone_getrequeststats(zone);
    532   1.1  christos 
    533   1.9  christos 	if (zonestats != NULL) {
    534   1.1  christos 		isc_stats_increment(zonestats, counter);
    535   1.9  christos 	}
    536   1.1  christos 
    537   1.1  christos 	/* Do query type statistics
    538   1.1  christos 	 *
    539   1.1  christos 	 * We only increment per-type if we're using the authoritative
    540   1.1  christos 	 * answer counter, preventing double-counting.
    541   1.1  christos 	 */
    542   1.1  christos 	if (counter == ns_statscounter_authans) {
    543   1.1  christos 		querystats = dns_zone_getrcvquerystats(zone);
    544   1.1  christos 		if (querystats != NULL) {
    545   1.1  christos 			rdataset = ISC_LIST_HEAD(client->query.qname->list);
    546   1.1  christos 			if (rdataset != NULL) {
    547   1.1  christos 				qtype = rdataset->type;
    548   1.1  christos 				dns_rdatatypestats_increment(querystats, qtype);
    549   1.1  christos 			}
    550   1.1  christos 		}
    551   1.1  christos 	}
    552   1.1  christos }
    553   1.1  christos 
    554   1.1  christos static void
    555   1.1  christos query_send(ns_client_t *client) {
    556   1.1  christos 	isc_statscounter_t counter;
    557   1.1  christos 
    558   1.9  christos 	if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0) {
    559   1.1  christos 		inc_stats(client, ns_statscounter_nonauthans);
    560   1.9  christos 	} else {
    561   1.1  christos 		inc_stats(client, ns_statscounter_authans);
    562   1.9  christos 	}
    563   1.1  christos 
    564   1.1  christos 	if (client->message->rcode == dns_rcode_noerror) {
    565   1.1  christos 		dns_section_t answer = DNS_SECTION_ANSWER;
    566   1.1  christos 		if (ISC_LIST_EMPTY(client->message->sections[answer])) {
    567   1.9  christos 			if (client->query.isreferral) {
    568   1.1  christos 				counter = ns_statscounter_referral;
    569   1.9  christos 			} else {
    570   1.1  christos 				counter = ns_statscounter_nxrrset;
    571   1.9  christos 			}
    572   1.9  christos 		} else {
    573   1.1  christos 			counter = ns_statscounter_success;
    574   1.9  christos 		}
    575   1.9  christos 	} else if (client->message->rcode == dns_rcode_nxdomain) {
    576   1.1  christos 		counter = ns_statscounter_nxdomain;
    577   1.9  christos 	} else if (client->message->rcode == dns_rcode_badcookie) {
    578   1.1  christos 		counter = ns_statscounter_badcookie;
    579   1.9  christos 	} else { /* We end up here in case of YXDOMAIN, and maybe others */
    580   1.1  christos 		counter = ns_statscounter_failure;
    581   1.9  christos 	}
    582   1.1  christos 
    583   1.1  christos 	inc_stats(client, counter);
    584   1.1  christos 	ns_client_send(client);
    585  1.11  christos 
    586  1.13  christos 	if (!client->nodetach) {
    587  1.11  christos 		isc_nmhandle_detach(&client->reqhandle);
    588  1.11  christos 	}
    589   1.1  christos }
    590   1.1  christos 
    591   1.1  christos static void
    592   1.1  christos query_error(ns_client_t *client, isc_result_t result, int line) {
    593   1.1  christos 	int loglevel = ISC_LOG_DEBUG(3);
    594   1.1  christos 
    595   1.3  christos 	switch (dns_result_torcode(result)) {
    596   1.3  christos 	case dns_rcode_servfail:
    597   1.1  christos 		loglevel = ISC_LOG_DEBUG(1);
    598   1.1  christos 		inc_stats(client, ns_statscounter_servfail);
    599   1.1  christos 		break;
    600   1.3  christos 	case dns_rcode_formerr:
    601   1.1  christos 		inc_stats(client, ns_statscounter_formerr);
    602   1.1  christos 		break;
    603   1.1  christos 	default:
    604   1.1  christos 		inc_stats(client, ns_statscounter_failure);
    605   1.1  christos 		break;
    606   1.1  christos 	}
    607   1.1  christos 
    608   1.9  christos 	if ((client->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
    609   1.1  christos 		loglevel = ISC_LOG_INFO;
    610   1.9  christos 	}
    611   1.1  christos 
    612   1.1  christos 	log_queryerror(client, result, line, loglevel);
    613   1.1  christos 
    614   1.1  christos 	ns_client_error(client, result);
    615  1.11  christos 
    616  1.13  christos 	if (!client->nodetach) {
    617  1.11  christos 		isc_nmhandle_detach(&client->reqhandle);
    618  1.11  christos 	}
    619   1.1  christos }
    620   1.1  christos 
    621   1.1  christos static void
    622   1.1  christos query_next(ns_client_t *client, isc_result_t result) {
    623   1.9  christos 	if (result == DNS_R_DUPLICATE) {
    624   1.1  christos 		inc_stats(client, ns_statscounter_duplicate);
    625   1.9  christos 	} else if (result == DNS_R_DROP) {
    626   1.1  christos 		inc_stats(client, ns_statscounter_dropped);
    627   1.9  christos 	} else {
    628   1.1  christos 		inc_stats(client, ns_statscounter_failure);
    629   1.9  christos 	}
    630   1.9  christos 	ns_client_drop(client, result);
    631  1.11  christos 
    632  1.13  christos 	if (!client->nodetach) {
    633  1.11  christos 		isc_nmhandle_detach(&client->reqhandle);
    634  1.11  christos 	}
    635   1.1  christos }
    636   1.1  christos 
    637  1.15  christos static void
    638   1.3  christos query_freefreeversions(ns_client_t *client, bool everything) {
    639   1.1  christos 	ns_dbversion_t *dbversion, *dbversion_next;
    640   1.1  christos 	unsigned int i;
    641   1.1  christos 
    642   1.1  christos 	for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
    643   1.9  christos 	     dbversion != NULL; dbversion = dbversion_next, i++)
    644   1.1  christos 	{
    645   1.1  christos 		dbversion_next = ISC_LIST_NEXT(dbversion, link);
    646   1.1  christos 		/*
    647   1.1  christos 		 * If we're not freeing everything, we keep the first three
    648   1.1  christos 		 * dbversions structures around.
    649   1.1  christos 		 */
    650   1.1  christos 		if (i > 3 || everything) {
    651   1.1  christos 			ISC_LIST_UNLINK(client->query.freeversions, dbversion,
    652   1.1  christos 					link);
    653   1.1  christos 			isc_mem_put(client->mctx, dbversion,
    654   1.1  christos 				    sizeof(*dbversion));
    655   1.1  christos 		}
    656   1.1  christos 	}
    657   1.1  christos }
    658   1.1  christos 
    659   1.1  christos void
    660   1.1  christos ns_query_cancel(ns_client_t *client) {
    661   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
    662   1.1  christos 
    663   1.1  christos 	LOCK(&client->query.fetchlock);
    664   1.1  christos 	if (client->query.fetch != NULL) {
    665   1.1  christos 		dns_resolver_cancelfetch(client->query.fetch);
    666   1.1  christos 
    667   1.1  christos 		client->query.fetch = NULL;
    668   1.1  christos 	}
    669  1.20  christos 	if (client->query.hookactx != NULL) {
    670  1.20  christos 		client->query.hookactx->cancel(client->query.hookactx);
    671  1.20  christos 		client->query.hookactx = NULL;
    672  1.20  christos 	}
    673   1.1  christos 	UNLOCK(&client->query.fetchlock);
    674   1.1  christos }
    675   1.1  christos 
    676  1.15  christos static void
    677   1.3  christos query_reset(ns_client_t *client, bool everything) {
    678   1.1  christos 	isc_buffer_t *dbuf, *dbuf_next;
    679   1.1  christos 	ns_dbversion_t *dbversion, *dbversion_next;
    680   1.1  christos 
    681   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_reset");
    682   1.1  christos 
    683   1.1  christos 	/*%
    684   1.1  christos 	 * Reset the query state of a client to its default state.
    685   1.1  christos 	 */
    686   1.1  christos 
    687   1.1  christos 	/*
    688   1.1  christos 	 * Cancel the fetch if it's running.
    689   1.1  christos 	 */
    690   1.1  christos 	ns_query_cancel(client);
    691   1.1  christos 
    692   1.1  christos 	/*
    693   1.1  christos 	 * Cleanup any active versions.
    694   1.1  christos 	 */
    695   1.1  christos 	for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
    696   1.9  christos 	     dbversion != NULL; dbversion = dbversion_next)
    697   1.9  christos 	{
    698   1.1  christos 		dbversion_next = ISC_LIST_NEXT(dbversion, link);
    699   1.9  christos 		dns_db_closeversion(dbversion->db, &dbversion->version, false);
    700   1.1  christos 		dns_db_detach(&dbversion->db);
    701   1.9  christos 		ISC_LIST_INITANDAPPEND(client->query.freeversions, dbversion,
    702   1.9  christos 				       link);
    703   1.1  christos 	}
    704   1.1  christos 	ISC_LIST_INIT(client->query.activeversions);
    705   1.1  christos 
    706   1.9  christos 	if (client->query.authdb != NULL) {
    707   1.1  christos 		dns_db_detach(&client->query.authdb);
    708   1.9  christos 	}
    709   1.9  christos 	if (client->query.authzone != NULL) {
    710   1.1  christos 		dns_zone_detach(&client->query.authzone);
    711   1.9  christos 	}
    712   1.1  christos 
    713   1.9  christos 	if (client->query.dns64_aaaa != NULL) {
    714   1.3  christos 		ns_client_putrdataset(client, &client->query.dns64_aaaa);
    715   1.9  christos 	}
    716   1.9  christos 	if (client->query.dns64_sigaaaa != NULL) {
    717   1.3  christos 		ns_client_putrdataset(client, &client->query.dns64_sigaaaa);
    718   1.9  christos 	}
    719   1.1  christos 	if (client->query.dns64_aaaaok != NULL) {
    720   1.1  christos 		isc_mem_put(client->mctx, client->query.dns64_aaaaok,
    721   1.9  christos 			    client->query.dns64_aaaaoklen * sizeof(bool));
    722   1.9  christos 		client->query.dns64_aaaaok = NULL;
    723   1.9  christos 		client->query.dns64_aaaaoklen = 0;
    724   1.1  christos 	}
    725   1.1  christos 
    726   1.3  christos 	ns_client_putrdataset(client, &client->query.redirect.rdataset);
    727   1.3  christos 	ns_client_putrdataset(client, &client->query.redirect.sigrdataset);
    728   1.1  christos 	if (client->query.redirect.db != NULL) {
    729   1.9  christos 		if (client->query.redirect.node != NULL) {
    730   1.1  christos 			dns_db_detachnode(client->query.redirect.db,
    731   1.1  christos 					  &client->query.redirect.node);
    732   1.9  christos 		}
    733   1.1  christos 		dns_db_detach(&client->query.redirect.db);
    734   1.1  christos 	}
    735   1.9  christos 	if (client->query.redirect.zone != NULL) {
    736   1.1  christos 		dns_zone_detach(&client->query.redirect.zone);
    737   1.9  christos 	}
    738   1.1  christos 
    739   1.1  christos 	query_freefreeversions(client, everything);
    740   1.1  christos 
    741   1.9  christos 	for (dbuf = ISC_LIST_HEAD(client->query.namebufs); dbuf != NULL;
    742   1.9  christos 	     dbuf = dbuf_next)
    743   1.9  christos 	{
    744   1.1  christos 		dbuf_next = ISC_LIST_NEXT(dbuf, link);
    745   1.1  christos 		if (dbuf_next != NULL || everything) {
    746   1.1  christos 			ISC_LIST_UNLINK(client->query.namebufs, dbuf, link);
    747   1.1  christos 			isc_buffer_free(&dbuf);
    748   1.1  christos 		}
    749   1.1  christos 	}
    750   1.1  christos 
    751   1.1  christos 	if (client->query.restarts > 0) {
    752   1.1  christos 		/*
    753   1.1  christos 		 * client->query.qname was dynamically allocated.
    754   1.1  christos 		 */
    755   1.9  christos 		dns_message_puttempname(client->message, &client->query.qname);
    756   1.1  christos 	}
    757   1.1  christos 	client->query.qname = NULL;
    758   1.1  christos 	client->query.attributes = (NS_QUERYATTR_RECURSIONOK |
    759   1.9  christos 				    NS_QUERYATTR_CACHEOK | NS_QUERYATTR_SECURE);
    760   1.1  christos 	client->query.restarts = 0;
    761   1.3  christos 	client->query.timerset = false;
    762   1.1  christos 	if (client->query.rpz_st != NULL) {
    763   1.1  christos 		rpz_st_clear(client);
    764   1.1  christos 		if (everything) {
    765   1.1  christos 			INSIST(client->query.rpz_st->rpsdb == NULL);
    766   1.1  christos 			isc_mem_put(client->mctx, client->query.rpz_st,
    767   1.1  christos 				    sizeof(*client->query.rpz_st));
    768   1.1  christos 			client->query.rpz_st = NULL;
    769   1.1  christos 		}
    770   1.1  christos 	}
    771   1.1  christos 	client->query.origqname = NULL;
    772   1.1  christos 	client->query.dboptions = 0;
    773   1.1  christos 	client->query.fetchoptions = 0;
    774   1.1  christos 	client->query.gluedb = NULL;
    775   1.3  christos 	client->query.authdbset = false;
    776   1.3  christos 	client->query.isreferral = false;
    777   1.1  christos 	client->query.dns64_options = 0;
    778   1.3  christos 	client->query.dns64_ttl = UINT32_MAX;
    779   1.3  christos 	recparam_update(&client->query.recparam, 0, NULL, NULL);
    780   1.1  christos 	client->query.root_key_sentinel_keyid = 0;
    781   1.3  christos 	client->query.root_key_sentinel_is_ta = false;
    782   1.3  christos 	client->query.root_key_sentinel_not_ta = false;
    783   1.1  christos }
    784   1.1  christos 
    785   1.1  christos static void
    786   1.9  christos query_cleanup(ns_client_t *client) {
    787   1.3  christos 	query_reset(client, false);
    788   1.1  christos }
    789   1.1  christos 
    790   1.1  christos void
    791   1.1  christos ns_query_free(ns_client_t *client) {
    792   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
    793   1.1  christos 
    794   1.3  christos 	query_reset(client, true);
    795   1.1  christos }
    796   1.1  christos 
    797   1.1  christos isc_result_t
    798   1.1  christos ns_query_init(ns_client_t *client) {
    799  1.14  christos 	isc_result_t result = ISC_R_SUCCESS;
    800   1.1  christos 
    801   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
    802   1.1  christos 
    803   1.1  christos 	ISC_LIST_INIT(client->query.namebufs);
    804   1.1  christos 	ISC_LIST_INIT(client->query.activeversions);
    805   1.1  christos 	ISC_LIST_INIT(client->query.freeversions);
    806   1.1  christos 	client->query.restarts = 0;
    807   1.3  christos 	client->query.timerset = false;
    808   1.1  christos 	client->query.rpz_st = NULL;
    809   1.1  christos 	client->query.qname = NULL;
    810   1.1  christos 	/*
    811   1.1  christos 	 * This mutex is destroyed when the client is destroyed in
    812   1.1  christos 	 * exit_check().
    813   1.1  christos 	 */
    814   1.3  christos 	isc_mutex_init(&client->query.fetchlock);
    815   1.3  christos 
    816   1.1  christos 	client->query.fetch = NULL;
    817   1.1  christos 	client->query.prefetch = NULL;
    818   1.1  christos 	client->query.authdb = NULL;
    819   1.1  christos 	client->query.authzone = NULL;
    820   1.3  christos 	client->query.authdbset = false;
    821   1.3  christos 	client->query.isreferral = false;
    822   1.1  christos 	client->query.dns64_aaaa = NULL;
    823   1.1  christos 	client->query.dns64_sigaaaa = NULL;
    824   1.1  christos 	client->query.dns64_aaaaok = NULL;
    825   1.1  christos 	client->query.dns64_aaaaoklen = 0;
    826   1.1  christos 	client->query.redirect.db = NULL;
    827   1.1  christos 	client->query.redirect.node = NULL;
    828   1.1  christos 	client->query.redirect.zone = NULL;
    829   1.1  christos 	client->query.redirect.qtype = dns_rdatatype_none;
    830   1.1  christos 	client->query.redirect.result = ISC_R_SUCCESS;
    831   1.1  christos 	client->query.redirect.rdataset = NULL;
    832   1.1  christos 	client->query.redirect.sigrdataset = NULL;
    833   1.3  christos 	client->query.redirect.authoritative = false;
    834   1.3  christos 	client->query.redirect.is_zone = false;
    835   1.1  christos 	client->query.redirect.fname =
    836   1.1  christos 		dns_fixedname_initname(&client->query.redirect.fixed);
    837   1.3  christos 	query_reset(client, false);
    838  1.14  christos 	ns_client_newdbversion(client, 3);
    839  1.14  christos 	ns_client_newnamebuf(client);
    840   1.1  christos 
    841   1.1  christos 	return (result);
    842   1.1  christos }
    843   1.1  christos 
    844   1.3  christos /*%
    845   1.3  christos  * Check if 'client' is allowed to query the cache of its associated view.
    846   1.3  christos  * Unless 'options' has DNS_GETDB_NOLOG set, log the result of cache ACL
    847   1.3  christos  * evaluation using the appropriate level, along with 'name' and 'qtype'.
    848   1.3  christos  *
    849   1.3  christos  * The cache ACL is only evaluated once for each client and then the result is
    850   1.3  christos  * cached: if NS_QUERYATTR_CACHEACLOKVALID is set in client->query.attributes,
    851   1.3  christos  * cache ACL evaluation has already been performed.  The evaluation result is
    852   1.3  christos  * also stored in client->query.attributes: if NS_QUERYATTR_CACHEACLOK is set,
    853   1.3  christos  * the client is allowed cache access.
    854   1.3  christos  *
    855   1.3  christos  * Returns:
    856   1.3  christos  *
    857   1.3  christos  *\li	#ISC_R_SUCCESS	'client' is allowed to access cache
    858   1.3  christos  *\li	#DNS_R_REFUSED	'client' is not allowed to access cache
    859   1.3  christos  */
    860   1.3  christos static isc_result_t
    861   1.3  christos query_checkcacheaccess(ns_client_t *client, const dns_name_t *name,
    862   1.9  christos 		       dns_rdatatype_t qtype, unsigned int options) {
    863   1.3  christos 	isc_result_t result;
    864   1.3  christos 
    865   1.3  christos 	if ((client->query.attributes & NS_QUERYATTR_CACHEACLOKVALID) == 0) {
    866  1.20  christos 		enum refusal_reasons {
    867  1.20  christos 			ALLOW_QUERY_CACHE,
    868  1.20  christos 			ALLOW_QUERY_CACHE_ON
    869  1.20  christos 		};
    870  1.20  christos 		static const char *acl_desc[] = {
    871  1.20  christos 			"allow-query-cache did not match",
    872  1.20  christos 			"allow-query-cache-on did not match",
    873  1.20  christos 		};
    874  1.20  christos 
    875   1.3  christos 		/*
    876   1.3  christos 		 * The view's cache ACLs have not yet been evaluated.
    877   1.3  christos 		 * Do it now. Both allow-query-cache and
    878  1.20  christos 		 * allow-query-cache-on must be satisfied.
    879   1.3  christos 		 */
    880   1.3  christos 		bool log = ((options & DNS_GETDB_NOLOG) == 0);
    881   1.3  christos 		char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")];
    882   1.1  christos 
    883  1.20  christos 		enum refusal_reasons refusal_reason = ALLOW_QUERY_CACHE;
    884   1.3  christos 		result = ns_client_checkaclsilent(client, NULL,
    885   1.9  christos 						  client->view->cacheacl, true);
    886   1.3  christos 		if (result == ISC_R_SUCCESS) {
    887  1.20  christos 			refusal_reason = ALLOW_QUERY_CACHE_ON;
    888   1.9  christos 			result = ns_client_checkaclsilent(
    889   1.9  christos 				client, &client->destaddr,
    890   1.9  christos 				client->view->cacheonacl, true);
    891   1.9  christos 		}
    892   1.3  christos 		if (result == ISC_R_SUCCESS) {
    893   1.3  christos 			/*
    894   1.3  christos 			 * We were allowed by the "allow-query-cache" ACL.
    895   1.3  christos 			 */
    896   1.3  christos 			client->query.attributes |= NS_QUERYATTR_CACHEACLOK;
    897   1.9  christos 			if (log && isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(3)))
    898   1.3  christos 			{
    899   1.3  christos 				ns_client_aclmsg("query (cache)", name, qtype,
    900   1.3  christos 						 client->view->rdclass, msg,
    901   1.3  christos 						 sizeof(msg));
    902   1.3  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
    903   1.3  christos 					      NS_LOGMODULE_QUERY,
    904   1.3  christos 					      ISC_LOG_DEBUG(3), "%s approved",
    905   1.3  christos 					      msg);
    906   1.3  christos 			}
    907  1.20  christos 		} else {
    908   1.3  christos 			/*
    909   1.3  christos 			 * We were denied by the "allow-query-cache" ACL.
    910   1.3  christos 			 * There is no need to clear NS_QUERYATTR_CACHEACLOK
    911   1.3  christos 			 * since it is cleared by query_reset(), before query
    912   1.3  christos 			 * processing starts.
    913   1.3  christos 			 */
    914  1.20  christos 			ns_client_extendederror(client, DNS_EDE_PROHIBITED,
    915  1.20  christos 						NULL);
    916  1.20  christos 
    917  1.20  christos 			if (log) {
    918  1.20  christos 				ns_client_aclmsg("query (cache)", name, qtype,
    919  1.20  christos 						 client->view->rdclass, msg,
    920  1.20  christos 						 sizeof(msg));
    921  1.20  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
    922  1.20  christos 					      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
    923  1.20  christos 					      "%s denied (%s)", msg,
    924  1.20  christos 					      acl_desc[refusal_reason]);
    925  1.20  christos 			}
    926   1.3  christos 		}
    927   1.1  christos 
    928   1.1  christos 		/*
    929   1.3  christos 		 * Evaluation has been finished; make sure we will just consult
    930   1.3  christos 		 * NS_QUERYATTR_CACHEACLOK for this client from now on.
    931   1.1  christos 		 */
    932   1.3  christos 		client->query.attributes |= NS_QUERYATTR_CACHEACLOKVALID;
    933   1.1  christos 	}
    934   1.1  christos 
    935   1.9  christos 	return ((client->query.attributes & NS_QUERYATTR_CACHEACLOK) != 0
    936   1.9  christos 			? ISC_R_SUCCESS
    937   1.9  christos 			: DNS_R_REFUSED);
    938   1.1  christos }
    939   1.1  christos 
    940  1.15  christos static isc_result_t
    941   1.1  christos query_validatezonedb(ns_client_t *client, const dns_name_t *name,
    942   1.1  christos 		     dns_rdatatype_t qtype, unsigned int options,
    943   1.1  christos 		     dns_zone_t *zone, dns_db_t *db,
    944   1.9  christos 		     dns_dbversion_t **versionp) {
    945   1.1  christos 	isc_result_t result;
    946   1.1  christos 	dns_acl_t *queryacl, *queryonacl;
    947   1.1  christos 	ns_dbversion_t *dbversion;
    948   1.1  christos 
    949   1.1  christos 	REQUIRE(zone != NULL);
    950   1.1  christos 	REQUIRE(db != NULL);
    951   1.1  christos 
    952   1.1  christos 	/*
    953   1.3  christos 	 * Mirror zone data is treated as cache data.
    954   1.3  christos 	 */
    955   1.3  christos 	if (dns_zone_gettype(zone) == dns_zone_mirror) {
    956   1.3  christos 		return (query_checkcacheaccess(client, name, qtype, options));
    957   1.3  christos 	}
    958   1.3  christos 
    959   1.3  christos 	/*
    960   1.1  christos 	 * This limits our searching to the zone where the first name
    961   1.1  christos 	 * (the query target) was looked for.  This prevents following
    962   1.1  christos 	 * CNAMES or DNAMES into other zones and prevents returning
    963   1.1  christos 	 * additional data from other zones. This does not apply if we're
    964   1.1  christos 	 * answering a query where recursion is requested and allowed.
    965   1.1  christos 	 */
    966   1.1  christos 	if (client->query.rpz_st == NULL &&
    967   1.1  christos 	    !(WANTRECURSION(client) && RECURSIONOK(client)) &&
    968   1.1  christos 	    client->query.authdbset && db != client->query.authdb)
    969   1.1  christos 	{
    970   1.1  christos 		return (DNS_R_REFUSED);
    971   1.1  christos 	}
    972   1.1  christos 
    973   1.1  christos 	/*
    974   1.1  christos 	 * Non recursive query to a static-stub zone is prohibited; its
    975   1.1  christos 	 * zone content is not public data, but a part of local configuration
    976   1.1  christos 	 * and should not be disclosed.
    977   1.1  christos 	 */
    978   1.1  christos 	if (dns_zone_gettype(zone) == dns_zone_staticstub &&
    979  1.16  christos 	    !RECURSIONOK(client))
    980  1.16  christos 	{
    981   1.1  christos 		return (DNS_R_REFUSED);
    982   1.1  christos 	}
    983   1.1  christos 
    984   1.1  christos 	/*
    985   1.1  christos 	 * If the zone has an ACL, we'll check it, otherwise
    986   1.1  christos 	 * we use the view's "allow-query" ACL.  Each ACL is only checked
    987   1.1  christos 	 * once per query.
    988   1.1  christos 	 *
    989   1.1  christos 	 * Also, get the database version to use.
    990   1.1  christos 	 */
    991   1.1  christos 
    992   1.1  christos 	/*
    993   1.1  christos 	 * Get the current version of this database.
    994   1.1  christos 	 */
    995   1.3  christos 	dbversion = ns_client_findversion(client, db);
    996   1.1  christos 	if (dbversion == NULL) {
    997   1.1  christos 		CTRACE(ISC_LOG_ERROR, "unable to get db version");
    998   1.1  christos 		return (DNS_R_SERVFAIL);
    999   1.1  christos 	}
   1000   1.1  christos 
   1001   1.9  christos 	if ((options & DNS_GETDB_IGNOREACL) != 0) {
   1002   1.1  christos 		goto approved;
   1003   1.9  christos 	}
   1004   1.1  christos 	if (dbversion->acl_checked) {
   1005   1.9  christos 		if (!dbversion->queryok) {
   1006   1.1  christos 			return (DNS_R_REFUSED);
   1007   1.9  christos 		}
   1008   1.1  christos 		goto approved;
   1009   1.1  christos 	}
   1010   1.1  christos 
   1011   1.1  christos 	queryacl = dns_zone_getqueryacl(zone);
   1012   1.1  christos 	if (queryacl == NULL) {
   1013   1.1  christos 		queryacl = client->view->queryacl;
   1014   1.9  christos 		if ((client->query.attributes & NS_QUERYATTR_QUERYOKVALID) != 0)
   1015   1.9  christos 		{
   1016   1.1  christos 			/*
   1017   1.1  christos 			 * We've evaluated the view's queryacl already.  If
   1018   1.1  christos 			 * NS_QUERYATTR_QUERYOK is set, then the client is
   1019   1.1  christos 			 * allowed to make queries, otherwise the query should
   1020   1.1  christos 			 * be refused.
   1021   1.1  christos 			 */
   1022   1.3  christos 			dbversion->acl_checked = true;
   1023   1.9  christos 			if ((client->query.attributes & NS_QUERYATTR_QUERYOK) ==
   1024  1.16  christos 			    0)
   1025  1.16  christos 			{
   1026   1.3  christos 				dbversion->queryok = false;
   1027   1.1  christos 				return (DNS_R_REFUSED);
   1028   1.1  christos 			}
   1029   1.3  christos 			dbversion->queryok = true;
   1030   1.1  christos 			goto approved;
   1031   1.1  christos 		}
   1032   1.1  christos 	}
   1033   1.1  christos 
   1034   1.3  christos 	result = ns_client_checkaclsilent(client, NULL, queryacl, true);
   1035   1.1  christos 	if ((options & DNS_GETDB_NOLOG) == 0) {
   1036   1.1  christos 		char msg[NS_CLIENT_ACLMSGSIZE("query")];
   1037   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1038   1.1  christos 			if (isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(3))) {
   1039   1.1  christos 				ns_client_aclmsg("query", name, qtype,
   1040   1.9  christos 						 client->view->rdclass, msg,
   1041   1.9  christos 						 sizeof(msg));
   1042   1.9  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1043   1.1  christos 					      NS_LOGMODULE_QUERY,
   1044   1.9  christos 					      ISC_LOG_DEBUG(3), "%s approved",
   1045   1.9  christos 					      msg);
   1046   1.1  christos 			}
   1047   1.1  christos 		} else {
   1048   1.7  christos 			pfilter_notify(result, client, "validatezonedb");
   1049   1.1  christos 			ns_client_aclmsg("query", name, qtype,
   1050   1.9  christos 					 client->view->rdclass, msg,
   1051   1.9  christos 					 sizeof(msg));
   1052   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1053   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   1054   1.1  christos 				      "%s denied", msg);
   1055  1.20  christos 			ns_client_extendederror(client, DNS_EDE_PROHIBITED,
   1056  1.20  christos 						NULL);
   1057   1.1  christos 		}
   1058   1.1  christos 	}
   1059   1.1  christos 
   1060   1.1  christos 	if (queryacl == client->view->queryacl) {
   1061   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1062   1.1  christos 			/*
   1063   1.1  christos 			 * We were allowed by the default
   1064   1.1  christos 			 * "allow-query" ACL.  Remember this so we
   1065   1.1  christos 			 * don't have to check again.
   1066   1.1  christos 			 */
   1067   1.1  christos 			client->query.attributes |= NS_QUERYATTR_QUERYOK;
   1068   1.1  christos 		}
   1069   1.1  christos 		/*
   1070   1.1  christos 		 * We've now evaluated the view's query ACL, and
   1071   1.1  christos 		 * the NS_QUERYATTR_QUERYOK attribute is now valid.
   1072   1.1  christos 		 */
   1073   1.1  christos 		client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
   1074   1.1  christos 	}
   1075   1.1  christos 
   1076   1.1  christos 	/* If and only if we've gotten this far, check allow-query-on too */
   1077   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1078   1.1  christos 		queryonacl = dns_zone_getqueryonacl(zone);
   1079   1.9  christos 		if (queryonacl == NULL) {
   1080   1.1  christos 			queryonacl = client->view->queryonacl;
   1081   1.9  christos 		}
   1082   1.1  christos 
   1083   1.1  christos 		result = ns_client_checkaclsilent(client, &client->destaddr,
   1084   1.3  christos 						  queryonacl, true);
   1085  1.20  christos 		if (result != ISC_R_SUCCESS) {
   1086  1.20  christos 			ns_client_extendederror(client, DNS_EDE_PROHIBITED,
   1087  1.20  christos 						NULL);
   1088  1.20  christos 		}
   1089   1.9  christos 		if ((options & DNS_GETDB_NOLOG) == 0 && result != ISC_R_SUCCESS)
   1090   1.9  christos 		{
   1091   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1092   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   1093   1.1  christos 				      "query-on denied");
   1094   1.9  christos 		}
   1095   1.1  christos 	}
   1096   1.1  christos 
   1097   1.3  christos 	dbversion->acl_checked = true;
   1098   1.1  christos 	if (result != ISC_R_SUCCESS) {
   1099   1.3  christos 		dbversion->queryok = false;
   1100   1.1  christos 		return (DNS_R_REFUSED);
   1101   1.1  christos 	}
   1102   1.3  christos 	dbversion->queryok = true;
   1103   1.1  christos 
   1104   1.9  christos approved:
   1105   1.1  christos 	/* Transfer ownership, if necessary. */
   1106   1.9  christos 	if (versionp != NULL) {
   1107   1.1  christos 		*versionp = dbversion->version;
   1108   1.9  christos 	}
   1109   1.1  christos 	return (ISC_R_SUCCESS);
   1110   1.1  christos }
   1111   1.1  christos 
   1112  1.15  christos static isc_result_t
   1113   1.1  christos query_getzonedb(ns_client_t *client, const dns_name_t *name,
   1114   1.9  christos 		dns_rdatatype_t qtype, unsigned int options, dns_zone_t **zonep,
   1115   1.9  christos 		dns_db_t **dbp, dns_dbversion_t **versionp) {
   1116   1.1  christos 	isc_result_t result;
   1117   1.1  christos 	unsigned int ztoptions;
   1118   1.1  christos 	dns_zone_t *zone = NULL;
   1119   1.1  christos 	dns_db_t *db = NULL;
   1120   1.3  christos 	bool partial = false;
   1121   1.1  christos 
   1122   1.1  christos 	REQUIRE(zonep != NULL && *zonep == NULL);
   1123   1.1  christos 	REQUIRE(dbp != NULL && *dbp == NULL);
   1124   1.1  christos 
   1125   1.1  christos 	/*%
   1126   1.1  christos 	 * Find a zone database to answer the query.
   1127   1.1  christos 	 */
   1128   1.3  christos 	ztoptions = DNS_ZTFIND_MIRROR;
   1129   1.3  christos 	if ((options & DNS_GETDB_NOEXACT) != 0) {
   1130   1.3  christos 		ztoptions |= DNS_ZTFIND_NOEXACT;
   1131   1.3  christos 	}
   1132   1.1  christos 
   1133   1.1  christos 	result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
   1134   1.1  christos 			     &zone);
   1135   1.1  christos 
   1136   1.9  christos 	if (result == DNS_R_PARTIALMATCH) {
   1137   1.3  christos 		partial = true;
   1138   1.9  christos 	}
   1139   1.9  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
   1140   1.1  christos 		result = dns_zone_getdb(zone, &db);
   1141   1.9  christos 	}
   1142   1.1  christos 
   1143   1.9  christos 	if (result != ISC_R_SUCCESS) {
   1144   1.1  christos 		goto fail;
   1145   1.9  christos 	}
   1146   1.1  christos 
   1147   1.1  christos 	result = query_validatezonedb(client, name, qtype, options, zone, db,
   1148   1.1  christos 				      versionp);
   1149   1.1  christos 
   1150   1.9  christos 	if (result != ISC_R_SUCCESS) {
   1151   1.1  christos 		goto fail;
   1152   1.9  christos 	}
   1153   1.1  christos 
   1154   1.1  christos 	/* Transfer ownership. */
   1155   1.1  christos 	*zonep = zone;
   1156   1.1  christos 	*dbp = db;
   1157   1.1  christos 
   1158   1.9  christos 	if (partial && (options & DNS_GETDB_PARTIAL) != 0) {
   1159   1.1  christos 		return (DNS_R_PARTIALMATCH);
   1160   1.9  christos 	}
   1161   1.1  christos 	return (ISC_R_SUCCESS);
   1162   1.1  christos 
   1163   1.9  christos fail:
   1164   1.9  christos 	if (zone != NULL) {
   1165   1.1  christos 		dns_zone_detach(&zone);
   1166   1.9  christos 	}
   1167   1.9  christos 	if (db != NULL) {
   1168   1.1  christos 		dns_db_detach(&db);
   1169   1.9  christos 	}
   1170   1.1  christos 
   1171   1.1  christos 	return (result);
   1172   1.1  christos }
   1173   1.1  christos 
   1174   1.1  christos static void
   1175   1.9  christos rpz_log_rewrite(ns_client_t *client, bool disabled, dns_rpz_policy_t policy,
   1176   1.9  christos 		dns_rpz_type_t type, dns_zone_t *p_zone, dns_name_t *p_name,
   1177   1.9  christos 		dns_name_t *cname, dns_rpz_num_t rpz_num) {
   1178   1.3  christos 	char cname_buf[DNS_NAME_FORMATSIZE] = { 0 };
   1179   1.3  christos 	char p_name_buf[DNS_NAME_FORMATSIZE];
   1180   1.1  christos 	char qname_buf[DNS_NAME_FORMATSIZE];
   1181   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   1182   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   1183   1.1  christos 	const char *s1 = cname_buf, *s2 = cname_buf;
   1184   1.3  christos 	dns_rdataset_t *rdataset;
   1185   1.1  christos 	dns_rpz_st_t *st;
   1186   1.3  christos 	isc_stats_t *zonestats;
   1187   1.1  christos 
   1188   1.1  christos 	/*
   1189   1.1  christos 	 * Count enabled rewrites in the global counter.
   1190   1.1  christos 	 * Count both enabled and disabled rewrites for each zone.
   1191   1.1  christos 	 */
   1192   1.1  christos 	if (!disabled && policy != DNS_RPZ_POLICY_PASSTHRU) {
   1193   1.1  christos 		ns_stats_increment(client->sctx->nsstats,
   1194   1.1  christos 				   ns_statscounter_rpz_rewrites);
   1195   1.1  christos 	}
   1196   1.1  christos 	if (p_zone != NULL) {
   1197   1.1  christos 		zonestats = dns_zone_getrequeststats(p_zone);
   1198   1.9  christos 		if (zonestats != NULL) {
   1199   1.1  christos 			isc_stats_increment(zonestats,
   1200   1.1  christos 					    ns_statscounter_rpz_rewrites);
   1201   1.9  christos 		}
   1202   1.1  christos 	}
   1203   1.1  christos 
   1204   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, DNS_RPZ_INFO_LEVEL)) {
   1205   1.1  christos 		return;
   1206   1.9  christos 	}
   1207   1.1  christos 
   1208   1.1  christos 	st = client->query.rpz_st;
   1209   1.9  christos 	if ((st->popt.no_log & DNS_RPZ_ZBIT(rpz_num)) != 0) {
   1210   1.1  christos 		return;
   1211   1.9  christos 	}
   1212   1.1  christos 
   1213   1.1  christos 	dns_name_format(client->query.qname, qname_buf, sizeof(qname_buf));
   1214   1.1  christos 	dns_name_format(p_name, p_name_buf, sizeof(p_name_buf));
   1215   1.1  christos 	if (cname != NULL) {
   1216   1.1  christos 		s1 = " (CNAME to: ";
   1217   1.1  christos 		dns_name_format(cname, cname_buf, sizeof(cname_buf));
   1218   1.1  christos 		s2 = ")";
   1219   1.1  christos 	}
   1220   1.1  christos 
   1221   1.3  christos 	/*
   1222   1.3  christos 	 *  Log Qclass and Qtype in addition to existing
   1223   1.3  christos 	 *  fields.
   1224   1.3  christos 	 */
   1225   1.3  christos 	rdataset = ISC_LIST_HEAD(client->query.origqname->list);
   1226   1.3  christos 	INSIST(rdataset != NULL);
   1227   1.3  christos 	dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf));
   1228   1.3  christos 	dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
   1229   1.3  christos 
   1230  1.20  christos 	/* It's possible to have a separate log channel for rpz passthru. */
   1231  1.20  christos 	isc_logcategory_t *log_cat = (policy == DNS_RPZ_POLICY_PASSTHRU)
   1232  1.20  christos 					     ? DNS_LOGCATEGORY_RPZ_PASSTHRU
   1233  1.20  christos 					     : DNS_LOGCATEGORY_RPZ;
   1234  1.20  christos 
   1235  1.20  christos 	ns_client_log(client, log_cat, NS_LOGMODULE_QUERY, DNS_RPZ_INFO_LEVEL,
   1236   1.3  christos 		      "%srpz %s %s rewrite %s/%s/%s via %s%s%s%s",
   1237   1.9  christos 		      disabled ? "disabled " : "", dns_rpz_type2str(type),
   1238   1.9  christos 		      dns_rpz_policy2str(policy), qname_buf, typebuf, classbuf,
   1239   1.3  christos 		      p_name_buf, s1, cname_buf, s2);
   1240   1.1  christos }
   1241   1.1  christos 
   1242   1.1  christos static void
   1243   1.1  christos rpz_log_fail_helper(ns_client_t *client, int level, dns_name_t *p_name,
   1244   1.1  christos 		    dns_rpz_type_t rpz_type1, dns_rpz_type_t rpz_type2,
   1245   1.9  christos 		    const char *str, isc_result_t result) {
   1246   1.1  christos 	char qnamebuf[DNS_NAME_FORMATSIZE];
   1247   1.1  christos 	char p_namebuf[DNS_NAME_FORMATSIZE];
   1248   1.1  christos 	const char *failed, *via, *slash, *str_blank;
   1249   1.1  christos 	const char *rpztypestr1;
   1250   1.1  christos 	const char *rpztypestr2;
   1251   1.1  christos 
   1252   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   1253   1.1  christos 		return;
   1254   1.9  christos 	}
   1255   1.1  christos 
   1256   1.1  christos 	/*
   1257   1.1  christos 	 * bin/tests/system/rpz/tests.sh looks for "rpz.*failed" for problems.
   1258   1.1  christos 	 */
   1259   1.9  christos 	if (level <= DNS_RPZ_DEBUG_LEVEL1) {
   1260   1.3  christos 		failed = " failed: ";
   1261   1.9  christos 	} else {
   1262   1.1  christos 		failed = ": ";
   1263   1.9  christos 	}
   1264   1.1  christos 
   1265   1.1  christos 	rpztypestr1 = dns_rpz_type2str(rpz_type1);
   1266   1.1  christos 	if (rpz_type2 != DNS_RPZ_TYPE_BAD) {
   1267   1.1  christos 		slash = "/";
   1268   1.1  christos 		rpztypestr2 = dns_rpz_type2str(rpz_type2);
   1269   1.1  christos 	} else {
   1270   1.1  christos 		slash = "";
   1271   1.1  christos 		rpztypestr2 = "";
   1272   1.1  christos 	}
   1273   1.1  christos 
   1274   1.1  christos 	str_blank = (*str != ' ' && *str != '\0') ? " " : "";
   1275   1.1  christos 
   1276   1.1  christos 	dns_name_format(client->query.qname, qnamebuf, sizeof(qnamebuf));
   1277   1.1  christos 
   1278   1.1  christos 	if (p_name != NULL) {
   1279   1.1  christos 		via = " via ";
   1280   1.1  christos 		dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
   1281   1.1  christos 	} else {
   1282   1.1  christos 		via = "";
   1283   1.1  christos 		p_namebuf[0] = '\0';
   1284   1.1  christos 	}
   1285   1.1  christos 
   1286   1.9  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS, NS_LOGMODULE_QUERY,
   1287   1.9  christos 		      level, "rpz %s%s%s rewrite %s%s%s%s%s%s%s", rpztypestr1,
   1288   1.9  christos 		      slash, rpztypestr2, qnamebuf, via, p_namebuf, str_blank,
   1289   1.1  christos 		      str, failed, isc_result_totext(result));
   1290   1.1  christos }
   1291   1.1  christos 
   1292   1.1  christos static void
   1293   1.1  christos rpz_log_fail(ns_client_t *client, int level, dns_name_t *p_name,
   1294   1.9  christos 	     dns_rpz_type_t rpz_type, const char *str, isc_result_t result) {
   1295   1.9  christos 	rpz_log_fail_helper(client, level, p_name, rpz_type, DNS_RPZ_TYPE_BAD,
   1296   1.9  christos 			    str, result);
   1297   1.1  christos }
   1298   1.1  christos 
   1299   1.1  christos /*
   1300   1.1  christos  * Get a policy rewrite zone database.
   1301   1.1  christos  */
   1302   1.1  christos static isc_result_t
   1303   1.1  christos rpz_getdb(ns_client_t *client, dns_name_t *p_name, dns_rpz_type_t rpz_type,
   1304   1.9  christos 	  dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp) {
   1305   1.1  christos 	char qnamebuf[DNS_NAME_FORMATSIZE];
   1306   1.1  christos 	char p_namebuf[DNS_NAME_FORMATSIZE];
   1307   1.1  christos 	dns_dbversion_t *rpz_version = NULL;
   1308   1.1  christos 	isc_result_t result;
   1309   1.1  christos 
   1310   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_getdb");
   1311   1.1  christos 
   1312   1.1  christos 	result = query_getzonedb(client, p_name, dns_rdatatype_any,
   1313   1.1  christos 				 DNS_GETDB_IGNOREACL, zonep, dbp, &rpz_version);
   1314   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1315   1.1  christos 		dns_rpz_st_t *st = client->query.rpz_st;
   1316   1.1  christos 
   1317   1.1  christos 		/*
   1318   1.1  christos 		 * It isn't meaningful to log this message when
   1319   1.1  christos 		 * logging is disabled for some policy zones.
   1320   1.1  christos 		 */
   1321   1.1  christos 		if (st->popt.no_log == 0 &&
   1322  1.16  christos 		    isc_log_wouldlog(ns_lctx, DNS_RPZ_DEBUG_LEVEL2))
   1323  1.16  christos 		{
   1324   1.1  christos 			dns_name_format(client->query.qname, qnamebuf,
   1325   1.1  christos 					sizeof(qnamebuf));
   1326   1.1  christos 			dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
   1327   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_RPZ,
   1328   1.1  christos 				      NS_LOGMODULE_QUERY, DNS_RPZ_DEBUG_LEVEL2,
   1329   1.1  christos 				      "try rpz %s rewrite %s via %s",
   1330   1.9  christos 				      dns_rpz_type2str(rpz_type), qnamebuf,
   1331   1.9  christos 				      p_namebuf);
   1332   1.1  christos 		}
   1333   1.1  christos 		*versionp = rpz_version;
   1334   1.1  christos 		return (ISC_R_SUCCESS);
   1335   1.1  christos 	}
   1336   1.1  christos 	rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type,
   1337   1.3  christos 		     "query_getzonedb()", result);
   1338   1.1  christos 	return (result);
   1339   1.1  christos }
   1340   1.1  christos 
   1341   1.3  christos /*%
   1342   1.3  christos  * Find a cache database to answer the query.  This may fail with DNS_R_REFUSED
   1343   1.3  christos  * if the client is not allowed to use the cache.
   1344   1.3  christos  */
   1345  1.15  christos static isc_result_t
   1346   1.1  christos query_getcachedb(ns_client_t *client, const dns_name_t *name,
   1347   1.9  christos 		 dns_rdatatype_t qtype, dns_db_t **dbp, unsigned int options) {
   1348   1.1  christos 	isc_result_t result;
   1349   1.1  christos 	dns_db_t *db = NULL;
   1350   1.1  christos 
   1351   1.1  christos 	REQUIRE(dbp != NULL && *dbp == NULL);
   1352   1.1  christos 
   1353   1.3  christos 	if (!USECACHE(client)) {
   1354   1.1  christos 		return (DNS_R_REFUSED);
   1355   1.1  christos 	}
   1356   1.1  christos 
   1357   1.3  christos 	dns_db_attach(client->view->cachedb, &db);
   1358   1.1  christos 
   1359   1.3  christos 	result = query_checkcacheaccess(client, name, qtype, options);
   1360   1.3  christos 	if (result != ISC_R_SUCCESS) {
   1361   1.3  christos 		dns_db_detach(&db);
   1362   1.1  christos 	}
   1363   1.1  christos 
   1364   1.3  christos 	/*
   1365   1.3  christos 	 * If query_checkcacheaccess() succeeded, transfer ownership of 'db'.
   1366   1.3  christos 	 * Otherwise, 'db' will be NULL due to the dns_db_detach() call above.
   1367   1.3  christos 	 */
   1368   1.1  christos 	*dbp = db;
   1369   1.1  christos 
   1370   1.3  christos 	return (result);
   1371   1.3  christos }
   1372   1.1  christos 
   1373  1.15  christos static isc_result_t
   1374   1.3  christos query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
   1375   1.1  christos 	    unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
   1376   1.9  christos 	    dns_dbversion_t **versionp, bool *is_zonep) {
   1377   1.1  christos 	isc_result_t result;
   1378   1.1  christos 	isc_result_t tresult;
   1379   1.1  christos 	unsigned int namelabels;
   1380   1.1  christos 	unsigned int zonelabels;
   1381   1.1  christos 	dns_zone_t *zone = NULL;
   1382   1.1  christos 
   1383   1.1  christos 	REQUIRE(zonep != NULL && *zonep == NULL);
   1384   1.1  christos 
   1385   1.1  christos 	/* Calculate how many labels are in name. */
   1386   1.1  christos 	namelabels = dns_name_countlabels(name);
   1387   1.1  christos 	zonelabels = 0;
   1388   1.1  christos 
   1389   1.1  christos 	/* Try to find name in bind's standard database. */
   1390   1.9  christos 	result = query_getzonedb(client, name, qtype, options, &zone, dbp,
   1391   1.9  christos 				 versionp);
   1392   1.1  christos 
   1393   1.1  christos 	/* See how many labels are in the zone's name.	  */
   1394   1.5  christos 	if (result == ISC_R_SUCCESS && zone != NULL) {
   1395   1.1  christos 		zonelabels = dns_name_countlabels(dns_zone_getorigin(zone));
   1396   1.5  christos 	}
   1397   1.1  christos 
   1398   1.1  christos 	/*
   1399   1.1  christos 	 * If # zone labels < # name labels, try to find an even better match
   1400   1.1  christos 	 * Only try if DLZ drivers are loaded for this view
   1401   1.1  christos 	 */
   1402  1.20  christos 	if (zonelabels < namelabels &&
   1403  1.20  christos 	    !ISC_LIST_EMPTY(client->view->dlz_searched))
   1404   1.1  christos 	{
   1405   1.1  christos 		dns_clientinfomethods_t cm;
   1406   1.1  christos 		dns_clientinfo_t ci;
   1407   1.1  christos 		dns_db_t *tdbp;
   1408   1.1  christos 
   1409   1.1  christos 		dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1410  1.20  christos 		dns_clientinfo_init(&ci, client, NULL);
   1411  1.20  christos 		dns_clientinfo_setecs(&ci, &client->ecs);
   1412   1.1  christos 
   1413   1.1  christos 		tdbp = NULL;
   1414   1.9  christos 		tresult = dns_view_searchdlz(client->view, name, zonelabels,
   1415   1.9  christos 					     &cm, &ci, &tdbp);
   1416   1.9  christos 		/* If we successful, we found a better match. */
   1417   1.1  christos 		if (tresult == ISC_R_SUCCESS) {
   1418   1.1  christos 			ns_dbversion_t *dbversion;
   1419   1.1  christos 
   1420   1.1  christos 			/*
   1421   1.1  christos 			 * If the previous search returned a zone, detach it.
   1422   1.1  christos 			 */
   1423   1.9  christos 			if (zone != NULL) {
   1424   1.1  christos 				dns_zone_detach(&zone);
   1425   1.9  christos 			}
   1426   1.1  christos 
   1427   1.1  christos 			/*
   1428   1.1  christos 			 * If the previous search returned a database,
   1429   1.1  christos 			 * detach it.
   1430   1.1  christos 			 */
   1431   1.9  christos 			if (*dbp != NULL) {
   1432   1.1  christos 				dns_db_detach(dbp);
   1433   1.9  christos 			}
   1434   1.1  christos 
   1435   1.1  christos 			/*
   1436   1.1  christos 			 * If the previous search returned a version, clear it.
   1437   1.1  christos 			 */
   1438   1.1  christos 			*versionp = NULL;
   1439   1.1  christos 
   1440   1.3  christos 			dbversion = ns_client_findversion(client, tdbp);
   1441   1.1  christos 			if (dbversion == NULL) {
   1442   1.1  christos 				tresult = ISC_R_NOMEMORY;
   1443   1.1  christos 			} else {
   1444   1.1  christos 				/*
   1445   1.1  christos 				 * Be sure to return our database.
   1446   1.1  christos 				 */
   1447   1.1  christos 				*dbp = tdbp;
   1448   1.1  christos 				*versionp = dbversion->version;
   1449   1.1  christos 			}
   1450   1.1  christos 
   1451   1.1  christos 			/*
   1452   1.1  christos 			 * We return a null zone, No stats for DLZ zones.
   1453   1.1  christos 			 */
   1454   1.1  christos 			zone = NULL;
   1455   1.1  christos 			result = tresult;
   1456   1.1  christos 		}
   1457   1.1  christos 	}
   1458   1.1  christos 
   1459   1.1  christos 	/* If successful, Transfer ownership of zone. */
   1460   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1461   1.1  christos 		*zonep = zone;
   1462   1.1  christos 		/*
   1463   1.1  christos 		 * If neither attempt above succeeded, return the cache instead
   1464   1.1  christos 		 */
   1465   1.3  christos 		*is_zonep = true;
   1466   1.5  christos 	} else {
   1467   1.5  christos 		if (result == ISC_R_NOTFOUND) {
   1468   1.5  christos 			result = query_getcachedb(client, name, qtype, dbp,
   1469   1.5  christos 						  options);
   1470   1.5  christos 		}
   1471   1.3  christos 		*is_zonep = false;
   1472   1.1  christos 	}
   1473   1.1  christos 	return (result);
   1474   1.1  christos }
   1475   1.1  christos 
   1476  1.15  christos static bool
   1477   1.9  christos query_isduplicate(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
   1478   1.9  christos 		  dns_name_t **mnamep) {
   1479   1.1  christos 	dns_section_t section;
   1480   1.1  christos 	dns_name_t *mname = NULL;
   1481   1.1  christos 	isc_result_t result;
   1482   1.1  christos 
   1483   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate");
   1484   1.1  christos 
   1485   1.9  christos 	for (section = DNS_SECTION_ANSWER; section <= DNS_SECTION_ADDITIONAL;
   1486  1.16  christos 	     section++)
   1487  1.16  christos 	{
   1488   1.9  christos 		result = dns_message_findname(client->message, section, name,
   1489   1.9  christos 					      type, 0, &mname, NULL);
   1490   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1491   1.1  christos 			/*
   1492   1.1  christos 			 * We've already got this RRset in the response.
   1493   1.1  christos 			 */
   1494   1.9  christos 			CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: true: "
   1495   1.9  christos 						 "done");
   1496   1.3  christos 			return (true);
   1497   1.1  christos 		} else if (result == DNS_R_NXRRSET) {
   1498   1.1  christos 			/*
   1499   1.1  christos 			 * The name exists, but the rdataset does not.
   1500   1.1  christos 			 */
   1501   1.9  christos 			if (section == DNS_SECTION_ADDITIONAL) {
   1502   1.1  christos 				break;
   1503   1.9  christos 			}
   1504   1.9  christos 		} else {
   1505   1.1  christos 			RUNTIME_CHECK(result == DNS_R_NXDOMAIN);
   1506   1.9  christos 		}
   1507   1.1  christos 		mname = NULL;
   1508   1.1  christos 	}
   1509   1.1  christos 
   1510   1.9  christos 	if (mnamep != NULL) {
   1511   1.1  christos 		*mnamep = mname;
   1512   1.9  christos 	}
   1513   1.1  christos 
   1514   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: false: done");
   1515   1.3  christos 	return (false);
   1516   1.1  christos }
   1517   1.1  christos 
   1518   1.6  christos /*
   1519   1.6  christos  * Look up data for given 'name' and 'type' in given 'version' of 'db' for
   1520   1.6  christos  * 'client'. Called from query_additionalauth().
   1521   1.6  christos  *
   1522   1.6  christos  * If the lookup is successful:
   1523   1.6  christos  *
   1524   1.6  christos  *   - store the node containing the result at 'nodep',
   1525   1.6  christos  *
   1526   1.6  christos  *   - store the owner name of the returned node in 'fname',
   1527   1.6  christos  *
   1528   1.6  christos  *   - if 'type' is not ANY, dns_db_findext() will put the exact rdataset being
   1529   1.6  christos  *     looked for in 'rdataset' and its signatures (if any) in 'sigrdataset',
   1530   1.6  christos  *
   1531   1.6  christos  *   - if 'type' is ANY, dns_db_findext() will leave 'rdataset' and
   1532   1.6  christos  *     'sigrdataset' disassociated and the returned node will be iterated in
   1533   1.6  christos  *     query_additional_cb().
   1534   1.6  christos  *
   1535   1.6  christos  * If the lookup is not successful:
   1536   1.6  christos  *
   1537   1.6  christos  *   - 'nodep' will not be written to,
   1538   1.6  christos  *   - 'fname' may still be modified as it is passed to dns_db_findext(),
   1539   1.6  christos  *   - 'rdataset' and 'sigrdataset' will remain disassociated.
   1540   1.6  christos  */
   1541   1.6  christos static isc_result_t
   1542   1.6  christos query_additionalauthfind(dns_db_t *db, dns_dbversion_t *version,
   1543   1.6  christos 			 const dns_name_t *name, dns_rdatatype_t type,
   1544   1.6  christos 			 ns_client_t *client, dns_dbnode_t **nodep,
   1545   1.6  christos 			 dns_name_t *fname, dns_rdataset_t *rdataset,
   1546   1.9  christos 			 dns_rdataset_t *sigrdataset) {
   1547   1.6  christos 	dns_clientinfomethods_t cm;
   1548   1.6  christos 	dns_dbnode_t *node = NULL;
   1549   1.6  christos 	dns_clientinfo_t ci;
   1550   1.6  christos 	isc_result_t result;
   1551   1.6  christos 
   1552   1.6  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1553  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   1554   1.6  christos 
   1555   1.6  christos 	/*
   1556   1.6  christos 	 * Since we are looking for authoritative data, we do not set
   1557   1.6  christos 	 * the GLUEOK flag.  Glue will be looked for later, but not
   1558   1.6  christos 	 * necessarily in the same database.
   1559   1.6  christos 	 */
   1560   1.6  christos 	result = dns_db_findext(db, name, version, type,
   1561   1.6  christos 				client->query.dboptions, client->now, &node,
   1562   1.6  christos 				fname, &cm, &ci, rdataset, sigrdataset);
   1563   1.6  christos 	if (result != ISC_R_SUCCESS) {
   1564   1.6  christos 		if (dns_rdataset_isassociated(rdataset)) {
   1565   1.6  christos 			dns_rdataset_disassociate(rdataset);
   1566   1.6  christos 		}
   1567   1.6  christos 
   1568   1.6  christos 		if (sigrdataset != NULL &&
   1569  1.16  christos 		    dns_rdataset_isassociated(sigrdataset))
   1570  1.16  christos 		{
   1571   1.6  christos 			dns_rdataset_disassociate(sigrdataset);
   1572   1.6  christos 		}
   1573   1.6  christos 
   1574   1.6  christos 		if (node != NULL) {
   1575   1.6  christos 			dns_db_detachnode(db, &node);
   1576   1.6  christos 		}
   1577   1.6  christos 
   1578   1.6  christos 		return (result);
   1579   1.6  christos 	}
   1580   1.6  christos 
   1581   1.6  christos 	/*
   1582   1.6  christos 	 * Do not return signatures if the zone is not fully signed.
   1583   1.6  christos 	 */
   1584   1.6  christos 	if (sigrdataset != NULL && !dns_db_issecure(db) &&
   1585   1.6  christos 	    dns_rdataset_isassociated(sigrdataset))
   1586   1.6  christos 	{
   1587   1.6  christos 		dns_rdataset_disassociate(sigrdataset);
   1588   1.6  christos 	}
   1589   1.6  christos 
   1590   1.6  christos 	*nodep = node;
   1591   1.6  christos 
   1592   1.6  christos 	return (ISC_R_SUCCESS);
   1593   1.6  christos }
   1594   1.6  christos 
   1595   1.6  christos /*
   1596   1.6  christos  * For query context 'qctx', try finding authoritative additional data for
   1597   1.6  christos  * given 'name' and 'type'. Called from query_additional_cb().
   1598   1.6  christos  *
   1599   1.6  christos  * If successful:
   1600   1.6  christos  *
   1601   1.6  christos  *   - store pointers to the database and node which contain the result in
   1602   1.6  christos  *     'dbp' and 'nodep', respectively,
   1603   1.6  christos  *
   1604   1.6  christos  *   - store the owner name of the returned node in 'fname',
   1605   1.6  christos  *
   1606   1.6  christos  *   - potentially bind 'rdataset' and 'sigrdataset', as explained in the
   1607   1.6  christos  *     comment for query_additionalauthfind().
   1608   1.6  christos  *
   1609   1.6  christos  * If unsuccessful:
   1610   1.6  christos  *
   1611   1.6  christos  *   - 'dbp' and 'nodep' will not be written to,
   1612   1.6  christos  *   - 'fname' may still be modified as it is passed to dns_db_findext(),
   1613   1.6  christos  *   - 'rdataset' and 'sigrdataset' will remain disassociated.
   1614   1.6  christos  */
   1615   1.6  christos static isc_result_t
   1616   1.6  christos query_additionalauth(query_ctx_t *qctx, const dns_name_t *name,
   1617   1.9  christos 		     dns_rdatatype_t type, dns_db_t **dbp, dns_dbnode_t **nodep,
   1618   1.9  christos 		     dns_name_t *fname, dns_rdataset_t *rdataset,
   1619   1.9  christos 		     dns_rdataset_t *sigrdataset) {
   1620   1.6  christos 	ns_client_t *client = qctx->client;
   1621   1.6  christos 	ns_dbversion_t *dbversion = NULL;
   1622   1.6  christos 	dns_dbversion_t *version = NULL;
   1623   1.6  christos 	dns_dbnode_t *node = NULL;
   1624   1.6  christos 	dns_zone_t *zone = NULL;
   1625   1.6  christos 	dns_db_t *db = NULL;
   1626   1.6  christos 	isc_result_t result;
   1627   1.6  christos 
   1628   1.6  christos 	/*
   1629   1.6  christos 	 * First, look within the same zone database for authoritative
   1630   1.6  christos 	 * additional data.
   1631   1.6  christos 	 */
   1632   1.6  christos 	if (!client->query.authdbset || client->query.authdb == NULL) {
   1633   1.6  christos 		return (ISC_R_NOTFOUND);
   1634   1.6  christos 	}
   1635   1.6  christos 
   1636   1.6  christos 	dbversion = ns_client_findversion(client, client->query.authdb);
   1637   1.6  christos 	if (dbversion == NULL) {
   1638   1.6  christos 		return (ISC_R_NOTFOUND);
   1639   1.6  christos 	}
   1640   1.6  christos 
   1641   1.6  christos 	dns_db_attach(client->query.authdb, &db);
   1642   1.6  christos 	version = dbversion->version;
   1643   1.6  christos 
   1644   1.6  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: same zone");
   1645   1.6  christos 
   1646   1.6  christos 	result = query_additionalauthfind(db, version, name, type, client,
   1647   1.6  christos 					  &node, fname, rdataset, sigrdataset);
   1648   1.6  christos 	if (result != ISC_R_SUCCESS &&
   1649   1.6  christos 	    qctx->view->minimalresponses == dns_minimal_no &&
   1650   1.6  christos 	    RECURSIONOK(client))
   1651   1.6  christos 	{
   1652   1.6  christos 		/*
   1653   1.6  christos 		 * If we aren't doing response minimization and recursion is
   1654   1.6  christos 		 * allowed, we can try and see if any other zone matches.
   1655   1.6  christos 		 */
   1656   1.6  christos 		version = NULL;
   1657   1.6  christos 		dns_db_detach(&db);
   1658   1.6  christos 		result = query_getzonedb(client, name, type, DNS_GETDB_NOLOG,
   1659   1.6  christos 					 &zone, &db, &version);
   1660   1.6  christos 		if (result != ISC_R_SUCCESS) {
   1661   1.6  christos 			return (result);
   1662   1.6  christos 		}
   1663   1.6  christos 		dns_zone_detach(&zone);
   1664   1.6  christos 
   1665   1.6  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: other zone");
   1666   1.6  christos 
   1667   1.6  christos 		result = query_additionalauthfind(db, version, name, type,
   1668   1.6  christos 						  client, &node, fname,
   1669   1.6  christos 						  rdataset, sigrdataset);
   1670   1.6  christos 	}
   1671   1.6  christos 
   1672   1.6  christos 	if (result != ISC_R_SUCCESS) {
   1673   1.6  christos 		dns_db_detach(&db);
   1674   1.6  christos 	} else {
   1675   1.6  christos 		*nodep = node;
   1676   1.6  christos 		node = NULL;
   1677   1.6  christos 
   1678   1.6  christos 		*dbp = db;
   1679   1.6  christos 		db = NULL;
   1680   1.6  christos 	}
   1681   1.6  christos 
   1682   1.6  christos 	return (result);
   1683   1.6  christos }
   1684   1.6  christos 
   1685   1.1  christos static isc_result_t
   1686  1.20  christos query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
   1687  1.20  christos 		    dns_rdataset_t *found) {
   1688   1.3  christos 	query_ctx_t *qctx = arg;
   1689   1.3  christos 	ns_client_t *client = qctx->client;
   1690   1.3  christos 	isc_result_t result, eresult = ISC_R_SUCCESS;
   1691   1.3  christos 	dns_dbnode_t *node = NULL;
   1692   1.3  christos 	dns_db_t *db = NULL;
   1693   1.3  christos 	dns_name_t *fname = NULL, *mname = NULL;
   1694   1.3  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   1695   1.3  christos 	dns_rdataset_t *trdataset = NULL;
   1696   1.3  christos 	isc_buffer_t *dbuf = NULL;
   1697   1.1  christos 	isc_buffer_t b;
   1698   1.3  christos 	ns_dbversion_t *dbversion = NULL;
   1699   1.3  christos 	dns_dbversion_t *version = NULL;
   1700   1.3  christos 	bool added_something = false, need_addname = false;
   1701   1.1  christos 	dns_rdatatype_t type;
   1702   1.1  christos 	dns_clientinfomethods_t cm;
   1703   1.1  christos 	dns_clientinfo_t ci;
   1704   1.3  christos 	dns_rdatasetadditional_t additionaltype =
   1705   1.3  christos 		dns_rdatasetadditional_fromauth;
   1706   1.1  christos 
   1707   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   1708   1.1  christos 	REQUIRE(qtype != dns_rdatatype_any);
   1709   1.1  christos 
   1710   1.3  christos 	if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) {
   1711   1.1  christos 		return (ISC_R_SUCCESS);
   1712   1.3  christos 	}
   1713   1.1  christos 
   1714   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb");
   1715   1.1  christos 
   1716   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1717  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   1718   1.1  christos 
   1719   1.1  christos 	/*
   1720   1.1  christos 	 * We treat type A additional section processing as if it
   1721   1.1  christos 	 * were "any address type" additional section processing.
   1722   1.1  christos 	 * To avoid multiple lookups, we do an 'any' database
   1723   1.1  christos 	 * lookup and iterate over the node.
   1724   1.1  christos 	 */
   1725   1.3  christos 	if (qtype == dns_rdatatype_a) {
   1726   1.1  christos 		type = dns_rdatatype_any;
   1727   1.3  christos 	} else {
   1728   1.1  christos 		type = qtype;
   1729   1.3  christos 	}
   1730   1.1  christos 
   1731   1.1  christos 	/*
   1732   1.1  christos 	 * Get some resources.
   1733   1.1  christos 	 */
   1734   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   1735   1.3  christos 	if (dbuf == NULL) {
   1736   1.1  christos 		goto cleanup;
   1737   1.3  christos 	}
   1738   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   1739   1.3  christos 	rdataset = ns_client_newrdataset(client);
   1740   1.3  christos 	if (fname == NULL || rdataset == NULL) {
   1741   1.1  christos 		goto cleanup;
   1742   1.3  christos 	}
   1743   1.1  christos 	if (WANTDNSSEC(client)) {
   1744   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   1745   1.3  christos 		if (sigrdataset == NULL) {
   1746   1.1  christos 			goto cleanup;
   1747   1.3  christos 		}
   1748   1.1  christos 	}
   1749   1.1  christos 
   1750   1.1  christos 	/*
   1751   1.1  christos 	 * If we want only minimal responses and are here, then it must
   1752   1.1  christos 	 * be for glue.
   1753   1.1  christos 	 */
   1754  1.11  christos 	if (qctx->view->minimalresponses == dns_minimal_yes &&
   1755  1.11  christos 	    client->query.qtype != dns_rdatatype_ns)
   1756  1.11  christos 	{
   1757   1.1  christos 		goto try_glue;
   1758   1.3  christos 	}
   1759   1.1  christos 
   1760   1.1  christos 	/*
   1761   1.6  christos 	 * First, look for authoritative additional data.
   1762   1.1  christos 	 */
   1763   1.6  christos 	result = query_additionalauth(qctx, name, type, &db, &node, fname,
   1764   1.6  christos 				      rdataset, sigrdataset);
   1765   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1766   1.1  christos 		goto found;
   1767   1.1  christos 	}
   1768   1.1  christos 
   1769   1.1  christos 	/*
   1770   1.1  christos 	 * No authoritative data was found.  The cache is our next best bet.
   1771   1.1  christos 	 */
   1772   1.3  christos 	if (!qctx->view->recursion) {
   1773   1.1  christos 		goto try_glue;
   1774   1.3  christos 	}
   1775   1.1  christos 
   1776   1.1  christos 	additionaltype = dns_rdatasetadditional_fromcache;
   1777   1.1  christos 	result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
   1778   1.1  christos 	if (result != ISC_R_SUCCESS) {
   1779   1.1  christos 		/*
   1780   1.1  christos 		 * Most likely the client isn't allowed to query the cache.
   1781   1.1  christos 		 */
   1782   1.1  christos 		goto try_glue;
   1783   1.1  christos 	}
   1784   1.1  christos 	/*
   1785   1.1  christos 	 * Attempt to validate glue.
   1786   1.1  christos 	 */
   1787   1.1  christos 	if (sigrdataset == NULL) {
   1788   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   1789   1.3  christos 		if (sigrdataset == NULL) {
   1790   1.1  christos 			goto cleanup;
   1791   1.3  christos 		}
   1792   1.1  christos 	}
   1793   1.1  christos 
   1794   1.1  christos 	version = NULL;
   1795   1.1  christos 	result = dns_db_findext(db, name, version, type,
   1796   1.9  christos 				client->query.dboptions | DNS_DBFIND_GLUEOK |
   1797   1.9  christos 					DNS_DBFIND_ADDITIONALOK,
   1798   1.9  christos 				client->now, &node, fname, &cm, &ci, rdataset,
   1799   1.9  christos 				sigrdataset);
   1800   1.1  christos 
   1801   1.3  christos 	dns_cache_updatestats(qctx->view->cache, result);
   1802   1.3  christos 	if (!WANTDNSSEC(client)) {
   1803   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   1804   1.3  christos 	}
   1805   1.9  christos 	if (result == ISC_R_SUCCESS) {
   1806   1.1  christos 		goto found;
   1807   1.9  christos 	}
   1808   1.1  christos 
   1809   1.3  christos 	if (dns_rdataset_isassociated(rdataset)) {
   1810   1.1  christos 		dns_rdataset_disassociate(rdataset);
   1811   1.3  christos 	}
   1812   1.3  christos 	if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
   1813   1.1  christos 		dns_rdataset_disassociate(sigrdataset);
   1814   1.3  christos 	}
   1815   1.3  christos 	if (node != NULL) {
   1816   1.1  christos 		dns_db_detachnode(db, &node);
   1817   1.3  christos 	}
   1818   1.1  christos 	dns_db_detach(&db);
   1819   1.1  christos 
   1820   1.9  christos try_glue:
   1821   1.1  christos 	/*
   1822   1.1  christos 	 * No cached data was found.  Glue is our last chance.
   1823   1.1  christos 	 * RFC1035 sayeth:
   1824   1.1  christos 	 *
   1825   1.1  christos 	 *	NS records cause both the usual additional section
   1826   1.1  christos 	 *	processing to locate a type A record, and, when used
   1827   1.1  christos 	 *	in a referral, a special search of the zone in which
   1828   1.1  christos 	 *	they reside for glue information.
   1829   1.1  christos 	 *
   1830   1.1  christos 	 * This is the "special search".  Note that we must search
   1831   1.1  christos 	 * the zone where the NS record resides, not the zone it
   1832   1.1  christos 	 * points to, and that we only do the search in the delegation
   1833   1.1  christos 	 * case (identified by client->query.gluedb being set).
   1834   1.1  christos 	 */
   1835   1.1  christos 
   1836   1.3  christos 	if (client->query.gluedb == NULL) {
   1837   1.1  christos 		goto cleanup;
   1838   1.3  christos 	}
   1839   1.1  christos 
   1840   1.1  christos 	/*
   1841   1.1  christos 	 * Don't poison caches using the bailiwick protection model.
   1842   1.1  christos 	 */
   1843   1.3  christos 	if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) {
   1844   1.1  christos 		goto cleanup;
   1845   1.3  christos 	}
   1846   1.1  christos 
   1847   1.3  christos 	dbversion = ns_client_findversion(client, client->query.gluedb);
   1848   1.3  christos 	if (dbversion == NULL) {
   1849   1.1  christos 		goto cleanup;
   1850   1.3  christos 	}
   1851   1.1  christos 
   1852   1.1  christos 	dns_db_attach(client->query.gluedb, &db);
   1853   1.1  christos 	version = dbversion->version;
   1854   1.1  christos 	additionaltype = dns_rdatasetadditional_fromglue;
   1855   1.1  christos 	result = dns_db_findext(db, name, version, type,
   1856   1.1  christos 				client->query.dboptions | DNS_DBFIND_GLUEOK,
   1857   1.9  christos 				client->now, &node, fname, &cm, &ci, rdataset,
   1858   1.9  christos 				sigrdataset);
   1859   1.9  christos 	if (result != ISC_R_SUCCESS && result != DNS_R_ZONECUT &&
   1860  1.16  christos 	    result != DNS_R_GLUE)
   1861  1.16  christos 	{
   1862   1.1  christos 		goto cleanup;
   1863   1.3  christos 	}
   1864   1.1  christos 
   1865   1.9  christos found:
   1866   1.1  christos 	/*
   1867   1.1  christos 	 * We have found a potential additional data rdataset, or
   1868   1.1  christos 	 * at least a node to iterate over.
   1869   1.1  christos 	 */
   1870   1.3  christos 	ns_client_keepname(client, fname, dbuf);
   1871   1.1  christos 
   1872   1.1  christos 	/*
   1873  1.20  christos 	 * Does the caller want the found rdataset?
   1874  1.20  christos 	 */
   1875  1.20  christos 	if (found != NULL && dns_rdataset_isassociated(rdataset)) {
   1876  1.20  christos 		dns_rdataset_clone(rdataset, found);
   1877  1.20  christos 	}
   1878  1.20  christos 
   1879  1.20  christos 	/*
   1880   1.1  christos 	 * If we have an rdataset, add it to the additional data
   1881   1.1  christos 	 * section.
   1882   1.1  christos 	 */
   1883   1.1  christos 	mname = NULL;
   1884   1.1  christos 	if (dns_rdataset_isassociated(rdataset) &&
   1885   1.3  christos 	    !query_isduplicate(client, fname, type, &mname))
   1886   1.3  christos 	{
   1887   1.1  christos 		if (mname != NULL) {
   1888   1.1  christos 			INSIST(mname != fname);
   1889   1.3  christos 			ns_client_releasename(client, &fname);
   1890   1.1  christos 			fname = mname;
   1891   1.3  christos 		} else {
   1892   1.3  christos 			need_addname = true;
   1893   1.3  christos 		}
   1894   1.1  christos 		ISC_LIST_APPEND(fname->list, rdataset, link);
   1895   1.1  christos 		trdataset = rdataset;
   1896   1.1  christos 		rdataset = NULL;
   1897   1.3  christos 		added_something = true;
   1898   1.1  christos 		/*
   1899   1.1  christos 		 * Note: we only add SIGs if we've added the type they cover,
   1900   1.1  christos 		 * so we do not need to check if the SIG rdataset is already
   1901   1.1  christos 		 * in the response.
   1902   1.1  christos 		 */
   1903   1.1  christos 		if (sigrdataset != NULL &&
   1904  1.16  christos 		    dns_rdataset_isassociated(sigrdataset))
   1905  1.16  christos 		{
   1906   1.1  christos 			ISC_LIST_APPEND(fname->list, sigrdataset, link);
   1907   1.1  christos 			sigrdataset = NULL;
   1908   1.1  christos 		}
   1909   1.1  christos 	}
   1910   1.1  christos 
   1911   1.1  christos 	if (qtype == dns_rdatatype_a) {
   1912   1.1  christos 		/*
   1913   1.1  christos 		 * We now go looking for A and AAAA records, along with
   1914   1.1  christos 		 * their signatures.
   1915   1.1  christos 		 *
   1916   1.1  christos 		 * XXXRTH  This code could be more efficient.
   1917   1.1  christos 		 */
   1918   1.1  christos 		if (rdataset != NULL) {
   1919   1.3  christos 			if (dns_rdataset_isassociated(rdataset)) {
   1920   1.1  christos 				dns_rdataset_disassociate(rdataset);
   1921   1.3  christos 			}
   1922   1.1  christos 		} else {
   1923   1.3  christos 			rdataset = ns_client_newrdataset(client);
   1924   1.3  christos 			if (rdataset == NULL) {
   1925   1.1  christos 				goto addname;
   1926   1.3  christos 			}
   1927   1.1  christos 		}
   1928   1.1  christos 		if (sigrdataset != NULL) {
   1929   1.3  christos 			if (dns_rdataset_isassociated(sigrdataset)) {
   1930   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   1931   1.3  christos 			}
   1932   1.1  christos 		} else if (WANTDNSSEC(client)) {
   1933   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   1934   1.3  christos 			if (sigrdataset == NULL) {
   1935   1.1  christos 				goto addname;
   1936   1.3  christos 			}
   1937   1.1  christos 		}
   1938   1.3  christos 		if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) {
   1939   1.1  christos 			goto aaaa_lookup;
   1940   1.3  christos 		}
   1941   1.9  christos 		result = dns_db_findrdataset(db, node, version, dns_rdatatype_a,
   1942   1.9  christos 					     0, client->now, rdataset,
   1943   1.9  christos 					     sigrdataset);
   1944   1.1  christos 		if (result == DNS_R_NCACHENXDOMAIN) {
   1945   1.1  christos 			goto addname;
   1946   1.1  christos 		} else if (result == DNS_R_NCACHENXRRSET) {
   1947   1.1  christos 			dns_rdataset_disassociate(rdataset);
   1948   1.1  christos 			if (sigrdataset != NULL &&
   1949  1.16  christos 			    dns_rdataset_isassociated(sigrdataset))
   1950  1.16  christos 			{
   1951   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   1952   1.3  christos 			}
   1953   1.1  christos 		} else if (result == ISC_R_SUCCESS) {
   1954   1.3  christos 			bool invalid = false;
   1955   1.1  christos 			mname = NULL;
   1956   1.1  christos 			if (additionaltype ==
   1957   1.9  christos 				    dns_rdatasetadditional_fromcache &&
   1958   1.1  christos 			    (DNS_TRUST_PENDING(rdataset->trust) ||
   1959   1.1  christos 			     DNS_TRUST_GLUE(rdataset->trust)))
   1960   1.1  christos 			{
   1961   1.1  christos 				/* validate() may change rdataset->trust */
   1962   1.9  christos 				invalid = !validate(client, db, fname, rdataset,
   1963   1.9  christos 						    sigrdataset);
   1964   1.1  christos 			}
   1965   1.1  christos 			if (invalid && DNS_TRUST_PENDING(rdataset->trust)) {
   1966   1.1  christos 				dns_rdataset_disassociate(rdataset);
   1967   1.1  christos 				if (sigrdataset != NULL &&
   1968  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   1969  1.16  christos 				{
   1970   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   1971   1.3  christos 				}
   1972   1.1  christos 			} else if (!query_isduplicate(client, fname,
   1973   1.9  christos 						      dns_rdatatype_a, &mname))
   1974   1.9  christos 			{
   1975   1.1  christos 				if (mname != fname) {
   1976   1.1  christos 					if (mname != NULL) {
   1977   1.3  christos 						ns_client_releasename(client,
   1978   1.3  christos 								      &fname);
   1979   1.1  christos 						fname = mname;
   1980   1.3  christos 					} else {
   1981   1.3  christos 						need_addname = true;
   1982   1.3  christos 					}
   1983   1.1  christos 				}
   1984   1.1  christos 				ISC_LIST_APPEND(fname->list, rdataset, link);
   1985   1.3  christos 				added_something = true;
   1986   1.1  christos 				if (sigrdataset != NULL &&
   1987  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   1988  1.16  christos 				{
   1989   1.1  christos 					ISC_LIST_APPEND(fname->list,
   1990   1.1  christos 							sigrdataset, link);
   1991   1.1  christos 					sigrdataset =
   1992   1.3  christos 						ns_client_newrdataset(client);
   1993   1.1  christos 				}
   1994   1.3  christos 				rdataset = ns_client_newrdataset(client);
   1995   1.3  christos 				if (rdataset == NULL) {
   1996   1.1  christos 					goto addname;
   1997   1.3  christos 				}
   1998   1.3  christos 				if (WANTDNSSEC(client) && sigrdataset == NULL) {
   1999   1.1  christos 					goto addname;
   2000   1.3  christos 				}
   2001   1.1  christos 			} else {
   2002   1.1  christos 				dns_rdataset_disassociate(rdataset);
   2003   1.1  christos 				if (sigrdataset != NULL &&
   2004  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2005  1.16  christos 				{
   2006   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   2007   1.3  christos 				}
   2008   1.1  christos 			}
   2009   1.1  christos 		}
   2010   1.9  christos 	aaaa_lookup:
   2011   1.1  christos 		if (query_isduplicate(client, fname, dns_rdatatype_aaaa, NULL))
   2012   1.3  christos 		{
   2013   1.1  christos 			goto addname;
   2014   1.3  christos 		}
   2015   1.1  christos 		result = dns_db_findrdataset(db, node, version,
   2016   1.9  christos 					     dns_rdatatype_aaaa, 0, client->now,
   2017   1.1  christos 					     rdataset, sigrdataset);
   2018   1.1  christos 		if (result == DNS_R_NCACHENXDOMAIN) {
   2019   1.1  christos 			goto addname;
   2020   1.1  christos 		} else if (result == DNS_R_NCACHENXRRSET) {
   2021   1.1  christos 			dns_rdataset_disassociate(rdataset);
   2022   1.1  christos 			if (sigrdataset != NULL &&
   2023  1.16  christos 			    dns_rdataset_isassociated(sigrdataset))
   2024  1.16  christos 			{
   2025   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   2026   1.3  christos 			}
   2027   1.1  christos 		} else if (result == ISC_R_SUCCESS) {
   2028   1.3  christos 			bool invalid = false;
   2029   1.1  christos 			mname = NULL;
   2030   1.3  christos 
   2031   1.1  christos 			if (additionaltype ==
   2032   1.9  christos 				    dns_rdatasetadditional_fromcache &&
   2033   1.1  christos 			    (DNS_TRUST_PENDING(rdataset->trust) ||
   2034   1.1  christos 			     DNS_TRUST_GLUE(rdataset->trust)))
   2035   1.1  christos 			{
   2036   1.1  christos 				/* validate() may change rdataset->trust */
   2037   1.9  christos 				invalid = !validate(client, db, fname, rdataset,
   2038   1.9  christos 						    sigrdataset);
   2039   1.1  christos 			}
   2040   1.1  christos 
   2041   1.1  christos 			if (invalid && DNS_TRUST_PENDING(rdataset->trust)) {
   2042   1.1  christos 				dns_rdataset_disassociate(rdataset);
   2043   1.1  christos 				if (sigrdataset != NULL &&
   2044  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2045  1.16  christos 				{
   2046   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   2047   1.3  christos 				}
   2048   1.1  christos 			} else if (!query_isduplicate(client, fname,
   2049   1.9  christos 						      dns_rdatatype_aaaa,
   2050  1.16  christos 						      &mname))
   2051  1.16  christos 			{
   2052   1.1  christos 				if (mname != fname) {
   2053   1.1  christos 					if (mname != NULL) {
   2054   1.3  christos 						ns_client_releasename(client,
   2055   1.3  christos 								      &fname);
   2056   1.1  christos 						fname = mname;
   2057   1.3  christos 					} else {
   2058   1.3  christos 						need_addname = true;
   2059   1.3  christos 					}
   2060   1.1  christos 				}
   2061   1.1  christos 				ISC_LIST_APPEND(fname->list, rdataset, link);
   2062   1.3  christos 				added_something = true;
   2063   1.1  christos 				if (sigrdataset != NULL &&
   2064  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2065  1.16  christos 				{
   2066   1.1  christos 					ISC_LIST_APPEND(fname->list,
   2067   1.1  christos 							sigrdataset, link);
   2068   1.1  christos 					sigrdataset = NULL;
   2069   1.1  christos 				}
   2070   1.1  christos 				rdataset = NULL;
   2071   1.1  christos 			}
   2072   1.1  christos 		}
   2073   1.1  christos 	}
   2074   1.1  christos 
   2075   1.9  christos addname:
   2076   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: addname");
   2077   1.1  christos 	/*
   2078   1.1  christos 	 * If we haven't added anything, then we're done.
   2079   1.1  christos 	 */
   2080   1.3  christos 	if (!added_something) {
   2081   1.1  christos 		goto cleanup;
   2082   1.3  christos 	}
   2083   1.1  christos 
   2084   1.1  christos 	/*
   2085   1.1  christos 	 * We may have added our rdatasets to an existing name, if so, then
   2086   1.3  christos 	 * need_addname will be false.  Whether we used an existing name
   2087   1.1  christos 	 * or a new one, we must set fname to NULL to prevent cleanup.
   2088   1.1  christos 	 */
   2089   1.3  christos 	if (need_addname) {
   2090   1.1  christos 		dns_message_addname(client->message, fname,
   2091   1.1  christos 				    DNS_SECTION_ADDITIONAL);
   2092   1.3  christos 	}
   2093   1.1  christos 
   2094   1.1  christos 	/*
   2095  1.15  christos 	 * In some cases, a record that has been added as additional
   2096  1.15  christos 	 * data may *also* trigger the addition of additional data.
   2097  1.22  christos 	 * This cannot go more than 'max-restarts' levels deep.
   2098  1.15  christos 	 */
   2099  1.15  christos 	if (trdataset != NULL && dns_rdatatype_followadditional(type)) {
   2100  1.22  christos 		if (client->additionaldepth++ < client->view->max_restarts) {
   2101  1.20  christos 			eresult = dns_rdataset_additionaldata(
   2102  1.20  christos 				trdataset, fname, query_additional_cb, qctx);
   2103  1.20  christos 		}
   2104  1.20  christos 		client->additionaldepth--;
   2105   1.1  christos 	}
   2106   1.1  christos 
   2107  1.20  christos 	/*
   2108  1.20  christos 	 * Don't release fname.
   2109  1.20  christos 	 */
   2110  1.20  christos 	fname = NULL;
   2111  1.20  christos 
   2112   1.9  christos cleanup:
   2113   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup");
   2114   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   2115   1.3  christos 	if (sigrdataset != NULL) {
   2116   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   2117   1.3  christos 	}
   2118   1.3  christos 	if (fname != NULL) {
   2119   1.3  christos 		ns_client_releasename(client, &fname);
   2120   1.3  christos 	}
   2121   1.3  christos 	if (node != NULL) {
   2122   1.1  christos 		dns_db_detachnode(db, &node);
   2123   1.3  christos 	}
   2124   1.3  christos 	if (db != NULL) {
   2125   1.1  christos 		dns_db_detach(&db);
   2126   1.3  christos 	}
   2127   1.1  christos 
   2128   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: done");
   2129   1.1  christos 	return (eresult);
   2130   1.1  christos }
   2131   1.1  christos 
   2132   1.3  christos /*
   2133   1.3  christos  * Add 'rdataset' to 'name'.
   2134   1.3  christos  */
   2135  1.15  christos static void
   2136   1.3  christos query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) {
   2137   1.3  christos 	ISC_LIST_APPEND(name->list, rdataset, link);
   2138   1.3  christos }
   2139   1.3  christos 
   2140   1.3  christos /*
   2141   1.3  christos  * Set the ordering for 'rdataset'.
   2142   1.3  christos  */
   2143   1.1  christos static void
   2144   1.3  christos query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) {
   2145   1.3  christos 	ns_client_t *client = qctx->client;
   2146   1.3  christos 	dns_order_t *order = client->view->order;
   2147   1.1  christos 
   2148   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_setorder");
   2149   1.1  christos 
   2150   1.3  christos 	UNUSED(client);
   2151   1.1  christos 
   2152   1.3  christos 	if (order != NULL) {
   2153   1.9  christos 		rdataset->attributes |= dns_order_find(
   2154   1.9  christos 			order, name, rdataset->type, rdataset->rdclass);
   2155   1.3  christos 	}
   2156   1.1  christos 	rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
   2157   1.9  christos }
   2158   1.3  christos 
   2159   1.3  christos /*
   2160   1.3  christos  * Handle glue and fetch any other needed additional data for 'rdataset'.
   2161   1.3  christos  */
   2162   1.3  christos static void
   2163  1.20  christos query_additional(query_ctx_t *qctx, dns_name_t *name,
   2164  1.20  christos 		 dns_rdataset_t *rdataset) {
   2165   1.3  christos 	ns_client_t *client = qctx->client;
   2166   1.3  christos 	isc_result_t result;
   2167   1.3  christos 
   2168   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional");
   2169   1.1  christos 
   2170   1.3  christos 	if (NOADDITIONAL(client)) {
   2171   1.1  christos 		return;
   2172   1.3  christos 	}
   2173   1.1  christos 
   2174   1.1  christos 	/*
   2175   1.1  christos 	 * Try to process glue directly.
   2176   1.1  christos 	 */
   2177   1.3  christos 	if (qctx->view->use_glue_cache &&
   2178   1.1  christos 	    (rdataset->type == dns_rdatatype_ns) &&
   2179   1.1  christos 	    (client->query.gluedb != NULL) &&
   2180   1.1  christos 	    dns_db_iszone(client->query.gluedb))
   2181   1.1  christos 	{
   2182   1.1  christos 		ns_dbversion_t *dbversion;
   2183   1.1  christos 
   2184   1.3  christos 		dbversion = ns_client_findversion(client, client->query.gluedb);
   2185   1.3  christos 		if (dbversion == NULL) {
   2186   1.1  christos 			goto regular;
   2187   1.1  christos 		}
   2188   1.1  christos 
   2189   1.1  christos 		result = dns_rdataset_addglue(rdataset, dbversion->version,
   2190   1.3  christos 					      client->message);
   2191   1.3  christos 		if (result == ISC_R_SUCCESS) {
   2192   1.1  christos 			return;
   2193   1.3  christos 		}
   2194   1.1  christos 	}
   2195   1.1  christos 
   2196   1.9  christos regular:
   2197   1.1  christos 	/*
   2198   1.3  christos 	 * Add other additional data if needed.
   2199   1.1  christos 	 * We don't care if dns_rdataset_additionaldata() fails.
   2200   1.1  christos 	 */
   2201  1.20  christos 	(void)dns_rdataset_additionaldata(rdataset, name, query_additional_cb,
   2202  1.20  christos 					  qctx);
   2203   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional: done");
   2204   1.1  christos }
   2205   1.1  christos 
   2206   1.1  christos static void
   2207   1.3  christos query_addrrset(query_ctx_t *qctx, dns_name_t **namep,
   2208   1.1  christos 	       dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,
   2209   1.9  christos 	       isc_buffer_t *dbuf, dns_section_t section) {
   2210   1.3  christos 	isc_result_t result;
   2211   1.3  christos 	ns_client_t *client = qctx->client;
   2212   1.1  christos 	dns_name_t *name = *namep, *mname = NULL;
   2213   1.1  christos 	dns_rdataset_t *rdataset = *rdatasetp, *mrdataset = NULL;
   2214   1.1  christos 	dns_rdataset_t *sigrdataset = NULL;
   2215   1.1  christos 
   2216   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addrrset");
   2217   1.1  christos 
   2218   1.3  christos 	REQUIRE(name != NULL);
   2219   1.3  christos 
   2220   1.3  christos 	if (sigrdatasetp != NULL) {
   2221   1.1  christos 		sigrdataset = *sigrdatasetp;
   2222   1.3  christos 	}
   2223   1.1  christos 
   2224   1.1  christos 	/*%
   2225   1.1  christos 	 * To the current response for 'client', add the answer RRset
   2226   1.1  christos 	 * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
   2227   1.1  christos 	 * owner name '*namep', to section 'section', unless they are
   2228   1.1  christos 	 * already there.  Also add any pertinent additional data.
   2229   1.1  christos 	 *
   2230   1.1  christos 	 * If 'dbuf' is not NULL, then '*namep' is the name whose data is
   2231   1.1  christos 	 * stored in 'dbuf'.  In this case, query_addrrset() guarantees that
   2232   1.1  christos 	 * when it returns the name will either have been kept or released.
   2233   1.1  christos 	 */
   2234   1.9  christos 	result = dns_message_findname(client->message, section, name,
   2235   1.9  christos 				      rdataset->type, rdataset->covers, &mname,
   2236   1.9  christos 				      &mrdataset);
   2237   1.1  christos 	if (result == ISC_R_SUCCESS) {
   2238   1.1  christos 		/*
   2239   1.1  christos 		 * We've already got an RRset of the given name and type.
   2240   1.1  christos 		 */
   2241   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: dns_message_findname "
   2242   1.9  christos 					 "succeeded: done");
   2243   1.3  christos 		if (dbuf != NULL) {
   2244   1.3  christos 			ns_client_releasename(client, namep);
   2245   1.3  christos 		}
   2246   1.3  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) {
   2247   1.1  christos 			mrdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   2248   1.3  christos 		}
   2249  1.13  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_STALE_ADDED) != 0)
   2250  1.13  christos 		{
   2251  1.13  christos 			mrdataset->attributes |= DNS_RDATASETATTR_STALE_ADDED;
   2252  1.13  christos 		}
   2253   1.1  christos 		return;
   2254   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   2255   1.1  christos 		/*
   2256   1.1  christos 		 * The name doesn't exist.
   2257   1.1  christos 		 */
   2258   1.3  christos 		if (dbuf != NULL) {
   2259   1.3  christos 			ns_client_keepname(client, name, dbuf);
   2260   1.3  christos 		}
   2261   1.1  christos 		dns_message_addname(client->message, name, section);
   2262   1.1  christos 		*namep = NULL;
   2263   1.1  christos 		mname = name;
   2264   1.1  christos 	} else {
   2265   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   2266   1.3  christos 		if (dbuf != NULL) {
   2267   1.3  christos 			ns_client_releasename(client, namep);
   2268   1.3  christos 		}
   2269   1.1  christos 	}
   2270   1.1  christos 
   2271   1.1  christos 	if (rdataset->trust != dns_trust_secure &&
   2272   1.9  christos 	    (section == DNS_SECTION_ANSWER || section == DNS_SECTION_AUTHORITY))
   2273   1.3  christos 	{
   2274   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   2275   1.3  christos 	}
   2276   1.3  christos 
   2277   1.3  christos 	/*
   2278   1.3  christos 	 * Update message name, set rdataset order, and do additional
   2279   1.3  christos 	 * section processing if needed.
   2280   1.3  christos 	 */
   2281   1.3  christos 	query_addtoname(mname, rdataset);
   2282   1.3  christos 	query_setorder(qctx, mname, rdataset);
   2283  1.20  christos 	query_additional(qctx, mname, rdataset);
   2284   1.1  christos 
   2285   1.1  christos 	/*
   2286   1.1  christos 	 * Note: we only add SIGs if we've added the type they cover, so
   2287   1.1  christos 	 * we do not need to check if the SIG rdataset is already in the
   2288   1.1  christos 	 * response.
   2289   1.1  christos 	 */
   2290   1.1  christos 	*rdatasetp = NULL;
   2291   1.1  christos 	if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
   2292   1.1  christos 		/*
   2293   1.1  christos 		 * We have a signature.  Add it to the response.
   2294   1.1  christos 		 */
   2295   1.1  christos 		ISC_LIST_APPEND(mname->list, sigrdataset, link);
   2296   1.1  christos 		*sigrdatasetp = NULL;
   2297   1.1  christos 	}
   2298   1.1  christos 
   2299   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: done");
   2300   1.1  christos }
   2301   1.1  christos 
   2302   1.1  christos /*
   2303   1.1  christos  * Mark the RRsets as secure.  Update the cache (db) to reflect the
   2304   1.1  christos  * change in trust level.
   2305   1.1  christos  */
   2306   1.1  christos static void
   2307   1.1  christos mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
   2308   1.1  christos 	    dns_rdata_rrsig_t *rrsig, dns_rdataset_t *rdataset,
   2309   1.9  christos 	    dns_rdataset_t *sigrdataset) {
   2310   1.1  christos 	isc_result_t result;
   2311   1.1  christos 	dns_dbnode_t *node = NULL;
   2312   1.1  christos 	dns_clientinfomethods_t cm;
   2313   1.1  christos 	dns_clientinfo_t ci;
   2314   1.1  christos 	isc_stdtime_t now;
   2315   1.1  christos 
   2316   1.1  christos 	rdataset->trust = dns_trust_secure;
   2317   1.1  christos 	sigrdataset->trust = dns_trust_secure;
   2318   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2319  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   2320   1.1  christos 
   2321   1.1  christos 	/*
   2322   1.1  christos 	 * Save the updated secure state.  Ignore failures.
   2323   1.1  christos 	 */
   2324   1.3  christos 	result = dns_db_findnodeext(db, name, true, &cm, &ci, &node);
   2325   1.9  christos 	if (result != ISC_R_SUCCESS) {
   2326   1.1  christos 		return;
   2327   1.9  christos 	}
   2328   1.1  christos 
   2329   1.1  christos 	isc_stdtime_get(&now);
   2330   1.1  christos 	dns_rdataset_trimttl(rdataset, sigrdataset, rrsig, now,
   2331   1.1  christos 			     client->view->acceptexpired);
   2332   1.1  christos 
   2333   1.9  christos 	(void)dns_db_addrdataset(db, node, NULL, client->now, rdataset, 0,
   2334   1.9  christos 				 NULL);
   2335   1.9  christos 	(void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset, 0,
   2336   1.9  christos 				 NULL);
   2337   1.1  christos 	dns_db_detachnode(db, &node);
   2338   1.1  christos }
   2339   1.1  christos 
   2340   1.1  christos /*
   2341   1.1  christos  * Find the secure key that corresponds to rrsig.
   2342   1.1  christos  * Note: 'keyrdataset' maintains state between successive calls,
   2343   1.1  christos  * there may be multiple keys with the same keyid.
   2344   1.3  christos  * Return false if we have exhausted all the possible keys.
   2345   1.1  christos  */
   2346   1.3  christos static bool
   2347   1.1  christos get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
   2348   1.9  christos 	dns_rdataset_t *keyrdataset, dst_key_t **keyp) {
   2349   1.1  christos 	isc_result_t result;
   2350   1.1  christos 	dns_dbnode_t *node = NULL;
   2351   1.3  christos 	bool secure = false;
   2352   1.1  christos 	dns_clientinfomethods_t cm;
   2353   1.1  christos 	dns_clientinfo_t ci;
   2354   1.1  christos 
   2355   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2356  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   2357   1.1  christos 
   2358   1.1  christos 	if (!dns_rdataset_isassociated(keyrdataset)) {
   2359   1.9  christos 		result = dns_db_findnodeext(db, &rrsig->signer, false, &cm, &ci,
   2360   1.9  christos 					    &node);
   2361   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2362   1.3  christos 			return (false);
   2363   1.9  christos 		}
   2364   1.1  christos 
   2365   1.1  christos 		result = dns_db_findrdataset(db, node, NULL,
   2366   1.1  christos 					     dns_rdatatype_dnskey, 0,
   2367   1.1  christos 					     client->now, keyrdataset, NULL);
   2368   1.1  christos 		dns_db_detachnode(db, &node);
   2369   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2370   1.3  christos 			return (false);
   2371   1.9  christos 		}
   2372   1.1  christos 
   2373   1.9  christos 		if (keyrdataset->trust != dns_trust_secure) {
   2374   1.3  christos 			return (false);
   2375   1.9  christos 		}
   2376   1.1  christos 
   2377   1.1  christos 		result = dns_rdataset_first(keyrdataset);
   2378   1.9  christos 	} else {
   2379   1.1  christos 		result = dns_rdataset_next(keyrdataset);
   2380   1.9  christos 	}
   2381   1.1  christos 
   2382   1.9  christos 	for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(keyrdataset))
   2383   1.9  christos 	{
   2384   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   2385   1.1  christos 		isc_buffer_t b;
   2386   1.1  christos 
   2387   1.1  christos 		dns_rdataset_current(keyrdataset, &rdata);
   2388   1.1  christos 		isc_buffer_init(&b, rdata.data, rdata.length);
   2389   1.1  christos 		isc_buffer_add(&b, rdata.length);
   2390   1.1  christos 		result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
   2391   1.1  christos 					 client->mctx, keyp);
   2392   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2393   1.1  christos 			continue;
   2394   1.9  christos 		}
   2395   1.1  christos 		if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
   2396   1.1  christos 		    rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
   2397   1.9  christos 		    dst_key_iszonekey(*keyp))
   2398   1.9  christos 		{
   2399   1.3  christos 			secure = true;
   2400   1.1  christos 			break;
   2401   1.1  christos 		}
   2402   1.1  christos 		dst_key_free(keyp);
   2403   1.1  christos 	}
   2404   1.1  christos 	return (secure);
   2405   1.1  christos }
   2406   1.1  christos 
   2407   1.3  christos static bool
   2408   1.1  christos verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset,
   2409   1.9  christos        dns_rdata_t *rdata, ns_client_t *client) {
   2410   1.1  christos 	isc_result_t result;
   2411   1.1  christos 	dns_fixedname_t fixed;
   2412   1.3  christos 	bool ignore = false;
   2413   1.1  christos 
   2414   1.1  christos 	dns_fixedname_init(&fixed);
   2415   1.1  christos 
   2416   1.1  christos again:
   2417   1.3  christos 	result = dns_dnssec_verify(name, rdataset, key, ignore,
   2418   1.9  christos 				   client->view->maxbits, client->mctx, rdata,
   2419   1.9  christos 				   NULL);
   2420   1.1  christos 	if (result == DNS_R_SIGEXPIRED && client->view->acceptexpired) {
   2421   1.3  christos 		ignore = true;
   2422   1.1  christos 		goto again;
   2423   1.1  christos 	}
   2424   1.9  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
   2425   1.3  christos 		return (true);
   2426   1.9  christos 	}
   2427   1.3  christos 	return (false);
   2428   1.1  christos }
   2429   1.1  christos 
   2430   1.1  christos /*
   2431   1.1  christos  * Validate the rdataset if possible with available records.
   2432   1.1  christos  */
   2433   1.3  christos static bool
   2434   1.1  christos validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
   2435   1.9  christos 	 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
   2436   1.1  christos 	isc_result_t result;
   2437   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2438   1.1  christos 	dns_rdata_rrsig_t rrsig;
   2439   1.1  christos 	dst_key_t *key = NULL;
   2440   1.1  christos 	dns_rdataset_t keyrdataset;
   2441   1.1  christos 
   2442   1.9  christos 	if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)) {
   2443   1.3  christos 		return (false);
   2444   1.9  christos 	}
   2445   1.1  christos 
   2446   1.9  christos 	for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
   2447   1.9  christos 	     result = dns_rdataset_next(sigrdataset))
   2448   1.9  christos 	{
   2449   1.1  christos 		dns_rdata_reset(&rdata);
   2450   1.1  christos 		dns_rdataset_current(sigrdataset, &rdata);
   2451   1.1  christos 		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
   2452   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2453   1.1  christos 		if (!dns_resolver_algorithm_supported(client->view->resolver,
   2454   1.1  christos 						      name, rrsig.algorithm))
   2455   1.9  christos 		{
   2456   1.1  christos 			continue;
   2457   1.9  christos 		}
   2458   1.9  christos 		if (!dns_name_issubdomain(name, &rrsig.signer)) {
   2459   1.1  christos 			continue;
   2460   1.9  christos 		}
   2461   1.1  christos 		dns_rdataset_init(&keyrdataset);
   2462   1.1  christos 		do {
   2463   1.9  christos 			if (!get_key(client, db, &rrsig, &keyrdataset, &key)) {
   2464   1.1  christos 				break;
   2465   1.9  christos 			}
   2466   1.1  christos 			if (verify(key, name, rdataset, &rdata, client)) {
   2467   1.1  christos 				dst_key_free(&key);
   2468   1.1  christos 				dns_rdataset_disassociate(&keyrdataset);
   2469   1.9  christos 				mark_secure(client, db, name, &rrsig, rdataset,
   2470   1.9  christos 					    sigrdataset);
   2471   1.3  christos 				return (true);
   2472   1.1  christos 			}
   2473   1.1  christos 			dst_key_free(&key);
   2474   1.1  christos 		} while (1);
   2475   1.9  christos 		if (dns_rdataset_isassociated(&keyrdataset)) {
   2476   1.1  christos 			dns_rdataset_disassociate(&keyrdataset);
   2477   1.9  christos 		}
   2478   1.1  christos 	}
   2479   1.3  christos 	return (false);
   2480   1.1  christos }
   2481   1.1  christos 
   2482   1.1  christos static void
   2483   1.1  christos fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) {
   2484   1.9  christos 	if (*rdataset == NULL) {
   2485   1.3  christos 		*rdataset = ns_client_newrdataset(client);
   2486   1.9  christos 	} else if (dns_rdataset_isassociated(*rdataset)) {
   2487   1.1  christos 		dns_rdataset_disassociate(*rdataset);
   2488   1.9  christos 	}
   2489   1.1  christos }
   2490   1.1  christos 
   2491   1.1  christos static void
   2492   1.1  christos fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf,
   2493   1.9  christos 	 isc_buffer_t *nbuf) {
   2494   1.1  christos 	if (*fname == NULL) {
   2495   1.3  christos 		*dbuf = ns_client_getnamebuf(client);
   2496   1.9  christos 		if (*dbuf == NULL) {
   2497   1.1  christos 			return;
   2498   1.9  christos 		}
   2499   1.3  christos 		*fname = ns_client_newname(client, *dbuf, nbuf);
   2500   1.1  christos 	}
   2501   1.1  christos }
   2502   1.1  christos 
   2503   1.1  christos static void
   2504   1.1  christos free_devent(ns_client_t *client, isc_event_t **eventp,
   2505   1.9  christos 	    dns_fetchevent_t **deventp) {
   2506   1.1  christos 	dns_fetchevent_t *devent = *deventp;
   2507   1.1  christos 
   2508   1.9  christos 	REQUIRE((void *)(*eventp) == (void *)(*deventp));
   2509   1.9  christos 
   2510   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "free_devent");
   2511   1.1  christos 
   2512   1.3  christos 	if (devent->fetch != NULL) {
   2513   1.1  christos 		dns_resolver_destroyfetch(&devent->fetch);
   2514   1.3  christos 	}
   2515   1.3  christos 	if (devent->node != NULL) {
   2516   1.1  christos 		dns_db_detachnode(devent->db, &devent->node);
   2517   1.3  christos 	}
   2518   1.3  christos 	if (devent->db != NULL) {
   2519   1.1  christos 		dns_db_detach(&devent->db);
   2520   1.3  christos 	}
   2521   1.3  christos 	if (devent->rdataset != NULL) {
   2522   1.3  christos 		ns_client_putrdataset(client, &devent->rdataset);
   2523   1.3  christos 	}
   2524   1.3  christos 	if (devent->sigrdataset != NULL) {
   2525   1.3  christos 		ns_client_putrdataset(client, &devent->sigrdataset);
   2526   1.3  christos 	}
   2527   1.9  christos 
   2528   1.1  christos 	/*
   2529   1.1  christos 	 * If the two pointers are the same then leave the setting of
   2530   1.1  christos 	 * (*deventp) to NULL to isc_event_free.
   2531   1.1  christos 	 */
   2532   1.9  christos 	if ((void *)eventp != (void *)deventp) {
   2533   1.1  christos 		(*deventp) = NULL;
   2534   1.9  christos 	}
   2535   1.1  christos 	isc_event_free(eventp);
   2536   1.1  christos }
   2537   1.1  christos 
   2538   1.1  christos static void
   2539   1.1  christos prefetch_done(isc_task_t *task, isc_event_t *event) {
   2540   1.1  christos 	dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
   2541   1.1  christos 	ns_client_t *client;
   2542   1.1  christos 
   2543   1.1  christos 	UNUSED(task);
   2544   1.1  christos 
   2545   1.1  christos 	REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
   2546   1.1  christos 	client = devent->ev_arg;
   2547   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   2548   1.1  christos 	REQUIRE(task == client->task);
   2549   1.1  christos 
   2550   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "prefetch_done");
   2551   1.9  christos 
   2552   1.1  christos 	LOCK(&client->query.fetchlock);
   2553   1.1  christos 	if (client->query.prefetch != NULL) {
   2554   1.1  christos 		INSIST(devent->fetch == client->query.prefetch);
   2555   1.1  christos 		client->query.prefetch = NULL;
   2556   1.1  christos 	}
   2557   1.1  christos 	UNLOCK(&client->query.fetchlock);
   2558   1.9  christos 
   2559   1.9  christos 	/*
   2560   1.9  christos 	 * We're done prefetching, detach from quota.
   2561   1.9  christos 	 */
   2562   1.9  christos 	if (client->recursionquota != NULL) {
   2563   1.9  christos 		isc_quota_detach(&client->recursionquota);
   2564  1.16  christos 		ns_stats_decrement(client->sctx->nsstats,
   2565  1.16  christos 				   ns_statscounter_recursclients);
   2566   1.9  christos 	}
   2567   1.9  christos 
   2568   1.1  christos 	free_devent(client, &event, &devent);
   2569  1.11  christos 	isc_nmhandle_detach(&client->prefetchhandle);
   2570   1.1  christos }
   2571   1.1  christos 
   2572   1.1  christos static void
   2573   1.1  christos query_prefetch(ns_client_t *client, dns_name_t *qname,
   2574   1.9  christos 	       dns_rdataset_t *rdataset) {
   2575   1.1  christos 	isc_result_t result;
   2576   1.1  christos 	isc_sockaddr_t *peeraddr;
   2577   1.1  christos 	dns_rdataset_t *tmprdataset;
   2578   1.1  christos 	unsigned int options;
   2579   1.1  christos 
   2580   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_prefetch");
   2581   1.9  christos 
   2582   1.1  christos 	if (client->query.prefetch != NULL ||
   2583   1.1  christos 	    client->view->prefetch_trigger == 0U ||
   2584   1.1  christos 	    rdataset->ttl > client->view->prefetch_trigger ||
   2585   1.1  christos 	    (rdataset->attributes & DNS_RDATASETATTR_PREFETCH) == 0)
   2586   1.9  christos 	{
   2587   1.1  christos 		return;
   2588   1.9  christos 	}
   2589   1.1  christos 
   2590   1.1  christos 	if (client->recursionquota == NULL) {
   2591   1.1  christos 		result = isc_quota_attach(&client->sctx->recursionquota,
   2592   1.1  christos 					  &client->recursionquota);
   2593  1.15  christos 		switch (result) {
   2594  1.15  christos 		case ISC_R_SUCCESS:
   2595  1.16  christos 			ns_stats_increment(client->sctx->nsstats,
   2596  1.16  christos 					   ns_statscounter_recursclients);
   2597  1.15  christos 			break;
   2598  1.15  christos 		case ISC_R_SOFTQUOTA:
   2599   1.9  christos 			isc_quota_detach(&client->recursionquota);
   2600  1.15  christos 			FALLTHROUGH;
   2601  1.15  christos 		default:
   2602   1.1  christos 			return;
   2603   1.6  christos 		}
   2604   1.1  christos 	}
   2605   1.1  christos 
   2606   1.3  christos 	tmprdataset = ns_client_newrdataset(client);
   2607   1.9  christos 	if (tmprdataset == NULL) {
   2608   1.1  christos 		return;
   2609   1.9  christos 	}
   2610   1.9  christos 
   2611   1.9  christos 	if (!TCP(client)) {
   2612   1.1  christos 		peeraddr = &client->peeraddr;
   2613   1.9  christos 	} else {
   2614   1.1  christos 		peeraddr = NULL;
   2615   1.9  christos 	}
   2616   1.9  christos 
   2617  1.11  christos 	isc_nmhandle_attach(client->handle, &client->prefetchhandle);
   2618   1.1  christos 	options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH;
   2619   1.9  christos 	result = dns_resolver_createfetch(
   2620   1.9  christos 		client->view->resolver, qname, rdataset->type, NULL, NULL, NULL,
   2621   1.9  christos 		peeraddr, client->message->id, options, 0, NULL, client->task,
   2622   1.9  christos 		prefetch_done, client, tmprdataset, NULL,
   2623   1.9  christos 		&client->query.prefetch);
   2624   1.1  christos 	if (result != ISC_R_SUCCESS) {
   2625   1.3  christos 		ns_client_putrdataset(client, &tmprdataset);
   2626  1.11  christos 		isc_nmhandle_detach(&client->prefetchhandle);
   2627   1.1  christos 	}
   2628   1.9  christos 
   2629   1.1  christos 	dns_rdataset_clearprefetch(rdataset);
   2630   1.9  christos 	ns_stats_increment(client->sctx->nsstats, ns_statscounter_prefetch);
   2631   1.1  christos }
   2632   1.1  christos 
   2633  1.15  christos static void
   2634   1.1  christos rpz_clean(dns_zone_t **zonep, dns_db_t **dbp, dns_dbnode_t **nodep,
   2635   1.9  christos 	  dns_rdataset_t **rdatasetp) {
   2636   1.1  christos 	if (nodep != NULL && *nodep != NULL) {
   2637   1.1  christos 		REQUIRE(dbp != NULL && *dbp != NULL);
   2638   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   2639   1.1  christos 	}
   2640   1.9  christos 	if (dbp != NULL && *dbp != NULL) {
   2641   1.1  christos 		dns_db_detach(dbp);
   2642   1.9  christos 	}
   2643   1.9  christos 	if (zonep != NULL && *zonep != NULL) {
   2644   1.1  christos 		dns_zone_detach(zonep);
   2645   1.9  christos 	}
   2646   1.1  christos 	if (rdatasetp != NULL && *rdatasetp != NULL &&
   2647   1.1  christos 	    dns_rdataset_isassociated(*rdatasetp))
   2648   1.9  christos 	{
   2649   1.1  christos 		dns_rdataset_disassociate(*rdatasetp);
   2650   1.9  christos 	}
   2651   1.1  christos }
   2652   1.1  christos 
   2653  1.15  christos static void
   2654   1.1  christos rpz_match_clear(dns_rpz_st_t *st) {
   2655   1.1  christos 	rpz_clean(&st->m.zone, &st->m.db, &st->m.node, &st->m.rdataset);
   2656   1.1  christos 	st->m.version = NULL;
   2657   1.1  christos }
   2658   1.1  christos 
   2659  1.15  christos static isc_result_t
   2660   1.1  christos rpz_ready(ns_client_t *client, dns_rdataset_t **rdatasetp) {
   2661   1.1  christos 	REQUIRE(rdatasetp != NULL);
   2662   1.1  christos 
   2663   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_ready");
   2664   1.1  christos 
   2665   1.1  christos 	if (*rdatasetp == NULL) {
   2666   1.3  christos 		*rdatasetp = ns_client_newrdataset(client);
   2667   1.1  christos 		if (*rdatasetp == NULL) {
   2668   1.9  christos 			CTRACE(ISC_LOG_ERROR, "rpz_ready: "
   2669   1.9  christos 					      "ns_client_newrdataset failed");
   2670   1.1  christos 			return (DNS_R_SERVFAIL);
   2671   1.1  christos 		}
   2672   1.1  christos 	} else if (dns_rdataset_isassociated(*rdatasetp)) {
   2673   1.1  christos 		dns_rdataset_disassociate(*rdatasetp);
   2674   1.1  christos 	}
   2675   1.1  christos 	return (ISC_R_SUCCESS);
   2676   1.1  christos }
   2677   1.1  christos 
   2678   1.1  christos static void
   2679   1.1  christos rpz_st_clear(ns_client_t *client) {
   2680   1.1  christos 	dns_rpz_st_t *st = client->query.rpz_st;
   2681   1.1  christos 
   2682   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_st_clear");
   2683   1.1  christos 
   2684   1.1  christos 	if (st->m.rdataset != NULL) {
   2685   1.3  christos 		ns_client_putrdataset(client, &st->m.rdataset);
   2686   1.1  christos 	}
   2687   1.1  christos 	rpz_match_clear(st);
   2688   1.1  christos 
   2689   1.1  christos 	rpz_clean(NULL, &st->r.db, NULL, NULL);
   2690   1.1  christos 	if (st->r.ns_rdataset != NULL) {
   2691   1.3  christos 		ns_client_putrdataset(client, &st->r.ns_rdataset);
   2692   1.1  christos 	}
   2693   1.1  christos 	if (st->r.r_rdataset != NULL) {
   2694   1.3  christos 		ns_client_putrdataset(client, &st->r.r_rdataset);
   2695   1.1  christos 	}
   2696   1.1  christos 
   2697   1.1  christos 	rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL);
   2698   1.1  christos 	if (st->q.rdataset != NULL) {
   2699   1.3  christos 		ns_client_putrdataset(client, &st->q.rdataset);
   2700   1.1  christos 	}
   2701   1.1  christos 	if (st->q.sigrdataset != NULL) {
   2702   1.3  christos 		ns_client_putrdataset(client, &st->q.sigrdataset);
   2703   1.1  christos 	}
   2704   1.1  christos 	st->state = 0;
   2705   1.1  christos 	st->m.type = DNS_RPZ_TYPE_BAD;
   2706   1.1  christos 	st->m.policy = DNS_RPZ_POLICY_MISS;
   2707   1.1  christos 	if (st->rpsdb != NULL) {
   2708   1.1  christos 		dns_db_detach(&st->rpsdb);
   2709   1.1  christos 	}
   2710   1.1  christos }
   2711   1.1  christos 
   2712   1.1  christos static dns_rpz_zbits_t
   2713   1.9  christos rpz_get_zbits(ns_client_t *client, dns_rdatatype_t ip_type,
   2714   1.9  christos 	      dns_rpz_type_t rpz_type) {
   2715   1.1  christos 	dns_rpz_st_t *st;
   2716   1.3  christos 	dns_rpz_zbits_t zbits = 0;
   2717   1.1  christos 
   2718   1.1  christos 	REQUIRE(client != NULL);
   2719   1.1  christos 	REQUIRE(client->query.rpz_st != NULL);
   2720   1.1  christos 
   2721   1.1  christos 	st = client->query.rpz_st;
   2722   1.1  christos 
   2723   1.1  christos #ifdef USE_DNSRPS
   2724   1.1  christos 	if (st->popt.dnsrps_enabled) {
   2725   1.1  christos 		if (st->rpsdb == NULL ||
   2726   1.1  christos 		    librpz->have_trig(dns_dnsrps_type2trig(rpz_type),
   2727   1.1  christos 				      ip_type == dns_rdatatype_aaaa,
   2728   1.1  christos 				      ((rpsdb_t *)st->rpsdb)->rsp))
   2729   1.1  christos 		{
   2730   1.1  christos 			return (DNS_RPZ_ALL_ZBITS);
   2731   1.1  christos 		}
   2732   1.1  christos 		return (0);
   2733   1.1  christos 	}
   2734   1.9  christos #endif /* ifdef USE_DNSRPS */
   2735   1.1  christos 
   2736   1.1  christos 	switch (rpz_type) {
   2737   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   2738   1.1  christos 		zbits = st->have.client_ip;
   2739   1.1  christos 		break;
   2740   1.1  christos 	case DNS_RPZ_TYPE_QNAME:
   2741   1.1  christos 		zbits = st->have.qname;
   2742   1.1  christos 		break;
   2743   1.1  christos 	case DNS_RPZ_TYPE_IP:
   2744   1.1  christos 		if (ip_type == dns_rdatatype_a) {
   2745   1.1  christos 			zbits = st->have.ipv4;
   2746   1.1  christos 		} else if (ip_type == dns_rdatatype_aaaa) {
   2747   1.1  christos 			zbits = st->have.ipv6;
   2748   1.1  christos 		} else {
   2749   1.1  christos 			zbits = st->have.ip;
   2750   1.1  christos 		}
   2751   1.1  christos 		break;
   2752   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   2753   1.1  christos 		zbits = st->have.nsdname;
   2754   1.1  christos 		break;
   2755   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   2756   1.1  christos 		if (ip_type == dns_rdatatype_a) {
   2757   1.1  christos 			zbits = st->have.nsipv4;
   2758   1.1  christos 		} else if (ip_type == dns_rdatatype_aaaa) {
   2759   1.1  christos 			zbits = st->have.nsipv6;
   2760   1.1  christos 		} else {
   2761   1.1  christos 			zbits = st->have.nsip;
   2762   1.1  christos 		}
   2763   1.1  christos 		break;
   2764   1.1  christos 	default:
   2765  1.15  christos 		UNREACHABLE();
   2766   1.1  christos 	}
   2767   1.1  christos 
   2768   1.1  christos 	/*
   2769   1.1  christos 	 * Choose
   2770   1.1  christos 	 *	the earliest configured policy zone (rpz->num)
   2771   1.1  christos 	 *	QNAME over IP over NSDNAME over NSIP (rpz_type)
   2772   1.1  christos 	 *	the smallest name,
   2773   1.1  christos 	 *	the longest IP address prefix,
   2774   1.1  christos 	 *	the lexically smallest address.
   2775   1.1  christos 	 */
   2776   1.1  christos 	if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   2777   1.1  christos 		if (st->m.type >= rpz_type) {
   2778   1.1  christos 			zbits &= DNS_RPZ_ZMASK(st->m.rpz->num);
   2779   1.9  christos 		} else {
   2780   1.1  christos 			zbits &= DNS_RPZ_ZMASK(st->m.rpz->num) >> 1;
   2781   1.1  christos 		}
   2782   1.1  christos 	}
   2783   1.1  christos 
   2784   1.1  christos 	/*
   2785   1.1  christos 	 * If the client wants recursion, allow only compatible policies.
   2786   1.1  christos 	 */
   2787   1.9  christos 	if (!RECURSIONOK(client)) {
   2788   1.1  christos 		zbits &= st->popt.no_rd_ok;
   2789   1.9  christos 	}
   2790   1.1  christos 
   2791   1.1  christos 	return (zbits);
   2792   1.1  christos }
   2793   1.1  christos 
   2794   1.1  christos static void
   2795   1.1  christos query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) {
   2796   1.1  christos 	isc_result_t result;
   2797   1.1  christos 	isc_sockaddr_t *peeraddr;
   2798   1.1  christos 	dns_rdataset_t *tmprdataset;
   2799   1.1  christos 	unsigned int options;
   2800   1.1  christos 
   2801   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_rpzfetch");
   2802   1.9  christos 
   2803   1.9  christos 	if (client->query.prefetch != NULL) {
   2804   1.1  christos 		return;
   2805   1.9  christos 	}
   2806   1.1  christos 
   2807   1.1  christos 	if (client->recursionquota == NULL) {
   2808   1.1  christos 		result = isc_quota_attach(&client->sctx->recursionquota,
   2809   1.1  christos 					  &client->recursionquota);
   2810  1.15  christos 		switch (result) {
   2811  1.15  christos 		case ISC_R_SUCCESS:
   2812  1.16  christos 			ns_stats_increment(client->sctx->nsstats,
   2813  1.16  christos 					   ns_statscounter_recursclients);
   2814  1.15  christos 			break;
   2815  1.15  christos 		case ISC_R_SOFTQUOTA:
   2816   1.9  christos 			isc_quota_detach(&client->recursionquota);
   2817  1.15  christos 			FALLTHROUGH;
   2818  1.15  christos 		default:
   2819   1.1  christos 			return;
   2820   1.6  christos 		}
   2821   1.1  christos 	}
   2822   1.1  christos 
   2823   1.3  christos 	tmprdataset = ns_client_newrdataset(client);
   2824   1.9  christos 	if (tmprdataset == NULL) {
   2825   1.1  christos 		return;
   2826   1.9  christos 	}
   2827   1.9  christos 
   2828   1.9  christos 	if (!TCP(client)) {
   2829   1.1  christos 		peeraddr = &client->peeraddr;
   2830   1.9  christos 	} else {
   2831   1.1  christos 		peeraddr = NULL;
   2832   1.9  christos 	}
   2833   1.9  christos 
   2834   1.1  christos 	options = client->query.fetchoptions;
   2835  1.11  christos 	isc_nmhandle_attach(client->handle, &client->prefetchhandle);
   2836   1.9  christos 	result = dns_resolver_createfetch(
   2837   1.9  christos 		client->view->resolver, qname, type, NULL, NULL, NULL, peeraddr,
   2838   1.9  christos 		client->message->id, options, 0, NULL, client->task,
   2839   1.9  christos 		prefetch_done, client, tmprdataset, NULL,
   2840   1.9  christos 		&client->query.prefetch);
   2841   1.1  christos 	if (result != ISC_R_SUCCESS) {
   2842   1.3  christos 		ns_client_putrdataset(client, &tmprdataset);
   2843  1.11  christos 		isc_nmhandle_detach(&client->prefetchhandle);
   2844   1.1  christos 	}
   2845   1.1  christos }
   2846   1.1  christos 
   2847   1.1  christos /*
   2848   1.1  christos  * Get an NS, A, or AAAA rrset related to the response for the client
   2849   1.1  christos  * to check the contents of that rrset for hits by eligible policy zones.
   2850   1.1  christos  */
   2851   1.1  christos static isc_result_t
   2852   1.1  christos rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
   2853  1.15  christos 	       unsigned int options, dns_rpz_type_t rpz_type, dns_db_t **dbp,
   2854   1.1  christos 	       dns_dbversion_t *version, dns_rdataset_t **rdatasetp,
   2855   1.9  christos 	       bool resuming) {
   2856   1.1  christos 	dns_rpz_st_t *st;
   2857   1.3  christos 	bool is_zone;
   2858   1.1  christos 	dns_dbnode_t *node;
   2859   1.1  christos 	dns_fixedname_t fixed;
   2860   1.1  christos 	dns_name_t *found;
   2861   1.1  christos 	isc_result_t result;
   2862   1.1  christos 	dns_clientinfomethods_t cm;
   2863   1.1  christos 	dns_clientinfo_t ci;
   2864   1.1  christos 
   2865   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rrset_find");
   2866   1.1  christos 
   2867   1.1  christos 	st = client->query.rpz_st;
   2868   1.1  christos 	if ((st->state & DNS_RPZ_RECURSING) != 0) {
   2869   1.1  christos 		INSIST(st->r.r_type == type);
   2870   1.1  christos 		INSIST(dns_name_equal(name, st->r_name));
   2871   1.1  christos 		INSIST(*rdatasetp == NULL ||
   2872   1.1  christos 		       !dns_rdataset_isassociated(*rdatasetp));
   2873   1.1  christos 		st->state &= ~DNS_RPZ_RECURSING;
   2874   1.1  christos 		RESTORE(*dbp, st->r.db);
   2875   1.3  christos 		if (*rdatasetp != NULL) {
   2876   1.3  christos 			ns_client_putrdataset(client, rdatasetp);
   2877   1.3  christos 		}
   2878   1.1  christos 		RESTORE(*rdatasetp, st->r.r_rdataset);
   2879   1.1  christos 		result = st->r.r_result;
   2880   1.1  christos 		if (result == DNS_R_DELEGATION) {
   2881   1.1  christos 			CTRACE(ISC_LOG_ERROR, "RPZ recursing");
   2882   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   2883   1.3  christos 				     rpz_type, "rpz_rrset_find(1)", result);
   2884   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   2885   1.1  christos 			result = DNS_R_SERVFAIL;
   2886   1.1  christos 		}
   2887   1.1  christos 		return (result);
   2888   1.1  christos 	}
   2889   1.1  christos 
   2890   1.1  christos 	result = rpz_ready(client, rdatasetp);
   2891   1.1  christos 	if (result != ISC_R_SUCCESS) {
   2892   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   2893   1.1  christos 		return (result);
   2894   1.1  christos 	}
   2895   1.1  christos 	if (*dbp != NULL) {
   2896   1.3  christos 		is_zone = false;
   2897   1.1  christos 	} else {
   2898   1.1  christos 		dns_zone_t *zone;
   2899   1.1  christos 
   2900   1.1  christos 		version = NULL;
   2901   1.1  christos 		zone = NULL;
   2902   1.1  christos 		result = query_getdb(client, name, type, 0, &zone, dbp,
   2903   1.1  christos 				     &version, &is_zone);
   2904   1.1  christos 		if (result != ISC_R_SUCCESS) {
   2905   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   2906   1.3  christos 				     rpz_type, "rpz_rrset_find(2)", result);
   2907   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   2908   1.9  christos 			if (zone != NULL) {
   2909   1.1  christos 				dns_zone_detach(&zone);
   2910   1.9  christos 			}
   2911   1.1  christos 			return (result);
   2912   1.1  christos 		}
   2913   1.9  christos 		if (zone != NULL) {
   2914   1.1  christos 			dns_zone_detach(&zone);
   2915   1.9  christos 		}
   2916   1.1  christos 	}
   2917   1.1  christos 
   2918   1.1  christos 	node = NULL;
   2919   1.1  christos 	found = dns_fixedname_initname(&fixed);
   2920   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2921  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   2922  1.15  christos 	result = dns_db_findext(*dbp, name, version, type, options, client->now,
   2923  1.15  christos 				&node, found, &cm, &ci, *rdatasetp, NULL);
   2924   1.1  christos 	if (result == DNS_R_DELEGATION && is_zone && USECACHE(client)) {
   2925   1.1  christos 		/*
   2926   1.1  christos 		 * Try the cache if we're authoritative for an
   2927   1.1  christos 		 * ancestor but not the domain itself.
   2928   1.1  christos 		 */
   2929   1.1  christos 		rpz_clean(NULL, dbp, &node, rdatasetp);
   2930   1.1  christos 		version = NULL;
   2931   1.1  christos 		dns_db_attach(client->view->cachedb, dbp);
   2932   1.9  christos 		result = dns_db_findext(*dbp, name, version, type, 0,
   2933   1.9  christos 					client->now, &node, found, &cm, &ci,
   2934   1.9  christos 					*rdatasetp, NULL);
   2935   1.1  christos 	}
   2936   1.1  christos 	rpz_clean(NULL, dbp, &node, NULL);
   2937   1.1  christos 	if (result == DNS_R_DELEGATION) {
   2938   1.1  christos 		rpz_clean(NULL, NULL, NULL, rdatasetp);
   2939   1.1  christos 		/*
   2940   1.1  christos 		 * Recurse for NS rrset or A or AAAA rrset for an NS.
   2941   1.1  christos 		 * Do not recurse for addresses for the query name.
   2942   1.1  christos 		 */
   2943   1.1  christos 		if (rpz_type == DNS_RPZ_TYPE_IP) {
   2944   1.1  christos 			result = DNS_R_NXRRSET;
   2945  1.20  christos 		} else if (!client->view->rpzs->p.nsip_wait_recurse ||
   2946  1.20  christos 			   (!client->view->rpzs->p.nsdname_wait_recurse &&
   2947  1.20  christos 			    rpz_type == DNS_RPZ_TYPE_NSDNAME))
   2948  1.20  christos 		{
   2949   1.1  christos 			query_rpzfetch(client, name, type);
   2950   1.1  christos 			result = DNS_R_NXRRSET;
   2951   1.1  christos 		} else {
   2952  1.20  christos 			dns_name_copy(name, st->r_name);
   2953   1.3  christos 			result = ns_query_recurse(client, type, st->r_name,
   2954   1.3  christos 						  NULL, NULL, resuming);
   2955   1.1  christos 			if (result == ISC_R_SUCCESS) {
   2956   1.1  christos 				st->state |= DNS_RPZ_RECURSING;
   2957   1.1  christos 				result = DNS_R_DELEGATION;
   2958   1.1  christos 			}
   2959   1.1  christos 		}
   2960   1.1  christos 	}
   2961   1.1  christos 	return (result);
   2962   1.1  christos }
   2963   1.1  christos 
   2964   1.1  christos /*
   2965   1.1  christos  * Compute a policy owner name, p_name, in a policy zone given the needed
   2966   1.1  christos  * policy type and the trigger name.
   2967   1.1  christos  */
   2968   1.1  christos static isc_result_t
   2969   1.9  christos rpz_get_p_name(ns_client_t *client, dns_name_t *p_name, dns_rpz_zone_t *rpz,
   2970   1.9  christos 	       dns_rpz_type_t rpz_type, dns_name_t *trig_name) {
   2971   1.1  christos 	dns_offsets_t prefix_offsets;
   2972   1.1  christos 	dns_name_t prefix, *suffix;
   2973   1.1  christos 	unsigned int first, labels;
   2974   1.1  christos 	isc_result_t result;
   2975   1.1  christos 
   2976   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_get_p_name");
   2977   1.1  christos 
   2978   1.1  christos 	/*
   2979   1.1  christos 	 * The policy owner name consists of a suffix depending on the type
   2980   1.1  christos 	 * and policy zone and a prefix that is the longest possible string
   2981   1.1  christos 	 * from the trigger name that keesp the resulting policy owner name
   2982   1.1  christos 	 * from being too long.
   2983   1.1  christos 	 */
   2984   1.1  christos 	switch (rpz_type) {
   2985   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   2986   1.1  christos 		suffix = &rpz->client_ip;
   2987   1.1  christos 		break;
   2988   1.1  christos 	case DNS_RPZ_TYPE_QNAME:
   2989   1.1  christos 		suffix = &rpz->origin;
   2990   1.1  christos 		break;
   2991   1.1  christos 	case DNS_RPZ_TYPE_IP:
   2992   1.1  christos 		suffix = &rpz->ip;
   2993   1.1  christos 		break;
   2994   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   2995   1.1  christos 		suffix = &rpz->nsdname;
   2996   1.1  christos 		break;
   2997   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   2998   1.1  christos 		suffix = &rpz->nsip;
   2999   1.1  christos 		break;
   3000   1.1  christos 	default:
   3001  1.15  christos 		UNREACHABLE();
   3002   1.1  christos 	}
   3003   1.1  christos 
   3004   1.1  christos 	/*
   3005   1.1  christos 	 * Start with relative version of the full trigger name,
   3006   1.1  christos 	 * and trim enough allow the addition of the suffix.
   3007   1.1  christos 	 */
   3008   1.1  christos 	dns_name_init(&prefix, prefix_offsets);
   3009   1.1  christos 	labels = dns_name_countlabels(trig_name);
   3010   1.1  christos 	first = 0;
   3011   1.1  christos 	for (;;) {
   3012   1.9  christos 		dns_name_getlabelsequence(trig_name, first, labels - first - 1,
   3013   1.1  christos 					  &prefix);
   3014   1.1  christos 		result = dns_name_concatenate(&prefix, suffix, p_name, NULL);
   3015   1.9  christos 		if (result == ISC_R_SUCCESS) {
   3016   1.1  christos 			break;
   3017   1.9  christos 		}
   3018   1.1  christos 		INSIST(result == DNS_R_NAMETOOLONG);
   3019   1.1  christos 		/*
   3020   1.1  christos 		 * Trim the trigger name until the combination is not too long.
   3021   1.1  christos 		 */
   3022   1.9  christos 		if (labels - first < 2) {
   3023   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, suffix,
   3024   1.9  christos 				     rpz_type, "concatenate()", result);
   3025   1.1  christos 			return (ISC_R_FAILURE);
   3026   1.1  christos 		}
   3027   1.1  christos 		/*
   3028   1.1  christos 		 * Complain once about trimming the trigger name.
   3029   1.1  christos 		 */
   3030   1.1  christos 		if (first == 0) {
   3031   1.1  christos 			rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, suffix,
   3032   1.9  christos 				     rpz_type, "concatenate()", result);
   3033   1.1  christos 		}
   3034   1.1  christos 		++first;
   3035   1.1  christos 	}
   3036   1.1  christos 	return (ISC_R_SUCCESS);
   3037   1.1  christos }
   3038   1.1  christos 
   3039   1.1  christos /*
   3040   1.1  christos  * Look in policy zone rpz for a policy of rpz_type by p_name.
   3041   1.1  christos  * The self-name (usually the client qname or an NS name) is compared with
   3042   1.1  christos  * the target of a CNAME policy for the old style passthru encoding.
   3043   1.1  christos  * If found, the policy is recorded in *zonep, *dbp, *versionp, *nodep,
   3044   1.1  christos  * *rdatasetp, and *policyp.
   3045   1.1  christos  * The target DNS type, qtype, chooses the best rdataset for *rdatasetp.
   3046   1.1  christos  * The caller must decide if the found policy is most suitable, including
   3047   1.1  christos  * better than a previously found policy.
   3048   1.1  christos  * If it is best, the caller records it in client->query.rpz_st->m.
   3049   1.1  christos  */
   3050   1.1  christos static isc_result_t
   3051   1.1  christos rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
   3052   1.1  christos 	   dns_name_t *p_name, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
   3053   1.1  christos 	   dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp,
   3054   1.1  christos 	   dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp,
   3055   1.9  christos 	   dns_rpz_policy_t *policyp) {
   3056   1.1  christos 	dns_fixedname_t foundf;
   3057   1.1  christos 	dns_name_t *found;
   3058   1.1  christos 	isc_result_t result;
   3059   1.1  christos 	dns_clientinfomethods_t cm;
   3060   1.1  christos 	dns_clientinfo_t ci;
   3061   1.6  christos 	bool found_a = false;
   3062   1.1  christos 
   3063   1.1  christos 	REQUIRE(nodep != NULL);
   3064   1.1  christos 
   3065   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_find_p");
   3066   1.1  christos 
   3067   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   3068  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   3069   1.1  christos 
   3070   1.1  christos 	/*
   3071   1.1  christos 	 * Try to find either a CNAME or the type of record demanded by the
   3072   1.1  christos 	 * request from the policy zone.
   3073   1.1  christos 	 */
   3074   1.1  christos 	rpz_clean(zonep, dbp, nodep, rdatasetp);
   3075   1.1  christos 	result = rpz_ready(client, rdatasetp);
   3076   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3077   1.1  christos 		CTRACE(ISC_LOG_ERROR, "rpz_ready() failed");
   3078   1.1  christos 		return (DNS_R_SERVFAIL);
   3079   1.1  christos 	}
   3080   1.1  christos 	*versionp = NULL;
   3081   1.1  christos 	result = rpz_getdb(client, p_name, rpz_type, zonep, dbp, versionp);
   3082   1.9  christos 	if (result != ISC_R_SUCCESS) {
   3083   1.1  christos 		return (DNS_R_NXDOMAIN);
   3084   1.9  christos 	}
   3085   1.1  christos 	found = dns_fixedname_initname(&foundf);
   3086   1.1  christos 
   3087   1.1  christos 	result = dns_db_findext(*dbp, p_name, *versionp, dns_rdatatype_any, 0,
   3088   1.9  christos 				client->now, nodep, found, &cm, &ci, *rdatasetp,
   3089   1.9  christos 				NULL);
   3090   1.1  christos 	/*
   3091   1.1  christos 	 * Choose the best rdataset if we found something.
   3092   1.1  christos 	 */
   3093   1.1  christos 	if (result == ISC_R_SUCCESS) {
   3094   1.1  christos 		dns_rdatasetiter_t *rdsiter;
   3095   1.1  christos 
   3096   1.1  christos 		rdsiter = NULL;
   3097  1.16  christos 		result = dns_db_allrdatasets(*dbp, *nodep, *versionp, 0, 0,
   3098   1.1  christos 					     &rdsiter);
   3099   1.1  christos 		if (result != ISC_R_SUCCESS) {
   3100   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name,
   3101   1.3  christos 				     rpz_type, "allrdatasets()", result);
   3102   1.1  christos 			CTRACE(ISC_LOG_ERROR,
   3103   1.1  christos 			       "rpz_find_p: allrdatasets failed");
   3104   1.1  christos 			return (DNS_R_SERVFAIL);
   3105   1.1  christos 		}
   3106   1.6  christos 		if (qtype == dns_rdatatype_aaaa &&
   3107  1.16  christos 		    !ISC_LIST_EMPTY(client->view->dns64))
   3108  1.16  christos 		{
   3109   1.6  christos 			for (result = dns_rdatasetiter_first(rdsiter);
   3110   1.6  christos 			     result == ISC_R_SUCCESS;
   3111   1.9  christos 			     result = dns_rdatasetiter_next(rdsiter))
   3112   1.9  christos 			{
   3113   1.6  christos 				dns_rdatasetiter_current(rdsiter, *rdatasetp);
   3114   1.6  christos 				if ((*rdatasetp)->type == dns_rdatatype_a) {
   3115   1.6  christos 					found_a = true;
   3116   1.6  christos 				}
   3117   1.6  christos 				dns_rdataset_disassociate(*rdatasetp);
   3118   1.6  christos 			}
   3119   1.6  christos 		}
   3120   1.1  christos 		for (result = dns_rdatasetiter_first(rdsiter);
   3121   1.1  christos 		     result == ISC_R_SUCCESS;
   3122   1.9  christos 		     result = dns_rdatasetiter_next(rdsiter))
   3123   1.9  christos 		{
   3124   1.1  christos 			dns_rdatasetiter_current(rdsiter, *rdatasetp);
   3125   1.1  christos 			if ((*rdatasetp)->type == dns_rdatatype_cname ||
   3126  1.16  christos 			    (*rdatasetp)->type == qtype)
   3127  1.16  christos 			{
   3128   1.1  christos 				break;
   3129   1.9  christos 			}
   3130   1.1  christos 			dns_rdataset_disassociate(*rdatasetp);
   3131   1.1  christos 		}
   3132   1.1  christos 		dns_rdatasetiter_destroy(&rdsiter);
   3133   1.1  christos 		if (result != ISC_R_SUCCESS) {
   3134   1.1  christos 			if (result != ISC_R_NOMORE) {
   3135   1.1  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
   3136   1.9  christos 					     p_name, rpz_type, "rdatasetiter",
   3137   1.9  christos 					     result);
   3138   1.9  christos 				CTRACE(ISC_LOG_ERROR, "rpz_find_p: "
   3139   1.9  christos 						      "rdatasetiter failed");
   3140   1.1  christos 				return (DNS_R_SERVFAIL);
   3141   1.1  christos 			}
   3142   1.1  christos 			/*
   3143   1.1  christos 			 * Ask again to get the right DNS_R_DNAME/NXRRSET/...
   3144   1.1  christos 			 * result if there is neither a CNAME nor target type.
   3145   1.1  christos 			 */
   3146   1.9  christos 			if (dns_rdataset_isassociated(*rdatasetp)) {
   3147   1.1  christos 				dns_rdataset_disassociate(*rdatasetp);
   3148   1.9  christos 			}
   3149   1.1  christos 			dns_db_detachnode(*dbp, nodep);
   3150   1.1  christos 
   3151   1.1  christos 			if (qtype == dns_rdatatype_rrsig ||
   3152  1.16  christos 			    qtype == dns_rdatatype_sig)
   3153  1.16  christos 			{
   3154   1.1  christos 				result = DNS_R_NXRRSET;
   3155   1.9  christos 			} else {
   3156   1.1  christos 				result = dns_db_findext(*dbp, p_name, *versionp,
   3157   1.1  christos 							qtype, 0, client->now,
   3158   1.1  christos 							nodep, found, &cm, &ci,
   3159   1.1  christos 							*rdatasetp, NULL);
   3160   1.9  christos 			}
   3161   1.1  christos 		}
   3162   1.1  christos 	}
   3163   1.1  christos 	switch (result) {
   3164   1.1  christos 	case ISC_R_SUCCESS:
   3165   1.1  christos 		if ((*rdatasetp)->type != dns_rdatatype_cname) {
   3166   1.1  christos 			*policyp = DNS_RPZ_POLICY_RECORD;
   3167   1.1  christos 		} else {
   3168   1.1  christos 			*policyp = dns_rpz_decode_cname(rpz, *rdatasetp,
   3169   1.1  christos 							self_name);
   3170   1.1  christos 			if ((*policyp == DNS_RPZ_POLICY_RECORD ||
   3171   1.1  christos 			     *policyp == DNS_RPZ_POLICY_WILDCNAME) &&
   3172   1.1  christos 			    qtype != dns_rdatatype_cname &&
   3173   1.1  christos 			    qtype != dns_rdatatype_any)
   3174   1.9  christos 			{
   3175   1.1  christos 				return (DNS_R_CNAME);
   3176   1.9  christos 			}
   3177   1.1  christos 		}
   3178   1.1  christos 		return (ISC_R_SUCCESS);
   3179   1.1  christos 	case DNS_R_NXRRSET:
   3180   1.6  christos 		if (found_a) {
   3181   1.6  christos 			*policyp = DNS_RPZ_POLICY_DNS64;
   3182   1.6  christos 		} else {
   3183   1.6  christos 			*policyp = DNS_RPZ_POLICY_NODATA;
   3184   1.6  christos 		}
   3185   1.1  christos 		return (result);
   3186   1.1  christos 	case DNS_R_DNAME:
   3187   1.9  christos 	/*
   3188   1.9  christos 	 * DNAME policy RRs have very few if any uses that are not
   3189   1.9  christos 	 * better served with simple wildcards.  Making them work would
   3190   1.9  christos 	 * require complications to get the number of labels matched
   3191   1.9  christos 	 * in the name or the found name to the main DNS_R_DNAME case
   3192   1.9  christos 	 * in query_dname().  The domain also does not appear in the
   3193   1.9  christos 	 * summary database at the right level, so this happens only
   3194   1.9  christos 	 * with a single policy zone when we have no summary database.
   3195   1.9  christos 	 * Treat it as a miss.
   3196   1.9  christos 	 */
   3197   1.1  christos 	case DNS_R_NXDOMAIN:
   3198   1.1  christos 	case DNS_R_EMPTYNAME:
   3199   1.1  christos 		return (DNS_R_NXDOMAIN);
   3200   1.1  christos 	default:
   3201   1.9  christos 		rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type, "",
   3202   1.9  christos 			     result);
   3203   1.9  christos 		CTRACE(ISC_LOG_ERROR, "rpz_find_p: unexpected result");
   3204   1.1  christos 		return (DNS_R_SERVFAIL);
   3205   1.1  christos 	}
   3206   1.1  christos }
   3207   1.1  christos 
   3208   1.1  christos static void
   3209   1.1  christos rpz_save_p(dns_rpz_st_t *st, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
   3210   1.1  christos 	   dns_rpz_policy_t policy, dns_name_t *p_name, dns_rpz_prefix_t prefix,
   3211   1.1  christos 	   isc_result_t result, dns_zone_t **zonep, dns_db_t **dbp,
   3212   1.1  christos 	   dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp,
   3213   1.9  christos 	   dns_dbversion_t *version) {
   3214   1.1  christos 	dns_rdataset_t *trdataset = NULL;
   3215   1.1  christos 
   3216   1.1  christos 	rpz_match_clear(st);
   3217   1.1  christos 	st->m.rpz = rpz;
   3218   1.1  christos 	st->m.type = rpz_type;
   3219   1.1  christos 	st->m.policy = policy;
   3220  1.20  christos 	dns_name_copy(p_name, st->p_name);
   3221   1.1  christos 	st->m.prefix = prefix;
   3222   1.1  christos 	st->m.result = result;
   3223   1.1  christos 	SAVE(st->m.zone, *zonep);
   3224   1.1  christos 	SAVE(st->m.db, *dbp);
   3225   1.1  christos 	SAVE(st->m.node, *nodep);
   3226   1.1  christos 	if (*rdatasetp != NULL && dns_rdataset_isassociated(*rdatasetp)) {
   3227   1.1  christos 		/*
   3228   1.1  christos 		 * Save the replacement rdataset from the policy
   3229   1.1  christos 		 * and make the previous replacement rdataset scratch.
   3230   1.1  christos 		 */
   3231   1.1  christos 		SAVE(trdataset, st->m.rdataset);
   3232   1.1  christos 		SAVE(st->m.rdataset, *rdatasetp);
   3233   1.1  christos 		SAVE(*rdatasetp, trdataset);
   3234   1.1  christos 		st->m.ttl = ISC_MIN(st->m.rdataset->ttl, rpz->max_policy_ttl);
   3235   1.1  christos 	} else {
   3236   1.1  christos 		st->m.ttl = ISC_MIN(DNS_RPZ_TTL_DEFAULT, rpz->max_policy_ttl);
   3237   1.1  christos 	}
   3238   1.1  christos 	SAVE(st->m.version, version);
   3239   1.1  christos }
   3240   1.1  christos 
   3241   1.1  christos #ifdef USE_DNSRPS
   3242   1.1  christos /*
   3243   1.1  christos  * Check the results of a RPZ service interface lookup.
   3244   1.1  christos  * Stop after an error (<0) or not a hit on a disabled zone (0).
   3245   1.1  christos  * Continue after a hit on a disabled zone (>0).
   3246   1.1  christos  */
   3247   1.1  christos static int
   3248   1.1  christos dnsrps_ck(librpz_emsg_t *emsg, ns_client_t *client, rpsdb_t *rpsdb,
   3249   1.9  christos 	  bool recursed) {
   3250   1.1  christos 	isc_region_t region;
   3251   1.1  christos 	librpz_domain_buf_t pname_buf;
   3252   1.1  christos 
   3253   1.1  christos 	if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
   3254   1.1  christos 		return (-1);
   3255   1.1  christos 	}
   3256   1.1  christos 
   3257   1.1  christos 	/*
   3258   1.1  christos 	 * Forget the state from before the IP address or domain check
   3259   1.1  christos 	 * if the lookup hit nothing.
   3260   1.1  christos 	 */
   3261   1.1  christos 	if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED ||
   3262   1.1  christos 	    rpsdb->result.hit_id != rpsdb->hit_id ||
   3263   1.1  christos 	    rpsdb->result.policy != LIBRPZ_POLICY_DISABLED)
   3264   1.1  christos 	{
   3265   1.1  christos 		if (!librpz->rsp_pop_discard(emsg, rpsdb->rsp)) {
   3266   1.1  christos 			return (-1);
   3267   1.1  christos 		}
   3268   1.1  christos 		return (0);
   3269   1.1  christos 	}
   3270   1.1  christos 
   3271   1.1  christos 	/*
   3272   1.1  christos 	 * Log a hit on a disabled zone.
   3273   1.1  christos 	 * Forget the zone to not try it again, and restore the pre-hit state.
   3274   1.1  christos 	 */
   3275   1.1  christos 	if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
   3276   1.1  christos 		return (-1);
   3277   1.1  christos 	}
   3278   1.1  christos 	region.base = pname_buf.d;
   3279   1.1  christos 	region.length = pname_buf.size;
   3280   1.1  christos 	dns_name_fromregion(client->query.rpz_st->p_name, &region);
   3281   1.9  christos 	rpz_log_rewrite(client, true, dns_dnsrps_2policy(rpsdb->result.zpolicy),
   3282   1.1  christos 			dns_dnsrps_trig2type(rpsdb->result.trig), NULL,
   3283   1.1  christos 			client->query.rpz_st->p_name, NULL,
   3284   1.1  christos 			rpsdb->result.cznum);
   3285   1.1  christos 
   3286   1.1  christos 	if (!librpz->rsp_forget_zone(emsg, rpsdb->result.cznum, rpsdb->rsp) ||
   3287   1.1  christos 	    !librpz->rsp_pop(emsg, &rpsdb->result, rpsdb->rsp))
   3288   1.1  christos 	{
   3289   1.1  christos 		return (-1);
   3290   1.1  christos 	}
   3291   1.1  christos 	return (1);
   3292   1.1  christos }
   3293   1.1  christos 
   3294   1.1  christos /*
   3295   1.1  christos  * Ready the shim database and rdataset for a DNSRPS hit.
   3296   1.1  christos  */
   3297   1.3  christos static bool
   3298   1.1  christos dnsrps_set_p(librpz_emsg_t *emsg, ns_client_t *client, dns_rpz_st_t *st,
   3299   1.1  christos 	     dns_rdatatype_t qtype, dns_rdataset_t **p_rdatasetp,
   3300   1.9  christos 	     bool recursed) {
   3301   1.1  christos 	rpsdb_t *rpsdb;
   3302   1.1  christos 	librpz_domain_buf_t pname_buf;
   3303   1.1  christos 	isc_region_t region;
   3304   1.1  christos 	dns_zone_t *p_zone;
   3305   1.1  christos 	dns_db_t *p_db;
   3306   1.1  christos 	dns_dbnode_t *p_node;
   3307   1.1  christos 	dns_rpz_policy_t policy;
   3308   1.1  christos 	dns_fixedname_t foundf;
   3309   1.1  christos 	dns_name_t *found;
   3310   1.1  christos 	dns_rdatatype_t foundtype, searchtype;
   3311   1.1  christos 	isc_result_t result;
   3312   1.1  christos 
   3313   1.1  christos 	rpsdb = (rpsdb_t *)st->rpsdb;
   3314   1.1  christos 
   3315   1.1  christos 	if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
   3316   1.3  christos 		return (false);
   3317   1.1  christos 	}
   3318   1.1  christos 
   3319   1.1  christos 	if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED) {
   3320   1.3  christos 		return (true);
   3321   1.1  christos 	}
   3322   1.1  christos 
   3323   1.1  christos 	/*
   3324   1.1  christos 	 * Give the fake or shim DNSRPS database its new origin.
   3325   1.1  christos 	 */
   3326   1.1  christos 	if (!librpz->rsp_soa(emsg, NULL, NULL, &rpsdb->origin_buf,
   3327   1.1  christos 			     &rpsdb->result, rpsdb->rsp))
   3328   1.1  christos 	{
   3329   1.3  christos 		return (false);
   3330   1.1  christos 	}
   3331   1.1  christos 	region.base = rpsdb->origin_buf.d;
   3332   1.1  christos 	region.length = rpsdb->origin_buf.size;
   3333   1.1  christos 	dns_name_fromregion(&rpsdb->common.origin, &region);
   3334   1.1  christos 
   3335   1.1  christos 	if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
   3336   1.3  christos 		return (false);
   3337   1.1  christos 	}
   3338   1.1  christos 	region.base = pname_buf.d;
   3339   1.1  christos 	region.length = pname_buf.size;
   3340   1.1  christos 	dns_name_fromregion(st->p_name, &region);
   3341   1.1  christos 
   3342   1.1  christos 	p_zone = NULL;
   3343   1.1  christos 	p_db = NULL;
   3344   1.1  christos 	p_node = NULL;
   3345   1.1  christos 	rpz_ready(client, p_rdatasetp);
   3346   1.1  christos 	dns_db_attach(st->rpsdb, &p_db);
   3347   1.1  christos 	policy = dns_dnsrps_2policy(rpsdb->result.policy);
   3348   1.1  christos 	if (policy != DNS_RPZ_POLICY_RECORD) {
   3349   1.1  christos 		result = ISC_R_SUCCESS;
   3350   1.1  christos 	} else if (qtype == dns_rdatatype_rrsig) {
   3351   1.1  christos 		/*
   3352   1.1  christos 		 * dns_find_db() refuses to look for and fail to
   3353   1.1  christos 		 * find dns_rdatatype_rrsig.
   3354   1.1  christos 		 */
   3355   1.1  christos 		result = DNS_R_NXRRSET;
   3356   1.1  christos 		policy = DNS_RPZ_POLICY_NODATA;
   3357   1.1  christos 	} else {
   3358   1.1  christos 		/*
   3359   1.1  christos 		 * Get the next (and so first) RR from the policy node.
   3360   1.1  christos 		 * If it is a CNAME, then look for it regardless of the
   3361   1.1  christos 		 * query type.
   3362   1.1  christos 		 */
   3363   1.1  christos 		if (!librpz->rsp_rr(emsg, &foundtype, NULL, NULL, NULL,
   3364   1.1  christos 				    &rpsdb->result, rpsdb->qname->ndata,
   3365   1.1  christos 				    rpsdb->qname->length, rpsdb->rsp))
   3366   1.1  christos 		{
   3367   1.3  christos 			return (false);
   3368   1.1  christos 		}
   3369   1.1  christos 		if (foundtype == dns_rdatatype_cname) {
   3370   1.1  christos 			searchtype = dns_rdatatype_cname;
   3371   1.1  christos 		} else {
   3372   1.1  christos 			searchtype = qtype;
   3373   1.1  christos 		}
   3374   1.1  christos 		/*
   3375   1.1  christos 		 * Get the DNSPRS imitation rdataset.
   3376   1.1  christos 		 */
   3377   1.1  christos 		found = dns_fixedname_initname(&foundf);
   3378   1.9  christos 		result = dns_db_find(p_db, st->p_name, NULL, searchtype, 0, 0,
   3379   1.9  christos 				     &p_node, found, *p_rdatasetp, NULL);
   3380   1.1  christos 
   3381   1.1  christos 		if (result == ISC_R_SUCCESS) {
   3382   1.1  christos 			if (searchtype == dns_rdatatype_cname &&
   3383  1.16  christos 			    qtype != dns_rdatatype_cname)
   3384  1.16  christos 			{
   3385   1.1  christos 				result = DNS_R_CNAME;
   3386   1.1  christos 			}
   3387   1.1  christos 		} else if (result == DNS_R_NXRRSET) {
   3388   1.1  christos 			policy = DNS_RPZ_POLICY_NODATA;
   3389   1.1  christos 		} else {
   3390   1.1  christos 			snprintf(emsg->c, sizeof(emsg->c), "dns_db_find(): %s",
   3391   1.1  christos 				 isc_result_totext(result));
   3392   1.3  christos 			return (false);
   3393   1.1  christos 		}
   3394   1.1  christos 	}
   3395   1.1  christos 
   3396   1.1  christos 	rpz_save_p(st, client->view->rpzs->zones[rpsdb->result.cznum],
   3397   1.9  christos 		   dns_dnsrps_trig2type(rpsdb->result.trig), policy, st->p_name,
   3398   1.9  christos 		   0, result, &p_zone, &p_db, &p_node, p_rdatasetp, NULL);
   3399   1.1  christos 
   3400   1.1  christos 	rpz_clean(NULL, NULL, NULL, p_rdatasetp);
   3401   1.1  christos 
   3402   1.3  christos 	return (true);
   3403   1.1  christos }
   3404   1.1  christos 
   3405   1.1  christos static isc_result_t
   3406   1.1  christos dnsrps_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
   3407   1.9  christos 		  dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp) {
   3408   1.1  christos 	dns_rpz_st_t *st;
   3409   1.1  christos 	rpsdb_t *rpsdb;
   3410   1.1  christos 	librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
   3411   1.3  christos 	bool recursed = false;
   3412   1.1  christos 	int res;
   3413   1.1  christos 	librpz_emsg_t emsg;
   3414   1.1  christos 	isc_result_t result;
   3415   1.1  christos 
   3416   1.1  christos 	st = client->query.rpz_st;
   3417   1.1  christos 	rpsdb = (rpsdb_t *)st->rpsdb;
   3418   1.1  christos 
   3419   1.1  christos 	result = rpz_ready(client, p_rdatasetp);
   3420   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3421   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   3422   1.1  christos 		return (result);
   3423   1.1  christos 	}
   3424   1.1  christos 
   3425   1.1  christos 	switch (rpz_type) {
   3426   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   3427   1.1  christos 		trig = LIBRPZ_TRIG_CLIENT_IP;
   3428   1.3  christos 		recursed = false;
   3429   1.1  christos 		break;
   3430   1.1  christos 	case DNS_RPZ_TYPE_IP:
   3431   1.1  christos 		trig = LIBRPZ_TRIG_IP;
   3432   1.3  christos 		recursed = true;
   3433   1.1  christos 		break;
   3434   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   3435   1.1  christos 		trig = LIBRPZ_TRIG_NSIP;
   3436   1.3  christos 		recursed = true;
   3437   1.1  christos 		break;
   3438   1.1  christos 	default:
   3439  1.15  christos 		UNREACHABLE();
   3440   1.1  christos 	}
   3441   1.1  christos 
   3442   1.1  christos 	do {
   3443   1.1  christos 		if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
   3444   1.1  christos 		    !librpz->ck_ip(&emsg,
   3445   1.1  christos 				   netaddr->family == AF_INET
   3446   1.9  christos 					   ? (const void *)&netaddr->type.in
   3447   1.9  christos 					   : (const void *)&netaddr->type.in6,
   3448   1.1  christos 				   netaddr->family, trig, ++rpsdb->hit_id,
   3449   1.1  christos 				   recursed, rpsdb->rsp) ||
   3450   1.1  christos 		    (res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
   3451   1.1  christos 		{
   3452   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   3453   1.1  christos 				     rpz_type, emsg.c, DNS_R_SERVFAIL);
   3454   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3455   1.1  christos 			return (DNS_R_SERVFAIL);
   3456   1.1  christos 		}
   3457   1.1  christos 	} while (res != 0);
   3458   1.1  christos 	return (ISC_R_SUCCESS);
   3459   1.1  christos }
   3460   1.1  christos 
   3461   1.1  christos static isc_result_t
   3462   1.9  christos dnsrps_rewrite_name(ns_client_t *client, dns_name_t *trig_name, bool recursed,
   3463   1.9  christos 		    dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp) {
   3464   1.1  christos 	dns_rpz_st_t *st;
   3465   1.1  christos 	rpsdb_t *rpsdb;
   3466   1.1  christos 	librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
   3467   1.1  christos 	isc_region_t r;
   3468   1.1  christos 	int res;
   3469   1.1  christos 	librpz_emsg_t emsg;
   3470   1.1  christos 	isc_result_t result;
   3471   1.1  christos 
   3472   1.1  christos 	st = client->query.rpz_st;
   3473   1.1  christos 	rpsdb = (rpsdb_t *)st->rpsdb;
   3474   1.1  christos 
   3475   1.1  christos 	result = rpz_ready(client, p_rdatasetp);
   3476   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3477   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   3478   1.1  christos 		return (result);
   3479   1.1  christos 	}
   3480   1.1  christos 
   3481   1.1  christos 	switch (rpz_type) {
   3482   1.1  christos 	case DNS_RPZ_TYPE_QNAME:
   3483   1.1  christos 		trig = LIBRPZ_TRIG_QNAME;
   3484   1.1  christos 		break;
   3485   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   3486   1.1  christos 		trig = LIBRPZ_TRIG_NSDNAME;
   3487   1.1  christos 		break;
   3488   1.1  christos 	default:
   3489  1.15  christos 		UNREACHABLE();
   3490   1.1  christos 	}
   3491   1.1  christos 
   3492   1.1  christos 	dns_name_toregion(trig_name, &r);
   3493   1.1  christos 	do {
   3494   1.1  christos 		if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
   3495   1.9  christos 		    !librpz->ck_domain(&emsg, r.base, r.length, trig,
   3496   1.9  christos 				       ++rpsdb->hit_id, recursed, rpsdb->rsp) ||
   3497   1.1  christos 		    (res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
   3498   1.1  christos 		{
   3499   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   3500   1.1  christos 				     rpz_type, emsg.c, DNS_R_SERVFAIL);
   3501   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3502   1.1  christos 			return (DNS_R_SERVFAIL);
   3503   1.1  christos 		}
   3504   1.1  christos 	} while (res != 0);
   3505   1.1  christos 	return (ISC_R_SUCCESS);
   3506   1.1  christos }
   3507   1.1  christos #endif /* USE_DNSRPS */
   3508   1.1  christos 
   3509   1.1  christos /*
   3510   1.1  christos  * Check this address in every eligible policy zone.
   3511   1.1  christos  */
   3512   1.1  christos static isc_result_t
   3513   1.1  christos rpz_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
   3514   1.1  christos 	       dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3515   1.9  christos 	       dns_rpz_zbits_t zbits, dns_rdataset_t **p_rdatasetp) {
   3516   1.1  christos 	dns_rpz_zones_t *rpzs;
   3517   1.1  christos 	dns_rpz_st_t *st;
   3518   1.1  christos 	dns_rpz_zone_t *rpz;
   3519   1.1  christos 	dns_rpz_prefix_t prefix;
   3520   1.1  christos 	dns_rpz_num_t rpz_num;
   3521   1.1  christos 	dns_fixedname_t ip_namef, p_namef;
   3522   1.1  christos 	dns_name_t *ip_name, *p_name;
   3523   1.1  christos 	dns_zone_t *p_zone;
   3524   1.1  christos 	dns_db_t *p_db;
   3525   1.1  christos 	dns_dbversion_t *p_version;
   3526   1.1  christos 	dns_dbnode_t *p_node;
   3527   1.1  christos 	dns_rpz_policy_t policy;
   3528   1.1  christos 	isc_result_t result;
   3529   1.1  christos 
   3530   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip");
   3531   1.1  christos 
   3532   1.1  christos 	rpzs = client->view->rpzs;
   3533   1.1  christos 	st = client->query.rpz_st;
   3534   1.1  christos #ifdef USE_DNSRPS
   3535   1.1  christos 	if (st->popt.dnsrps_enabled) {
   3536   1.1  christos 		return (dnsrps_rewrite_ip(client, netaddr, rpz_type,
   3537   1.9  christos 					  p_rdatasetp));
   3538   1.1  christos 	}
   3539   1.9  christos #endif /* ifdef USE_DNSRPS */
   3540   1.1  christos 
   3541   1.1  christos 	ip_name = dns_fixedname_initname(&ip_namef);
   3542   1.1  christos 
   3543   1.1  christos 	p_zone = NULL;
   3544   1.1  christos 	p_db = NULL;
   3545   1.1  christos 	p_node = NULL;
   3546   1.1  christos 
   3547   1.1  christos 	while (zbits != 0) {
   3548   1.1  christos 		rpz_num = dns_rpz_find_ip(rpzs, rpz_type, zbits, netaddr,
   3549   1.1  christos 					  ip_name, &prefix);
   3550   1.9  christos 		if (rpz_num == DNS_RPZ_INVALID_NUM) {
   3551   1.1  christos 			break;
   3552   1.9  christos 		}
   3553   1.1  christos 		zbits &= (DNS_RPZ_ZMASK(rpz_num) >> 1);
   3554   1.1  christos 
   3555   1.1  christos 		/*
   3556   1.1  christos 		 * Do not try applying policy zones that cannot replace a
   3557   1.1  christos 		 * previously found policy zone.
   3558   1.1  christos 		 * Stop looking if the next best choice cannot
   3559   1.1  christos 		 * replace what we already have.
   3560   1.1  christos 		 */
   3561   1.1  christos 		rpz = rpzs->zones[rpz_num];
   3562   1.1  christos 		if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   3563   1.9  christos 			if (st->m.rpz->num < rpz->num) {
   3564   1.1  christos 				break;
   3565   1.9  christos 			}
   3566   1.1  christos 			if (st->m.rpz->num == rpz->num &&
   3567   1.9  christos 			    (st->m.type < rpz_type || st->m.prefix > prefix))
   3568   1.9  christos 			{
   3569   1.1  christos 				break;
   3570   1.9  christos 			}
   3571   1.1  christos 		}
   3572   1.1  christos 
   3573   1.1  christos 		/*
   3574   1.1  christos 		 * Get the policy for a prefix at least as long
   3575   1.1  christos 		 * as the prefix of the entry we had before.
   3576   1.1  christos 		 */
   3577   1.1  christos 		p_name = dns_fixedname_initname(&p_namef);
   3578   1.1  christos 		result = rpz_get_p_name(client, p_name, rpz, rpz_type, ip_name);
   3579   1.9  christos 		if (result != ISC_R_SUCCESS) {
   3580   1.1  christos 			continue;
   3581   1.9  christos 		}
   3582   1.9  christos 		result = rpz_find_p(client, ip_name, qtype, p_name, rpz,
   3583   1.9  christos 				    rpz_type, &p_zone, &p_db, &p_version,
   3584   1.9  christos 				    &p_node, p_rdatasetp, &policy);
   3585   1.1  christos 		switch (result) {
   3586   1.1  christos 		case DNS_R_NXDOMAIN:
   3587   1.1  christos 			/*
   3588   1.1  christos 			 * Continue after a policy record that is missing
   3589   1.1  christos 			 * contrary to the summary data.  The summary
   3590   1.1  christos 			 * data can out of date during races with and among
   3591   1.1  christos 			 * policy zone updates.
   3592   1.1  christos 			 */
   3593   1.9  christos 			CTRACE(ISC_LOG_ERROR, "rpz_rewrite_ip: mismatched "
   3594   1.9  christos 					      "summary data; "
   3595   1.9  christos 					      "continuing");
   3596   1.1  christos 			continue;
   3597   1.1  christos 		case DNS_R_SERVFAIL:
   3598   1.1  christos 			rpz_clean(&p_zone, &p_db, &p_node, p_rdatasetp);
   3599   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3600   1.1  christos 			return (DNS_R_SERVFAIL);
   3601   1.1  christos 		default:
   3602   1.1  christos 			/*
   3603   1.1  christos 			 * Forget this policy if it is not preferable
   3604   1.1  christos 			 * to the previously found policy.
   3605   1.1  christos 			 * If this policy is not good, then stop looking
   3606   1.1  christos 			 * because none of the later policy zones would work.
   3607   1.1  christos 			 *
   3608   1.1  christos 			 * With more than one applicable policy, prefer
   3609   1.1  christos 			 * the earliest configured policy,
   3610   1.1  christos 			 * client-IP over QNAME over IP over NSDNAME over NSIP,
   3611   1.1  christos 			 * the longest prefix
   3612   1.1  christos 			 * the lexically smallest address.
   3613   1.1  christos 			 * dns_rpz_find_ip() ensures st->m.rpz->num >= rpz->num.
   3614   1.1  christos 			 * We can compare new and current p_name because
   3615   1.1  christos 			 * both are of the same type and in the same zone.
   3616   1.1  christos 			 * The tests above eliminate other reasons to
   3617   1.1  christos 			 * reject this policy.  If this policy can't work,
   3618   1.1  christos 			 * then neither can later zones.
   3619   1.1  christos 			 */
   3620   1.1  christos 			if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   3621   1.1  christos 			    rpz->num == st->m.rpz->num &&
   3622   1.9  christos 			    (st->m.type == rpz_type && st->m.prefix == prefix &&
   3623   1.9  christos 			     0 > dns_name_rdatacompare(st->p_name, p_name)))
   3624   1.9  christos 			{
   3625   1.1  christos 				break;
   3626   1.9  christos 			}
   3627   1.1  christos 
   3628   1.1  christos 			/*
   3629   1.1  christos 			 * Stop checking after saving an enabled hit in this
   3630   1.1  christos 			 * policy zone.  The radix tree in the policy zone
   3631   1.1  christos 			 * ensures that we found the longest match.
   3632   1.1  christos 			 */
   3633   1.1  christos 			if (rpz->policy != DNS_RPZ_POLICY_DISABLED) {
   3634   1.9  christos 				CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip: "
   3635   1.9  christos 							 "rpz_save_p");
   3636   1.9  christos 				rpz_save_p(st, rpz, rpz_type, policy, p_name,
   3637   1.9  christos 					   prefix, result, &p_zone, &p_db,
   3638   1.9  christos 					   &p_node, p_rdatasetp, p_version);
   3639   1.1  christos 				break;
   3640   1.1  christos 			}
   3641   1.1  christos 
   3642   1.1  christos 			/*
   3643   1.1  christos 			 * Log DNS_RPZ_POLICY_DISABLED zones
   3644   1.1  christos 			 * and try the next eligible policy zone.
   3645   1.1  christos 			 */
   3646   1.9  christos 			rpz_log_rewrite(client, true, policy, rpz_type, p_zone,
   3647   1.9  christos 					p_name, NULL, rpz_num);
   3648   1.1  christos 		}
   3649   1.1  christos 	}
   3650   1.1  christos 
   3651   1.1  christos 	rpz_clean(&p_zone, &p_db, &p_node, p_rdatasetp);
   3652   1.1  christos 	return (ISC_R_SUCCESS);
   3653   1.1  christos }
   3654   1.1  christos 
   3655   1.1  christos /*
   3656   1.1  christos  * Check the IP addresses in the A or AAAA rrsets for name against
   3657   1.1  christos  * all eligible rpz_type (IP or NSIP) response policy rewrite rules.
   3658   1.1  christos  */
   3659   1.1  christos static isc_result_t
   3660   1.9  christos rpz_rewrite_ip_rrset(ns_client_t *client, dns_name_t *name,
   3661   1.9  christos 		     dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3662   1.9  christos 		     dns_rdatatype_t ip_type, dns_db_t **ip_dbp,
   3663   1.9  christos 		     dns_dbversion_t *ip_version, dns_rdataset_t **ip_rdatasetp,
   3664   1.9  christos 		     dns_rdataset_t **p_rdatasetp, bool resuming) {
   3665   1.1  christos 	dns_rpz_zbits_t zbits;
   3666   1.1  christos 	isc_netaddr_t netaddr;
   3667   1.1  christos 	struct in_addr ina;
   3668   1.1  christos 	struct in6_addr in6a;
   3669   1.1  christos 	isc_result_t result;
   3670  1.16  christos 	unsigned int options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   3671  1.15  christos 	bool done = false;
   3672   1.1  christos 
   3673   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip_rrset");
   3674   1.1  christos 
   3675  1.15  christos 	do {
   3676  1.15  christos 		zbits = rpz_get_zbits(client, ip_type, rpz_type);
   3677  1.15  christos 		if (zbits == 0) {
   3678  1.15  christos 			return (ISC_R_SUCCESS);
   3679  1.15  christos 		}
   3680   1.1  christos 
   3681  1.15  christos 		/*
   3682  1.15  christos 		 * Get the A or AAAA rdataset.
   3683  1.15  christos 		 */
   3684  1.15  christos 		result = rpz_rrset_find(client, name, ip_type, options,
   3685  1.15  christos 					rpz_type, ip_dbp, ip_version,
   3686  1.15  christos 					ip_rdatasetp, resuming);
   3687  1.15  christos 		switch (result) {
   3688  1.15  christos 		case ISC_R_SUCCESS:
   3689  1.15  christos 		case DNS_R_GLUE:
   3690  1.15  christos 		case DNS_R_ZONECUT:
   3691  1.15  christos 			break;
   3692  1.15  christos 		case DNS_R_EMPTYNAME:
   3693  1.15  christos 		case DNS_R_EMPTYWILD:
   3694  1.15  christos 		case DNS_R_NXDOMAIN:
   3695  1.15  christos 		case DNS_R_NCACHENXDOMAIN:
   3696  1.15  christos 		case DNS_R_NXRRSET:
   3697  1.15  christos 		case DNS_R_NCACHENXRRSET:
   3698  1.15  christos 		case ISC_R_NOTFOUND:
   3699  1.15  christos 			return (ISC_R_SUCCESS);
   3700  1.15  christos 		case DNS_R_DELEGATION:
   3701  1.15  christos 		case DNS_R_DUPLICATE:
   3702  1.15  christos 		case DNS_R_DROP:
   3703  1.15  christos 			return (result);
   3704  1.15  christos 		case DNS_R_CNAME:
   3705  1.15  christos 		case DNS_R_DNAME:
   3706  1.15  christos 			rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, name,
   3707   1.3  christos 				     rpz_type, "NS address rewrite rrset",
   3708   1.1  christos 				     result);
   3709  1.15  christos 			return (ISC_R_SUCCESS);
   3710  1.15  christos 		default:
   3711  1.15  christos 			if (client->query.rpz_st->m.policy !=
   3712  1.16  christos 			    DNS_RPZ_POLICY_ERROR)
   3713  1.16  christos 			{
   3714  1.15  christos 				client->query.rpz_st->m.policy =
   3715  1.15  christos 					DNS_RPZ_POLICY_ERROR;
   3716  1.15  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   3717  1.15  christos 					     rpz_type,
   3718  1.15  christos 					     "NS address rewrite rrset",
   3719  1.15  christos 					     result);
   3720  1.15  christos 			}
   3721  1.15  christos 			CTRACE(ISC_LOG_ERROR,
   3722  1.15  christos 			       "rpz_rewrite_ip_rrset: unexpected "
   3723  1.15  christos 			       "result");
   3724  1.15  christos 			return (DNS_R_SERVFAIL);
   3725   1.1  christos 		}
   3726   1.1  christos 
   3727  1.15  christos 		/*
   3728  1.15  christos 		 * If we are processing glue setup for the next loop
   3729  1.15  christos 		 * otherwise we are done.
   3730  1.15  christos 		 */
   3731  1.15  christos 		if (result == DNS_R_GLUE) {
   3732  1.16  christos 			options = client->query.dboptions;
   3733  1.15  christos 		} else {
   3734  1.16  christos 			options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   3735  1.15  christos 			done = true;
   3736   1.1  christos 		}
   3737   1.1  christos 
   3738  1.15  christos 		/*
   3739  1.15  christos 		 * Check all of the IP addresses in the rdataset.
   3740  1.15  christos 		 */
   3741  1.15  christos 		for (result = dns_rdataset_first(*ip_rdatasetp);
   3742  1.15  christos 		     result == ISC_R_SUCCESS;
   3743  1.15  christos 		     result = dns_rdataset_next(*ip_rdatasetp))
   3744  1.15  christos 		{
   3745  1.15  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   3746  1.15  christos 			dns_rdataset_current(*ip_rdatasetp, &rdata);
   3747  1.15  christos 			switch (rdata.type) {
   3748  1.15  christos 			case dns_rdatatype_a:
   3749  1.15  christos 				INSIST(rdata.length == 4);
   3750  1.15  christos 				memmove(&ina.s_addr, rdata.data, 4);
   3751  1.15  christos 				isc_netaddr_fromin(&netaddr, &ina);
   3752  1.15  christos 				break;
   3753  1.15  christos 			case dns_rdatatype_aaaa:
   3754  1.15  christos 				INSIST(rdata.length == 16);
   3755  1.15  christos 				memmove(in6a.s6_addr, rdata.data, 16);
   3756  1.15  christos 				isc_netaddr_fromin6(&netaddr, &in6a);
   3757  1.15  christos 				break;
   3758  1.15  christos 			default:
   3759  1.15  christos 				continue;
   3760  1.15  christos 			}
   3761  1.15  christos 
   3762  1.15  christos 			result = rpz_rewrite_ip(client, &netaddr, qtype,
   3763  1.15  christos 						rpz_type, zbits, p_rdatasetp);
   3764  1.15  christos 			if (result != ISC_R_SUCCESS) {
   3765  1.15  christos 				return (result);
   3766  1.15  christos 			}
   3767   1.9  christos 		}
   3768  1.15  christos 	} while (!done &&
   3769  1.15  christos 		 client->query.rpz_st->m.policy == DNS_RPZ_POLICY_MISS);
   3770   1.1  christos 
   3771   1.1  christos 	return (ISC_R_SUCCESS);
   3772   1.1  christos }
   3773   1.1  christos 
   3774   1.1  christos /*
   3775   1.1  christos  * Look for IP addresses in A and AAAA rdatasets
   3776   1.1  christos  * that trigger all eligible IP or NSIP policy rules.
   3777   1.1  christos  */
   3778   1.1  christos static isc_result_t
   3779   1.1  christos rpz_rewrite_ip_rrsets(ns_client_t *client, dns_name_t *name,
   3780   1.1  christos 		      dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3781   1.9  christos 		      dns_rdataset_t **ip_rdatasetp, bool resuming) {
   3782   1.1  christos 	dns_rpz_st_t *st;
   3783   1.1  christos 	dns_dbversion_t *ip_version;
   3784   1.1  christos 	dns_db_t *ip_db;
   3785   1.1  christos 	dns_rdataset_t *p_rdataset;
   3786   1.1  christos 	isc_result_t result;
   3787   1.1  christos 
   3788   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip_rrsets");
   3789   1.1  christos 
   3790   1.1  christos 	st = client->query.rpz_st;
   3791   1.1  christos 	ip_version = NULL;
   3792   1.1  christos 	ip_db = NULL;
   3793   1.1  christos 	p_rdataset = NULL;
   3794   1.1  christos 	if ((st->state & DNS_RPZ_DONE_IPv4) == 0 &&
   3795   1.9  christos 	    (qtype == dns_rdatatype_a || qtype == dns_rdatatype_any ||
   3796   1.9  christos 	     rpz_type == DNS_RPZ_TYPE_NSIP))
   3797   1.9  christos 	{
   3798   1.1  christos 		/*
   3799   1.1  christos 		 * Rewrite based on an IPv4 address that will appear
   3800   1.1  christos 		 * in the ANSWER section or if we are checking IP addresses.
   3801   1.1  christos 		 */
   3802   1.9  christos 		result = rpz_rewrite_ip_rrset(
   3803   1.9  christos 			client, name, qtype, rpz_type, dns_rdatatype_a, &ip_db,
   3804   1.9  christos 			ip_version, ip_rdatasetp, &p_rdataset, resuming);
   3805   1.9  christos 		if (result == ISC_R_SUCCESS) {
   3806   1.1  christos 			st->state |= DNS_RPZ_DONE_IPv4;
   3807   1.9  christos 		}
   3808   1.1  christos 	} else {
   3809   1.1  christos 		result = ISC_R_SUCCESS;
   3810   1.1  christos 	}
   3811   1.1  christos 	if (result == ISC_R_SUCCESS &&
   3812   1.9  christos 	    (qtype == dns_rdatatype_aaaa || qtype == dns_rdatatype_any ||
   3813   1.9  christos 	     rpz_type == DNS_RPZ_TYPE_NSIP))
   3814   1.9  christos 	{
   3815   1.1  christos 		/*
   3816   1.1  christos 		 * Rewrite based on IPv6 addresses that will appear
   3817   1.1  christos 		 * in the ANSWER section or if we are checking IP addresses.
   3818   1.1  christos 		 */
   3819   1.9  christos 		result = rpz_rewrite_ip_rrset(client, name, qtype, rpz_type,
   3820   1.9  christos 					      dns_rdatatype_aaaa, &ip_db,
   3821   1.9  christos 					      ip_version, ip_rdatasetp,
   3822   1.1  christos 					      &p_rdataset, resuming);
   3823   1.1  christos 	}
   3824   1.9  christos 	if (ip_db != NULL) {
   3825   1.1  christos 		dns_db_detach(&ip_db);
   3826   1.9  christos 	}
   3827   1.3  christos 	ns_client_putrdataset(client, &p_rdataset);
   3828   1.1  christos 	return (result);
   3829   1.1  christos }
   3830   1.1  christos 
   3831   1.1  christos /*
   3832   1.1  christos  * Try to rewrite a request for a qtype rdataset based on the trigger name
   3833   1.1  christos  * trig_name and rpz_type (DNS_RPZ_TYPE_QNAME or DNS_RPZ_TYPE_NSDNAME).
   3834   1.1  christos  * Record the results including the replacement rdataset if any
   3835   1.1  christos  * in client->query.rpz_st.
   3836   1.1  christos  * *rdatasetp is a scratch rdataset.
   3837   1.1  christos  */
   3838   1.1  christos static isc_result_t
   3839   1.1  christos rpz_rewrite_name(ns_client_t *client, dns_name_t *trig_name,
   3840   1.1  christos 		 dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3841   1.3  christos 		 dns_rpz_zbits_t allowed_zbits, bool recursed,
   3842   1.9  christos 		 dns_rdataset_t **rdatasetp) {
   3843   1.1  christos 	dns_rpz_zones_t *rpzs;
   3844   1.1  christos 	dns_rpz_zone_t *rpz;
   3845   1.1  christos 	dns_rpz_st_t *st;
   3846   1.1  christos 	dns_fixedname_t p_namef;
   3847   1.1  christos 	dns_name_t *p_name;
   3848   1.1  christos 	dns_rpz_zbits_t zbits;
   3849   1.1  christos 	dns_rpz_num_t rpz_num;
   3850   1.1  christos 	dns_zone_t *p_zone;
   3851   1.1  christos 	dns_db_t *p_db;
   3852   1.1  christos 	dns_dbversion_t *p_version;
   3853   1.1  christos 	dns_dbnode_t *p_node;
   3854   1.1  christos 	dns_rpz_policy_t policy;
   3855   1.1  christos 	isc_result_t result;
   3856   1.1  christos 
   3857   1.1  christos #ifndef USE_DNSRPS
   3858   1.1  christos 	UNUSED(recursed);
   3859   1.9  christos #endif /* ifndef USE_DNSRPS */
   3860   1.1  christos 
   3861   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name");
   3862   1.1  christos 
   3863   1.1  christos 	rpzs = client->view->rpzs;
   3864   1.1  christos 	st = client->query.rpz_st;
   3865   1.1  christos 
   3866   1.1  christos #ifdef USE_DNSRPS
   3867   1.1  christos 	if (st->popt.dnsrps_enabled) {
   3868   1.1  christos 		return (dnsrps_rewrite_name(client, trig_name, recursed,
   3869   1.9  christos 					    rpz_type, rdatasetp));
   3870   1.1  christos 	}
   3871   1.9  christos #endif /* ifdef USE_DNSRPS */
   3872   1.1  christos 
   3873   1.1  christos 	zbits = rpz_get_zbits(client, qtype, rpz_type);
   3874   1.1  christos 	zbits &= allowed_zbits;
   3875   1.9  christos 	if (zbits == 0) {
   3876   1.1  christos 		return (ISC_R_SUCCESS);
   3877   1.9  christos 	}
   3878   1.1  christos 
   3879   1.1  christos 	/*
   3880   1.1  christos 	 * Use the summary database to find the bit mask of policy zones
   3881   1.1  christos 	 * with policies for this trigger name. We do this even if there
   3882   1.1  christos 	 * is only one eligible policy zone so that wildcard triggers
   3883   1.1  christos 	 * are matched correctly, and not into their parent.
   3884   1.1  christos 	 */
   3885   1.1  christos 	zbits = dns_rpz_find_name(rpzs, rpz_type, zbits, trig_name);
   3886   1.9  christos 	if (zbits == 0) {
   3887   1.1  christos 		return (ISC_R_SUCCESS);
   3888   1.9  christos 	}
   3889   1.1  christos 
   3890   1.1  christos 	p_name = dns_fixedname_initname(&p_namef);
   3891   1.1  christos 
   3892   1.1  christos 	p_zone = NULL;
   3893   1.1  christos 	p_db = NULL;
   3894   1.1  christos 	p_node = NULL;
   3895   1.1  christos 
   3896   1.1  christos 	/*
   3897   1.1  christos 	 * Check the trigger name in every policy zone that the summary data
   3898   1.1  christos 	 * says has a hit for the trigger name.
   3899   1.1  christos 	 * Most of the time there are no eligible zones and the summary data
   3900   1.1  christos 	 * keeps us from getting this far.
   3901   1.1  christos 	 * We check the most eligible zone first and so usually check only
   3902   1.1  christos 	 * one policy zone.
   3903   1.1  christos 	 */
   3904   1.1  christos 	for (rpz_num = 0; zbits != 0; ++rpz_num, zbits >>= 1) {
   3905   1.9  christos 		if ((zbits & 1) == 0) {
   3906   1.1  christos 			continue;
   3907   1.9  christos 		}
   3908   1.1  christos 
   3909   1.1  christos 		/*
   3910   1.1  christos 		 * Do not check policy zones that cannot replace a previously
   3911   1.1  christos 		 * found policy.
   3912   1.1  christos 		 */
   3913   1.1  christos 		rpz = rpzs->zones[rpz_num];
   3914   1.1  christos 		if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   3915   1.9  christos 			if (st->m.rpz->num < rpz->num) {
   3916   1.1  christos 				break;
   3917   1.9  christos 			}
   3918   1.9  christos 			if (st->m.rpz->num == rpz->num && st->m.type < rpz_type)
   3919   1.9  christos 			{
   3920   1.1  christos 				break;
   3921   1.9  christos 			}
   3922   1.1  christos 		}
   3923   1.1  christos 
   3924   1.1  christos 		/*
   3925   1.1  christos 		 * Get the next policy zone's record for this trigger name.
   3926   1.1  christos 		 */
   3927   1.1  christos 		result = rpz_get_p_name(client, p_name, rpz, rpz_type,
   3928   1.1  christos 					trig_name);
   3929   1.9  christos 		if (result != ISC_R_SUCCESS) {
   3930   1.1  christos 			continue;
   3931   1.9  christos 		}
   3932   1.9  christos 		result = rpz_find_p(client, trig_name, qtype, p_name, rpz,
   3933   1.9  christos 				    rpz_type, &p_zone, &p_db, &p_version,
   3934   1.9  christos 				    &p_node, rdatasetp, &policy);
   3935   1.1  christos 		switch (result) {
   3936   1.1  christos 		case DNS_R_NXDOMAIN:
   3937   1.1  christos 			/*
   3938   1.1  christos 			 * Continue after a missing policy record
   3939   1.1  christos 			 * contrary to the summary data.  The summary
   3940   1.1  christos 			 * data can out of date during races with and among
   3941   1.1  christos 			 * policy zone updates.
   3942   1.1  christos 			 */
   3943   1.9  christos 			CTRACE(ISC_LOG_ERROR, "rpz_rewrite_name: mismatched "
   3944   1.9  christos 					      "summary data; "
   3945   1.9  christos 					      "continuing");
   3946   1.1  christos 			continue;
   3947   1.1  christos 		case DNS_R_SERVFAIL:
   3948   1.1  christos 			rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   3949   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3950   1.1  christos 			return (DNS_R_SERVFAIL);
   3951   1.1  christos 		default:
   3952   1.1  christos 			/*
   3953   1.1  christos 			 * With more than one applicable policy, prefer
   3954   1.1  christos 			 * the earliest configured policy,
   3955   1.1  christos 			 * client-IP over QNAME over IP over NSDNAME over NSIP,
   3956   1.1  christos 			 * and the smallest name.
   3957   1.1  christos 			 * We known st->m.rpz->num >= rpz->num  and either
   3958   1.1  christos 			 * st->m.rpz->num > rpz->num or st->m.type >= rpz_type
   3959   1.1  christos 			 */
   3960   1.1  christos 			if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   3961   1.1  christos 			    rpz->num == st->m.rpz->num &&
   3962   1.1  christos 			    (st->m.type < rpz_type ||
   3963   1.1  christos 			     (st->m.type == rpz_type &&
   3964   1.1  christos 			      0 >= dns_name_compare(p_name, st->p_name))))
   3965   1.9  christos 			{
   3966   1.1  christos 				continue;
   3967   1.9  christos 			}
   3968   1.4  christos 
   3969   1.1  christos 			if (rpz->policy != DNS_RPZ_POLICY_DISABLED) {
   3970   1.9  christos 				CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name: "
   3971   1.9  christos 							 "rpz_save_p");
   3972   1.9  christos 				rpz_save_p(st, rpz, rpz_type, policy, p_name, 0,
   3973   1.9  christos 					   result, &p_zone, &p_db, &p_node,
   3974   1.1  christos 					   rdatasetp, p_version);
   3975   1.1  christos 				/*
   3976   1.1  christos 				 * After a hit, higher numbered policy zones
   3977   1.1  christos 				 * are irrelevant
   3978   1.1  christos 				 */
   3979   1.1  christos 				rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   3980   1.1  christos 				return (ISC_R_SUCCESS);
   3981   1.1  christos 			}
   3982   1.1  christos 			/*
   3983   1.1  christos 			 * Log DNS_RPZ_POLICY_DISABLED zones
   3984   1.1  christos 			 * and try the next eligible policy zone.
   3985   1.1  christos 			 */
   3986   1.9  christos 			rpz_log_rewrite(client, true, policy, rpz_type, p_zone,
   3987   1.9  christos 					p_name, NULL, rpz_num);
   3988   1.1  christos 			break;
   3989   1.1  christos 		}
   3990   1.1  christos 	}
   3991   1.1  christos 
   3992   1.1  christos 	rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   3993   1.1  christos 	return (ISC_R_SUCCESS);
   3994   1.1  christos }
   3995   1.1  christos 
   3996   1.1  christos static void
   3997   1.1  christos rpz_rewrite_ns_skip(ns_client_t *client, dns_name_t *nsname,
   3998   1.9  christos 		    isc_result_t result, int level, const char *str) {
   3999   1.1  christos 	dns_rpz_st_t *st;
   4000   1.1  christos 
   4001   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ns_skip");
   4002   1.1  christos 
   4003   1.1  christos 	st = client->query.rpz_st;
   4004   1.1  christos 
   4005   1.9  christos 	if (str != NULL) {
   4006   1.9  christos 		rpz_log_fail_helper(client, level, nsname, DNS_RPZ_TYPE_NSIP,
   4007   1.9  christos 				    DNS_RPZ_TYPE_NSDNAME, str, result);
   4008   1.9  christos 	}
   4009   1.1  christos 	if (st->r.ns_rdataset != NULL &&
   4010  1.16  christos 	    dns_rdataset_isassociated(st->r.ns_rdataset))
   4011  1.16  christos 	{
   4012   1.1  christos 		dns_rdataset_disassociate(st->r.ns_rdataset);
   4013   1.9  christos 	}
   4014   1.1  christos 
   4015   1.1  christos 	st->r.label--;
   4016   1.1  christos }
   4017   1.1  christos 
   4018   1.1  christos /*
   4019   1.1  christos  * RPZ query result types
   4020   1.1  christos  */
   4021   1.1  christos typedef enum {
   4022   1.1  christos 	qresult_type_done = 0,
   4023   1.1  christos 	qresult_type_restart = 1,
   4024   1.1  christos 	qresult_type_recurse = 2
   4025   1.1  christos } qresult_type_t;
   4026   1.1  christos 
   4027   1.1  christos /*
   4028   1.1  christos  * Look for response policy zone QNAME, NSIP, and NSDNAME rewriting.
   4029   1.1  christos  */
   4030   1.1  christos static isc_result_t
   4031   1.9  christos rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype, isc_result_t qresult,
   4032   1.9  christos 	    bool resuming, dns_rdataset_t *ordataset, dns_rdataset_t *osigset) {
   4033   1.1  christos 	dns_rpz_zones_t *rpzs;
   4034   1.1  christos 	dns_rpz_st_t *st;
   4035   1.1  christos 	dns_rdataset_t *rdataset;
   4036   1.1  christos 	dns_fixedname_t nsnamef;
   4037   1.1  christos 	dns_name_t *nsname;
   4038   1.1  christos 	qresult_type_t qresult_type;
   4039   1.1  christos 	dns_rpz_zbits_t zbits;
   4040   1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   4041   1.1  christos 	dns_rpz_have_t have;
   4042   1.1  christos 	dns_rpz_popt_t popt;
   4043   1.1  christos 	int rpz_ver;
   4044  1.15  christos 	unsigned int options;
   4045   1.1  christos #ifdef USE_DNSRPS
   4046   1.1  christos 	librpz_emsg_t emsg;
   4047   1.9  christos #endif /* ifdef USE_DNSRPS */
   4048   1.1  christos 
   4049   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite");
   4050   1.1  christos 
   4051   1.1  christos 	rpzs = client->view->rpzs;
   4052   1.1  christos 	st = client->query.rpz_st;
   4053   1.1  christos 
   4054  1.13  christos 	if (rpzs == NULL) {
   4055  1.13  christos 		return (ISC_R_NOTFOUND);
   4056  1.13  christos 	}
   4057  1.13  christos 	if (st != NULL && (st->state & DNS_RPZ_REWRITTEN) != 0) {
   4058  1.13  christos 		return (DNS_R_DISALLOWED);
   4059  1.13  christos 	}
   4060  1.13  christos 	if (RECURSING(client)) {
   4061   1.1  christos 		return (DNS_R_DISALLOWED);
   4062   1.9  christos 	}
   4063   1.1  christos 
   4064   1.1  christos 	RWLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4065   1.1  christos 	if ((rpzs->p.num_zones == 0 && !rpzs->p.dnsrps_enabled) ||
   4066   1.1  christos 	    (!RECURSIONOK(client) && rpzs->p.no_rd_ok == 0) ||
   4067   1.1  christos 	    !rpz_ck_dnssec(client, qresult, ordataset, osigset))
   4068   1.1  christos 	{
   4069   1.1  christos 		RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4070   1.1  christos 		return (DNS_R_DISALLOWED);
   4071   1.1  christos 	}
   4072   1.1  christos 	have = rpzs->have;
   4073   1.1  christos 	popt = rpzs->p;
   4074   1.1  christos 	rpz_ver = rpzs->rpz_ver;
   4075   1.1  christos 	RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4076   1.1  christos 
   4077   1.1  christos #ifndef USE_DNSRPS
   4078   1.1  christos 	INSIST(!popt.dnsrps_enabled);
   4079   1.9  christos #endif /* ifndef USE_DNSRPS */
   4080   1.1  christos 
   4081   1.1  christos 	if (st == NULL) {
   4082   1.1  christos 		st = isc_mem_get(client->mctx, sizeof(*st));
   4083   1.1  christos 		st->state = 0;
   4084   1.1  christos 		st->rpsdb = NULL;
   4085   1.1  christos 	}
   4086   1.1  christos 	if (st->state == 0) {
   4087   1.1  christos 		st->state |= DNS_RPZ_ACTIVE;
   4088   1.1  christos 		memset(&st->m, 0, sizeof(st->m));
   4089   1.1  christos 		st->m.type = DNS_RPZ_TYPE_BAD;
   4090   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_MISS;
   4091   1.1  christos 		st->m.ttl = ~0;
   4092   1.1  christos 		memset(&st->r, 0, sizeof(st->r));
   4093   1.1  christos 		memset(&st->q, 0, sizeof(st->q));
   4094   1.1  christos 		st->p_name = dns_fixedname_initname(&st->_p_namef);
   4095   1.1  christos 		st->r_name = dns_fixedname_initname(&st->_r_namef);
   4096   1.1  christos 		st->fname = dns_fixedname_initname(&st->_fnamef);
   4097   1.1  christos 		st->have = have;
   4098   1.1  christos 		st->popt = popt;
   4099   1.1  christos 		st->rpz_ver = rpz_ver;
   4100   1.1  christos 		client->query.rpz_st = st;
   4101   1.1  christos #ifdef USE_DNSRPS
   4102   1.1  christos 		if (popt.dnsrps_enabled) {
   4103   1.1  christos 			if (st->rpsdb != NULL) {
   4104   1.1  christos 				dns_db_detach(&st->rpsdb);
   4105   1.1  christos 			}
   4106   1.9  christos 			result = dns_dnsrps_rewrite_init(
   4107   1.9  christos 				&emsg, st, rpzs, client->query.qname,
   4108   1.9  christos 				client->mctx, RECURSIONOK(client));
   4109   1.1  christos 			if (result != ISC_R_SUCCESS) {
   4110   1.9  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   4111   1.9  christos 					     DNS_RPZ_TYPE_QNAME, emsg.c,
   4112   1.9  christos 					     result);
   4113   1.1  christos 				st->m.policy = DNS_RPZ_POLICY_ERROR;
   4114   1.1  christos 				return (ISC_R_SUCCESS);
   4115   1.1  christos 			}
   4116   1.1  christos 		}
   4117   1.9  christos #endif /* ifdef USE_DNSRPS */
   4118   1.1  christos 	}
   4119   1.1  christos 
   4120   1.1  christos 	/*
   4121   1.1  christos 	 * There is nothing to rewrite if the main query failed.
   4122   1.1  christos 	 */
   4123   1.1  christos 	switch (qresult) {
   4124   1.1  christos 	case ISC_R_SUCCESS:
   4125   1.1  christos 	case DNS_R_GLUE:
   4126   1.1  christos 	case DNS_R_ZONECUT:
   4127   1.1  christos 		qresult_type = qresult_type_done;
   4128   1.1  christos 		break;
   4129   1.1  christos 	case DNS_R_EMPTYNAME:
   4130   1.1  christos 	case DNS_R_NXRRSET:
   4131   1.1  christos 	case DNS_R_NXDOMAIN:
   4132   1.1  christos 	case DNS_R_EMPTYWILD:
   4133   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   4134   1.1  christos 	case DNS_R_NCACHENXRRSET:
   4135   1.3  christos 	case DNS_R_COVERINGNSEC:
   4136   1.1  christos 	case DNS_R_CNAME:
   4137   1.1  christos 	case DNS_R_DNAME:
   4138   1.1  christos 		qresult_type = qresult_type_restart;
   4139   1.1  christos 		break;
   4140   1.1  christos 	case DNS_R_DELEGATION:
   4141   1.1  christos 	case ISC_R_NOTFOUND:
   4142   1.1  christos 		/*
   4143   1.1  christos 		 * If recursion is on, do only tentative rewriting.
   4144   1.1  christos 		 * If recursion is off, this the normal and only time we
   4145   1.1  christos 		 * can rewrite.
   4146   1.1  christos 		 */
   4147   1.9  christos 		if (RECURSIONOK(client)) {
   4148   1.1  christos 			qresult_type = qresult_type_recurse;
   4149   1.9  christos 		} else {
   4150   1.1  christos 			qresult_type = qresult_type_restart;
   4151   1.9  christos 		}
   4152   1.1  christos 		break;
   4153   1.1  christos 	case ISC_R_FAILURE:
   4154   1.1  christos 	case ISC_R_TIMEDOUT:
   4155  1.22  christos 	case ISC_R_CANCELED:
   4156   1.1  christos 	case DNS_R_BROKENCHAIN:
   4157   1.1  christos 		rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, NULL,
   4158   1.1  christos 			     DNS_RPZ_TYPE_QNAME,
   4159   1.3  christos 			     "stop on qresult in rpz_rewrite()", qresult);
   4160   1.1  christos 		return (ISC_R_SUCCESS);
   4161   1.1  christos 	default:
   4162   1.1  christos 		rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, NULL,
   4163   1.1  christos 			     DNS_RPZ_TYPE_QNAME,
   4164   1.3  christos 			     "stop on unrecognized qresult in rpz_rewrite()",
   4165   1.1  christos 			     qresult);
   4166   1.1  christos 		return (ISC_R_SUCCESS);
   4167   1.1  christos 	}
   4168   1.1  christos 
   4169   1.1  christos 	rdataset = NULL;
   4170   1.1  christos 
   4171   1.1  christos 	if ((st->state & (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) !=
   4172   1.1  christos 	    (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME))
   4173   1.1  christos 	{
   4174   1.1  christos 		isc_netaddr_t netaddr;
   4175   1.1  christos 		dns_rpz_zbits_t allowed;
   4176   1.1  christos 
   4177   1.1  christos 		if (!st->popt.dnsrps_enabled &&
   4178  1.16  christos 		    qresult_type == qresult_type_recurse)
   4179  1.16  christos 		{
   4180   1.1  christos 			/*
   4181   1.1  christos 			 * This request needs recursion that has not been done.
   4182   1.1  christos 			 * Get bits for the policy zones that do not need
   4183   1.1  christos 			 * to wait for the results of recursion.
   4184   1.1  christos 			 */
   4185   1.1  christos 			allowed = st->have.qname_skip_recurse;
   4186   1.1  christos 			if (allowed == 0) {
   4187   1.1  christos 				return (ISC_R_SUCCESS);
   4188   1.1  christos 			}
   4189   1.1  christos 		} else {
   4190   1.1  christos 			allowed = DNS_RPZ_ALL_ZBITS;
   4191   1.1  christos 		}
   4192   1.1  christos 
   4193   1.1  christos 		/*
   4194   1.1  christos 		 * Check once for triggers for the client IP address.
   4195   1.1  christos 		 */
   4196   1.1  christos 		if ((st->state & DNS_RPZ_DONE_CLIENT_IP) == 0) {
   4197   1.1  christos 			zbits = rpz_get_zbits(client, dns_rdatatype_none,
   4198   1.1  christos 					      DNS_RPZ_TYPE_CLIENT_IP);
   4199   1.1  christos 			zbits &= allowed;
   4200   1.1  christos 			if (zbits != 0) {
   4201   1.1  christos 				isc_netaddr_fromsockaddr(&netaddr,
   4202   1.1  christos 							 &client->peeraddr);
   4203   1.1  christos 				result = rpz_rewrite_ip(client, &netaddr, qtype,
   4204   1.1  christos 							DNS_RPZ_TYPE_CLIENT_IP,
   4205   1.1  christos 							zbits, &rdataset);
   4206   1.9  christos 				if (result != ISC_R_SUCCESS) {
   4207   1.1  christos 					goto cleanup;
   4208   1.9  christos 				}
   4209   1.1  christos 			}
   4210   1.1  christos 		}
   4211   1.1  christos 
   4212   1.1  christos 		/*
   4213   1.1  christos 		 * Check triggers for the query name if this is the first time
   4214   1.1  christos 		 * for the current qname.
   4215   1.1  christos 		 * There is a first time for each name in a CNAME chain
   4216   1.1  christos 		 */
   4217   1.1  christos 		if ((st->state & DNS_RPZ_DONE_QNAME) == 0) {
   4218   1.3  christos 			bool norec = (qresult_type != qresult_type_recurse);
   4219   1.1  christos 			result = rpz_rewrite_name(client, client->query.qname,
   4220   1.1  christos 						  qtype, DNS_RPZ_TYPE_QNAME,
   4221   1.9  christos 						  allowed, norec, &rdataset);
   4222   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4223   1.1  christos 				goto cleanup;
   4224   1.9  christos 			}
   4225   1.1  christos 
   4226   1.1  christos 			/*
   4227   1.1  christos 			 * Check IPv4 addresses in A RRs next.
   4228   1.1  christos 			 * Reset to the start of the NS names.
   4229   1.1  christos 			 */
   4230   1.1  christos 			st->r.label = dns_name_countlabels(client->query.qname);
   4231   1.1  christos 			st->state &= ~(DNS_RPZ_DONE_QNAME_IP |
   4232   1.1  christos 				       DNS_RPZ_DONE_IPv4);
   4233   1.1  christos 		}
   4234   1.1  christos 
   4235   1.1  christos 		/*
   4236   1.1  christos 		 * Quit if this was an attempt to find a qname or
   4237   1.1  christos 		 * client-IP trigger before recursion.
   4238   1.1  christos 		 * We will be back if no pre-recursion triggers hit.
   4239   1.1  christos 		 * For example, consider 2 policy zones, both with qname and
   4240   1.1  christos 		 * IP address triggers.  If the qname misses the 1st zone,
   4241   1.1  christos 		 * then we cannot know whether a hit for the qname in the
   4242   1.1  christos 		 * 2nd zone matters until after recursing to get the A RRs and
   4243   1.1  christos 		 * testing them in the first zone.
   4244   1.1  christos 		 * Do not bother saving the work from this attempt,
   4245   1.9  christos 		 * because recursion is so slow.
   4246   1.1  christos 		 */
   4247   1.9  christos 		if (qresult_type == qresult_type_recurse) {
   4248   1.1  christos 			goto cleanup;
   4249   1.9  christos 		}
   4250   1.1  christos 
   4251   1.1  christos 		/*
   4252   1.1  christos 		 * DNS_RPZ_DONE_QNAME but not DNS_RPZ_DONE_CLIENT_IP
   4253   1.1  christos 		 * is reset at the end of dealing with each CNAME.
   4254   1.1  christos 		 */
   4255   1.1  christos 		st->state |= (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME);
   4256   1.1  christos 	}
   4257   1.1  christos 
   4258   1.1  christos 	/*
   4259   1.1  christos 	 * Check known IP addresses for the query name if the database lookup
   4260   1.1  christos 	 * resulted in some addresses (qresult_type == qresult_type_done)
   4261   1.1  christos 	 * and if we have not already checked them.
   4262   1.1  christos 	 * Any recursion required for the query has already happened.
   4263   1.1  christos 	 * Do not check addresses that will not be in the ANSWER section.
   4264   1.1  christos 	 */
   4265   1.1  christos 	if ((st->state & DNS_RPZ_DONE_QNAME_IP) == 0 &&
   4266   1.1  christos 	    qresult_type == qresult_type_done &&
   4267   1.9  christos 	    rpz_get_zbits(client, qtype, DNS_RPZ_TYPE_IP) != 0)
   4268   1.9  christos 	{
   4269   1.9  christos 		result = rpz_rewrite_ip_rrsets(client, client->query.qname,
   4270   1.9  christos 					       qtype, DNS_RPZ_TYPE_IP,
   4271   1.1  christos 					       &rdataset, resuming);
   4272   1.9  christos 		if (result != ISC_R_SUCCESS) {
   4273   1.1  christos 			goto cleanup;
   4274   1.9  christos 		}
   4275   1.1  christos 		/*
   4276   1.1  christos 		 * We are finished checking the IP addresses for the qname.
   4277   1.9  christos 		 * Start with IPv4 if we will check NS IP addresses.
   4278   1.1  christos 		 */
   4279   1.1  christos 		st->state |= DNS_RPZ_DONE_QNAME_IP;
   4280   1.1  christos 		st->state &= ~DNS_RPZ_DONE_IPv4;
   4281   1.1  christos 	}
   4282   1.1  christos 
   4283   1.1  christos 	/*
   4284   1.1  christos 	 * Stop looking for rules if there are none of the other kinds
   4285   1.1  christos 	 * that could override what we already have.
   4286   1.1  christos 	 */
   4287   1.9  christos 	if (rpz_get_zbits(client, dns_rdatatype_any, DNS_RPZ_TYPE_NSDNAME) ==
   4288   1.9  christos 		    0 &&
   4289   1.9  christos 	    rpz_get_zbits(client, dns_rdatatype_any, DNS_RPZ_TYPE_NSIP) == 0)
   4290   1.9  christos 	{
   4291   1.1  christos 		result = ISC_R_SUCCESS;
   4292   1.1  christos 		goto cleanup;
   4293   1.1  christos 	}
   4294   1.1  christos 
   4295   1.1  christos 	dns_fixedname_init(&nsnamef);
   4296   1.1  christos 	dns_name_clone(client->query.qname, dns_fixedname_name(&nsnamef));
   4297  1.16  christos 	options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   4298   1.1  christos 	while (st->r.label > st->popt.min_ns_labels) {
   4299  1.15  christos 		bool was_glue = false;
   4300   1.1  christos 		/*
   4301   1.1  christos 		 * Get NS rrset for each domain in the current qname.
   4302   1.1  christos 		 */
   4303   1.1  christos 		if (st->r.label == dns_name_countlabels(client->query.qname)) {
   4304   1.1  christos 			nsname = client->query.qname;
   4305   1.1  christos 		} else {
   4306   1.1  christos 			nsname = dns_fixedname_name(&nsnamef);
   4307   1.9  christos 			dns_name_split(client->query.qname, st->r.label, NULL,
   4308   1.9  christos 				       nsname);
   4309   1.1  christos 		}
   4310   1.1  christos 		if (st->r.ns_rdataset == NULL ||
   4311  1.16  christos 		    !dns_rdataset_isassociated(st->r.ns_rdataset))
   4312  1.16  christos 		{
   4313   1.1  christos 			dns_db_t *db = NULL;
   4314   1.1  christos 			result = rpz_rrset_find(client, nsname,
   4315  1.15  christos 						dns_rdatatype_ns, options,
   4316   1.9  christos 						DNS_RPZ_TYPE_NSDNAME, &db, NULL,
   4317   1.9  christos 						&st->r.ns_rdataset, resuming);
   4318   1.9  christos 			if (db != NULL) {
   4319   1.1  christos 				dns_db_detach(&db);
   4320   1.9  christos 			}
   4321   1.9  christos 			if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
   4322   1.1  christos 				goto cleanup;
   4323   1.9  christos 			}
   4324   1.1  christos 			switch (result) {
   4325  1.15  christos 			case DNS_R_GLUE:
   4326  1.15  christos 				was_glue = true;
   4327  1.15  christos 				FALLTHROUGH;
   4328   1.1  christos 			case ISC_R_SUCCESS:
   4329   1.1  christos 				result = dns_rdataset_first(st->r.ns_rdataset);
   4330   1.9  christos 				if (result != ISC_R_SUCCESS) {
   4331   1.1  christos 					goto cleanup;
   4332   1.9  christos 				}
   4333   1.1  christos 				st->state &= ~(DNS_RPZ_DONE_NSDNAME |
   4334   1.1  christos 					       DNS_RPZ_DONE_IPv4);
   4335   1.1  christos 				break;
   4336   1.1  christos 			case DNS_R_DELEGATION:
   4337   1.1  christos 			case DNS_R_DUPLICATE:
   4338   1.1  christos 			case DNS_R_DROP:
   4339   1.1  christos 				goto cleanup;
   4340   1.1  christos 			case DNS_R_EMPTYNAME:
   4341   1.1  christos 			case DNS_R_NXRRSET:
   4342   1.1  christos 			case DNS_R_EMPTYWILD:
   4343   1.1  christos 			case DNS_R_NXDOMAIN:
   4344   1.1  christos 			case DNS_R_NCACHENXDOMAIN:
   4345   1.1  christos 			case DNS_R_NCACHENXRRSET:
   4346   1.1  christos 			case ISC_R_NOTFOUND:
   4347   1.1  christos 			case DNS_R_CNAME:
   4348   1.1  christos 			case DNS_R_DNAME:
   4349   1.9  christos 				rpz_rewrite_ns_skip(client, nsname, result, 0,
   4350   1.9  christos 						    NULL);
   4351   1.1  christos 				continue;
   4352   1.1  christos 			case ISC_R_TIMEDOUT:
   4353   1.1  christos 			case DNS_R_BROKENCHAIN:
   4354   1.1  christos 			case ISC_R_FAILURE:
   4355   1.1  christos 				rpz_rewrite_ns_skip(client, nsname, result,
   4356   1.9  christos 						    DNS_RPZ_DEBUG_LEVEL3,
   4357   1.9  christos 						    " NS rpz_rrset_find()");
   4358   1.1  christos 				continue;
   4359   1.1  christos 			default:
   4360   1.1  christos 				rpz_rewrite_ns_skip(client, nsname, result,
   4361   1.9  christos 						    DNS_RPZ_INFO_LEVEL,
   4362   1.9  christos 						    " unrecognized NS"
   4363   1.9  christos 						    " rpz_rrset_find()");
   4364   1.1  christos 				continue;
   4365   1.1  christos 			}
   4366   1.1  christos 		}
   4367  1.15  christos 
   4368   1.1  christos 		/*
   4369   1.1  christos 		 * Check all NS names.
   4370   1.1  christos 		 */
   4371   1.1  christos 		do {
   4372   1.1  christos 			dns_rdata_ns_t ns;
   4373   1.1  christos 			dns_rdata_t nsrdata = DNS_RDATA_INIT;
   4374   1.1  christos 
   4375   1.1  christos 			dns_rdataset_current(st->r.ns_rdataset, &nsrdata);
   4376   1.1  christos 			result = dns_rdata_tostruct(&nsrdata, &ns, NULL);
   4377   1.3  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4378   1.1  christos 			dns_rdata_reset(&nsrdata);
   4379   1.3  christos 
   4380   1.1  christos 			/*
   4381   1.1  christos 			 * Do nothing about "NS ."
   4382   1.1  christos 			 */
   4383   1.1  christos 			if (dns_name_equal(&ns.name, dns_rootname)) {
   4384   1.1  christos 				dns_rdata_freestruct(&ns);
   4385   1.1  christos 				result = dns_rdataset_next(st->r.ns_rdataset);
   4386   1.1  christos 				continue;
   4387   1.1  christos 			}
   4388   1.1  christos 			/*
   4389   1.1  christos 			 * Check this NS name if we did not handle it
   4390   1.1  christos 			 * during a previous recursion.
   4391   1.1  christos 			 */
   4392   1.1  christos 			if ((st->state & DNS_RPZ_DONE_NSDNAME) == 0) {
   4393   1.9  christos 				result = rpz_rewrite_name(
   4394   1.9  christos 					client, &ns.name, qtype,
   4395   1.9  christos 					DNS_RPZ_TYPE_NSDNAME, DNS_RPZ_ALL_ZBITS,
   4396   1.9  christos 					true, &rdataset);
   4397   1.1  christos 				if (result != ISC_R_SUCCESS) {
   4398   1.1  christos 					dns_rdata_freestruct(&ns);
   4399   1.1  christos 					goto cleanup;
   4400   1.1  christos 				}
   4401   1.1  christos 				st->state |= DNS_RPZ_DONE_NSDNAME;
   4402   1.1  christos 			}
   4403   1.1  christos 			/*
   4404   1.1  christos 			 * Check all IP addresses for this NS name.
   4405   1.1  christos 			 */
   4406   1.1  christos 			result = rpz_rewrite_ip_rrsets(client, &ns.name, qtype,
   4407   1.1  christos 						       DNS_RPZ_TYPE_NSIP,
   4408   1.1  christos 						       &rdataset, resuming);
   4409   1.1  christos 			dns_rdata_freestruct(&ns);
   4410   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4411   1.1  christos 				goto cleanup;
   4412   1.9  christos 			}
   4413   1.1  christos 			st->state &= ~(DNS_RPZ_DONE_NSDNAME |
   4414   1.1  christos 				       DNS_RPZ_DONE_IPv4);
   4415   1.1  christos 			result = dns_rdataset_next(st->r.ns_rdataset);
   4416   1.1  christos 		} while (result == ISC_R_SUCCESS);
   4417   1.1  christos 		dns_rdataset_disassociate(st->r.ns_rdataset);
   4418  1.15  christos 
   4419  1.15  christos 		/*
   4420  1.15  christos 		 * If we just checked a glue NS RRset retry without allowing
   4421  1.15  christos 		 * glue responses, otherwise setup for the next name.
   4422  1.15  christos 		 */
   4423  1.15  christos 		if (was_glue) {
   4424  1.16  christos 			options = client->query.dboptions;
   4425  1.15  christos 		} else {
   4426  1.16  christos 			options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   4427  1.15  christos 			st->r.label--;
   4428  1.15  christos 		}
   4429   1.1  christos 
   4430   1.1  christos 		if (rpz_get_zbits(client, dns_rdatatype_any,
   4431   1.1  christos 				  DNS_RPZ_TYPE_NSDNAME) == 0 &&
   4432   1.1  christos 		    rpz_get_zbits(client, dns_rdatatype_any,
   4433   1.1  christos 				  DNS_RPZ_TYPE_NSIP) == 0)
   4434   1.9  christos 		{
   4435   1.1  christos 			break;
   4436   1.9  christos 		}
   4437   1.1  christos 	}
   4438   1.1  christos 
   4439   1.1  christos 	/*
   4440   1.1  christos 	 * Use the best hit, if any.
   4441   1.1  christos 	 */
   4442   1.1  christos 	result = ISC_R_SUCCESS;
   4443   1.1  christos 
   4444   1.1  christos cleanup:
   4445   1.1  christos #ifdef USE_DNSRPS
   4446   1.9  christos 	if (st->popt.dnsrps_enabled && st->m.policy != DNS_RPZ_POLICY_ERROR &&
   4447   1.1  christos 	    !dnsrps_set_p(&emsg, client, st, qtype, &rdataset,
   4448   1.3  christos 			  (qresult_type != qresult_type_recurse)))
   4449   1.1  christos 	{
   4450   1.1  christos 		rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   4451   1.1  christos 			     DNS_RPZ_TYPE_BAD, emsg.c, DNS_R_SERVFAIL);
   4452   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   4453   1.1  christos 	}
   4454   1.9  christos #endif /* ifdef USE_DNSRPS */
   4455   1.1  christos 	if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   4456   1.1  christos 	    st->m.policy != DNS_RPZ_POLICY_ERROR &&
   4457   1.1  christos 	    st->m.rpz->policy != DNS_RPZ_POLICY_GIVEN)
   4458   1.9  christos 	{
   4459   1.1  christos 		st->m.policy = st->m.rpz->policy;
   4460   1.9  christos 	}
   4461   1.1  christos 	if (st->m.policy == DNS_RPZ_POLICY_MISS ||
   4462   1.1  christos 	    st->m.policy == DNS_RPZ_POLICY_PASSTHRU ||
   4463   1.9  christos 	    st->m.policy == DNS_RPZ_POLICY_ERROR)
   4464   1.9  christos 	{
   4465   1.1  christos 		if (st->m.policy == DNS_RPZ_POLICY_PASSTHRU &&
   4466  1.16  christos 		    result != DNS_R_DELEGATION)
   4467  1.16  christos 		{
   4468   1.9  christos 			rpz_log_rewrite(client, false, st->m.policy, st->m.type,
   4469   1.9  christos 					st->m.zone, st->p_name, NULL,
   4470   1.9  christos 					st->m.rpz->num);
   4471   1.9  christos 		}
   4472   1.1  christos 		rpz_match_clear(st);
   4473   1.1  christos 	}
   4474   1.1  christos 	if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
   4475   1.1  christos 		CTRACE(ISC_LOG_ERROR, "SERVFAIL due to RPZ policy");
   4476   1.1  christos 		st->m.type = DNS_RPZ_TYPE_BAD;
   4477   1.1  christos 		result = DNS_R_SERVFAIL;
   4478   1.1  christos 	}
   4479   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   4480   1.9  christos 	if ((st->state & DNS_RPZ_RECURSING) == 0) {
   4481   1.1  christos 		rpz_clean(NULL, &st->r.db, NULL, &st->r.ns_rdataset);
   4482   1.9  christos 	}
   4483   1.1  christos 
   4484   1.1  christos 	return (result);
   4485   1.1  christos }
   4486   1.1  christos 
   4487   1.1  christos /*
   4488   1.1  christos  * See if response policy zone rewriting is allowed by a lack of interest
   4489   1.1  christos  * by the client in DNSSEC or a lack of signatures.
   4490   1.1  christos  */
   4491   1.3  christos static bool
   4492   1.1  christos rpz_ck_dnssec(ns_client_t *client, isc_result_t qresult,
   4493   1.9  christos 	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
   4494   1.1  christos 	dns_fixedname_t fixed;
   4495   1.1  christos 	dns_name_t *found;
   4496   1.1  christos 	dns_rdataset_t trdataset;
   4497   1.1  christos 	dns_rdatatype_t type;
   4498   1.1  christos 	isc_result_t result;
   4499   1.1  christos 
   4500   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_ck_dnssec");
   4501   1.1  christos 
   4502   1.9  christos 	if (client->view->rpzs->p.break_dnssec || !WANTDNSSEC(client)) {
   4503   1.3  christos 		return (true);
   4504   1.9  christos 	}
   4505   1.1  christos 
   4506   1.1  christos 	/*
   4507   1.1  christos 	 * We do not know if there are signatures if we have not recursed
   4508   1.1  christos 	 * for them.
   4509   1.1  christos 	 */
   4510   1.9  christos 	if (qresult == DNS_R_DELEGATION || qresult == ISC_R_NOTFOUND) {
   4511   1.3  christos 		return (false);
   4512   1.9  christos 	}
   4513   1.1  christos 
   4514   1.9  christos 	if (sigrdataset == NULL) {
   4515   1.3  christos 		return (true);
   4516   1.9  christos 	}
   4517   1.9  christos 	if (dns_rdataset_isassociated(sigrdataset)) {
   4518   1.3  christos 		return (false);
   4519   1.9  christos 	}
   4520   1.1  christos 
   4521   1.1  christos 	/*
   4522   1.1  christos 	 * We are happy to rewrite nothing.
   4523   1.1  christos 	 */
   4524   1.9  christos 	if (rdataset == NULL || !dns_rdataset_isassociated(rdataset)) {
   4525   1.3  christos 		return (true);
   4526   1.9  christos 	}
   4527   1.1  christos 	/*
   4528   1.1  christos 	 * Do not rewrite if there is any sign of signatures.
   4529   1.1  christos 	 */
   4530   1.1  christos 	if (rdataset->type == dns_rdatatype_nsec ||
   4531   1.1  christos 	    rdataset->type == dns_rdatatype_nsec3 ||
   4532   1.1  christos 	    rdataset->type == dns_rdatatype_rrsig)
   4533   1.9  christos 	{
   4534   1.3  christos 		return (false);
   4535   1.9  christos 	}
   4536   1.1  christos 
   4537   1.1  christos 	/*
   4538   1.1  christos 	 * Look for a signature in a negative cache rdataset.
   4539   1.1  christos 	 */
   4540   1.9  christos 	if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) == 0) {
   4541   1.3  christos 		return (true);
   4542   1.9  christos 	}
   4543   1.1  christos 	found = dns_fixedname_initname(&fixed);
   4544   1.1  christos 	dns_rdataset_init(&trdataset);
   4545   1.9  christos 	for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
   4546   1.9  christos 	     result = dns_rdataset_next(rdataset))
   4547   1.9  christos 	{
   4548   1.1  christos 		dns_ncache_current(rdataset, found, &trdataset);
   4549   1.1  christos 		type = trdataset.type;
   4550   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   4551   1.9  christos 		if (type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3 ||
   4552   1.1  christos 		    type == dns_rdatatype_rrsig)
   4553   1.9  christos 		{
   4554   1.3  christos 			return (false);
   4555   1.9  christos 		}
   4556   1.1  christos 	}
   4557   1.3  christos 	return (true);
   4558   1.1  christos }
   4559   1.1  christos 
   4560   1.1  christos /*
   4561   1.1  christos  * Extract a network address from the RDATA of an A or AAAA
   4562   1.1  christos  * record.
   4563   1.1  christos  *
   4564   1.1  christos  * Returns:
   4565   1.1  christos  *	ISC_R_SUCCESS
   4566   1.1  christos  *	ISC_R_NOTIMPLEMENTED	The rdata is not a known address type.
   4567   1.1  christos  */
   4568   1.1  christos static isc_result_t
   4569   1.1  christos rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
   4570   1.1  christos 	struct in_addr ina;
   4571   1.1  christos 	struct in6_addr in6a;
   4572   1.1  christos 
   4573   1.1  christos 	switch (rdata->type) {
   4574   1.1  christos 	case dns_rdatatype_a:
   4575   1.1  christos 		INSIST(rdata->length == 4);
   4576   1.1  christos 		memmove(&ina.s_addr, rdata->data, 4);
   4577   1.1  christos 		isc_netaddr_fromin(netaddr, &ina);
   4578   1.1  christos 		return (ISC_R_SUCCESS);
   4579   1.1  christos 	case dns_rdatatype_aaaa:
   4580   1.1  christos 		INSIST(rdata->length == 16);
   4581   1.1  christos 		memmove(in6a.s6_addr, rdata->data, 16);
   4582   1.1  christos 		isc_netaddr_fromin6(netaddr, &in6a);
   4583   1.1  christos 		return (ISC_R_SUCCESS);
   4584   1.1  christos 	default:
   4585   1.1  christos 		return (ISC_R_NOTIMPLEMENTED);
   4586   1.1  christos 	}
   4587   1.1  christos }
   4588   1.1  christos 
   4589   1.1  christos static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
   4590   1.1  christos static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
   4591   1.1  christos static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
   4592   1.1  christos 
   4593   1.1  christos static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
   4594   1.1  christos 
   4595   1.1  christos static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
   4596   1.1  christos static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
   4597   1.1  christos static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
   4598   1.1  christos static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
   4599   1.1  christos static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
   4600   1.1  christos static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
   4601   1.1  christos static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
   4602   1.1  christos static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
   4603   1.1  christos static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
   4604   1.1  christos static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
   4605   1.1  christos static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
   4606   1.1  christos static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
   4607   1.1  christos static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
   4608   1.1  christos static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
   4609   1.1  christos static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
   4610   1.1  christos static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
   4611   1.1  christos 
   4612   1.1  christos static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
   4613   1.1  christos 
   4614   1.1  christos static dns_name_t rfc1918names[] = {
   4615   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr10, inaddr10_offsets),
   4616   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr16172, inaddr172_offsets),
   4617   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr17172, inaddr172_offsets),
   4618   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr18172, inaddr172_offsets),
   4619   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr19172, inaddr172_offsets),
   4620   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr20172, inaddr172_offsets),
   4621   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr21172, inaddr172_offsets),
   4622   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr22172, inaddr172_offsets),
   4623   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr23172, inaddr172_offsets),
   4624   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr24172, inaddr172_offsets),
   4625   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr25172, inaddr172_offsets),
   4626   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr26172, inaddr172_offsets),
   4627   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr27172, inaddr172_offsets),
   4628   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr28172, inaddr172_offsets),
   4629   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr29172, inaddr172_offsets),
   4630   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr30172, inaddr172_offsets),
   4631   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr31172, inaddr172_offsets),
   4632   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets)
   4633   1.1  christos };
   4634   1.1  christos 
   4635   1.1  christos static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
   4636   1.9  christos static unsigned char hostmaster_data[] = "\012hostmaster\014root-"
   4637   1.9  christos 					 "servers\003org";
   4638   1.1  christos 
   4639   1.1  christos static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 };
   4640   1.1  christos static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 };
   4641   1.1  christos 
   4642   1.9  christos static dns_name_t const prisoner = DNS_NAME_INITABSOLUTE(prisoner_data,
   4643   1.9  christos 							 prisoner_offsets);
   4644   1.9  christos static dns_name_t const hostmaster = DNS_NAME_INITABSOLUTE(hostmaster_data,
   4645   1.9  christos 							   hostmaster_offsets);
   4646   1.1  christos 
   4647   1.1  christos static void
   4648   1.1  christos warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) {
   4649   1.1  christos 	unsigned int i;
   4650   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   4651   1.1  christos 	dns_rdata_soa_t soa;
   4652   1.1  christos 	dns_rdataset_t found;
   4653   1.1  christos 	isc_result_t result;
   4654   1.1  christos 
   4655   1.9  christos 	for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) {
   4656   1.1  christos 		if (dns_name_issubdomain(fname, &rfc1918names[i])) {
   4657   1.1  christos 			dns_rdataset_init(&found);
   4658   1.9  christos 			result = dns_ncache_getrdataset(
   4659   1.9  christos 				rdataset, &rfc1918names[i], dns_rdatatype_soa,
   4660   1.9  christos 				&found);
   4661   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4662   1.1  christos 				return;
   4663   1.9  christos 			}
   4664   1.1  christos 
   4665   1.1  christos 			result = dns_rdataset_first(&found);
   4666   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4667   1.1  christos 			dns_rdataset_current(&found, &rdata);
   4668   1.1  christos 			result = dns_rdata_tostruct(&rdata, &soa, NULL);
   4669   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4670   1.1  christos 			if (dns_name_equal(&soa.origin, &prisoner) &&
   4671   1.9  christos 			    dns_name_equal(&soa.contact, &hostmaster))
   4672   1.9  christos 			{
   4673   1.1  christos 				char buf[DNS_NAME_FORMATSIZE];
   4674   1.1  christos 				dns_name_format(fname, buf, sizeof(buf));
   4675   1.1  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   4676   1.1  christos 					      NS_LOGMODULE_QUERY,
   4677   1.1  christos 					      ISC_LOG_WARNING,
   4678   1.1  christos 					      "RFC 1918 response from "
   4679   1.9  christos 					      "Internet for %s",
   4680   1.9  christos 					      buf);
   4681   1.1  christos 			}
   4682   1.1  christos 			dns_rdataset_disassociate(&found);
   4683   1.1  christos 			return;
   4684   1.1  christos 		}
   4685   1.1  christos 	}
   4686   1.1  christos }
   4687   1.1  christos 
   4688   1.1  christos static void
   4689   1.1  christos query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
   4690   1.1  christos 		       dns_dbversion_t *version, ns_client_t *client,
   4691   1.1  christos 		       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
   4692   1.9  christos 		       dns_name_t *fname, bool exact, dns_name_t *found) {
   4693   1.1  christos 	unsigned char salt[256];
   4694   1.1  christos 	size_t salt_length;
   4695   1.3  christos 	uint16_t iterations;
   4696   1.1  christos 	isc_result_t result;
   4697   1.1  christos 	unsigned int dboptions;
   4698   1.1  christos 	dns_fixedname_t fixed;
   4699   1.1  christos 	dns_hash_t hash;
   4700   1.1  christos 	dns_name_t name;
   4701   1.1  christos 	unsigned int skip = 0, labels;
   4702   1.1  christos 	dns_rdata_nsec3_t nsec3;
   4703   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   4704   1.3  christos 	bool optout;
   4705   1.1  christos 	dns_clientinfomethods_t cm;
   4706   1.1  christos 	dns_clientinfo_t ci;
   4707   1.1  christos 
   4708   1.1  christos 	salt_length = sizeof(salt);
   4709   1.1  christos 	result = dns_db_getnsec3parameters(db, version, &hash, NULL,
   4710   1.1  christos 					   &iterations, salt, &salt_length);
   4711   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4712   1.1  christos 		return;
   4713   1.9  christos 	}
   4714   1.1  christos 
   4715   1.1  christos 	dns_name_init(&name, NULL);
   4716   1.1  christos 	dns_name_clone(qname, &name);
   4717   1.1  christos 	labels = dns_name_countlabels(&name);
   4718   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   4719  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   4720   1.1  christos 
   4721   1.1  christos 	/*
   4722   1.1  christos 	 * Map unknown algorithm to known value.
   4723   1.1  christos 	 */
   4724   1.9  christos 	if (hash == DNS_NSEC3_UNKNOWNALG) {
   4725   1.1  christos 		hash = 1;
   4726   1.9  christos 	}
   4727   1.1  christos 
   4728   1.9  christos again:
   4729   1.1  christos 	dns_fixedname_init(&fixed);
   4730   1.1  christos 	result = dns_nsec3_hashname(&fixed, NULL, NULL, &name,
   4731   1.9  christos 				    dns_db_origin(db), hash, iterations, salt,
   4732   1.9  christos 				    salt_length);
   4733   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4734   1.1  christos 		return;
   4735   1.9  christos 	}
   4736   1.1  christos 
   4737   1.1  christos 	dboptions = client->query.dboptions | DNS_DBFIND_FORCENSEC3;
   4738   1.1  christos 	result = dns_db_findext(db, dns_fixedname_name(&fixed), version,
   4739   1.1  christos 				dns_rdatatype_nsec3, dboptions, client->now,
   4740   1.1  christos 				NULL, fname, &cm, &ci, rdataset, sigrdataset);
   4741   1.1  christos 
   4742   1.1  christos 	if (result == DNS_R_NXDOMAIN) {
   4743   1.1  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   4744   1.1  christos 			return;
   4745   1.1  christos 		}
   4746   1.1  christos 		result = dns_rdataset_first(rdataset);
   4747   1.1  christos 		INSIST(result == ISC_R_SUCCESS);
   4748   1.1  christos 		dns_rdataset_current(rdataset, &rdata);
   4749   1.3  christos 		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
   4750   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4751   1.1  christos 		dns_rdata_reset(&rdata);
   4752   1.3  christos 		optout = ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
   4753   1.1  christos 		if (found != NULL && optout &&
   4754  1.16  christos 		    dns_name_issubdomain(&name, dns_db_origin(db)))
   4755  1.16  christos 		{
   4756   1.1  christos 			dns_rdataset_disassociate(rdataset);
   4757   1.9  christos 			if (dns_rdataset_isassociated(sigrdataset)) {
   4758   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   4759   1.9  christos 			}
   4760   1.1  christos 			skip++;
   4761   1.1  christos 			dns_name_getlabelsequence(qname, skip, labels - skip,
   4762   1.1  christos 						  &name);
   4763   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   4764   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3),
   4765   1.1  christos 				      "looking for closest provable encloser");
   4766   1.1  christos 			goto again;
   4767   1.1  christos 		}
   4768   1.9  christos 		if (exact) {
   4769   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   4770   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   4771   1.1  christos 				      "expected a exact match NSEC3, got "
   4772   1.1  christos 				      "a covering record");
   4773   1.9  christos 		}
   4774   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   4775   1.1  christos 		return;
   4776   1.9  christos 	} else if (!exact) {
   4777   1.1  christos 		ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   4778   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   4779   1.1  christos 			      "expected covering NSEC3, got an exact match");
   4780   1.9  christos 	}
   4781   1.1  christos 	if (found == qname) {
   4782   1.9  christos 		if (skip != 0U) {
   4783   1.1  christos 			dns_name_getlabelsequence(qname, skip, labels - skip,
   4784   1.1  christos 						  found);
   4785   1.9  christos 		}
   4786   1.9  christos 	} else if (found != NULL) {
   4787  1.20  christos 		dns_name_copy(&name, found);
   4788   1.9  christos 	}
   4789   1.1  christos 	return;
   4790   1.1  christos }
   4791   1.1  christos 
   4792   1.3  christos static uint32_t
   4793   1.1  christos dns64_ttl(dns_db_t *db, dns_dbversion_t *version) {
   4794   1.1  christos 	dns_dbnode_t *node = NULL;
   4795   1.1  christos 	dns_rdata_soa_t soa;
   4796   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   4797   1.1  christos 	dns_rdataset_t rdataset;
   4798   1.1  christos 	isc_result_t result;
   4799   1.3  christos 	uint32_t ttl = UINT32_MAX;
   4800   1.1  christos 
   4801   1.1  christos 	dns_rdataset_init(&rdataset);
   4802   1.1  christos 
   4803   1.1  christos 	result = dns_db_getoriginnode(db, &node);
   4804   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4805   1.1  christos 		goto cleanup;
   4806   1.9  christos 	}
   4807   1.1  christos 
   4808   1.9  christos 	result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, 0, 0,
   4809   1.9  christos 				     &rdataset, NULL);
   4810   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4811   1.1  christos 		goto cleanup;
   4812   1.9  christos 	}
   4813   1.1  christos 	result = dns_rdataset_first(&rdataset);
   4814   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4815   1.1  christos 		goto cleanup;
   4816   1.9  christos 	}
   4817   1.1  christos 
   4818   1.1  christos 	dns_rdataset_current(&rdataset, &rdata);
   4819   1.1  christos 	result = dns_rdata_tostruct(&rdata, &soa, NULL);
   4820   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4821   1.1  christos 	ttl = ISC_MIN(rdataset.ttl, soa.minimum);
   4822   1.1  christos 
   4823   1.1  christos cleanup:
   4824   1.9  christos 	if (dns_rdataset_isassociated(&rdataset)) {
   4825   1.1  christos 		dns_rdataset_disassociate(&rdataset);
   4826   1.9  christos 	}
   4827   1.9  christos 	if (node != NULL) {
   4828   1.1  christos 		dns_db_detachnode(db, &node);
   4829   1.9  christos 	}
   4830   1.1  christos 	return (ttl);
   4831   1.1  christos }
   4832   1.1  christos 
   4833   1.3  christos static bool
   4834   1.1  christos dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset,
   4835   1.9  christos 	     dns_rdataset_t *sigrdataset) {
   4836   1.1  christos 	isc_netaddr_t netaddr;
   4837  1.20  christos 	dns_aclenv_t *env = client->manager->aclenv;
   4838   1.1  christos 	dns_dns64_t *dns64 = ISC_LIST_HEAD(client->view->dns64);
   4839   1.1  christos 	unsigned int flags = 0;
   4840   1.1  christos 	unsigned int i, count;
   4841   1.3  christos 	bool *aaaaok;
   4842   1.1  christos 
   4843   1.1  christos 	INSIST(client->query.dns64_aaaaok == NULL);
   4844   1.1  christos 	INSIST(client->query.dns64_aaaaoklen == 0);
   4845   1.1  christos 	INSIST(client->query.dns64_aaaa == NULL);
   4846   1.1  christos 	INSIST(client->query.dns64_sigaaaa == NULL);
   4847   1.1  christos 
   4848   1.9  christos 	if (dns64 == NULL) {
   4849   1.3  christos 		return (true);
   4850   1.9  christos 	}
   4851   1.1  christos 
   4852   1.9  christos 	if (RECURSIONOK(client)) {
   4853   1.1  christos 		flags |= DNS_DNS64_RECURSIVE;
   4854   1.9  christos 	}
   4855   1.1  christos 
   4856   1.1  christos 	if (WANTDNSSEC(client) && sigrdataset != NULL &&
   4857   1.1  christos 	    dns_rdataset_isassociated(sigrdataset))
   4858   1.9  christos 	{
   4859   1.1  christos 		flags |= DNS_DNS64_DNSSEC;
   4860   1.9  christos 	}
   4861   1.1  christos 
   4862   1.1  christos 	count = dns_rdataset_count(rdataset);
   4863   1.3  christos 	aaaaok = isc_mem_get(client->mctx, sizeof(bool) * count);
   4864   1.1  christos 
   4865   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   4866   1.9  christos 	if (dns_dns64_aaaaok(dns64, &netaddr, client->signer, env, flags,
   4867   1.9  christos 			     rdataset, aaaaok, count))
   4868   1.1  christos 	{
   4869   1.1  christos 		for (i = 0; i < count; i++) {
   4870   1.1  christos 			if (aaaaok != NULL && !aaaaok[i]) {
   4871   1.1  christos 				SAVE(client->query.dns64_aaaaok, aaaaok);
   4872   1.1  christos 				client->query.dns64_aaaaoklen = count;
   4873   1.1  christos 				break;
   4874   1.1  christos 			}
   4875   1.1  christos 		}
   4876   1.9  christos 		if (aaaaok != NULL) {
   4877   1.9  christos 			isc_mem_put(client->mctx, aaaaok, sizeof(bool) * count);
   4878   1.9  christos 		}
   4879   1.3  christos 		return (true);
   4880   1.1  christos 	}
   4881   1.9  christos 	if (aaaaok != NULL) {
   4882   1.9  christos 		isc_mem_put(client->mctx, aaaaok, sizeof(bool) * count);
   4883   1.9  christos 	}
   4884   1.3  christos 	return (false);
   4885   1.1  christos }
   4886   1.1  christos 
   4887   1.1  christos /*
   4888   1.1  christos  * Look for the name and type in the redirection zone.  If found update
   4889   1.3  christos  * the arguments as appropriate.  Return true if a update was
   4890   1.1  christos  * performed.
   4891   1.1  christos  *
   4892   1.1  christos  * Only perform the update if the client is in the allow query acl and
   4893   1.1  christos  * returning the update would not cause a DNSSEC validation failure.
   4894   1.1  christos  */
   4895   1.1  christos static isc_result_t
   4896   1.1  christos redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
   4897   1.1  christos 	 dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
   4898   1.9  christos 	 dns_rdatatype_t qtype) {
   4899   1.1  christos 	dns_db_t *db = NULL;
   4900   1.1  christos 	dns_dbnode_t *node = NULL;
   4901   1.1  christos 	dns_fixedname_t fixed;
   4902   1.1  christos 	dns_name_t *found;
   4903   1.1  christos 	dns_rdataset_t trdataset;
   4904   1.1  christos 	isc_result_t result;
   4905   1.1  christos 	dns_rdatatype_t type;
   4906   1.1  christos 	dns_clientinfomethods_t cm;
   4907   1.1  christos 	dns_clientinfo_t ci;
   4908   1.1  christos 	ns_dbversion_t *dbversion;
   4909   1.1  christos 
   4910   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect");
   4911   1.1  christos 
   4912   1.9  christos 	if (client->view->redirect == NULL) {
   4913   1.1  christos 		return (ISC_R_NOTFOUND);
   4914   1.9  christos 	}
   4915   1.1  christos 
   4916   1.1  christos 	found = dns_fixedname_initname(&fixed);
   4917   1.1  christos 	dns_rdataset_init(&trdataset);
   4918   1.1  christos 
   4919   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   4920  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   4921  1.20  christos 	dns_clientinfo_setecs(&ci, &client->ecs);
   4922   1.1  christos 
   4923   1.1  christos 	if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
   4924   1.9  christos 	{
   4925   1.1  christos 		return (ISC_R_NOTFOUND);
   4926   1.9  christos 	}
   4927   1.1  christos 
   4928   1.1  christos 	if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
   4929   1.9  christos 		if (rdataset->trust == dns_trust_secure) {
   4930   1.1  christos 			return (ISC_R_NOTFOUND);
   4931   1.9  christos 		}
   4932   1.1  christos 		if (rdataset->trust == dns_trust_ultimate &&
   4933   1.1  christos 		    (rdataset->type == dns_rdatatype_nsec ||
   4934   1.1  christos 		     rdataset->type == dns_rdatatype_nsec3))
   4935   1.9  christos 		{
   4936   1.1  christos 			return (ISC_R_NOTFOUND);
   4937   1.9  christos 		}
   4938   1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
   4939   1.1  christos 			for (result = dns_rdataset_first(rdataset);
   4940   1.1  christos 			     result == ISC_R_SUCCESS;
   4941   1.9  christos 			     result = dns_rdataset_next(rdataset))
   4942   1.9  christos 			{
   4943   1.1  christos 				dns_ncache_current(rdataset, found, &trdataset);
   4944   1.1  christos 				type = trdataset.type;
   4945   1.1  christos 				dns_rdataset_disassociate(&trdataset);
   4946   1.1  christos 				if (type == dns_rdatatype_nsec ||
   4947   1.1  christos 				    type == dns_rdatatype_nsec3 ||
   4948   1.1  christos 				    type == dns_rdatatype_rrsig)
   4949   1.9  christos 				{
   4950   1.1  christos 					return (ISC_R_NOTFOUND);
   4951   1.9  christos 				}
   4952   1.1  christos 			}
   4953   1.1  christos 		}
   4954   1.1  christos 	}
   4955   1.1  christos 
   4956   1.9  christos 	result = ns_client_checkaclsilent(
   4957   1.9  christos 		client, NULL, dns_zone_getqueryacl(client->view->redirect),
   4958   1.9  christos 		true);
   4959   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4960   1.1  christos 		return (ISC_R_NOTFOUND);
   4961   1.9  christos 	}
   4962   1.1  christos 
   4963   1.1  christos 	result = dns_zone_getdb(client->view->redirect, &db);
   4964   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4965   1.1  christos 		return (ISC_R_NOTFOUND);
   4966   1.9  christos 	}
   4967   1.1  christos 
   4968   1.3  christos 	dbversion = ns_client_findversion(client, db);
   4969   1.1  christos 	if (dbversion == NULL) {
   4970   1.1  christos 		dns_db_detach(&db);
   4971   1.1  christos 		return (ISC_R_NOTFOUND);
   4972   1.1  christos 	}
   4973   1.1  christos 
   4974   1.1  christos 	/*
   4975   1.1  christos 	 * Lookup the requested data in the redirect zone.
   4976   1.1  christos 	 */
   4977   1.1  christos 	result = dns_db_findext(db, client->query.qname, dbversion->version,
   4978   1.9  christos 				qtype, DNS_DBFIND_NOZONECUT, client->now, &node,
   4979   1.9  christos 				found, &cm, &ci, &trdataset, NULL);
   4980   1.1  christos 	if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
   4981   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   4982   1.1  christos 			dns_rdataset_disassociate(rdataset);
   4983   1.9  christos 		}
   4984   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   4985   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   4986   1.9  christos 		}
   4987   1.1  christos 		goto nxrrset;
   4988   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   4989   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   4990   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   4991   1.9  christos 		}
   4992   1.9  christos 		if (node != NULL) {
   4993   1.1  christos 			dns_db_detachnode(db, &node);
   4994   1.9  christos 		}
   4995   1.1  christos 		dns_db_detach(&db);
   4996   1.1  christos 		return (ISC_R_NOTFOUND);
   4997   1.1  christos 	}
   4998   1.1  christos 
   4999   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect: found data: done");
   5000  1.20  christos 	dns_name_copy(found, name);
   5001   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   5002   1.1  christos 		dns_rdataset_disassociate(rdataset);
   5003   1.9  christos 	}
   5004   1.1  christos 	if (dns_rdataset_isassociated(&trdataset)) {
   5005   1.1  christos 		dns_rdataset_clone(&trdataset, rdataset);
   5006   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   5007   1.1  christos 	}
   5008   1.9  christos nxrrset:
   5009   1.9  christos 	if (*nodep != NULL) {
   5010   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   5011   1.9  christos 	}
   5012   1.1  christos 	dns_db_detach(dbp);
   5013   1.1  christos 	dns_db_attachnode(db, node, nodep);
   5014   1.1  christos 	dns_db_attach(db, dbp);
   5015   1.1  christos 	dns_db_detachnode(db, &node);
   5016   1.1  christos 	dns_db_detach(&db);
   5017   1.1  christos 	*versionp = dbversion->version;
   5018   1.1  christos 
   5019   1.1  christos 	client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   5020   1.1  christos 				     NS_QUERYATTR_NOADDITIONAL);
   5021   1.1  christos 
   5022   1.1  christos 	return (result);
   5023   1.1  christos }
   5024   1.1  christos 
   5025   1.1  christos static isc_result_t
   5026   1.1  christos redirect2(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
   5027   1.1  christos 	  dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
   5028   1.9  christos 	  dns_rdatatype_t qtype, bool *is_zonep) {
   5029   1.1  christos 	dns_db_t *db = NULL;
   5030   1.1  christos 	dns_dbnode_t *node = NULL;
   5031   1.1  christos 	dns_fixedname_t fixed;
   5032   1.1  christos 	dns_fixedname_t fixedredirect;
   5033   1.1  christos 	dns_name_t *found, *redirectname;
   5034   1.1  christos 	dns_rdataset_t trdataset;
   5035   1.1  christos 	isc_result_t result;
   5036   1.1  christos 	dns_rdatatype_t type;
   5037   1.1  christos 	dns_clientinfomethods_t cm;
   5038   1.1  christos 	dns_clientinfo_t ci;
   5039   1.1  christos 	dns_dbversion_t *version = NULL;
   5040   1.1  christos 	dns_zone_t *zone = NULL;
   5041   1.3  christos 	bool is_zone;
   5042   1.5  christos 	unsigned int labels;
   5043   1.1  christos 	unsigned int options;
   5044   1.1  christos 
   5045   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect2");
   5046   1.1  christos 
   5047   1.5  christos 	if (client->view->redirectzone == NULL) {
   5048   1.1  christos 		return (ISC_R_NOTFOUND);
   5049   1.5  christos 	}
   5050   1.1  christos 
   5051   1.5  christos 	if (dns_name_issubdomain(name, client->view->redirectzone)) {
   5052   1.1  christos 		return (ISC_R_NOTFOUND);
   5053   1.5  christos 	}
   5054   1.1  christos 
   5055   1.1  christos 	found = dns_fixedname_initname(&fixed);
   5056   1.1  christos 	dns_rdataset_init(&trdataset);
   5057   1.1  christos 
   5058   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   5059  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   5060  1.20  christos 	dns_clientinfo_setecs(&ci, &client->ecs);
   5061   1.1  christos 
   5062   1.9  christos 	if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
   5063   1.9  christos 	{
   5064   1.1  christos 		return (ISC_R_NOTFOUND);
   5065   1.5  christos 	}
   5066   1.1  christos 
   5067   1.1  christos 	if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
   5068   1.9  christos 		if (rdataset->trust == dns_trust_secure) {
   5069   1.1  christos 			return (ISC_R_NOTFOUND);
   5070   1.9  christos 		}
   5071   1.1  christos 		if (rdataset->trust == dns_trust_ultimate &&
   5072   1.1  christos 		    (rdataset->type == dns_rdatatype_nsec ||
   5073   1.1  christos 		     rdataset->type == dns_rdatatype_nsec3))
   5074   1.9  christos 		{
   5075   1.1  christos 			return (ISC_R_NOTFOUND);
   5076   1.9  christos 		}
   5077   1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
   5078   1.1  christos 			for (result = dns_rdataset_first(rdataset);
   5079   1.1  christos 			     result == ISC_R_SUCCESS;
   5080   1.9  christos 			     result = dns_rdataset_next(rdataset))
   5081   1.9  christos 			{
   5082   1.1  christos 				dns_ncache_current(rdataset, found, &trdataset);
   5083   1.1  christos 				type = trdataset.type;
   5084   1.1  christos 				dns_rdataset_disassociate(&trdataset);
   5085   1.1  christos 				if (type == dns_rdatatype_nsec ||
   5086   1.1  christos 				    type == dns_rdatatype_nsec3 ||
   5087   1.1  christos 				    type == dns_rdatatype_rrsig)
   5088   1.9  christos 				{
   5089   1.1  christos 					return (ISC_R_NOTFOUND);
   5090   1.9  christos 				}
   5091   1.1  christos 			}
   5092   1.1  christos 		}
   5093   1.1  christos 	}
   5094   1.1  christos 
   5095   1.1  christos 	redirectname = dns_fixedname_initname(&fixedredirect);
   5096   1.5  christos 	labels = dns_name_countlabels(client->query.qname);
   5097   1.5  christos 	if (labels > 1U) {
   5098   1.1  christos 		dns_name_t prefix;
   5099   1.1  christos 
   5100   1.1  christos 		dns_name_init(&prefix, NULL);
   5101   1.5  christos 		dns_name_getlabelsequence(client->query.qname, 0, labels - 1,
   5102   1.5  christos 					  &prefix);
   5103   1.1  christos 		result = dns_name_concatenate(&prefix,
   5104   1.1  christos 					      client->view->redirectzone,
   5105   1.1  christos 					      redirectname, NULL);
   5106   1.9  christos 		if (result != ISC_R_SUCCESS) {
   5107   1.1  christos 			return (ISC_R_NOTFOUND);
   5108   1.9  christos 		}
   5109   1.5  christos 	} else {
   5110  1.20  christos 		dns_name_copy(redirectname, client->view->redirectzone);
   5111   1.5  christos 	}
   5112   1.1  christos 
   5113   1.1  christos 	options = 0;
   5114   1.9  christos 	result = query_getdb(client, redirectname, qtype, options, &zone, &db,
   5115   1.9  christos 			     &version, &is_zone);
   5116   1.5  christos 	if (result != ISC_R_SUCCESS) {
   5117   1.1  christos 		return (ISC_R_NOTFOUND);
   5118   1.5  christos 	}
   5119   1.5  christos 	if (zone != NULL) {
   5120   1.1  christos 		dns_zone_detach(&zone);
   5121   1.5  christos 	}
   5122   1.1  christos 
   5123   1.1  christos 	/*
   5124   1.1  christos 	 * Lookup the requested data in the redirect zone.
   5125   1.1  christos 	 */
   5126   1.9  christos 	result = dns_db_findext(db, redirectname, version, qtype, 0,
   5127   1.9  christos 				client->now, &node, found, &cm, &ci, &trdataset,
   5128   1.9  christos 				NULL);
   5129   1.1  christos 	if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
   5130   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   5131   1.1  christos 			dns_rdataset_disassociate(rdataset);
   5132   1.9  christos 		}
   5133   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5134   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5135   1.9  christos 		}
   5136   1.1  christos 		goto nxrrset;
   5137   1.1  christos 	} else if (result == ISC_R_NOTFOUND || result == DNS_R_DELEGATION) {
   5138   1.1  christos 		/*
   5139   1.1  christos 		 * Cleanup.
   5140   1.1  christos 		 */
   5141   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5142   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5143   1.9  christos 		}
   5144   1.9  christos 		if (node != NULL) {
   5145   1.1  christos 			dns_db_detachnode(db, &node);
   5146   1.9  christos 		}
   5147   1.1  christos 		dns_db_detach(&db);
   5148   1.1  christos 		/*
   5149   1.1  christos 		 * Don't loop forever if the lookup failed last time.
   5150   1.1  christos 		 */
   5151   1.1  christos 		if (!REDIRECT(client)) {
   5152   1.3  christos 			result = ns_query_recurse(client, qtype, redirectname,
   5153   1.3  christos 						  NULL, NULL, true);
   5154   1.1  christos 			if (result == ISC_R_SUCCESS) {
   5155   1.1  christos 				client->query.attributes |=
   5156   1.9  christos 					NS_QUERYATTR_RECURSING;
   5157   1.1  christos 				client->query.attributes |=
   5158   1.9  christos 					NS_QUERYATTR_REDIRECT;
   5159   1.1  christos 				return (DNS_R_CONTINUE);
   5160   1.1  christos 			}
   5161   1.1  christos 		}
   5162   1.1  christos 		return (ISC_R_NOTFOUND);
   5163   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   5164   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5165   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5166   1.9  christos 		}
   5167   1.9  christos 		if (node != NULL) {
   5168   1.1  christos 			dns_db_detachnode(db, &node);
   5169   1.9  christos 		}
   5170   1.1  christos 		dns_db_detach(&db);
   5171   1.1  christos 		return (ISC_R_NOTFOUND);
   5172   1.1  christos 	}
   5173   1.1  christos 
   5174   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect2: found data: done");
   5175   1.1  christos 	/*
   5176   1.1  christos 	 * Adjust the found name to not include the redirectzone suffix.
   5177   1.1  christos 	 */
   5178   1.1  christos 	dns_name_split(found, dns_name_countlabels(client->view->redirectzone),
   5179   1.1  christos 		       found, NULL);
   5180   1.1  christos 	/*
   5181   1.1  christos 	 * Make the name absolute.
   5182   1.1  christos 	 */
   5183   1.1  christos 	result = dns_name_concatenate(found, dns_rootname, found, NULL);
   5184   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   5185   1.1  christos 
   5186  1.20  christos 	dns_name_copy(found, name);
   5187   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   5188   1.1  christos 		dns_rdataset_disassociate(rdataset);
   5189   1.9  christos 	}
   5190   1.1  christos 	if (dns_rdataset_isassociated(&trdataset)) {
   5191   1.1  christos 		dns_rdataset_clone(&trdataset, rdataset);
   5192   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   5193   1.1  christos 	}
   5194   1.9  christos nxrrset:
   5195   1.9  christos 	if (*nodep != NULL) {
   5196   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   5197   1.9  christos 	}
   5198   1.1  christos 	dns_db_detach(dbp);
   5199   1.1  christos 	dns_db_attachnode(db, node, nodep);
   5200   1.1  christos 	dns_db_attach(db, dbp);
   5201   1.1  christos 	dns_db_detachnode(db, &node);
   5202   1.1  christos 	dns_db_detach(&db);
   5203   1.1  christos 	*is_zonep = is_zone;
   5204   1.1  christos 	*versionp = version;
   5205   1.1  christos 
   5206   1.1  christos 	client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   5207   1.1  christos 				     NS_QUERYATTR_NOADDITIONAL);
   5208   1.1  christos 
   5209   1.1  christos 	return (result);
   5210   1.1  christos }
   5211   1.1  christos 
   5212   1.1  christos /*%
   5213   1.1  christos  * Initialize query context 'qctx'. Run by query_setup() when
   5214   1.1  christos  * first handling a client query, and by query_resume() when
   5215   1.1  christos  * returning from recursion.
   5216   1.3  christos  *
   5217   1.3  christos  * Whenever this function is called, qctx_destroy() must be called
   5218   1.3  christos  * when leaving the scope or freeing the qctx.
   5219   1.1  christos  */
   5220   1.1  christos static void
   5221  1.11  christos qctx_init(ns_client_t *client, dns_fetchevent_t **eventp, dns_rdatatype_t qtype,
   5222   1.9  christos 	  query_ctx_t *qctx) {
   5223   1.1  christos 	REQUIRE(qctx != NULL);
   5224   1.1  christos 	REQUIRE(client != NULL);
   5225   1.1  christos 
   5226   1.3  christos 	memset(qctx, 0, sizeof(*qctx));
   5227   1.3  christos 
   5228   1.1  christos 	/* Set this first so CCTRACE will work */
   5229   1.1  christos 	qctx->client = client;
   5230   1.9  christos 
   5231   1.3  christos 	dns_view_attach(client->view, &qctx->view);
   5232   1.1  christos 
   5233   1.3  christos 	CCTRACE(ISC_LOG_DEBUG(3), "qctx_init");
   5234   1.1  christos 
   5235  1.11  christos 	if (eventp != NULL) {
   5236  1.11  christos 		qctx->event = *eventp;
   5237  1.11  christos 		*eventp = NULL;
   5238  1.11  christos 	} else {
   5239  1.11  christos 		qctx->event = NULL;
   5240  1.11  christos 	}
   5241   1.1  christos 	qctx->qtype = qctx->type = qtype;
   5242   1.1  christos 	qctx->result = ISC_R_SUCCESS;
   5243   1.3  christos 	qctx->findcoveringnsec = qctx->view->synthfromdnssec;
   5244   1.3  christos 
   5245  1.16  christos 	/*
   5246  1.16  christos 	 * If it's an RRSIG or SIG query, we'll iterate the node.
   5247  1.16  christos 	 */
   5248  1.16  christos 	if (qctx->qtype == dns_rdatatype_rrsig ||
   5249  1.16  christos 	    qctx->qtype == dns_rdatatype_sig)
   5250  1.16  christos 	{
   5251  1.16  christos 		qctx->type = dns_rdatatype_any;
   5252  1.16  christos 	}
   5253  1.16  christos 
   5254   1.3  christos 	CALL_HOOK_NORETURN(NS_QUERY_QCTX_INITIALIZED, qctx);
   5255   1.1  christos }
   5256   1.1  christos 
   5257  1.11  christos /*
   5258  1.11  christos  * Make 'dst' and exact copy of 'src', with exception of the
   5259  1.11  christos  * option field, which is reset to zero.
   5260  1.11  christos  * This function also attaches dst's view and db to the src's
   5261  1.11  christos  * view and cachedb.
   5262  1.11  christos  */
   5263  1.11  christos static void
   5264  1.11  christos qctx_copy(const query_ctx_t *qctx, query_ctx_t *dst) {
   5265  1.11  christos 	REQUIRE(qctx != NULL);
   5266  1.11  christos 	REQUIRE(dst != NULL);
   5267  1.11  christos 
   5268  1.11  christos 	memmove(dst, qctx, sizeof(*dst));
   5269  1.11  christos 	dst->view = NULL;
   5270  1.11  christos 	dst->db = NULL;
   5271  1.11  christos 	dst->options = 0;
   5272  1.11  christos 	dns_view_attach(qctx->view, &dst->view);
   5273  1.11  christos 	dns_db_attach(qctx->view->cachedb, &dst->db);
   5274  1.11  christos 	CCTRACE(ISC_LOG_DEBUG(3), "qctx_copy");
   5275  1.11  christos }
   5276  1.11  christos 
   5277   1.1  christos /*%
   5278   1.1  christos  * Clean up and disassociate the rdataset and node pointers in qctx.
   5279   1.1  christos  */
   5280   1.1  christos static void
   5281   1.1  christos qctx_clean(query_ctx_t *qctx) {
   5282   1.9  christos 	if (qctx->rdataset != NULL && dns_rdataset_isassociated(qctx->rdataset))
   5283   1.1  christos 	{
   5284   1.1  christos 		dns_rdataset_disassociate(qctx->rdataset);
   5285   1.1  christos 	}
   5286   1.1  christos 	if (qctx->sigrdataset != NULL &&
   5287  1.16  christos 	    dns_rdataset_isassociated(qctx->sigrdataset))
   5288  1.16  christos 	{
   5289   1.1  christos 		dns_rdataset_disassociate(qctx->sigrdataset);
   5290   1.1  christos 	}
   5291   1.1  christos 	if (qctx->db != NULL && qctx->node != NULL) {
   5292   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   5293   1.1  christos 	}
   5294   1.1  christos }
   5295   1.1  christos 
   5296   1.1  christos /*%
   5297   1.1  christos  * Free any allocated memory associated with qctx.
   5298   1.1  christos  */
   5299   1.1  christos static void
   5300   1.1  christos qctx_freedata(query_ctx_t *qctx) {
   5301   1.1  christos 	if (qctx->rdataset != NULL) {
   5302   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   5303   1.1  christos 	}
   5304   1.1  christos 
   5305   1.1  christos 	if (qctx->sigrdataset != NULL) {
   5306   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   5307   1.1  christos 	}
   5308   1.1  christos 
   5309   1.1  christos 	if (qctx->fname != NULL) {
   5310   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   5311   1.1  christos 	}
   5312   1.1  christos 
   5313   1.1  christos 	if (qctx->db != NULL) {
   5314   1.1  christos 		INSIST(qctx->node == NULL);
   5315   1.1  christos 		dns_db_detach(&qctx->db);
   5316   1.1  christos 	}
   5317   1.1  christos 
   5318   1.1  christos 	if (qctx->zone != NULL) {
   5319   1.1  christos 		dns_zone_detach(&qctx->zone);
   5320   1.1  christos 	}
   5321   1.1  christos 
   5322   1.1  christos 	if (qctx->zdb != NULL) {
   5323   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->zsigrdataset);
   5324   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->zrdataset);
   5325   1.3  christos 		ns_client_releasename(qctx->client, &qctx->zfname);
   5326   1.3  christos 		dns_db_detachnode(qctx->zdb, &qctx->znode);
   5327   1.1  christos 		dns_db_detach(&qctx->zdb);
   5328  1.22  christos 		qctx->zversion = NULL;
   5329   1.1  christos 	}
   5330   1.1  christos 
   5331  1.13  christos 	if (qctx->event != NULL && !qctx->client->nodetach) {
   5332   1.9  christos 		free_devent(qctx->client, ISC_EVENT_PTR(&qctx->event),
   5333   1.9  christos 			    &qctx->event);
   5334   1.1  christos 	}
   5335   1.1  christos }
   5336   1.1  christos 
   5337   1.3  christos static void
   5338   1.3  christos qctx_destroy(query_ctx_t *qctx) {
   5339   1.3  christos 	CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx);
   5340   1.3  christos 
   5341   1.3  christos 	dns_view_detach(&qctx->view);
   5342   1.3  christos }
   5343   1.3  christos 
   5344  1.20  christos /*
   5345  1.20  christos  * Call SAVE but set 'a' to NULL first so as not to assert.
   5346  1.20  christos  */
   5347  1.20  christos #define INITANDSAVE(a, b)   \
   5348  1.20  christos 	do {                \
   5349  1.20  christos 		a = NULL;   \
   5350  1.20  christos 		SAVE(a, b); \
   5351  1.20  christos 	} while (0)
   5352  1.20  christos 
   5353  1.20  christos /*
   5354  1.20  christos  * "save" qctx data from 'src' to 'tgt'.
   5355  1.20  christos  * It essentially moves ownership of the data from src to tgt, so the former
   5356  1.20  christos  * becomes unusable except for final cleanup (such as by qctx_destroy).
   5357  1.20  christos  * Note: this function doesn't attach to the client's handle.  It's the caller's
   5358  1.20  christos  * responsibility to do it if it's necessary.
   5359  1.20  christos  */
   5360  1.20  christos static void
   5361  1.20  christos qctx_save(query_ctx_t *src, query_ctx_t *tgt) {
   5362  1.20  christos 	/* First copy all fields in a straightforward way */
   5363  1.20  christos 	*tgt = *src;
   5364  1.20  christos 
   5365  1.20  christos 	/* Then "move" pointers (except client and view) */
   5366  1.20  christos 	INITANDSAVE(tgt->dbuf, src->dbuf);
   5367  1.20  christos 	INITANDSAVE(tgt->fname, src->fname);
   5368  1.20  christos 	INITANDSAVE(tgt->tname, src->tname);
   5369  1.20  christos 	INITANDSAVE(tgt->rdataset, src->rdataset);
   5370  1.20  christos 	INITANDSAVE(tgt->sigrdataset, src->sigrdataset);
   5371  1.20  christos 	INITANDSAVE(tgt->noqname, src->noqname);
   5372  1.20  christos 	INITANDSAVE(tgt->event, src->event);
   5373  1.20  christos 	INITANDSAVE(tgt->db, src->db);
   5374  1.20  christos 	INITANDSAVE(tgt->version, src->version);
   5375  1.20  christos 	INITANDSAVE(tgt->node, src->node);
   5376  1.20  christos 	INITANDSAVE(tgt->zdb, src->zdb);
   5377  1.20  christos 	INITANDSAVE(tgt->znode, src->znode);
   5378  1.20  christos 	INITANDSAVE(tgt->zfname, src->zfname);
   5379  1.20  christos 	INITANDSAVE(tgt->zversion, src->zversion);
   5380  1.20  christos 	INITANDSAVE(tgt->zrdataset, src->zrdataset);
   5381  1.20  christos 	INITANDSAVE(tgt->zsigrdataset, src->zsigrdataset);
   5382  1.20  christos 	INITANDSAVE(tgt->rpz_st, src->rpz_st);
   5383  1.20  christos 	INITANDSAVE(tgt->zone, src->zone);
   5384  1.20  christos 
   5385  1.20  christos 	/* View has to stay in 'src' for qctx_destroy. */
   5386  1.20  christos 	tgt->view = NULL;
   5387  1.20  christos 	dns_view_attach(src->view, &tgt->view);
   5388  1.20  christos }
   5389  1.20  christos 
   5390   1.1  christos /*%
   5391   1.1  christos  * Log detailed information about the query immediately after
   5392   1.1  christos  * the client request or a return from recursion.
   5393   1.1  christos  */
   5394   1.1  christos static void
   5395   1.1  christos query_trace(query_ctx_t *qctx) {
   5396   1.1  christos #ifdef WANT_QUERYTRACE
   5397   1.6  christos 	char mbuf[2 * DNS_NAME_FORMATSIZE];
   5398   1.1  christos 	char qbuf[DNS_NAME_FORMATSIZE];
   5399   1.1  christos 
   5400   1.9  christos 	if (qctx->client->query.origqname != NULL) {
   5401   1.1  christos 		dns_name_format(qctx->client->query.origqname, qbuf,
   5402   1.1  christos 				sizeof(qbuf));
   5403   1.9  christos 	} else {
   5404   1.1  christos 		snprintf(qbuf, sizeof(qbuf), "<unset>");
   5405   1.9  christos 	}
   5406   1.1  christos 
   5407   1.1  christos 	snprintf(mbuf, sizeof(mbuf) - 1,
   5408   1.1  christos 		 "client attr:0x%x, query attr:0x%X, restarts:%u, "
   5409   1.1  christos 		 "origqname:%s, timer:%d, authdb:%d, referral:%d",
   5410   1.9  christos 		 qctx->client->attributes, qctx->client->query.attributes,
   5411   1.1  christos 		 qctx->client->query.restarts, qbuf,
   5412   1.9  christos 		 (int)qctx->client->query.timerset,
   5413   1.9  christos 		 (int)qctx->client->query.authdbset,
   5414   1.9  christos 		 (int)qctx->client->query.isreferral);
   5415   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   5416   1.9  christos #else  /* ifdef WANT_QUERYTRACE */
   5417   1.1  christos 	UNUSED(qctx);
   5418   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   5419   1.1  christos }
   5420   1.1  christos 
   5421   1.1  christos /*
   5422   1.1  christos  * Set up query processing for the current query of 'client'.
   5423   1.1  christos  * Calls qctx_init() to initialize a query context, checks
   5424   1.1  christos  * the SERVFAIL cache, then hands off processing to ns__query_start().
   5425   1.1  christos  *
   5426   1.1  christos  * This is called only from ns_query_start(), to begin a query
   5427   1.1  christos  * for the first time.  Restarting an existing query (for
   5428   1.1  christos  * instance, to handle CNAME lookups), is done by calling
   5429   1.1  christos  * ns__query_start() again with the same query context. Resuming from
   5430   1.1  christos  * recursion is handled by query_resume().
   5431   1.1  christos  */
   5432   1.1  christos static isc_result_t
   5433   1.1  christos query_setup(ns_client_t *client, dns_rdatatype_t qtype) {
   5434  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   5435   1.1  christos 	query_ctx_t qctx;
   5436   1.1  christos 
   5437   1.1  christos 	qctx_init(client, NULL, qtype, &qctx);
   5438   1.1  christos 	query_trace(&qctx);
   5439   1.1  christos 
   5440   1.3  christos 	CALL_HOOK(NS_QUERY_SETUP, &qctx);
   5441   1.3  christos 
   5442   1.1  christos 	/*
   5443   1.1  christos 	 * Check SERVFAIL cache
   5444   1.1  christos 	 */
   5445   1.1  christos 	result = ns__query_sfcache(&qctx);
   5446   1.1  christos 	if (result != ISC_R_COMPLETE) {
   5447   1.3  christos 		qctx_destroy(&qctx);
   5448   1.1  christos 		return (result);
   5449   1.1  christos 	}
   5450   1.1  christos 
   5451   1.3  christos 	result = ns__query_start(&qctx);
   5452   1.3  christos 
   5453   1.9  christos cleanup:
   5454   1.3  christos 	qctx_destroy(&qctx);
   5455   1.3  christos 	return (result);
   5456   1.1  christos }
   5457   1.1  christos 
   5458   1.3  christos static bool
   5459   1.1  christos get_root_key_sentinel_id(query_ctx_t *qctx, const char *ndata) {
   5460   1.1  christos 	unsigned int v = 0;
   5461   1.1  christos 	int i;
   5462   1.1  christos 
   5463   1.1  christos 	for (i = 0; i < 5; i++) {
   5464  1.14  christos 		if (!isdigit((unsigned char)ndata[i])) {
   5465   1.3  christos 			return (false);
   5466   1.1  christos 		}
   5467   1.1  christos 		v *= 10;
   5468   1.1  christos 		v += ndata[i] - '0';
   5469   1.1  christos 	}
   5470   1.1  christos 	if (v > 65535U) {
   5471   1.3  christos 		return (false);
   5472   1.1  christos 	}
   5473   1.1  christos 	qctx->client->query.root_key_sentinel_keyid = v;
   5474   1.3  christos 	return (true);
   5475   1.1  christos }
   5476   1.1  christos 
   5477   1.1  christos /*%
   5478   1.1  christos  * Find out if the query is for a root key sentinel and if so, record the type
   5479   1.1  christos  * of root key sentinel query and the key id that is being checked for.
   5480   1.1  christos  *
   5481   1.1  christos  * The code is assuming a zero padded decimal field of width 5.
   5482   1.1  christos  */
   5483   1.1  christos static void
   5484   1.1  christos root_key_sentinel_detect(query_ctx_t *qctx) {
   5485   1.1  christos 	const char *ndata = (const char *)qctx->client->query.qname->ndata;
   5486   1.1  christos 
   5487   1.1  christos 	if (qctx->client->query.qname->length > 30 && ndata[0] == 29 &&
   5488   1.1  christos 	    strncasecmp(ndata + 1, "root-key-sentinel-is-ta-", 24) == 0)
   5489   1.1  christos 	{
   5490   1.1  christos 		if (!get_root_key_sentinel_id(qctx, ndata + 25)) {
   5491   1.1  christos 			return;
   5492   1.1  christos 		}
   5493   1.3  christos 		qctx->client->query.root_key_sentinel_is_ta = true;
   5494   1.1  christos 		/*
   5495   1.9  christos 		 * Simplify processing by disabling aggressive
   5496   1.1  christos 		 * negative caching.
   5497   1.1  christos 		 */
   5498   1.3  christos 		qctx->findcoveringnsec = false;
   5499   1.1  christos 		ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
   5500   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5501   1.1  christos 			      "root-key-sentinel-is-ta query label found");
   5502   1.1  christos 	} else if (qctx->client->query.qname->length > 31 && ndata[0] == 30 &&
   5503   1.1  christos 		   strncasecmp(ndata + 1, "root-key-sentinel-not-ta-", 25) == 0)
   5504   1.1  christos 	{
   5505   1.1  christos 		if (!get_root_key_sentinel_id(qctx, ndata + 26)) {
   5506   1.1  christos 			return;
   5507   1.1  christos 		}
   5508   1.3  christos 		qctx->client->query.root_key_sentinel_not_ta = true;
   5509   1.1  christos 		/*
   5510   1.9  christos 		 * Simplify processing by disabling aggressive
   5511   1.1  christos 		 * negative caching.
   5512   1.1  christos 		 */
   5513   1.3  christos 		qctx->findcoveringnsec = false;
   5514   1.1  christos 		ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
   5515   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5516   1.1  christos 			      "root-key-sentinel-not-ta query label found");
   5517   1.1  christos 	}
   5518   1.1  christos }
   5519   1.1  christos 
   5520   1.1  christos /*%
   5521   1.1  christos  * Starting point for a client query or a chaining query.
   5522   1.1  christos  *
   5523   1.1  christos  * Called first by query_setup(), and then again as often as needed to
   5524   1.1  christos  * follow a CNAME chain.  Determines which authoritative database to
   5525   1.1  christos  * search, then hands off processing to query_lookup().
   5526   1.1  christos  */
   5527   1.1  christos isc_result_t
   5528   1.1  christos ns__query_start(query_ctx_t *qctx) {
   5529  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   5530   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "ns__query_start");
   5531   1.3  christos 	qctx->want_restart = false;
   5532   1.3  christos 	qctx->authoritative = false;
   5533   1.1  christos 	qctx->version = NULL;
   5534   1.1  christos 	qctx->zversion = NULL;
   5535   1.3  christos 	qctx->need_wildcardproof = false;
   5536   1.3  christos 	qctx->rpz = false;
   5537   1.3  christos 
   5538   1.3  christos 	CALL_HOOK(NS_QUERY_START_BEGIN, qctx);
   5539   1.3  christos 
   5540   1.3  christos 	/*
   5541   1.3  christos 	 * If we require a server cookie then send back BADCOOKIE
   5542   1.3  christos 	 * before we have done too much work.
   5543   1.3  christos 	 */
   5544   1.3  christos 	if (!TCP(qctx->client) && qctx->view->requireservercookie &&
   5545   1.3  christos 	    WANTCOOKIE(qctx->client) && !HAVECOOKIE(qctx->client))
   5546   1.3  christos 	{
   5547   1.3  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
   5548   1.3  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
   5549   1.3  christos 		qctx->client->message->rcode = dns_rcode_badcookie;
   5550   1.3  christos 		return (ns_query_done(qctx));
   5551   1.3  christos 	}
   5552   1.1  christos 
   5553   1.3  christos 	if (qctx->view->checknames &&
   5554   1.1  christos 	    !dns_rdata_checkowner(qctx->client->query.qname,
   5555   1.9  christos 				  qctx->client->message->rdclass, qctx->qtype,
   5556   1.9  christos 				  false))
   5557   1.1  christos 	{
   5558   1.1  christos 		char namebuf[DNS_NAME_FORMATSIZE];
   5559   1.3  christos 		char typebuf[DNS_RDATATYPE_FORMATSIZE];
   5560   1.3  christos 		char classbuf[DNS_RDATACLASS_FORMATSIZE];
   5561   1.1  christos 
   5562   1.9  christos 		dns_name_format(qctx->client->query.qname, namebuf,
   5563   1.9  christos 				sizeof(namebuf));
   5564   1.3  christos 		dns_rdatatype_format(qctx->qtype, typebuf, sizeof(typebuf));
   5565   1.9  christos 		dns_rdataclass_format(qctx->client->message->rdclass, classbuf,
   5566   1.9  christos 				      sizeof(classbuf));
   5567   1.1  christos 		ns_client_log(qctx->client, DNS_LOGCATEGORY_SECURITY,
   5568   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_ERROR,
   5569   1.9  christos 			      "check-names failure %s/%s/%s", namebuf, typebuf,
   5570   1.9  christos 			      classbuf);
   5571   1.1  christos 		QUERY_ERROR(qctx, DNS_R_REFUSED);
   5572   1.3  christos 		return (ns_query_done(qctx));
   5573   1.1  christos 	}
   5574   1.1  christos 
   5575   1.1  christos 	/*
   5576   1.1  christos 	 * Setup for root key sentinel processing.
   5577   1.1  christos 	 */
   5578   1.3  christos 	if (qctx->view->root_key_sentinel &&
   5579   1.1  christos 	    qctx->client->query.restarts == 0 &&
   5580   1.1  christos 	    (qctx->qtype == dns_rdatatype_a ||
   5581   1.1  christos 	     qctx->qtype == dns_rdatatype_aaaa) &&
   5582   1.1  christos 	    (qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)
   5583   1.1  christos 	{
   5584   1.9  christos 		root_key_sentinel_detect(qctx);
   5585   1.1  christos 	}
   5586   1.1  christos 
   5587   1.1  christos 	/*
   5588   1.1  christos 	 * First we must find the right database.
   5589   1.1  christos 	 */
   5590   1.1  christos 	qctx->options &= DNS_GETDB_NOLOG; /* Preserve DNS_GETDB_NOLOG. */
   5591   1.1  christos 	if (dns_rdatatype_atparent(qctx->qtype) &&
   5592   1.1  christos 	    !dns_name_equal(qctx->client->query.qname, dns_rootname))
   5593   1.1  christos 	{
   5594   1.1  christos 		/*
   5595   1.1  christos 		 * If authoritative data for this QTYPE is supposed to live in
   5596   1.1  christos 		 * the parent zone, do not look for an exact match for QNAME,
   5597   1.1  christos 		 * but rather for its containing zone (unless the QNAME is
   5598   1.1  christos 		 * root).
   5599   1.1  christos 		 */
   5600   1.1  christos 		qctx->options |= DNS_GETDB_NOEXACT;
   5601   1.1  christos 	}
   5602   1.1  christos 
   5603   1.1  christos 	result = query_getdb(qctx->client, qctx->client->query.qname,
   5604   1.9  christos 			     qctx->qtype, qctx->options, &qctx->zone, &qctx->db,
   5605   1.9  christos 			     &qctx->version, &qctx->is_zone);
   5606  1.20  christos 	if ((result != ISC_R_SUCCESS || !qctx->is_zone) &&
   5607  1.20  christos 	    qctx->qtype == dns_rdatatype_ds && !RECURSIONOK(qctx->client) &&
   5608  1.20  christos 	    (qctx->options & DNS_GETDB_NOEXACT) != 0)
   5609   1.1  christos 	{
   5610   1.1  christos 		/*
   5611   1.1  christos 		 * This is a non-recursive QTYPE=DS query with QNAME whose
   5612   1.1  christos 		 * parent we are not authoritative for.  Check whether we are
   5613   1.1  christos 		 * authoritative for QNAME, because if so, we need to send a
   5614   1.1  christos 		 * "no data" response as required by RFC 4035, section 3.1.4.1.
   5615   1.1  christos 		 */
   5616   1.1  christos 		dns_db_t *tdb = NULL;
   5617   1.1  christos 		dns_zone_t *tzone = NULL;
   5618   1.1  christos 		dns_dbversion_t *tversion = NULL;
   5619   1.1  christos 		isc_result_t tresult;
   5620   1.1  christos 
   5621   1.9  christos 		tresult = query_getzonedb(
   5622   1.9  christos 			qctx->client, qctx->client->query.qname, qctx->qtype,
   5623   1.9  christos 			DNS_GETDB_PARTIAL, &tzone, &tdb, &tversion);
   5624   1.1  christos 		if (tresult == ISC_R_SUCCESS) {
   5625   1.1  christos 			/*
   5626   1.1  christos 			 * We are authoritative for QNAME.  Attach the relevant
   5627   1.1  christos 			 * zone to query context, set result to ISC_R_SUCCESS.
   5628   1.1  christos 			 */
   5629   1.1  christos 			qctx->options &= ~DNS_GETDB_NOEXACT;
   5630   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   5631   1.1  christos 			if (qctx->db != NULL) {
   5632   1.1  christos 				dns_db_detach(&qctx->db);
   5633   1.1  christos 			}
   5634   1.1  christos 			if (qctx->zone != NULL) {
   5635   1.1  christos 				dns_zone_detach(&qctx->zone);
   5636   1.1  christos 			}
   5637   1.1  christos 			qctx->version = NULL;
   5638   1.1  christos 			RESTORE(qctx->version, tversion);
   5639   1.1  christos 			RESTORE(qctx->db, tdb);
   5640   1.1  christos 			RESTORE(qctx->zone, tzone);
   5641   1.3  christos 			qctx->is_zone = true;
   5642   1.1  christos 			result = ISC_R_SUCCESS;
   5643   1.1  christos 		} else {
   5644   1.1  christos 			/*
   5645   1.1  christos 			 * We are not authoritative for QNAME.  Clean up and
   5646   1.1  christos 			 * leave result as it was.
   5647   1.1  christos 			 */
   5648   1.1  christos 			if (tdb != NULL) {
   5649   1.1  christos 				dns_db_detach(&tdb);
   5650   1.1  christos 			}
   5651   1.1  christos 			if (tzone != NULL) {
   5652   1.1  christos 				dns_zone_detach(&tzone);
   5653   1.1  christos 			}
   5654   1.1  christos 		}
   5655   1.1  christos 	}
   5656   1.1  christos 	/*
   5657   1.1  christos 	 * If we did not find a database from which we can answer the query,
   5658   1.1  christos 	 * respond with either REFUSED or SERVFAIL, depending on what the
   5659   1.1  christos 	 * result of query_getdb() was.
   5660   1.1  christos 	 */
   5661   1.1  christos 	if (result != ISC_R_SUCCESS) {
   5662   1.1  christos 		if (result == DNS_R_REFUSED) {
   5663   1.1  christos 			if (WANTRECURSION(qctx->client)) {
   5664   1.1  christos 				inc_stats(qctx->client,
   5665   1.1  christos 					  ns_statscounter_recurserej);
   5666   1.1  christos 			} else {
   5667   1.1  christos 				inc_stats(qctx->client,
   5668   1.1  christos 					  ns_statscounter_authrej);
   5669   1.1  christos 			}
   5670   1.1  christos 			if (!PARTIALANSWER(qctx->client)) {
   5671   1.1  christos 				QUERY_ERROR(qctx, DNS_R_REFUSED);
   5672   1.1  christos 			}
   5673   1.1  christos 		} else {
   5674   1.9  christos 			CCTRACE(ISC_LOG_ERROR, "ns__query_start: query_getdb "
   5675   1.9  christos 					       "failed");
   5676   1.3  christos 			QUERY_ERROR(qctx, result);
   5677   1.1  christos 		}
   5678   1.3  christos 		return (ns_query_done(qctx));
   5679   1.1  christos 	}
   5680   1.1  christos 
   5681   1.1  christos 	/*
   5682   1.1  christos 	 * We found a database from which we can answer the query.  Update
   5683   1.1  christos 	 * relevant query context flags if the answer is to be prepared using
   5684   1.1  christos 	 * authoritative data.
   5685   1.1  christos 	 */
   5686   1.3  christos 	qctx->is_staticstub_zone = false;
   5687   1.1  christos 	if (qctx->is_zone) {
   5688   1.3  christos 		qctx->authoritative = true;
   5689   1.3  christos 		if (qctx->zone != NULL) {
   5690   1.3  christos 			if (dns_zone_gettype(qctx->zone) == dns_zone_mirror) {
   5691   1.3  christos 				qctx->authoritative = false;
   5692   1.3  christos 			}
   5693   1.9  christos 			if (dns_zone_gettype(qctx->zone) == dns_zone_staticstub)
   5694   1.3  christos 			{
   5695   1.3  christos 				qctx->is_staticstub_zone = true;
   5696   1.3  christos 			}
   5697   1.1  christos 		}
   5698   1.1  christos 	}
   5699   1.1  christos 
   5700   1.1  christos 	/*
   5701   1.1  christos 	 * Attach to the database which will be used to prepare the answer.
   5702   1.1  christos 	 * Update query statistics.
   5703   1.1  christos 	 */
   5704   1.1  christos 	if (qctx->event == NULL && qctx->client->query.restarts == 0) {
   5705   1.1  christos 		if (qctx->is_zone) {
   5706   1.1  christos 			if (qctx->zone != NULL) {
   5707   1.1  christos 				/*
   5708   1.1  christos 				 * if is_zone = true, zone = NULL then this is
   5709   1.1  christos 				 * a DLZ zone.  Don't attempt to attach zone.
   5710   1.1  christos 				 */
   5711   1.1  christos 				dns_zone_attach(qctx->zone,
   5712   1.1  christos 						&qctx->client->query.authzone);
   5713   1.1  christos 			}
   5714   1.1  christos 			dns_db_attach(qctx->db, &qctx->client->query.authdb);
   5715   1.1  christos 		}
   5716   1.3  christos 		qctx->client->query.authdbset = true;
   5717   1.1  christos 
   5718   1.1  christos 		/* Track TCP vs UDP stats per zone */
   5719   1.1  christos 		if (TCP(qctx->client)) {
   5720   1.1  christos 			inc_stats(qctx->client, ns_statscounter_tcp);
   5721   1.1  christos 		} else {
   5722   1.1  christos 			inc_stats(qctx->client, ns_statscounter_udp);
   5723   1.1  christos 		}
   5724   1.1  christos 	}
   5725   1.1  christos 
   5726  1.11  christos 	if (!qctx->is_zone && (qctx->view->staleanswerclienttimeout == 0) &&
   5727  1.11  christos 	    dns_view_staleanswerenabled(qctx->view))
   5728  1.11  christos 	{
   5729  1.11  christos 		/*
   5730  1.11  christos 		 * If stale answers are enabled and
   5731  1.11  christos 		 * stale-answer-client-timeout is zero, then we can promptly
   5732  1.11  christos 		 * answer with a stale RRset if one is available in cache.
   5733  1.11  christos 		 */
   5734  1.11  christos 		qctx->options |= DNS_GETDB_STALEFIRST;
   5735  1.11  christos 	}
   5736  1.11  christos 
   5737  1.11  christos 	result = query_lookup(qctx);
   5738  1.11  christos 
   5739  1.11  christos 	/*
   5740  1.11  christos 	 * Clear "look-also-for-stale-data" flag.
   5741  1.11  christos 	 * If a fetch is created to resolve this query, then,
   5742  1.11  christos 	 * when it completes, this option is not expected to be set.
   5743  1.11  christos 	 */
   5744  1.11  christos 	qctx->options &= ~DNS_GETDB_STALEFIRST;
   5745   1.3  christos 
   5746   1.9  christos cleanup:
   5747   1.3  christos 	return (result);
   5748   1.1  christos }
   5749   1.1  christos 
   5750  1.11  christos /*
   5751  1.11  christos  * Allocate buffers in 'qctx' used to store query results.
   5752  1.11  christos  *
   5753  1.11  christos  * 'buffer' must be a pointer to an object whose lifetime
   5754  1.11  christos  * doesn't expire while 'qctx' is in use.
   5755  1.11  christos  */
   5756  1.11  christos static isc_result_t
   5757  1.11  christos qctx_prepare_buffers(query_ctx_t *qctx, isc_buffer_t *buffer) {
   5758  1.11  christos 	REQUIRE(qctx != NULL);
   5759  1.11  christos 	REQUIRE(qctx->client != NULL);
   5760  1.11  christos 	REQUIRE(buffer != NULL);
   5761  1.11  christos 
   5762  1.11  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   5763  1.20  christos 	if (qctx->dbuf == NULL) {
   5764  1.11  christos 		CCTRACE(ISC_LOG_ERROR,
   5765  1.11  christos 			"qctx_prepare_buffers: ns_client_getnamebuf "
   5766  1.11  christos 			"failed");
   5767  1.11  christos 		return (ISC_R_NOMEMORY);
   5768  1.11  christos 	}
   5769  1.11  christos 
   5770  1.11  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, buffer);
   5771  1.20  christos 	if (qctx->fname == NULL) {
   5772  1.11  christos 		CCTRACE(ISC_LOG_ERROR,
   5773  1.11  christos 			"qctx_prepare_buffers: ns_client_newname failed");
   5774  1.11  christos 
   5775  1.11  christos 		return (ISC_R_NOMEMORY);
   5776  1.11  christos 	}
   5777  1.11  christos 
   5778  1.11  christos 	qctx->rdataset = ns_client_newrdataset(qctx->client);
   5779  1.20  christos 	if (qctx->rdataset == NULL) {
   5780  1.11  christos 		CCTRACE(ISC_LOG_ERROR,
   5781  1.11  christos 			"qctx_prepare_buffers: ns_client_newrdataset failed");
   5782  1.11  christos 		goto error;
   5783  1.11  christos 	}
   5784  1.11  christos 
   5785  1.11  christos 	if ((WANTDNSSEC(qctx->client) || qctx->findcoveringnsec) &&
   5786  1.11  christos 	    (!qctx->is_zone || dns_db_issecure(qctx->db)))
   5787  1.11  christos 	{
   5788  1.11  christos 		qctx->sigrdataset = ns_client_newrdataset(qctx->client);
   5789  1.11  christos 		if (qctx->sigrdataset == NULL) {
   5790  1.11  christos 			CCTRACE(ISC_LOG_ERROR,
   5791  1.11  christos 				"qctx_prepare_buffers: "
   5792  1.11  christos 				"ns_client_newrdataset failed (2)");
   5793  1.11  christos 			goto error;
   5794  1.11  christos 		}
   5795  1.11  christos 	}
   5796  1.11  christos 
   5797  1.11  christos 	return (ISC_R_SUCCESS);
   5798  1.11  christos 
   5799  1.11  christos error:
   5800  1.11  christos 	if (qctx->fname != NULL) {
   5801  1.11  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   5802  1.11  christos 	}
   5803  1.11  christos 	if (qctx->rdataset != NULL) {
   5804  1.11  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   5805  1.11  christos 	}
   5806  1.11  christos 
   5807  1.11  christos 	return (ISC_R_NOMEMORY);
   5808  1.11  christos }
   5809  1.11  christos 
   5810  1.11  christos /*
   5811  1.11  christos  * Setup a new query context for resolving a query.
   5812  1.11  christos  *
   5813  1.11  christos  * This function is only called if both these conditions are met:
   5814  1.11  christos  *    1. BIND is configured with stale-answer-client-timeout 0.
   5815  1.11  christos  *    2. A stale RRset is found in cache during initial query
   5816  1.11  christos  *       database lookup.
   5817  1.11  christos  *
   5818  1.11  christos  * We continue with this function for refreshing/resolving an RRset
   5819  1.11  christos  * after answering a client with stale data.
   5820  1.11  christos  */
   5821  1.11  christos static void
   5822  1.11  christos query_refresh_rrset(query_ctx_t *orig_qctx) {
   5823  1.11  christos 	isc_buffer_t buffer;
   5824  1.11  christos 	query_ctx_t qctx;
   5825  1.11  christos 
   5826  1.11  christos 	REQUIRE(orig_qctx != NULL);
   5827  1.11  christos 	REQUIRE(orig_qctx->client != NULL);
   5828  1.11  christos 
   5829  1.11  christos 	qctx_copy(orig_qctx, &qctx);
   5830  1.13  christos 	qctx.client->query.dboptions &= ~(DNS_DBFIND_STALETIMEOUT |
   5831  1.11  christos 					  DNS_DBFIND_STALEOK |
   5832  1.11  christos 					  DNS_DBFIND_STALEENABLED);
   5833  1.17  christos 	qctx.client->nodetach = false;
   5834  1.11  christos 
   5835  1.11  christos 	/*
   5836  1.11  christos 	 * We'll need some resources...
   5837  1.11  christos 	 */
   5838  1.11  christos 	if (qctx_prepare_buffers(&qctx, &buffer) != ISC_R_SUCCESS) {
   5839  1.11  christos 		dns_db_detach(&qctx.db);
   5840  1.11  christos 		qctx_destroy(&qctx);
   5841  1.11  christos 		return;
   5842  1.11  christos 	}
   5843  1.11  christos 
   5844  1.11  christos 	/*
   5845  1.11  christos 	 * Pretend we didn't find anything in cache.
   5846  1.11  christos 	 */
   5847  1.11  christos 	(void)query_gotanswer(&qctx, ISC_R_NOTFOUND);
   5848  1.11  christos 
   5849  1.11  christos 	if (qctx.fname != NULL) {
   5850  1.11  christos 		ns_client_releasename(qctx.client, &qctx.fname);
   5851  1.11  christos 	}
   5852  1.11  christos 	if (qctx.rdataset != NULL) {
   5853  1.11  christos 		ns_client_putrdataset(qctx.client, &qctx.rdataset);
   5854  1.11  christos 	}
   5855  1.11  christos 
   5856  1.11  christos 	qctx_destroy(&qctx);
   5857  1.11  christos }
   5858  1.11  christos 
   5859   1.1  christos /*%
   5860  1.17  christos  * Depending on the db lookup result, we can respond to the
   5861  1.17  christos  * client this stale answer.
   5862  1.17  christos  */
   5863  1.17  christos static bool
   5864  1.17  christos stale_client_answer(isc_result_t result) {
   5865  1.17  christos 	switch (result) {
   5866  1.17  christos 	case ISC_R_SUCCESS:
   5867  1.17  christos 	case DNS_R_EMPTYNAME:
   5868  1.17  christos 	case DNS_R_NXRRSET:
   5869  1.17  christos 	case DNS_R_NCACHENXRRSET:
   5870  1.17  christos 	case DNS_R_CNAME:
   5871  1.17  christos 	case DNS_R_DNAME:
   5872  1.17  christos 		return (true);
   5873  1.17  christos 	default:
   5874  1.17  christos 		return (false);
   5875  1.17  christos 	}
   5876  1.17  christos 
   5877  1.17  christos 	UNREACHABLE();
   5878  1.17  christos }
   5879  1.17  christos 
   5880  1.17  christos /*%
   5881   1.1  christos  * Perform a local database lookup, in either an authoritative or
   5882   1.3  christos  * cache database. If unable to answer, call ns_query_done(); otherwise
   5883   1.1  christos  * hand off processing to query_gotanswer().
   5884   1.1  christos  */
   5885   1.1  christos static isc_result_t
   5886   1.1  christos query_lookup(query_ctx_t *qctx) {
   5887  1.11  christos 	isc_buffer_t buffer;
   5888  1.11  christos 	isc_result_t result = ISC_R_UNSET;
   5889   1.1  christos 	dns_clientinfomethods_t cm;
   5890   1.1  christos 	dns_clientinfo_t ci;
   5891   1.1  christos 	dns_name_t *rpzqname = NULL;
   5892  1.13  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   5893   1.1  christos 	unsigned int dboptions;
   5894  1.11  christos 	dns_ttl_t stale_refresh = 0;
   5895  1.11  christos 	bool dbfind_stale = false;
   5896  1.13  christos 	bool stale_timeout = false;
   5897  1.16  christos 	bool answer_found = false;
   5898  1.11  christos 	bool stale_found = false;
   5899  1.11  christos 	bool stale_refresh_window = false;
   5900  1.20  christos 	uint16_t ede = 0;
   5901   1.1  christos 
   5902   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_lookup");
   5903   1.1  christos 
   5904   1.3  christos 	CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx);
   5905   1.1  christos 
   5906   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   5907  1.20  christos 	dns_clientinfo_init(&ci, qctx->client, NULL);
   5908  1.20  christos 	if (HAVEECS(qctx->client)) {
   5909  1.20  christos 		dns_clientinfo_setecs(&ci, &qctx->client->ecs);
   5910  1.20  christos 	}
   5911   1.1  christos 
   5912   1.1  christos 	/*
   5913   1.1  christos 	 * We'll need some resources...
   5914   1.1  christos 	 */
   5915  1.11  christos 	result = qctx_prepare_buffers(qctx, &buffer);
   5916  1.11  christos 	if (result != ISC_R_SUCCESS) {
   5917  1.11  christos 		QUERY_ERROR(qctx, result);
   5918   1.3  christos 		return (ns_query_done(qctx));
   5919   1.1  christos 	}
   5920   1.1  christos 
   5921   1.1  christos 	/*
   5922   1.1  christos 	 * Now look for an answer in the database.
   5923   1.1  christos 	 */
   5924   1.1  christos 	if (qctx->dns64 && qctx->rpz) {
   5925   1.1  christos 		rpzqname = qctx->client->query.rpz_st->p_name;
   5926   1.1  christos 	} else {
   5927   1.1  christos 		rpzqname = qctx->client->query.qname;
   5928   1.1  christos 	}
   5929   1.1  christos 
   5930  1.11  christos 	if ((qctx->options & DNS_GETDB_STALEFIRST) != 0) {
   5931  1.11  christos 		/*
   5932  1.11  christos 		 * If DNS_GETDB_STALEFIRST is set, it means that a stale
   5933  1.11  christos 		 * RRset may be returned as part of this lookup. An attempt
   5934  1.11  christos 		 * to refresh the RRset will still take place if an
   5935  1.11  christos 		 * active RRset is not available.
   5936  1.11  christos 		 */
   5937  1.13  christos 		qctx->client->query.dboptions |= DNS_DBFIND_STALETIMEOUT;
   5938  1.11  christos 	}
   5939  1.11  christos 
   5940   1.1  christos 	dboptions = qctx->client->query.dboptions;
   5941   1.1  christos 	if (!qctx->is_zone && qctx->findcoveringnsec &&
   5942   1.1  christos 	    (qctx->type != dns_rdatatype_null || !dns_name_istat(rpzqname)))
   5943   1.9  christos 	{
   5944   1.1  christos 		dboptions |= DNS_DBFIND_COVERINGNSEC;
   5945   1.9  christos 	}
   5946   1.1  christos 
   5947  1.11  christos 	(void)dns_db_getservestalerefresh(qctx->client->view->cachedb,
   5948  1.11  christos 					  &stale_refresh);
   5949  1.11  christos 	if (stale_refresh > 0 &&
   5950  1.16  christos 	    dns_view_staleanswerenabled(qctx->client->view))
   5951  1.16  christos 	{
   5952  1.11  christos 		dboptions |= DNS_DBFIND_STALEENABLED;
   5953  1.11  christos 	}
   5954  1.11  christos 
   5955   1.1  christos 	result = dns_db_findext(qctx->db, rpzqname, qctx->version, qctx->type,
   5956   1.1  christos 				dboptions, qctx->client->now, &qctx->node,
   5957   1.9  christos 				qctx->fname, &cm, &ci, qctx->rdataset,
   5958   1.9  christos 				qctx->sigrdataset);
   5959   1.1  christos 
   5960   1.1  christos 	/*
   5961   1.1  christos 	 * Fixup fname and sigrdataset.
   5962   1.1  christos 	 */
   5963   1.1  christos 	if (qctx->dns64 && qctx->rpz) {
   5964  1.20  christos 		dns_name_copy(qctx->client->query.qname, qctx->fname);
   5965   1.1  christos 		if (qctx->sigrdataset != NULL &&
   5966  1.16  christos 		    dns_rdataset_isassociated(qctx->sigrdataset))
   5967  1.16  christos 		{
   5968   1.1  christos 			dns_rdataset_disassociate(qctx->sigrdataset);
   5969   1.1  christos 		}
   5970   1.1  christos 	}
   5971   1.1  christos 
   5972   1.1  christos 	if (!qctx->is_zone) {
   5973   1.3  christos 		dns_cache_updatestats(qctx->view->cache, result);
   5974   1.1  christos 	}
   5975   1.1  christos 
   5976  1.11  christos 	/*
   5977  1.11  christos 	 * If DNS_DBFIND_STALEOK is set this means we are dealing with a
   5978  1.11  christos 	 * lookup following a failed lookup and it is okay to serve a stale
   5979  1.11  christos 	 * answer. This will (re)start the 'stale-refresh-time' window in
   5980  1.11  christos 	 * rbtdb, tracking the last time the RRset lookup failed.
   5981  1.11  christos 	 */
   5982  1.11  christos 	dbfind_stale = ((dboptions & DNS_DBFIND_STALEOK) != 0);
   5983  1.11  christos 
   5984  1.11  christos 	/*
   5985  1.11  christos 	 * If DNS_DBFIND_STALEENABLED is set, this may be a normal lookup, but
   5986  1.11  christos 	 * we are allowed to immediately respond with a stale answer if the
   5987  1.11  christos 	 * request is within the 'stale-refresh-time' window.
   5988  1.11  christos 	 */
   5989  1.11  christos 	stale_refresh_window = (STALE_WINDOW(qctx->rdataset) &&
   5990  1.11  christos 				(dboptions & DNS_DBFIND_STALEENABLED) != 0);
   5991  1.11  christos 
   5992  1.11  christos 	/*
   5993  1.13  christos 	 * If DNS_DBFIND_STALETIMEOUT is set, a stale answer is requested.
   5994  1.11  christos 	 * This can happen if 'stale-answer-client-timeout' is enabled.
   5995  1.11  christos 	 *
   5996  1.13  christos 	 * If 'stale-answer-client-timeout' is set to 0, and a stale
   5997  1.11  christos 	 * answer is found, send it to the client, and try to refresh the
   5998  1.13  christos 	 * RRset.
   5999  1.11  christos 	 *
   6000  1.13  christos 	 * If 'stale-answer-client-timeout' is non-zero, and a stale
   6001  1.11  christos 	 * answer is found, send it to the client. Don't try to refresh the
   6002  1.13  christos 	 * RRset because a fetch is already in progress.
   6003  1.11  christos 	 */
   6004  1.13  christos 	stale_timeout = ((dboptions & DNS_DBFIND_STALETIMEOUT) != 0);
   6005  1.11  christos 
   6006  1.16  christos 	if (dns_rdataset_isassociated(qctx->rdataset) &&
   6007  1.16  christos 	    dns_rdataset_count(qctx->rdataset) > 0 && !STALE(qctx->rdataset))
   6008  1.16  christos 	{
   6009  1.16  christos 		/* Found non-stale usable rdataset. */
   6010  1.16  christos 		answer_found = true;
   6011  1.16  christos 	}
   6012  1.16  christos 
   6013  1.13  christos 	if (dbfind_stale || stale_refresh_window || stale_timeout) {
   6014  1.13  christos 		dns_name_format(qctx->client->query.qname, namebuf,
   6015  1.13  christos 				sizeof(namebuf));
   6016   1.1  christos 
   6017  1.11  christos 		inc_stats(qctx->client, ns_statscounter_trystale);
   6018  1.11  christos 
   6019   1.1  christos 		if (dns_rdataset_isassociated(qctx->rdataset) &&
   6020   1.1  christos 		    dns_rdataset_count(qctx->rdataset) > 0 &&
   6021   1.9  christos 		    STALE(qctx->rdataset))
   6022   1.9  christos 		{
   6023  1.20  christos 			stale_found = true;
   6024  1.20  christos 			if (result == DNS_R_NCACHENXDOMAIN ||
   6025  1.20  christos 			    result == DNS_R_NXDOMAIN)
   6026  1.20  christos 			{
   6027  1.20  christos 				ede = DNS_EDE_STALENXANSWER;
   6028  1.20  christos 			} else {
   6029  1.20  christos 				ede = DNS_EDE_STALEANSWER;
   6030  1.20  christos 			}
   6031   1.3  christos 			qctx->rdataset->ttl = qctx->view->staleanswerttl;
   6032  1.14  christos 			inc_stats(qctx->client, ns_statscounter_usedstale);
   6033   1.1  christos 		} else {
   6034  1.11  christos 			stale_found = false;
   6035   1.1  christos 		}
   6036  1.13  christos 	}
   6037   1.1  christos 
   6038  1.13  christos 	if (dbfind_stale) {
   6039  1.13  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   6040  1.13  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   6041  1.13  christos 			      "%s resolver failure, stale answer %s", namebuf,
   6042  1.13  christos 			      stale_found ? "used" : "unavailable");
   6043  1.20  christos 		if (stale_found) {
   6044  1.20  christos 			ns_client_extendederror(qctx->client, ede,
   6045  1.20  christos 						"resolver failure");
   6046  1.20  christos 		} else if (!answer_found) {
   6047  1.13  christos 			/*
   6048  1.13  christos 			 * Resolver failure, no stale data, nothing more we
   6049  1.13  christos 			 * can do, return SERVFAIL.
   6050  1.13  christos 			 */
   6051  1.13  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   6052  1.13  christos 			return (ns_query_done(qctx));
   6053  1.13  christos 		}
   6054  1.13  christos 	} else if (stale_refresh_window) {
   6055  1.13  christos 		/*
   6056  1.13  christos 		 * A recent lookup failed, so during this time window we are
   6057  1.13  christos 		 * allowed to return stale data immediately.
   6058  1.13  christos 		 */
   6059  1.13  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   6060  1.13  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   6061  1.13  christos 			      "%s query within stale refresh time, stale "
   6062  1.13  christos 			      "answer %s",
   6063  1.13  christos 			      namebuf, stale_found ? "used" : "unavailable");
   6064  1.11  christos 
   6065  1.20  christos 		if (stale_found) {
   6066  1.20  christos 			ns_client_extendederror(
   6067  1.20  christos 				qctx->client, ede,
   6068  1.20  christos 				"query within stale refresh time window");
   6069  1.20  christos 		} else if (!answer_found) {
   6070  1.11  christos 			/*
   6071  1.13  christos 			 * During the stale refresh window explicitly do not try
   6072  1.13  christos 			 * to refresh the data, because a recent lookup failed.
   6073  1.11  christos 			 */
   6074  1.13  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   6075  1.13  christos 			return (ns_query_done(qctx));
   6076  1.13  christos 		}
   6077  1.13  christos 	} else if (stale_timeout) {
   6078  1.13  christos 		if ((qctx->options & DNS_GETDB_STALEFIRST) != 0) {
   6079  1.17  christos 			if (!stale_found && !answer_found) {
   6080  1.11  christos 				/*
   6081  1.13  christos 				 * We have nothing useful in cache to return
   6082  1.13  christos 				 * immediately.
   6083  1.11  christos 				 */
   6084  1.13  christos 				qctx_clean(qctx);
   6085  1.13  christos 				qctx_freedata(qctx);
   6086  1.13  christos 				dns_db_attach(qctx->client->view->cachedb,
   6087  1.13  christos 					      &qctx->db);
   6088  1.13  christos 				qctx->client->query.dboptions &=
   6089  1.13  christos 					~DNS_DBFIND_STALETIMEOUT;
   6090  1.13  christos 				qctx->options &= ~DNS_GETDB_STALEFIRST;
   6091  1.13  christos 				if (qctx->client->query.fetch != NULL) {
   6092  1.13  christos 					dns_resolver_destroyfetch(
   6093  1.13  christos 						&qctx->client->query.fetch);
   6094  1.11  christos 				}
   6095  1.14  christos 				return (query_lookup(qctx));
   6096  1.17  christos 			} else if (stale_client_answer(result)) {
   6097  1.11  christos 				/*
   6098  1.13  christos 				 * Immediately return the stale answer, start a
   6099  1.13  christos 				 * resolver fetch to refresh the data in cache.
   6100  1.11  christos 				 */
   6101  1.11  christos 				isc_log_write(
   6102  1.11  christos 					ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   6103  1.11  christos 					NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   6104  1.13  christos 					"%s stale answer used, an attempt to "
   6105  1.13  christos 					"refresh the RRset will still be made",
   6106  1.13  christos 					namebuf);
   6107  1.17  christos 
   6108  1.15  christos 				qctx->refresh_rrset = STALE(qctx->rdataset);
   6109  1.17  christos 				/*
   6110  1.17  christos 				 * If we are refreshing the RRSet, we must not
   6111  1.17  christos 				 * detach from the client in query_send().
   6112  1.17  christos 				 */
   6113  1.17  christos 				qctx->client->nodetach = qctx->refresh_rrset;
   6114  1.20  christos 
   6115  1.20  christos 				if (stale_found) {
   6116  1.20  christos 					ns_client_extendederror(
   6117  1.20  christos 						qctx->client, ede,
   6118  1.20  christos 						"stale data prioritized over "
   6119  1.20  christos 						"lookup");
   6120  1.20  christos 				}
   6121  1.13  christos 			}
   6122  1.13  christos 		} else {
   6123  1.13  christos 			/*
   6124  1.13  christos 			 * The 'stale-answer-client-timeout' triggered, return
   6125  1.13  christos 			 * the stale answer if available, otherwise wait until
   6126  1.13  christos 			 * the resolver finishes.
   6127  1.13  christos 			 */
   6128  1.13  christos 			isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   6129  1.13  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   6130  1.13  christos 				      "%s client timeout, stale answer %s",
   6131  1.13  christos 				      namebuf,
   6132  1.13  christos 				      stale_found ? "used" : "unavailable");
   6133  1.20  christos 			if (stale_found) {
   6134  1.20  christos 				ns_client_extendederror(qctx->client, ede,
   6135  1.20  christos 							"client timeout");
   6136  1.20  christos 			} else if (!answer_found) {
   6137  1.17  christos 				return (result);
   6138  1.17  christos 			}
   6139  1.17  christos 
   6140  1.17  christos 			if (!stale_client_answer(result)) {
   6141  1.13  christos 				return (result);
   6142  1.11  christos 			}
   6143  1.14  christos 
   6144  1.14  christos 			/*
   6145  1.14  christos 			 * There still might be real answer later. Mark the
   6146  1.14  christos 			 * query so we'll know we can skip answering.
   6147  1.14  christos 			 */
   6148  1.14  christos 			qctx->client->query.attributes |=
   6149  1.14  christos 				NS_QUERYATTR_STALEPENDING;
   6150   1.1  christos 		}
   6151  1.11  christos 	}
   6152  1.11  christos 
   6153  1.16  christos 	if (stale_timeout && (answer_found || stale_found)) {
   6154  1.11  christos 		/*
   6155  1.13  christos 		 * Mark RRsets that we are adding to the client message on a
   6156  1.13  christos 		 * lookup during 'stale-answer-client-timeout', so we can
   6157  1.13  christos 		 * clean it up if needed when we resume from recursion.
   6158  1.11  christos 		 */
   6159  1.13  christos 		qctx->client->query.attributes |= NS_QUERYATTR_STALEOK;
   6160  1.13  christos 		qctx->rdataset->attributes |= DNS_RDATASETATTR_STALE_ADDED;
   6161  1.11  christos 	}
   6162  1.14  christos 
   6163  1.11  christos 	result = query_gotanswer(qctx, result);
   6164  1.11  christos 
   6165   1.9  christos cleanup:
   6166   1.3  christos 	return (result);
   6167   1.1  christos }
   6168   1.1  christos 
   6169   1.1  christos /*
   6170  1.13  christos  * Clear all rdatasets from the message that are in the given section and
   6171  1.13  christos  * that have the 'attr' attribute set.
   6172  1.13  christos  */
   6173  1.13  christos static void
   6174  1.13  christos message_clearrdataset(dns_message_t *msg, unsigned int attr) {
   6175  1.13  christos 	unsigned int i;
   6176  1.13  christos 	dns_name_t *name, *next_name;
   6177  1.13  christos 	dns_rdataset_t *rds, *next_rds;
   6178  1.13  christos 
   6179  1.13  christos 	/*
   6180  1.13  christos 	 * Clean up name lists by calling the rdataset disassociate function.
   6181  1.13  christos 	 */
   6182  1.13  christos 	for (i = DNS_SECTION_ANSWER; i < DNS_SECTION_MAX; i++) {
   6183  1.13  christos 		name = ISC_LIST_HEAD(msg->sections[i]);
   6184  1.13  christos 		while (name != NULL) {
   6185  1.13  christos 			next_name = ISC_LIST_NEXT(name, link);
   6186  1.13  christos 
   6187  1.13  christos 			rds = ISC_LIST_HEAD(name->list);
   6188  1.13  christos 			while (rds != NULL) {
   6189  1.13  christos 				next_rds = ISC_LIST_NEXT(rds, link);
   6190  1.13  christos 				if ((rds->attributes & attr) != attr) {
   6191  1.13  christos 					rds = next_rds;
   6192  1.13  christos 					continue;
   6193  1.13  christos 				}
   6194  1.13  christos 				ISC_LIST_UNLINK(name->list, rds, link);
   6195  1.13  christos 				INSIST(dns_rdataset_isassociated(rds));
   6196  1.13  christos 				dns_rdataset_disassociate(rds);
   6197  1.13  christos 				isc_mempool_put(msg->rdspool, rds);
   6198  1.13  christos 				rds = next_rds;
   6199  1.13  christos 			}
   6200  1.13  christos 
   6201  1.13  christos 			if (ISC_LIST_EMPTY(name->list)) {
   6202  1.13  christos 				ISC_LIST_UNLINK(msg->sections[i], name, link);
   6203  1.13  christos 				if (dns_name_dynamic(name)) {
   6204  1.13  christos 					dns_name_free(name, msg->mctx);
   6205  1.13  christos 				}
   6206  1.13  christos 				isc_mempool_put(msg->namepool, name);
   6207  1.13  christos 			}
   6208  1.13  christos 
   6209  1.13  christos 			name = next_name;
   6210  1.13  christos 		}
   6211  1.13  christos 	}
   6212  1.13  christos }
   6213  1.13  christos 
   6214  1.13  christos /*
   6215  1.13  christos  * Clear any rdatasets from the client's message that were added on a lookup
   6216  1.13  christos  * due to a client timeout.
   6217  1.13  christos  */
   6218  1.13  christos static void
   6219  1.13  christos query_clear_stale(ns_client_t *client) {
   6220  1.13  christos 	message_clearrdataset(client->message, DNS_RDATASETATTR_STALE_ADDED);
   6221  1.13  christos }
   6222  1.13  christos 
   6223  1.13  christos /*
   6224  1.13  christos  * Create a new query context with the sole intent of looking up for a stale
   6225  1.13  christos  * RRset in cache. If an entry is found, we mark the original query as
   6226  1.13  christos  * answered, in order to avoid answering the query twice, when the original
   6227  1.13  christos  * fetch finishes.
   6228  1.11  christos  */
   6229  1.15  christos static void
   6230  1.13  christos query_lookup_stale(ns_client_t *client) {
   6231  1.11  christos 	query_ctx_t qctx;
   6232  1.11  christos 
   6233  1.11  christos 	qctx_init(client, NULL, client->query.qtype, &qctx);
   6234  1.19  christos 	if (DNS64(client)) {
   6235  1.19  christos 		qctx.qtype = qctx.type = dns_rdatatype_a;
   6236  1.19  christos 		qctx.dns64 = true;
   6237  1.19  christos 	}
   6238  1.19  christos 	if (DNS64EXCLUDE(client)) {
   6239  1.19  christos 		qctx.dns64_exclude = true;
   6240  1.19  christos 	}
   6241  1.11  christos 	dns_db_attach(client->view->cachedb, &qctx.db);
   6242  1.13  christos 	client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
   6243  1.13  christos 	client->query.dboptions |= DNS_DBFIND_STALETIMEOUT;
   6244  1.13  christos 	client->nodetach = true;
   6245  1.11  christos 	(void)query_lookup(&qctx);
   6246  1.11  christos 	if (qctx.node != NULL) {
   6247  1.11  christos 		dns_db_detachnode(qctx.db, &qctx.node);
   6248  1.11  christos 	}
   6249  1.11  christos 	qctx_freedata(&qctx);
   6250  1.11  christos 	qctx_destroy(&qctx);
   6251  1.11  christos }
   6252  1.11  christos 
   6253  1.11  christos /*
   6254  1.11  christos  * Event handler to resume processing a query after recursion, or when a
   6255  1.11  christos  * client timeout is triggered. If the query has timed out or been cancelled
   6256  1.11  christos  * or the system is shutting down, clean up and exit. If a client timeout is
   6257  1.11  christos  * triggered, see if we can respond with a stale answer from cache. Otherwise,
   6258  1.11  christos  * call query_resume() to continue the ongoing work.
   6259   1.1  christos  */
   6260   1.1  christos static void
   6261   1.1  christos fetch_callback(isc_task_t *task, isc_event_t *event) {
   6262   1.1  christos 	dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
   6263   1.1  christos 	dns_fetch_t *fetch = NULL;
   6264  1.14  christos 	ns_client_t *client = NULL;
   6265  1.14  christos 	bool fetch_canceled = false;
   6266  1.14  christos 	bool fetch_answered = false;
   6267  1.14  christos 	bool client_shuttingdown = false;
   6268  1.14  christos 	isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_ERRORS;
   6269   1.1  christos 	isc_result_t result;
   6270   1.1  christos 	int errorloglevel;
   6271  1.11  christos 	query_ctx_t qctx;
   6272   1.1  christos 
   6273   1.1  christos 	UNUSED(task);
   6274   1.1  christos 
   6275  1.11  christos 	REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE ||
   6276  1.11  christos 		event->ev_type == DNS_EVENT_TRYSTALE);
   6277  1.14  christos 
   6278   1.1  christos 	client = devent->ev_arg;
   6279  1.14  christos 
   6280   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   6281   1.1  christos 	REQUIRE(task == client->task);
   6282   1.1  christos 	REQUIRE(RECURSING(client));
   6283   1.1  christos 
   6284   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "fetch_callback");
   6285   1.9  christos 
   6286  1.11  christos 	if (event->ev_type == DNS_EVENT_TRYSTALE) {
   6287  1.16  christos 		if (devent->result != ISC_R_CANCELED) {
   6288  1.16  christos 			query_lookup_stale(client);
   6289  1.16  christos 		}
   6290  1.11  christos 		isc_event_free(ISC_EVENT_PTR(&event));
   6291  1.11  christos 		return;
   6292  1.11  christos 	}
   6293  1.13  christos 	/*
   6294  1.13  christos 	 * We are resuming from recursion. Reset any attributes, options
   6295  1.13  christos 	 * that a lookup due to stale-answer-client-timeout may have set.
   6296  1.13  christos 	 */
   6297  1.13  christos 	if (client->view->cachedb != NULL && client->view->recursion) {
   6298  1.13  christos 		client->query.attributes |= NS_QUERYATTR_RECURSIONOK;
   6299  1.13  christos 	}
   6300  1.14  christos 	client->query.fetchoptions &= ~DNS_FETCHOPT_TRYSTALE_ONTIMEOUT;
   6301  1.13  christos 	client->query.dboptions &= ~DNS_DBFIND_STALETIMEOUT;
   6302  1.13  christos 	client->nodetach = false;
   6303  1.13  christos 
   6304   1.1  christos 	LOCK(&client->query.fetchlock);
   6305  1.14  christos 	INSIST(client->query.fetch == devent->fetch ||
   6306  1.14  christos 	       client->query.fetch == NULL);
   6307  1.14  christos 	if (QUERY_STALEPENDING(&client->query)) {
   6308  1.14  christos 		/*
   6309  1.14  christos 		 * We've gotten an authoritative answer to a query that
   6310  1.14  christos 		 * was left pending after a stale timeout. We don't need
   6311  1.14  christos 		 * to do anything with it; free all the data and go home.
   6312  1.14  christos 		 */
   6313  1.14  christos 		client->query.fetch = NULL;
   6314  1.14  christos 		fetch_answered = true;
   6315  1.14  christos 	} else if (client->query.fetch != NULL) {
   6316   1.1  christos 		/*
   6317   1.1  christos 		 * This is the fetch we've been waiting for.
   6318   1.1  christos 		 */
   6319   1.1  christos 		INSIST(devent->fetch == client->query.fetch);
   6320   1.1  christos 		client->query.fetch = NULL;
   6321  1.14  christos 
   6322   1.1  christos 		/*
   6323   1.1  christos 		 * Update client->now.
   6324   1.1  christos 		 */
   6325   1.1  christos 		isc_stdtime_get(&client->now);
   6326   1.1  christos 	} else {
   6327   1.1  christos 		/*
   6328   1.1  christos 		 * This is a fetch completion event for a canceled fetch.
   6329   1.1  christos 		 * Clean up and don't resume the find.
   6330   1.1  christos 		 */
   6331   1.3  christos 		fetch_canceled = true;
   6332   1.1  christos 	}
   6333   1.1  christos 	UNLOCK(&client->query.fetchlock);
   6334   1.1  christos 
   6335   1.9  christos 	SAVE(fetch, devent->fetch);
   6336   1.9  christos 
   6337   1.9  christos 	/*
   6338   1.9  christos 	 * We're done recursing, detach from quota and unlink from
   6339   1.9  christos 	 * the manager's recursing-clients list.
   6340   1.9  christos 	 */
   6341   1.9  christos 
   6342   1.9  christos 	if (client->recursionquota != NULL) {
   6343   1.9  christos 		isc_quota_detach(&client->recursionquota);
   6344  1.16  christos 		ns_stats_decrement(client->sctx->nsstats,
   6345  1.16  christos 				   ns_statscounter_recursclients);
   6346   1.9  christos 	}
   6347   1.9  christos 
   6348   1.9  christos 	LOCK(&client->manager->reclock);
   6349   1.9  christos 	if (ISC_LINK_LINKED(client, rlink)) {
   6350   1.9  christos 		ISC_LIST_UNLINK(client->manager->recursing, client, rlink);
   6351   1.9  christos 	}
   6352   1.9  christos 	UNLOCK(&client->manager->reclock);
   6353   1.9  christos 
   6354  1.11  christos 	isc_nmhandle_detach(&client->fetchhandle);
   6355  1.11  christos 
   6356   1.1  christos 	client->query.attributes &= ~NS_QUERYATTR_RECURSING;
   6357   1.9  christos 	client->state = NS_CLIENTSTATE_WORKING;
   6358   1.1  christos 
   6359   1.1  christos 	/*
   6360  1.11  christos 	 * Initialize a new qctx and use it to either resume from
   6361  1.11  christos 	 * recursion or clean up after cancelation.  Transfer
   6362  1.11  christos 	 * ownership of devent to the new qctx in the process.
   6363   1.1  christos 	 */
   6364  1.11  christos 	qctx_init(client, &devent, 0, &qctx);
   6365  1.11  christos 
   6366   1.1  christos 	client_shuttingdown = ns_client_shuttingdown(client);
   6367  1.14  christos 	if (fetch_canceled || fetch_answered || client_shuttingdown) {
   6368  1.11  christos 		/*
   6369  1.11  christos 		 * We've timed out or are shutting down. We can now
   6370  1.11  christos 		 * free the event and other resources held by qctx, but
   6371  1.11  christos 		 * don't call qctx_destroy() yet: it might destroy the
   6372  1.11  christos 		 * client, which we still need for a moment.
   6373  1.11  christos 		 */
   6374  1.11  christos 		qctx_freedata(&qctx);
   6375  1.11  christos 
   6376  1.11  christos 		/*
   6377  1.11  christos 		 * Return an error to the client, or just drop.
   6378  1.11  christos 		 */
   6379   1.1  christos 		if (fetch_canceled) {
   6380   1.1  christos 			CTRACE(ISC_LOG_ERROR, "fetch cancelled");
   6381   1.1  christos 			query_error(client, DNS_R_SERVFAIL, __LINE__);
   6382   1.1  christos 		} else {
   6383   1.1  christos 			query_next(client, ISC_R_CANCELED);
   6384   1.1  christos 		}
   6385  1.11  christos 
   6386  1.11  christos 		/*
   6387  1.11  christos 		 * Free any persistent plugin data that was allocated to
   6388  1.11  christos 		 * service the client, then detach the client object.
   6389  1.11  christos 		 */
   6390  1.11  christos 		qctx.detach_client = true;
   6391  1.11  christos 		qctx_destroy(&qctx);
   6392   1.1  christos 	} else {
   6393   1.3  christos 		/*
   6394  1.11  christos 		 * Resume the find process.
   6395   1.3  christos 		 */
   6396   1.1  christos 		query_trace(&qctx);
   6397   1.1  christos 
   6398   1.1  christos 		result = query_resume(&qctx);
   6399   1.1  christos 		if (result != ISC_R_SUCCESS) {
   6400   1.1  christos 			if (result == DNS_R_SERVFAIL) {
   6401   1.1  christos 				errorloglevel = ISC_LOG_DEBUG(2);
   6402   1.1  christos 			} else {
   6403   1.1  christos 				errorloglevel = ISC_LOG_DEBUG(4);
   6404   1.1  christos 			}
   6405   1.1  christos 			if (isc_log_wouldlog(ns_lctx, errorloglevel)) {
   6406   1.1  christos 				dns_resolver_logfetch(fetch, ns_lctx,
   6407   1.1  christos 						      logcategory,
   6408   1.1  christos 						      NS_LOGMODULE_QUERY,
   6409   1.3  christos 						      errorloglevel, false);
   6410   1.1  christos 			}
   6411   1.1  christos 		}
   6412   1.3  christos 
   6413   1.3  christos 		qctx_destroy(&qctx);
   6414   1.1  christos 	}
   6415   1.1  christos 
   6416   1.1  christos 	dns_resolver_destroyfetch(&fetch);
   6417   1.1  christos }
   6418   1.1  christos 
   6419   1.1  christos /*%
   6420   1.1  christos  * Check whether the recursion parameters in 'param' match the current query's
   6421   1.1  christos  * recursion parameters provided in 'qtype', 'qname', and 'qdomain'.
   6422   1.1  christos  */
   6423   1.3  christos static bool
   6424   1.1  christos recparam_match(const ns_query_recparam_t *param, dns_rdatatype_t qtype,
   6425   1.9  christos 	       const dns_name_t *qname, const dns_name_t *qdomain) {
   6426   1.1  christos 	REQUIRE(param != NULL);
   6427   1.1  christos 
   6428   1.9  christos 	return (param->qtype == qtype && param->qname != NULL &&
   6429   1.9  christos 		qname != NULL && param->qdomain != NULL && qdomain != NULL &&
   6430   1.3  christos 		dns_name_equal(param->qname, qname) &&
   6431   1.3  christos 		dns_name_equal(param->qdomain, qdomain));
   6432   1.1  christos }
   6433   1.1  christos 
   6434   1.1  christos /*%
   6435   1.1  christos  * Update 'param' with current query's recursion parameters provided in
   6436   1.1  christos  * 'qtype', 'qname', and 'qdomain'.
   6437   1.1  christos  */
   6438   1.1  christos static void
   6439   1.1  christos recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
   6440   1.9  christos 		const dns_name_t *qname, const dns_name_t *qdomain) {
   6441   1.1  christos 	REQUIRE(param != NULL);
   6442   1.1  christos 
   6443   1.1  christos 	param->qtype = qtype;
   6444   1.1  christos 
   6445   1.1  christos 	if (qname == NULL) {
   6446   1.1  christos 		param->qname = NULL;
   6447   1.1  christos 	} else {
   6448   1.3  christos 		param->qname = dns_fixedname_initname(&param->fqname);
   6449  1.20  christos 		dns_name_copy(qname, param->qname);
   6450   1.1  christos 	}
   6451   1.1  christos 
   6452   1.1  christos 	if (qdomain == NULL) {
   6453   1.1  christos 		param->qdomain = NULL;
   6454   1.1  christos 	} else {
   6455   1.3  christos 		param->qdomain = dns_fixedname_initname(&param->fqdomain);
   6456  1.20  christos 		dns_name_copy(qdomain, param->qdomain);
   6457   1.1  christos 	}
   6458   1.1  christos }
   6459   1.9  christos static atomic_uint_fast32_t last_soft, last_hard;
   6460   1.1  christos 
   6461  1.20  christos /*%
   6462  1.20  christos  * Check recursion quota before making the current client "recursing".
   6463  1.20  christos  */
   6464  1.20  christos static isc_result_t
   6465  1.20  christos check_recursionquota(ns_client_t *client) {
   6466  1.20  christos 	isc_result_t result = ISC_R_SUCCESS;
   6467   1.1  christos 
   6468   1.1  christos 	/*
   6469   1.1  christos 	 * We are about to recurse, which means that this client will
   6470   1.1  christos 	 * be unavailable for serving new requests for an indeterminate
   6471   1.1  christos 	 * amount of time.  If this client is currently responsible
   6472   1.1  christos 	 * for handling incoming queries, set up a new client
   6473   1.1  christos 	 * object to handle them while we are waiting for a
   6474   1.1  christos 	 * response.  There is no need to replace TCP clients
   6475   1.1  christos 	 * because those have already been replaced when the
   6476   1.1  christos 	 * connection was accepted (if allowed by the TCP quota).
   6477   1.1  christos 	 */
   6478   1.1  christos 	if (client->recursionquota == NULL) {
   6479   1.1  christos 		result = isc_quota_attach(&client->sctx->recursionquota,
   6480   1.1  christos 					  &client->recursionquota);
   6481  1.16  christos 		if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) {
   6482  1.16  christos 			ns_stats_increment(client->sctx->nsstats,
   6483  1.16  christos 					   ns_statscounter_recursclients);
   6484  1.16  christos 		}
   6485  1.16  christos 
   6486   1.9  christos 		if (result == ISC_R_SOFTQUOTA) {
   6487   1.1  christos 			isc_stdtime_t now;
   6488   1.1  christos 			isc_stdtime_get(&now);
   6489   1.9  christos 			if (now != atomic_load_relaxed(&last_soft)) {
   6490   1.9  christos 				atomic_store_relaxed(&last_soft, now);
   6491   1.1  christos 				ns_client_log(client, NS_LOGCATEGORY_CLIENT,
   6492   1.9  christos 					      NS_LOGMODULE_QUERY,
   6493   1.9  christos 					      ISC_LOG_WARNING,
   6494   1.9  christos 					      "recursive-clients soft limit "
   6495   1.9  christos 					      "exceeded (%u/%u/%u), "
   6496   1.9  christos 					      "aborting oldest query",
   6497   1.9  christos 					      isc_quota_getused(
   6498   1.9  christos 						      client->recursionquota),
   6499   1.9  christos 					      isc_quota_getsoft(
   6500   1.9  christos 						      client->recursionquota),
   6501   1.9  christos 					      isc_quota_getmax(
   6502   1.9  christos 						      client->recursionquota));
   6503   1.1  christos 			}
   6504   1.1  christos 			ns_client_killoldestquery(client);
   6505   1.1  christos 			result = ISC_R_SUCCESS;
   6506   1.1  christos 		} else if (result == ISC_R_QUOTA) {
   6507   1.1  christos 			isc_stdtime_t now;
   6508   1.1  christos 			isc_stdtime_get(&now);
   6509   1.9  christos 			if (now != atomic_load_relaxed(&last_hard)) {
   6510   1.4  christos 				ns_server_t *sctx = client->sctx;
   6511   1.9  christos 				atomic_store_relaxed(&last_hard, now);
   6512   1.9  christos 				ns_client_log(
   6513   1.9  christos 					client, NS_LOGCATEGORY_CLIENT,
   6514   1.9  christos 					NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   6515   1.9  christos 					"no more recursive clients "
   6516   1.9  christos 					"(%u/%u/%u): %s",
   6517   1.9  christos 					isc_quota_getused(
   6518   1.9  christos 						&sctx->recursionquota),
   6519   1.9  christos 					isc_quota_getsoft(
   6520   1.9  christos 						&sctx->recursionquota),
   6521   1.9  christos 					isc_quota_getmax(&sctx->recursionquota),
   6522   1.9  christos 					isc_result_totext(result));
   6523   1.1  christos 			}
   6524   1.1  christos 			ns_client_killoldestquery(client);
   6525   1.1  christos 		}
   6526   1.9  christos 		if (result != ISC_R_SUCCESS) {
   6527   1.9  christos 			return (result);
   6528   1.1  christos 		}
   6529   1.9  christos 
   6530  1.11  christos 		dns_message_clonebuffer(client->message);
   6531   1.1  christos 		ns_client_recursing(client);
   6532   1.1  christos 	}
   6533   1.1  christos 
   6534  1.20  christos 	return (result);
   6535  1.20  christos }
   6536  1.20  christos 
   6537  1.20  christos isc_result_t
   6538  1.20  christos ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
   6539  1.20  christos 		 dns_name_t *qdomain, dns_rdataset_t *nameservers,
   6540  1.20  christos 		 bool resuming) {
   6541  1.20  christos 	isc_result_t result;
   6542  1.20  christos 	dns_rdataset_t *rdataset, *sigrdataset;
   6543  1.20  christos 	isc_sockaddr_t *peeraddr = NULL;
   6544  1.20  christos 
   6545  1.20  christos 	CTRACE(ISC_LOG_DEBUG(3), "ns_query_recurse");
   6546  1.20  christos 
   6547  1.20  christos 	/*
   6548  1.20  christos 	 * Check recursion parameters from the previous query to see if they
   6549  1.20  christos 	 * match.  If not, update recursion parameters and proceed.
   6550  1.20  christos 	 */
   6551  1.20  christos 	if (recparam_match(&client->query.recparam, qtype, qname, qdomain)) {
   6552  1.20  christos 		ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
   6553  1.20  christos 			      ISC_LOG_INFO, "recursion loop detected");
   6554  1.20  christos 		return (ISC_R_ALREADYRUNNING);
   6555  1.20  christos 	}
   6556  1.20  christos 
   6557  1.20  christos 	recparam_update(&client->query.recparam, qtype, qname, qdomain);
   6558  1.20  christos 
   6559  1.20  christos 	if (!resuming) {
   6560  1.20  christos 		inc_stats(client, ns_statscounter_recursion);
   6561  1.20  christos 	}
   6562  1.20  christos 
   6563  1.20  christos 	result = check_recursionquota(client);
   6564  1.20  christos 	if (result != ISC_R_SUCCESS) {
   6565  1.20  christos 		return (result);
   6566  1.20  christos 	}
   6567  1.20  christos 
   6568   1.1  christos 	/*
   6569   1.1  christos 	 * Invoke the resolver.
   6570   1.1  christos 	 */
   6571   1.1  christos 	REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
   6572   1.1  christos 	REQUIRE(client->query.fetch == NULL);
   6573   1.1  christos 
   6574   1.3  christos 	rdataset = ns_client_newrdataset(client);
   6575   1.1  christos 	if (rdataset == NULL) {
   6576   1.1  christos 		return (ISC_R_NOMEMORY);
   6577   1.1  christos 	}
   6578   1.1  christos 
   6579   1.1  christos 	if (WANTDNSSEC(client)) {
   6580   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   6581   1.1  christos 		if (sigrdataset == NULL) {
   6582   1.3  christos 			ns_client_putrdataset(client, &rdataset);
   6583   1.1  christos 			return (ISC_R_NOMEMORY);
   6584   1.1  christos 		}
   6585   1.1  christos 	} else {
   6586   1.1  christos 		sigrdataset = NULL;
   6587   1.1  christos 	}
   6588   1.1  christos 
   6589  1.10  christos 	if (!client->query.timerset) {
   6590   1.1  christos 		ns_client_settimeout(client, 60);
   6591   1.1  christos 	}
   6592   1.1  christos 
   6593   1.1  christos 	if (!TCP(client)) {
   6594   1.1  christos 		peeraddr = &client->peeraddr;
   6595   1.1  christos 	}
   6596   1.1  christos 
   6597  1.11  christos 	if (client->view->staleanswerclienttimeout > 0 &&
   6598  1.11  christos 	    client->view->staleanswerclienttimeout != (uint32_t)-1 &&
   6599  1.11  christos 	    dns_view_staleanswerenabled(client->view))
   6600  1.11  christos 	{
   6601  1.11  christos 		client->query.fetchoptions |= DNS_FETCHOPT_TRYSTALE_ONTIMEOUT;
   6602  1.11  christos 	}
   6603  1.11  christos 
   6604  1.11  christos 	isc_nmhandle_attach(client->handle, &client->fetchhandle);
   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.9  christos 		0, NULL, client->task, fetch_callback, client, rdataset,
   6609   1.9  christos 		sigrdataset, &client->query.fetch);
   6610   1.1  christos 	if (result != ISC_R_SUCCESS) {
   6611  1.11  christos 		isc_nmhandle_detach(&client->fetchhandle);
   6612   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   6613   1.1  christos 		if (sigrdataset != NULL) {
   6614   1.3  christos 			ns_client_putrdataset(client, &sigrdataset);
   6615   1.1  christos 		}
   6616   1.1  christos 	}
   6617   1.1  christos 
   6618   1.1  christos 	/*
   6619   1.1  christos 	 * We're now waiting for a fetch event. A client which is
   6620   1.1  christos 	 * shutting down will not be destroyed until all the events
   6621   1.1  christos 	 * have been received.
   6622   1.1  christos 	 */
   6623   1.1  christos 
   6624   1.1  christos 	return (result);
   6625   1.1  christos }
   6626   1.1  christos 
   6627   1.1  christos /*%
   6628   1.1  christos  * Restores the query context after resuming from recursion, and
   6629   1.1  christos  * continues the query processing if needed.
   6630   1.1  christos  */
   6631   1.1  christos static isc_result_t
   6632   1.1  christos query_resume(query_ctx_t *qctx) {
   6633  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   6634   1.1  christos 	dns_name_t *tname;
   6635   1.1  christos 	isc_buffer_t b;
   6636   1.1  christos #ifdef WANT_QUERYTRACE
   6637   1.6  christos 	char mbuf[4 * DNS_NAME_FORMATSIZE];
   6638   1.1  christos 	char qbuf[DNS_NAME_FORMATSIZE];
   6639   1.1  christos 	char tbuf[DNS_RDATATYPE_FORMATSIZE];
   6640   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6641   1.9  christos 
   6642   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_resume");
   6643   1.1  christos 
   6644   1.3  christos 	CALL_HOOK(NS_QUERY_RESUME_BEGIN, qctx);
   6645   1.3  christos 
   6646   1.3  christos 	qctx->want_restart = false;
   6647   1.1  christos 
   6648   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   6649   1.1  christos 	if (qctx->rpz_st != NULL &&
   6650  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6651  1.16  christos 	{
   6652   1.1  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from RPZ recursion");
   6653   1.1  christos #ifdef WANT_QUERYTRACE
   6654   1.1  christos 		{
   6655   1.1  christos 			char pbuf[DNS_NAME_FORMATSIZE] = "<unset>";
   6656   1.1  christos 			char fbuf[DNS_NAME_FORMATSIZE] = "<unset>";
   6657   1.9  christos 			if (qctx->rpz_st->r_name != NULL) {
   6658   1.9  christos 				dns_name_format(qctx->rpz_st->r_name, qbuf,
   6659   1.9  christos 						sizeof(qbuf));
   6660   1.9  christos 			} else {
   6661   1.9  christos 				snprintf(qbuf, sizeof(qbuf), "<unset>");
   6662   1.9  christos 			}
   6663   1.9  christos 			if (qctx->rpz_st->p_name != NULL) {
   6664   1.9  christos 				dns_name_format(qctx->rpz_st->p_name, pbuf,
   6665   1.9  christos 						sizeof(pbuf));
   6666   1.9  christos 			}
   6667   1.9  christos 			if (qctx->rpz_st->fname != NULL) {
   6668   1.9  christos 				dns_name_format(qctx->rpz_st->fname, fbuf,
   6669   1.9  christos 						sizeof(fbuf));
   6670   1.9  christos 			}
   6671   1.1  christos 
   6672   1.1  christos 			snprintf(mbuf, sizeof(mbuf) - 1,
   6673   1.9  christos 				 "rpz rname:%s, pname:%s, qctx->fname:%s", qbuf,
   6674   1.9  christos 				 pbuf, fbuf);
   6675   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   6676   1.1  christos 		}
   6677   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6678   1.1  christos 
   6679   1.1  christos 		qctx->is_zone = qctx->rpz_st->q.is_zone;
   6680   1.1  christos 		qctx->authoritative = qctx->rpz_st->q.authoritative;
   6681   1.1  christos 		RESTORE(qctx->zone, qctx->rpz_st->q.zone);
   6682   1.1  christos 		RESTORE(qctx->node, qctx->rpz_st->q.node);
   6683   1.1  christos 		RESTORE(qctx->db, qctx->rpz_st->q.db);
   6684   1.1  christos 		RESTORE(qctx->rdataset, qctx->rpz_st->q.rdataset);
   6685   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->rpz_st->q.sigrdataset);
   6686   1.1  christos 		qctx->qtype = qctx->rpz_st->q.qtype;
   6687   1.1  christos 
   6688   1.9  christos 		if (qctx->event->node != NULL) {
   6689   1.1  christos 			dns_db_detachnode(qctx->event->db, &qctx->event->node);
   6690   1.9  christos 		}
   6691   1.1  christos 		SAVE(qctx->rpz_st->r.db, qctx->event->db);
   6692   1.1  christos 		qctx->rpz_st->r.r_type = qctx->event->qtype;
   6693   1.1  christos 		SAVE(qctx->rpz_st->r.r_rdataset, qctx->event->rdataset);
   6694   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->event->sigrdataset);
   6695   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6696   1.1  christos 		/*
   6697   1.1  christos 		 * Restore saved state.
   6698   1.1  christos 		 */
   6699   1.9  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from redirect recursion");
   6700   1.1  christos #ifdef WANT_QUERYTRACE
   6701   1.9  christos 		dns_name_format(qctx->client->query.redirect.fname, qbuf,
   6702   1.9  christos 				sizeof(qbuf));
   6703   1.9  christos 		dns_rdatatype_format(qctx->client->query.redirect.qtype, tbuf,
   6704   1.9  christos 				     sizeof(tbuf));
   6705   1.1  christos 		snprintf(mbuf, sizeof(mbuf) - 1,
   6706   1.9  christos 			 "redirect qctx->fname:%s, qtype:%s, auth:%d", qbuf,
   6707   1.9  christos 			 tbuf, qctx->client->query.redirect.authoritative);
   6708   1.1  christos 		CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   6709   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6710   1.1  christos 		qctx->qtype = qctx->client->query.redirect.qtype;
   6711   1.1  christos 		INSIST(qctx->client->query.redirect.rdataset != NULL);
   6712   1.1  christos 		RESTORE(qctx->rdataset, qctx->client->query.redirect.rdataset);
   6713   1.1  christos 		RESTORE(qctx->sigrdataset,
   6714   1.1  christos 			qctx->client->query.redirect.sigrdataset);
   6715   1.1  christos 		RESTORE(qctx->db, qctx->client->query.redirect.db);
   6716   1.1  christos 		RESTORE(qctx->node, qctx->client->query.redirect.node);
   6717   1.1  christos 		RESTORE(qctx->zone, qctx->client->query.redirect.zone);
   6718   1.1  christos 		qctx->authoritative =
   6719   1.1  christos 			qctx->client->query.redirect.authoritative;
   6720   1.1  christos 
   6721   1.1  christos 		/*
   6722   1.1  christos 		 * Free resources used while recursing.
   6723   1.1  christos 		 */
   6724   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->event->rdataset);
   6725   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->event->sigrdataset);
   6726   1.9  christos 		if (qctx->event->node != NULL) {
   6727   1.1  christos 			dns_db_detachnode(qctx->event->db, &qctx->event->node);
   6728   1.9  christos 		}
   6729   1.9  christos 		if (qctx->event->db != NULL) {
   6730   1.1  christos 			dns_db_detach(&qctx->event->db);
   6731   1.9  christos 		}
   6732   1.1  christos 	} else {
   6733   1.9  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from normal recursion");
   6734   1.3  christos 		qctx->authoritative = false;
   6735   1.1  christos 
   6736   1.1  christos 		qctx->qtype = qctx->event->qtype;
   6737   1.1  christos 		SAVE(qctx->db, qctx->event->db);
   6738   1.1  christos 		SAVE(qctx->node, qctx->event->node);
   6739   1.1  christos 		SAVE(qctx->rdataset, qctx->event->rdataset);
   6740   1.1  christos 		SAVE(qctx->sigrdataset, qctx->event->sigrdataset);
   6741   1.1  christos 	}
   6742   1.1  christos 	INSIST(qctx->rdataset != NULL);
   6743   1.1  christos 
   6744   1.1  christos 	if (qctx->qtype == dns_rdatatype_rrsig ||
   6745  1.16  christos 	    qctx->qtype == dns_rdatatype_sig)
   6746  1.16  christos 	{
   6747   1.1  christos 		qctx->type = dns_rdatatype_any;
   6748   1.1  christos 	} else {
   6749   1.1  christos 		qctx->type = qctx->qtype;
   6750   1.1  christos 	}
   6751   1.1  christos 
   6752   1.3  christos 	CALL_HOOK(NS_QUERY_RESUME_RESTORED, qctx);
   6753   1.3  christos 
   6754   1.1  christos 	if (DNS64(qctx->client)) {
   6755   1.1  christos 		qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64;
   6756   1.3  christos 		qctx->dns64 = true;
   6757   1.1  christos 	}
   6758   1.1  christos 
   6759   1.1  christos 	if (DNS64EXCLUDE(qctx->client)) {
   6760   1.1  christos 		qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64EXCLUDE;
   6761   1.3  christos 		qctx->dns64_exclude = true;
   6762   1.1  christos 	}
   6763   1.1  christos 
   6764   1.1  christos 	if (qctx->rpz_st != NULL &&
   6765  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6766  1.16  christos 	{
   6767   1.1  christos 		/*
   6768   1.1  christos 		 * Has response policy changed out from under us?
   6769   1.1  christos 		 */
   6770   1.9  christos 		if (qctx->rpz_st->rpz_ver != qctx->view->rpzs->rpz_ver) {
   6771   1.1  christos 			ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
   6772   1.9  christos 				      NS_LOGMODULE_QUERY, DNS_RPZ_INFO_LEVEL,
   6773   1.1  christos 				      "query_resume: RPZ settings "
   6774   1.1  christos 				      "out of date "
   6775   1.1  christos 				      "(rpz_ver %d, expected %d)",
   6776   1.3  christos 				      qctx->view->rpzs->rpz_ver,
   6777   1.1  christos 				      qctx->rpz_st->rpz_ver);
   6778   1.1  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   6779   1.3  christos 			return (ns_query_done(qctx));
   6780   1.1  christos 		}
   6781   1.1  christos 	}
   6782   1.1  christos 
   6783   1.1  christos 	/*
   6784   1.1  christos 	 * We'll need some resources...
   6785   1.1  christos 	 */
   6786   1.3  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   6787   1.1  christos 	if (qctx->dbuf == NULL) {
   6788   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_resume: ns_client_getnamebuf "
   6789   1.9  christos 				       "failed (1)");
   6790   1.3  christos 		QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   6791   1.3  christos 		return (ns_query_done(qctx));
   6792   1.1  christos 	}
   6793   1.1  christos 
   6794   1.3  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   6795   1.1  christos 	if (qctx->fname == NULL) {
   6796   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_resume: ns_client_newname failed "
   6797   1.9  christos 				       "(1)");
   6798   1.3  christos 		QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   6799   1.3  christos 		return (ns_query_done(qctx));
   6800   1.1  christos 	}
   6801   1.1  christos 
   6802   1.1  christos 	if (qctx->rpz_st != NULL &&
   6803  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6804  1.16  christos 	{
   6805   1.1  christos 		tname = qctx->rpz_st->fname;
   6806   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6807   1.1  christos 		tname = qctx->client->query.redirect.fname;
   6808   1.1  christos 	} else {
   6809  1.20  christos 		tname = qctx->event->foundname;
   6810   1.1  christos 	}
   6811   1.1  christos 
   6812  1.20  christos 	dns_name_copy(tname, qctx->fname);
   6813   1.1  christos 
   6814   1.1  christos 	if (qctx->rpz_st != NULL &&
   6815  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6816  1.16  christos 	{
   6817   1.1  christos 		qctx->rpz_st->r.r_result = qctx->event->result;
   6818   1.1  christos 		result = qctx->rpz_st->q.result;
   6819   1.9  christos 		free_devent(qctx->client, ISC_EVENT_PTR(&qctx->event),
   6820   1.9  christos 			    &qctx->event);
   6821   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6822   1.1  christos 		result = qctx->client->query.redirect.result;
   6823   1.1  christos 	} else {
   6824   1.1  christos 		result = qctx->event->result;
   6825   1.1  christos 	}
   6826   1.1  christos 
   6827   1.3  christos 	qctx->resuming = true;
   6828   1.1  christos 
   6829   1.1  christos 	return (query_gotanswer(qctx, result));
   6830   1.3  christos 
   6831   1.9  christos cleanup:
   6832   1.3  christos 	return (result);
   6833   1.1  christos }
   6834   1.1  christos 
   6835  1.20  christos static void
   6836  1.20  christos query_hookresume(isc_task_t *task, isc_event_t *event) {
   6837  1.20  christos 	ns_hook_resevent_t *rev = (ns_hook_resevent_t *)event;
   6838  1.20  christos 	ns_hookasync_t *hctx = NULL;
   6839  1.20  christos 	ns_client_t *client = rev->ev_arg;
   6840  1.20  christos 	query_ctx_t *qctx = rev->saved_qctx;
   6841  1.20  christos 	bool canceled;
   6842  1.20  christos 
   6843  1.20  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_hookresume");
   6844  1.20  christos 
   6845  1.20  christos 	REQUIRE(NS_CLIENT_VALID(client));
   6846  1.20  christos 	REQUIRE(task == client->task);
   6847  1.20  christos 	REQUIRE(event->ev_type == NS_EVENT_HOOKASYNCDONE);
   6848  1.20  christos 
   6849  1.20  christos 	LOCK(&client->query.fetchlock);
   6850  1.20  christos 	if (client->query.hookactx != NULL) {
   6851  1.20  christos 		INSIST(rev->ctx == client->query.hookactx);
   6852  1.20  christos 		client->query.hookactx = NULL;
   6853  1.20  christos 		canceled = false;
   6854  1.20  christos 		isc_stdtime_get(&client->now);
   6855  1.20  christos 	} else {
   6856  1.20  christos 		canceled = true;
   6857  1.20  christos 	}
   6858  1.20  christos 	UNLOCK(&client->query.fetchlock);
   6859  1.20  christos 	SAVE(hctx, rev->ctx);
   6860  1.20  christos 
   6861  1.20  christos 	if (client->recursionquota != NULL) {
   6862  1.20  christos 		isc_quota_detach(&client->recursionquota);
   6863  1.20  christos 		ns_stats_decrement(client->sctx->nsstats,
   6864  1.20  christos 				   ns_statscounter_recursclients);
   6865  1.20  christos 	}
   6866  1.20  christos 
   6867  1.20  christos 	LOCK(&client->manager->reclock);
   6868  1.20  christos 	if (ISC_LINK_LINKED(client, rlink)) {
   6869  1.20  christos 		ISC_LIST_UNLINK(client->manager->recursing, client, rlink);
   6870  1.20  christos 	}
   6871  1.20  christos 	UNLOCK(&client->manager->reclock);
   6872  1.20  christos 
   6873  1.20  christos 	/*
   6874  1.20  christos 	 * This event is running under a client task, so it's safe to detach
   6875  1.20  christos 	 * the fetch handle.  And it should be done before resuming query
   6876  1.20  christos 	 * processing below, since that may trigger another recursion or
   6877  1.20  christos 	 * asynchronous hook event.
   6878  1.20  christos 	 */
   6879  1.20  christos 	isc_nmhandle_detach(&client->fetchhandle);
   6880  1.20  christos 
   6881  1.20  christos 	client->state = NS_CLIENTSTATE_WORKING;
   6882  1.20  christos 
   6883  1.20  christos 	if (canceled) {
   6884  1.20  christos 		/*
   6885  1.20  christos 		 * Note: unlike fetch_callback, this function doesn't bother
   6886  1.20  christos 		 * to check the 'shutdown' condition, as that doesn't seem to
   6887  1.20  christos 		 * happen in the latest implementation.
   6888  1.20  christos 		 */
   6889  1.20  christos 		query_error(client, DNS_R_SERVFAIL, __LINE__);
   6890  1.20  christos 
   6891  1.20  christos 		/*
   6892  1.20  christos 		 * There's no other place to free/release any data maintained
   6893  1.20  christos 		 * in qctx.  We need to do it here to prevent leak.
   6894  1.20  christos 		 */
   6895  1.20  christos 		qctx_clean(qctx);
   6896  1.20  christos 		qctx_freedata(qctx);
   6897  1.20  christos 
   6898  1.20  christos 		/*
   6899  1.20  christos 		 * As we're almost done with this client, make sure any internal
   6900  1.20  christos 		 * resource for hooks will be released (if necessary) via the
   6901  1.20  christos 		 * QCTX_DESTROYED hook.
   6902  1.20  christos 		 */
   6903  1.20  christos 		qctx->detach_client = true;
   6904  1.20  christos 	} else {
   6905  1.20  christos 		switch (rev->hookpoint) {
   6906  1.20  christos 		case NS_QUERY_SETUP:
   6907  1.20  christos 			(void)query_setup(client, qctx->qtype);
   6908  1.20  christos 			break;
   6909  1.20  christos 		case NS_QUERY_START_BEGIN:
   6910  1.20  christos 			(void)ns__query_start(qctx);
   6911  1.20  christos 			break;
   6912  1.20  christos 		case NS_QUERY_LOOKUP_BEGIN:
   6913  1.20  christos 			(void)query_lookup(qctx);
   6914  1.20  christos 			break;
   6915  1.20  christos 		case NS_QUERY_RESUME_BEGIN:
   6916  1.20  christos 		case NS_QUERY_RESUME_RESTORED:
   6917  1.20  christos 			(void)query_resume(qctx);
   6918  1.20  christos 			break;
   6919  1.20  christos 		case NS_QUERY_GOT_ANSWER_BEGIN:
   6920  1.20  christos 			(void)query_gotanswer(qctx, rev->origresult);
   6921  1.20  christos 			break;
   6922  1.20  christos 		case NS_QUERY_RESPOND_ANY_BEGIN:
   6923  1.20  christos 			(void)query_respond_any(qctx);
   6924  1.20  christos 			break;
   6925  1.20  christos 		case NS_QUERY_ADDANSWER_BEGIN:
   6926  1.20  christos 			(void)query_addanswer(qctx);
   6927  1.20  christos 			break;
   6928  1.20  christos 		case NS_QUERY_NOTFOUND_BEGIN:
   6929  1.20  christos 			(void)query_notfound(qctx);
   6930  1.20  christos 			break;
   6931  1.20  christos 		case NS_QUERY_PREP_DELEGATION_BEGIN:
   6932  1.20  christos 			(void)query_prepare_delegation_response(qctx);
   6933  1.20  christos 			break;
   6934  1.20  christos 		case NS_QUERY_ZONE_DELEGATION_BEGIN:
   6935  1.20  christos 			(void)query_zone_delegation(qctx);
   6936  1.20  christos 			break;
   6937  1.20  christos 		case NS_QUERY_DELEGATION_BEGIN:
   6938  1.20  christos 			(void)query_delegation(qctx);
   6939  1.20  christos 			break;
   6940  1.20  christos 		case NS_QUERY_DELEGATION_RECURSE_BEGIN:
   6941  1.20  christos 			(void)query_delegation_recurse(qctx);
   6942  1.20  christos 			break;
   6943  1.20  christos 		case NS_QUERY_NODATA_BEGIN:
   6944  1.20  christos 			(void)query_nodata(qctx, rev->origresult);
   6945  1.20  christos 			break;
   6946  1.20  christos 		case NS_QUERY_NXDOMAIN_BEGIN:
   6947  1.20  christos 			(void)query_nxdomain(qctx, rev->origresult);
   6948  1.20  christos 			break;
   6949  1.20  christos 		case NS_QUERY_NCACHE_BEGIN:
   6950  1.20  christos 			(void)query_ncache(qctx, rev->origresult);
   6951  1.20  christos 			break;
   6952  1.20  christos 		case NS_QUERY_CNAME_BEGIN:
   6953  1.20  christos 			(void)query_cname(qctx);
   6954  1.20  christos 			break;
   6955  1.20  christos 		case NS_QUERY_DNAME_BEGIN:
   6956  1.20  christos 			(void)query_dname(qctx);
   6957  1.20  christos 			break;
   6958  1.20  christos 		case NS_QUERY_RESPOND_BEGIN:
   6959  1.20  christos 			(void)query_respond(qctx);
   6960  1.20  christos 			break;
   6961  1.20  christos 		case NS_QUERY_PREP_RESPONSE_BEGIN:
   6962  1.20  christos 			(void)query_prepresponse(qctx);
   6963  1.20  christos 			break;
   6964  1.20  christos 		case NS_QUERY_DONE_BEGIN:
   6965  1.20  christos 		case NS_QUERY_DONE_SEND:
   6966  1.20  christos 			(void)ns_query_done(qctx);
   6967  1.20  christos 			break;
   6968  1.20  christos 
   6969  1.20  christos 		/* Not all hookpoints can use recursion.  Catch violations */
   6970  1.20  christos 		case NS_QUERY_RESPOND_ANY_FOUND: /* due to side effect */
   6971  1.20  christos 		case NS_QUERY_NOTFOUND_RECURSE:	 /* in recursion */
   6972  1.20  christos 		case NS_QUERY_ZEROTTL_RECURSE:	 /* in recursion */
   6973  1.20  christos 		default:			 /* catch-all just in case */
   6974  1.20  christos 			INSIST(false);
   6975  1.20  christos 		}
   6976  1.20  christos 	}
   6977  1.20  christos 
   6978  1.20  christos 	hctx->destroy(&hctx);
   6979  1.20  christos 	qctx_destroy(qctx);
   6980  1.20  christos 	isc_mem_put(client->mctx, qctx, sizeof(*qctx));
   6981  1.20  christos 	isc_event_free(&event);
   6982  1.20  christos }
   6983  1.20  christos 
   6984  1.20  christos isc_result_t
   6985  1.20  christos ns_query_hookasync(query_ctx_t *qctx, ns_query_starthookasync_t runasync,
   6986  1.20  christos 		   void *arg) {
   6987  1.20  christos 	isc_result_t result;
   6988  1.20  christos 	ns_client_t *client = qctx->client;
   6989  1.20  christos 	query_ctx_t *saved_qctx = NULL;
   6990  1.20  christos 
   6991  1.20  christos 	CTRACE(ISC_LOG_DEBUG(3), "ns_query_hookasync");
   6992  1.20  christos 
   6993  1.20  christos 	REQUIRE(NS_CLIENT_VALID(client));
   6994  1.20  christos 	REQUIRE(client->query.hookactx == NULL);
   6995  1.20  christos 	REQUIRE(client->query.fetch == NULL);
   6996  1.20  christos 
   6997  1.20  christos 	result = check_recursionquota(client);
   6998  1.20  christos 	if (result != ISC_R_SUCCESS) {
   6999  1.20  christos 		goto cleanup;
   7000  1.20  christos 	}
   7001  1.20  christos 
   7002  1.20  christos 	saved_qctx = isc_mem_get(client->mctx, sizeof(*saved_qctx));
   7003  1.20  christos 	qctx_save(qctx, saved_qctx);
   7004  1.20  christos 	result = runasync(saved_qctx, client->mctx, arg, client->task,
   7005  1.20  christos 			  query_hookresume, client, &client->query.hookactx);
   7006  1.20  christos 	if (result != ISC_R_SUCCESS) {
   7007  1.20  christos 		goto cleanup;
   7008  1.20  christos 	}
   7009  1.20  christos 
   7010  1.20  christos 	/*
   7011  1.20  christos 	 * Typically the runasync() function will trigger recursion, but
   7012  1.20  christos 	 * there is no need to set NS_QUERYATTR_RECURSING. The calling hook
   7013  1.20  christos 	 * is expected to return NS_HOOK_RETURN, and the RECURSING
   7014  1.20  christos 	 * attribute won't be checked anywhere.
   7015  1.20  christos 	 *
   7016  1.20  christos 	 * Hook-based asynchronous processing cannot coincide with normal
   7017  1.20  christos 	 * recursion, so we can safely use fetchhandle here.  Unlike in
   7018  1.20  christos 	 * ns_query_recurse(), we attach to the handle only if 'runasync'
   7019  1.20  christos 	 * succeeds. It should be safe since we're either in the client
   7020  1.20  christos 	 * task or pausing it.
   7021  1.20  christos 	 */
   7022  1.20  christos 	isc_nmhandle_attach(client->handle, &client->fetchhandle);
   7023  1.20  christos 	return (ISC_R_SUCCESS);
   7024  1.20  christos 
   7025  1.20  christos cleanup:
   7026  1.20  christos 	/*
   7027  1.20  christos 	 * If we fail, send SERVFAIL now.  It may be better to let the caller
   7028  1.20  christos 	 * decide what to do on failure of this function, but hooks don't have
   7029  1.20  christos 	 * access to query_error().
   7030  1.20  christos 	 */
   7031  1.20  christos 	query_error(client, DNS_R_SERVFAIL, __LINE__);
   7032  1.20  christos 
   7033  1.20  christos 	/*
   7034  1.20  christos 	 * Free all resource related to the query and set detach_client,
   7035  1.20  christos 	 * similar to the cancel case of query_hookresume; the callers will
   7036  1.20  christos 	 * simply return on failure of this function, so there's no other
   7037  1.20  christos 	 * place for this to prevent leak.
   7038  1.20  christos 	 */
   7039  1.20  christos 	if (saved_qctx != NULL) {
   7040  1.20  christos 		qctx_clean(saved_qctx);
   7041  1.20  christos 		qctx_freedata(saved_qctx);
   7042  1.20  christos 		qctx_destroy(saved_qctx);
   7043  1.20  christos 		isc_mem_put(client->mctx, saved_qctx, sizeof(*saved_qctx));
   7044  1.20  christos 	}
   7045  1.20  christos 	qctx->detach_client = true;
   7046  1.20  christos 	return (result);
   7047  1.20  christos }
   7048  1.20  christos 
   7049   1.1  christos /*%
   7050   1.1  christos  * If the query is recursive, check the SERVFAIL cache to see whether
   7051   1.1  christos  * identical queries have failed recently.  If we find a match, and it was
   7052   1.1  christos  * from a query with CD=1, *or* if the current query has CD=0, then we just
   7053   1.1  christos  * return SERVFAIL again.  This prevents a validation failure from eliciting a
   7054   1.1  christos  * SERVFAIL response to a CD=1 query.
   7055   1.1  christos  */
   7056   1.1  christos isc_result_t
   7057   1.1  christos ns__query_sfcache(query_ctx_t *qctx) {
   7058   1.3  christos 	bool failcache;
   7059   1.3  christos 	uint32_t flags;
   7060   1.1  christos 
   7061   1.1  christos 	/*
   7062   1.1  christos 	 * The SERVFAIL cache doesn't apply to authoritative queries.
   7063   1.1  christos 	 */
   7064   1.1  christos 	if (!RECURSIONOK(qctx->client)) {
   7065   1.1  christos 		return (ISC_R_COMPLETE);
   7066   1.1  christos 	}
   7067   1.1  christos 
   7068   1.1  christos 	flags = 0;
   7069   1.1  christos #ifdef ENABLE_AFL
   7070   1.1  christos 	if (qctx->client->sctx->fuzztype == isc_fuzz_resolver) {
   7071   1.3  christos 		failcache = false;
   7072   1.1  christos 	} else {
   7073   1.9  christos 		failcache = dns_badcache_find(
   7074   1.9  christos 			qctx->view->failcache, qctx->client->query.qname,
   7075   1.9  christos 			qctx->qtype, &flags, &qctx->client->tnow);
   7076   1.1  christos 	}
   7077   1.9  christos #else  /* ifdef ENABLE_AFL */
   7078   1.3  christos 	failcache = dns_badcache_find(qctx->view->failcache,
   7079   1.9  christos 				      qctx->client->query.qname, qctx->qtype,
   7080   1.9  christos 				      &flags, &qctx->client->tnow);
   7081   1.9  christos #endif /* ifdef ENABLE_AFL */
   7082   1.1  christos 	if (failcache &&
   7083   1.1  christos 	    (((flags & NS_FAILCACHE_CD) != 0) ||
   7084   1.1  christos 	     ((qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)))
   7085   1.1  christos 	{
   7086   1.1  christos 		if (isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1))) {
   7087   1.1  christos 			char namebuf[DNS_NAME_FORMATSIZE];
   7088   1.3  christos 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
   7089   1.1  christos 
   7090   1.9  christos 			dns_name_format(qctx->client->query.qname, namebuf,
   7091   1.9  christos 					sizeof(namebuf));
   7092   1.3  christos 			dns_rdatatype_format(qctx->qtype, typebuf,
   7093   1.3  christos 					     sizeof(typebuf));
   7094   1.9  christos 			ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
   7095   1.9  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(1),
   7096   1.9  christos 				      "servfail cache hit %s/%s (%s)", namebuf,
   7097   1.9  christos 				      typebuf,
   7098   1.9  christos 				      ((flags & NS_FAILCACHE_CD) != 0) ? "CD=1"
   7099   1.9  christos 								       : "CD="
   7100   1.9  christos 									 "0");
   7101   1.1  christos 		}
   7102   1.1  christos 
   7103   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
   7104   1.1  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   7105   1.3  christos 		return (ns_query_done(qctx));
   7106   1.1  christos 	}
   7107   1.1  christos 
   7108   1.1  christos 	return (ISC_R_COMPLETE);
   7109   1.1  christos }
   7110   1.1  christos 
   7111   1.1  christos /*%
   7112   1.1  christos  * Handle response rate limiting (RRL).
   7113   1.1  christos  */
   7114   1.1  christos static isc_result_t
   7115   1.1  christos query_checkrrl(query_ctx_t *qctx, isc_result_t result) {
   7116   1.1  christos 	/*
   7117   1.1  christos 	 * Rate limit these responses to this client.
   7118   1.1  christos 	 * Do not delay counting and handling obvious referrals,
   7119   1.1  christos 	 *	since those won't come here again.
   7120   1.1  christos 	 * Delay handling delegations for which we are certain to recurse and
   7121   1.1  christos 	 *	return here (DNS_R_DELEGATION, not a child of one of our
   7122   1.1  christos 	 *	own zones, and recursion enabled)
   7123   1.1  christos 	 * Don't mess with responses rewritten by RPZ
   7124   1.1  christos 	 * Count each response at most once.
   7125   1.1  christos 	 */
   7126   1.3  christos 
   7127   1.3  christos 	/*
   7128   1.3  christos 	 * XXXMPA the rrl system tests fails sometimes and RRL_CHECKED
   7129   1.3  christos 	 * is set when we are called the second time preventing the
   7130   1.3  christos 	 * response being dropped.
   7131   1.3  christos 	 */
   7132   1.9  christos 	ns_client_log(
   7133   1.9  christos 		qctx->client, DNS_LOGCATEGORY_RRL, NS_LOGMODULE_QUERY,
   7134   1.9  christos 		ISC_LOG_DEBUG(99),
   7135   1.9  christos 		"rrl=%p, HAVECOOKIE=%u, result=%s, "
   7136   1.9  christos 		"fname=%p(%u), is_zone=%u, RECURSIONOK=%u, "
   7137   1.9  christos 		"query.rpz_st=%p(%u), RRL_CHECKED=%u\n",
   7138   1.9  christos 		qctx->client->view->rrl, HAVECOOKIE(qctx->client),
   7139   1.9  christos 		isc_result_toid(result), qctx->fname,
   7140   1.9  christos 		qctx->fname != NULL ? dns_name_isabsolute(qctx->fname) : 0,
   7141   1.9  christos 		qctx->is_zone, RECURSIONOK(qctx->client),
   7142   1.9  christos 		qctx->client->query.rpz_st,
   7143   1.9  christos 		qctx->client->query.rpz_st != NULL
   7144   1.9  christos 			? ((qctx->client->query.rpz_st->state &
   7145   1.9  christos 			    DNS_RPZ_REWRITTEN) != 0)
   7146   1.9  christos 			: 0,
   7147   1.9  christos 		(qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) !=
   7148   1.9  christos 			0);
   7149   1.3  christos 
   7150   1.9  christos 	if (qctx->view->rrl != NULL && !HAVECOOKIE(qctx->client) &&
   7151   1.1  christos 	    ((qctx->fname != NULL && dns_name_isabsolute(qctx->fname)) ||
   7152   1.1  christos 	     (result == ISC_R_NOTFOUND && !RECURSIONOK(qctx->client))) &&
   7153   1.9  christos 	    !(result == DNS_R_DELEGATION && !qctx->is_zone &&
   7154   1.9  christos 	      RECURSIONOK(qctx->client)) &&
   7155   1.1  christos 	    (qctx->client->query.rpz_st == NULL ||
   7156   1.1  christos 	     (qctx->client->query.rpz_st->state & DNS_RPZ_REWRITTEN) == 0) &&
   7157   1.1  christos 	    (qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) == 0)
   7158   1.1  christos 	{
   7159   1.1  christos 		dns_rdataset_t nc_rdataset;
   7160   1.3  christos 		bool wouldlog;
   7161   1.1  christos 		dns_fixedname_t fixed;
   7162   1.1  christos 		const dns_name_t *constname;
   7163   1.1  christos 		char log_buf[DNS_RRL_LOG_BUF_LEN];
   7164   1.1  christos 		isc_result_t nc_result, resp_result;
   7165   1.1  christos 		dns_rrl_result_t rrl_result;
   7166   1.1  christos 
   7167   1.1  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RRL_CHECKED;
   7168   1.1  christos 
   7169   1.1  christos 		wouldlog = isc_log_wouldlog(ns_lctx, DNS_RRL_LOG_DROP);
   7170   1.1  christos 		constname = qctx->fname;
   7171   1.1  christos 		if (result == DNS_R_NXDOMAIN) {
   7172   1.1  christos 			/*
   7173   1.1  christos 			 * Use the database origin name to rate limit NXDOMAIN
   7174   1.1  christos 			 */
   7175   1.9  christos 			if (qctx->db != NULL) {
   7176   1.1  christos 				constname = dns_db_origin(qctx->db);
   7177   1.9  christos 			}
   7178   1.1  christos 			resp_result = result;
   7179   1.1  christos 		} else if (result == DNS_R_NCACHENXDOMAIN &&
   7180   1.1  christos 			   qctx->rdataset != NULL &&
   7181   1.1  christos 			   dns_rdataset_isassociated(qctx->rdataset) &&
   7182   1.1  christos 			   (qctx->rdataset->attributes &
   7183   1.9  christos 			    DNS_RDATASETATTR_NEGATIVE) != 0)
   7184   1.9  christos 		{
   7185   1.1  christos 			/*
   7186   1.1  christos 			 * Try to use owner name in the negative cache SOA.
   7187   1.1  christos 			 */
   7188   1.1  christos 			dns_fixedname_init(&fixed);
   7189   1.1  christos 			dns_rdataset_init(&nc_rdataset);
   7190   1.1  christos 			for (nc_result = dns_rdataset_first(qctx->rdataset);
   7191   1.1  christos 			     nc_result == ISC_R_SUCCESS;
   7192   1.1  christos 			     nc_result = dns_rdataset_next(qctx->rdataset))
   7193   1.1  christos 			{
   7194   1.1  christos 				dns_ncache_current(qctx->rdataset,
   7195   1.1  christos 						   dns_fixedname_name(&fixed),
   7196   1.1  christos 						   &nc_rdataset);
   7197   1.1  christos 				if (nc_rdataset.type == dns_rdatatype_soa) {
   7198   1.1  christos 					dns_rdataset_disassociate(&nc_rdataset);
   7199   1.1  christos 					constname = dns_fixedname_name(&fixed);
   7200   1.1  christos 					break;
   7201   1.1  christos 				}
   7202   1.1  christos 				dns_rdataset_disassociate(&nc_rdataset);
   7203   1.1  christos 			}
   7204   1.1  christos 			resp_result = DNS_R_NXDOMAIN;
   7205   1.9  christos 		} else if (result == DNS_R_NXRRSET || result == DNS_R_EMPTYNAME)
   7206   1.9  christos 		{
   7207   1.1  christos 			resp_result = DNS_R_NXRRSET;
   7208   1.1  christos 		} else if (result == DNS_R_DELEGATION) {
   7209   1.1  christos 			resp_result = result;
   7210   1.1  christos 		} else if (result == ISC_R_NOTFOUND) {
   7211   1.1  christos 			/*
   7212   1.1  christos 			 * Handle referral to ".", including when recursion
   7213   1.1  christos 			 * is off or not requested and the hints have not
   7214  1.20  christos 			 * been loaded.
   7215   1.1  christos 			 */
   7216   1.1  christos 			constname = dns_rootname;
   7217   1.1  christos 			resp_result = DNS_R_DELEGATION;
   7218   1.1  christos 		} else {
   7219   1.1  christos 			resp_result = ISC_R_SUCCESS;
   7220   1.1  christos 		}
   7221   1.1  christos 
   7222   1.9  christos 		rrl_result = dns_rrl(
   7223  1.15  christos 			qctx->view, qctx->zone, &qctx->client->peeraddr,
   7224  1.15  christos 			TCP(qctx->client), qctx->client->message->rdclass,
   7225  1.15  christos 			qctx->qtype, constname, resp_result, qctx->client->now,
   7226  1.15  christos 			wouldlog, log_buf, sizeof(log_buf));
   7227   1.1  christos 		if (rrl_result != DNS_RRL_RESULT_OK) {
   7228   1.1  christos 			/*
   7229   1.1  christos 			 * Log dropped or slipped responses in the query
   7230   1.1  christos 			 * category so that requests are not silently lost.
   7231   1.1  christos 			 * Starts of rate-limited bursts are logged in
   7232   1.1  christos 			 * DNS_LOGCATEGORY_RRL.
   7233   1.1  christos 			 *
   7234   1.1  christos 			 * Dropped responses are counted with dropped queries
   7235   1.1  christos 			 * in QryDropped while slipped responses are counted
   7236   1.1  christos 			 * with other truncated responses in RespTruncated.
   7237   1.1  christos 			 */
   7238   1.1  christos 			if (wouldlog) {
   7239   1.1  christos 				ns_client_log(qctx->client, DNS_LOGCATEGORY_RRL,
   7240   1.1  christos 					      NS_LOGMODULE_QUERY,
   7241   1.9  christos 					      DNS_RRL_LOG_DROP, "%s", log_buf);
   7242   1.1  christos 			}
   7243   1.1  christos 
   7244   1.3  christos 			if (!qctx->view->rrl->log_only) {
   7245   1.1  christos 				if (rrl_result == DNS_RRL_RESULT_DROP) {
   7246   1.1  christos 					/*
   7247   1.1  christos 					 * These will also be counted in
   7248   1.1  christos 					 * ns_statscounter_dropped
   7249   1.1  christos 					 */
   7250   1.1  christos 					inc_stats(qctx->client,
   7251   1.9  christos 						  ns_statscounter_ratedropped);
   7252   1.1  christos 					QUERY_ERROR(qctx, DNS_R_DROP);
   7253   1.1  christos 				} else {
   7254   1.1  christos 					/*
   7255   1.1  christos 					 * These will also be counted in
   7256   1.1  christos 					 * ns_statscounter_truncatedresp
   7257   1.1  christos 					 */
   7258   1.1  christos 					inc_stats(qctx->client,
   7259   1.9  christos 						  ns_statscounter_rateslipped);
   7260   1.1  christos 					if (WANTCOOKIE(qctx->client)) {
   7261   1.1  christos 						qctx->client->message->flags &=
   7262   1.1  christos 							~DNS_MESSAGEFLAG_AA;
   7263   1.1  christos 						qctx->client->message->flags &=
   7264   1.1  christos 							~DNS_MESSAGEFLAG_AD;
   7265   1.1  christos 						qctx->client->message->rcode =
   7266   1.9  christos 							dns_rcode_badcookie;
   7267   1.1  christos 					} else {
   7268   1.1  christos 						qctx->client->message->flags |=
   7269   1.1  christos 							DNS_MESSAGEFLAG_TC;
   7270   1.1  christos 						if (resp_result ==
   7271  1.16  christos 						    DNS_R_NXDOMAIN)
   7272  1.16  christos 						{
   7273   1.9  christos 							qctx->client->message
   7274   1.9  christos 								->rcode =
   7275   1.9  christos 								dns_rcode_nxdomain;
   7276   1.1  christos 						}
   7277   1.1  christos 					}
   7278   1.1  christos 				}
   7279   1.1  christos 				return (DNS_R_DROP);
   7280   1.1  christos 			}
   7281   1.1  christos 		}
   7282   1.1  christos 	}
   7283   1.1  christos 
   7284   1.1  christos 	return (ISC_R_SUCCESS);
   7285   1.1  christos }
   7286   1.1  christos 
   7287   1.1  christos /*%
   7288   1.1  christos  * Do any RPZ rewriting that may be needed for this query.
   7289   1.1  christos  */
   7290   1.1  christos static isc_result_t
   7291   1.1  christos query_checkrpz(query_ctx_t *qctx, isc_result_t result) {
   7292   1.1  christos 	isc_result_t rresult;
   7293   1.1  christos 
   7294   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_checkrpz");
   7295   1.9  christos 
   7296   1.9  christos 	rresult = rpz_rewrite(qctx->client, qctx->qtype, result, qctx->resuming,
   7297   1.1  christos 			      qctx->rdataset, qctx->sigrdataset);
   7298   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   7299   1.1  christos 	switch (rresult) {
   7300   1.1  christos 	case ISC_R_SUCCESS:
   7301   1.1  christos 		break;
   7302  1.13  christos 	case ISC_R_NOTFOUND:
   7303   1.1  christos 	case DNS_R_DISALLOWED:
   7304   1.1  christos 		return (result);
   7305   1.1  christos 	case DNS_R_DELEGATION:
   7306   1.1  christos 		/*
   7307   1.1  christos 		 * recursing for NS names or addresses,
   7308   1.1  christos 		 * so save the main query state
   7309   1.1  christos 		 */
   7310  1.13  christos 		INSIST(!RECURSING(qctx->client));
   7311   1.1  christos 		qctx->rpz_st->q.qtype = qctx->qtype;
   7312   1.1  christos 		qctx->rpz_st->q.is_zone = qctx->is_zone;
   7313   1.1  christos 		qctx->rpz_st->q.authoritative = qctx->authoritative;
   7314   1.1  christos 		SAVE(qctx->rpz_st->q.zone, qctx->zone);
   7315   1.1  christos 		SAVE(qctx->rpz_st->q.db, qctx->db);
   7316   1.1  christos 		SAVE(qctx->rpz_st->q.node, qctx->node);
   7317   1.1  christos 		SAVE(qctx->rpz_st->q.rdataset, qctx->rdataset);
   7318   1.1  christos 		SAVE(qctx->rpz_st->q.sigrdataset, qctx->sigrdataset);
   7319  1.20  christos 		dns_name_copy(qctx->fname, qctx->rpz_st->fname);
   7320   1.1  christos 		qctx->rpz_st->q.result = result;
   7321   1.1  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   7322   1.1  christos 		return (ISC_R_COMPLETE);
   7323   1.1  christos 	default:
   7324   1.3  christos 		QUERY_ERROR(qctx, rresult);
   7325   1.3  christos 		return (ISC_R_COMPLETE);
   7326   1.1  christos 	}
   7327   1.1  christos 
   7328   1.1  christos 	if (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS) {
   7329   1.1  christos 		qctx->rpz_st->state |= DNS_RPZ_REWRITTEN;
   7330   1.1  christos 	}
   7331   1.1  christos 
   7332   1.1  christos 	if (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS &&
   7333   1.1  christos 	    qctx->rpz_st->m.policy != DNS_RPZ_POLICY_PASSTHRU &&
   7334   1.1  christos 	    (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_TCP_ONLY ||
   7335   1.1  christos 	     !TCP(qctx->client)) &&
   7336   1.1  christos 	    qctx->rpz_st->m.policy != DNS_RPZ_POLICY_ERROR)
   7337   1.1  christos 	{
   7338   1.1  christos 		/*
   7339   1.1  christos 		 * We got a hit and are going to answer with our
   7340   1.1  christos 		 * fiction. Ensure that we answer with the name
   7341   1.1  christos 		 * we looked up even if we were stopped short
   7342   1.1  christos 		 * in recursion or for a deferral.
   7343   1.1  christos 		 */
   7344  1.20  christos 		dns_name_copy(qctx->client->query.qname, qctx->fname);
   7345   1.1  christos 		rpz_clean(&qctx->zone, &qctx->db, &qctx->node, NULL);
   7346   1.1  christos 		if (qctx->rpz_st->m.rdataset != NULL) {
   7347   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   7348   1.1  christos 			RESTORE(qctx->rdataset, qctx->rpz_st->m.rdataset);
   7349   1.1  christos 		} else {
   7350   1.1  christos 			qctx_clean(qctx);
   7351   1.1  christos 		}
   7352   1.1  christos 		qctx->version = NULL;
   7353   1.1  christos 
   7354   1.1  christos 		RESTORE(qctx->node, qctx->rpz_st->m.node);
   7355   1.1  christos 		RESTORE(qctx->db, qctx->rpz_st->m.db);
   7356   1.1  christos 		RESTORE(qctx->version, qctx->rpz_st->m.version);
   7357   1.1  christos 		RESTORE(qctx->zone, qctx->rpz_st->m.zone);
   7358   1.1  christos 
   7359   1.1  christos 		/*
   7360   1.1  christos 		 * Add SOA record to additional section
   7361   1.1  christos 		 */
   7362   1.5  christos 		if (qctx->rpz_st->m.rpz->addsoa) {
   7363  1.22  christos 			rresult = query_addsoa(qctx, UINT32_MAX,
   7364   1.5  christos 					       DNS_SECTION_ADDITIONAL);
   7365   1.5  christos 			if (rresult != ISC_R_SUCCESS) {
   7366   1.5  christos 				QUERY_ERROR(qctx, result);
   7367   1.5  christos 				return (ISC_R_COMPLETE);
   7368   1.5  christos 			}
   7369   1.1  christos 		}
   7370   1.1  christos 
   7371   1.1  christos 		switch (qctx->rpz_st->m.policy) {
   7372   1.1  christos 		case DNS_RPZ_POLICY_TCP_ONLY:
   7373   1.1  christos 			qctx->client->message->flags |= DNS_MESSAGEFLAG_TC;
   7374   1.1  christos 			if (result == DNS_R_NXDOMAIN ||
   7375  1.16  christos 			    result == DNS_R_NCACHENXDOMAIN)
   7376  1.16  christos 			{
   7377   1.1  christos 				qctx->client->message->rcode =
   7378   1.9  christos 					dns_rcode_nxdomain;
   7379   1.9  christos 			}
   7380   1.3  christos 			rpz_log_rewrite(qctx->client, false,
   7381   1.1  christos 					qctx->rpz_st->m.policy,
   7382   1.1  christos 					qctx->rpz_st->m.type, qctx->zone,
   7383   1.1  christos 					qctx->rpz_st->p_name, NULL,
   7384   1.1  christos 					qctx->rpz_st->m.rpz->num);
   7385   1.1  christos 			return (ISC_R_COMPLETE);
   7386   1.1  christos 		case DNS_RPZ_POLICY_DROP:
   7387   1.1  christos 			QUERY_ERROR(qctx, DNS_R_DROP);
   7388   1.3  christos 			rpz_log_rewrite(qctx->client, false,
   7389   1.1  christos 					qctx->rpz_st->m.policy,
   7390   1.1  christos 					qctx->rpz_st->m.type, qctx->zone,
   7391   1.1  christos 					qctx->rpz_st->p_name, NULL,
   7392   1.1  christos 					qctx->rpz_st->m.rpz->num);
   7393   1.1  christos 			return (ISC_R_COMPLETE);
   7394   1.1  christos 		case DNS_RPZ_POLICY_NXDOMAIN:
   7395   1.1  christos 			result = DNS_R_NXDOMAIN;
   7396   1.3  christos 			qctx->nxrewrite = true;
   7397   1.3  christos 			qctx->rpz = true;
   7398   1.1  christos 			break;
   7399   1.1  christos 		case DNS_RPZ_POLICY_NODATA:
   7400   1.6  christos 			qctx->nxrewrite = true;
   7401  1.15  christos 			FALLTHROUGH;
   7402   1.6  christos 		case DNS_RPZ_POLICY_DNS64:
   7403   1.1  christos 			result = DNS_R_NXRRSET;
   7404   1.3  christos 			qctx->rpz = true;
   7405   1.1  christos 			break;
   7406   1.1  christos 		case DNS_RPZ_POLICY_RECORD:
   7407   1.1  christos 			result = qctx->rpz_st->m.result;
   7408   1.1  christos 			if (qctx->qtype == dns_rdatatype_any &&
   7409  1.16  christos 			    result != DNS_R_CNAME)
   7410  1.16  christos 			{
   7411   1.1  christos 				/*
   7412   1.1  christos 				 * We will add all of the rdatasets of
   7413   1.1  christos 				 * the node by iterating later,
   7414   1.1  christos 				 * and set the TTL then.
   7415   1.1  christos 				 */
   7416   1.9  christos 				if (dns_rdataset_isassociated(qctx->rdataset)) {
   7417   1.9  christos 					dns_rdataset_disassociate(
   7418   1.9  christos 						qctx->rdataset);
   7419   1.9  christos 				}
   7420   1.1  christos 			} else {
   7421   1.1  christos 				/*
   7422   1.1  christos 				 * We will add this rdataset.
   7423   1.1  christos 				 */
   7424   1.1  christos 				qctx->rdataset->ttl =
   7425   1.1  christos 					ISC_MIN(qctx->rdataset->ttl,
   7426   1.1  christos 						qctx->rpz_st->m.ttl);
   7427   1.1  christos 			}
   7428   1.3  christos 			qctx->rpz = true;
   7429   1.1  christos 			break;
   7430   1.1  christos 		case DNS_RPZ_POLICY_WILDCNAME: {
   7431   1.1  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   7432   1.1  christos 			dns_rdata_cname_t cname;
   7433   1.1  christos 			result = dns_rdataset_first(qctx->rdataset);
   7434   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7435   1.1  christos 			dns_rdataset_current(qctx->rdataset, &rdata);
   7436   1.9  christos 			result = dns_rdata_tostruct(&rdata, &cname, NULL);
   7437   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7438   1.1  christos 			dns_rdata_reset(&rdata);
   7439   1.1  christos 			result = query_rpzcname(qctx, &cname.cname);
   7440   1.9  christos 			if (result != ISC_R_SUCCESS) {
   7441   1.1  christos 				return (ISC_R_COMPLETE);
   7442   1.9  christos 			}
   7443   1.1  christos 			qctx->fname = NULL;
   7444   1.3  christos 			qctx->want_restart = true;
   7445   1.1  christos 			return (ISC_R_COMPLETE);
   7446   1.1  christos 		}
   7447   1.1  christos 		case DNS_RPZ_POLICY_CNAME:
   7448   1.1  christos 			/*
   7449   1.9  christos 			 * Add overriding CNAME from a named.conf
   7450   1.1  christos 			 * response-policy statement
   7451   1.1  christos 			 */
   7452   1.1  christos 			result = query_rpzcname(qctx,
   7453   1.1  christos 						&qctx->rpz_st->m.rpz->cname);
   7454   1.9  christos 			if (result != ISC_R_SUCCESS) {
   7455   1.1  christos 				return (ISC_R_COMPLETE);
   7456   1.9  christos 			}
   7457   1.1  christos 			qctx->fname = NULL;
   7458   1.3  christos 			qctx->want_restart = true;
   7459   1.1  christos 			return (ISC_R_COMPLETE);
   7460   1.1  christos 		default:
   7461  1.15  christos 			UNREACHABLE();
   7462   1.1  christos 		}
   7463   1.1  christos 
   7464   1.1  christos 		/*
   7465   1.1  christos 		 * Turn off DNSSEC because the results of a
   7466   1.1  christos 		 * response policy zone cannot verify.
   7467   1.1  christos 		 */
   7468   1.1  christos 		qctx->client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC |
   7469   1.1  christos 					      NS_CLIENTATTR_WANTAD);
   7470   1.1  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
   7471   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   7472   1.1  christos 		qctx->rpz_st->q.is_zone = qctx->is_zone;
   7473   1.3  christos 		qctx->is_zone = true;
   7474   1.9  christos 		rpz_log_rewrite(qctx->client, false, qctx->rpz_st->m.policy,
   7475   1.1  christos 				qctx->rpz_st->m.type, qctx->zone,
   7476   1.1  christos 				qctx->rpz_st->p_name, NULL,
   7477   1.1  christos 				qctx->rpz_st->m.rpz->num);
   7478   1.1  christos 	}
   7479   1.1  christos 
   7480   1.1  christos 	return (result);
   7481   1.1  christos }
   7482   1.1  christos 
   7483   1.1  christos /*%
   7484   1.1  christos  * Add a CNAME to a query response, including translating foo.evil.com and
   7485   1.1  christos  *	*.evil.com CNAME *.example.com
   7486   1.1  christos  * to
   7487   1.1  christos  *	foo.evil.com CNAME foo.evil.com.example.com
   7488   1.1  christos  */
   7489   1.1  christos static isc_result_t
   7490   1.1  christos query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) {
   7491   1.6  christos 	ns_client_t *client;
   7492   1.1  christos 	dns_fixedname_t prefix, suffix;
   7493   1.1  christos 	unsigned int labels;
   7494   1.1  christos 	isc_result_t result;
   7495   1.1  christos 
   7496   1.6  christos 	REQUIRE(qctx != NULL && qctx->client != NULL);
   7497   1.6  christos 
   7498   1.6  christos 	client = qctx->client;
   7499   1.6  christos 
   7500   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_rpzcname");
   7501   1.1  christos 
   7502   1.1  christos 	labels = dns_name_countlabels(cname);
   7503   1.1  christos 	if (labels > 2 && dns_name_iswildcard(cname)) {
   7504   1.1  christos 		dns_fixedname_init(&prefix);
   7505   1.1  christos 		dns_name_split(client->query.qname, 1,
   7506   1.1  christos 			       dns_fixedname_name(&prefix), NULL);
   7507   1.1  christos 		dns_fixedname_init(&suffix);
   7508   1.9  christos 		dns_name_split(cname, labels - 1, NULL,
   7509   1.9  christos 			       dns_fixedname_name(&suffix));
   7510   1.1  christos 		result = dns_name_concatenate(dns_fixedname_name(&prefix),
   7511   1.1  christos 					      dns_fixedname_name(&suffix),
   7512   1.1  christos 					      qctx->fname, NULL);
   7513   1.1  christos 		if (result == DNS_R_NAMETOOLONG) {
   7514   1.1  christos 			client->message->rcode = dns_rcode_yxdomain;
   7515   1.1  christos 		} else if (result != ISC_R_SUCCESS) {
   7516   1.1  christos 			return (result);
   7517   1.1  christos 		}
   7518   1.1  christos 	} else {
   7519  1.20  christos 		dns_name_copy(cname, qctx->fname);
   7520   1.1  christos 	}
   7521   1.1  christos 
   7522   1.3  christos 	ns_client_keepname(client, qctx->fname, qctx->dbuf);
   7523   1.1  christos 	result = query_addcname(qctx, dns_trust_authanswer,
   7524   1.1  christos 				qctx->rpz_st->m.ttl);
   7525   1.1  christos 	if (result != ISC_R_SUCCESS) {
   7526   1.1  christos 		return (result);
   7527   1.1  christos 	}
   7528   1.1  christos 
   7529   1.3  christos 	rpz_log_rewrite(client, false, qctx->rpz_st->m.policy,
   7530   1.1  christos 			qctx->rpz_st->m.type, qctx->rpz_st->m.zone,
   7531   1.1  christos 			qctx->rpz_st->p_name, qctx->fname,
   7532   1.1  christos 			qctx->rpz_st->m.rpz->num);
   7533   1.1  christos 
   7534   1.1  christos 	ns_client_qnamereplace(client, qctx->fname);
   7535   1.1  christos 
   7536   1.1  christos 	/*
   7537   1.1  christos 	 * Turn off DNSSEC because the results of a
   7538   1.1  christos 	 * response policy zone cannot verify.
   7539   1.1  christos 	 */
   7540   1.1  christos 	client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC |
   7541   1.1  christos 				NS_CLIENTATTR_WANTAD);
   7542   1.1  christos 
   7543   1.1  christos 	return (ISC_R_SUCCESS);
   7544   1.1  christos }
   7545   1.1  christos 
   7546   1.1  christos /*%
   7547   1.1  christos  * Check the configured trust anchors for a root zone trust anchor
   7548   1.1  christos  * with a key id that matches qctx->client->query.root_key_sentinel_keyid.
   7549   1.1  christos  *
   7550   1.3  christos  * Return true when found, otherwise return false.
   7551   1.1  christos  */
   7552   1.3  christos static bool
   7553   1.1  christos has_ta(query_ctx_t *qctx) {
   7554   1.1  christos 	dns_keytable_t *keytable = NULL;
   7555   1.1  christos 	dns_keynode_t *keynode = NULL;
   7556  1.10  christos 	dns_rdataset_t dsset;
   7557   1.9  christos 	dns_keytag_t sentinel = qctx->client->query.root_key_sentinel_keyid;
   7558   1.1  christos 	isc_result_t result;
   7559   1.1  christos 
   7560   1.3  christos 	result = dns_view_getsecroots(qctx->view, &keytable);
   7561   1.1  christos 	if (result != ISC_R_SUCCESS) {
   7562   1.3  christos 		return (false);
   7563   1.1  christos 	}
   7564   1.1  christos 
   7565   1.1  christos 	result = dns_keytable_find(keytable, dns_rootname, &keynode);
   7566   1.9  christos 	if (result != ISC_R_SUCCESS) {
   7567   1.9  christos 		if (keynode != NULL) {
   7568   1.1  christos 			dns_keytable_detachkeynode(keytable, &keynode);
   7569   1.1  christos 		}
   7570   1.9  christos 		dns_keytable_detach(&keytable);
   7571   1.9  christos 		return (false);
   7572   1.9  christos 	}
   7573   1.9  christos 
   7574  1.10  christos 	dns_rdataset_init(&dsset);
   7575  1.10  christos 	if (dns_keynode_dsset(keynode, &dsset)) {
   7576  1.10  christos 		for (result = dns_rdataset_first(&dsset);
   7577  1.10  christos 		     result == ISC_R_SUCCESS;
   7578  1.10  christos 		     result = dns_rdataset_next(&dsset))
   7579   1.9  christos 		{
   7580   1.9  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   7581   1.9  christos 			dns_rdata_ds_t ds;
   7582   1.9  christos 
   7583   1.9  christos 			dns_rdata_reset(&rdata);
   7584  1.10  christos 			dns_rdataset_current(&dsset, &rdata);
   7585   1.9  christos 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
   7586   1.9  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7587   1.9  christos 			if (ds.key_tag == sentinel) {
   7588   1.9  christos 				dns_keytable_detachkeynode(keytable, &keynode);
   7589   1.9  christos 				dns_keytable_detach(&keytable);
   7590  1.10  christos 				dns_rdataset_disassociate(&dsset);
   7591   1.9  christos 				return (true);
   7592   1.9  christos 			}
   7593   1.9  christos 		}
   7594  1.10  christos 		dns_rdataset_disassociate(&dsset);
   7595   1.9  christos 	}
   7596   1.9  christos 
   7597   1.9  christos 	if (keynode != NULL) {
   7598   1.1  christos 		dns_keytable_detachkeynode(keytable, &keynode);
   7599   1.1  christos 	}
   7600   1.9  christos 
   7601   1.1  christos 	dns_keytable_detach(&keytable);
   7602   1.1  christos 
   7603   1.3  christos 	return (false);
   7604   1.1  christos }
   7605   1.1  christos 
   7606   1.1  christos /*%
   7607   1.1  christos  * Check if a root key sentinel SERVFAIL should be returned.
   7608   1.1  christos  */
   7609   1.3  christos static bool
   7610   1.1  christos root_key_sentinel_return_servfail(query_ctx_t *qctx, isc_result_t result) {
   7611   1.1  christos 	/*
   7612   1.1  christos 	 * Are we looking at a "root-key-sentinel" query?
   7613   1.1  christos 	 */
   7614   1.1  christos 	if (!qctx->client->query.root_key_sentinel_is_ta &&
   7615   1.1  christos 	    !qctx->client->query.root_key_sentinel_not_ta)
   7616   1.1  christos 	{
   7617   1.3  christos 		return (false);
   7618   1.1  christos 	}
   7619   1.1  christos 
   7620   1.1  christos 	/*
   7621   1.1  christos 	 * We only care about the query if 'result' indicates we have a cached
   7622   1.1  christos 	 * answer.
   7623   1.1  christos 	 */
   7624   1.1  christos 	switch (result) {
   7625   1.1  christos 	case ISC_R_SUCCESS:
   7626   1.1  christos 	case DNS_R_CNAME:
   7627   1.1  christos 	case DNS_R_DNAME:
   7628   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   7629   1.1  christos 	case DNS_R_NCACHENXRRSET:
   7630   1.1  christos 		break;
   7631   1.1  christos 	default:
   7632   1.3  christos 		return (false);
   7633   1.1  christos 	}
   7634   1.1  christos 
   7635   1.1  christos 	/*
   7636   1.1  christos 	 * Do we meet the specified conditions to return SERVFAIL?
   7637   1.1  christos 	 */
   7638   1.9  christos 	if (!qctx->is_zone && qctx->rdataset->trust == dns_trust_secure &&
   7639   1.1  christos 	    ((qctx->client->query.root_key_sentinel_is_ta && !has_ta(qctx)) ||
   7640   1.1  christos 	     (qctx->client->query.root_key_sentinel_not_ta && has_ta(qctx))))
   7641   1.1  christos 	{
   7642   1.3  christos 		return (true);
   7643   1.1  christos 	}
   7644   1.1  christos 
   7645   1.1  christos 	/*
   7646   1.1  christos 	 * As special processing may only be triggered by the original QNAME,
   7647   1.1  christos 	 * disable it after following a CNAME/DNAME.
   7648   1.1  christos 	 */
   7649   1.3  christos 	qctx->client->query.root_key_sentinel_is_ta = false;
   7650   1.3  christos 	qctx->client->query.root_key_sentinel_not_ta = false;
   7651   1.1  christos 
   7652   1.3  christos 	return (false);
   7653   1.1  christos }
   7654   1.1  christos 
   7655   1.1  christos /*%
   7656   1.3  christos  * If serving stale answers is allowed, set up 'qctx' to look for one and
   7657   1.3  christos  * return true; otherwise, return false.
   7658   1.3  christos  */
   7659   1.3  christos static bool
   7660  1.13  christos query_usestale(query_ctx_t *qctx, isc_result_t result) {
   7661  1.13  christos 	if ((qctx->client->query.dboptions & DNS_DBFIND_STALEOK) != 0) {
   7662  1.13  christos 		/*
   7663  1.13  christos 		 * Query was already using stale, if that didn't work the
   7664  1.13  christos 		 * last time, it won't work this time either.
   7665  1.13  christos 		 */
   7666  1.13  christos 		return (false);
   7667  1.13  christos 	}
   7668  1.13  christos 
   7669  1.17  christos 	if (qctx->refresh_rrset) {
   7670  1.17  christos 		/*
   7671  1.17  christos 		 * This is a refreshing query, we have already prioritized
   7672  1.17  christos 		 * stale data, so don't enable serve-stale again.
   7673  1.17  christos 		 */
   7674  1.17  christos 		return (false);
   7675  1.17  christos 	}
   7676  1.17  christos 
   7677  1.17  christos 	if (result == DNS_R_DUPLICATE || result == DNS_R_DROP ||
   7678  1.17  christos 	    result == ISC_R_ALREADYRUNNING)
   7679  1.17  christos 	{
   7680  1.15  christos 		/*
   7681  1.15  christos 		 * Don't enable serve-stale if the result signals a duplicate
   7682  1.17  christos 		 * query or a query that is being dropped or can't proceed
   7683  1.17  christos 		 * because of a recursion loop.
   7684  1.15  christos 		 */
   7685  1.15  christos 		return (false);
   7686  1.15  christos 	}
   7687  1.15  christos 
   7688   1.3  christos 	qctx_clean(qctx);
   7689   1.3  christos 	qctx_freedata(qctx);
   7690   1.3  christos 
   7691  1.11  christos 	if (dns_view_staleanswerenabled(qctx->client->view)) {
   7692  1.20  christos 		isc_result_t ret;
   7693  1.20  christos 		ret = query_getdb(qctx->client, qctx->client->query.qname,
   7694  1.20  christos 				  qctx->client->query.qtype, qctx->options,
   7695  1.20  christos 				  &qctx->zone, &qctx->db, &qctx->version,
   7696  1.20  christos 				  &qctx->is_zone);
   7697  1.20  christos 		if (ret != ISC_R_SUCCESS) {
   7698  1.20  christos 			/*
   7699  1.20  christos 			 * Failed to get the database, unexpected, but let us
   7700  1.20  christos 			 * at least abandon serve-stale.
   7701  1.20  christos 			 */
   7702  1.20  christos 			return (false);
   7703  1.20  christos 		}
   7704  1.20  christos 
   7705   1.3  christos 		qctx->client->query.dboptions |= DNS_DBFIND_STALEOK;
   7706   1.3  christos 		if (qctx->client->query.fetch != NULL) {
   7707   1.3  christos 			dns_resolver_destroyfetch(&qctx->client->query.fetch);
   7708   1.3  christos 		}
   7709  1.11  christos 
   7710  1.13  christos 		/*
   7711  1.13  christos 		 * Start the stale-refresh-time window in case there was a
   7712  1.13  christos 		 * resolver query timeout.
   7713  1.13  christos 		 */
   7714  1.13  christos 		if (qctx->resuming && result == ISC_R_TIMEDOUT) {
   7715  1.13  christos 			qctx->client->query.dboptions |= DNS_DBFIND_STALESTART;
   7716  1.13  christos 		}
   7717  1.11  christos 		return (true);
   7718   1.3  christos 	}
   7719   1.3  christos 
   7720  1.11  christos 	return (false);
   7721   1.3  christos }
   7722   1.3  christos 
   7723   1.3  christos /*%
   7724   1.3  christos  * Continue after doing a database lookup or returning from
   7725   1.3  christos  * recursion, and call out to the next function depending on the
   7726   1.3  christos  * result from the search.
   7727   1.1  christos  */
   7728   1.1  christos static isc_result_t
   7729  1.18  christos query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
   7730   1.1  christos 	char errmsg[256];
   7731   1.1  christos 
   7732   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer");
   7733   1.1  christos 
   7734   1.3  christos 	CALL_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx);
   7735   1.3  christos 
   7736   1.1  christos 	if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) {
   7737   1.3  christos 		return (ns_query_done(qctx));
   7738   1.1  christos 	}
   7739   1.1  christos 
   7740  1.13  christos 	if (!dns_name_equal(qctx->client->query.qname, dns_rootname)) {
   7741   1.1  christos 		result = query_checkrpz(qctx, result);
   7742  1.13  christos 		if (result == ISC_R_NOTFOUND) {
   7743  1.13  christos 			/*
   7744  1.13  christos 			 * RPZ not configured for this view.
   7745  1.13  christos 			 */
   7746  1.13  christos 			goto root_key_sentinel;
   7747  1.13  christos 		}
   7748  1.13  christos 		if (RECURSING(qctx->client) && result == DNS_R_DISALLOWED) {
   7749  1.13  christos 			/*
   7750  1.13  christos 			 * We are recursing, and thus RPZ processing is not
   7751  1.13  christos 			 * allowed at the moment. This could happen on a
   7752  1.13  christos 			 * "stale-answer-client-timeout" lookup. In this case,
   7753  1.13  christos 			 * bail out and wait for recursion to complete, as we
   7754  1.13  christos 			 * we can't perform the RPZ rewrite rules.
   7755  1.13  christos 			 */
   7756  1.13  christos 			return (result);
   7757  1.13  christos 		}
   7758   1.3  christos 		if (result == ISC_R_COMPLETE) {
   7759   1.3  christos 			return (ns_query_done(qctx));
   7760   1.3  christos 		}
   7761   1.1  christos 	}
   7762   1.1  christos 
   7763  1.13  christos root_key_sentinel:
   7764   1.1  christos 	/*
   7765   1.1  christos 	 * If required, handle special "root-key-sentinel-is-ta-<keyid>" and
   7766   1.1  christos 	 * "root-key-sentinel-not-ta-<keyid>" labels by returning SERVFAIL.
   7767   1.1  christos 	 */
   7768   1.1  christos 	if (root_key_sentinel_return_servfail(qctx, result)) {
   7769   1.1  christos 		/*
   7770   1.1  christos 		 * Don't record this response in the SERVFAIL cache.
   7771   1.1  christos 		 */
   7772   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
   7773   1.1  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   7774   1.3  christos 		return (ns_query_done(qctx));
   7775   1.1  christos 	}
   7776   1.1  christos 
   7777   1.1  christos 	switch (result) {
   7778   1.1  christos 	case ISC_R_SUCCESS:
   7779   1.1  christos 		return (query_prepresponse(qctx));
   7780   1.1  christos 
   7781   1.1  christos 	case DNS_R_GLUE:
   7782   1.1  christos 	case DNS_R_ZONECUT:
   7783   1.1  christos 		INSIST(qctx->is_zone);
   7784   1.3  christos 		qctx->authoritative = false;
   7785   1.1  christos 		return (query_prepresponse(qctx));
   7786   1.1  christos 
   7787   1.1  christos 	case ISC_R_NOTFOUND:
   7788   1.1  christos 		return (query_notfound(qctx));
   7789   1.1  christos 
   7790   1.1  christos 	case DNS_R_DELEGATION:
   7791   1.1  christos 		return (query_delegation(qctx));
   7792   1.1  christos 
   7793   1.1  christos 	case DNS_R_EMPTYNAME:
   7794   1.1  christos 	case DNS_R_NXRRSET:
   7795  1.20  christos 		return (query_nodata(qctx, result));
   7796   1.1  christos 
   7797   1.1  christos 	case DNS_R_EMPTYWILD:
   7798   1.1  christos 	case DNS_R_NXDOMAIN:
   7799  1.20  christos 		return (query_nxdomain(qctx, result));
   7800   1.1  christos 
   7801   1.1  christos 	case DNS_R_COVERINGNSEC:
   7802   1.1  christos 		return (query_coveringnsec(qctx));
   7803   1.1  christos 
   7804   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   7805  1.18  christos 		result = query_redirect(qctx, result);
   7806   1.9  christos 		if (result != ISC_R_COMPLETE) {
   7807   1.1  christos 			return (result);
   7808   1.9  christos 		}
   7809   1.1  christos 		return (query_ncache(qctx, DNS_R_NCACHENXDOMAIN));
   7810   1.1  christos 
   7811   1.1  christos 	case DNS_R_NCACHENXRRSET:
   7812   1.1  christos 		return (query_ncache(qctx, DNS_R_NCACHENXRRSET));
   7813   1.1  christos 
   7814   1.1  christos 	case DNS_R_CNAME:
   7815   1.1  christos 		return (query_cname(qctx));
   7816   1.1  christos 
   7817   1.1  christos 	case DNS_R_DNAME:
   7818   1.1  christos 		return (query_dname(qctx));
   7819   1.1  christos 
   7820   1.1  christos 	default:
   7821   1.1  christos 		/*
   7822   1.1  christos 		 * Something has gone wrong.
   7823   1.1  christos 		 */
   7824   1.1  christos 		snprintf(errmsg, sizeof(errmsg) - 1,
   7825   1.1  christos 			 "query_gotanswer: unexpected error: %s",
   7826   1.1  christos 			 isc_result_totext(result));
   7827   1.1  christos 		CCTRACE(ISC_LOG_ERROR, errmsg);
   7828  1.13  christos 		if (query_usestale(qctx, result)) {
   7829   1.3  christos 			/*
   7830   1.3  christos 			 * If serve-stale is enabled, query_usestale() already
   7831   1.3  christos 			 * set up 'qctx' for looking up a stale response.
   7832   1.3  christos 			 */
   7833   1.3  christos 			return (query_lookup(qctx));
   7834   1.1  christos 		}
   7835   1.6  christos 
   7836   1.6  christos 		/*
   7837   1.6  christos 		 * Regardless of the triggering result, we definitely
   7838   1.6  christos 		 * want to return SERVFAIL from here.
   7839   1.6  christos 		 */
   7840   1.6  christos 		qctx->client->rcode_override = dns_rcode_servfail;
   7841   1.6  christos 
   7842   1.3  christos 		QUERY_ERROR(qctx, result);
   7843   1.3  christos 		return (ns_query_done(qctx));
   7844   1.1  christos 	}
   7845   1.3  christos 
   7846   1.9  christos cleanup:
   7847   1.3  christos 	return (result);
   7848   1.1  christos }
   7849   1.1  christos 
   7850   1.1  christos static void
   7851   1.1  christos query_addnoqnameproof(query_ctx_t *qctx) {
   7852   1.1  christos 	ns_client_t *client = qctx->client;
   7853   1.1  christos 	isc_buffer_t *dbuf, b;
   7854   1.1  christos 	dns_name_t *fname = NULL;
   7855   1.1  christos 	dns_rdataset_t *neg = NULL, *negsig = NULL;
   7856   1.1  christos 	isc_result_t result = ISC_R_NOMEMORY;
   7857   1.1  christos 
   7858   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addnoqnameproof");
   7859   1.1  christos 
   7860   1.1  christos 	if (qctx->noqname == NULL) {
   7861   1.1  christos 		return;
   7862   1.1  christos 	}
   7863   1.1  christos 
   7864   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   7865   1.1  christos 	if (dbuf == NULL) {
   7866   1.1  christos 		goto cleanup;
   7867   1.1  christos 	}
   7868   1.1  christos 
   7869   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   7870   1.3  christos 	neg = ns_client_newrdataset(client);
   7871   1.3  christos 	negsig = ns_client_newrdataset(client);
   7872   1.1  christos 	if (fname == NULL || neg == NULL || negsig == NULL) {
   7873   1.1  christos 		goto cleanup;
   7874   1.1  christos 	}
   7875   1.1  christos 
   7876   1.1  christos 	result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig);
   7877   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7878   1.1  christos 
   7879   1.3  christos 	query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
   7880   1.1  christos 		       DNS_SECTION_AUTHORITY);
   7881   1.1  christos 
   7882   1.1  christos 	if ((qctx->noqname->attributes & DNS_RDATASETATTR_CLOSEST) == 0) {
   7883   1.1  christos 		goto cleanup;
   7884   1.1  christos 	}
   7885   1.1  christos 
   7886   1.1  christos 	if (fname == NULL) {
   7887   1.3  christos 		dbuf = ns_client_getnamebuf(client);
   7888   1.9  christos 		if (dbuf == NULL) {
   7889   1.1  christos 			goto cleanup;
   7890   1.9  christos 		}
   7891   1.3  christos 		fname = ns_client_newname(client, dbuf, &b);
   7892   1.1  christos 	}
   7893   1.1  christos 
   7894   1.1  christos 	if (neg == NULL) {
   7895   1.3  christos 		neg = ns_client_newrdataset(client);
   7896   1.1  christos 	} else if (dns_rdataset_isassociated(neg)) {
   7897   1.1  christos 		dns_rdataset_disassociate(neg);
   7898   1.1  christos 	}
   7899   1.1  christos 
   7900   1.1  christos 	if (negsig == NULL) {
   7901   1.3  christos 		negsig = ns_client_newrdataset(client);
   7902   1.1  christos 	} else if (dns_rdataset_isassociated(negsig)) {
   7903   1.1  christos 		dns_rdataset_disassociate(negsig);
   7904   1.1  christos 	}
   7905   1.1  christos 
   7906   1.9  christos 	if (fname == NULL || neg == NULL || negsig == NULL) {
   7907   1.1  christos 		goto cleanup;
   7908   1.9  christos 	}
   7909   1.1  christos 	result = dns_rdataset_getclosest(qctx->noqname, fname, neg, negsig);
   7910   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7911   1.1  christos 
   7912   1.3  christos 	query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
   7913   1.1  christos 		       DNS_SECTION_AUTHORITY);
   7914   1.1  christos 
   7915   1.9  christos cleanup:
   7916   1.1  christos 	if (neg != NULL) {
   7917   1.3  christos 		ns_client_putrdataset(client, &neg);
   7918   1.1  christos 	}
   7919   1.1  christos 	if (negsig != NULL) {
   7920   1.3  christos 		ns_client_putrdataset(client, &negsig);
   7921   1.1  christos 	}
   7922   1.1  christos 	if (fname != NULL) {
   7923   1.3  christos 		ns_client_releasename(client, &fname);
   7924   1.1  christos 	}
   7925   1.1  christos }
   7926   1.1  christos 
   7927   1.1  christos /*%
   7928   1.1  christos  * Build the response for a query for type ANY.
   7929   1.1  christos  */
   7930   1.1  christos static isc_result_t
   7931   1.1  christos query_respond_any(query_ctx_t *qctx) {
   7932   1.5  christos 	bool found = false, hidden = false;
   7933   1.1  christos 	dns_rdatasetiter_t *rdsiter = NULL;
   7934  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   7935   1.9  christos 	dns_rdatatype_t onetype = 0; /* type to use for minimal-any */
   7936   1.3  christos 	isc_buffer_t b;
   7937   1.1  christos 
   7938   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_respond_any");
   7939   1.9  christos 
   7940   1.3  christos 	CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx);
   7941   1.1  christos 
   7942  1.16  christos 	result = dns_db_allrdatasets(qctx->db, qctx->node, qctx->version, 0, 0,
   7943   1.9  christos 				     &rdsiter);
   7944   1.1  christos 	if (result != ISC_R_SUCCESS) {
   7945   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_respond_any: allrdatasets "
   7946   1.9  christos 				       "failed");
   7947   1.3  christos 		QUERY_ERROR(qctx, result);
   7948   1.3  christos 		return (ns_query_done(qctx));
   7949   1.1  christos 	}
   7950   1.1  christos 
   7951   1.1  christos 	/*
   7952   1.1  christos 	 * Calling query_addrrset() with a non-NULL dbuf is going
   7953   1.1  christos 	 * to either keep or release the name.  We don't want it to
   7954   1.1  christos 	 * release fname, since we may have to call query_addrrset()
   7955   1.3  christos 	 * more than once.  That means we have to call ns_client_keepname()
   7956   1.1  christos 	 * now, and pass a NULL dbuf to query_addrrset().
   7957   1.1  christos 	 *
   7958   1.1  christos 	 * If we do a query_addrrset() below, we must set qctx->fname to
   7959   1.1  christos 	 * NULL before leaving this block, otherwise we might try to
   7960   1.1  christos 	 * cleanup qctx->fname even though we're using it!
   7961   1.1  christos 	 */
   7962   1.3  christos 	ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   7963   1.3  christos 	qctx->tname = qctx->fname;
   7964   1.1  christos 
   7965   1.1  christos 	result = dns_rdatasetiter_first(rdsiter);
   7966   1.1  christos 	while (result == ISC_R_SUCCESS) {
   7967   1.1  christos 		dns_rdatasetiter_current(rdsiter, qctx->rdataset);
   7968   1.1  christos 
   7969   1.1  christos 		/*
   7970   1.1  christos 		 * We found an NS RRset; no need to add one later.
   7971   1.1  christos 		 */
   7972   1.1  christos 		if (qctx->qtype == dns_rdatatype_any &&
   7973   1.1  christos 		    qctx->rdataset->type == dns_rdatatype_ns)
   7974   1.1  christos 		{
   7975   1.3  christos 			qctx->answer_has_ns = true;
   7976   1.1  christos 		}
   7977   1.1  christos 
   7978   1.1  christos 		/*
   7979   1.1  christos 		 * Note: if we're in this function, then qctx->type
   7980   1.1  christos 		 * is guaranteed to be ANY, but qctx->qtype (i.e. the
   7981   1.1  christos 		 * original type requested) might have been RRSIG or
   7982   1.1  christos 		 * SIG; we need to check for that.
   7983   1.1  christos 		 */
   7984   1.1  christos 		if (qctx->is_zone && qctx->qtype == dns_rdatatype_any &&
   7985   1.1  christos 		    !dns_db_issecure(qctx->db) &&
   7986   1.1  christos 		    dns_rdatatype_isdnssec(qctx->rdataset->type))
   7987   1.1  christos 		{
   7988   1.1  christos 			/*
   7989   1.5  christos 			 * The zone may be transitioning from insecure
   7990   1.5  christos 			 * to secure. Hide DNSSEC records from ANY queries.
   7991   1.1  christos 			 */
   7992   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   7993   1.5  christos 			hidden = true;
   7994   1.9  christos 		} else if (qctx->view->minimal_any && !TCP(qctx->client) &&
   7995   1.9  christos 			   !WANTDNSSEC(qctx->client) &&
   7996   1.1  christos 			   qctx->qtype == dns_rdatatype_any &&
   7997   1.1  christos 			   (qctx->rdataset->type == dns_rdatatype_sig ||
   7998   1.1  christos 			    qctx->rdataset->type == dns_rdatatype_rrsig))
   7999   1.1  christos 		{
   8000   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
   8001   1.9  christos 						  "minimal-any skip signature");
   8002   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   8003   1.9  christos 		} else if (qctx->view->minimal_any && !TCP(qctx->client) &&
   8004   1.9  christos 			   onetype != 0 && qctx->rdataset->type != onetype &&
   8005   1.1  christos 			   qctx->rdataset->covers != onetype)
   8006   1.1  christos 		{
   8007   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
   8008   1.9  christos 						  "minimal-any skip rdataset");
   8009   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   8010   1.1  christos 		} else if ((qctx->qtype == dns_rdatatype_any ||
   8011   1.1  christos 			    qctx->rdataset->type == qctx->qtype) &&
   8012   1.1  christos 			   qctx->rdataset->type != 0)
   8013   1.1  christos 		{
   8014   1.9  christos 			if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client))
   8015   1.1  christos 			{
   8016   1.1  christos 				qctx->noqname = qctx->rdataset;
   8017   1.1  christos 			} else {
   8018   1.1  christos 				qctx->noqname = NULL;
   8019   1.1  christos 			}
   8020   1.1  christos 
   8021   1.1  christos 			qctx->rpz_st = qctx->client->query.rpz_st;
   8022   1.9  christos 			if (qctx->rpz_st != NULL) {
   8023   1.1  christos 				qctx->rdataset->ttl =
   8024   1.1  christos 					ISC_MIN(qctx->rdataset->ttl,
   8025   1.1  christos 						qctx->rpz_st->m.ttl);
   8026   1.9  christos 			}
   8027   1.1  christos 
   8028   1.1  christos 			if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   8029   1.1  christos 				dns_name_t *name;
   8030   1.9  christos 				name = (qctx->fname != NULL) ? qctx->fname
   8031   1.9  christos 							     : qctx->tname;
   8032   1.1  christos 				query_prefetch(qctx->client, name,
   8033   1.1  christos 					       qctx->rdataset);
   8034   1.1  christos 			}
   8035   1.1  christos 
   8036   1.1  christos 			/*
   8037   1.1  christos 			 * Remember the first RRtype we find so we
   8038   1.1  christos 			 * can skip others with minimal-any.
   8039   1.1  christos 			 */
   8040   1.1  christos 			if (qctx->rdataset->type == dns_rdatatype_sig ||
   8041   1.1  christos 			    qctx->rdataset->type == dns_rdatatype_rrsig)
   8042   1.3  christos 			{
   8043   1.1  christos 				onetype = qctx->rdataset->covers;
   8044   1.3  christos 			} else {
   8045   1.1  christos 				onetype = qctx->rdataset->type;
   8046   1.3  christos 			}
   8047   1.1  christos 
   8048   1.3  christos 			query_addrrset(qctx,
   8049   1.9  christos 				       (qctx->fname != NULL) ? &qctx->fname
   8050   1.9  christos 							     : &qctx->tname,
   8051   1.9  christos 				       &qctx->rdataset, NULL, NULL,
   8052   1.9  christos 				       DNS_SECTION_ANSWER);
   8053   1.1  christos 
   8054   1.1  christos 			query_addnoqnameproof(qctx);
   8055   1.1  christos 
   8056   1.3  christos 			found = true;
   8057   1.3  christos 			INSIST(qctx->tname != NULL);
   8058   1.1  christos 
   8059   1.1  christos 			/*
   8060   1.1  christos 			 * rdataset is non-NULL only in certain
   8061   1.1  christos 			 * pathological cases involving DNAMEs.
   8062   1.1  christos 			 */
   8063   1.3  christos 			if (qctx->rdataset != NULL) {
   8064   1.3  christos 				ns_client_putrdataset(qctx->client,
   8065   1.3  christos 						      &qctx->rdataset);
   8066   1.3  christos 			}
   8067   1.1  christos 
   8068   1.3  christos 			qctx->rdataset = ns_client_newrdataset(qctx->client);
   8069   1.5  christos 			if (qctx->rdataset == NULL) {
   8070   1.1  christos 				break;
   8071   1.5  christos 			}
   8072   1.1  christos 		} else {
   8073   1.1  christos 			/*
   8074   1.1  christos 			 * We're not interested in this rdataset.
   8075   1.1  christos 			 */
   8076   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   8077   1.1  christos 		}
   8078   1.1  christos 
   8079   1.1  christos 		result = dns_rdatasetiter_next(rdsiter);
   8080   1.1  christos 	}
   8081   1.1  christos 
   8082   1.3  christos 	dns_rdatasetiter_destroy(&rdsiter);
   8083   1.3  christos 
   8084   1.3  christos 	if (result != ISC_R_NOMORE) {
   8085   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_respond_any: rdataset iterator "
   8086   1.9  christos 				       "failed");
   8087   1.3  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   8088   1.3  christos 		return (ns_query_done(qctx));
   8089   1.3  christos 	}
   8090   1.3  christos 
   8091   1.3  christos 	if (found) {
   8092   1.5  christos 		/*
   8093   1.5  christos 		 * Call hook if any answers were found.
   8094   1.5  christos 		 * Do this before releasing qctx->fname, in case
   8095   1.5  christos 		 * the hook function needs it.
   8096   1.5  christos 		 */
   8097   1.3  christos 		CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx);
   8098   1.3  christos 	}
   8099   1.3  christos 
   8100   1.3  christos 	if (qctx->fname != NULL) {
   8101   1.5  christos 		dns_message_puttempname(qctx->client->message, &qctx->fname);
   8102   1.1  christos 	}
   8103   1.1  christos 
   8104   1.5  christos 	if (found) {
   8105   1.5  christos 		/*
   8106   1.5  christos 		 * At least one matching rdataset was found
   8107   1.5  christos 		 */
   8108   1.1  christos 		query_addauth(qctx);
   8109   1.5  christos 	} else if (qctx->qtype == dns_rdatatype_rrsig ||
   8110   1.5  christos 		   qctx->qtype == dns_rdatatype_sig)
   8111   1.5  christos 	{
   8112   1.5  christos 		/*
   8113   1.5  christos 		 * No matching rdatasets were found, but we got
   8114   1.5  christos 		 * here on a search for RRSIG/SIG, so that's okay.
   8115   1.5  christos 		 */
   8116   1.5  christos 		if (!qctx->is_zone) {
   8117   1.5  christos 			qctx->authoritative = false;
   8118   1.5  christos 			qctx->client->attributes &= ~NS_CLIENTATTR_RA;
   8119   1.5  christos 			query_addauth(qctx);
   8120   1.5  christos 			return (ns_query_done(qctx));
   8121   1.5  christos 		}
   8122   1.5  christos 
   8123   1.5  christos 		if (qctx->qtype == dns_rdatatype_rrsig &&
   8124  1.16  christos 		    dns_db_issecure(qctx->db))
   8125  1.16  christos 		{
   8126   1.5  christos 			char namebuf[DNS_NAME_FORMATSIZE];
   8127   1.9  christos 			dns_name_format(qctx->client->query.qname, namebuf,
   8128   1.9  christos 					sizeof(namebuf));
   8129   1.5  christos 			ns_client_log(qctx->client, DNS_LOGCATEGORY_DNSSEC,
   8130   1.5  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   8131   1.5  christos 				      "missing signature for %s", namebuf);
   8132   1.5  christos 		}
   8133   1.1  christos 
   8134   1.5  christos 		qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   8135   1.5  christos 		return (query_sign_nodata(qctx));
   8136   1.5  christos 	} else if (!hidden) {
   8137   1.5  christos 		/*
   8138   1.5  christos 		 * No matching rdatasets were found and nothing was
   8139   1.5  christos 		 * deliberately hidden: something must have gone wrong.
   8140   1.5  christos 		 */
   8141   1.5  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   8142   1.3  christos 	}
   8143   1.3  christos 
   8144   1.5  christos 	return (ns_query_done(qctx));
   8145   1.3  christos 
   8146   1.9  christos cleanup:
   8147   1.3  christos 	return (result);
   8148   1.1  christos }
   8149   1.1  christos 
   8150   1.1  christos /*
   8151  1.20  christos  * Set the expire time, if requested, when answering from a secondary,
   8152  1.20  christos  * mirror, or primary zone.
   8153   1.1  christos  */
   8154   1.1  christos static void
   8155   1.1  christos query_getexpire(query_ctx_t *qctx) {
   8156   1.1  christos 	dns_zone_t *raw = NULL, *mayberaw;
   8157   1.1  christos 
   8158   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_getexpire");
   8159   1.9  christos 
   8160   1.1  christos 	if (qctx->zone == NULL || !qctx->is_zone ||
   8161   1.1  christos 	    qctx->qtype != dns_rdatatype_soa ||
   8162   1.1  christos 	    qctx->client->query.restarts != 0 ||
   8163   1.1  christos 	    (qctx->client->attributes & NS_CLIENTATTR_WANTEXPIRE) == 0)
   8164   1.1  christos 	{
   8165   1.1  christos 		return;
   8166   1.1  christos 	}
   8167   1.1  christos 
   8168   1.1  christos 	dns_zone_getraw(qctx->zone, &raw);
   8169   1.1  christos 	mayberaw = (raw != NULL) ? raw : qctx->zone;
   8170   1.1  christos 
   8171  1.15  christos 	if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
   8172   1.3  christos 	    dns_zone_gettype(mayberaw) == dns_zone_mirror)
   8173   1.3  christos 	{
   8174   1.1  christos 		isc_time_t expiretime;
   8175   1.3  christos 		uint32_t secs;
   8176   1.1  christos 		dns_zone_getexpiretime(qctx->zone, &expiretime);
   8177   1.1  christos 		secs = isc_time_seconds(&expiretime);
   8178   1.9  christos 		if (secs >= qctx->client->now && qctx->result == ISC_R_SUCCESS)
   8179   1.1  christos 		{
   8180   1.9  christos 			qctx->client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
   8181   1.1  christos 			qctx->client->expire = secs - qctx->client->now;
   8182   1.1  christos 		}
   8183  1.15  christos 	} else if (dns_zone_gettype(mayberaw) == dns_zone_primary) {
   8184   1.1  christos 		isc_result_t result;
   8185   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   8186   1.1  christos 		dns_rdata_soa_t soa;
   8187   1.1  christos 
   8188   1.1  christos 		result = dns_rdataset_first(qctx->rdataset);
   8189   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   8190   1.1  christos 
   8191   1.1  christos 		dns_rdataset_current(qctx->rdataset, &rdata);
   8192   1.1  christos 		result = dns_rdata_tostruct(&rdata, &soa, NULL);
   8193   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   8194   1.1  christos 
   8195   1.1  christos 		qctx->client->expire = soa.expire;
   8196   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
   8197   1.1  christos 	}
   8198   1.1  christos 
   8199   1.1  christos 	if (raw != NULL) {
   8200   1.1  christos 		dns_zone_detach(&raw);
   8201   1.1  christos 	}
   8202   1.1  christos }
   8203   1.1  christos 
   8204   1.3  christos /*%
   8205   1.3  christos  * Fill the ANSWER section of a positive response.
   8206   1.1  christos  */
   8207   1.1  christos static isc_result_t
   8208   1.3  christos query_addanswer(query_ctx_t *qctx) {
   8209   1.3  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   8210  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8211   1.1  christos 
   8212   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_addanswer");
   8213   1.9  christos 
   8214   1.3  christos 	CALL_HOOK(NS_QUERY_ADDANSWER_BEGIN, qctx);
   8215   1.1  christos 
   8216  1.13  christos 	/*
   8217  1.13  christos 	 * On normal lookups, clear any rdatasets that were added on a
   8218  1.15  christos 	 * lookup due to stale-answer-client-timeout. Do not clear if we
   8219  1.15  christos 	 * are going to refresh the RRset, because the stale contents are
   8220  1.15  christos 	 * prioritized.
   8221  1.13  christos 	 */
   8222  1.13  christos 	if (QUERY_STALEOK(&qctx->client->query) &&
   8223  1.15  christos 	    !QUERY_STALETIMEOUT(&qctx->client->query) && !qctx->refresh_rrset)
   8224  1.13  christos 	{
   8225  1.15  christos 		CCTRACE(ISC_LOG_DEBUG(3), "query_clear_stale");
   8226  1.13  christos 		query_clear_stale(qctx->client);
   8227  1.13  christos 		/*
   8228  1.13  christos 		 * We can clear the attribute to prevent redundant clearing
   8229  1.13  christos 		 * in subsequent lookups.
   8230  1.13  christos 		 */
   8231  1.14  christos 		qctx->client->query.attributes &= ~NS_QUERYATTR_STALEOK;
   8232  1.13  christos 	}
   8233  1.13  christos 
   8234   1.3  christos 	if (qctx->dns64) {
   8235   1.3  christos 		result = query_dns64(qctx);
   8236   1.3  christos 		qctx->noqname = NULL;
   8237   1.3  christos 		dns_rdataset_disassociate(qctx->rdataset);
   8238   1.3  christos 		dns_message_puttemprdataset(qctx->client->message,
   8239   1.3  christos 					    &qctx->rdataset);
   8240   1.3  christos 		if (result == ISC_R_NOMORE) {
   8241   1.3  christos #ifndef dns64_bis_return_excluded_addresses
   8242   1.3  christos 			if (qctx->dns64_exclude) {
   8243   1.9  christos 				if (!qctx->is_zone) {
   8244   1.3  christos 					return (ns_query_done(qctx));
   8245   1.9  christos 				}
   8246   1.3  christos 				/*
   8247   1.3  christos 				 * Add a fake SOA record.
   8248   1.3  christos 				 */
   8249   1.3  christos 				(void)query_addsoa(qctx, 600,
   8250   1.3  christos 						   DNS_SECTION_AUTHORITY);
   8251   1.3  christos 				return (ns_query_done(qctx));
   8252   1.3  christos 			}
   8253   1.9  christos #endif /* ifndef dns64_bis_return_excluded_addresses */
   8254   1.3  christos 			if (qctx->is_zone) {
   8255   1.3  christos 				return (query_nodata(qctx, DNS_R_NXDOMAIN));
   8256   1.3  christos 			} else {
   8257   1.3  christos 				return (query_ncache(qctx, DNS_R_NXDOMAIN));
   8258   1.1  christos 			}
   8259   1.3  christos 		} else if (result != ISC_R_SUCCESS) {
   8260   1.3  christos 			qctx->result = result;
   8261   1.3  christos 			return (ns_query_done(qctx));
   8262   1.3  christos 		}
   8263   1.3  christos 	} else if (qctx->client->query.dns64_aaaaok != NULL) {
   8264   1.3  christos 		query_filter64(qctx);
   8265   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   8266   1.3  christos 	} else {
   8267  1.11  christos 		if (!qctx->is_zone && RECURSIONOK(qctx->client) &&
   8268  1.13  christos 		    !QUERY_STALETIMEOUT(&qctx->client->query))
   8269  1.11  christos 		{
   8270   1.3  christos 			query_prefetch(qctx->client, qctx->fname,
   8271   1.3  christos 				       qctx->rdataset);
   8272   1.1  christos 		}
   8273   1.3  christos 		if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   8274   1.3  christos 			sigrdatasetp = &qctx->sigrdataset;
   8275   1.3  christos 		}
   8276   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   8277   1.9  christos 			       sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER);
   8278   1.1  christos 	}
   8279   1.1  christos 
   8280   1.1  christos 	return (ISC_R_COMPLETE);
   8281   1.3  christos 
   8282   1.9  christos cleanup:
   8283   1.3  christos 	return (result);
   8284   1.1  christos }
   8285   1.1  christos 
   8286   1.1  christos /*%
   8287   1.9  christos  * Build a response for a "normal" query, for a type other than ANY,
   8288   1.1  christos  * for which we have an answer (either positive or negative).
   8289   1.1  christos  */
   8290   1.1  christos static isc_result_t
   8291   1.1  christos query_respond(query_ctx_t *qctx) {
   8292  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8293   1.1  christos 
   8294   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_respond");
   8295   1.9  christos 
   8296   1.1  christos 	/*
   8297   1.1  christos 	 * Check to see if the AAAA RRset has non-excluded addresses
   8298   1.1  christos 	 * in it.  If not look for a A RRset.
   8299   1.1  christos 	 */
   8300   1.1  christos 	INSIST(qctx->client->query.dns64_aaaaok == NULL);
   8301   1.1  christos 
   8302   1.1  christos 	if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude &&
   8303   1.3  christos 	    !ISC_LIST_EMPTY(qctx->view->dns64) &&
   8304   1.1  christos 	    qctx->client->message->rdclass == dns_rdataclass_in &&
   8305   1.1  christos 	    !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset))
   8306   1.1  christos 	{
   8307   1.1  christos 		/*
   8308   1.1  christos 		 * Look to see if there are A records for this name.
   8309   1.1  christos 		 */
   8310   1.1  christos 		qctx->client->query.dns64_ttl = qctx->rdataset->ttl;
   8311   1.1  christos 		SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset);
   8312   1.1  christos 		SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset);
   8313   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   8314   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   8315   1.1  christos 		qctx->type = qctx->qtype = dns_rdatatype_a;
   8316   1.3  christos 		qctx->dns64_exclude = qctx->dns64 = true;
   8317   1.1  christos 
   8318   1.1  christos 		return (query_lookup(qctx));
   8319   1.1  christos 	}
   8320   1.1  christos 
   8321   1.3  christos 	/*
   8322   1.3  christos 	 * XXX: This hook is meant to be at the top of this function,
   8323   1.3  christos 	 * but is postponed until after DNS64 in order to avoid an
   8324   1.3  christos 	 * assertion if the hook causes recursion. (When DNS64 also
   8325   1.3  christos 	 * becomes a plugin, it will be necessary to find some
   8326   1.3  christos 	 * other way to prevent that assertion, since the order in
   8327   1.3  christos 	 * which plugins are configured can't be enforced.)
   8328   1.3  christos 	 */
   8329   1.3  christos 	CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx);
   8330   1.1  christos 
   8331   1.1  christos 	if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) {
   8332   1.1  christos 		qctx->noqname = qctx->rdataset;
   8333   1.1  christos 	} else {
   8334   1.1  christos 		qctx->noqname = NULL;
   8335   1.1  christos 	}
   8336   1.1  christos 
   8337   1.1  christos 	/*
   8338   1.1  christos 	 * Special case NS handling
   8339   1.1  christos 	 */
   8340   1.1  christos 	if (qctx->is_zone && qctx->qtype == dns_rdatatype_ns) {
   8341   1.1  christos 		/*
   8342   1.1  christos 		 * We've already got an NS, no need to add one in
   8343   1.1  christos 		 * the authority section
   8344   1.1  christos 		 */
   8345   1.1  christos 		if (dns_name_equal(qctx->client->query.qname,
   8346  1.16  christos 				   dns_db_origin(qctx->db)))
   8347  1.16  christos 		{
   8348   1.3  christos 			qctx->answer_has_ns = true;
   8349   1.1  christos 		}
   8350   1.1  christos 
   8351   1.1  christos 		/*
   8352   1.6  christos 		 * Always add glue for root priming queries, regardless
   8353   1.6  christos 		 * of "minimal-responses" setting.
   8354   1.1  christos 		 */
   8355   1.1  christos 		if (dns_name_equal(qctx->client->query.qname, dns_rootname)) {
   8356   1.1  christos 			qctx->client->query.attributes &=
   8357   1.1  christos 				~NS_QUERYATTR_NOADDITIONAL;
   8358   1.6  christos 			dns_db_attach(qctx->db, &qctx->client->query.gluedb);
   8359   1.1  christos 		}
   8360   1.1  christos 	}
   8361   1.1  christos 
   8362   1.1  christos 	/*
   8363   1.1  christos 	 * Set expire time
   8364   1.1  christos 	 */
   8365   1.1  christos 	query_getexpire(qctx);
   8366   1.1  christos 
   8367   1.3  christos 	result = query_addanswer(qctx);
   8368   1.3  christos 	if (result != ISC_R_COMPLETE) {
   8369   1.3  christos 		return (result);
   8370   1.1  christos 	}
   8371   1.1  christos 
   8372   1.1  christos 	query_addnoqnameproof(qctx);
   8373   1.1  christos 
   8374   1.1  christos 	/*
   8375  1.13  christos 	 * 'qctx->rdataset' will only be non-NULL here if the ANSWER section of
   8376  1.13  christos 	 * the message to be sent to the client already contains an RRset with
   8377  1.13  christos 	 * the same owner name and the same type as 'qctx->rdataset'.  This
   8378  1.13  christos 	 * should never happen, with one exception: when chasing DNAME records,
   8379  1.13  christos 	 * one of the DNAME records placed in the ANSWER section may turn out
   8380  1.13  christos 	 * to be the final answer to the client's query, but we have no way of
   8381  1.13  christos 	 * knowing that until now.  In such a case, 'qctx->rdataset' will be
   8382  1.13  christos 	 * freed later, so we do not need to free it here.
   8383   1.1  christos 	 */
   8384  1.13  christos 	INSIST(qctx->rdataset == NULL || qctx->qtype == dns_rdatatype_dname);
   8385   1.1  christos 
   8386   1.1  christos 	query_addauth(qctx);
   8387   1.1  christos 
   8388   1.3  christos 	return (ns_query_done(qctx));
   8389   1.3  christos 
   8390   1.9  christos cleanup:
   8391   1.3  christos 	return (result);
   8392   1.1  christos }
   8393   1.1  christos 
   8394   1.1  christos static isc_result_t
   8395   1.1  christos query_dns64(query_ctx_t *qctx) {
   8396   1.1  christos 	ns_client_t *client = qctx->client;
   8397  1.20  christos 	dns_aclenv_t *env = client->manager->aclenv;
   8398   1.1  christos 	dns_name_t *name, *mname;
   8399   1.1  christos 	dns_rdata_t *dns64_rdata;
   8400   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   8401   1.1  christos 	dns_rdatalist_t *dns64_rdatalist;
   8402   1.1  christos 	dns_rdataset_t *dns64_rdataset;
   8403   1.1  christos 	dns_rdataset_t *mrdataset;
   8404   1.1  christos 	isc_buffer_t *buffer;
   8405   1.1  christos 	isc_region_t r;
   8406   1.1  christos 	isc_result_t result;
   8407   1.1  christos 	dns_view_t *view = client->view;
   8408   1.1  christos 	isc_netaddr_t netaddr;
   8409   1.1  christos 	dns_dns64_t *dns64;
   8410   1.1  christos 	unsigned int flags = 0;
   8411   1.1  christos 	const dns_section_t section = DNS_SECTION_ANSWER;
   8412   1.1  christos 
   8413   1.1  christos 	/*%
   8414   1.1  christos 	 * To the current response for 'qctx->client', add the answer RRset
   8415   1.1  christos 	 * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
   8416   1.1  christos 	 * owner name '*namep', to the answer section, unless they are
   8417   1.1  christos 	 * already there.  Also add any pertinent additional data.
   8418   1.1  christos 	 *
   8419   1.1  christos 	 * If 'qctx->dbuf' is not NULL, then 'qctx->fname' is the name
   8420   1.1  christos 	 * whose data is stored 'qctx->dbuf'.  In this case,
   8421   1.1  christos 	 * query_addrrset() guarantees that when it returns the name
   8422   1.1  christos 	 * will either have been kept or released.
   8423   1.1  christos 	 */
   8424   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_dns64");
   8425   1.1  christos 
   8426   1.1  christos 	qctx->qtype = qctx->type = dns_rdatatype_aaaa;
   8427   1.1  christos 
   8428   1.1  christos 	name = qctx->fname;
   8429   1.1  christos 	mname = NULL;
   8430   1.1  christos 	mrdataset = NULL;
   8431   1.1  christos 	buffer = NULL;
   8432   1.1  christos 	dns64_rdata = NULL;
   8433   1.1  christos 	dns64_rdataset = NULL;
   8434   1.1  christos 	dns64_rdatalist = NULL;
   8435   1.9  christos 	result = dns_message_findname(
   8436   1.9  christos 		client->message, section, name, dns_rdatatype_aaaa,
   8437   1.9  christos 		qctx->rdataset->covers, &mname, &mrdataset);
   8438   1.1  christos 	if (result == ISC_R_SUCCESS) {
   8439   1.1  christos 		/*
   8440   1.1  christos 		 * We've already got an RRset of the given name and type.
   8441   1.1  christos 		 * There's nothing else to do;
   8442   1.1  christos 		 */
   8443   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_dns64: dns_message_findname "
   8444   1.9  christos 					 "succeeded: done");
   8445   1.3  christos 		if (qctx->dbuf != NULL) {
   8446   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8447   1.3  christos 		}
   8448   1.1  christos 		return (ISC_R_SUCCESS);
   8449   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   8450   1.1  christos 		/*
   8451   1.1  christos 		 * The name doesn't exist.
   8452   1.1  christos 		 */
   8453   1.3  christos 		if (qctx->dbuf != NULL) {
   8454   1.3  christos 			ns_client_keepname(client, name, qctx->dbuf);
   8455   1.3  christos 		}
   8456   1.1  christos 		dns_message_addname(client->message, name, section);
   8457   1.1  christos 		qctx->fname = NULL;
   8458   1.1  christos 		mname = name;
   8459   1.1  christos 	} else {
   8460   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   8461   1.3  christos 		if (qctx->dbuf != NULL) {
   8462   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8463   1.3  christos 		}
   8464   1.1  christos 	}
   8465   1.1  christos 
   8466   1.1  christos 	if (qctx->rdataset->trust != dns_trust_secure) {
   8467   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   8468   1.1  christos 	}
   8469   1.1  christos 
   8470   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   8471   1.1  christos 
   8472   1.9  christos 	isc_buffer_allocate(client->mctx, &buffer,
   8473   1.9  christos 			    view->dns64cnt * 16 *
   8474   1.9  christos 				    dns_rdataset_count(qctx->rdataset));
   8475   1.9  christos 	result = dns_message_gettemprdataset(client->message, &dns64_rdataset);
   8476   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8477   1.1  christos 		goto cleanup;
   8478   1.9  christos 	}
   8479   1.1  christos 	result = dns_message_gettemprdatalist(client->message,
   8480   1.1  christos 					      &dns64_rdatalist);
   8481   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8482   1.1  christos 		goto cleanup;
   8483   1.9  christos 	}
   8484   1.1  christos 
   8485   1.1  christos 	dns_rdatalist_init(dns64_rdatalist);
   8486   1.1  christos 	dns64_rdatalist->rdclass = dns_rdataclass_in;
   8487   1.1  christos 	dns64_rdatalist->type = dns_rdatatype_aaaa;
   8488   1.9  christos 	if (client->query.dns64_ttl != UINT32_MAX) {
   8489   1.1  christos 		dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl,
   8490   1.1  christos 					       client->query.dns64_ttl);
   8491   1.9  christos 	} else {
   8492   1.1  christos 		dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl, 600);
   8493   1.9  christos 	}
   8494   1.1  christos 
   8495   1.9  christos 	if (RECURSIONOK(client)) {
   8496   1.1  christos 		flags |= DNS_DNS64_RECURSIVE;
   8497   1.9  christos 	}
   8498   1.1  christos 
   8499   1.1  christos 	/*
   8500   1.1  christos 	 * We use the signatures from the A lookup to set DNS_DNS64_DNSSEC
   8501   1.1  christos 	 * as this provides a easy way to see if the answer was signed.
   8502   1.1  christos 	 */
   8503   1.1  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
   8504   1.1  christos 	    dns_rdataset_isassociated(qctx->sigrdataset))
   8505   1.9  christos 	{
   8506   1.1  christos 		flags |= DNS_DNS64_DNSSEC;
   8507   1.9  christos 	}
   8508   1.1  christos 
   8509   1.1  christos 	for (result = dns_rdataset_first(qctx->rdataset);
   8510   1.1  christos 	     result == ISC_R_SUCCESS;
   8511   1.9  christos 	     result = dns_rdataset_next(qctx->rdataset))
   8512   1.9  christos 	{
   8513   1.9  christos 		for (dns64 = ISC_LIST_HEAD(client->view->dns64); dns64 != NULL;
   8514   1.9  christos 		     dns64 = dns_dns64_next(dns64))
   8515   1.9  christos 		{
   8516   1.1  christos 			dns_rdataset_current(qctx->rdataset, &rdata);
   8517   1.1  christos 			isc_buffer_availableregion(buffer, &r);
   8518   1.1  christos 			INSIST(r.length >= 16);
   8519   1.1  christos 			result = dns_dns64_aaaafroma(dns64, &netaddr,
   8520   1.1  christos 						     client->signer, env, flags,
   8521   1.1  christos 						     rdata.data, r.base);
   8522   1.1  christos 			if (result != ISC_R_SUCCESS) {
   8523   1.1  christos 				dns_rdata_reset(&rdata);
   8524   1.1  christos 				continue;
   8525   1.1  christos 			}
   8526   1.1  christos 			isc_buffer_add(buffer, 16);
   8527   1.1  christos 			isc_buffer_remainingregion(buffer, &r);
   8528   1.1  christos 			isc_buffer_forward(buffer, 16);
   8529   1.1  christos 			result = dns_message_gettemprdata(client->message,
   8530   1.1  christos 							  &dns64_rdata);
   8531   1.9  christos 			if (result != ISC_R_SUCCESS) {
   8532   1.1  christos 				goto cleanup;
   8533   1.9  christos 			}
   8534   1.1  christos 			dns_rdata_init(dns64_rdata);
   8535   1.1  christos 			dns_rdata_fromregion(dns64_rdata, dns_rdataclass_in,
   8536   1.1  christos 					     dns_rdatatype_aaaa, &r);
   8537   1.1  christos 			ISC_LIST_APPEND(dns64_rdatalist->rdata, dns64_rdata,
   8538   1.1  christos 					link);
   8539   1.1  christos 			dns64_rdata = NULL;
   8540   1.1  christos 			dns_rdata_reset(&rdata);
   8541   1.1  christos 		}
   8542   1.1  christos 	}
   8543   1.9  christos 	if (result != ISC_R_NOMORE) {
   8544   1.1  christos 		goto cleanup;
   8545   1.9  christos 	}
   8546   1.1  christos 
   8547   1.9  christos 	if (ISC_LIST_EMPTY(dns64_rdatalist->rdata)) {
   8548   1.1  christos 		goto cleanup;
   8549   1.9  christos 	}
   8550   1.1  christos 
   8551   1.1  christos 	result = dns_rdatalist_tordataset(dns64_rdatalist, dns64_rdataset);
   8552   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8553   1.1  christos 		goto cleanup;
   8554   1.9  christos 	}
   8555   1.1  christos 	dns_rdataset_setownercase(dns64_rdataset, mname);
   8556   1.1  christos 	client->query.attributes |= NS_QUERYATTR_NOADDITIONAL;
   8557   1.1  christos 	dns64_rdataset->trust = qctx->rdataset->trust;
   8558   1.3  christos 
   8559   1.3  christos 	query_addtoname(mname, dns64_rdataset);
   8560   1.3  christos 	query_setorder(qctx, mname, dns64_rdataset);
   8561   1.3  christos 
   8562   1.1  christos 	dns64_rdataset = NULL;
   8563   1.1  christos 	dns64_rdatalist = NULL;
   8564   1.1  christos 	dns_message_takebuffer(client->message, &buffer);
   8565   1.1  christos 	inc_stats(client, ns_statscounter_dns64);
   8566   1.1  christos 	result = ISC_R_SUCCESS;
   8567   1.1  christos 
   8568   1.9  christos cleanup:
   8569   1.9  christos 	if (buffer != NULL) {
   8570   1.1  christos 		isc_buffer_free(&buffer);
   8571   1.9  christos 	}
   8572   1.1  christos 
   8573   1.9  christos 	if (dns64_rdata != NULL) {
   8574   1.1  christos 		dns_message_puttemprdata(client->message, &dns64_rdata);
   8575   1.9  christos 	}
   8576   1.1  christos 
   8577   1.9  christos 	if (dns64_rdataset != NULL) {
   8578   1.1  christos 		dns_message_puttemprdataset(client->message, &dns64_rdataset);
   8579   1.9  christos 	}
   8580   1.1  christos 
   8581   1.1  christos 	if (dns64_rdatalist != NULL) {
   8582   1.1  christos 		for (dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata);
   8583   1.1  christos 		     dns64_rdata != NULL;
   8584   1.1  christos 		     dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata))
   8585   1.1  christos 		{
   8586   1.9  christos 			ISC_LIST_UNLINK(dns64_rdatalist->rdata, dns64_rdata,
   8587   1.9  christos 					link);
   8588   1.1  christos 			dns_message_puttemprdata(client->message, &dns64_rdata);
   8589   1.1  christos 		}
   8590   1.1  christos 		dns_message_puttemprdatalist(client->message, &dns64_rdatalist);
   8591   1.1  christos 	}
   8592   1.1  christos 
   8593   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_dns64: done");
   8594   1.1  christos 	return (result);
   8595   1.1  christos }
   8596   1.1  christos 
   8597   1.1  christos static void
   8598   1.1  christos query_filter64(query_ctx_t *qctx) {
   8599   1.1  christos 	ns_client_t *client = qctx->client;
   8600   1.1  christos 	dns_name_t *name, *mname;
   8601   1.1  christos 	dns_rdata_t *myrdata;
   8602   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   8603   1.1  christos 	dns_rdatalist_t *myrdatalist;
   8604   1.1  christos 	dns_rdataset_t *myrdataset;
   8605   1.1  christos 	isc_buffer_t *buffer;
   8606   1.1  christos 	isc_region_t r;
   8607   1.1  christos 	isc_result_t result;
   8608   1.1  christos 	unsigned int i;
   8609   1.1  christos 	const dns_section_t section = DNS_SECTION_ANSWER;
   8610   1.1  christos 
   8611   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_filter64");
   8612   1.1  christos 
   8613   1.1  christos 	INSIST(client->query.dns64_aaaaok != NULL);
   8614   1.1  christos 	INSIST(client->query.dns64_aaaaoklen ==
   8615   1.1  christos 	       dns_rdataset_count(qctx->rdataset));
   8616   1.1  christos 
   8617   1.1  christos 	name = qctx->fname;
   8618   1.1  christos 	mname = NULL;
   8619   1.1  christos 	buffer = NULL;
   8620   1.1  christos 	myrdata = NULL;
   8621   1.1  christos 	myrdataset = NULL;
   8622   1.1  christos 	myrdatalist = NULL;
   8623   1.9  christos 	result = dns_message_findname(
   8624   1.9  christos 		client->message, section, name, dns_rdatatype_aaaa,
   8625   1.9  christos 		qctx->rdataset->covers, &mname, &myrdataset);
   8626   1.1  christos 	if (result == ISC_R_SUCCESS) {
   8627   1.1  christos 		/*
   8628   1.1  christos 		 * We've already got an RRset of the given name and type.
   8629   1.1  christos 		 * There's nothing else to do;
   8630   1.1  christos 		 */
   8631   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_filter64: dns_message_findname "
   8632   1.9  christos 					 "succeeded: done");
   8633   1.3  christos 		if (qctx->dbuf != NULL) {
   8634   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8635   1.3  christos 		}
   8636   1.1  christos 		return;
   8637   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   8638   1.1  christos 		mname = name;
   8639   1.1  christos 		qctx->fname = NULL;
   8640   1.1  christos 	} else {
   8641   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   8642   1.3  christos 		if (qctx->dbuf != NULL) {
   8643   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8644   1.3  christos 		}
   8645   1.1  christos 		qctx->dbuf = NULL;
   8646   1.1  christos 	}
   8647   1.1  christos 
   8648   1.1  christos 	if (qctx->rdataset->trust != dns_trust_secure) {
   8649   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   8650   1.1  christos 	}
   8651   1.1  christos 
   8652   1.9  christos 	isc_buffer_allocate(client->mctx, &buffer,
   8653   1.9  christos 			    16 * dns_rdataset_count(qctx->rdataset));
   8654   1.1  christos 	result = dns_message_gettemprdataset(client->message, &myrdataset);
   8655   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8656   1.1  christos 		goto cleanup;
   8657   1.9  christos 	}
   8658   1.1  christos 	result = dns_message_gettemprdatalist(client->message, &myrdatalist);
   8659   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8660   1.1  christos 		goto cleanup;
   8661   1.9  christos 	}
   8662   1.1  christos 
   8663   1.1  christos 	dns_rdatalist_init(myrdatalist);
   8664   1.1  christos 	myrdatalist->rdclass = dns_rdataclass_in;
   8665   1.1  christos 	myrdatalist->type = dns_rdatatype_aaaa;
   8666   1.1  christos 	myrdatalist->ttl = qctx->rdataset->ttl;
   8667   1.1  christos 
   8668   1.1  christos 	i = 0;
   8669   1.1  christos 	for (result = dns_rdataset_first(qctx->rdataset);
   8670   1.1  christos 	     result == ISC_R_SUCCESS;
   8671   1.3  christos 	     result = dns_rdataset_next(qctx->rdataset))
   8672   1.3  christos 	{
   8673   1.9  christos 		if (!client->query.dns64_aaaaok[i++]) {
   8674   1.1  christos 			continue;
   8675   1.9  christos 		}
   8676   1.1  christos 		dns_rdataset_current(qctx->rdataset, &rdata);
   8677   1.1  christos 		INSIST(rdata.length == 16);
   8678   1.1  christos 		isc_buffer_putmem(buffer, rdata.data, rdata.length);
   8679   1.1  christos 		isc_buffer_remainingregion(buffer, &r);
   8680   1.1  christos 		isc_buffer_forward(buffer, rdata.length);
   8681   1.1  christos 		result = dns_message_gettemprdata(client->message, &myrdata);
   8682   1.9  christos 		if (result != ISC_R_SUCCESS) {
   8683   1.1  christos 			goto cleanup;
   8684   1.9  christos 		}
   8685   1.1  christos 		dns_rdata_init(myrdata);
   8686   1.1  christos 		dns_rdata_fromregion(myrdata, dns_rdataclass_in,
   8687   1.1  christos 				     dns_rdatatype_aaaa, &r);
   8688   1.1  christos 		ISC_LIST_APPEND(myrdatalist->rdata, myrdata, link);
   8689   1.1  christos 		myrdata = NULL;
   8690   1.1  christos 		dns_rdata_reset(&rdata);
   8691   1.1  christos 	}
   8692   1.9  christos 	if (result != ISC_R_NOMORE) {
   8693   1.1  christos 		goto cleanup;
   8694   1.9  christos 	}
   8695   1.1  christos 
   8696   1.1  christos 	result = dns_rdatalist_tordataset(myrdatalist, myrdataset);
   8697   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8698   1.1  christos 		goto cleanup;
   8699   1.9  christos 	}
   8700   1.1  christos 	dns_rdataset_setownercase(myrdataset, name);
   8701   1.1  christos 	client->query.attributes |= NS_QUERYATTR_NOADDITIONAL;
   8702   1.1  christos 	if (mname == name) {
   8703   1.3  christos 		if (qctx->dbuf != NULL) {
   8704   1.3  christos 			ns_client_keepname(client, name, qctx->dbuf);
   8705   1.3  christos 		}
   8706   1.9  christos 		dns_message_addname(client->message, name, section);
   8707   1.1  christos 		qctx->dbuf = NULL;
   8708   1.1  christos 	}
   8709   1.1  christos 	myrdataset->trust = qctx->rdataset->trust;
   8710   1.3  christos 
   8711   1.3  christos 	query_addtoname(mname, myrdataset);
   8712   1.3  christos 	query_setorder(qctx, mname, myrdataset);
   8713   1.3  christos 
   8714   1.1  christos 	myrdataset = NULL;
   8715   1.1  christos 	myrdatalist = NULL;
   8716   1.1  christos 	dns_message_takebuffer(client->message, &buffer);
   8717   1.1  christos 
   8718   1.9  christos cleanup:
   8719   1.9  christos 	if (buffer != NULL) {
   8720   1.1  christos 		isc_buffer_free(&buffer);
   8721   1.9  christos 	}
   8722   1.1  christos 
   8723   1.9  christos 	if (myrdata != NULL) {
   8724   1.1  christos 		dns_message_puttemprdata(client->message, &myrdata);
   8725   1.9  christos 	}
   8726   1.1  christos 
   8727   1.9  christos 	if (myrdataset != NULL) {
   8728   1.1  christos 		dns_message_puttemprdataset(client->message, &myrdataset);
   8729   1.9  christos 	}
   8730   1.1  christos 
   8731   1.1  christos 	if (myrdatalist != NULL) {
   8732   1.1  christos 		for (myrdata = ISC_LIST_HEAD(myrdatalist->rdata);
   8733   1.1  christos 		     myrdata != NULL;
   8734   1.1  christos 		     myrdata = ISC_LIST_HEAD(myrdatalist->rdata))
   8735   1.1  christos 		{
   8736   1.1  christos 			ISC_LIST_UNLINK(myrdatalist->rdata, myrdata, link);
   8737   1.1  christos 			dns_message_puttemprdata(client->message, &myrdata);
   8738   1.1  christos 		}
   8739   1.1  christos 		dns_message_puttemprdatalist(client->message, &myrdatalist);
   8740   1.1  christos 	}
   8741   1.3  christos 	if (qctx->dbuf != NULL) {
   8742   1.3  christos 		ns_client_releasename(client, &name);
   8743   1.3  christos 	}
   8744   1.1  christos 
   8745   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done");
   8746   1.1  christos }
   8747   1.1  christos 
   8748   1.1  christos /*%
   8749   1.1  christos  * Handle the case of a name not being found in a database lookup.
   8750   1.1  christos  * Called from query_gotanswer(). Passes off processing to
   8751   1.1  christos  * query_delegation() for a root referral if appropriate.
   8752   1.1  christos  */
   8753   1.1  christos static isc_result_t
   8754   1.1  christos query_notfound(query_ctx_t *qctx) {
   8755  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8756   1.1  christos 
   8757   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_notfound");
   8758   1.9  christos 
   8759   1.3  christos 	CALL_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx);
   8760   1.3  christos 
   8761   1.1  christos 	INSIST(!qctx->is_zone);
   8762   1.1  christos 
   8763   1.9  christos 	if (qctx->db != NULL) {
   8764   1.1  christos 		dns_db_detach(&qctx->db);
   8765   1.9  christos 	}
   8766   1.1  christos 
   8767   1.1  christos 	/*
   8768   1.1  christos 	 * If the cache doesn't even have the root NS,
   8769   1.1  christos 	 * try to get that from the hints DB.
   8770   1.1  christos 	 */
   8771   1.3  christos 	if (qctx->view->hints != NULL) {
   8772   1.1  christos 		dns_clientinfomethods_t cm;
   8773   1.1  christos 		dns_clientinfo_t ci;
   8774   1.1  christos 
   8775   1.1  christos 		dns_clientinfomethods_init(&cm, ns_client_sourceip);
   8776  1.20  christos 		dns_clientinfo_init(&ci, qctx->client, NULL);
   8777   1.1  christos 
   8778   1.3  christos 		dns_db_attach(qctx->view->hints, &qctx->db);
   8779   1.9  christos 		result = dns_db_findext(qctx->db, dns_rootname, NULL,
   8780   1.9  christos 					dns_rdatatype_ns, 0, qctx->client->now,
   8781   1.9  christos 					&qctx->node, qctx->fname, &cm, &ci,
   8782   1.1  christos 					qctx->rdataset, qctx->sigrdataset);
   8783   1.1  christos 	} else {
   8784   1.1  christos 		/* We have no hints. */
   8785   1.1  christos 		result = ISC_R_FAILURE;
   8786   1.1  christos 	}
   8787   1.1  christos 	if (result != ISC_R_SUCCESS) {
   8788   1.1  christos 		/*
   8789   1.1  christos 		 * Nonsensical root hints may require cleanup.
   8790   1.1  christos 		 */
   8791   1.1  christos 		qctx_clean(qctx);
   8792   1.1  christos 
   8793   1.1  christos 		/*
   8794   1.1  christos 		 * We don't have any root server hints, but
   8795   1.1  christos 		 * we may have working forwarders, so try to
   8796   1.1  christos 		 * recurse anyway.
   8797   1.1  christos 		 */
   8798   1.1  christos 		if (RECURSIONOK(qctx->client)) {
   8799   1.1  christos 			INSIST(!REDIRECT(qctx->client));
   8800   1.3  christos 			result = ns_query_recurse(qctx->client, qctx->qtype,
   8801   1.3  christos 						  qctx->client->query.qname,
   8802   1.3  christos 						  NULL, NULL, qctx->resuming);
   8803   1.1  christos 			if (result == ISC_R_SUCCESS) {
   8804   1.3  christos 				CALL_HOOK(NS_QUERY_NOTFOUND_RECURSE, qctx);
   8805   1.1  christos 				qctx->client->query.attributes |=
   8806   1.9  christos 					NS_QUERYATTR_RECURSING;
   8807   1.3  christos 
   8808   1.3  christos 				if (qctx->dns64) {
   8809   1.1  christos 					qctx->client->query.attributes |=
   8810   1.1  christos 						NS_QUERYATTR_DNS64;
   8811   1.3  christos 				}
   8812   1.3  christos 				if (qctx->dns64_exclude) {
   8813   1.1  christos 					qctx->client->query.attributes |=
   8814   1.1  christos 						NS_QUERYATTR_DNS64EXCLUDE;
   8815   1.3  christos 				}
   8816  1.13  christos 			} else if (query_usestale(qctx, result)) {
   8817  1.13  christos 				/*
   8818  1.13  christos 				 * If serve-stale is enabled, query_usestale()
   8819  1.13  christos 				 * already set up 'qctx' for looking up a
   8820  1.13  christos 				 * stale response.
   8821  1.13  christos 				 */
   8822  1.13  christos 				return (query_lookup(qctx));
   8823   1.3  christos 			} else {
   8824   1.3  christos 				QUERY_ERROR(qctx, result);
   8825   1.3  christos 			}
   8826   1.3  christos 			return (ns_query_done(qctx));
   8827   1.1  christos 		} else {
   8828   1.1  christos 			/* Unable to give root server referral. */
   8829   1.9  christos 			CCTRACE(ISC_LOG_ERROR, "unable to give root server "
   8830   1.9  christos 					       "referral");
   8831   1.3  christos 			QUERY_ERROR(qctx, result);
   8832   1.3  christos 			return (ns_query_done(qctx));
   8833   1.1  christos 		}
   8834   1.1  christos 	}
   8835   1.1  christos 
   8836   1.1  christos 	return (query_delegation(qctx));
   8837   1.3  christos 
   8838   1.9  christos cleanup:
   8839   1.3  christos 	return (result);
   8840   1.3  christos }
   8841   1.3  christos 
   8842   1.3  christos /*%
   8843   1.3  christos  * We have a delegation but recursion is not allowed, so return the delegation
   8844   1.3  christos  * to the client.
   8845   1.3  christos  */
   8846   1.3  christos static isc_result_t
   8847   1.3  christos query_prepare_delegation_response(query_ctx_t *qctx) {
   8848  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8849   1.3  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   8850   1.3  christos 	bool detach = false;
   8851   1.3  christos 
   8852   1.3  christos 	CALL_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx);
   8853   1.3  christos 
   8854   1.3  christos 	/*
   8855   1.3  christos 	 * qctx->fname could be released in query_addrrset(), so save a copy of
   8856   1.3  christos 	 * it here in case we need it.
   8857   1.3  christos 	 */
   8858   1.3  christos 	dns_fixedname_init(&qctx->dsname);
   8859  1.20  christos 	dns_name_copy(qctx->fname, dns_fixedname_name(&qctx->dsname));
   8860   1.3  christos 
   8861   1.3  christos 	/*
   8862   1.3  christos 	 * This is the best answer.
   8863   1.3  christos 	 */
   8864   1.3  christos 	qctx->client->query.isreferral = true;
   8865   1.3  christos 
   8866   1.3  christos 	if (!dns_db_iscache(qctx->db) && qctx->client->query.gluedb == NULL) {
   8867   1.3  christos 		dns_db_attach(qctx->db, &qctx->client->query.gluedb);
   8868   1.3  christos 		detach = true;
   8869   1.3  christos 	}
   8870   1.3  christos 
   8871   1.3  christos 	/*
   8872   1.3  christos 	 * We must ensure NOADDITIONAL is off, because the generation of
   8873   1.3  christos 	 * additional data is required in delegations.
   8874   1.3  christos 	 */
   8875   1.3  christos 	qctx->client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL;
   8876   1.3  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   8877   1.3  christos 		sigrdatasetp = &qctx->sigrdataset;
   8878   1.3  christos 	}
   8879   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   8880   1.9  christos 		       qctx->dbuf, DNS_SECTION_AUTHORITY);
   8881   1.3  christos 	if (detach) {
   8882   1.3  christos 		dns_db_detach(&qctx->client->query.gluedb);
   8883   1.3  christos 	}
   8884   1.3  christos 
   8885   1.3  christos 	/*
   8886  1.14  christos 	 * Add DS/NSEC(3) record(s) if needed.
   8887   1.3  christos 	 */
   8888   1.3  christos 	query_addds(qctx);
   8889   1.3  christos 
   8890   1.3  christos 	return (ns_query_done(qctx));
   8891   1.3  christos 
   8892   1.9  christos cleanup:
   8893   1.3  christos 	return (result);
   8894   1.1  christos }
   8895   1.1  christos 
   8896   1.1  christos /*%
   8897   1.1  christos  * Handle a delegation response from an authoritative lookup. This
   8898   1.1  christos  * may trigger additional lookups, e.g. from the cache database to
   8899   1.1  christos  * see if we have a better answer; if that is not allowed, return the
   8900   1.3  christos  * delegation to the client and call ns_query_done().
   8901   1.1  christos  */
   8902   1.1  christos static isc_result_t
   8903   1.1  christos query_zone_delegation(query_ctx_t *qctx) {
   8904  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   8905   1.3  christos 
   8906   1.3  christos 	CALL_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx);
   8907   1.1  christos 
   8908   1.1  christos 	/*
   8909   1.1  christos 	 * If the query type is DS, look to see if we are
   8910   1.1  christos 	 * authoritative for the child zone
   8911   1.1  christos 	 */
   8912   1.1  christos 	if (!RECURSIONOK(qctx->client) &&
   8913   1.1  christos 	    (qctx->options & DNS_GETDB_NOEXACT) != 0 &&
   8914   1.1  christos 	    qctx->qtype == dns_rdatatype_ds)
   8915   1.1  christos 	{
   8916   1.1  christos 		dns_db_t *tdb = NULL;
   8917   1.1  christos 		dns_zone_t *tzone = NULL;
   8918   1.1  christos 		dns_dbversion_t *tversion = NULL;
   8919   1.9  christos 		result = query_getzonedb(
   8920   1.9  christos 			qctx->client, qctx->client->query.qname, qctx->qtype,
   8921   1.9  christos 			DNS_GETDB_PARTIAL, &tzone, &tdb, &tversion);
   8922   1.1  christos 		if (result != ISC_R_SUCCESS) {
   8923   1.9  christos 			if (tdb != NULL) {
   8924   1.1  christos 				dns_db_detach(&tdb);
   8925   1.9  christos 			}
   8926   1.9  christos 			if (tzone != NULL) {
   8927   1.1  christos 				dns_zone_detach(&tzone);
   8928   1.9  christos 			}
   8929   1.1  christos 		} else {
   8930   1.1  christos 			qctx->options &= ~DNS_GETDB_NOEXACT;
   8931   1.9  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   8932   1.3  christos 			if (qctx->sigrdataset != NULL) {
   8933   1.3  christos 				ns_client_putrdataset(qctx->client,
   8934   1.3  christos 						      &qctx->sigrdataset);
   8935   1.3  christos 			}
   8936   1.3  christos 			if (qctx->fname != NULL) {
   8937   1.3  christos 				ns_client_releasename(qctx->client,
   8938   1.3  christos 						      &qctx->fname);
   8939   1.3  christos 			}
   8940   1.9  christos 			if (qctx->node != NULL) {
   8941   1.9  christos 				dns_db_detachnode(qctx->db, &qctx->node);
   8942   1.9  christos 			}
   8943   1.9  christos 			if (qctx->db != NULL) {
   8944   1.1  christos 				dns_db_detach(&qctx->db);
   8945   1.9  christos 			}
   8946   1.9  christos 			if (qctx->zone != NULL) {
   8947   1.1  christos 				dns_zone_detach(&qctx->zone);
   8948   1.9  christos 			}
   8949   1.1  christos 			qctx->version = NULL;
   8950   1.1  christos 			RESTORE(qctx->version, tversion);
   8951   1.1  christos 			RESTORE(qctx->db, tdb);
   8952   1.1  christos 			RESTORE(qctx->zone, tzone);
   8953   1.3  christos 			qctx->authoritative = true;
   8954   1.1  christos 
   8955   1.1  christos 			return (query_lookup(qctx));
   8956   1.1  christos 		}
   8957   1.1  christos 	}
   8958   1.1  christos 
   8959   1.3  christos 	if (USECACHE(qctx->client) &&
   8960   1.3  christos 	    (RECURSIONOK(qctx->client) ||
   8961   1.3  christos 	     (qctx->zone != NULL &&
   8962   1.3  christos 	      dns_zone_gettype(qctx->zone) == dns_zone_mirror)))
   8963   1.3  christos 	{
   8964   1.1  christos 		/*
   8965   1.1  christos 		 * We might have a better answer or delegation in the
   8966   1.1  christos 		 * cache.  We'll remember the current values of fname,
   8967   1.1  christos 		 * rdataset, and sigrdataset.  We'll then go looking for
   8968   1.1  christos 		 * QNAME in the cache.  If we find something better, we'll
   8969   1.1  christos 		 * use it instead. If not, then query_lookup() calls
   8970   1.1  christos 		 * query_notfound() which calls query_delegation(), and
   8971   1.1  christos 		 * we'll restore these values there.
   8972   1.1  christos 		 */
   8973   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   8974   1.1  christos 		SAVE(qctx->zdb, qctx->db);
   8975   1.3  christos 		SAVE(qctx->znode, qctx->node);
   8976   1.1  christos 		SAVE(qctx->zfname, qctx->fname);
   8977   1.1  christos 		SAVE(qctx->zversion, qctx->version);
   8978   1.1  christos 		SAVE(qctx->zrdataset, qctx->rdataset);
   8979   1.1  christos 		SAVE(qctx->zsigrdataset, qctx->sigrdataset);
   8980   1.3  christos 		dns_db_attach(qctx->view->cachedb, &qctx->db);
   8981   1.3  christos 		qctx->is_zone = false;
   8982   1.1  christos 
   8983   1.1  christos 		return (query_lookup(qctx));
   8984   1.1  christos 	}
   8985   1.1  christos 
   8986   1.3  christos 	return (query_prepare_delegation_response(qctx));
   8987   1.1  christos 
   8988   1.9  christos cleanup:
   8989   1.3  christos 	return (result);
   8990   1.1  christos }
   8991   1.1  christos 
   8992   1.1  christos /*%
   8993   1.1  christos  * Handle delegation responses, including root referrals.
   8994   1.1  christos  *
   8995   1.1  christos  * If the delegation was returned from authoritative data,
   8996   1.1  christos  * call query_zone_delgation().  Otherwise, we can start
   8997   1.1  christos  * recursion if allowed; or else return the delegation to the
   8998   1.3  christos  * client and call ns_query_done().
   8999   1.1  christos  */
   9000   1.1  christos static isc_result_t
   9001   1.1  christos query_delegation(query_ctx_t *qctx) {
   9002  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   9003   1.1  christos 
   9004   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_delegation");
   9005   1.9  christos 
   9006   1.3  christos 	CALL_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx);
   9007   1.3  christos 
   9008   1.3  christos 	qctx->authoritative = false;
   9009   1.1  christos 
   9010   1.1  christos 	if (qctx->is_zone) {
   9011   1.1  christos 		return (query_zone_delegation(qctx));
   9012   1.1  christos 	}
   9013   1.1  christos 
   9014   1.1  christos 	if (qctx->zfname != NULL &&
   9015   1.1  christos 	    (!dns_name_issubdomain(qctx->fname, qctx->zfname) ||
   9016   1.1  christos 	     (qctx->is_staticstub_zone &&
   9017   1.1  christos 	      dns_name_equal(qctx->fname, qctx->zfname))))
   9018   1.1  christos 	{
   9019   1.1  christos 		/*
   9020   1.1  christos 		 * In the following cases use "authoritative"
   9021   1.1  christos 		 * data instead of the cache delegation:
   9022   1.1  christos 		 * 1. We've already got a delegation from
   9023   1.1  christos 		 *    authoritative data, and it is better
   9024   1.1  christos 		 *    than what we found in the cache.
   9025   1.1  christos 		 *    (See the comment above.)
   9026   1.1  christos 		 * 2. The query name matches the origin name
   9027   1.1  christos 		 *    of a static-stub zone.  This needs to be
   9028   1.1  christos 		 *    considered for the case where the NS of
   9029   1.1  christos 		 *    the static-stub zone and the cached NS
   9030   1.1  christos 		 *    are different.  We still need to contact
   9031   1.1  christos 		 *    the nameservers configured in the
   9032   1.1  christos 		 *    static-stub zone.
   9033   1.1  christos 		 */
   9034   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9035   1.1  christos 
   9036   1.1  christos 		/*
   9037   1.3  christos 		 * We've already done ns_client_keepname() on
   9038   1.1  christos 		 * qctx->zfname, so we must set dbuf to NULL to
   9039   1.1  christos 		 * prevent query_addrrset() from trying to
   9040   1.3  christos 		 * call ns_client_keepname() again.
   9041   1.1  christos 		 */
   9042   1.1  christos 		qctx->dbuf = NULL;
   9043   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   9044   1.3  christos 		if (qctx->sigrdataset != NULL) {
   9045   1.9  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   9046   1.3  christos 		}
   9047   1.1  christos 		qctx->version = NULL;
   9048   1.1  christos 
   9049   1.3  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   9050   1.3  christos 		dns_db_detach(&qctx->db);
   9051   1.3  christos 		RESTORE(qctx->db, qctx->zdb);
   9052   1.3  christos 		RESTORE(qctx->node, qctx->znode);
   9053   1.1  christos 		RESTORE(qctx->fname, qctx->zfname);
   9054   1.1  christos 		RESTORE(qctx->version, qctx->zversion);
   9055   1.1  christos 		RESTORE(qctx->rdataset, qctx->zrdataset);
   9056   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->zsigrdataset);
   9057   1.3  christos 	}
   9058   1.1  christos 
   9059   1.3  christos 	result = query_delegation_recurse(qctx);
   9060   1.3  christos 	if (result != ISC_R_COMPLETE) {
   9061   1.3  christos 		return (result);
   9062   1.1  christos 	}
   9063   1.1  christos 
   9064   1.3  christos 	return (query_prepare_delegation_response(qctx));
   9065   1.1  christos 
   9066   1.9  christos cleanup:
   9067   1.3  christos 	return (result);
   9068   1.3  christos }
   9069   1.1  christos 
   9070   1.3  christos /*%
   9071   1.3  christos  * Handle recursive queries that are triggered as part of the
   9072   1.3  christos  * delegation process.
   9073   1.3  christos  */
   9074   1.3  christos static isc_result_t
   9075   1.3  christos query_delegation_recurse(query_ctx_t *qctx) {
   9076  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   9077   1.3  christos 	dns_name_t *qname = qctx->client->query.qname;
   9078   1.1  christos 
   9079   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_delegation_recurse");
   9080   1.9  christos 
   9081   1.3  christos 	if (!RECURSIONOK(qctx->client)) {
   9082   1.3  christos 		return (ISC_R_COMPLETE);
   9083   1.1  christos 	}
   9084   1.1  christos 
   9085   1.3  christos 	CALL_HOOK(NS_QUERY_DELEGATION_RECURSE_BEGIN, qctx);
   9086   1.3  christos 
   9087   1.1  christos 	/*
   9088   1.3  christos 	 * We have a delegation and recursion is allowed,
   9089   1.3  christos 	 * so we call ns_query_recurse() to follow it.
   9090   1.3  christos 	 * This phase of the query processing is done;
   9091   1.3  christos 	 * we'll resume via fetch_callback() and
   9092   1.3  christos 	 * query_resume() when the recursion is complete.
   9093   1.1  christos 	 */
   9094   1.1  christos 
   9095   1.3  christos 	INSIST(!REDIRECT(qctx->client));
   9096   1.1  christos 
   9097   1.3  christos 	if (dns_rdatatype_atparent(qctx->type)) {
   9098   1.3  christos 		/*
   9099   1.3  christos 		 * Parent is authoritative for this RDATA type (i.e. DS).
   9100   1.3  christos 		 */
   9101   1.3  christos 		result = ns_query_recurse(qctx->client, qctx->qtype, qname,
   9102   1.3  christos 					  NULL, NULL, qctx->resuming);
   9103   1.3  christos 	} else if (qctx->dns64) {
   9104   1.3  christos 		/*
   9105   1.3  christos 		 * Look up an A record so we can synthesize DNS64.
   9106   1.3  christos 		 */
   9107   1.3  christos 		result = ns_query_recurse(qctx->client, dns_rdatatype_a, qname,
   9108   1.3  christos 					  NULL, NULL, qctx->resuming);
   9109   1.3  christos 	} else {
   9110   1.3  christos 		/*
   9111   1.3  christos 		 * Any other recursion.
   9112   1.3  christos 		 */
   9113   1.3  christos 		result = ns_query_recurse(qctx->client, qctx->qtype, qname,
   9114   1.3  christos 					  qctx->fname, qctx->rdataset,
   9115   1.3  christos 					  qctx->resuming);
   9116   1.1  christos 	}
   9117   1.1  christos 
   9118   1.3  christos 	if (result == ISC_R_SUCCESS) {
   9119   1.3  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   9120   1.3  christos 		if (qctx->dns64) {
   9121   1.3  christos 			qctx->client->query.attributes |= NS_QUERYATTR_DNS64;
   9122   1.3  christos 		}
   9123   1.3  christos 		if (qctx->dns64_exclude) {
   9124   1.3  christos 			qctx->client->query.attributes |=
   9125   1.9  christos 				NS_QUERYATTR_DNS64EXCLUDE;
   9126   1.3  christos 		}
   9127  1.13  christos 	} else if (query_usestale(qctx, result)) {
   9128  1.13  christos 		/*
   9129  1.13  christos 		 * If serve-stale is enabled, query_usestale() already set up
   9130  1.13  christos 		 * 'qctx' for looking up a stale response.
   9131  1.13  christos 		 */
   9132  1.13  christos 		return (query_lookup(qctx));
   9133   1.3  christos 	} else {
   9134   1.3  christos 		QUERY_ERROR(qctx, result);
   9135   1.1  christos 	}
   9136   1.1  christos 
   9137   1.3  christos 	return (ns_query_done(qctx));
   9138   1.1  christos 
   9139   1.9  christos cleanup:
   9140   1.3  christos 	return (result);
   9141   1.1  christos }
   9142   1.1  christos 
   9143   1.1  christos /*%
   9144  1.14  christos  * Add DS/NSEC(3) record(s) if needed.
   9145   1.1  christos  */
   9146   1.1  christos static void
   9147   1.1  christos query_addds(query_ctx_t *qctx) {
   9148   1.1  christos 	ns_client_t *client = qctx->client;
   9149   1.1  christos 	dns_fixedname_t fixed;
   9150   1.1  christos 	dns_name_t *fname = NULL;
   9151   1.1  christos 	dns_name_t *rname = NULL;
   9152   1.1  christos 	dns_name_t *name;
   9153   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   9154   1.1  christos 	isc_buffer_t *dbuf, b;
   9155   1.1  christos 	isc_result_t result;
   9156   1.1  christos 	unsigned int count;
   9157   1.1  christos 
   9158   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addds");
   9159   1.1  christos 
   9160   1.1  christos 	/*
   9161   1.1  christos 	 * DS not needed.
   9162   1.1  christos 	 */
   9163   1.1  christos 	if (!WANTDNSSEC(client)) {
   9164   1.1  christos 		return;
   9165   1.1  christos 	}
   9166   1.1  christos 
   9167   1.1  christos 	/*
   9168   1.1  christos 	 * We'll need some resources...
   9169   1.1  christos 	 */
   9170   1.3  christos 	rdataset = ns_client_newrdataset(client);
   9171   1.3  christos 	sigrdataset = ns_client_newrdataset(client);
   9172   1.9  christos 	if (rdataset == NULL || sigrdataset == NULL) {
   9173   1.1  christos 		goto cleanup;
   9174   1.9  christos 	}
   9175   1.1  christos 
   9176   1.1  christos 	/*
   9177   1.1  christos 	 * Look for the DS record, which may or may not be present.
   9178   1.1  christos 	 */
   9179   1.1  christos 	result = dns_db_findrdataset(qctx->db, qctx->node, qctx->version,
   9180   1.9  christos 				     dns_rdatatype_ds, 0, client->now, rdataset,
   9181   1.9  christos 				     sigrdataset);
   9182   1.1  christos 	/*
   9183   1.1  christos 	 * If we didn't find it, look for an NSEC.
   9184   1.1  christos 	 */
   9185   1.9  christos 	if (result == ISC_R_NOTFOUND) {
   9186   1.9  christos 		result = dns_db_findrdataset(
   9187   1.9  christos 			qctx->db, qctx->node, qctx->version, dns_rdatatype_nsec,
   9188   1.9  christos 			0, client->now, rdataset, sigrdataset);
   9189   1.9  christos 	}
   9190   1.9  christos 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
   9191   1.1  christos 		goto addnsec3;
   9192   1.9  christos 	}
   9193   1.1  christos 	if (!dns_rdataset_isassociated(rdataset) ||
   9194   1.1  christos 	    !dns_rdataset_isassociated(sigrdataset))
   9195   1.9  christos 	{
   9196   1.1  christos 		goto addnsec3;
   9197   1.9  christos 	}
   9198   1.1  christos 
   9199   1.1  christos 	/*
   9200   1.1  christos 	 * We've already added the NS record, so if the name's not there,
   9201  1.14  christos 	 * we have other problems.
   9202   1.1  christos 	 */
   9203   1.1  christos 	result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
   9204   1.9  christos 	if (result != ISC_R_SUCCESS) {
   9205   1.1  christos 		goto cleanup;
   9206   1.9  christos 	}
   9207   1.1  christos 
   9208  1.14  christos 	/*
   9209  1.14  christos 	 * Find the delegation in the response message - it is not necessarily
   9210  1.14  christos 	 * the first name in the AUTHORITY section when wildcard processing is
   9211  1.14  christos 	 * involved.
   9212  1.14  christos 	 */
   9213  1.14  christos 	while (result == ISC_R_SUCCESS) {
   9214  1.14  christos 		rname = NULL;
   9215  1.14  christos 		dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
   9216  1.14  christos 					&rname);
   9217  1.14  christos 		result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
   9218  1.14  christos 		if (result == ISC_R_SUCCESS) {
   9219  1.14  christos 			break;
   9220  1.14  christos 		}
   9221  1.14  christos 		result = dns_message_nextname(client->message,
   9222  1.14  christos 					      DNS_SECTION_AUTHORITY);
   9223  1.14  christos 	}
   9224  1.14  christos 
   9225   1.9  christos 	if (result != ISC_R_SUCCESS) {
   9226   1.1  christos 		goto cleanup;
   9227   1.9  christos 	}
   9228   1.1  christos 
   9229  1.14  christos 	/*
   9230  1.14  christos 	 * Add the relevant RRset (DS or NSEC) to the delegation.
   9231  1.14  christos 	 */
   9232  1.14  christos 	query_addrrset(qctx, &rname, &rdataset, &sigrdataset, NULL,
   9233  1.14  christos 		       DNS_SECTION_AUTHORITY);
   9234  1.14  christos 	goto cleanup;
   9235   1.1  christos 
   9236   1.9  christos addnsec3:
   9237   1.9  christos 	if (!dns_db_iszone(qctx->db)) {
   9238   1.1  christos 		goto cleanup;
   9239   1.9  christos 	}
   9240   1.1  christos 	/*
   9241   1.1  christos 	 * Add the NSEC3 which proves the DS does not exist.
   9242   1.1  christos 	 */
   9243   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   9244   1.9  christos 	if (dbuf == NULL) {
   9245   1.1  christos 		goto cleanup;
   9246   1.9  christos 	}
   9247   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   9248   1.1  christos 	dns_fixedname_init(&fixed);
   9249   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   9250   1.1  christos 		dns_rdataset_disassociate(rdataset);
   9251   1.9  christos 	}
   9252   1.9  christos 	if (dns_rdataset_isassociated(sigrdataset)) {
   9253   1.1  christos 		dns_rdataset_disassociate(sigrdataset);
   9254   1.9  christos 	}
   9255   1.1  christos 	name = dns_fixedname_name(&qctx->dsname);
   9256   1.1  christos 	query_findclosestnsec3(name, qctx->db, qctx->version, client, rdataset,
   9257   1.3  christos 			       sigrdataset, fname, true,
   9258   1.1  christos 			       dns_fixedname_name(&fixed));
   9259   1.9  christos 	if (!dns_rdataset_isassociated(rdataset)) {
   9260   1.1  christos 		goto cleanup;
   9261   1.9  christos 	}
   9262   1.3  christos 	query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   9263   1.1  christos 		       DNS_SECTION_AUTHORITY);
   9264   1.1  christos 	/*
   9265   1.1  christos 	 * Did we find the closest provable encloser instead?
   9266   1.1  christos 	 * If so add the nearest to the closest provable encloser.
   9267   1.1  christos 	 */
   9268   1.1  christos 	if (!dns_name_equal(name, dns_fixedname_name(&fixed))) {
   9269   1.1  christos 		count = dns_name_countlabels(dns_fixedname_name(&fixed)) + 1;
   9270   1.1  christos 		dns_name_getlabelsequence(name,
   9271   1.1  christos 					  dns_name_countlabels(name) - count,
   9272   1.1  christos 					  count, dns_fixedname_name(&fixed));
   9273   1.1  christos 		fixfname(client, &fname, &dbuf, &b);
   9274   1.1  christos 		fixrdataset(client, &rdataset);
   9275   1.1  christos 		fixrdataset(client, &sigrdataset);
   9276   1.9  christos 		if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   9277   1.9  christos 			goto cleanup;
   9278   1.9  christos 		}
   9279   1.9  christos 		query_findclosestnsec3(dns_fixedname_name(&fixed), qctx->db,
   9280   1.9  christos 				       qctx->version, client, rdataset,
   9281   1.9  christos 				       sigrdataset, fname, false, NULL);
   9282   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   9283   1.1  christos 			goto cleanup;
   9284   1.9  christos 		}
   9285   1.3  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   9286   1.1  christos 			       DNS_SECTION_AUTHORITY);
   9287   1.1  christos 	}
   9288   1.1  christos 
   9289   1.9  christos cleanup:
   9290   1.3  christos 	if (rdataset != NULL) {
   9291   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   9292   1.3  christos 	}
   9293   1.3  christos 	if (sigrdataset != NULL) {
   9294   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   9295   1.3  christos 	}
   9296   1.3  christos 	if (fname != NULL) {
   9297   1.3  christos 		ns_client_releasename(client, &fname);
   9298   1.3  christos 	}
   9299   1.1  christos }
   9300   1.1  christos 
   9301   1.1  christos /*%
   9302   1.1  christos  * Handle authoritative NOERROR/NODATA responses.
   9303   1.1  christos  */
   9304   1.1  christos static isc_result_t
   9305   1.3  christos query_nodata(query_ctx_t *qctx, isc_result_t res) {
   9306   1.3  christos 	isc_result_t result = res;
   9307   1.3  christos 
   9308   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_nodata");
   9309   1.9  christos 
   9310   1.3  christos 	CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx);
   9311   1.3  christos 
   9312   1.1  christos #ifdef dns64_bis_return_excluded_addresses
   9313   1.1  christos 	if (qctx->dns64)
   9314   1.9  christos #else  /* ifdef dns64_bis_return_excluded_addresses */
   9315   1.1  christos 	if (qctx->dns64 && !qctx->dns64_exclude)
   9316   1.9  christos #endif /* ifdef dns64_bis_return_excluded_addresses */
   9317   1.1  christos 	{
   9318   1.1  christos 		isc_buffer_t b;
   9319   1.1  christos 		/*
   9320   1.1  christos 		 * Restore the answers from the previous AAAA lookup.
   9321   1.1  christos 		 */
   9322   1.9  christos 		if (qctx->rdataset != NULL) {
   9323   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   9324   1.9  christos 		}
   9325   1.9  christos 		if (qctx->sigrdataset != NULL) {
   9326   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   9327   1.9  christos 		}
   9328   1.1  christos 		RESTORE(qctx->rdataset, qctx->client->query.dns64_aaaa);
   9329   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->client->query.dns64_sigaaaa);
   9330   1.1  christos 		if (qctx->fname == NULL) {
   9331   1.3  christos 			qctx->dbuf = ns_client_getnamebuf(qctx->client);
   9332   1.1  christos 			if (qctx->dbuf == NULL) {
   9333   1.9  christos 				CCTRACE(ISC_LOG_ERROR, "query_nodata: "
   9334   1.9  christos 						       "ns_client_getnamebuf "
   9335   1.9  christos 						       "failed (3)");
   9336   1.3  christos 				QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   9337   1.9  christos 				return (ns_query_done(qctx));
   9338   1.1  christos 			}
   9339   1.3  christos 			qctx->fname = ns_client_newname(qctx->client,
   9340   1.3  christos 							qctx->dbuf, &b);
   9341   1.1  christos 			if (qctx->fname == NULL) {
   9342   1.9  christos 				CCTRACE(ISC_LOG_ERROR, "query_nodata: "
   9343   1.9  christos 						       "ns_client_newname "
   9344   1.9  christos 						       "failed (3)");
   9345   1.3  christos 				QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   9346   1.9  christos 				return (ns_query_done(qctx));
   9347   1.1  christos 			}
   9348   1.1  christos 		}
   9349  1.20  christos 		dns_name_copy(qctx->client->query.qname, qctx->fname);
   9350   1.3  christos 		qctx->dns64 = false;
   9351   1.1  christos #ifdef dns64_bis_return_excluded_addresses
   9352   1.1  christos 		/*
   9353   1.1  christos 		 * Resume the diverted processing of the AAAA response?
   9354   1.1  christos 		 */
   9355   1.9  christos 		if (qctx->dns64_exclude) {
   9356   1.1  christos 			return (query_prepresponse(qctx));
   9357   1.9  christos 		}
   9358   1.9  christos #endif /* ifdef dns64_bis_return_excluded_addresses */
   9359   1.9  christos 	} else if ((result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) &&
   9360   1.9  christos 		   !ISC_LIST_EMPTY(qctx->view->dns64) && !qctx->nxrewrite &&
   9361   1.1  christos 		   qctx->client->message->rdclass == dns_rdataclass_in &&
   9362   1.1  christos 		   qctx->qtype == dns_rdatatype_aaaa)
   9363   1.1  christos 	{
   9364   1.1  christos 		/*
   9365   1.1  christos 		 * Look to see if there are A records for this name.
   9366   1.1  christos 		 */
   9367   1.1  christos 		switch (result) {
   9368   1.1  christos 		case DNS_R_NCACHENXRRSET:
   9369   1.1  christos 			/*
   9370   1.1  christos 			 * This is from the negative cache; if the ttl is
   9371   1.1  christos 			 * zero, we need to work out whether we have just
   9372   1.1  christos 			 * decremented to zero or there was no negative
   9373   1.1  christos 			 * cache ttl in the answer.
   9374   1.1  christos 			 */
   9375   1.1  christos 			if (qctx->rdataset->ttl != 0) {
   9376   1.1  christos 				qctx->client->query.dns64_ttl =
   9377   1.1  christos 					qctx->rdataset->ttl;
   9378   1.1  christos 				break;
   9379   1.1  christos 			}
   9380   1.1  christos 			if (dns_rdataset_first(qctx->rdataset) == ISC_R_SUCCESS)
   9381   1.9  christos 			{
   9382   1.1  christos 				qctx->client->query.dns64_ttl = 0;
   9383   1.9  christos 			}
   9384   1.1  christos 			break;
   9385   1.1  christos 		case DNS_R_NXRRSET:
   9386   1.1  christos 			qctx->client->query.dns64_ttl =
   9387   1.1  christos 				dns64_ttl(qctx->db, qctx->version);
   9388   1.1  christos 			break;
   9389   1.1  christos 		default:
   9390  1.15  christos 			UNREACHABLE();
   9391   1.1  christos 		}
   9392   1.1  christos 
   9393   1.1  christos 		SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset);
   9394   1.1  christos 		SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset);
   9395   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9396   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   9397   1.1  christos 		qctx->type = qctx->qtype = dns_rdatatype_a;
   9398   1.3  christos 		qctx->dns64 = true;
   9399   1.1  christos 		return (query_lookup(qctx));
   9400   1.1  christos 	}
   9401   1.1  christos 
   9402   1.1  christos 	if (qctx->is_zone) {
   9403   1.1  christos 		return (query_sign_nodata(qctx));
   9404   1.1  christos 	} else {
   9405   1.1  christos 		/*
   9406   1.1  christos 		 * We don't call query_addrrset() because we don't need any
   9407   1.1  christos 		 * of its extra features (and things would probably break!).
   9408   1.1  christos 		 */
   9409   1.1  christos 		if (dns_rdataset_isassociated(qctx->rdataset)) {
   9410   1.3  christos 			ns_client_keepname(qctx->client, qctx->fname,
   9411   1.3  christos 					   qctx->dbuf);
   9412   1.9  christos 			dns_message_addname(qctx->client->message, qctx->fname,
   9413   1.1  christos 					    DNS_SECTION_AUTHORITY);
   9414   1.9  christos 			ISC_LIST_APPEND(qctx->fname->list, qctx->rdataset,
   9415   1.9  christos 					link);
   9416   1.1  christos 			qctx->fname = NULL;
   9417   1.1  christos 			qctx->rdataset = NULL;
   9418   1.1  christos 		}
   9419   1.1  christos 	}
   9420   1.1  christos 
   9421   1.3  christos 	return (ns_query_done(qctx));
   9422   1.3  christos 
   9423   1.9  christos cleanup:
   9424   1.3  christos 	return (result);
   9425   1.1  christos }
   9426   1.1  christos 
   9427   1.1  christos /*%
   9428   1.1  christos  * Add RRSIGs for NOERROR/NODATA responses when answering authoritatively.
   9429   1.1  christos  */
   9430   1.1  christos isc_result_t
   9431   1.1  christos query_sign_nodata(query_ctx_t *qctx) {
   9432   1.1  christos 	isc_result_t result;
   9433   1.9  christos 
   9434   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_sign_nodata");
   9435   1.9  christos 
   9436   1.1  christos 	/*
   9437   1.1  christos 	 * Look for a NSEC3 record if we don't have a NSEC record.
   9438   1.1  christos 	 */
   9439   1.9  christos 	if (qctx->redirected) {
   9440   1.3  christos 		return (ns_query_done(qctx));
   9441   1.9  christos 	}
   9442   1.1  christos 	if (!dns_rdataset_isassociated(qctx->rdataset) &&
   9443  1.16  christos 	    WANTDNSSEC(qctx->client))
   9444  1.16  christos 	{
   9445   1.1  christos 		if ((qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
   9446   1.1  christos 			dns_name_t *found;
   9447   1.1  christos 			dns_name_t *qname;
   9448   1.1  christos 			dns_fixedname_t fixed;
   9449   1.1  christos 			isc_buffer_t b;
   9450   1.1  christos 
   9451   1.1  christos 			found = dns_fixedname_initname(&fixed);
   9452   1.1  christos 			qname = qctx->client->query.qname;
   9453   1.1  christos 
   9454   1.1  christos 			query_findclosestnsec3(qname, qctx->db, qctx->version,
   9455   1.1  christos 					       qctx->client, qctx->rdataset,
   9456   1.1  christos 					       qctx->sigrdataset, qctx->fname,
   9457   1.3  christos 					       true, found);
   9458   1.1  christos 			/*
   9459   1.1  christos 			 * Did we find the closest provable encloser
   9460   1.1  christos 			 * instead? If so add the nearest to the
   9461   1.1  christos 			 * closest provable encloser.
   9462   1.1  christos 			 */
   9463   1.1  christos 			if (dns_rdataset_isassociated(qctx->rdataset) &&
   9464   1.1  christos 			    !dns_name_equal(qname, found) &&
   9465   1.1  christos 			    (((qctx->client->sctx->options &
   9466   1.1  christos 			       NS_SERVER_NONEAREST) == 0) ||
   9467   1.1  christos 			     qctx->qtype == dns_rdatatype_ds))
   9468   1.1  christos 			{
   9469   1.1  christos 				unsigned int count;
   9470   1.1  christos 				unsigned int skip;
   9471   1.1  christos 
   9472   1.1  christos 				/*
   9473   1.1  christos 				 * Add the closest provable encloser.
   9474   1.1  christos 				 */
   9475   1.3  christos 				query_addrrset(qctx, &qctx->fname,
   9476   1.1  christos 					       &qctx->rdataset,
   9477   1.9  christos 					       &qctx->sigrdataset, qctx->dbuf,
   9478   1.1  christos 					       DNS_SECTION_AUTHORITY);
   9479   1.1  christos 
   9480   1.9  christos 				count = dns_name_countlabels(found) + 1;
   9481   1.9  christos 				skip = dns_name_countlabels(qname) - count;
   9482   1.9  christos 				dns_name_getlabelsequence(qname, skip, count,
   9483   1.1  christos 							  found);
   9484   1.1  christos 
   9485   1.1  christos 				fixfname(qctx->client, &qctx->fname,
   9486   1.1  christos 					 &qctx->dbuf, &b);
   9487   1.1  christos 				fixrdataset(qctx->client, &qctx->rdataset);
   9488   1.1  christos 				fixrdataset(qctx->client, &qctx->sigrdataset);
   9489   1.1  christos 				if (qctx->fname == NULL ||
   9490   1.1  christos 				    qctx->rdataset == NULL ||
   9491  1.16  christos 				    qctx->sigrdataset == NULL)
   9492  1.16  christos 				{
   9493   1.9  christos 					CCTRACE(ISC_LOG_ERROR, "query_sign_"
   9494   1.9  christos 							       "nodata: "
   9495   1.9  christos 							       "failure "
   9496   1.9  christos 							       "getting "
   9497   1.9  christos 							       "closest "
   9498   1.9  christos 							       "encloser");
   9499   1.3  christos 					QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   9500   1.3  christos 					return (ns_query_done(qctx));
   9501   1.1  christos 				}
   9502   1.1  christos 				/*
   9503   1.1  christos 				 * 'nearest' doesn't exist so
   9504   1.3  christos 				 * 'exist' is set to false.
   9505   1.1  christos 				 */
   9506   1.9  christos 				query_findclosestnsec3(
   9507   1.9  christos 					found, qctx->db, qctx->version,
   9508   1.9  christos 					qctx->client, qctx->rdataset,
   9509   1.9  christos 					qctx->sigrdataset, qctx->fname, false,
   9510   1.9  christos 					NULL);
   9511   1.1  christos 			}
   9512   1.1  christos 		} else {
   9513   1.3  christos 			ns_client_releasename(qctx->client, &qctx->fname);
   9514   1.3  christos 			query_addwildcardproof(qctx, false, true);
   9515   1.1  christos 		}
   9516   1.1  christos 	}
   9517   1.1  christos 	if (dns_rdataset_isassociated(qctx->rdataset)) {
   9518   1.1  christos 		/*
   9519   1.1  christos 		 * If we've got a NSEC record, we need to save the
   9520   1.1  christos 		 * name now because we're going call query_addsoa()
   9521   1.1  christos 		 * below, and it needs to use the name buffer.
   9522   1.1  christos 		 */
   9523   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9524   1.1  christos 	} else if (qctx->fname != NULL) {
   9525   1.1  christos 		/*
   9526   1.1  christos 		 * We're not going to use fname, and need to release
   9527   1.1  christos 		 * our hold on the name buffer so query_addsoa()
   9528   1.1  christos 		 * may use it.
   9529   1.1  christos 		 */
   9530   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9531   1.1  christos 	}
   9532   1.1  christos 
   9533   1.1  christos 	/*
   9534   1.1  christos 	 * The RPZ SOA has already been added to the additional section
   9535   1.1  christos 	 * if this was an RPZ rewrite, but if it wasn't, add it now.
   9536   1.1  christos 	 */
   9537   1.1  christos 	if (!qctx->nxrewrite) {
   9538   1.9  christos 		result = query_addsoa(qctx, UINT32_MAX, DNS_SECTION_AUTHORITY);
   9539   1.1  christos 		if (result != ISC_R_SUCCESS) {
   9540   1.1  christos 			QUERY_ERROR(qctx, result);
   9541   1.3  christos 			return (ns_query_done(qctx));
   9542   1.1  christos 		}
   9543   1.1  christos 	}
   9544   1.1  christos 
   9545   1.1  christos 	/*
   9546   1.1  christos 	 * Add NSEC record if we found one.
   9547   1.1  christos 	 */
   9548   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   9549  1.16  christos 	    dns_rdataset_isassociated(qctx->rdataset))
   9550  1.16  christos 	{
   9551   1.1  christos 		query_addnxrrsetnsec(qctx);
   9552   1.1  christos 	}
   9553   1.1  christos 
   9554   1.3  christos 	return (ns_query_done(qctx));
   9555   1.1  christos }
   9556   1.1  christos 
   9557   1.1  christos static void
   9558   1.1  christos query_addnxrrsetnsec(query_ctx_t *qctx) {
   9559   1.1  christos 	ns_client_t *client = qctx->client;
   9560   1.1  christos 	dns_rdata_t sigrdata;
   9561   1.1  christos 	dns_rdata_rrsig_t sig;
   9562   1.1  christos 	unsigned int labels;
   9563   1.1  christos 	isc_buffer_t *dbuf, b;
   9564   1.1  christos 	dns_name_t *fname;
   9565   1.3  christos 	isc_result_t result;
   9566   1.1  christos 
   9567   1.1  christos 	INSIST(qctx->fname != NULL);
   9568   1.1  christos 
   9569   1.1  christos 	if ((qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
   9570   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9571   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9572   1.1  christos 		return;
   9573   1.1  christos 	}
   9574   1.1  christos 
   9575   1.1  christos 	if (qctx->sigrdataset == NULL ||
   9576  1.16  christos 	    !dns_rdataset_isassociated(qctx->sigrdataset))
   9577  1.16  christos 	{
   9578   1.1  christos 		return;
   9579   1.1  christos 	}
   9580   1.1  christos 
   9581   1.1  christos 	if (dns_rdataset_first(qctx->sigrdataset) != ISC_R_SUCCESS) {
   9582   1.1  christos 		return;
   9583   1.1  christos 	}
   9584   1.1  christos 
   9585   1.1  christos 	dns_rdata_init(&sigrdata);
   9586   1.1  christos 	dns_rdataset_current(qctx->sigrdataset, &sigrdata);
   9587   1.3  christos 	result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
   9588   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9589   1.1  christos 
   9590   1.1  christos 	labels = dns_name_countlabels(qctx->fname);
   9591   1.1  christos 	if ((unsigned int)sig.labels + 1 >= labels) {
   9592   1.1  christos 		return;
   9593   1.1  christos 	}
   9594   1.1  christos 
   9595   1.3  christos 	query_addwildcardproof(qctx, true, false);
   9596   1.1  christos 
   9597   1.1  christos 	/*
   9598   1.1  christos 	 * We'll need some resources...
   9599   1.1  christos 	 */
   9600   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   9601   1.1  christos 	if (dbuf == NULL) {
   9602   1.1  christos 		return;
   9603   1.1  christos 	}
   9604   1.1  christos 
   9605   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   9606   1.1  christos 	if (fname == NULL) {
   9607   1.1  christos 		return;
   9608   1.1  christos 	}
   9609   1.1  christos 
   9610   1.1  christos 	dns_name_split(qctx->fname, sig.labels + 1, NULL, fname);
   9611   1.1  christos 	/* This will succeed, since we've stripped labels. */
   9612   1.1  christos 	RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname,
   9613   1.1  christos 					   NULL) == ISC_R_SUCCESS);
   9614   1.9  christos 	query_addrrset(qctx, &fname, &qctx->rdataset, &qctx->sigrdataset, dbuf,
   9615   1.9  christos 		       DNS_SECTION_AUTHORITY);
   9616   1.1  christos }
   9617   1.1  christos 
   9618   1.1  christos /*%
   9619   1.1  christos  * Handle NXDOMAIN and empty wildcard responses.
   9620   1.1  christos  */
   9621   1.1  christos static isc_result_t
   9622  1.18  christos query_nxdomain(query_ctx_t *qctx, isc_result_t result) {
   9623   1.1  christos 	dns_section_t section;
   9624   1.3  christos 	uint32_t ttl;
   9625  1.18  christos 	bool empty_wild = (result == DNS_R_EMPTYWILD);
   9626   1.1  christos 
   9627   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain");
   9628   1.9  christos 
   9629   1.3  christos 	CALL_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx);
   9630   1.3  christos 
   9631   1.1  christos 	INSIST(qctx->is_zone || REDIRECT(qctx->client));
   9632   1.1  christos 
   9633   1.1  christos 	if (!empty_wild) {
   9634  1.18  christos 		result = query_redirect(qctx, result);
   9635   1.9  christos 		if (result != ISC_R_COMPLETE) {
   9636   1.1  christos 			return (result);
   9637   1.9  christos 		}
   9638   1.1  christos 	}
   9639   1.1  christos 
   9640   1.1  christos 	if (dns_rdataset_isassociated(qctx->rdataset)) {
   9641   1.1  christos 		/*
   9642   1.1  christos 		 * If we've got a NSEC record, we need to save the
   9643   1.1  christos 		 * name now because we're going call query_addsoa()
   9644   1.1  christos 		 * below, and it needs to use the name buffer.
   9645   1.1  christos 		 */
   9646   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9647   1.1  christos 	} else if (qctx->fname != NULL) {
   9648   1.1  christos 		/*
   9649   1.1  christos 		 * We're not going to use fname, and need to release
   9650   1.1  christos 		 * our hold on the name buffer so query_addsoa()
   9651   1.1  christos 		 * may use it.
   9652   1.1  christos 		 */
   9653   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9654   1.1  christos 	}
   9655   1.1  christos 
   9656   1.1  christos 	/*
   9657   1.1  christos 	 * Add SOA to the additional section if generated by a
   9658   1.1  christos 	 * RPZ rewrite.
   9659   1.1  christos 	 *
   9660   1.1  christos 	 * If the query was for a SOA record force the
   9661   1.1  christos 	 * ttl to zero so that it is possible for clients to find
   9662   1.1  christos 	 * the containing zone of an arbitrary name with a stub
   9663   1.1  christos 	 * resolver and not have it cached.
   9664   1.1  christos 	 */
   9665   1.1  christos 	section = qctx->nxrewrite ? DNS_SECTION_ADDITIONAL
   9666   1.1  christos 				  : DNS_SECTION_AUTHORITY;
   9667   1.3  christos 	ttl = UINT32_MAX;
   9668   1.1  christos 	if (!qctx->nxrewrite && qctx->qtype == dns_rdatatype_soa &&
   9669   1.1  christos 	    qctx->zone != NULL && dns_zone_getzeronosoattl(qctx->zone))
   9670   1.1  christos 	{
   9671   1.1  christos 		ttl = 0;
   9672   1.1  christos 	}
   9673  1.16  christos 	if (!qctx->nxrewrite ||
   9674  1.16  christos 	    (qctx->rpz_st != NULL && qctx->rpz_st->m.rpz->addsoa))
   9675  1.16  christos 	{
   9676   1.5  christos 		result = query_addsoa(qctx, ttl, section);
   9677   1.5  christos 		if (result != ISC_R_SUCCESS) {
   9678   1.5  christos 			QUERY_ERROR(qctx, result);
   9679   1.5  christos 			return (ns_query_done(qctx));
   9680   1.5  christos 		}
   9681   1.1  christos 	}
   9682   1.1  christos 
   9683   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9684   1.1  christos 		/*
   9685   1.1  christos 		 * Add NSEC record if we found one.
   9686   1.1  christos 		 */
   9687   1.9  christos 		if (dns_rdataset_isassociated(qctx->rdataset)) {
   9688   1.9  christos 			query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9689   1.9  christos 				       &qctx->sigrdataset, NULL,
   9690   1.9  christos 				       DNS_SECTION_AUTHORITY);
   9691   1.9  christos 		}
   9692   1.3  christos 		query_addwildcardproof(qctx, false, false);
   9693   1.1  christos 	}
   9694   1.1  christos 
   9695   1.1  christos 	/*
   9696   1.1  christos 	 * Set message rcode.
   9697   1.1  christos 	 */
   9698   1.9  christos 	if (empty_wild) {
   9699   1.1  christos 		qctx->client->message->rcode = dns_rcode_noerror;
   9700   1.9  christos 	} else {
   9701   1.1  christos 		qctx->client->message->rcode = dns_rcode_nxdomain;
   9702   1.9  christos 	}
   9703   1.1  christos 
   9704   1.3  christos 	return (ns_query_done(qctx));
   9705   1.3  christos 
   9706   1.9  christos cleanup:
   9707   1.3  christos 	return (result);
   9708   1.1  christos }
   9709   1.1  christos 
   9710   1.1  christos /*
   9711   1.1  christos  * Handle both types of NXDOMAIN redirection, calling redirect()
   9712   1.1  christos  * (which implements type redirect zones) and redirect2() (which
   9713   1.1  christos  * implements recursive nxdomain-redirect lookups).
   9714   1.1  christos  *
   9715   1.1  christos  * Any result code other than ISC_R_COMPLETE means redirection was
   9716   1.1  christos  * successful and the result code should be returned up the call stack.
   9717   1.1  christos  *
   9718   1.1  christos  * ISC_R_COMPLETE means we reached the end of this function without
   9719   1.1  christos  * redirecting, so query processing should continue past it.
   9720   1.1  christos  */
   9721   1.1  christos static isc_result_t
   9722  1.18  christos query_redirect(query_ctx_t *qctx, isc_result_t saved_result) {
   9723   1.1  christos 	isc_result_t result;
   9724   1.1  christos 
   9725   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_redirect");
   9726   1.9  christos 
   9727   1.1  christos 	result = redirect(qctx->client, qctx->fname, qctx->rdataset,
   9728   1.9  christos 			  &qctx->node, &qctx->db, &qctx->version, qctx->type);
   9729   1.1  christos 	switch (result) {
   9730   1.1  christos 	case ISC_R_SUCCESS:
   9731   1.9  christos 		inc_stats(qctx->client, ns_statscounter_nxdomainredirect);
   9732   1.1  christos 		return (query_prepresponse(qctx));
   9733   1.1  christos 	case DNS_R_NXRRSET:
   9734   1.3  christos 		qctx->redirected = true;
   9735   1.3  christos 		qctx->is_zone = true;
   9736   1.1  christos 		return (query_nodata(qctx, DNS_R_NXRRSET));
   9737   1.1  christos 	case DNS_R_NCACHENXRRSET:
   9738   1.3  christos 		qctx->redirected = true;
   9739   1.3  christos 		qctx->is_zone = false;
   9740   1.1  christos 		return (query_ncache(qctx, DNS_R_NCACHENXRRSET));
   9741   1.1  christos 	default:
   9742   1.1  christos 		break;
   9743   1.1  christos 	}
   9744   1.1  christos 
   9745   1.1  christos 	result = redirect2(qctx->client, qctx->fname, qctx->rdataset,
   9746   1.9  christos 			   &qctx->node, &qctx->db, &qctx->version, qctx->type,
   9747   1.9  christos 			   &qctx->is_zone);
   9748   1.1  christos 	switch (result) {
   9749   1.1  christos 	case ISC_R_SUCCESS:
   9750   1.9  christos 		inc_stats(qctx->client, ns_statscounter_nxdomainredirect);
   9751   1.1  christos 		return (query_prepresponse(qctx));
   9752   1.1  christos 	case DNS_R_CONTINUE:
   9753   1.1  christos 		inc_stats(qctx->client,
   9754   1.1  christos 			  ns_statscounter_nxdomainredirect_rlookup);
   9755   1.1  christos 		SAVE(qctx->client->query.redirect.db, qctx->db);
   9756   1.1  christos 		SAVE(qctx->client->query.redirect.node, qctx->node);
   9757   1.1  christos 		SAVE(qctx->client->query.redirect.zone, qctx->zone);
   9758   1.1  christos 		qctx->client->query.redirect.qtype = qctx->qtype;
   9759   1.1  christos 		INSIST(qctx->rdataset != NULL);
   9760   1.1  christos 		SAVE(qctx->client->query.redirect.rdataset, qctx->rdataset);
   9761   1.1  christos 		SAVE(qctx->client->query.redirect.sigrdataset,
   9762   1.1  christos 		     qctx->sigrdataset);
   9763  1.18  christos 		qctx->client->query.redirect.result = saved_result;
   9764  1.20  christos 		dns_name_copy(qctx->fname, qctx->client->query.redirect.fname);
   9765   1.1  christos 		qctx->client->query.redirect.authoritative =
   9766   1.1  christos 			qctx->authoritative;
   9767   1.1  christos 		qctx->client->query.redirect.is_zone = qctx->is_zone;
   9768   1.3  christos 		return (ns_query_done(qctx));
   9769   1.1  christos 	case DNS_R_NXRRSET:
   9770   1.3  christos 		qctx->redirected = true;
   9771   1.3  christos 		qctx->is_zone = true;
   9772   1.1  christos 		return (query_nodata(qctx, DNS_R_NXRRSET));
   9773   1.1  christos 	case DNS_R_NCACHENXRRSET:
   9774   1.3  christos 		qctx->redirected = true;
   9775   1.3  christos 		qctx->is_zone = false;
   9776   1.1  christos 		return (query_ncache(qctx, DNS_R_NCACHENXRRSET));
   9777   1.1  christos 	default:
   9778   1.1  christos 		break;
   9779   1.1  christos 	}
   9780   1.1  christos 
   9781   1.1  christos 	return (ISC_R_COMPLETE);
   9782   1.1  christos }
   9783   1.1  christos 
   9784   1.1  christos /*%
   9785   1.1  christos  * Logging function to be passed to dns_nsec_noexistnodata.
   9786   1.1  christos  */
   9787   1.1  christos static void
   9788   1.1  christos log_noexistnodata(void *val, int level, const char *fmt, ...) {
   9789   1.1  christos 	query_ctx_t *qctx = val;
   9790   1.1  christos 	va_list ap;
   9791   1.1  christos 
   9792   1.1  christos 	va_start(ap, fmt);
   9793   1.9  christos 	ns_client_logv(qctx->client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
   9794   1.9  christos 		       level, fmt, ap);
   9795   1.1  christos 	va_end(ap);
   9796   1.1  christos }
   9797   1.1  christos 
   9798   1.1  christos static dns_ttl_t
   9799   1.1  christos query_synthttl(dns_rdataset_t *soardataset, dns_rdataset_t *sigsoardataset,
   9800   1.1  christos 	       dns_rdataset_t *p1rdataset, dns_rdataset_t *sigp1rdataset,
   9801   1.9  christos 	       dns_rdataset_t *p2rdataset, dns_rdataset_t *sigp2rdataset) {
   9802   1.1  christos 	dns_rdata_soa_t soa;
   9803   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   9804   1.1  christos 	dns_ttl_t ttl;
   9805   1.1  christos 	isc_result_t result;
   9806   1.1  christos 
   9807   1.1  christos 	REQUIRE(soardataset != NULL);
   9808   1.1  christos 	REQUIRE(sigsoardataset != NULL);
   9809   1.1  christos 	REQUIRE(p1rdataset != NULL);
   9810   1.1  christos 	REQUIRE(sigp1rdataset != NULL);
   9811   1.1  christos 
   9812   1.1  christos 	result = dns_rdataset_first(soardataset);
   9813   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9814   1.1  christos 	dns_rdataset_current(soardataset, &rdata);
   9815   1.3  christos 	result = dns_rdata_tostruct(&rdata, &soa, NULL);
   9816   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9817   1.1  christos 
   9818   1.1  christos 	ttl = ISC_MIN(soa.minimum, soardataset->ttl);
   9819   1.1  christos 	ttl = ISC_MIN(ttl, sigsoardataset->ttl);
   9820   1.1  christos 	ttl = ISC_MIN(ttl, p1rdataset->ttl);
   9821   1.1  christos 	ttl = ISC_MIN(ttl, sigp1rdataset->ttl);
   9822   1.9  christos 	if (p2rdataset != NULL) {
   9823   1.1  christos 		ttl = ISC_MIN(ttl, p2rdataset->ttl);
   9824   1.9  christos 	}
   9825   1.9  christos 	if (sigp2rdataset != NULL) {
   9826   1.1  christos 		ttl = ISC_MIN(ttl, sigp2rdataset->ttl);
   9827   1.9  christos 	}
   9828   1.1  christos 
   9829   1.1  christos 	return (ttl);
   9830   1.1  christos }
   9831   1.1  christos 
   9832   1.1  christos /*
   9833   1.1  christos  * Synthesize a NODATA response from the SOA and covering NSEC in cache.
   9834   1.1  christos  */
   9835   1.1  christos static isc_result_t
   9836   1.1  christos query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer,
   9837   1.1  christos 		  dns_rdataset_t **soardatasetp,
   9838   1.9  christos 		  dns_rdataset_t **sigsoardatasetp) {
   9839   1.1  christos 	dns_name_t *name = NULL;
   9840   1.1  christos 	dns_ttl_t ttl;
   9841   1.1  christos 	isc_buffer_t *dbuf, b;
   9842   1.1  christos 	isc_result_t result;
   9843   1.1  christos 
   9844   1.1  christos 	/*
   9845   1.9  christos 	 * Determine the correct TTL to use for the SOA and RRSIG
   9846   1.1  christos 	 */
   9847   1.9  christos 	ttl = query_synthttl(*soardatasetp, *sigsoardatasetp, qctx->rdataset,
   9848   1.9  christos 			     qctx->sigrdataset, NULL, NULL);
   9849   1.1  christos 	(*soardatasetp)->ttl = (*sigsoardatasetp)->ttl = ttl;
   9850   1.1  christos 
   9851   1.1  christos 	/*
   9852   1.1  christos 	 * We want the SOA record to be first, so save the
   9853   1.1  christos 	 * NODATA proof's name now or else discard it.
   9854   1.1  christos 	 */
   9855   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9856   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9857   1.1  christos 	} else {
   9858   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9859   1.1  christos 	}
   9860   1.1  christos 
   9861   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   9862   1.1  christos 	if (dbuf == NULL) {
   9863   1.1  christos 		result = ISC_R_NOMEMORY;
   9864   1.1  christos 		goto cleanup;
   9865   1.1  christos 	}
   9866   1.1  christos 
   9867   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   9868   1.1  christos 	if (name == NULL) {
   9869   1.1  christos 		result = ISC_R_NOMEMORY;
   9870   1.1  christos 		goto cleanup;
   9871   1.1  christos 	}
   9872   1.1  christos 
   9873  1.20  christos 	dns_name_copy(signer, name);
   9874   1.1  christos 
   9875   1.1  christos 	/*
   9876   1.1  christos 	 * Add SOA record. Omit the RRSIG if DNSSEC was not requested.
   9877   1.1  christos 	 */
   9878   1.1  christos 	if (!WANTDNSSEC(qctx->client)) {
   9879   1.1  christos 		sigsoardatasetp = NULL;
   9880   1.1  christos 	}
   9881   1.9  christos 	query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf,
   9882   1.9  christos 		       DNS_SECTION_AUTHORITY);
   9883   1.1  christos 
   9884   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9885   1.1  christos 		/*
   9886   1.1  christos 		 * Add NODATA proof.
   9887   1.1  christos 		 */
   9888   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9889   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9890   1.1  christos 	}
   9891   1.1  christos 
   9892   1.1  christos 	result = ISC_R_SUCCESS;
   9893   1.1  christos 	inc_stats(qctx->client, ns_statscounter_nodatasynth);
   9894   1.1  christos 
   9895   1.1  christos cleanup:
   9896   1.1  christos 	if (name != NULL) {
   9897   1.3  christos 		ns_client_releasename(qctx->client, &name);
   9898   1.1  christos 	}
   9899   1.1  christos 	return (result);
   9900   1.1  christos }
   9901   1.1  christos 
   9902   1.1  christos /*
   9903   1.1  christos  * Synthesize a wildcard answer using the contents of 'rdataset'.
   9904   1.1  christos  * qctx contains the NODATA proof.
   9905   1.1  christos  */
   9906   1.1  christos static isc_result_t
   9907   1.1  christos query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
   9908   1.9  christos 		    dns_rdataset_t *sigrdataset) {
   9909   1.1  christos 	dns_name_t *name = NULL;
   9910   1.1  christos 	isc_buffer_t *dbuf, b;
   9911   1.1  christos 	isc_result_t result;
   9912   1.3  christos 	dns_rdataset_t *cloneset = NULL, *clonesigset = NULL;
   9913   1.1  christos 	dns_rdataset_t **sigrdatasetp;
   9914   1.1  christos 
   9915   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_synthwildcard");
   9916   1.9  christos 
   9917   1.1  christos 	/*
   9918   1.1  christos 	 * We want the answer to be first, so save the
   9919   1.1  christos 	 * NOQNAME proof's name now or else discard it.
   9920   1.1  christos 	 */
   9921   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9922   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9923   1.1  christos 	} else {
   9924   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9925   1.1  christos 	}
   9926   1.1  christos 
   9927   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   9928   1.1  christos 	if (dbuf == NULL) {
   9929   1.1  christos 		result = ISC_R_NOMEMORY;
   9930   1.1  christos 		goto cleanup;
   9931   1.1  christos 	}
   9932   1.1  christos 
   9933   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   9934   1.1  christos 	if (name == NULL) {
   9935   1.1  christos 		result = ISC_R_NOMEMORY;
   9936   1.1  christos 		goto cleanup;
   9937   1.1  christos 	}
   9938  1.20  christos 	dns_name_copy(qctx->client->query.qname, name);
   9939   1.1  christos 
   9940   1.3  christos 	cloneset = ns_client_newrdataset(qctx->client);
   9941   1.3  christos 	if (cloneset == NULL) {
   9942   1.1  christos 		result = ISC_R_NOMEMORY;
   9943   1.1  christos 		goto cleanup;
   9944   1.1  christos 	}
   9945   1.3  christos 	dns_rdataset_clone(rdataset, cloneset);
   9946   1.1  christos 
   9947   1.1  christos 	/*
   9948   1.1  christos 	 * Add answer RRset. Omit the RRSIG if DNSSEC was not requested.
   9949   1.1  christos 	 */
   9950   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9951   1.3  christos 		clonesigset = ns_client_newrdataset(qctx->client);
   9952   1.3  christos 		if (clonesigset == NULL) {
   9953   1.1  christos 			result = ISC_R_NOMEMORY;
   9954   1.1  christos 			goto cleanup;
   9955   1.1  christos 		}
   9956   1.3  christos 		dns_rdataset_clone(sigrdataset, clonesigset);
   9957   1.3  christos 		sigrdatasetp = &clonesigset;
   9958   1.1  christos 	} else {
   9959   1.1  christos 		sigrdatasetp = NULL;
   9960   1.1  christos 	}
   9961   1.1  christos 
   9962   1.9  christos 	query_addrrset(qctx, &name, &cloneset, sigrdatasetp, dbuf,
   9963   1.9  christos 		       DNS_SECTION_ANSWER);
   9964   1.1  christos 
   9965   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9966   1.1  christos 		/*
   9967   1.1  christos 		 * Add NOQNAME proof.
   9968   1.1  christos 		 */
   9969   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9970   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9971   1.1  christos 	}
   9972   1.1  christos 
   9973   1.1  christos 	result = ISC_R_SUCCESS;
   9974   1.1  christos 	inc_stats(qctx->client, ns_statscounter_wildcardsynth);
   9975   1.1  christos 
   9976   1.1  christos cleanup:
   9977   1.1  christos 	if (name != NULL) {
   9978   1.3  christos 		ns_client_releasename(qctx->client, &name);
   9979   1.1  christos 	}
   9980   1.3  christos 	if (cloneset != NULL) {
   9981   1.3  christos 		ns_client_putrdataset(qctx->client, &cloneset);
   9982   1.1  christos 	}
   9983   1.3  christos 	if (clonesigset != NULL) {
   9984   1.3  christos 		ns_client_putrdataset(qctx->client, &clonesigset);
   9985   1.1  christos 	}
   9986   1.1  christos 	return (result);
   9987   1.1  christos }
   9988   1.1  christos 
   9989   1.1  christos /*
   9990   1.1  christos  * Add a synthesized CNAME record from the wildard RRset (rdataset)
   9991   1.1  christos  * and NODATA proof by calling query_synthwildcard then setup to
   9992   1.1  christos  * follow the CNAME.
   9993   1.1  christos  */
   9994   1.1  christos static isc_result_t
   9995   1.1  christos query_synthcnamewildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
   9996   1.9  christos 			 dns_rdataset_t *sigrdataset) {
   9997   1.1  christos 	isc_result_t result;
   9998   1.1  christos 	dns_name_t *tname = NULL;
   9999   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   10000   1.1  christos 	dns_rdata_cname_t cname;
   10001   1.1  christos 
   10002   1.1  christos 	result = query_synthwildcard(qctx, rdataset, sigrdataset);
   10003   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10004   1.1  christos 		return (result);
   10005   1.1  christos 	}
   10006   1.1  christos 
   10007   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   10008   1.1  christos 
   10009   1.1  christos 	/*
   10010   1.1  christos 	 * Reset qname to be the target name of the CNAME and restart
   10011   1.1  christos 	 * the query.
   10012   1.1  christos 	 */
   10013   1.1  christos 	result = dns_message_gettempname(qctx->client->message, &tname);
   10014   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10015   1.1  christos 		return (result);
   10016   1.1  christos 	}
   10017   1.1  christos 
   10018   1.1  christos 	result = dns_rdataset_first(rdataset);
   10019   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10020   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10021   1.1  christos 		return (result);
   10022   1.1  christos 	}
   10023   1.1  christos 
   10024   1.1  christos 	dns_rdataset_current(rdataset, &rdata);
   10025   1.1  christos 	result = dns_rdata_tostruct(&rdata, &cname, NULL);
   10026   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10027   1.1  christos 	dns_rdata_reset(&rdata);
   10028   1.1  christos 
   10029  1.20  christos 	if (dns_name_equal(qctx->client->query.qname, &cname.cname)) {
   10030  1.20  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10031  1.20  christos 		dns_rdata_freestruct(&cname);
   10032  1.20  christos 		return (ISC_R_SUCCESS);
   10033  1.20  christos 	}
   10034  1.20  christos 
   10035  1.20  christos 	dns_name_copy(&cname.cname, tname);
   10036   1.1  christos 
   10037   1.1  christos 	dns_rdata_freestruct(&cname);
   10038   1.1  christos 	ns_client_qnamereplace(qctx->client, tname);
   10039   1.3  christos 	qctx->want_restart = true;
   10040   1.1  christos 	if (!WANTRECURSION(qctx->client)) {
   10041   1.1  christos 		qctx->options |= DNS_GETDB_NOLOG;
   10042   1.1  christos 	}
   10043   1.1  christos 
   10044   1.1  christos 	return (result);
   10045   1.1  christos }
   10046   1.1  christos 
   10047   1.1  christos /*
   10048  1.20  christos  * Synthesize a NXDOMAIN or NODATA response from qctx (which contains the
   10049  1.20  christos  * NOQNAME proof), nowild + nowildrdataset + signowildrdataset (which
   10050  1.20  christos  * contains the NOWILDCARD proof or NODATA at wildcard) and
   10051  1.20  christos  * signer + soardatasetp + sigsoardatasetp which contain the
   10052  1.20  christos  * SOA record + RRSIG for the negative answer.
   10053   1.1  christos  */
   10054   1.1  christos static isc_result_t
   10055  1.20  christos query_synthnxdomainnodata(query_ctx_t *qctx, bool nodata, dns_name_t *nowild,
   10056  1.20  christos 			  dns_rdataset_t *nowildrdataset,
   10057  1.20  christos 			  dns_rdataset_t *signowildrdataset, dns_name_t *signer,
   10058  1.20  christos 			  dns_rdataset_t **soardatasetp,
   10059  1.20  christos 			  dns_rdataset_t **sigsoardatasetp) {
   10060   1.1  christos 	dns_name_t *name = NULL;
   10061   1.1  christos 	dns_ttl_t ttl;
   10062   1.1  christos 	isc_buffer_t *dbuf, b;
   10063   1.1  christos 	isc_result_t result;
   10064   1.3  christos 	dns_rdataset_t *cloneset = NULL, *clonesigset = NULL;
   10065   1.1  christos 
   10066   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_synthnxdomain");
   10067   1.9  christos 
   10068   1.1  christos 	/*
   10069   1.9  christos 	 * Determine the correct TTL to use for the SOA and RRSIG
   10070   1.1  christos 	 */
   10071   1.9  christos 	ttl = query_synthttl(*soardatasetp, *sigsoardatasetp, qctx->rdataset,
   10072   1.9  christos 			     qctx->sigrdataset, nowildrdataset,
   10073   1.9  christos 			     signowildrdataset);
   10074   1.1  christos 	(*soardatasetp)->ttl = (*sigsoardatasetp)->ttl = ttl;
   10075   1.1  christos 
   10076   1.1  christos 	/*
   10077   1.1  christos 	 * We want the SOA record to be first, so save the
   10078   1.1  christos 	 * NOQNAME proof's name now or else discard it.
   10079   1.1  christos 	 */
   10080   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   10081   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   10082   1.1  christos 	} else {
   10083   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   10084   1.1  christos 	}
   10085   1.1  christos 
   10086   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   10087   1.1  christos 	if (dbuf == NULL) {
   10088   1.1  christos 		result = ISC_R_NOMEMORY;
   10089   1.1  christos 		goto cleanup;
   10090   1.1  christos 	}
   10091   1.1  christos 
   10092   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   10093   1.1  christos 	if (name == NULL) {
   10094   1.1  christos 		result = ISC_R_NOMEMORY;
   10095   1.1  christos 		goto cleanup;
   10096   1.1  christos 	}
   10097   1.1  christos 
   10098  1.20  christos 	dns_name_copy(signer, name);
   10099   1.1  christos 
   10100   1.1  christos 	/*
   10101   1.1  christos 	 * Add SOA record. Omit the RRSIG if DNSSEC was not requested.
   10102   1.1  christos 	 */
   10103   1.1  christos 	if (!WANTDNSSEC(qctx->client)) {
   10104   1.1  christos 		sigsoardatasetp = NULL;
   10105   1.1  christos 	}
   10106   1.9  christos 	query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf,
   10107   1.9  christos 		       DNS_SECTION_AUTHORITY);
   10108   1.1  christos 
   10109   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   10110   1.1  christos 		/*
   10111   1.1  christos 		 * Add NOQNAME proof.
   10112   1.1  christos 		 */
   10113   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   10114   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   10115   1.1  christos 
   10116   1.3  christos 		dbuf = ns_client_getnamebuf(qctx->client);
   10117   1.1  christos 		if (dbuf == NULL) {
   10118   1.1  christos 			result = ISC_R_NOMEMORY;
   10119   1.1  christos 			goto cleanup;
   10120   1.1  christos 		}
   10121   1.1  christos 
   10122   1.3  christos 		name = ns_client_newname(qctx->client, dbuf, &b);
   10123   1.1  christos 		if (name == NULL) {
   10124   1.1  christos 			result = ISC_R_NOMEMORY;
   10125   1.1  christos 			goto cleanup;
   10126   1.1  christos 		}
   10127   1.1  christos 
   10128  1.20  christos 		dns_name_copy(nowild, name);
   10129   1.1  christos 
   10130   1.3  christos 		cloneset = ns_client_newrdataset(qctx->client);
   10131   1.3  christos 		clonesigset = ns_client_newrdataset(qctx->client);
   10132   1.3  christos 		if (cloneset == NULL || clonesigset == NULL) {
   10133   1.1  christos 			result = ISC_R_NOMEMORY;
   10134   1.1  christos 			goto cleanup;
   10135   1.1  christos 		}
   10136   1.1  christos 
   10137   1.3  christos 		dns_rdataset_clone(nowildrdataset, cloneset);
   10138   1.3  christos 		dns_rdataset_clone(signowildrdataset, clonesigset);
   10139   1.1  christos 
   10140   1.1  christos 		/*
   10141   1.1  christos 		 * Add NOWILDCARD proof.
   10142   1.1  christos 		 */
   10143   1.9  christos 		query_addrrset(qctx, &name, &cloneset, &clonesigset, dbuf,
   10144   1.9  christos 			       DNS_SECTION_AUTHORITY);
   10145   1.1  christos 	}
   10146   1.1  christos 
   10147  1.20  christos 	if (nodata) {
   10148  1.20  christos 		inc_stats(qctx->client, ns_statscounter_nodatasynth);
   10149  1.20  christos 	} else {
   10150  1.20  christos 		qctx->client->message->rcode = dns_rcode_nxdomain;
   10151  1.20  christos 		inc_stats(qctx->client, ns_statscounter_nxdomainsynth);
   10152  1.20  christos 	}
   10153   1.1  christos 	result = ISC_R_SUCCESS;
   10154   1.1  christos 
   10155   1.1  christos cleanup:
   10156   1.1  christos 	if (name != NULL) {
   10157   1.3  christos 		ns_client_releasename(qctx->client, &name);
   10158   1.1  christos 	}
   10159   1.3  christos 	if (cloneset != NULL) {
   10160   1.3  christos 		ns_client_putrdataset(qctx->client, &cloneset);
   10161   1.1  christos 	}
   10162   1.3  christos 	if (clonesigset != NULL) {
   10163   1.3  christos 		ns_client_putrdataset(qctx->client, &clonesigset);
   10164   1.1  christos 	}
   10165   1.1  christos 	return (result);
   10166   1.1  christos }
   10167   1.1  christos 
   10168   1.1  christos /*
   10169   1.1  christos  * Check that all signer names in sigrdataset match the expected signer.
   10170   1.1  christos  */
   10171   1.1  christos static isc_result_t
   10172   1.1  christos checksignames(dns_name_t *signer, dns_rdataset_t *sigrdataset) {
   10173   1.1  christos 	isc_result_t result;
   10174   1.1  christos 
   10175   1.9  christos 	for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
   10176   1.9  christos 	     result = dns_rdataset_next(sigrdataset))
   10177   1.9  christos 	{
   10178   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   10179   1.1  christos 		dns_rdata_rrsig_t rrsig;
   10180   1.1  christos 
   10181   1.1  christos 		dns_rdataset_current(sigrdataset, &rdata);
   10182   1.1  christos 		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
   10183   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10184   1.1  christos 		if (dns_name_countlabels(signer) == 0) {
   10185  1.20  christos 			dns_name_copy(&rrsig.signer, signer);
   10186   1.1  christos 		} else if (!dns_name_equal(signer, &rrsig.signer)) {
   10187   1.1  christos 			return (ISC_R_FAILURE);
   10188   1.1  christos 		}
   10189   1.1  christos 	}
   10190   1.1  christos 
   10191   1.1  christos 	return (ISC_R_SUCCESS);
   10192   1.1  christos }
   10193   1.1  christos 
   10194   1.1  christos /*%
   10195   1.1  christos  * Handle covering NSEC responses.
   10196   1.1  christos  *
   10197   1.9  christos  * Verify the NSEC record is appropriate for the QNAME; if not,
   10198   1.1  christos  * redo the initial query without DNS_DBFIND_COVERINGNSEC.
   10199   1.1  christos  *
   10200   1.1  christos  * If the covering NSEC proves that the name exists but not the type,
   10201   1.1  christos  * synthesize a NODATA response.
   10202   1.1  christos  *
   10203   1.1  christos  * If the name doesn't exist, compute the wildcard record and check whether
   10204   1.1  christos  * the wildcard name exists or not.  If we can't determine this, redo the
   10205   1.1  christos  * initial query without DNS_DBFIND_COVERINGNSEC.
   10206   1.1  christos  *
   10207   1.1  christos  * If the wildcard name does not exist, compute the SOA name and look that
   10208   1.1  christos  * up.  If the SOA record does not exist, redo the initial query without
   10209   1.1  christos  * DNS_DBFIND_COVERINGNSEC.  If the SOA record exists, synthesize an
   10210   1.1  christos  * NXDOMAIN response from the found records.
   10211   1.1  christos  *
   10212   1.1  christos  * If the wildcard name does exist, perform a lookup for the requested
   10213   1.1  christos  * type at the wildcard name.
   10214   1.1  christos  */
   10215   1.1  christos static isc_result_t
   10216   1.1  christos query_coveringnsec(query_ctx_t *qctx) {
   10217   1.1  christos 	dns_db_t *db = NULL;
   10218   1.1  christos 	dns_clientinfo_t ci;
   10219   1.1  christos 	dns_clientinfomethods_t cm;
   10220   1.1  christos 	dns_dbnode_t *node = NULL;
   10221   1.1  christos 	dns_fixedname_t fixed;
   10222  1.20  christos 	dns_fixedname_t fnamespace;
   10223   1.1  christos 	dns_fixedname_t fnowild;
   10224   1.1  christos 	dns_fixedname_t fsigner;
   10225   1.1  christos 	dns_fixedname_t fwild;
   10226   1.1  christos 	dns_name_t *fname = NULL;
   10227  1.20  christos 	dns_name_t *namespace = NULL;
   10228   1.1  christos 	dns_name_t *nowild = NULL;
   10229   1.1  christos 	dns_name_t *signer = NULL;
   10230   1.1  christos 	dns_name_t *wild = NULL;
   10231  1.20  christos 	dns_name_t qname;
   10232   1.1  christos 	dns_rdataset_t *soardataset = NULL, *sigsoardataset = NULL;
   10233   1.1  christos 	dns_rdataset_t rdataset, sigrdataset;
   10234   1.3  christos 	bool done = false;
   10235   1.3  christos 	bool exists = true, data = true;
   10236   1.3  christos 	bool redirected = false;
   10237   1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   10238   1.1  christos 	unsigned int dboptions = qctx->client->query.dboptions;
   10239  1.20  christos 	unsigned int labels;
   10240   1.1  christos 
   10241   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_coveringnsec");
   10242   1.9  christos 
   10243  1.20  christos 	dns_name_init(&qname, NULL);
   10244   1.1  christos 	dns_rdataset_init(&rdataset);
   10245   1.1  christos 	dns_rdataset_init(&sigrdataset);
   10246  1.20  christos 	namespace = dns_fixedname_initname(&fnamespace);
   10247  1.20  christos 
   10248  1.20  christos 	/*
   10249  1.20  christos 	 * Check that the NSEC record is from the correct namespace.
   10250  1.20  christos 	 * For records that belong to the parent zone (i.e. DS),
   10251  1.20  christos 	 * remove a label to find the correct namespace.
   10252  1.20  christos 	 */
   10253  1.20  christos 	dns_name_clone(qctx->client->query.qname, &qname);
   10254  1.20  christos 	labels = dns_name_countlabels(&qname);
   10255  1.20  christos 	if (dns_rdatatype_atparent(qctx->qtype) && labels > 1) {
   10256  1.20  christos 		dns_name_getlabelsequence(&qname, 1, labels - 1, &qname);
   10257  1.20  christos 	}
   10258  1.20  christos 	dns_view_sfd_find(qctx->view, &qname, namespace);
   10259  1.20  christos 	if (!dns_name_issubdomain(qctx->fname, namespace)) {
   10260  1.20  christos 		goto cleanup;
   10261  1.20  christos 	}
   10262   1.1  christos 
   10263   1.1  christos 	/*
   10264   1.1  christos 	 * If we have no signer name, stop immediately.
   10265   1.1  christos 	 */
   10266   1.1  christos 	if (!dns_rdataset_isassociated(qctx->sigrdataset)) {
   10267   1.1  christos 		goto cleanup;
   10268   1.1  christos 	}
   10269   1.1  christos 
   10270   1.1  christos 	wild = dns_fixedname_initname(&fwild);
   10271   1.1  christos 	fname = dns_fixedname_initname(&fixed);
   10272   1.1  christos 	signer = dns_fixedname_initname(&fsigner);
   10273   1.1  christos 	nowild = dns_fixedname_initname(&fnowild);
   10274   1.1  christos 
   10275   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   10276  1.20  christos 	dns_clientinfo_init(&ci, qctx->client, NULL);
   10277   1.1  christos 
   10278   1.1  christos 	/*
   10279   1.1  christos 	 * All signer names must be the same to accept.
   10280   1.1  christos 	 */
   10281   1.1  christos 	result = checksignames(signer, qctx->sigrdataset);
   10282   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10283   1.1  christos 		result = ISC_R_SUCCESS;
   10284   1.1  christos 		goto cleanup;
   10285   1.1  christos 	}
   10286   1.1  christos 
   10287   1.1  christos 	/*
   10288  1.20  christos 	 * If NSEC or RRSIG are missing from the type map
   10289  1.20  christos 	 * reject the NSEC RRset.
   10290  1.20  christos 	 */
   10291  1.20  christos 	if (!dns_nsec_requiredtypespresent(qctx->rdataset)) {
   10292  1.20  christos 		goto cleanup;
   10293  1.20  christos 	}
   10294  1.20  christos 
   10295  1.20  christos 	/*
   10296   1.1  christos 	 * Check that we have the correct NOQNAME NSEC record.
   10297   1.1  christos 	 */
   10298   1.1  christos 	result = dns_nsec_noexistnodata(qctx->qtype, qctx->client->query.qname,
   10299   1.9  christos 					qctx->fname, qctx->rdataset, &exists,
   10300   1.9  christos 					&data, wild, log_noexistnodata, qctx);
   10301   1.1  christos 
   10302   1.1  christos 	if (result != ISC_R_SUCCESS || (exists && data)) {
   10303   1.1  christos 		goto cleanup;
   10304   1.1  christos 	}
   10305   1.1  christos 
   10306   1.1  christos 	if (exists) {
   10307   1.9  christos 		if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
   10308   1.1  christos 			goto cleanup;
   10309   1.1  christos 		}
   10310   1.3  christos 		if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
   10311   1.1  christos 		    (qctx->type == dns_rdatatype_a ||
   10312   1.1  christos 		     qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
   10313   1.1  christos 		{
   10314   1.1  christos 			goto cleanup;
   10315   1.1  christos 		}
   10316   1.1  christos 		if (!qctx->resuming && !STALE(qctx->rdataset) &&
   10317   1.1  christos 		    qctx->rdataset->ttl == 0 && RECURSIONOK(qctx->client))
   10318   1.1  christos 		{
   10319   1.1  christos 			goto cleanup;
   10320   1.1  christos 		}
   10321   1.1  christos 
   10322   1.3  christos 		soardataset = ns_client_newrdataset(qctx->client);
   10323   1.3  christos 		sigsoardataset = ns_client_newrdataset(qctx->client);
   10324   1.1  christos 		if (soardataset == NULL || sigsoardataset == NULL) {
   10325   1.1  christos 			goto cleanup;
   10326   1.1  christos 		}
   10327   1.1  christos 
   10328   1.1  christos 		/*
   10329   1.1  christos 		 * Look for SOA record to construct NODATA response.
   10330   1.1  christos 		 */
   10331   1.1  christos 		dns_db_attach(qctx->db, &db);
   10332   1.1  christos 		result = dns_db_findext(db, signer, qctx->version,
   10333   1.1  christos 					dns_rdatatype_soa, dboptions,
   10334   1.9  christos 					qctx->client->now, &node, fname, &cm,
   10335   1.9  christos 					&ci, soardataset, sigsoardataset);
   10336   1.1  christos 
   10337   1.1  christos 		if (result != ISC_R_SUCCESS) {
   10338   1.1  christos 			goto cleanup;
   10339   1.1  christos 		}
   10340   1.9  christos 		(void)query_synthnodata(qctx, signer, &soardataset,
   10341   1.9  christos 					&sigsoardataset);
   10342   1.3  christos 		done = true;
   10343   1.1  christos 		goto cleanup;
   10344   1.1  christos 	}
   10345   1.1  christos 
   10346   1.1  christos 	/*
   10347   1.1  christos 	 * Look up the no-wildcard proof.
   10348   1.1  christos 	 */
   10349   1.1  christos 	dns_db_attach(qctx->db, &db);
   10350   1.1  christos 	result = dns_db_findext(db, wild, qctx->version, qctx->type,
   10351   1.1  christos 				dboptions | DNS_DBFIND_COVERINGNSEC,
   10352   1.9  christos 				qctx->client->now, &node, nowild, &cm, &ci,
   10353   1.9  christos 				&rdataset, &sigrdataset);
   10354   1.1  christos 
   10355   1.1  christos 	if (rdataset.trust != dns_trust_secure ||
   10356  1.16  christos 	    sigrdataset.trust != dns_trust_secure)
   10357  1.16  christos 	{
   10358   1.1  christos 		goto cleanup;
   10359   1.1  christos 	}
   10360   1.1  christos 
   10361   1.1  christos 	/*
   10362   1.1  christos 	 * Zero TTL handling of wildcard record.
   10363   1.1  christos 	 *
   10364   1.3  christos 	 * We don't yet have code to handle synthesis and type ANY or dns64
   10365   1.3  christos 	 * processing so we abort the synthesis here if there would be a
   10366   1.3  christos 	 * interaction.
   10367   1.1  christos 	 */
   10368   1.1  christos 	switch (result) {
   10369   1.1  christos 	case ISC_R_SUCCESS:
   10370   1.9  christos 		if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
   10371   1.1  christos 			goto cleanup;
   10372   1.1  christos 		}
   10373   1.3  christos 		if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
   10374   1.1  christos 		    (qctx->type == dns_rdatatype_a ||
   10375   1.1  christos 		     qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
   10376   1.1  christos 		{
   10377   1.1  christos 			goto cleanup;
   10378   1.1  christos 		}
   10379  1.15  christos 		FALLTHROUGH;
   10380   1.1  christos 	case DNS_R_CNAME:
   10381   1.9  christos 		if (!qctx->resuming && !STALE(&rdataset) && rdataset.ttl == 0 &&
   10382   1.9  christos 		    RECURSIONOK(qctx->client))
   10383   1.1  christos 		{
   10384   1.1  christos 			goto cleanup;
   10385   1.1  christos 		}
   10386   1.1  christos 	default:
   10387   1.1  christos 		break;
   10388   1.1  christos 	}
   10389   1.1  christos 
   10390   1.1  christos 	switch (result) {
   10391   1.1  christos 	case DNS_R_COVERINGNSEC:
   10392  1.20  christos 		/*
   10393  1.20  christos 		 * Check that the covering NSEC record is from the right
   10394  1.20  christos 		 * namespace.
   10395  1.20  christos 		 */
   10396  1.20  christos 		if (!dns_name_issubdomain(nowild, namespace)) {
   10397  1.20  christos 			goto cleanup;
   10398  1.20  christos 		}
   10399   1.9  christos 		result = dns_nsec_noexistnodata(qctx->qtype, wild, nowild,
   10400   1.9  christos 						&rdataset, &exists, &data, NULL,
   10401   1.1  christos 						log_noexistnodata, qctx);
   10402  1.20  christos 		if (result != ISC_R_SUCCESS || (exists && data)) {
   10403   1.1  christos 			goto cleanup;
   10404   1.1  christos 		}
   10405   1.1  christos 		break;
   10406   1.9  christos 	case ISC_R_SUCCESS: /* wild card match */
   10407   1.1  christos 		(void)query_synthwildcard(qctx, &rdataset, &sigrdataset);
   10408   1.3  christos 		done = true;
   10409   1.1  christos 		goto cleanup;
   10410   1.9  christos 	case DNS_R_CNAME: /* wild card cname */
   10411   1.1  christos 		(void)query_synthcnamewildcard(qctx, &rdataset, &sigrdataset);
   10412   1.3  christos 		done = true;
   10413   1.1  christos 		goto cleanup;
   10414   1.9  christos 	case DNS_R_NCACHENXRRSET:  /* wild card nodata */
   10415   1.9  christos 	case DNS_R_NCACHENXDOMAIN: /* direct nxdomain */
   10416   1.1  christos 	default:
   10417   1.1  christos 		goto cleanup;
   10418   1.1  christos 	}
   10419   1.1  christos 
   10420   1.1  christos 	/*
   10421   1.1  christos 	 * We now have the proof that we have an NXDOMAIN.  Apply
   10422   1.1  christos 	 * NXDOMAIN redirection if configured.
   10423   1.1  christos 	 */
   10424  1.18  christos 	result = query_redirect(qctx, DNS_R_COVERINGNSEC);
   10425   1.1  christos 	if (result != ISC_R_COMPLETE) {
   10426   1.3  christos 		redirected = true;
   10427   1.1  christos 		goto cleanup;
   10428   1.1  christos 	}
   10429   1.1  christos 
   10430   1.1  christos 	/*
   10431   1.1  christos 	 * Must be signed to accept.
   10432   1.1  christos 	 */
   10433   1.1  christos 	if (!dns_rdataset_isassociated(&sigrdataset)) {
   10434   1.1  christos 		goto cleanup;
   10435   1.1  christos 	}
   10436   1.1  christos 
   10437   1.1  christos 	/*
   10438   1.1  christos 	 * Check signer signer names again.
   10439   1.1  christos 	 */
   10440   1.1  christos 	result = checksignames(signer, &sigrdataset);
   10441   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10442   1.1  christos 		result = ISC_R_SUCCESS;
   10443   1.1  christos 		goto cleanup;
   10444   1.1  christos 	}
   10445   1.1  christos 
   10446   1.1  christos 	if (node != NULL) {
   10447   1.1  christos 		dns_db_detachnode(db, &node);
   10448   1.1  christos 	}
   10449   1.1  christos 
   10450   1.3  christos 	soardataset = ns_client_newrdataset(qctx->client);
   10451   1.3  christos 	sigsoardataset = ns_client_newrdataset(qctx->client);
   10452   1.1  christos 	if (soardataset == NULL || sigsoardataset == NULL) {
   10453   1.1  christos 		goto cleanup;
   10454   1.1  christos 	}
   10455   1.1  christos 
   10456   1.1  christos 	/*
   10457   1.1  christos 	 * Look for SOA record to construct NXDOMAIN response.
   10458   1.1  christos 	 */
   10459   1.9  christos 	result = dns_db_findext(db, signer, qctx->version, dns_rdatatype_soa,
   10460   1.9  christos 				dboptions, qctx->client->now, &node, fname, &cm,
   10461   1.9  christos 				&ci, soardataset, sigsoardataset);
   10462   1.1  christos 
   10463   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10464   1.1  christos 		goto cleanup;
   10465   1.1  christos 	}
   10466  1.20  christos 	(void)query_synthnxdomainnodata(qctx, exists, nowild, &rdataset,
   10467  1.20  christos 					&sigrdataset, signer, &soardataset,
   10468  1.20  christos 					&sigsoardataset);
   10469   1.3  christos 	done = true;
   10470   1.1  christos 
   10471   1.9  christos cleanup:
   10472   1.1  christos 	if (dns_rdataset_isassociated(&rdataset)) {
   10473   1.1  christos 		dns_rdataset_disassociate(&rdataset);
   10474   1.1  christos 	}
   10475   1.1  christos 	if (dns_rdataset_isassociated(&sigrdataset)) {
   10476   1.1  christos 		dns_rdataset_disassociate(&sigrdataset);
   10477   1.1  christos 	}
   10478   1.1  christos 	if (soardataset != NULL) {
   10479   1.3  christos 		ns_client_putrdataset(qctx->client, &soardataset);
   10480   1.1  christos 	}
   10481   1.1  christos 	if (sigsoardataset != NULL) {
   10482   1.3  christos 		ns_client_putrdataset(qctx->client, &sigsoardataset);
   10483   1.1  christos 	}
   10484   1.1  christos 	if (db != NULL) {
   10485   1.1  christos 		if (node != NULL) {
   10486   1.1  christos 			dns_db_detachnode(db, &node);
   10487   1.1  christos 		}
   10488   1.1  christos 		dns_db_detach(&db);
   10489   1.1  christos 	}
   10490   1.1  christos 
   10491   1.1  christos 	if (redirected) {
   10492   1.1  christos 		return (result);
   10493   1.1  christos 	}
   10494   1.1  christos 
   10495   1.1  christos 	if (!done) {
   10496   1.1  christos 		/*
   10497   1.1  christos 		 * No covering NSEC was found; proceed with recursion.
   10498   1.1  christos 		 */
   10499   1.3  christos 		qctx->findcoveringnsec = false;
   10500   1.1  christos 		if (qctx->fname != NULL) {
   10501   1.3  christos 			ns_client_releasename(qctx->client, &qctx->fname);
   10502   1.1  christos 		}
   10503   1.1  christos 		if (qctx->node != NULL) {
   10504   1.1  christos 			dns_db_detachnode(qctx->db, &qctx->node);
   10505   1.1  christos 		}
   10506   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   10507   1.1  christos 		if (qctx->sigrdataset != NULL) {
   10508   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   10509   1.1  christos 		}
   10510   1.1  christos 		return (query_lookup(qctx));
   10511   1.1  christos 	}
   10512   1.1  christos 
   10513   1.3  christos 	return (ns_query_done(qctx));
   10514   1.1  christos }
   10515   1.1  christos 
   10516   1.1  christos /*%
   10517   1.1  christos  * Handle negative cache responses, DNS_R_NCACHENXRRSET or
   10518   1.1  christos  * DNS_R_NCACHENXDOMAIN. (Note: may also be called with result
   10519   1.1  christos  * set to DNS_R_NXDOMAIN when handling DNS64 lookups.)
   10520   1.1  christos  */
   10521   1.1  christos static isc_result_t
   10522   1.1  christos query_ncache(query_ctx_t *qctx, isc_result_t result) {
   10523   1.1  christos 	INSIST(!qctx->is_zone);
   10524   1.1  christos 	INSIST(result == DNS_R_NCACHENXDOMAIN ||
   10525   1.9  christos 	       result == DNS_R_NCACHENXRRSET || result == DNS_R_NXDOMAIN);
   10526   1.9  christos 
   10527   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_ncache");
   10528   1.1  christos 
   10529   1.3  christos 	CALL_HOOK(NS_QUERY_NCACHE_BEGIN, qctx);
   10530   1.3  christos 
   10531   1.3  christos 	qctx->authoritative = false;
   10532   1.1  christos 
   10533   1.1  christos 	if (result == DNS_R_NCACHENXDOMAIN) {
   10534   1.1  christos 		/*
   10535   1.1  christos 		 * Set message rcode. (This is not done when
   10536   1.1  christos 		 * result == DNS_R_NXDOMAIN because that means we're
   10537   1.1  christos 		 * being called after a DNS64 lookup and don't want
   10538   1.1  christos 		 * to update the rcode now.)
   10539   1.1  christos 		 */
   10540   1.1  christos 		qctx->client->message->rcode = dns_rcode_nxdomain;
   10541   1.1  christos 
   10542   1.1  christos 		/* Look for RFC 1918 leakage from Internet. */
   10543   1.1  christos 		if (qctx->qtype == dns_rdatatype_ptr &&
   10544   1.1  christos 		    qctx->client->message->rdclass == dns_rdataclass_in &&
   10545   1.1  christos 		    dns_name_countlabels(qctx->fname) == 7)
   10546   1.1  christos 		{
   10547   1.1  christos 			warn_rfc1918(qctx->client, qctx->fname, qctx->rdataset);
   10548   1.1  christos 		}
   10549   1.1  christos 	}
   10550   1.1  christos 
   10551   1.1  christos 	return (query_nodata(qctx, result));
   10552   1.3  christos 
   10553   1.9  christos cleanup:
   10554   1.3  christos 	return (result);
   10555   1.3  christos }
   10556   1.3  christos 
   10557   1.3  christos /*
   10558   1.3  christos  * If we have a zero ttl from the cache, refetch.
   10559   1.3  christos  */
   10560   1.3  christos static isc_result_t
   10561   1.3  christos query_zerottl_refetch(query_ctx_t *qctx) {
   10562   1.3  christos 	isc_result_t result;
   10563   1.3  christos 
   10564   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_zerottl_refetch");
   10565   1.9  christos 
   10566   1.3  christos 	if (qctx->is_zone || qctx->resuming || STALE(qctx->rdataset) ||
   10567   1.3  christos 	    qctx->rdataset->ttl != 0 || !RECURSIONOK(qctx->client))
   10568   1.3  christos 	{
   10569   1.3  christos 		return (ISC_R_COMPLETE);
   10570   1.3  christos 	}
   10571   1.3  christos 
   10572   1.3  christos 	qctx_clean(qctx);
   10573   1.3  christos 
   10574   1.3  christos 	INSIST(!REDIRECT(qctx->client));
   10575   1.3  christos 
   10576   1.3  christos 	result = ns_query_recurse(qctx->client, qctx->qtype,
   10577   1.9  christos 				  qctx->client->query.qname, NULL, NULL,
   10578   1.9  christos 				  qctx->resuming);
   10579   1.3  christos 	if (result == ISC_R_SUCCESS) {
   10580   1.3  christos 		CALL_HOOK(NS_QUERY_ZEROTTL_RECURSE, qctx);
   10581   1.9  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   10582   1.3  christos 
   10583   1.3  christos 		if (qctx->dns64) {
   10584   1.9  christos 			qctx->client->query.attributes |= NS_QUERYATTR_DNS64;
   10585   1.3  christos 		}
   10586   1.3  christos 		if (qctx->dns64_exclude) {
   10587   1.3  christos 			qctx->client->query.attributes |=
   10588   1.3  christos 				NS_QUERYATTR_DNS64EXCLUDE;
   10589   1.3  christos 		}
   10590   1.3  christos 	} else {
   10591  1.13  christos 		/*
   10592  1.13  christos 		 * There was a zero ttl from the cache, don't fallback to
   10593  1.13  christos 		 * serve-stale lookup.
   10594  1.13  christos 		 */
   10595   1.3  christos 		QUERY_ERROR(qctx, result);
   10596   1.3  christos 	}
   10597   1.3  christos 
   10598   1.3  christos 	return (ns_query_done(qctx));
   10599   1.3  christos 
   10600   1.9  christos cleanup:
   10601   1.3  christos 	return (result);
   10602   1.1  christos }
   10603   1.1  christos 
   10604   1.1  christos /*
   10605   1.1  christos  * Handle CNAME responses.
   10606   1.1  christos  */
   10607   1.1  christos static isc_result_t
   10608   1.1  christos query_cname(query_ctx_t *qctx) {
   10609  1.14  christos 	isc_result_t result = ISC_R_UNSET;
   10610  1.14  christos 	dns_name_t *tname = NULL;
   10611  1.14  christos 	dns_rdataset_t *trdataset = NULL;
   10612   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10613   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   10614   1.1  christos 	dns_rdata_cname_t cname;
   10615   1.1  christos 
   10616   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_cname");
   10617   1.9  christos 
   10618   1.3  christos 	CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx);
   10619   1.1  christos 
   10620   1.3  christos 	result = query_zerottl_refetch(qctx);
   10621   1.3  christos 	if (result != ISC_R_COMPLETE) {
   10622   1.3  christos 		return (result);
   10623   1.1  christos 	}
   10624   1.1  christos 
   10625   1.1  christos 	/*
   10626   1.1  christos 	 * Keep a copy of the rdataset.  We have to do this because
   10627   1.1  christos 	 * query_addrrset may clear 'rdataset' (to prevent the
   10628   1.1  christos 	 * cleanup code from cleaning it up).
   10629   1.1  christos 	 */
   10630   1.1  christos 	trdataset = qctx->rdataset;
   10631   1.1  christos 
   10632   1.1  christos 	/*
   10633   1.1  christos 	 * Add the CNAME to the answer section.
   10634   1.1  christos 	 */
   10635   1.9  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   10636   1.1  christos 		sigrdatasetp = &qctx->sigrdataset;
   10637   1.9  christos 	}
   10638   1.1  christos 
   10639   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   10640   1.1  christos 	    (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
   10641   1.1  christos 	{
   10642   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10643  1.20  christos 		dns_name_copy(qctx->fname,
   10644  1.20  christos 			      dns_fixedname_name(&qctx->wildcardname));
   10645   1.3  christos 		qctx->need_wildcardproof = true;
   10646   1.1  christos 	}
   10647   1.1  christos 
   10648   1.1  christos 	if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) {
   10649   1.1  christos 		qctx->noqname = qctx->rdataset;
   10650   1.1  christos 	} else {
   10651   1.1  christos 		qctx->noqname = NULL;
   10652   1.1  christos 	}
   10653   1.1  christos 
   10654   1.9  christos 	if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   10655   1.1  christos 		query_prefetch(qctx->client, qctx->fname, qctx->rdataset);
   10656   1.9  christos 	}
   10657   1.1  christos 
   10658   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   10659   1.9  christos 		       qctx->dbuf, DNS_SECTION_ANSWER);
   10660   1.1  christos 
   10661   1.1  christos 	query_addnoqnameproof(qctx);
   10662   1.1  christos 
   10663   1.1  christos 	/*
   10664   1.1  christos 	 * We set the PARTIALANSWER attribute so that if anything goes
   10665   1.1  christos 	 * wrong later on, we'll return what we've got so far.
   10666   1.1  christos 	 */
   10667   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   10668   1.1  christos 
   10669   1.1  christos 	/*
   10670   1.1  christos 	 * Reset qname to be the target name of the CNAME and restart
   10671   1.1  christos 	 * the query.
   10672   1.1  christos 	 */
   10673   1.1  christos 	result = dns_message_gettempname(qctx->client->message, &tname);
   10674   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10675   1.3  christos 		return (ns_query_done(qctx));
   10676   1.9  christos 	}
   10677   1.1  christos 
   10678   1.1  christos 	result = dns_rdataset_first(trdataset);
   10679   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10680   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10681   1.3  christos 		return (ns_query_done(qctx));
   10682   1.1  christos 	}
   10683   1.1  christos 
   10684   1.1  christos 	dns_rdataset_current(trdataset, &rdata);
   10685   1.1  christos 	result = dns_rdata_tostruct(&rdata, &cname, NULL);
   10686   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10687   1.1  christos 	dns_rdata_reset(&rdata);
   10688   1.1  christos 
   10689  1.20  christos 	dns_name_copy(&cname.cname, tname);
   10690   1.1  christos 
   10691   1.1  christos 	dns_rdata_freestruct(&cname);
   10692   1.1  christos 	ns_client_qnamereplace(qctx->client, tname);
   10693   1.3  christos 	qctx->want_restart = true;
   10694   1.9  christos 	if (!WANTRECURSION(qctx->client)) {
   10695   1.1  christos 		qctx->options |= DNS_GETDB_NOLOG;
   10696   1.9  christos 	}
   10697   1.1  christos 
   10698   1.1  christos 	query_addauth(qctx);
   10699   1.1  christos 
   10700   1.3  christos 	return (ns_query_done(qctx));
   10701   1.3  christos 
   10702   1.9  christos cleanup:
   10703   1.3  christos 	return (result);
   10704   1.1  christos }
   10705   1.1  christos 
   10706   1.1  christos /*
   10707   1.1  christos  * Handle DNAME responses.
   10708   1.1  christos  */
   10709   1.1  christos static isc_result_t
   10710   1.1  christos query_dname(query_ctx_t *qctx) {
   10711   1.1  christos 	dns_name_t *tname, *prefix;
   10712   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   10713   1.1  christos 	dns_rdata_dname_t dname;
   10714   1.1  christos 	dns_fixedname_t fixed;
   10715   1.1  christos 	dns_rdataset_t *trdataset;
   10716   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10717   1.1  christos 	dns_namereln_t namereln;
   10718   1.1  christos 	isc_buffer_t b;
   10719   1.1  christos 	int order;
   10720  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   10721   1.1  christos 	unsigned int nlabels;
   10722   1.1  christos 
   10723   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_dname");
   10724   1.9  christos 
   10725   1.3  christos 	CALL_HOOK(NS_QUERY_DNAME_BEGIN, qctx);
   10726   1.3  christos 
   10727   1.1  christos 	/*
   10728   1.1  christos 	 * Compare the current qname to the found name.  We need
   10729   1.1  christos 	 * to know how many labels and bits are in common because
   10730   1.1  christos 	 * we're going to have to split qname later on.
   10731   1.1  christos 	 */
   10732   1.1  christos 	namereln = dns_name_fullcompare(qctx->client->query.qname, qctx->fname,
   10733   1.1  christos 					&order, &nlabels);
   10734   1.1  christos 	INSIST(namereln == dns_namereln_subdomain);
   10735   1.1  christos 
   10736   1.1  christos 	/*
   10737   1.1  christos 	 * Keep a copy of the rdataset.  We have to do this because
   10738   1.1  christos 	 * query_addrrset may clear 'rdataset' (to prevent the
   10739   1.1  christos 	 * cleanup code from cleaning it up).
   10740   1.1  christos 	 */
   10741   1.1  christos 	trdataset = qctx->rdataset;
   10742   1.1  christos 
   10743   1.1  christos 	/*
   10744   1.1  christos 	 * Add the DNAME to the answer section.
   10745   1.1  christos 	 */
   10746   1.9  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   10747   1.1  christos 		sigrdatasetp = &qctx->sigrdataset;
   10748   1.9  christos 	}
   10749   1.1  christos 
   10750   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   10751   1.1  christos 	    (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
   10752   1.1  christos 	{
   10753   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10754  1.20  christos 		dns_name_copy(qctx->fname,
   10755  1.20  christos 			      dns_fixedname_name(&qctx->wildcardname));
   10756   1.3  christos 		qctx->need_wildcardproof = true;
   10757   1.1  christos 	}
   10758   1.1  christos 
   10759   1.9  christos 	if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   10760   1.1  christos 		query_prefetch(qctx->client, qctx->fname, qctx->rdataset);
   10761   1.9  christos 	}
   10762   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   10763   1.9  christos 		       qctx->dbuf, DNS_SECTION_ANSWER);
   10764   1.1  christos 
   10765   1.1  christos 	/*
   10766   1.1  christos 	 * We set the PARTIALANSWER attribute so that if anything goes
   10767   1.1  christos 	 * wrong later on, we'll return what we've got so far.
   10768   1.1  christos 	 */
   10769   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   10770   1.1  christos 
   10771   1.1  christos 	/*
   10772   1.1  christos 	 * Get the target name of the DNAME.
   10773   1.1  christos 	 */
   10774   1.1  christos 	tname = NULL;
   10775   1.1  christos 	result = dns_message_gettempname(qctx->client->message, &tname);
   10776   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10777   1.3  christos 		return (ns_query_done(qctx));
   10778   1.9  christos 	}
   10779   1.1  christos 
   10780   1.1  christos 	result = dns_rdataset_first(trdataset);
   10781   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10782   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10783   1.3  christos 		return (ns_query_done(qctx));
   10784   1.1  christos 	}
   10785   1.1  christos 
   10786   1.1  christos 	dns_rdataset_current(trdataset, &rdata);
   10787   1.1  christos 	result = dns_rdata_tostruct(&rdata, &dname, NULL);
   10788   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10789   1.1  christos 	dns_rdata_reset(&rdata);
   10790   1.1  christos 
   10791  1.20  christos 	dns_name_copy(&dname.dname, tname);
   10792   1.1  christos 	dns_rdata_freestruct(&dname);
   10793   1.1  christos 
   10794   1.1  christos 	/*
   10795   1.1  christos 	 * Construct the new qname consisting of
   10796   1.1  christos 	 * <found name prefix>.<dname target>
   10797   1.1  christos 	 */
   10798   1.1  christos 	prefix = dns_fixedname_initname(&fixed);
   10799   1.1  christos 	dns_name_split(qctx->client->query.qname, nlabels, prefix, NULL);
   10800   1.1  christos 	INSIST(qctx->fname == NULL);
   10801   1.3  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   10802   1.1  christos 	if (qctx->dbuf == NULL) {
   10803   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10804   1.3  christos 		return (ns_query_done(qctx));
   10805   1.1  christos 	}
   10806   1.3  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   10807   1.1  christos 	if (qctx->fname == NULL) {
   10808   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10809   1.3  christos 		return (ns_query_done(qctx));
   10810   1.1  christos 	}
   10811   1.1  christos 	result = dns_name_concatenate(prefix, tname, qctx->fname, NULL);
   10812   1.1  christos 	dns_message_puttempname(qctx->client->message, &tname);
   10813   1.1  christos 
   10814   1.1  christos 	/*
   10815   1.1  christos 	 * RFC2672, section 4.1, subsection 3c says
   10816   1.1  christos 	 * we should return YXDOMAIN if the constructed
   10817   1.1  christos 	 * name would be too long.
   10818   1.1  christos 	 */
   10819   1.9  christos 	if (result == DNS_R_NAMETOOLONG) {
   10820   1.1  christos 		qctx->client->message->rcode = dns_rcode_yxdomain;
   10821   1.9  christos 	}
   10822   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10823   1.3  christos 		return (ns_query_done(qctx));
   10824   1.9  christos 	}
   10825   1.1  christos 
   10826   1.3  christos 	ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   10827   1.1  christos 
   10828   1.1  christos 	/*
   10829   1.1  christos 	 * Synthesize a CNAME consisting of
   10830   1.1  christos 	 *   <old qname> <dname ttl> CNAME <new qname>
   10831   1.1  christos 	 *	    with <dname trust value>
   10832   1.1  christos 	 *
   10833   1.1  christos 	 * Synthesize a CNAME so old old clients that don't understand
   10834   1.1  christos 	 * DNAME can chain.
   10835   1.1  christos 	 *
   10836   1.1  christos 	 * We do not try to synthesize a signature because we hope
   10837   1.1  christos 	 * that security aware servers will understand DNAME.  Also,
   10838   1.1  christos 	 * even if we had an online key, making a signature
   10839   1.1  christos 	 * on-the-fly is costly, and not really legitimate anyway
   10840   1.1  christos 	 * since the synthesized CNAME is NOT in the zone.
   10841   1.1  christos 	 */
   10842   1.1  christos 	result = query_addcname(qctx, trdataset->trust, trdataset->ttl);
   10843   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10844   1.3  christos 		return (ns_query_done(qctx));
   10845   1.9  christos 	}
   10846   1.1  christos 
   10847   1.1  christos 	/*
   10848  1.11  christos 	 * If the original query was not for a CNAME or ANY then follow the
   10849  1.11  christos 	 * CNAME.
   10850   1.1  christos 	 */
   10851  1.11  christos 	if (qctx->qtype != dns_rdatatype_cname &&
   10852  1.16  christos 	    qctx->qtype != dns_rdatatype_any)
   10853  1.16  christos 	{
   10854  1.11  christos 		/*
   10855  1.11  christos 		 * Switch to the new qname and restart.
   10856  1.11  christos 		 */
   10857  1.11  christos 		ns_client_qnamereplace(qctx->client, qctx->fname);
   10858  1.11  christos 		qctx->fname = NULL;
   10859  1.11  christos 		qctx->want_restart = true;
   10860  1.11  christos 		if (!WANTRECURSION(qctx->client)) {
   10861  1.11  christos 			qctx->options |= DNS_GETDB_NOLOG;
   10862  1.11  christos 		}
   10863   1.9  christos 	}
   10864   1.1  christos 
   10865   1.1  christos 	query_addauth(qctx);
   10866   1.1  christos 
   10867   1.3  christos 	return (ns_query_done(qctx));
   10868   1.3  christos 
   10869   1.9  christos cleanup:
   10870   1.3  christos 	return (result);
   10871   1.1  christos }
   10872   1.1  christos 
   10873   1.1  christos /*%
   10874   1.9  christos  * Add CNAME to response.
   10875   1.1  christos  */
   10876   1.1  christos static isc_result_t
   10877   1.1  christos query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) {
   10878   1.1  christos 	ns_client_t *client = qctx->client;
   10879   1.1  christos 	dns_rdataset_t *rdataset = NULL;
   10880   1.1  christos 	dns_rdatalist_t *rdatalist = NULL;
   10881   1.1  christos 	dns_rdata_t *rdata = NULL;
   10882   1.1  christos 	isc_region_t r;
   10883   1.1  christos 	dns_name_t *aname = NULL;
   10884   1.1  christos 	isc_result_t result;
   10885   1.1  christos 
   10886   1.1  christos 	result = dns_message_gettempname(client->message, &aname);
   10887   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10888   1.1  christos 		return (result);
   10889   1.1  christos 	}
   10890  1.14  christos 
   10891  1.20  christos 	dns_name_copy(client->query.qname, aname);
   10892   1.1  christos 
   10893   1.1  christos 	result = dns_message_gettemprdatalist(client->message, &rdatalist);
   10894   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10895   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10896   1.1  christos 		return (result);
   10897   1.1  christos 	}
   10898   1.1  christos 
   10899   1.1  christos 	result = dns_message_gettemprdata(client->message, &rdata);
   10900   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10901   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10902   1.1  christos 		dns_message_puttemprdatalist(client->message, &rdatalist);
   10903   1.1  christos 		return (result);
   10904   1.1  christos 	}
   10905   1.1  christos 
   10906   1.1  christos 	result = dns_message_gettemprdataset(client->message, &rdataset);
   10907   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10908   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10909   1.1  christos 		dns_message_puttemprdatalist(client->message, &rdatalist);
   10910   1.1  christos 		dns_message_puttemprdata(client->message, &rdata);
   10911   1.1  christos 		return (result);
   10912   1.1  christos 	}
   10913   1.1  christos 
   10914   1.1  christos 	rdatalist->type = dns_rdatatype_cname;
   10915   1.1  christos 	rdatalist->rdclass = client->message->rdclass;
   10916   1.1  christos 	rdatalist->ttl = ttl;
   10917   1.1  christos 
   10918   1.1  christos 	dns_name_toregion(qctx->fname, &r);
   10919   1.1  christos 	rdata->data = r.base;
   10920   1.1  christos 	rdata->length = r.length;
   10921   1.1  christos 	rdata->rdclass = client->message->rdclass;
   10922   1.1  christos 	rdata->type = dns_rdatatype_cname;
   10923   1.1  christos 
   10924   1.1  christos 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
   10925   1.9  christos 	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
   10926   1.9  christos 		      ISC_R_SUCCESS);
   10927   1.1  christos 	rdataset->trust = trust;
   10928   1.1  christos 	dns_rdataset_setownercase(rdataset, aname);
   10929   1.1  christos 
   10930   1.9  christos 	query_addrrset(qctx, &aname, &rdataset, NULL, NULL, DNS_SECTION_ANSWER);
   10931   1.1  christos 	if (rdataset != NULL) {
   10932   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   10933   1.1  christos 			dns_rdataset_disassociate(rdataset);
   10934   1.9  christos 		}
   10935   1.1  christos 		dns_message_puttemprdataset(client->message, &rdataset);
   10936   1.1  christos 	}
   10937   1.9  christos 	if (aname != NULL) {
   10938   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10939   1.9  christos 	}
   10940   1.1  christos 
   10941   1.1  christos 	return (ISC_R_SUCCESS);
   10942   1.1  christos }
   10943   1.1  christos 
   10944   1.1  christos /*%
   10945   1.1  christos  * Prepare to respond: determine whether a wildcard proof is needed,
   10946   1.3  christos  * then hand off to query_respond() or (for type ANY queries)
   10947   1.3  christos  * query_respond_any().
   10948   1.1  christos  */
   10949   1.1  christos static isc_result_t
   10950   1.1  christos query_prepresponse(query_ctx_t *qctx) {
   10951  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   10952   1.3  christos 
   10953   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_prepresponse");
   10954   1.9  christos 
   10955   1.3  christos 	CALL_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx);
   10956   1.3  christos 
   10957   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   10958   1.1  christos 	    (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
   10959   1.1  christos 	{
   10960   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10961  1.20  christos 		dns_name_copy(qctx->fname,
   10962  1.20  christos 			      dns_fixedname_name(&qctx->wildcardname));
   10963   1.3  christos 		qctx->need_wildcardproof = true;
   10964   1.3  christos 	}
   10965   1.3  christos 
   10966   1.3  christos 	if (qctx->type == dns_rdatatype_any) {
   10967   1.3  christos 		return (query_respond_any(qctx));
   10968   1.1  christos 	}
   10969   1.1  christos 
   10970   1.3  christos 	result = query_zerottl_refetch(qctx);
   10971   1.3  christos 	if (result != ISC_R_COMPLETE) {
   10972   1.3  christos 		return (result);
   10973   1.1  christos 	}
   10974   1.1  christos 
   10975   1.3  christos 	return (query_respond(qctx));
   10976   1.1  christos 
   10977   1.9  christos cleanup:
   10978   1.3  christos 	return (result);
   10979   1.1  christos }
   10980   1.1  christos 
   10981   1.1  christos /*%
   10982   1.1  christos  * Add SOA to the authority section when sending negative responses
   10983   1.1  christos  * (or to the additional section if sending negative responses triggered
   10984   1.1  christos  * by RPZ rewriting.)
   10985   1.1  christos  */
   10986   1.1  christos static isc_result_t
   10987   1.1  christos query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
   10988   1.9  christos 	     dns_section_t section) {
   10989   1.1  christos 	ns_client_t *client = qctx->client;
   10990  1.20  christos 	dns_name_t *name = NULL;
   10991  1.20  christos 	dns_dbnode_t *node = NULL;
   10992  1.20  christos 	isc_result_t result, eresult = ISC_R_SUCCESS;
   10993   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   10994   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10995   1.1  christos 	dns_clientinfomethods_t cm;
   10996   1.1  christos 	dns_clientinfo_t ci;
   10997   1.1  christos 
   10998   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addsoa");
   10999   1.1  christos 
   11000   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   11001  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   11002   1.1  christos 
   11003   1.1  christos 	/*
   11004   1.1  christos 	 * Don't add the SOA record for test which set "-T nosoa".
   11005   1.1  christos 	 */
   11006   1.1  christos 	if (((client->sctx->options & NS_SERVER_NOSOA) != 0) &&
   11007   1.1  christos 	    (!WANTDNSSEC(client) || !dns_rdataset_isassociated(qctx->rdataset)))
   11008   1.1  christos 	{
   11009   1.1  christos 		return (ISC_R_SUCCESS);
   11010   1.1  christos 	}
   11011   1.1  christos 
   11012   1.1  christos 	/*
   11013   1.1  christos 	 * Get resources and make 'name' be the database origin.
   11014   1.1  christos 	 */
   11015   1.1  christos 	result = dns_message_gettempname(client->message, &name);
   11016   1.9  christos 	if (result != ISC_R_SUCCESS) {
   11017   1.1  christos 		return (result);
   11018   1.9  christos 	}
   11019  1.14  christos 
   11020  1.14  christos 	/*
   11021  1.14  christos 	 * We'll be releasing 'name' before returning, so it's safe to
   11022  1.14  christos 	 * use clone instead of copying here.
   11023  1.14  christos 	 */
   11024   1.1  christos 	dns_name_clone(dns_db_origin(qctx->db), name);
   11025  1.14  christos 
   11026   1.3  christos 	rdataset = ns_client_newrdataset(client);
   11027   1.1  christos 	if (rdataset == NULL) {
   11028   1.1  christos 		CTRACE(ISC_LOG_ERROR, "unable to allocate rdataset");
   11029   1.1  christos 		eresult = DNS_R_SERVFAIL;
   11030   1.1  christos 		goto cleanup;
   11031   1.1  christos 	}
   11032   1.1  christos 	if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) {
   11033   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   11034   1.1  christos 		if (sigrdataset == NULL) {
   11035   1.1  christos 			CTRACE(ISC_LOG_ERROR, "unable to allocate sigrdataset");
   11036   1.1  christos 			eresult = DNS_R_SERVFAIL;
   11037   1.1  christos 			goto cleanup;
   11038   1.1  christos 		}
   11039   1.1  christos 	}
   11040   1.1  christos 
   11041   1.1  christos 	/*
   11042   1.1  christos 	 * Find the SOA.
   11043   1.1  christos 	 */
   11044   1.1  christos 	result = dns_db_getoriginnode(qctx->db, &node);
   11045   1.1  christos 	if (result == ISC_R_SUCCESS) {
   11046   1.1  christos 		result = dns_db_findrdataset(qctx->db, node, qctx->version,
   11047   1.9  christos 					     dns_rdatatype_soa, 0, client->now,
   11048   1.1  christos 					     rdataset, sigrdataset);
   11049   1.1  christos 	} else {
   11050   1.1  christos 		dns_fixedname_t foundname;
   11051   1.1  christos 		dns_name_t *fname;
   11052   1.1  christos 
   11053   1.1  christos 		fname = dns_fixedname_initname(&foundname);
   11054   1.1  christos 
   11055   1.1  christos 		result = dns_db_findext(qctx->db, name, qctx->version,
   11056   1.1  christos 					dns_rdatatype_soa,
   11057   1.9  christos 					client->query.dboptions, 0, &node,
   11058   1.9  christos 					fname, &cm, &ci, rdataset, sigrdataset);
   11059   1.1  christos 	}
   11060   1.1  christos 	if (result != ISC_R_SUCCESS) {
   11061   1.1  christos 		/*
   11062   1.1  christos 		 * This is bad.  We tried to get the SOA RR at the zone top
   11063   1.1  christos 		 * and it didn't work!
   11064   1.1  christos 		 */
   11065   1.1  christos 		CTRACE(ISC_LOG_ERROR, "unable to find SOA RR at zone apex");
   11066   1.1  christos 		eresult = DNS_R_SERVFAIL;
   11067   1.1  christos 	} else {
   11068   1.1  christos 		/*
   11069   1.1  christos 		 * Extract the SOA MINIMUM.
   11070   1.1  christos 		 */
   11071   1.1  christos 		dns_rdata_soa_t soa;
   11072   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   11073   1.1  christos 		result = dns_rdataset_first(rdataset);
   11074   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   11075   1.1  christos 		dns_rdataset_current(rdataset, &rdata);
   11076   1.1  christos 		result = dns_rdata_tostruct(&rdata, &soa, NULL);
   11077   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   11078   1.1  christos 
   11079   1.9  christos 		if (override_ttl != UINT32_MAX && override_ttl < rdataset->ttl)
   11080   1.1  christos 		{
   11081   1.1  christos 			rdataset->ttl = override_ttl;
   11082   1.9  christos 			if (sigrdataset != NULL) {
   11083   1.1  christos 				sigrdataset->ttl = override_ttl;
   11084   1.9  christos 			}
   11085   1.1  christos 		}
   11086   1.1  christos 
   11087   1.1  christos 		/*
   11088   1.1  christos 		 * Add the SOA and its SIG to the response, with the
   11089   1.1  christos 		 * TTLs adjusted per RFC2308 section 3.
   11090   1.1  christos 		 */
   11091   1.9  christos 		if (rdataset->ttl > soa.minimum) {
   11092   1.1  christos 			rdataset->ttl = soa.minimum;
   11093   1.9  christos 		}
   11094   1.9  christos 		if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum) {
   11095   1.1  christos 			sigrdataset->ttl = soa.minimum;
   11096   1.9  christos 		}
   11097   1.1  christos 
   11098   1.9  christos 		if (sigrdataset != NULL) {
   11099   1.1  christos 			sigrdatasetp = &sigrdataset;
   11100   1.9  christos 		} else {
   11101   1.1  christos 			sigrdatasetp = NULL;
   11102   1.9  christos 		}
   11103   1.1  christos 
   11104   1.9  christos 		if (section == DNS_SECTION_ADDITIONAL) {
   11105   1.1  christos 			rdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   11106   1.9  christos 		}
   11107   1.9  christos 		query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL,
   11108   1.9  christos 			       section);
   11109   1.1  christos 	}
   11110   1.1  christos 
   11111   1.9  christos cleanup:
   11112   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   11113   1.9  christos 	if (sigrdataset != NULL) {
   11114   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11115   1.9  christos 	}
   11116   1.9  christos 	if (name != NULL) {
   11117   1.3  christos 		ns_client_releasename(client, &name);
   11118   1.9  christos 	}
   11119   1.9  christos 	if (node != NULL) {
   11120   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   11121   1.9  christos 	}
   11122   1.1  christos 
   11123   1.1  christos 	return (eresult);
   11124   1.1  christos }
   11125   1.1  christos 
   11126   1.1  christos /*%
   11127   1.1  christos  * Add NS to authority section (used when the zone apex is already known).
   11128   1.1  christos  */
   11129   1.1  christos static isc_result_t
   11130   1.1  christos query_addns(query_ctx_t *qctx) {
   11131   1.1  christos 	ns_client_t *client = qctx->client;
   11132   1.1  christos 	isc_result_t result, eresult;
   11133   1.1  christos 	dns_name_t *name = NULL, *fname;
   11134   1.1  christos 	dns_dbnode_t *node = NULL;
   11135   1.1  christos 	dns_fixedname_t foundname;
   11136   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   11137   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   11138   1.1  christos 	dns_clientinfomethods_t cm;
   11139   1.1  christos 	dns_clientinfo_t ci;
   11140   1.1  christos 
   11141   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns");
   11142   1.1  christos 
   11143   1.1  christos 	/*
   11144   1.1  christos 	 * Initialization.
   11145   1.1  christos 	 */
   11146   1.1  christos 	eresult = ISC_R_SUCCESS;
   11147   1.1  christos 	fname = dns_fixedname_initname(&foundname);
   11148   1.1  christos 
   11149   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   11150  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   11151   1.1  christos 
   11152   1.1  christos 	/*
   11153   1.1  christos 	 * Get resources and make 'name' be the database origin.
   11154   1.1  christos 	 */
   11155   1.1  christos 	result = dns_message_gettempname(client->message, &name);
   11156   1.1  christos 	if (result != ISC_R_SUCCESS) {
   11157   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addns: dns_message_gettempname "
   11158   1.9  christos 					 "failed: done");
   11159   1.1  christos 		return (result);
   11160   1.1  christos 	}
   11161   1.1  christos 	dns_name_clone(dns_db_origin(qctx->db), name);
   11162   1.3  christos 	rdataset = ns_client_newrdataset(client);
   11163   1.1  christos 	if (rdataset == NULL) {
   11164   1.9  christos 		CTRACE(ISC_LOG_ERROR, "query_addns: ns_client_newrdataset "
   11165   1.9  christos 				      "failed");
   11166   1.1  christos 		eresult = DNS_R_SERVFAIL;
   11167   1.1  christos 		goto cleanup;
   11168   1.1  christos 	}
   11169   1.1  christos 
   11170   1.1  christos 	if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) {
   11171   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   11172   1.1  christos 		if (sigrdataset == NULL) {
   11173   1.9  christos 			CTRACE(ISC_LOG_ERROR, "query_addns: "
   11174   1.9  christos 					      "ns_client_newrdataset failed");
   11175   1.1  christos 			eresult = DNS_R_SERVFAIL;
   11176   1.1  christos 			goto cleanup;
   11177   1.1  christos 		}
   11178   1.1  christos 	}
   11179   1.1  christos 
   11180   1.1  christos 	/*
   11181   1.1  christos 	 * Find the NS rdataset.
   11182   1.1  christos 	 */
   11183   1.1  christos 	result = dns_db_getoriginnode(qctx->db, &node);
   11184   1.1  christos 	if (result == ISC_R_SUCCESS) {
   11185   1.1  christos 		result = dns_db_findrdataset(qctx->db, node, qctx->version,
   11186   1.1  christos 					     dns_rdatatype_ns, 0, client->now,
   11187   1.1  christos 					     rdataset, sigrdataset);
   11188   1.1  christos 	} else {
   11189   1.1  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addns: calling dns_db_find");
   11190   1.1  christos 		result = dns_db_findext(qctx->db, name, NULL, dns_rdatatype_ns,
   11191   1.1  christos 					client->query.dboptions, 0, &node,
   11192   1.1  christos 					fname, &cm, &ci, rdataset, sigrdataset);
   11193   1.1  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addns: dns_db_find complete");
   11194   1.1  christos 	}
   11195   1.1  christos 	if (result != ISC_R_SUCCESS) {
   11196   1.9  christos 		CTRACE(ISC_LOG_ERROR, "query_addns: "
   11197   1.9  christos 				      "dns_db_findrdataset or dns_db_find "
   11198   1.9  christos 				      "failed");
   11199   1.1  christos 		/*
   11200   1.1  christos 		 * This is bad.  We tried to get the NS rdataset at the zone
   11201   1.1  christos 		 * top and it didn't work!
   11202   1.1  christos 		 */
   11203   1.1  christos 		eresult = DNS_R_SERVFAIL;
   11204   1.1  christos 	} else {
   11205   1.1  christos 		if (sigrdataset != NULL) {
   11206   1.1  christos 			sigrdatasetp = &sigrdataset;
   11207   1.1  christos 		}
   11208   1.3  christos 		query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL,
   11209   1.1  christos 			       DNS_SECTION_AUTHORITY);
   11210   1.1  christos 	}
   11211   1.1  christos 
   11212   1.9  christos cleanup:
   11213   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns: cleanup");
   11214   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   11215   1.1  christos 	if (sigrdataset != NULL) {
   11216   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11217   1.1  christos 	}
   11218   1.1  christos 	if (name != NULL) {
   11219   1.3  christos 		ns_client_releasename(client, &name);
   11220   1.1  christos 	}
   11221   1.1  christos 	if (node != NULL) {
   11222   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   11223   1.1  christos 	}
   11224   1.1  christos 
   11225   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns: done");
   11226   1.1  christos 	return (eresult);
   11227   1.1  christos }
   11228   1.1  christos 
   11229   1.1  christos /*%
   11230   1.1  christos  * Find the zone cut and add the best NS rrset to the authority section.
   11231   1.1  christos  */
   11232   1.1  christos static void
   11233   1.1  christos query_addbestns(query_ctx_t *qctx) {
   11234   1.1  christos 	ns_client_t *client = qctx->client;
   11235   1.1  christos 	dns_db_t *db = NULL, *zdb = NULL;
   11236   1.1  christos 	dns_dbnode_t *node = NULL;
   11237   1.1  christos 	dns_name_t *fname = NULL, *zfname = NULL;
   11238   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   11239   1.1  christos 	dns_rdataset_t *zrdataset = NULL, *zsigrdataset = NULL;
   11240   1.3  christos 	bool is_zone = false, use_zone = false;
   11241   1.1  christos 	isc_buffer_t *dbuf = NULL;
   11242   1.1  christos 	isc_result_t result;
   11243   1.1  christos 	dns_dbversion_t *version = NULL;
   11244   1.1  christos 	dns_zone_t *zone = NULL;
   11245   1.1  christos 	isc_buffer_t b;
   11246   1.1  christos 	dns_clientinfomethods_t cm;
   11247   1.1  christos 	dns_clientinfo_t ci;
   11248  1.22  christos 	dns_name_t qname;
   11249   1.1  christos 
   11250   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addbestns");
   11251   1.1  christos 
   11252   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   11253  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   11254   1.1  christos 
   11255  1.22  christos 	dns_name_init(&qname, NULL);
   11256  1.22  christos 	dns_name_clone(client->query.qname, &qname);
   11257  1.22  christos 
   11258   1.1  christos 	/*
   11259   1.1  christos 	 * Find the right database.
   11260   1.1  christos 	 */
   11261  1.22  christos 	do {
   11262  1.22  christos 		result = query_getdb(client, &qname, dns_rdatatype_ns, 0, &zone,
   11263  1.22  christos 				     &db, &version, &is_zone);
   11264  1.22  christos 		if (result != ISC_R_SUCCESS) {
   11265  1.22  christos 			goto cleanup;
   11266  1.22  christos 		}
   11267  1.22  christos 
   11268  1.22  christos 		/*
   11269  1.22  christos 		 * If this is a static stub zone look for a parent zone.
   11270  1.22  christos 		 */
   11271  1.22  christos 		if (zone != NULL &&
   11272  1.22  christos 		    dns_zone_gettype(zone) == dns_zone_staticstub)
   11273  1.22  christos 		{
   11274  1.22  christos 			unsigned int labels = dns_name_countlabels(&qname);
   11275  1.22  christos 			dns_db_detach(&db);
   11276  1.22  christos 			dns_zone_detach(&zone);
   11277  1.22  christos 			version = NULL;
   11278  1.22  christos 			if (labels != 1) {
   11279  1.22  christos 				dns_name_split(&qname, labels - 1, NULL,
   11280  1.22  christos 					       &qname);
   11281  1.22  christos 				continue;
   11282  1.22  christos 			}
   11283  1.22  christos 			if (!USECACHE(client)) {
   11284  1.22  christos 				goto cleanup;
   11285  1.22  christos 			}
   11286  1.22  christos 			dns_db_attach(client->view->cachedb, &db);
   11287  1.22  christos 			is_zone = false;
   11288  1.22  christos 		}
   11289  1.22  christos 		break;
   11290  1.22  christos 	} while (true);
   11291   1.1  christos 
   11292   1.9  christos db_find:
   11293   1.1  christos 	/*
   11294   1.1  christos 	 * We'll need some resources...
   11295   1.1  christos 	 */
   11296   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   11297   1.1  christos 	if (dbuf == NULL) {
   11298   1.1  christos 		goto cleanup;
   11299   1.1  christos 	}
   11300   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   11301   1.3  christos 	rdataset = ns_client_newrdataset(client);
   11302   1.1  christos 	if (fname == NULL || rdataset == NULL) {
   11303   1.1  christos 		goto cleanup;
   11304   1.1  christos 	}
   11305   1.1  christos 
   11306   1.1  christos 	/*
   11307   1.1  christos 	 * Get the RRSIGs if the client requested them or if we may
   11308   1.1  christos 	 * need to validate answers from the cache.
   11309   1.1  christos 	 */
   11310   1.1  christos 	if (WANTDNSSEC(client) || !is_zone) {
   11311   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   11312   1.1  christos 		if (sigrdataset == NULL) {
   11313   1.1  christos 			goto cleanup;
   11314   1.1  christos 		}
   11315   1.1  christos 	}
   11316   1.1  christos 
   11317   1.1  christos 	/*
   11318   1.1  christos 	 * Now look for the zonecut.
   11319   1.1  christos 	 */
   11320   1.1  christos 	if (is_zone) {
   11321   1.9  christos 		result = dns_db_findext(
   11322   1.9  christos 			db, client->query.qname, version, dns_rdatatype_ns,
   11323   1.9  christos 			client->query.dboptions, client->now, &node, fname, &cm,
   11324   1.9  christos 			&ci, rdataset, sigrdataset);
   11325   1.1  christos 		if (result != DNS_R_DELEGATION) {
   11326   1.1  christos 			goto cleanup;
   11327   1.1  christos 		}
   11328   1.1  christos 		if (USECACHE(client)) {
   11329   1.3  christos 			ns_client_keepname(client, fname, dbuf);
   11330   1.1  christos 			dns_db_detachnode(db, &node);
   11331   1.1  christos 			SAVE(zdb, db);
   11332   1.1  christos 			SAVE(zfname, fname);
   11333   1.1  christos 			SAVE(zrdataset, rdataset);
   11334   1.1  christos 			SAVE(zsigrdataset, sigrdataset);
   11335   1.1  christos 			version = NULL;
   11336   1.1  christos 			dns_db_attach(client->view->cachedb, &db);
   11337   1.3  christos 			is_zone = false;
   11338   1.1  christos 			goto db_find;
   11339   1.1  christos 		}
   11340   1.1  christos 	} else {
   11341   1.9  christos 		result = dns_db_findzonecut(
   11342   1.9  christos 			db, client->query.qname, client->query.dboptions,
   11343   1.9  christos 			client->now, &node, fname, NULL, rdataset, sigrdataset);
   11344   1.1  christos 		if (result == ISC_R_SUCCESS) {
   11345   1.1  christos 			if (zfname != NULL &&
   11346  1.16  christos 			    !dns_name_issubdomain(fname, zfname))
   11347  1.16  christos 			{
   11348   1.1  christos 				/*
   11349   1.1  christos 				 * We found a zonecut in the cache, but our
   11350   1.1  christos 				 * zone delegation is better.
   11351   1.1  christos 				 */
   11352   1.3  christos 				use_zone = true;
   11353   1.1  christos 			}
   11354   1.1  christos 		} else if (result == ISC_R_NOTFOUND && zfname != NULL) {
   11355   1.1  christos 			/*
   11356   1.1  christos 			 * We didn't find anything in the cache, but we
   11357   1.1  christos 			 * have a zone delegation, so use it.
   11358   1.1  christos 			 */
   11359   1.3  christos 			use_zone = true;
   11360   1.1  christos 		} else {
   11361   1.1  christos 			goto cleanup;
   11362   1.1  christos 		}
   11363   1.1  christos 	}
   11364   1.1  christos 
   11365   1.1  christos 	if (use_zone) {
   11366   1.3  christos 		ns_client_releasename(client, &fname);
   11367   1.1  christos 		/*
   11368   1.3  christos 		 * We've already done ns_client_keepname() on
   11369   1.1  christos 		 * zfname, so we must set dbuf to NULL to
   11370   1.1  christos 		 * prevent query_addrrset() from trying to
   11371   1.3  christos 		 * call ns_client_keepname() again.
   11372   1.1  christos 		 */
   11373   1.1  christos 		dbuf = NULL;
   11374   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11375   1.1  christos 		if (sigrdataset != NULL) {
   11376   1.3  christos 			ns_client_putrdataset(client, &sigrdataset);
   11377   1.1  christos 		}
   11378   1.1  christos 
   11379   1.1  christos 		if (node != NULL) {
   11380   1.1  christos 			dns_db_detachnode(db, &node);
   11381   1.1  christos 		}
   11382   1.1  christos 		dns_db_detach(&db);
   11383   1.1  christos 
   11384   1.1  christos 		RESTORE(db, zdb);
   11385   1.1  christos 		RESTORE(fname, zfname);
   11386   1.1  christos 		RESTORE(rdataset, zrdataset);
   11387   1.1  christos 		RESTORE(sigrdataset, zsigrdataset);
   11388   1.1  christos 	}
   11389   1.1  christos 
   11390   1.1  christos 	/*
   11391   1.1  christos 	 * Attempt to validate RRsets that are pending or that are glue.
   11392   1.1  christos 	 */
   11393   1.1  christos 	if ((DNS_TRUST_PENDING(rdataset->trust) ||
   11394   1.1  christos 	     (sigrdataset != NULL && DNS_TRUST_PENDING(sigrdataset->trust))) &&
   11395   1.1  christos 	    !validate(client, db, fname, rdataset, sigrdataset) &&
   11396   1.1  christos 	    !PENDINGOK(client->query.dboptions))
   11397   1.1  christos 	{
   11398   1.1  christos 		goto cleanup;
   11399   1.1  christos 	}
   11400   1.1  christos 
   11401   1.1  christos 	if ((DNS_TRUST_GLUE(rdataset->trust) ||
   11402   1.1  christos 	     (sigrdataset != NULL && DNS_TRUST_GLUE(sigrdataset->trust))) &&
   11403   1.1  christos 	    !validate(client, db, fname, rdataset, sigrdataset) &&
   11404   1.1  christos 	    SECURE(client) && WANTDNSSEC(client))
   11405   1.1  christos 	{
   11406   1.1  christos 		goto cleanup;
   11407   1.1  christos 	}
   11408   1.1  christos 
   11409   1.1  christos 	/*
   11410   1.1  christos 	 * If the answer is secure only add NS records if they are secure
   11411   1.1  christos 	 * when the client may be looking for AD in the response.
   11412   1.1  christos 	 */
   11413   1.1  christos 	if (SECURE(client) && (WANTDNSSEC(client) || WANTAD(client)) &&
   11414   1.1  christos 	    ((rdataset->trust != dns_trust_secure) ||
   11415   1.9  christos 	     (sigrdataset != NULL && sigrdataset->trust != dns_trust_secure)))
   11416   1.1  christos 	{
   11417   1.1  christos 		goto cleanup;
   11418   1.1  christos 	}
   11419   1.1  christos 
   11420   1.1  christos 	/*
   11421   1.1  christos 	 * If the client doesn't want DNSSEC we can discard the sigrdataset
   11422   1.1  christos 	 * now.
   11423   1.1  christos 	 */
   11424   1.1  christos 	if (!WANTDNSSEC(client)) {
   11425   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11426   1.1  christos 	}
   11427   1.1  christos 
   11428   1.3  christos 	query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11429   1.1  christos 		       DNS_SECTION_AUTHORITY);
   11430   1.1  christos 
   11431   1.9  christos cleanup:
   11432   1.1  christos 	if (rdataset != NULL) {
   11433   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11434   1.1  christos 	}
   11435   1.1  christos 	if (sigrdataset != NULL) {
   11436   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11437   1.1  christos 	}
   11438   1.1  christos 	if (fname != NULL) {
   11439   1.3  christos 		ns_client_releasename(client, &fname);
   11440   1.1  christos 	}
   11441   1.1  christos 	if (node != NULL) {
   11442   1.1  christos 		dns_db_detachnode(db, &node);
   11443   1.1  christos 	}
   11444   1.1  christos 	if (db != NULL) {
   11445   1.1  christos 		dns_db_detach(&db);
   11446   1.1  christos 	}
   11447   1.1  christos 	if (zone != NULL) {
   11448   1.1  christos 		dns_zone_detach(&zone);
   11449   1.1  christos 	}
   11450   1.1  christos 	if (zdb != NULL) {
   11451   1.3  christos 		ns_client_putrdataset(client, &zrdataset);
   11452   1.3  christos 		if (zsigrdataset != NULL) {
   11453   1.3  christos 			ns_client_putrdataset(client, &zsigrdataset);
   11454   1.3  christos 		}
   11455   1.3  christos 		if (zfname != NULL) {
   11456   1.3  christos 			ns_client_releasename(client, &zfname);
   11457   1.3  christos 		}
   11458   1.1  christos 		dns_db_detach(&zdb);
   11459   1.1  christos 	}
   11460   1.1  christos }
   11461   1.1  christos 
   11462   1.1  christos static void
   11463   1.9  christos query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata) {
   11464   1.1  christos 	ns_client_t *client = qctx->client;
   11465   1.1  christos 	isc_buffer_t *dbuf, b;
   11466   1.1  christos 	dns_name_t *name;
   11467   1.1  christos 	dns_name_t *fname = NULL;
   11468   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   11469   1.1  christos 	dns_fixedname_t wfixed;
   11470   1.1  christos 	dns_name_t *wname;
   11471   1.1  christos 	dns_dbnode_t *node = NULL;
   11472   1.1  christos 	unsigned int options;
   11473   1.1  christos 	unsigned int olabels, nlabels, labels;
   11474   1.1  christos 	isc_result_t result;
   11475   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   11476   1.1  christos 	dns_rdata_nsec_t nsec;
   11477   1.3  christos 	bool have_wname;
   11478   1.1  christos 	int order;
   11479   1.1  christos 	dns_fixedname_t cfixed;
   11480   1.1  christos 	dns_name_t *cname;
   11481   1.1  christos 	dns_clientinfomethods_t cm;
   11482   1.1  christos 	dns_clientinfo_t ci;
   11483   1.1  christos 
   11484   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addwildcardproof");
   11485   1.1  christos 
   11486   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   11487  1.20  christos 	dns_clientinfo_init(&ci, client, NULL);
   11488   1.1  christos 
   11489   1.1  christos 	/*
   11490   1.1  christos 	 * If a name has been specifically flagged as needing
   11491   1.1  christos 	 * a wildcard proof then it will have been copied to
   11492   1.1  christos 	 * qctx->wildcardname. Otherwise we just use the client
   11493   1.1  christos 	 * QNAME.
   11494   1.1  christos 	 */
   11495   1.1  christos 	if (qctx->need_wildcardproof) {
   11496   1.1  christos 		name = dns_fixedname_name(&qctx->wildcardname);
   11497   1.1  christos 	} else {
   11498   1.1  christos 		name = client->query.qname;
   11499   1.1  christos 	}
   11500   1.1  christos 
   11501   1.1  christos 	/*
   11502   1.1  christos 	 * Get the NOQNAME proof then if !ispositive
   11503   1.1  christos 	 * get the NOWILDCARD proof.
   11504   1.1  christos 	 *
   11505   1.1  christos 	 * DNS_DBFIND_NOWILD finds the NSEC records that covers the
   11506   1.1  christos 	 * name ignoring any wildcard.  From the owner and next names
   11507   1.1  christos 	 * of this record you can compute which wildcard (if it exists)
   11508   1.1  christos 	 * will match by finding the longest common suffix of the
   11509   1.1  christos 	 * owner name and next names with the qname and prefixing that
   11510   1.1  christos 	 * with the wildcard label.
   11511   1.1  christos 	 *
   11512   1.1  christos 	 * e.g.
   11513   1.1  christos 	 *   Given:
   11514   1.1  christos 	 *	example SOA
   11515   1.1  christos 	 *	example NSEC b.example
   11516   1.1  christos 	 *	b.example A
   11517   1.1  christos 	 *	b.example NSEC a.d.example
   11518   1.1  christos 	 *	a.d.example A
   11519   1.1  christos 	 *	a.d.example NSEC g.f.example
   11520   1.1  christos 	 *	g.f.example A
   11521   1.1  christos 	 *	g.f.example NSEC z.i.example
   11522   1.1  christos 	 *	z.i.example A
   11523   1.1  christos 	 *	z.i.example NSEC example
   11524   1.1  christos 	 *
   11525   1.1  christos 	 *   QNAME:
   11526   1.1  christos 	 *   a.example -> example NSEC b.example
   11527   1.1  christos 	 *	owner common example
   11528   1.1  christos 	 *	next common example
   11529   1.1  christos 	 *	wild *.example
   11530   1.1  christos 	 *   d.b.example -> b.example NSEC a.d.example
   11531   1.1  christos 	 *	owner common b.example
   11532   1.1  christos 	 *	next common example
   11533   1.1  christos 	 *	wild *.b.example
   11534   1.1  christos 	 *   a.f.example -> a.d.example NSEC g.f.example
   11535   1.1  christos 	 *	owner common example
   11536   1.1  christos 	 *	next common f.example
   11537   1.1  christos 	 *	wild *.f.example
   11538   1.1  christos 	 *  j.example -> z.i.example NSEC example
   11539   1.1  christos 	 *	owner common example
   11540   1.1  christos 	 *	next common example
   11541   1.1  christos 	 *	wild *.example
   11542   1.1  christos 	 */
   11543   1.1  christos 	options = client->query.dboptions | DNS_DBFIND_NOWILD;
   11544   1.1  christos 	wname = dns_fixedname_initname(&wfixed);
   11545   1.9  christos again:
   11546   1.3  christos 	have_wname = false;
   11547   1.1  christos 	/*
   11548   1.1  christos 	 * We'll need some resources...
   11549   1.1  christos 	 */
   11550   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   11551   1.9  christos 	if (dbuf == NULL) {
   11552   1.1  christos 		goto cleanup;
   11553   1.9  christos 	}
   11554   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   11555   1.3  christos 	rdataset = ns_client_newrdataset(client);
   11556   1.3  christos 	sigrdataset = ns_client_newrdataset(client);
   11557   1.9  christos 	if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   11558   1.1  christos 		goto cleanup;
   11559   1.9  christos 	}
   11560   1.1  christos 
   11561   1.1  christos 	result = dns_db_findext(qctx->db, name, qctx->version,
   11562   1.9  christos 				dns_rdatatype_nsec, options, 0, &node, fname,
   11563   1.9  christos 				&cm, &ci, rdataset, sigrdataset);
   11564   1.9  christos 	if (node != NULL) {
   11565   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   11566   1.9  christos 	}
   11567   1.1  christos 
   11568   1.1  christos 	if (!dns_rdataset_isassociated(rdataset)) {
   11569   1.1  christos 		/*
   11570   1.1  christos 		 * No NSEC proof available, return NSEC3 proofs instead.
   11571   1.1  christos 		 */
   11572   1.1  christos 		cname = dns_fixedname_initname(&cfixed);
   11573   1.1  christos 		/*
   11574   1.1  christos 		 * Find the closest encloser.
   11575   1.1  christos 		 */
   11576  1.20  christos 		dns_name_copy(name, cname);
   11577  1.22  christos 		bool once = true;
   11578   1.1  christos 		while (result == DNS_R_NXDOMAIN) {
   11579   1.1  christos 			labels = dns_name_countlabels(cname) - 1;
   11580   1.1  christos 			/*
   11581   1.1  christos 			 * Sanity check.
   11582   1.1  christos 			 */
   11583   1.9  christos 			if (labels == 0U) {
   11584   1.1  christos 				goto cleanup;
   11585   1.9  christos 			}
   11586   1.1  christos 			dns_name_split(cname, labels, NULL, cname);
   11587  1.22  christos 			result = dns_db_findext(
   11588  1.22  christos 				qctx->db, cname, qctx->version,
   11589  1.22  christos 				dns_rdatatype_nsec,
   11590  1.22  christos 				options | (once ? DNS_DBFIND_WANTPARTIAL : 0),
   11591  1.22  christos 				0, NULL, fname, &cm, &ci, NULL, NULL);
   11592  1.22  christos 			if (result == DNS_R_PARTIALMATCH && once) {
   11593  1.22  christos 				unsigned int flabels =
   11594  1.22  christos 					dns_name_countlabels(fname);
   11595  1.22  christos 				if (labels > flabels + 1) {
   11596  1.22  christos 					dns_name_split(cname, flabels + 1, NULL,
   11597  1.22  christos 						       cname);
   11598  1.22  christos 				}
   11599  1.22  christos 				result = DNS_R_NXDOMAIN;
   11600  1.22  christos 			}
   11601  1.22  christos 			once = false;
   11602   1.1  christos 		}
   11603   1.1  christos 		/*
   11604   1.1  christos 		 * Add closest (provable) encloser NSEC3.
   11605   1.1  christos 		 */
   11606   1.9  christos 		query_findclosestnsec3(cname, qctx->db, qctx->version, client,
   11607   1.9  christos 				       rdataset, sigrdataset, fname, true,
   11608   1.9  christos 				       cname);
   11609   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11610   1.1  christos 			goto cleanup;
   11611   1.9  christos 		}
   11612   1.9  christos 		if (!ispositive) {
   11613   1.3  christos 			query_addrrset(qctx, &fname, &rdataset, &sigrdataset,
   11614   1.1  christos 				       dbuf, DNS_SECTION_AUTHORITY);
   11615   1.9  christos 		}
   11616   1.1  christos 
   11617   1.1  christos 		/*
   11618   1.1  christos 		 * Replace resources which were consumed by query_addrrset.
   11619   1.1  christos 		 */
   11620   1.1  christos 		if (fname == NULL) {
   11621   1.3  christos 			dbuf = ns_client_getnamebuf(client);
   11622   1.9  christos 			if (dbuf == NULL) {
   11623   1.1  christos 				goto cleanup;
   11624   1.9  christos 			}
   11625   1.3  christos 			fname = ns_client_newname(client, dbuf, &b);
   11626   1.1  christos 		}
   11627   1.1  christos 
   11628   1.9  christos 		if (rdataset == NULL) {
   11629   1.3  christos 			rdataset = ns_client_newrdataset(client);
   11630   1.9  christos 		} else if (dns_rdataset_isassociated(rdataset)) {
   11631   1.1  christos 			dns_rdataset_disassociate(rdataset);
   11632   1.9  christos 		}
   11633   1.1  christos 
   11634   1.9  christos 		if (sigrdataset == NULL) {
   11635   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   11636   1.9  christos 		} else if (dns_rdataset_isassociated(sigrdataset)) {
   11637   1.1  christos 			dns_rdataset_disassociate(sigrdataset);
   11638   1.9  christos 		}
   11639   1.1  christos 
   11640   1.9  christos 		if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   11641   1.1  christos 			goto cleanup;
   11642   1.9  christos 		}
   11643   1.1  christos 		/*
   11644   1.1  christos 		 * Add no qname proof.
   11645   1.1  christos 		 */
   11646   1.1  christos 		labels = dns_name_countlabels(cname) + 1;
   11647   1.9  christos 		if (dns_name_countlabels(name) == labels) {
   11648  1.20  christos 			dns_name_copy(name, wname);
   11649   1.9  christos 		} else {
   11650   1.1  christos 			dns_name_split(name, labels, NULL, wname);
   11651   1.9  christos 		}
   11652   1.1  christos 
   11653   1.9  christos 		query_findclosestnsec3(wname, qctx->db, qctx->version, client,
   11654   1.9  christos 				       rdataset, sigrdataset, fname, false,
   11655   1.9  christos 				       NULL);
   11656   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11657   1.1  christos 			goto cleanup;
   11658   1.9  christos 		}
   11659   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11660   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11661   1.1  christos 
   11662   1.9  christos 		if (ispositive) {
   11663   1.1  christos 			goto cleanup;
   11664   1.9  christos 		}
   11665   1.1  christos 
   11666   1.1  christos 		/*
   11667   1.1  christos 		 * Replace resources which were consumed by query_addrrset.
   11668   1.1  christos 		 */
   11669   1.1  christos 		if (fname == NULL) {
   11670   1.3  christos 			dbuf = ns_client_getnamebuf(client);
   11671   1.9  christos 			if (dbuf == NULL) {
   11672   1.1  christos 				goto cleanup;
   11673   1.9  christos 			}
   11674   1.3  christos 			fname = ns_client_newname(client, dbuf, &b);
   11675   1.1  christos 		}
   11676   1.1  christos 
   11677   1.9  christos 		if (rdataset == NULL) {
   11678   1.3  christos 			rdataset = ns_client_newrdataset(client);
   11679   1.9  christos 		} else if (dns_rdataset_isassociated(rdataset)) {
   11680   1.1  christos 			dns_rdataset_disassociate(rdataset);
   11681   1.9  christos 		}
   11682   1.1  christos 
   11683   1.9  christos 		if (sigrdataset == NULL) {
   11684   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   11685   1.9  christos 		} else if (dns_rdataset_isassociated(sigrdataset)) {
   11686   1.1  christos 			dns_rdataset_disassociate(sigrdataset);
   11687   1.9  christos 		}
   11688   1.1  christos 
   11689   1.9  christos 		if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   11690   1.1  christos 			goto cleanup;
   11691   1.9  christos 		}
   11692   1.1  christos 		/*
   11693   1.1  christos 		 * Add the no wildcard proof.
   11694   1.1  christos 		 */
   11695   1.9  christos 		result = dns_name_concatenate(dns_wildcardname, cname, wname,
   11696   1.9  christos 					      NULL);
   11697   1.9  christos 		if (result != ISC_R_SUCCESS) {
   11698   1.1  christos 			goto cleanup;
   11699   1.9  christos 		}
   11700   1.1  christos 
   11701   1.9  christos 		query_findclosestnsec3(wname, qctx->db, qctx->version, client,
   11702   1.9  christos 				       rdataset, sigrdataset, fname, nodata,
   11703   1.9  christos 				       NULL);
   11704   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11705   1.1  christos 			goto cleanup;
   11706   1.9  christos 		}
   11707   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11708   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11709   1.1  christos 
   11710   1.1  christos 		goto cleanup;
   11711   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   11712   1.9  christos 		if (!ispositive) {
   11713   1.1  christos 			result = dns_rdataset_first(rdataset);
   11714   1.9  christos 		}
   11715   1.1  christos 		if (result == ISC_R_SUCCESS) {
   11716   1.1  christos 			dns_rdataset_current(rdataset, &rdata);
   11717   1.1  christos 			result = dns_rdata_tostruct(&rdata, &nsec, NULL);
   11718   1.3  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   11719   1.1  christos 			(void)dns_name_fullcompare(name, fname, &order,
   11720   1.1  christos 						   &olabels);
   11721   1.1  christos 			(void)dns_name_fullcompare(name, &nsec.next, &order,
   11722   1.1  christos 						   &nlabels);
   11723   1.1  christos 			/*
   11724   1.1  christos 			 * Check for a pathological condition created when
   11725   1.1  christos 			 * serving some malformed signed zones and bail out.
   11726   1.1  christos 			 */
   11727   1.9  christos 			if (dns_name_countlabels(name) == nlabels) {
   11728   1.1  christos 				goto cleanup;
   11729   1.9  christos 			}
   11730   1.1  christos 
   11731   1.9  christos 			if (olabels > nlabels) {
   11732   1.1  christos 				dns_name_split(name, olabels, NULL, wname);
   11733   1.9  christos 			} else {
   11734   1.1  christos 				dns_name_split(name, nlabels, NULL, wname);
   11735   1.9  christos 			}
   11736   1.9  christos 			result = dns_name_concatenate(dns_wildcardname, wname,
   11737   1.9  christos 						      wname, NULL);
   11738   1.9  christos 			if (result == ISC_R_SUCCESS) {
   11739   1.3  christos 				have_wname = true;
   11740   1.9  christos 			}
   11741   1.1  christos 			dns_rdata_freestruct(&nsec);
   11742   1.1  christos 		}
   11743   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11744   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11745   1.1  christos 	}
   11746   1.3  christos 	if (rdataset != NULL) {
   11747   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11748   1.3  christos 	}
   11749   1.3  christos 	if (sigrdataset != NULL) {
   11750   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11751   1.3  christos 	}
   11752   1.3  christos 	if (fname != NULL) {
   11753   1.3  christos 		ns_client_releasename(client, &fname);
   11754   1.3  christos 	}
   11755   1.1  christos 	if (have_wname) {
   11756   1.9  christos 		ispositive = true; /* prevent loop */
   11757   1.1  christos 		if (!dns_name_equal(name, wname)) {
   11758   1.1  christos 			name = wname;
   11759   1.1  christos 			goto again;
   11760   1.1  christos 		}
   11761   1.1  christos 	}
   11762   1.9  christos cleanup:
   11763   1.3  christos 	if (rdataset != NULL) {
   11764   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11765   1.3  christos 	}
   11766   1.3  christos 	if (sigrdataset != NULL) {
   11767   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11768   1.3  christos 	}
   11769   1.3  christos 	if (fname != NULL) {
   11770   1.3  christos 		ns_client_releasename(client, &fname);
   11771   1.3  christos 	}
   11772   1.1  christos }
   11773   1.1  christos 
   11774   1.1  christos /*%
   11775   1.1  christos  * Add NS records, and NSEC/NSEC3 wildcard proof records if needed,
   11776   1.1  christos  * to the authority section.
   11777   1.1  christos  */
   11778   1.1  christos static void
   11779   1.1  christos query_addauth(query_ctx_t *qctx) {
   11780   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_addauth");
   11781   1.1  christos 	/*
   11782   1.1  christos 	 * Add NS records to the authority section (if we haven't already
   11783   1.1  christos 	 * added them to the answer section).
   11784   1.1  christos 	 */
   11785   1.1  christos 	if (!qctx->want_restart && !NOAUTHORITY(qctx->client)) {
   11786   1.1  christos 		if (qctx->is_zone) {
   11787   1.1  christos 			if (!qctx->answer_has_ns) {
   11788   1.1  christos 				(void)query_addns(qctx);
   11789   1.1  christos 			}
   11790   1.1  christos 		} else if (!qctx->answer_has_ns &&
   11791  1.16  christos 			   qctx->qtype != dns_rdatatype_ns)
   11792  1.16  christos 		{
   11793   1.1  christos 			if (qctx->fname != NULL) {
   11794   1.3  christos 				ns_client_releasename(qctx->client,
   11795   1.3  christos 						      &qctx->fname);
   11796   1.1  christos 			}
   11797   1.1  christos 			query_addbestns(qctx);
   11798   1.1  christos 		}
   11799   1.1  christos 	}
   11800   1.1  christos 
   11801   1.1  christos 	/*
   11802   1.1  christos 	 * Add NSEC records to the authority section if they're needed for
   11803   1.1  christos 	 * DNSSEC wildcard proofs.
   11804   1.1  christos 	 */
   11805   1.9  christos 	if (qctx->need_wildcardproof && dns_db_issecure(qctx->db)) {
   11806   1.3  christos 		query_addwildcardproof(qctx, true, false);
   11807   1.9  christos 	}
   11808   1.1  christos }
   11809   1.1  christos 
   11810   1.1  christos /*
   11811   1.1  christos  * Find the sort order of 'rdata' in the topology-like
   11812   1.1  christos  * ACL forming the second element in a 2-element top-level
   11813   1.1  christos  * sortlist statement.
   11814   1.1  christos  */
   11815   1.1  christos static int
   11816   1.1  christos query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) {
   11817   1.1  christos 	isc_netaddr_t netaddr;
   11818   1.1  christos 
   11819   1.9  christos 	if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) {
   11820   1.1  christos 		return (INT_MAX);
   11821   1.9  christos 	}
   11822   1.1  christos 	return (ns_sortlist_addrorder2(&netaddr, arg));
   11823   1.1  christos }
   11824   1.1  christos 
   11825   1.1  christos /*
   11826   1.1  christos  * Find the sort order of 'rdata' in the matching element
   11827   1.1  christos  * of a 1-element top-level sortlist statement.
   11828   1.1  christos  */
   11829   1.1  christos static int
   11830   1.1  christos query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) {
   11831   1.1  christos 	isc_netaddr_t netaddr;
   11832   1.1  christos 
   11833   1.9  christos 	if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) {
   11834   1.1  christos 		return (INT_MAX);
   11835   1.9  christos 	}
   11836   1.1  christos 	return (ns_sortlist_addrorder1(&netaddr, arg));
   11837   1.1  christos }
   11838   1.1  christos 
   11839   1.1  christos /*
   11840   1.1  christos  * Find the sortlist statement that applies to 'client' and set up
   11841   1.1  christos  * the sortlist info in in client->message appropriately.
   11842   1.1  christos  */
   11843   1.1  christos static void
   11844   1.1  christos query_setup_sortlist(query_ctx_t *qctx) {
   11845   1.1  christos 	isc_netaddr_t netaddr;
   11846   1.1  christos 	ns_client_t *client = qctx->client;
   11847  1.20  christos 	dns_aclenv_t *env = client->manager->aclenv;
   11848  1.20  christos 	dns_acl_t *acl = NULL;
   11849  1.20  christos 	dns_aclelement_t *elt = NULL;
   11850  1.20  christos 	void *order_arg = NULL;
   11851   1.1  christos 
   11852   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   11853   1.9  christos 	switch (ns_sortlist_setup(client->view->sortlist, env, &netaddr,
   11854  1.16  christos 				  &order_arg))
   11855  1.16  christos 	{
   11856   1.1  christos 	case NS_SORTLISTTYPE_1ELEMENT:
   11857  1.20  christos 		elt = order_arg;
   11858   1.1  christos 		dns_message_setsortorder(client->message,
   11859   1.9  christos 					 query_sortlist_order_1element, env,
   11860  1.20  christos 					 NULL, elt);
   11861   1.1  christos 		break;
   11862   1.1  christos 	case NS_SORTLISTTYPE_2ELEMENT:
   11863  1.20  christos 		acl = order_arg;
   11864   1.1  christos 		dns_message_setsortorder(client->message,
   11865   1.9  christos 					 query_sortlist_order_2element, env,
   11866  1.20  christos 					 acl, NULL);
   11867  1.20  christos 		dns_acl_detach(&acl);
   11868   1.1  christos 		break;
   11869   1.1  christos 	case NS_SORTLISTTYPE_NONE:
   11870   1.1  christos 		break;
   11871   1.1  christos 	default:
   11872  1.15  christos 		UNREACHABLE();
   11873   1.1  christos 	}
   11874   1.1  christos }
   11875   1.1  christos 
   11876   1.1  christos /*
   11877   1.1  christos  * When sending a referral, if the answer to the question is
   11878   1.1  christos  * in the glue, sort it to the start of the additional section.
   11879   1.1  christos  */
   11880  1.15  christos static void
   11881   1.1  christos query_glueanswer(query_ctx_t *qctx) {
   11882   1.1  christos 	const dns_namelist_t *secs = qctx->client->message->sections;
   11883   1.1  christos 	const dns_section_t section = DNS_SECTION_ADDITIONAL;
   11884   1.1  christos 	dns_name_t *name;
   11885   1.1  christos 	dns_message_t *msg;
   11886   1.1  christos 	dns_rdataset_t *rdataset = NULL;
   11887   1.1  christos 
   11888   1.1  christos 	if (!ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
   11889   1.1  christos 	    qctx->client->message->rcode != dns_rcode_noerror ||
   11890   1.1  christos 	    (qctx->qtype != dns_rdatatype_a &&
   11891   1.1  christos 	     qctx->qtype != dns_rdatatype_aaaa))
   11892   1.1  christos 	{
   11893   1.1  christos 		return;
   11894   1.1  christos 	}
   11895   1.1  christos 
   11896   1.1  christos 	msg = qctx->client->message;
   11897   1.9  christos 	for (name = ISC_LIST_HEAD(msg->sections[section]); name != NULL;
   11898   1.1  christos 	     name = ISC_LIST_NEXT(name, link))
   11899   1.9  christos 	{
   11900   1.1  christos 		if (dns_name_equal(name, qctx->client->query.qname)) {
   11901   1.1  christos 			for (rdataset = ISC_LIST_HEAD(name->list);
   11902   1.1  christos 			     rdataset != NULL;
   11903   1.1  christos 			     rdataset = ISC_LIST_NEXT(rdataset, link))
   11904   1.9  christos 			{
   11905   1.9  christos 				if (rdataset->type == qctx->qtype) {
   11906   1.1  christos 					break;
   11907   1.9  christos 				}
   11908   1.9  christos 			}
   11909   1.1  christos 			break;
   11910   1.1  christos 		}
   11911   1.9  christos 	}
   11912   1.1  christos 	if (rdataset != NULL) {
   11913   1.1  christos 		ISC_LIST_UNLINK(msg->sections[section], name, link);
   11914   1.1  christos 		ISC_LIST_PREPEND(msg->sections[section], name, link);
   11915   1.1  christos 		ISC_LIST_UNLINK(name->list, rdataset, link);
   11916   1.1  christos 		ISC_LIST_PREPEND(name->list, rdataset, link);
   11917   1.1  christos 		rdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   11918   1.1  christos 	}
   11919   1.1  christos }
   11920   1.1  christos 
   11921   1.3  christos isc_result_t
   11922   1.3  christos ns_query_done(query_ctx_t *qctx) {
   11923  1.20  christos 	isc_result_t result = ISC_R_UNSET;
   11924   1.1  christos 	const dns_namelist_t *secs = qctx->client->message->sections;
   11925  1.22  christos 	bool nodetach, partial_result_with_servfail = false;
   11926   1.1  christos 
   11927   1.3  christos 	CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done");
   11928   1.3  christos 
   11929   1.3  christos 	CALL_HOOK(NS_QUERY_DONE_BEGIN, qctx);
   11930   1.1  christos 
   11931   1.1  christos 	/*
   11932   1.1  christos 	 * General cleanup.
   11933   1.1  christos 	 */
   11934   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   11935   1.1  christos 	if (qctx->rpz_st != NULL &&
   11936  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) == 0)
   11937  1.16  christos 	{
   11938   1.1  christos 		rpz_match_clear(qctx->rpz_st);
   11939   1.1  christos 		qctx->rpz_st->state &= ~DNS_RPZ_DONE_QNAME;
   11940   1.1  christos 	}
   11941   1.1  christos 
   11942   1.1  christos 	qctx_clean(qctx);
   11943   1.1  christos 	qctx_freedata(qctx);
   11944   1.1  christos 
   11945   1.6  christos 	if (qctx->client->query.gluedb != NULL) {
   11946   1.6  christos 		dns_db_detach(&qctx->client->query.gluedb);
   11947   1.6  christos 	}
   11948   1.6  christos 
   11949   1.1  christos 	/*
   11950   1.1  christos 	 * Clear the AA bit if we're not authoritative.
   11951   1.1  christos 	 */
   11952   1.1  christos 	if (qctx->client->query.restarts == 0 && !qctx->authoritative) {
   11953   1.1  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
   11954   1.1  christos 	}
   11955   1.1  christos 
   11956   1.1  christos 	/*
   11957   1.1  christos 	 * Do we need to restart the query (e.g. for CNAME chaining)?
   11958   1.1  christos 	 */
   11959  1.22  christos 	if (qctx->want_restart) {
   11960  1.22  christos 		if (qctx->client->query.restarts <
   11961  1.22  christos 		    qctx->client->view->max_restarts)
   11962  1.22  christos 		{
   11963  1.22  christos 			qctx->client->query.restarts++;
   11964  1.22  christos 			return (ns__query_start(qctx));
   11965  1.22  christos 		} else {
   11966  1.22  christos 			/*
   11967  1.22  christos 			 * This is e.g. a long CNAME chain which we cut short.
   11968  1.22  christos 			 */
   11969  1.22  christos 			qctx->client->query.attributes |=
   11970  1.22  christos 				NS_QUERYATTR_PARTIALANSWER;
   11971  1.22  christos 			qctx->client->message->rcode = dns_rcode_servfail;
   11972  1.22  christos 			qctx->result = DNS_R_SERVFAIL;
   11973  1.22  christos 
   11974  1.22  christos 			/*
   11975  1.22  christos 			 * Send the answer back with a SERVFAIL result even
   11976  1.22  christos 			 * if recursion was requested.
   11977  1.22  christos 			 */
   11978  1.22  christos 			partial_result_with_servfail = true;
   11979  1.22  christos 
   11980  1.22  christos 			ns_client_extendederror(qctx->client, 0,
   11981  1.22  christos 						"max. restarts reached");
   11982  1.22  christos 			ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
   11983  1.22  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   11984  1.22  christos 				      "query iterations limit reached");
   11985  1.22  christos 		}
   11986   1.1  christos 	}
   11987   1.1  christos 
   11988   1.1  christos 	if (qctx->result != ISC_R_SUCCESS &&
   11989  1.22  christos 	    (!PARTIALANSWER(qctx->client) ||
   11990  1.22  christos 	     (WANTRECURSION(qctx->client) && !partial_result_with_servfail) ||
   11991   1.1  christos 	     qctx->result == DNS_R_DROP))
   11992   1.1  christos 	{
   11993   1.1  christos 		if (qctx->result == DNS_R_DUPLICATE ||
   11994  1.16  christos 		    qctx->result == DNS_R_DROP)
   11995  1.16  christos 		{
   11996   1.1  christos 			/*
   11997   1.1  christos 			 * This was a duplicate query that we are
   11998   1.1  christos 			 * recursing on or the result of rate limiting.
   11999   1.1  christos 			 * Don't send a response now for a duplicate query,
   12000   1.1  christos 			 * because the original will still cause a response.
   12001   1.1  christos 			 */
   12002   1.1  christos 			query_next(qctx->client, qctx->result);
   12003   1.1  christos 		} else {
   12004   1.1  christos 			/*
   12005   1.1  christos 			 * If we don't have any answer to give the client,
   12006   1.1  christos 			 * or if the client requested recursion and thus wanted
   12007   1.1  christos 			 * the complete answer, send an error response.
   12008   1.1  christos 			 */
   12009   1.1  christos 			INSIST(qctx->line >= 0);
   12010   1.1  christos 			query_error(qctx->client, qctx->result, qctx->line);
   12011   1.1  christos 		}
   12012   1.1  christos 
   12013   1.3  christos 		qctx->detach_client = true;
   12014   1.1  christos 		return (qctx->result);
   12015   1.1  christos 	}
   12016   1.1  christos 
   12017   1.1  christos 	/*
   12018   1.1  christos 	 * If we're recursing then just return; the query will
   12019   1.1  christos 	 * resume when recursion ends.
   12020   1.1  christos 	 */
   12021  1.11  christos 	if (RECURSING(qctx->client) &&
   12022  1.13  christos 	    (!QUERY_STALETIMEOUT(&qctx->client->query) ||
   12023  1.11  christos 	     ((qctx->options & DNS_GETDB_STALEFIRST) != 0)))
   12024  1.11  christos 	{
   12025   1.1  christos 		return (qctx->result);
   12026   1.1  christos 	}
   12027   1.1  christos 
   12028   1.1  christos 	/*
   12029   1.1  christos 	 * We are done.  Set up sortlist data for the message
   12030   1.1  christos 	 * rendering code, sort the answer to the front of the
   12031   1.1  christos 	 * additional section if necessary, make a final tweak
   12032   1.1  christos 	 * to the AA bit if the auth-nxdomain config option
   12033   1.1  christos 	 * says so, then render and send the response.
   12034   1.1  christos 	 */
   12035  1.13  christos 	query_setup_sortlist(qctx);
   12036  1.13  christos 	query_glueanswer(qctx);
   12037   1.1  christos 
   12038   1.1  christos 	if (qctx->client->message->rcode == dns_rcode_nxdomain &&
   12039  1.10  christos 	    qctx->view->auth_nxdomain)
   12040   1.1  christos 	{
   12041   1.1  christos 		qctx->client->message->flags |= DNS_MESSAGEFLAG_AA;
   12042   1.1  christos 	}
   12043   1.1  christos 
   12044   1.1  christos 	/*
   12045   1.1  christos 	 * If the response is somehow unexpected for the client and this
   12046   1.1  christos 	 * is a result of recursion, return an error to the caller
   12047   1.1  christos 	 * to indicate it may need to be logged.
   12048   1.1  christos 	 */
   12049   1.1  christos 	if (qctx->resuming &&
   12050   1.1  christos 	    (ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
   12051   1.1  christos 	     qctx->client->message->rcode != dns_rcode_noerror))
   12052   1.1  christos 	{
   12053   1.1  christos 		qctx->result = ISC_R_FAILURE;
   12054   1.1  christos 	}
   12055   1.1  christos 
   12056   1.3  christos 	CALL_HOOK(NS_QUERY_DONE_SEND, qctx);
   12057   1.3  christos 
   12058  1.11  christos 	/*
   12059  1.11  christos 	 * Client may have been detached after query_send(), so
   12060  1.11  christos 	 * we test and store the flag state here, for safety.
   12061  1.11  christos 	 */
   12062  1.13  christos 	nodetach = qctx->client->nodetach;
   12063   1.1  christos 	query_send(qctx->client);
   12064  1.15  christos 
   12065  1.15  christos 	if (qctx->refresh_rrset) {
   12066  1.15  christos 		/*
   12067  1.15  christos 		 * If we reached this point then it means that we have found a
   12068  1.15  christos 		 * stale RRset entry in cache and BIND is configured to allow
   12069  1.15  christos 		 * queries to be answered with stale data if no active RRset
   12070  1.15  christos 		 * is available, i.e. "stale-anwer-client-timeout 0". But, we
   12071  1.15  christos 		 * still need to refresh the RRset. To prevent adding duplicate
   12072  1.15  christos 		 * RRsets, clear the RRsets from the message before doing the
   12073  1.15  christos 		 * refresh.
   12074  1.15  christos 		 */
   12075  1.15  christos 		message_clearrdataset(qctx->client->message, 0);
   12076  1.15  christos 		query_refresh_rrset(qctx);
   12077  1.15  christos 	}
   12078  1.15  christos 
   12079  1.13  christos 	if (!nodetach) {
   12080  1.11  christos 		qctx->detach_client = true;
   12081  1.11  christos 	}
   12082   1.1  christos 	return (qctx->result);
   12083   1.3  christos 
   12084   1.9  christos cleanup:
   12085   1.3  christos 	return (result);
   12086   1.1  christos }
   12087   1.1  christos 
   12088  1.15  christos static void
   12089   1.1  christos log_tat(ns_client_t *client) {
   12090   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   12091   1.1  christos 	char clientbuf[ISC_NETADDR_FORMATSIZE];
   12092   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   12093   1.1  christos 	isc_netaddr_t netaddr;
   12094   1.1  christos 	char *tags = NULL;
   12095   1.1  christos 	size_t taglen = 0;
   12096   1.1  christos 
   12097   1.1  christos 	if (!isc_log_wouldlog(ns_lctx, ISC_LOG_INFO)) {
   12098   1.1  christos 		return;
   12099   1.1  christos 	}
   12100   1.1  christos 
   12101   1.1  christos 	if ((client->query.qtype != dns_rdatatype_null ||
   12102   1.1  christos 	     !dns_name_istat(client->query.qname)) &&
   12103   1.1  christos 	    (client->keytag == NULL ||
   12104   1.1  christos 	     client->query.qtype != dns_rdatatype_dnskey))
   12105   1.1  christos 	{
   12106   1.1  christos 		return;
   12107   1.1  christos 	}
   12108   1.1  christos 
   12109   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   12110   1.1  christos 	dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
   12111   1.3  christos 	isc_netaddr_format(&netaddr, clientbuf, sizeof(clientbuf));
   12112   1.3  christos 	dns_rdataclass_format(client->view->rdclass, classbuf,
   12113   1.3  christos 			      sizeof(classbuf));
   12114   1.1  christos 
   12115   1.1  christos 	if (client->query.qtype == dns_rdatatype_dnskey) {
   12116   1.3  christos 		uint16_t keytags = client->keytag_len / 2;
   12117   1.1  christos 		size_t len = taglen = sizeof("65000") * keytags + 1;
   12118   1.1  christos 		char *cp = tags = isc_mem_get(client->mctx, taglen);
   12119   1.1  christos 		int i = 0;
   12120   1.1  christos 
   12121   1.1  christos 		INSIST(client->keytag != NULL);
   12122   1.1  christos 		if (tags != NULL) {
   12123   1.1  christos 			while (keytags-- > 0U) {
   12124   1.1  christos 				int n;
   12125   1.3  christos 				uint16_t keytag;
   12126   1.1  christos 				keytag = (client->keytag[i * 2] << 8) |
   12127   1.1  christos 					 client->keytag[i * 2 + 1];
   12128   1.1  christos 				n = snprintf(cp, len, " %u", keytag);
   12129   1.1  christos 				if (n > 0 && (size_t)n <= len) {
   12130   1.1  christos 					cp += n;
   12131   1.1  christos 					len -= n;
   12132   1.1  christos 					i++;
   12133   1.1  christos 				} else {
   12134   1.1  christos 					break;
   12135   1.1  christos 				}
   12136   1.1  christos 			}
   12137   1.1  christos 		}
   12138   1.1  christos 	}
   12139   1.1  christos 
   12140   1.1  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_TAT, NS_LOGMODULE_QUERY,
   12141   1.1  christos 		      ISC_LOG_INFO, "trust-anchor-telemetry '%s/%s' from %s%s",
   12142   1.9  christos 		      namebuf, classbuf, clientbuf, tags != NULL ? tags : "");
   12143   1.1  christos 	if (tags != NULL) {
   12144   1.1  christos 		isc_mem_put(client->mctx, tags, taglen);
   12145   1.1  christos 	}
   12146   1.1  christos }
   12147   1.1  christos 
   12148  1.15  christos static void
   12149   1.1  christos log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) {
   12150   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   12151   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   12152   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   12153   1.1  christos 	char onbuf[ISC_NETADDR_FORMATSIZE];
   12154   1.1  christos 	char ecsbuf[DNS_ECS_FORMATSIZE + sizeof(" [ECS ]") - 1] = { 0 };
   12155   1.1  christos 	char ednsbuf[sizeof("E(65535)")] = { 0 };
   12156   1.1  christos 	dns_rdataset_t *rdataset;
   12157   1.1  christos 	int level = ISC_LOG_INFO;
   12158   1.1  christos 
   12159   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   12160   1.1  christos 		return;
   12161   1.9  christos 	}
   12162   1.1  christos 
   12163   1.1  christos 	rdataset = ISC_LIST_HEAD(client->query.qname->list);
   12164   1.1  christos 	INSIST(rdataset != NULL);
   12165   1.1  christos 	dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
   12166   1.3  christos 	dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf));
   12167   1.3  christos 	dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
   12168   1.1  christos 	isc_netaddr_format(&client->destaddr, onbuf, sizeof(onbuf));
   12169   1.1  christos 
   12170   1.9  christos 	if (client->ednsversion >= 0) {
   12171   1.1  christos 		snprintf(ednsbuf, sizeof(ednsbuf), "E(%hd)",
   12172   1.1  christos 			 client->ednsversion);
   12173   1.9  christos 	}
   12174   1.1  christos 
   12175   1.1  christos 	if (HAVEECS(client)) {
   12176   1.1  christos 		strlcpy(ecsbuf, " [ECS ", sizeof(ecsbuf));
   12177   1.1  christos 		dns_ecs_format(&client->ecs, ecsbuf + 6, sizeof(ecsbuf) - 6);
   12178   1.1  christos 		strlcat(ecsbuf, "]", sizeof(ecsbuf));
   12179   1.1  christos 	}
   12180   1.1  christos 
   12181   1.9  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY, level,
   12182   1.9  christos 		      "query: %s %s %s %s%s%s%s%s%s%s (%s)%s", namebuf,
   12183   1.9  christos 		      classbuf, typebuf, WANTRECURSION(client) ? "+" : "-",
   12184   1.1  christos 		      (client->signer != NULL) ? "S" : "", ednsbuf,
   12185   1.1  christos 		      TCP(client) ? "T" : "",
   12186   1.1  christos 		      ((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) ? "D" : "",
   12187   1.1  christos 		      ((flags & DNS_MESSAGEFLAG_CD) != 0) ? "C" : "",
   12188  1.11  christos 		      HAVECOOKIE(client)   ? "V"
   12189  1.11  christos 		      : WANTCOOKIE(client) ? "K"
   12190  1.11  christos 					   : "",
   12191   1.1  christos 		      onbuf, ecsbuf);
   12192   1.1  christos }
   12193   1.1  christos 
   12194  1.15  christos static void
   12195   1.1  christos log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) {
   12196   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   12197   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   12198   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   12199   1.1  christos 	const char *namep, *typep, *classp, *sep1, *sep2;
   12200   1.1  christos 	dns_rdataset_t *rdataset;
   12201   1.1  christos 
   12202   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   12203   1.1  christos 		return;
   12204   1.9  christos 	}
   12205   1.1  christos 
   12206   1.1  christos 	namep = typep = classp = sep1 = sep2 = "";
   12207   1.1  christos 
   12208   1.1  christos 	/*
   12209   1.1  christos 	 * Query errors can happen for various reasons.  In some cases we cannot
   12210   1.1  christos 	 * even assume the query contains a valid question section, so we should
   12211   1.1  christos 	 * expect exceptional cases.
   12212   1.1  christos 	 */
   12213   1.1  christos 	if (client->query.origqname != NULL) {
   12214   1.1  christos 		dns_name_format(client->query.origqname, namebuf,
   12215   1.1  christos 				sizeof(namebuf));
   12216   1.1  christos 		namep = namebuf;
   12217   1.1  christos 		sep1 = " for ";
   12218   1.1  christos 
   12219   1.1  christos 		rdataset = ISC_LIST_HEAD(client->query.origqname->list);
   12220   1.1  christos 		if (rdataset != NULL) {
   12221   1.3  christos 			dns_rdataclass_format(rdataset->rdclass, classbuf,
   12222   1.3  christos 					      sizeof(classbuf));
   12223   1.3  christos 			classp = classbuf;
   12224   1.3  christos 			dns_rdatatype_format(rdataset->type, typebuf,
   12225   1.3  christos 					     sizeof(typebuf));
   12226   1.3  christos 			typep = typebuf;
   12227   1.1  christos 			sep2 = "/";
   12228   1.1  christos 		}
   12229   1.1  christos 	}
   12230   1.1  christos 
   12231   1.1  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS, NS_LOGMODULE_QUERY,
   12232   1.1  christos 		      level, "query failed (%s)%s%s%s%s%s%s at %s:%d",
   12233   1.9  christos 		      isc_result_totext(result), sep1, namep, sep2, classp,
   12234   1.9  christos 		      sep2, typep, __FILE__, line);
   12235   1.1  christos }
   12236   1.1  christos 
   12237   1.1  christos void
   12238  1.11  christos ns_query_start(ns_client_t *client, isc_nmhandle_t *handle) {
   12239   1.1  christos 	isc_result_t result;
   12240   1.8  christos 	dns_message_t *message;
   12241   1.1  christos 	dns_rdataset_t *rdataset;
   12242   1.1  christos 	dns_rdatatype_t qtype;
   12243   1.8  christos 	unsigned int saved_extflags;
   12244   1.8  christos 	unsigned int saved_flags;
   12245   1.1  christos 
   12246   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   12247   1.1  christos 
   12248  1.11  christos 	/*
   12249  1.11  christos 	 * Attach to the request handle
   12250  1.11  christos 	 */
   12251  1.11  christos 	isc_nmhandle_attach(handle, &client->reqhandle);
   12252  1.11  christos 
   12253   1.8  christos 	message = client->message;
   12254   1.8  christos 	saved_extflags = client->extflags;
   12255   1.8  christos 	saved_flags = client->message->flags;
   12256   1.8  christos 
   12257   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "ns_query_start");
   12258   1.1  christos 
   12259   1.1  christos 	/*
   12260   1.1  christos 	 * Ensure that appropriate cleanups occur.
   12261   1.1  christos 	 */
   12262   1.9  christos 	client->cleanup = query_cleanup;
   12263   1.1  christos 
   12264   1.9  christos 	if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) {
   12265   1.9  christos 		client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
   12266   1.1  christos 	}
   12267   1.1  christos 
   12268   1.9  christos 	if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0) {
   12269   1.1  christos 		client->attributes |= NS_CLIENTATTR_WANTDNSSEC;
   12270   1.9  christos 	}
   12271   1.1  christos 
   12272   1.1  christos 	switch (client->view->minimalresponses) {
   12273   1.1  christos 	case dns_minimal_no:
   12274   1.1  christos 		break;
   12275   1.1  christos 	case dns_minimal_yes:
   12276   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   12277   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   12278   1.1  christos 		break;
   12279   1.1  christos 	case dns_minimal_noauth:
   12280   1.1  christos 		client->query.attributes |= NS_QUERYATTR_NOAUTHORITY;
   12281   1.1  christos 		break;
   12282   1.1  christos 	case dns_minimal_noauthrec:
   12283   1.9  christos 		if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) {
   12284   1.1  christos 			client->query.attributes |= NS_QUERYATTR_NOAUTHORITY;
   12285   1.9  christos 		}
   12286   1.1  christos 		break;
   12287   1.1  christos 	}
   12288   1.1  christos 
   12289   1.1  christos 	if (client->view->cachedb == NULL || !client->view->recursion) {
   12290   1.1  christos 		/*
   12291   1.1  christos 		 * We don't have a cache.  Turn off cache support and
   12292   1.1  christos 		 * recursion.
   12293   1.1  christos 		 */
   12294   1.9  christos 		client->query.attributes &= ~(NS_QUERYATTR_RECURSIONOK |
   12295   1.9  christos 					      NS_QUERYATTR_CACHEOK);
   12296   1.1  christos 		client->attributes |= NS_CLIENTATTR_NOSETFC;
   12297   1.1  christos 	} else if ((client->attributes & NS_CLIENTATTR_RA) == 0 ||
   12298   1.9  christos 		   (message->flags & DNS_MESSAGEFLAG_RD) == 0)
   12299   1.9  christos 	{
   12300   1.1  christos 		/*
   12301   1.1  christos 		 * If the client isn't allowed to recurse (due to
   12302   1.1  christos 		 * "recursion no", the allow-recursion ACL, or the
   12303   1.1  christos 		 * lack of a resolver in this view), or if it
   12304   1.1  christos 		 * doesn't want recursion, turn recursion off.
   12305   1.1  christos 		 */
   12306   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
   12307   1.1  christos 		client->attributes |= NS_CLIENTATTR_NOSETFC;
   12308   1.1  christos 	}
   12309   1.1  christos 
   12310   1.1  christos 	/*
   12311   1.1  christos 	 * Check for multiple question queries, since edns1 is dead.
   12312   1.1  christos 	 */
   12313   1.1  christos 	if (message->counts[DNS_SECTION_QUESTION] > 1) {
   12314   1.1  christos 		query_error(client, DNS_R_FORMERR, __LINE__);
   12315   1.1  christos 		return;
   12316   1.1  christos 	}
   12317   1.1  christos 
   12318   1.1  christos 	/*
   12319   1.1  christos 	 * Get the question name.
   12320   1.1  christos 	 */
   12321   1.1  christos 	result = dns_message_firstname(message, DNS_SECTION_QUESTION);
   12322   1.1  christos 	if (result != ISC_R_SUCCESS) {
   12323   1.1  christos 		query_error(client, result, __LINE__);
   12324   1.1  christos 		return;
   12325   1.1  christos 	}
   12326   1.1  christos 	dns_message_currentname(message, DNS_SECTION_QUESTION,
   12327   1.1  christos 				&client->query.qname);
   12328   1.1  christos 	client->query.origqname = client->query.qname;
   12329   1.1  christos 	result = dns_message_nextname(message, DNS_SECTION_QUESTION);
   12330   1.1  christos 	if (result != ISC_R_NOMORE) {
   12331   1.1  christos 		if (result == ISC_R_SUCCESS) {
   12332   1.1  christos 			/*
   12333   1.1  christos 			 * There's more than one QNAME in the question
   12334   1.1  christos 			 * section.
   12335   1.1  christos 			 */
   12336   1.1  christos 			query_error(client, DNS_R_FORMERR, __LINE__);
   12337   1.9  christos 		} else {
   12338   1.1  christos 			query_error(client, result, __LINE__);
   12339   1.9  christos 		}
   12340   1.1  christos 		return;
   12341   1.1  christos 	}
   12342   1.1  christos 
   12343   1.9  christos 	if ((client->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
   12344   1.1  christos 		log_query(client, saved_flags, saved_extflags);
   12345   1.9  christos 	}
   12346   1.1  christos 
   12347   1.1  christos 	/*
   12348   1.1  christos 	 * Check for meta-queries like IXFR and AXFR.
   12349   1.1  christos 	 */
   12350   1.1  christos 	rdataset = ISC_LIST_HEAD(client->query.qname->list);
   12351   1.1  christos 	INSIST(rdataset != NULL);
   12352   1.1  christos 	client->query.qtype = qtype = rdataset->type;
   12353   1.1  christos 	dns_rdatatypestats_increment(client->sctx->rcvquerystats, qtype);
   12354   1.1  christos 
   12355   1.1  christos 	log_tat(client);
   12356   1.1  christos 
   12357   1.1  christos 	if (dns_rdatatype_ismeta(qtype)) {
   12358   1.1  christos 		switch (qtype) {
   12359   1.1  christos 		case dns_rdatatype_any:
   12360   1.1  christos 			break; /* Let the query logic handle it. */
   12361   1.1  christos 		case dns_rdatatype_ixfr:
   12362   1.1  christos 		case dns_rdatatype_axfr:
   12363  1.20  christos 			if (isc_nm_is_http_handle(handle)) {
   12364  1.20  christos 				/*
   12365  1.20  christos 				 * We cannot use DoH for zone transfers.
   12366  1.20  christos 				 * According to RFC 8484 a DoH request contains
   12367  1.20  christos 				 * exactly one DNS message (see Section 6:
   12368  1.20  christos 				 * Definition of the "application/dns-message"
   12369  1.20  christos 				 * Media Type).
   12370  1.20  christos 				 *
   12371  1.20  christos 				 * This makes DoH unsuitable for zone transfers
   12372  1.20  christos 				 * as often (and usually!) these need more than
   12373  1.20  christos 				 * one DNS message, especially for larger zones.
   12374  1.20  christos 				 * As zone transfers over DoH are not (yet)
   12375  1.20  christos 				 * standardised, nor discussed in RFC 8484,
   12376  1.20  christos 				 * the best thing we can do is to return "not
   12377  1.20  christos 				 * implemented".
   12378  1.20  christos 				 */
   12379  1.20  christos 				query_error(client, DNS_R_NOTIMP, __LINE__);
   12380  1.20  christos 				return;
   12381  1.20  christos 			}
   12382  1.20  christos 			if (isc_nm_socket_type(handle) == isc_nm_tlsdnssocket) {
   12383  1.20  christos 				/*
   12384  1.20  christos 				 * Currently this code is here for DoT, which
   12385  1.20  christos 				 * has more complex requirements for zone
   12386  1.20  christos 				 * transfers compared to other stream
   12387  1.20  christos 				 * protocols. See RFC 9103 for details.
   12388  1.20  christos 				 */
   12389  1.20  christos 				switch (isc_nm_xfr_checkperm(handle)) {
   12390  1.20  christos 				case ISC_R_SUCCESS:
   12391  1.20  christos 					break;
   12392  1.20  christos 				case ISC_R_DOTALPNERROR:
   12393  1.20  christos 					query_error(client, DNS_R_NOALPN,
   12394  1.20  christos 						    __LINE__);
   12395  1.20  christos 					return;
   12396  1.20  christos 				default:
   12397  1.20  christos 					query_error(client, DNS_R_REFUSED,
   12398  1.20  christos 						    __LINE__);
   12399  1.20  christos 					return;
   12400  1.20  christos 				}
   12401  1.20  christos 			}
   12402   1.1  christos 			ns_xfr_start(client, rdataset->type);
   12403   1.1  christos 			return;
   12404   1.1  christos 		case dns_rdatatype_maila:
   12405   1.1  christos 		case dns_rdatatype_mailb:
   12406   1.1  christos 			query_error(client, DNS_R_NOTIMP, __LINE__);
   12407   1.1  christos 			return;
   12408   1.1  christos 		case dns_rdatatype_tkey:
   12409   1.9  christos 			result = dns_tkey_processquery(
   12410   1.9  christos 				client->message, client->sctx->tkeyctx,
   12411   1.9  christos 				client->view->dynamickeys);
   12412   1.9  christos 			if (result == ISC_R_SUCCESS) {
   12413   1.1  christos 				query_send(client);
   12414   1.9  christos 			} else {
   12415   1.1  christos 				query_error(client, result, __LINE__);
   12416   1.9  christos 			}
   12417   1.1  christos 			return;
   12418   1.1  christos 		default: /* TSIG, etc. */
   12419   1.1  christos 			query_error(client, DNS_R_FORMERR, __LINE__);
   12420   1.1  christos 			return;
   12421   1.1  christos 		}
   12422   1.1  christos 	}
   12423   1.1  christos 
   12424   1.1  christos 	/*
   12425   1.1  christos 	 * Turn on minimal response for (C)DNSKEY and (C)DS queries.
   12426   1.1  christos 	 */
   12427  1.22  christos 	if (dns_rdatatype_iskeymaterial(qtype) || qtype == dns_rdatatype_ds) {
   12428   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   12429   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   12430  1.11  christos 	} else if (qtype == dns_rdatatype_ns) {
   12431  1.11  christos 		/*
   12432  1.11  christos 		 * Always turn on additional records for NS queries.
   12433  1.11  christos 		 */
   12434  1.11  christos 		client->query.attributes &= ~(NS_QUERYATTR_NOAUTHORITY |
   12435  1.11  christos 					      NS_QUERYATTR_NOADDITIONAL);
   12436   1.1  christos 	}
   12437   1.1  christos 
   12438   1.1  christos 	/*
   12439   1.1  christos 	 * Maybe turn on minimal responses for ANY queries.
   12440   1.1  christos 	 */
   12441   1.9  christos 	if (qtype == dns_rdatatype_any && client->view->minimal_any &&
   12442  1.16  christos 	    !TCP(client))
   12443  1.16  christos 	{
   12444   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   12445   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   12446   1.9  christos 	}
   12447   1.1  christos 
   12448   1.1  christos 	/*
   12449   1.1  christos 	 * Turn on minimal responses for EDNS/UDP bufsize 512 queries.
   12450   1.1  christos 	 */
   12451   1.1  christos 	if (client->ednsversion >= 0 && client->udpsize <= 512U && !TCP(client))
   12452   1.9  christos 	{
   12453   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   12454   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   12455   1.9  christos 	}
   12456   1.1  christos 
   12457   1.1  christos 	/*
   12458   1.1  christos 	 * If the client has requested that DNSSEC checking be disabled,
   12459   1.1  christos 	 * allow lookups to return pending data and instruct the resolver
   12460   1.1  christos 	 * to return data before validation has completed.
   12461   1.1  christos 	 *
   12462   1.1  christos 	 * We don't need to set DNS_DBFIND_PENDINGOK when validation is
   12463   1.1  christos 	 * disabled as there will be no pending data.
   12464   1.1  christos 	 */
   12465   1.3  christos 	if ((message->flags & DNS_MESSAGEFLAG_CD) != 0 ||
   12466  1.16  christos 	    qtype == dns_rdatatype_rrsig)
   12467  1.16  christos 	{
   12468   1.1  christos 		client->query.dboptions |= DNS_DBFIND_PENDINGOK;
   12469   1.1  christos 		client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
   12470   1.9  christos 	} else if (!client->view->enablevalidation) {
   12471   1.1  christos 		client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
   12472   1.9  christos 	}
   12473   1.1  christos 
   12474   1.3  christos 	if (client->view->qminimization) {
   12475   1.3  christos 		client->query.fetchoptions |= DNS_FETCHOPT_QMINIMIZE |
   12476   1.9  christos 					      DNS_FETCHOPT_QMIN_SKIP_IP6A;
   12477   1.3  christos 		if (client->view->qmin_strict) {
   12478   1.3  christos 			client->query.fetchoptions |= DNS_FETCHOPT_QMIN_STRICT;
   12479   1.3  christos 		}
   12480   1.3  christos 	}
   12481   1.3  christos 
   12482   1.1  christos 	/*
   12483   1.1  christos 	 * Allow glue NS records to be added to the authority section
   12484   1.1  christos 	 * if the answer is secure.
   12485   1.1  christos 	 */
   12486   1.3  christos 	if ((message->flags & DNS_MESSAGEFLAG_CD) != 0) {
   12487   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   12488   1.3  christos 	}
   12489   1.1  christos 
   12490   1.1  christos 	/*
   12491   1.1  christos 	 * Set NS_CLIENTATTR_WANTAD if the client has set AD in the query.
   12492   1.1  christos 	 * This allows AD to be returned on queries without DO set.
   12493   1.1  christos 	 */
   12494   1.9  christos 	if ((message->flags & DNS_MESSAGEFLAG_AD) != 0) {
   12495   1.1  christos 		client->attributes |= NS_CLIENTATTR_WANTAD;
   12496   1.9  christos 	}
   12497   1.1  christos 
   12498   1.1  christos 	/*
   12499   1.1  christos 	 * This is an ordinary query.
   12500   1.1  christos 	 */
   12501   1.3  christos 	result = dns_message_reply(message, true);
   12502   1.1  christos 	if (result != ISC_R_SUCCESS) {
   12503   1.1  christos 		query_next(client, result);
   12504   1.1  christos 		return;
   12505   1.1  christos 	}
   12506   1.1  christos 
   12507   1.1  christos 	/*
   12508   1.1  christos 	 * Assume authoritative response until it is known to be
   12509   1.1  christos 	 * otherwise.
   12510   1.1  christos 	 *
   12511   1.1  christos 	 * If "-T noaa" has been set on the command line don't set
   12512   1.1  christos 	 * AA on authoritative answers.
   12513   1.1  christos 	 */
   12514   1.9  christos 	if ((client->sctx->options & NS_SERVER_NOAA) == 0) {
   12515   1.1  christos 		message->flags |= DNS_MESSAGEFLAG_AA;
   12516   1.9  christos 	}
   12517   1.1  christos 
   12518   1.1  christos 	/*
   12519   1.1  christos 	 * Set AD.  We must clear it if we add non-validated data to a
   12520   1.1  christos 	 * response.
   12521   1.1  christos 	 */
   12522   1.9  christos 	if (WANTDNSSEC(client) || WANTAD(client)) {
   12523   1.1  christos 		message->flags |= DNS_MESSAGEFLAG_AD;
   12524   1.9  christos 	}
   12525   1.1  christos 
   12526   1.9  christos 	(void)query_setup(client, qtype);
   12527   1.1  christos }
   12528