Home | History | Annotate | Line # | Download | only in ns
query.c revision 1.18
      1  1.18  christos /*	$NetBSD: query.c,v 1.18 2024/02/13 15:22:03 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.1  christos #include <isc/rwlock.h>
     29   1.1  christos #include <isc/serial.h>
     30   1.1  christos #include <isc/stats.h>
     31   1.1  christos #include <isc/string.h>
     32   1.1  christos #include <isc/thread.h>
     33   1.1  christos #include <isc/util.h>
     34   1.1  christos 
     35   1.1  christos #include <dns/adb.h>
     36   1.1  christos #include <dns/badcache.h>
     37   1.1  christos #include <dns/byaddr.h>
     38   1.1  christos #include <dns/cache.h>
     39   1.1  christos #include <dns/db.h>
     40   1.1  christos #include <dns/dlz.h>
     41   1.1  christos #include <dns/dns64.h>
     42   1.1  christos #include <dns/dnsrps.h>
     43   1.1  christos #include <dns/dnssec.h>
     44   1.1  christos #include <dns/events.h>
     45   1.1  christos #include <dns/keytable.h>
     46   1.1  christos #include <dns/message.h>
     47   1.1  christos #include <dns/ncache.h>
     48   1.1  christos #include <dns/nsec.h>
     49   1.1  christos #include <dns/nsec3.h>
     50   1.1  christos #include <dns/order.h>
     51   1.1  christos #include <dns/rdata.h>
     52   1.1  christos #include <dns/rdataclass.h>
     53   1.1  christos #include <dns/rdatalist.h>
     54   1.1  christos #include <dns/rdataset.h>
     55   1.1  christos #include <dns/rdatasetiter.h>
     56   1.1  christos #include <dns/rdatastruct.h>
     57   1.1  christos #include <dns/rdatatype.h>
     58   1.1  christos #include <dns/resolver.h>
     59   1.1  christos #include <dns/result.h>
     60   1.1  christos #include <dns/stats.h>
     61   1.1  christos #include <dns/tkey.h>
     62   1.1  christos #include <dns/types.h>
     63   1.1  christos #include <dns/view.h>
     64   1.1  christos #include <dns/zone.h>
     65   1.1  christos #include <dns/zt.h>
     66   1.1  christos 
     67   1.1  christos #include <ns/client.h>
     68   1.9  christos #include <ns/hooks.h>
     69   1.1  christos #include <ns/interfacemgr.h>
     70   1.1  christos #include <ns/log.h>
     71   1.1  christos #include <ns/server.h>
     72   1.1  christos #include <ns/sortlist.h>
     73   1.1  christos #include <ns/stats.h>
     74   1.1  christos #include <ns/xfrout.h>
     75   1.1  christos 
     76   1.7  christos #include <ns/pfilter.h>
     77   1.7  christos 
     78   1.1  christos #if 0
     79   1.1  christos /*
     80   1.1  christos  * It has been recommended that DNS64 be changed to return excluded
     81   1.1  christos  * AAAA addresses if DNS64 synthesis does not occur.  This minimises
     82   1.1  christos  * the impact on the lookup results.  While most DNS AAAA lookups are
     83   1.1  christos  * done to send IP packets to a host, not all of them are and filtering
     84   1.1  christos  * excluded addresses has a negative impact on those uses.
     85   1.1  christos  */
     86   1.1  christos #define dns64_bis_return_excluded_addresses 1
     87   1.9  christos #endif /* if 0 */
     88   1.1  christos 
     89   1.1  christos /*%
     90   1.1  christos  * Maximum number of chained queries before we give up
     91   1.1  christos  * to prevent CNAME loops.
     92   1.1  christos  */
     93   1.1  christos #define MAX_RESTARTS 16
     94   1.1  christos 
     95  1.11  christos #define QUERY_ERROR(qctx, r)                  \
     96  1.11  christos 	do {                                  \
     97  1.11  christos 		(qctx)->result = r;           \
     98  1.11  christos 		(qctx)->want_restart = false; \
     99  1.11  christos 		(qctx)->line = __LINE__;      \
    100  1.12    rillig 	} while (0)
    101   1.1  christos 
    102   1.1  christos /*% Partial answer? */
    103   1.9  christos #define PARTIALANSWER(c) \
    104   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_PARTIALANSWER) != 0)
    105   1.1  christos /*% Use Cache? */
    106   1.9  christos #define USECACHE(c) (((c)->query.attributes & NS_QUERYATTR_CACHEOK) != 0)
    107   1.1  christos /*% Recursion OK? */
    108   1.9  christos #define RECURSIONOK(c) (((c)->query.attributes & NS_QUERYATTR_RECURSIONOK) != 0)
    109   1.1  christos /*% Recursing? */
    110   1.9  christos #define RECURSING(c) (((c)->query.attributes & NS_QUERYATTR_RECURSING) != 0)
    111   1.1  christos /*% Want Recursion? */
    112   1.9  christos #define WANTRECURSION(c) \
    113   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_WANTRECURSION) != 0)
    114   1.1  christos /*% Is TCP? */
    115   1.9  christos #define TCP(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0)
    116   1.1  christos 
    117   1.1  christos /*% Want DNSSEC? */
    118   1.9  christos #define WANTDNSSEC(c) (((c)->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0)
    119   1.1  christos /*% Want WANTAD? */
    120   1.9  christos #define WANTAD(c) (((c)->attributes & NS_CLIENTATTR_WANTAD) != 0)
    121   1.1  christos /*% Client presented a valid COOKIE. */
    122   1.9  christos #define HAVECOOKIE(c) (((c)->attributes & NS_CLIENTATTR_HAVECOOKIE) != 0)
    123   1.1  christos /*% Client presented a COOKIE. */
    124   1.9  christos #define WANTCOOKIE(c) (((c)->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0)
    125   1.1  christos /*% Client presented a CLIENT-SUBNET option. */
    126   1.9  christos #define HAVEECS(c) (((c)->attributes & NS_CLIENTATTR_HAVEECS) != 0)
    127   1.1  christos /*% No authority? */
    128   1.9  christos #define NOAUTHORITY(c) (((c)->query.attributes & NS_QUERYATTR_NOAUTHORITY) != 0)
    129   1.1  christos /*% No additional? */
    130   1.9  christos #define NOADDITIONAL(c) \
    131   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_NOADDITIONAL) != 0)
    132   1.1  christos /*% Secure? */
    133   1.9  christos #define SECURE(c) (((c)->query.attributes & NS_QUERYATTR_SECURE) != 0)
    134   1.1  christos /*% DNS64 A lookup? */
    135   1.9  christos #define DNS64(c) (((c)->query.attributes & NS_QUERYATTR_DNS64) != 0)
    136   1.1  christos 
    137   1.9  christos #define DNS64EXCLUDE(c) \
    138   1.9  christos 	(((c)->query.attributes & NS_QUERYATTR_DNS64EXCLUDE) != 0)
    139   1.1  christos 
    140   1.9  christos #define REDIRECT(c) (((c)->query.attributes & NS_QUERYATTR_REDIRECT) != 0)
    141   1.1  christos 
    142  1.14  christos /*% Was the client already sent a response? */
    143  1.11  christos #define QUERY_ANSWERED(q) (((q)->attributes & NS_QUERYATTR_ANSWERED) != 0)
    144  1.11  christos 
    145  1.14  christos /*% Have we already processed an answer via stale-answer-client-timeout? */
    146  1.14  christos #define QUERY_STALEPENDING(q) \
    147  1.14  christos 	(((q)->attributes & NS_QUERYATTR_STALEPENDING) != 0)
    148  1.14  christos 
    149  1.13  christos /*% Does the query allow stale data in the response? */
    150  1.13  christos #define QUERY_STALEOK(q) (((q)->attributes & NS_QUERYATTR_STALEOK) != 0)
    151  1.13  christos 
    152  1.13  christos /*% Does the query wants to check for stale RRset due to a timeout? */
    153  1.13  christos #define QUERY_STALETIMEOUT(q) (((q)->dboptions & DNS_DBFIND_STALETIMEOUT) != 0)
    154  1.11  christos 
    155   1.1  christos /*% Does the rdataset 'r' have an attached 'No QNAME Proof'? */
    156   1.9  christos #define NOQNAME(r) (((r)->attributes & DNS_RDATASETATTR_NOQNAME) != 0)
    157   1.1  christos 
    158   1.4  christos /*% Does the rdataset 'r' contain a stale answer? */
    159   1.9  christos #define STALE(r) (((r)->attributes & DNS_RDATASETATTR_STALE) != 0)
    160   1.1  christos 
    161  1.11  christos /*% Does the rdataset 'r' is stale and within stale-refresh-time? */
    162  1.11  christos #define STALE_WINDOW(r) (((r)->attributes & DNS_RDATASETATTR_STALE_WINDOW) != 0)
    163  1.11  christos 
    164   1.1  christos #ifdef WANT_QUERYTRACE
    165  1.15  christos static void
    166   1.1  christos client_trace(ns_client_t *client, int level, const char *message) {
    167   1.1  christos 	if (client != NULL && client->query.qname != NULL) {
    168   1.1  christos 		if (isc_log_wouldlog(ns_lctx, level)) {
    169   1.1  christos 			char qbuf[DNS_NAME_FORMATSIZE];
    170   1.1  christos 			char tbuf[DNS_RDATATYPE_FORMATSIZE];
    171   1.9  christos 			dns_name_format(client->query.qname, qbuf,
    172   1.9  christos 					sizeof(qbuf));
    173   1.9  christos 			dns_rdatatype_format(client->query.qtype, tbuf,
    174   1.9  christos 					     sizeof(tbuf));
    175   1.9  christos 			isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT,
    176   1.1  christos 				      NS_LOGMODULE_QUERY, level,
    177  1.13  christos 				      "query client=%p thread=0x%" PRIxPTR
    178   1.1  christos 				      "(%s/%s): %s",
    179  1.13  christos 				      client, isc_thread_self(), qbuf, tbuf,
    180  1.13  christos 				      message);
    181   1.1  christos 		}
    182   1.9  christos 	} else {
    183   1.9  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT,
    184   1.1  christos 			      NS_LOGMODULE_QUERY, level,
    185  1.13  christos 			      "query client=%p thread=0x%" PRIxPTR
    186   1.1  christos 			      "(<unknown-query>): %s",
    187  1.13  christos 			      client, isc_thread_self(), message);
    188   1.1  christos 	}
    189   1.1  christos }
    190   1.9  christos #define CTRACE(l, m)  client_trace(client, l, m)
    191   1.9  christos #define CCTRACE(l, m) client_trace(qctx->client, l, m)
    192   1.9  christos #else /* ifdef WANT_QUERYTRACE */
    193   1.9  christos #define CTRACE(l, m)  ((void)m)
    194   1.9  christos #define CCTRACE(l, m) ((void)m)
    195   1.1  christos #endif /* WANT_QUERYTRACE */
    196   1.1  christos 
    197  1.11  christos #define DNS_GETDB_NOEXACT    0x01U
    198  1.11  christos #define DNS_GETDB_NOLOG	     0x02U
    199  1.11  christos #define DNS_GETDB_PARTIAL    0x04U
    200  1.11  christos #define DNS_GETDB_IGNOREACL  0x08U
    201  1.11  christos #define DNS_GETDB_STALEFIRST 0X0CU
    202   1.1  christos 
    203   1.9  christos #define PENDINGOK(x) (((x)&DNS_DBFIND_PENDINGOK) != 0)
    204   1.1  christos 
    205   1.1  christos #define SFCACHE_CDFLAG 0x1
    206   1.1  christos 
    207   1.1  christos /*
    208   1.1  christos  * These have the same semantics as:
    209   1.1  christos  *
    210   1.1  christos  * 	foo_attach(b, a);
    211   1.1  christos  *	foo_detach(&a);
    212   1.1  christos  *
    213   1.1  christos  * without the locking and magic testing.
    214   1.1  christos  *
    215   1.1  christos  * We use SAVE and RESTORE as that shows the operation being performed.
    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.3  christos /*
    250   1.3  christos  * Return the hooktable in use with 'qctx', or if there isn't one
    251   1.3  christos  * set, return the default hooktable.
    252   1.3  christos  */
    253  1.15  christos static ns_hooktable_t *
    254   1.3  christos get_hooktab(query_ctx_t *qctx) {
    255   1.9  christos 	if (qctx == NULL || qctx->view == NULL || qctx->view->hooktable == NULL)
    256   1.3  christos 	{
    257   1.3  christos 		return (ns__hook_table);
    258   1.3  christos 	}
    259   1.1  christos 
    260   1.3  christos 	return (qctx->view->hooktable);
    261   1.3  christos }
    262   1.1  christos 
    263   1.3  christos /*
    264   1.3  christos  * Call the specified hook function in every configured module that implements
    265   1.3  christos  * that function. If any hook function returns NS_HOOK_RETURN, we
    266   1.3  christos  * set 'result' and terminate processing by jumping to the 'cleanup' tag.
    267   1.3  christos  *
    268   1.3  christos  * (Note that a hook function may set the 'result' to ISC_R_SUCCESS but
    269   1.3  christos  * still terminate processing within the calling function. That's why this
    270  1.15  christos  * is a macro instead of a static function; it needs to be able to use
    271   1.3  christos  * 'goto cleanup' regardless of the return value.)
    272   1.3  christos  */
    273   1.9  christos #define CALL_HOOK(_id, _qctx)                                       \
    274   1.9  christos 	do {                                                        \
    275   1.9  christos 		isc_result_t _res;                                  \
    276   1.9  christos 		ns_hooktable_t *_tab = get_hooktab(_qctx);          \
    277   1.9  christos 		ns_hook_t *_hook;                                   \
    278   1.9  christos 		_hook = ISC_LIST_HEAD((*_tab)[_id]);                \
    279   1.9  christos 		while (_hook != NULL) {                             \
    280   1.9  christos 			ns_hook_action_t _func = _hook->action;     \
    281   1.9  christos 			void *_data = _hook->action_data;           \
    282   1.9  christos 			INSIST(_func != NULL);                      \
    283   1.9  christos 			switch (_func(_qctx, _data, &_res)) {       \
    284   1.9  christos 			case NS_HOOK_CONTINUE:                      \
    285   1.9  christos 				_hook = ISC_LIST_NEXT(_hook, link); \
    286   1.9  christos 				break;                              \
    287   1.9  christos 			case NS_HOOK_RETURN:                        \
    288   1.9  christos 				result = _res;                      \
    289   1.9  christos 				goto cleanup;                       \
    290   1.9  christos 			default:                                    \
    291  1.15  christos 				UNREACHABLE();                      \
    292   1.9  christos 			}                                           \
    293   1.9  christos 		}                                                   \
    294   1.3  christos 	} while (false)
    295   1.1  christos 
    296   1.3  christos /*
    297   1.3  christos  * Call the specified hook function in every configured module that
    298   1.3  christos  * implements that function. All modules are called; hook function return
    299   1.3  christos  * codes are ignored. This is intended for use with initialization and
    300   1.3  christos  * destruction calls which *must* run in every configured module.
    301   1.3  christos  *
    302  1.15  christos  * (This could be implemented as a static void function, but is left as a
    303   1.3  christos  * macro for symmetry with CALL_HOOK above.)
    304   1.3  christos  */
    305   1.9  christos #define CALL_HOOK_NORETURN(_id, _qctx)                          \
    306   1.9  christos 	do {                                                    \
    307   1.9  christos 		isc_result_t _res;                              \
    308   1.9  christos 		ns_hooktable_t *_tab = get_hooktab(_qctx);      \
    309   1.9  christos 		ns_hook_t *_hook;                               \
    310   1.9  christos 		_hook = ISC_LIST_HEAD((*_tab)[_id]);            \
    311   1.9  christos 		while (_hook != NULL) {                         \
    312   1.9  christos 			ns_hook_action_t _func = _hook->action; \
    313   1.9  christos 			void *_data = _hook->action_data;       \
    314   1.9  christos 			INSIST(_func != NULL);                  \
    315   1.9  christos 			_func(_qctx, _data, &_res);             \
    316   1.9  christos 			_hook = ISC_LIST_NEXT(_hook, link);     \
    317   1.9  christos 		}                                               \
    318   1.3  christos 	} while (false)
    319   1.1  christos 
    320   1.1  christos /*
    321   1.1  christos  * The functions defined below implement the query logic that previously lived
    322   1.1  christos  * in the single very complex function query_find().  The query_ctx_t structure
    323   1.1  christos  * defined in <ns/query.h> maintains state from function to function.  The call
    324   1.1  christos  * flow for the general query processing algorithm is described below:
    325   1.1  christos  *
    326   1.1  christos  * 1. Set up query context and other resources for a client
    327   1.1  christos  *    query (query_setup())
    328   1.1  christos  *
    329   1.1  christos  * 2. Start the search (ns__query_start())
    330   1.1  christos  *
    331   1.1  christos  * 3. Identify authoritative data sources which may have an answer;
    332   1.1  christos  *    search them (query_lookup()). If an answer is found, go to 7.
    333   1.1  christos  *
    334   1.1  christos  * 4. If recursion or cache access are allowed, search the cache
    335   1.1  christos  *    (query_lookup() again, using the cache database) to find a better
    336   1.1  christos  *    answer. If an answer is found, go to 7.
    337   1.1  christos  *
    338   1.3  christos  * 5. If recursion is allowed, begin recursion (ns_query_recurse()).
    339   1.1  christos  *    Go to 15 to clean up this phase of the query. When recursion
    340   1.1  christos  *    is complete, processing will resume at 6.
    341   1.1  christos  *
    342   1.1  christos  * 6. Resume from recursion; set up query context for resumed processing.
    343   1.1  christos  *
    344   1.1  christos  * 7. Determine what sort of answer we've found (query_gotanswer())
    345   1.1  christos  *    and call other functions accordingly:
    346   1.1  christos  *      - not found (auth or cache), go to 8
    347   1.1  christos  *      - delegation, go to 9
    348   1.1  christos  *      - no such domain (auth), go to 10
    349   1.1  christos  *      - empty answer (auth), go to 11
    350   1.1  christos  *      - negative response (cache), go to 12
    351   1.1  christos  *      - answer found, go to 13
    352   1.1  christos  *
    353   1.1  christos  * 8. The answer was not found in the database (query_notfound().
    354   1.1  christos  *    Set up a referral and go to 9.
    355   1.1  christos  *
    356   1.3  christos  * 9. Handle a delegation response (query_delegation()). If we need
    357   1.3  christos  *    to and are allowed to recurse (query_delegation_recurse()), go to 5,
    358   1.3  christos  *    otherwise go to 15 to clean up and return the delegation to the client.
    359   1.1  christos  *
    360   1.1  christos  * 10. No such domain (query_nxdomain()). Attempt redirection; if
    361   1.1  christos  *     unsuccessful, add authority section records (query_addsoa(),
    362   1.1  christos  *     query_addauth()), then go to 15 to return NXDOMAIN to client.
    363   1.1  christos  *
    364   1.1  christos  * 11. Empty answer (query_nodata()). Add authority section records
    365   1.1  christos  *     (query_addsoa(), query_addauth()) and signatures if authoritative
    366   1.1  christos  *     (query_sign_nodata()) then go to 15 and return
    367   1.1  christos  *     NOERROR/ANCOUNT=0 to client.
    368   1.1  christos  *
    369   1.1  christos  * 12. No such domain or empty answer returned from cache (query_ncache()).
    370   1.1  christos  *     Set response code appropriately, go to 11.
    371   1.1  christos  *
    372   1.1  christos  * 13. Prepare a response (query_prepresponse()) and then fill it
    373   1.1  christos  *     appropriately (query_respond(), or for type ANY,
    374   1.1  christos  *     query_respond_any()).
    375   1.1  christos  *
    376   1.1  christos  * 14. If a restart is needed due to CNAME/DNAME chaining, go to 2.
    377   1.1  christos  *
    378   1.1  christos  * 15. Clean up resources. If recursing, stop and wait for the event
    379   1.1  christos  *     handler to be called back (step 6).  If an answer is ready,
    380   1.1  christos  *     return it to the client.
    381   1.1  christos  *
    382   1.1  christos  * (XXX: This description omits several special cases including
    383   1.3  christos  * DNS64, RPZ, RRL, and the SERVFAIL cache. It also doesn't discuss
    384   1.3  christos  * plugins.)
    385   1.1  christos  */
    386   1.1  christos 
    387   1.1  christos static void
    388   1.1  christos query_trace(query_ctx_t *qctx);
    389   1.1  christos 
    390   1.1  christos static void
    391  1.11  christos qctx_init(ns_client_t *client, dns_fetchevent_t **eventp, dns_rdatatype_t qtype,
    392   1.9  christos 	  query_ctx_t *qctx);
    393   1.1  christos 
    394   1.1  christos static isc_result_t
    395   1.1  christos query_setup(ns_client_t *client, dns_rdatatype_t qtype);
    396   1.1  christos 
    397   1.1  christos static isc_result_t
    398   1.1  christos query_lookup(query_ctx_t *qctx);
    399   1.1  christos 
    400   1.1  christos static void
    401   1.1  christos fetch_callback(isc_task_t *task, isc_event_t *event);
    402   1.1  christos 
    403   1.1  christos static void
    404   1.1  christos recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
    405   1.1  christos 		const dns_name_t *qname, const dns_name_t *qdomain);
    406   1.1  christos 
    407   1.1  christos static isc_result_t
    408   1.1  christos query_resume(query_ctx_t *qctx);
    409   1.1  christos 
    410   1.1  christos static isc_result_t
    411   1.1  christos query_checkrrl(query_ctx_t *qctx, isc_result_t result);
    412   1.1  christos 
    413   1.1  christos static isc_result_t
    414   1.1  christos query_checkrpz(query_ctx_t *qctx, isc_result_t result);
    415   1.1  christos 
    416   1.1  christos static isc_result_t
    417   1.1  christos query_rpzcname(query_ctx_t *qctx, dns_name_t *cname);
    418   1.1  christos 
    419   1.1  christos static isc_result_t
    420   1.1  christos query_gotanswer(query_ctx_t *qctx, isc_result_t result);
    421   1.1  christos 
    422   1.1  christos static void
    423   1.1  christos query_addnoqnameproof(query_ctx_t *qctx);
    424   1.1  christos 
    425   1.1  christos static isc_result_t
    426   1.1  christos query_respond_any(query_ctx_t *qctx);
    427   1.1  christos 
    428   1.1  christos static isc_result_t
    429   1.1  christos query_respond(query_ctx_t *qctx);
    430   1.1  christos 
    431   1.1  christos static isc_result_t
    432   1.1  christos query_dns64(query_ctx_t *qctx);
    433   1.1  christos 
    434   1.1  christos static void
    435   1.1  christos query_filter64(query_ctx_t *qctx);
    436   1.1  christos 
    437   1.1  christos static isc_result_t
    438   1.1  christos query_notfound(query_ctx_t *qctx);
    439   1.1  christos 
    440   1.1  christos static isc_result_t
    441   1.1  christos query_zone_delegation(query_ctx_t *qctx);
    442   1.1  christos 
    443   1.1  christos static isc_result_t
    444   1.1  christos query_delegation(query_ctx_t *qctx);
    445   1.1  christos 
    446   1.3  christos static isc_result_t
    447   1.3  christos query_delegation_recurse(query_ctx_t *qctx);
    448   1.3  christos 
    449   1.1  christos static void
    450   1.1  christos query_addds(query_ctx_t *qctx);
    451   1.1  christos 
    452   1.1  christos static isc_result_t
    453   1.1  christos query_nodata(query_ctx_t *qctx, isc_result_t result);
    454   1.1  christos 
    455   1.1  christos static isc_result_t
    456   1.1  christos query_sign_nodata(query_ctx_t *qctx);
    457   1.1  christos 
    458   1.1  christos static void
    459   1.1  christos query_addnxrrsetnsec(query_ctx_t *qctx);
    460   1.1  christos 
    461   1.1  christos static isc_result_t
    462  1.18  christos query_nxdomain(query_ctx_t *qctx, isc_result_t result);
    463   1.1  christos 
    464   1.1  christos static isc_result_t
    465  1.18  christos query_redirect(query_ctx_t *qctx, isc_result_t result);
    466   1.1  christos 
    467   1.1  christos static isc_result_t
    468   1.1  christos query_ncache(query_ctx_t *qctx, isc_result_t result);
    469   1.1  christos 
    470   1.1  christos static isc_result_t
    471   1.1  christos query_coveringnsec(query_ctx_t *qctx);
    472   1.1  christos 
    473   1.1  christos static isc_result_t
    474   1.3  christos query_zerottl_refetch(query_ctx_t *qctx);
    475   1.3  christos 
    476   1.3  christos static isc_result_t
    477   1.1  christos query_cname(query_ctx_t *qctx);
    478   1.1  christos 
    479   1.1  christos static isc_result_t
    480   1.1  christos query_dname(query_ctx_t *qctx);
    481   1.1  christos 
    482   1.1  christos static isc_result_t
    483   1.1  christos query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl);
    484   1.1  christos 
    485   1.1  christos static isc_result_t
    486   1.1  christos query_prepresponse(query_ctx_t *qctx);
    487   1.1  christos 
    488   1.1  christos static isc_result_t
    489   1.1  christos query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
    490   1.1  christos 	     dns_section_t section);
    491   1.1  christos 
    492   1.1  christos static isc_result_t
    493   1.1  christos query_addns(query_ctx_t *qctx);
    494   1.1  christos 
    495   1.1  christos static void
    496   1.1  christos query_addbestns(query_ctx_t *qctx);
    497   1.1  christos 
    498   1.1  christos static void
    499   1.3  christos query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata);
    500   1.1  christos 
    501   1.1  christos static void
    502   1.1  christos query_addauth(query_ctx_t *qctx);
    503   1.1  christos 
    504  1.13  christos static void
    505  1.13  christos query_clear_stale(ns_client_t *client);
    506  1.13  christos 
    507   1.3  christos /*
    508   1.1  christos  * Increment query statistics counters.
    509   1.1  christos  */
    510  1.15  christos static void
    511   1.1  christos inc_stats(ns_client_t *client, isc_statscounter_t counter) {
    512   1.1  christos 	dns_zone_t *zone = client->query.authzone;
    513   1.1  christos 	dns_rdatatype_t qtype;
    514   1.1  christos 	dns_rdataset_t *rdataset;
    515   1.1  christos 	isc_stats_t *zonestats;
    516   1.1  christos 	dns_stats_t *querystats = NULL;
    517   1.1  christos 
    518   1.1  christos 	ns_stats_increment(client->sctx->nsstats, counter);
    519   1.1  christos 
    520   1.9  christos 	if (zone == NULL) {
    521   1.1  christos 		return;
    522   1.9  christos 	}
    523   1.1  christos 
    524   1.1  christos 	/* Do regular response type stats */
    525   1.1  christos 	zonestats = dns_zone_getrequeststats(zone);
    526   1.1  christos 
    527   1.9  christos 	if (zonestats != NULL) {
    528   1.1  christos 		isc_stats_increment(zonestats, counter);
    529   1.9  christos 	}
    530   1.1  christos 
    531   1.1  christos 	/* Do query type statistics
    532   1.1  christos 	 *
    533   1.1  christos 	 * We only increment per-type if we're using the authoritative
    534   1.1  christos 	 * answer counter, preventing double-counting.
    535   1.1  christos 	 */
    536   1.1  christos 	if (counter == ns_statscounter_authans) {
    537   1.1  christos 		querystats = dns_zone_getrcvquerystats(zone);
    538   1.1  christos 		if (querystats != NULL) {
    539   1.1  christos 			rdataset = ISC_LIST_HEAD(client->query.qname->list);
    540   1.1  christos 			if (rdataset != NULL) {
    541   1.1  christos 				qtype = rdataset->type;
    542   1.1  christos 				dns_rdatatypestats_increment(querystats, qtype);
    543   1.1  christos 			}
    544   1.1  christos 		}
    545   1.1  christos 	}
    546   1.1  christos }
    547   1.1  christos 
    548   1.1  christos static void
    549   1.1  christos query_send(ns_client_t *client) {
    550   1.1  christos 	isc_statscounter_t counter;
    551   1.1  christos 
    552   1.9  christos 	if ((client->message->flags & DNS_MESSAGEFLAG_AA) == 0) {
    553   1.1  christos 		inc_stats(client, ns_statscounter_nonauthans);
    554   1.9  christos 	} else {
    555   1.1  christos 		inc_stats(client, ns_statscounter_authans);
    556   1.9  christos 	}
    557   1.1  christos 
    558   1.1  christos 	if (client->message->rcode == dns_rcode_noerror) {
    559   1.1  christos 		dns_section_t answer = DNS_SECTION_ANSWER;
    560   1.1  christos 		if (ISC_LIST_EMPTY(client->message->sections[answer])) {
    561   1.9  christos 			if (client->query.isreferral) {
    562   1.1  christos 				counter = ns_statscounter_referral;
    563   1.9  christos 			} else {
    564   1.1  christos 				counter = ns_statscounter_nxrrset;
    565   1.9  christos 			}
    566   1.9  christos 		} else {
    567   1.1  christos 			counter = ns_statscounter_success;
    568   1.9  christos 		}
    569   1.9  christos 	} else if (client->message->rcode == dns_rcode_nxdomain) {
    570   1.1  christos 		counter = ns_statscounter_nxdomain;
    571   1.9  christos 	} else if (client->message->rcode == dns_rcode_badcookie) {
    572   1.1  christos 		counter = ns_statscounter_badcookie;
    573   1.9  christos 	} else { /* We end up here in case of YXDOMAIN, and maybe others */
    574   1.1  christos 		counter = ns_statscounter_failure;
    575   1.9  christos 	}
    576   1.1  christos 
    577   1.1  christos 	inc_stats(client, counter);
    578   1.1  christos 	ns_client_send(client);
    579  1.11  christos 
    580  1.13  christos 	if (!client->nodetach) {
    581  1.11  christos 		isc_nmhandle_detach(&client->reqhandle);
    582  1.11  christos 	}
    583   1.1  christos }
    584   1.1  christos 
    585   1.1  christos static void
    586   1.1  christos query_error(ns_client_t *client, isc_result_t result, int line) {
    587   1.1  christos 	int loglevel = ISC_LOG_DEBUG(3);
    588   1.1  christos 
    589   1.3  christos 	switch (dns_result_torcode(result)) {
    590   1.3  christos 	case dns_rcode_servfail:
    591   1.1  christos 		loglevel = ISC_LOG_DEBUG(1);
    592   1.1  christos 		inc_stats(client, ns_statscounter_servfail);
    593   1.1  christos 		break;
    594   1.3  christos 	case dns_rcode_formerr:
    595   1.1  christos 		inc_stats(client, ns_statscounter_formerr);
    596   1.1  christos 		break;
    597   1.1  christos 	default:
    598   1.1  christos 		inc_stats(client, ns_statscounter_failure);
    599   1.1  christos 		break;
    600   1.1  christos 	}
    601   1.1  christos 
    602   1.9  christos 	if ((client->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
    603   1.1  christos 		loglevel = ISC_LOG_INFO;
    604   1.9  christos 	}
    605   1.1  christos 
    606   1.1  christos 	log_queryerror(client, result, line, loglevel);
    607   1.1  christos 
    608   1.1  christos 	ns_client_error(client, result);
    609  1.11  christos 
    610  1.13  christos 	if (!client->nodetach) {
    611  1.11  christos 		isc_nmhandle_detach(&client->reqhandle);
    612  1.11  christos 	}
    613   1.1  christos }
    614   1.1  christos 
    615   1.1  christos static void
    616   1.1  christos query_next(ns_client_t *client, isc_result_t result) {
    617   1.9  christos 	if (result == DNS_R_DUPLICATE) {
    618   1.1  christos 		inc_stats(client, ns_statscounter_duplicate);
    619   1.9  christos 	} else if (result == DNS_R_DROP) {
    620   1.1  christos 		inc_stats(client, ns_statscounter_dropped);
    621   1.9  christos 	} else {
    622   1.1  christos 		inc_stats(client, ns_statscounter_failure);
    623   1.9  christos 	}
    624   1.9  christos 	ns_client_drop(client, result);
    625  1.11  christos 
    626  1.13  christos 	if (!client->nodetach) {
    627  1.11  christos 		isc_nmhandle_detach(&client->reqhandle);
    628  1.11  christos 	}
    629   1.1  christos }
    630   1.1  christos 
    631  1.15  christos static void
    632   1.3  christos query_freefreeversions(ns_client_t *client, bool everything) {
    633   1.1  christos 	ns_dbversion_t *dbversion, *dbversion_next;
    634   1.1  christos 	unsigned int i;
    635   1.1  christos 
    636   1.1  christos 	for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
    637   1.9  christos 	     dbversion != NULL; dbversion = dbversion_next, i++)
    638   1.1  christos 	{
    639   1.1  christos 		dbversion_next = ISC_LIST_NEXT(dbversion, link);
    640   1.1  christos 		/*
    641   1.1  christos 		 * If we're not freeing everything, we keep the first three
    642   1.1  christos 		 * dbversions structures around.
    643   1.1  christos 		 */
    644   1.1  christos 		if (i > 3 || everything) {
    645   1.1  christos 			ISC_LIST_UNLINK(client->query.freeversions, dbversion,
    646   1.1  christos 					link);
    647   1.1  christos 			isc_mem_put(client->mctx, dbversion,
    648   1.1  christos 				    sizeof(*dbversion));
    649   1.1  christos 		}
    650   1.1  christos 	}
    651   1.1  christos }
    652   1.1  christos 
    653   1.1  christos void
    654   1.1  christos ns_query_cancel(ns_client_t *client) {
    655   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
    656   1.1  christos 
    657   1.1  christos 	LOCK(&client->query.fetchlock);
    658   1.1  christos 	if (client->query.fetch != NULL) {
    659   1.1  christos 		dns_resolver_cancelfetch(client->query.fetch);
    660   1.1  christos 
    661   1.1  christos 		client->query.fetch = NULL;
    662   1.1  christos 	}
    663   1.1  christos 	UNLOCK(&client->query.fetchlock);
    664   1.1  christos }
    665   1.1  christos 
    666  1.15  christos static void
    667   1.3  christos query_reset(ns_client_t *client, bool everything) {
    668   1.1  christos 	isc_buffer_t *dbuf, *dbuf_next;
    669   1.1  christos 	ns_dbversion_t *dbversion, *dbversion_next;
    670   1.1  christos 
    671   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_reset");
    672   1.1  christos 
    673   1.1  christos 	/*%
    674   1.1  christos 	 * Reset the query state of a client to its default state.
    675   1.1  christos 	 */
    676   1.1  christos 
    677   1.1  christos 	/*
    678   1.1  christos 	 * Cancel the fetch if it's running.
    679   1.1  christos 	 */
    680   1.1  christos 	ns_query_cancel(client);
    681   1.1  christos 
    682   1.1  christos 	/*
    683   1.1  christos 	 * Cleanup any active versions.
    684   1.1  christos 	 */
    685   1.1  christos 	for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
    686   1.9  christos 	     dbversion != NULL; dbversion = dbversion_next)
    687   1.9  christos 	{
    688   1.1  christos 		dbversion_next = ISC_LIST_NEXT(dbversion, link);
    689   1.9  christos 		dns_db_closeversion(dbversion->db, &dbversion->version, false);
    690   1.1  christos 		dns_db_detach(&dbversion->db);
    691   1.9  christos 		ISC_LIST_INITANDAPPEND(client->query.freeversions, dbversion,
    692   1.9  christos 				       link);
    693   1.1  christos 	}
    694   1.1  christos 	ISC_LIST_INIT(client->query.activeversions);
    695   1.1  christos 
    696   1.9  christos 	if (client->query.authdb != NULL) {
    697   1.1  christos 		dns_db_detach(&client->query.authdb);
    698   1.9  christos 	}
    699   1.9  christos 	if (client->query.authzone != NULL) {
    700   1.1  christos 		dns_zone_detach(&client->query.authzone);
    701   1.9  christos 	}
    702   1.1  christos 
    703   1.9  christos 	if (client->query.dns64_aaaa != NULL) {
    704   1.3  christos 		ns_client_putrdataset(client, &client->query.dns64_aaaa);
    705   1.9  christos 	}
    706   1.9  christos 	if (client->query.dns64_sigaaaa != NULL) {
    707   1.3  christos 		ns_client_putrdataset(client, &client->query.dns64_sigaaaa);
    708   1.9  christos 	}
    709   1.1  christos 	if (client->query.dns64_aaaaok != NULL) {
    710   1.1  christos 		isc_mem_put(client->mctx, client->query.dns64_aaaaok,
    711   1.9  christos 			    client->query.dns64_aaaaoklen * sizeof(bool));
    712   1.9  christos 		client->query.dns64_aaaaok = NULL;
    713   1.9  christos 		client->query.dns64_aaaaoklen = 0;
    714   1.1  christos 	}
    715   1.1  christos 
    716   1.3  christos 	ns_client_putrdataset(client, &client->query.redirect.rdataset);
    717   1.3  christos 	ns_client_putrdataset(client, &client->query.redirect.sigrdataset);
    718   1.1  christos 	if (client->query.redirect.db != NULL) {
    719   1.9  christos 		if (client->query.redirect.node != NULL) {
    720   1.1  christos 			dns_db_detachnode(client->query.redirect.db,
    721   1.1  christos 					  &client->query.redirect.node);
    722   1.9  christos 		}
    723   1.1  christos 		dns_db_detach(&client->query.redirect.db);
    724   1.1  christos 	}
    725   1.9  christos 	if (client->query.redirect.zone != NULL) {
    726   1.1  christos 		dns_zone_detach(&client->query.redirect.zone);
    727   1.9  christos 	}
    728   1.1  christos 
    729   1.1  christos 	query_freefreeversions(client, everything);
    730   1.1  christos 
    731   1.9  christos 	for (dbuf = ISC_LIST_HEAD(client->query.namebufs); dbuf != NULL;
    732   1.9  christos 	     dbuf = dbuf_next)
    733   1.9  christos 	{
    734   1.1  christos 		dbuf_next = ISC_LIST_NEXT(dbuf, link);
    735   1.1  christos 		if (dbuf_next != NULL || everything) {
    736   1.1  christos 			ISC_LIST_UNLINK(client->query.namebufs, dbuf, link);
    737   1.1  christos 			isc_buffer_free(&dbuf);
    738   1.1  christos 		}
    739   1.1  christos 	}
    740   1.1  christos 
    741   1.1  christos 	if (client->query.restarts > 0) {
    742   1.1  christos 		/*
    743   1.1  christos 		 * client->query.qname was dynamically allocated.
    744   1.1  christos 		 */
    745   1.9  christos 		dns_message_puttempname(client->message, &client->query.qname);
    746   1.1  christos 	}
    747   1.1  christos 	client->query.qname = NULL;
    748   1.1  christos 	client->query.attributes = (NS_QUERYATTR_RECURSIONOK |
    749   1.9  christos 				    NS_QUERYATTR_CACHEOK | NS_QUERYATTR_SECURE);
    750   1.1  christos 	client->query.restarts = 0;
    751   1.3  christos 	client->query.timerset = false;
    752   1.1  christos 	if (client->query.rpz_st != NULL) {
    753   1.1  christos 		rpz_st_clear(client);
    754   1.1  christos 		if (everything) {
    755   1.1  christos 			INSIST(client->query.rpz_st->rpsdb == NULL);
    756   1.1  christos 			isc_mem_put(client->mctx, client->query.rpz_st,
    757   1.1  christos 				    sizeof(*client->query.rpz_st));
    758   1.1  christos 			client->query.rpz_st = NULL;
    759   1.1  christos 		}
    760   1.1  christos 	}
    761   1.1  christos 	client->query.origqname = NULL;
    762   1.1  christos 	client->query.dboptions = 0;
    763   1.1  christos 	client->query.fetchoptions = 0;
    764   1.1  christos 	client->query.gluedb = NULL;
    765   1.3  christos 	client->query.authdbset = false;
    766   1.3  christos 	client->query.isreferral = false;
    767   1.1  christos 	client->query.dns64_options = 0;
    768   1.3  christos 	client->query.dns64_ttl = UINT32_MAX;
    769   1.3  christos 	recparam_update(&client->query.recparam, 0, NULL, NULL);
    770   1.1  christos 	client->query.root_key_sentinel_keyid = 0;
    771   1.3  christos 	client->query.root_key_sentinel_is_ta = false;
    772   1.3  christos 	client->query.root_key_sentinel_not_ta = false;
    773   1.1  christos }
    774   1.1  christos 
    775   1.1  christos static void
    776   1.9  christos query_cleanup(ns_client_t *client) {
    777   1.3  christos 	query_reset(client, false);
    778   1.1  christos }
    779   1.1  christos 
    780   1.1  christos void
    781   1.1  christos ns_query_free(ns_client_t *client) {
    782   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
    783   1.1  christos 
    784   1.3  christos 	query_reset(client, true);
    785   1.1  christos }
    786   1.1  christos 
    787   1.1  christos isc_result_t
    788   1.1  christos ns_query_init(ns_client_t *client) {
    789  1.14  christos 	isc_result_t result = ISC_R_SUCCESS;
    790   1.1  christos 
    791   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
    792   1.1  christos 
    793   1.1  christos 	ISC_LIST_INIT(client->query.namebufs);
    794   1.1  christos 	ISC_LIST_INIT(client->query.activeversions);
    795   1.1  christos 	ISC_LIST_INIT(client->query.freeversions);
    796   1.1  christos 	client->query.restarts = 0;
    797   1.3  christos 	client->query.timerset = false;
    798   1.1  christos 	client->query.rpz_st = NULL;
    799   1.1  christos 	client->query.qname = NULL;
    800   1.1  christos 	/*
    801   1.1  christos 	 * This mutex is destroyed when the client is destroyed in
    802   1.1  christos 	 * exit_check().
    803   1.1  christos 	 */
    804   1.3  christos 	isc_mutex_init(&client->query.fetchlock);
    805   1.3  christos 
    806   1.1  christos 	client->query.fetch = NULL;
    807   1.1  christos 	client->query.prefetch = NULL;
    808   1.1  christos 	client->query.authdb = NULL;
    809   1.1  christos 	client->query.authzone = NULL;
    810   1.3  christos 	client->query.authdbset = false;
    811   1.3  christos 	client->query.isreferral = false;
    812   1.1  christos 	client->query.dns64_aaaa = NULL;
    813   1.1  christos 	client->query.dns64_sigaaaa = NULL;
    814   1.1  christos 	client->query.dns64_aaaaok = NULL;
    815   1.1  christos 	client->query.dns64_aaaaoklen = 0;
    816   1.1  christos 	client->query.redirect.db = NULL;
    817   1.1  christos 	client->query.redirect.node = NULL;
    818   1.1  christos 	client->query.redirect.zone = NULL;
    819   1.1  christos 	client->query.redirect.qtype = dns_rdatatype_none;
    820   1.1  christos 	client->query.redirect.result = ISC_R_SUCCESS;
    821   1.1  christos 	client->query.redirect.rdataset = NULL;
    822   1.1  christos 	client->query.redirect.sigrdataset = NULL;
    823   1.3  christos 	client->query.redirect.authoritative = false;
    824   1.3  christos 	client->query.redirect.is_zone = false;
    825   1.1  christos 	client->query.redirect.fname =
    826   1.1  christos 		dns_fixedname_initname(&client->query.redirect.fixed);
    827   1.3  christos 	query_reset(client, false);
    828  1.14  christos 	ns_client_newdbversion(client, 3);
    829  1.14  christos 	ns_client_newnamebuf(client);
    830   1.1  christos 
    831   1.1  christos 	return (result);
    832   1.1  christos }
    833   1.1  christos 
    834   1.3  christos /*%
    835   1.3  christos  * Check if 'client' is allowed to query the cache of its associated view.
    836   1.3  christos  * Unless 'options' has DNS_GETDB_NOLOG set, log the result of cache ACL
    837   1.3  christos  * evaluation using the appropriate level, along with 'name' and 'qtype'.
    838   1.3  christos  *
    839   1.3  christos  * The cache ACL is only evaluated once for each client and then the result is
    840   1.3  christos  * cached: if NS_QUERYATTR_CACHEACLOKVALID is set in client->query.attributes,
    841   1.3  christos  * cache ACL evaluation has already been performed.  The evaluation result is
    842   1.3  christos  * also stored in client->query.attributes: if NS_QUERYATTR_CACHEACLOK is set,
    843   1.3  christos  * the client is allowed cache access.
    844   1.3  christos  *
    845   1.3  christos  * Returns:
    846   1.3  christos  *
    847   1.3  christos  *\li	#ISC_R_SUCCESS	'client' is allowed to access cache
    848   1.3  christos  *\li	#DNS_R_REFUSED	'client' is not allowed to access cache
    849   1.3  christos  */
    850   1.3  christos static isc_result_t
    851   1.3  christos query_checkcacheaccess(ns_client_t *client, const dns_name_t *name,
    852   1.9  christos 		       dns_rdatatype_t qtype, unsigned int options) {
    853   1.3  christos 	isc_result_t result;
    854   1.3  christos 
    855   1.3  christos 	if ((client->query.attributes & NS_QUERYATTR_CACHEACLOKVALID) == 0) {
    856   1.3  christos 		/*
    857   1.3  christos 		 * The view's cache ACLs have not yet been evaluated.
    858   1.3  christos 		 * Do it now. Both allow-query-cache and
    859   1.3  christos 		 * allow-query-cache-on must be satsified.
    860   1.3  christos 		 */
    861   1.3  christos 		bool log = ((options & DNS_GETDB_NOLOG) == 0);
    862   1.3  christos 		char msg[NS_CLIENT_ACLMSGSIZE("query (cache)")];
    863   1.1  christos 
    864   1.3  christos 		result = ns_client_checkaclsilent(client, NULL,
    865   1.9  christos 						  client->view->cacheacl, true);
    866   1.3  christos 		if (result == ISC_R_SUCCESS) {
    867   1.9  christos 			result = ns_client_checkaclsilent(
    868   1.9  christos 				client, &client->destaddr,
    869   1.9  christos 				client->view->cacheonacl, true);
    870   1.9  christos 		}
    871   1.3  christos 		if (result == ISC_R_SUCCESS) {
    872   1.3  christos 			/*
    873   1.3  christos 			 * We were allowed by the "allow-query-cache" ACL.
    874   1.3  christos 			 */
    875   1.3  christos 			client->query.attributes |= NS_QUERYATTR_CACHEACLOK;
    876   1.9  christos 			if (log && isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(3)))
    877   1.3  christos 			{
    878   1.3  christos 				ns_client_aclmsg("query (cache)", name, qtype,
    879   1.3  christos 						 client->view->rdclass, msg,
    880   1.3  christos 						 sizeof(msg));
    881   1.3  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
    882   1.3  christos 					      NS_LOGMODULE_QUERY,
    883   1.3  christos 					      ISC_LOG_DEBUG(3), "%s approved",
    884   1.3  christos 					      msg);
    885   1.3  christos 			}
    886   1.3  christos 		} else if (log) {
    887   1.7  christos 			pfilter_notify(result, client, "checkcacheaccess");
    888   1.7  christos 
    889   1.3  christos 			/*
    890   1.3  christos 			 * We were denied by the "allow-query-cache" ACL.
    891   1.3  christos 			 * There is no need to clear NS_QUERYATTR_CACHEACLOK
    892   1.3  christos 			 * since it is cleared by query_reset(), before query
    893   1.3  christos 			 * processing starts.
    894   1.3  christos 			 */
    895   1.3  christos 			ns_client_aclmsg("query (cache)", name, qtype,
    896   1.3  christos 					 client->view->rdclass, msg,
    897   1.3  christos 					 sizeof(msg));
    898   1.3  christos 			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
    899   1.3  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
    900   1.3  christos 				      "%s denied", msg);
    901   1.3  christos 		}
    902   1.1  christos 
    903   1.1  christos 		/*
    904   1.3  christos 		 * Evaluation has been finished; make sure we will just consult
    905   1.3  christos 		 * NS_QUERYATTR_CACHEACLOK for this client from now on.
    906   1.1  christos 		 */
    907   1.3  christos 		client->query.attributes |= NS_QUERYATTR_CACHEACLOKVALID;
    908   1.1  christos 	}
    909   1.1  christos 
    910   1.9  christos 	return ((client->query.attributes & NS_QUERYATTR_CACHEACLOK) != 0
    911   1.9  christos 			? ISC_R_SUCCESS
    912   1.9  christos 			: DNS_R_REFUSED);
    913   1.1  christos }
    914   1.1  christos 
    915  1.15  christos static isc_result_t
    916   1.1  christos query_validatezonedb(ns_client_t *client, const dns_name_t *name,
    917   1.1  christos 		     dns_rdatatype_t qtype, unsigned int options,
    918   1.1  christos 		     dns_zone_t *zone, dns_db_t *db,
    919   1.9  christos 		     dns_dbversion_t **versionp) {
    920   1.1  christos 	isc_result_t result;
    921   1.1  christos 	dns_acl_t *queryacl, *queryonacl;
    922   1.1  christos 	ns_dbversion_t *dbversion;
    923   1.1  christos 
    924   1.1  christos 	REQUIRE(zone != NULL);
    925   1.1  christos 	REQUIRE(db != NULL);
    926   1.1  christos 
    927   1.1  christos 	/*
    928   1.3  christos 	 * Mirror zone data is treated as cache data.
    929   1.3  christos 	 */
    930   1.3  christos 	if (dns_zone_gettype(zone) == dns_zone_mirror) {
    931   1.3  christos 		return (query_checkcacheaccess(client, name, qtype, options));
    932   1.3  christos 	}
    933   1.3  christos 
    934   1.3  christos 	/*
    935   1.1  christos 	 * This limits our searching to the zone where the first name
    936   1.1  christos 	 * (the query target) was looked for.  This prevents following
    937   1.1  christos 	 * CNAMES or DNAMES into other zones and prevents returning
    938   1.1  christos 	 * additional data from other zones. This does not apply if we're
    939   1.1  christos 	 * answering a query where recursion is requested and allowed.
    940   1.1  christos 	 */
    941   1.1  christos 	if (client->query.rpz_st == NULL &&
    942   1.1  christos 	    !(WANTRECURSION(client) && RECURSIONOK(client)) &&
    943   1.1  christos 	    client->query.authdbset && db != client->query.authdb)
    944   1.1  christos 	{
    945   1.1  christos 		return (DNS_R_REFUSED);
    946   1.1  christos 	}
    947   1.1  christos 
    948   1.1  christos 	/*
    949   1.1  christos 	 * Non recursive query to a static-stub zone is prohibited; its
    950   1.1  christos 	 * zone content is not public data, but a part of local configuration
    951   1.1  christos 	 * and should not be disclosed.
    952   1.1  christos 	 */
    953   1.1  christos 	if (dns_zone_gettype(zone) == dns_zone_staticstub &&
    954  1.16  christos 	    !RECURSIONOK(client))
    955  1.16  christos 	{
    956   1.1  christos 		return (DNS_R_REFUSED);
    957   1.1  christos 	}
    958   1.1  christos 
    959   1.1  christos 	/*
    960   1.1  christos 	 * If the zone has an ACL, we'll check it, otherwise
    961   1.1  christos 	 * we use the view's "allow-query" ACL.  Each ACL is only checked
    962   1.1  christos 	 * once per query.
    963   1.1  christos 	 *
    964   1.1  christos 	 * Also, get the database version to use.
    965   1.1  christos 	 */
    966   1.1  christos 
    967   1.1  christos 	/*
    968   1.1  christos 	 * Get the current version of this database.
    969   1.1  christos 	 */
    970   1.3  christos 	dbversion = ns_client_findversion(client, db);
    971   1.1  christos 	if (dbversion == NULL) {
    972   1.1  christos 		CTRACE(ISC_LOG_ERROR, "unable to get db version");
    973   1.1  christos 		return (DNS_R_SERVFAIL);
    974   1.1  christos 	}
    975   1.1  christos 
    976   1.9  christos 	if ((options & DNS_GETDB_IGNOREACL) != 0) {
    977   1.1  christos 		goto approved;
    978   1.9  christos 	}
    979   1.1  christos 	if (dbversion->acl_checked) {
    980   1.9  christos 		if (!dbversion->queryok) {
    981   1.1  christos 			return (DNS_R_REFUSED);
    982   1.9  christos 		}
    983   1.1  christos 		goto approved;
    984   1.1  christos 	}
    985   1.1  christos 
    986   1.1  christos 	queryacl = dns_zone_getqueryacl(zone);
    987   1.1  christos 	if (queryacl == NULL) {
    988   1.1  christos 		queryacl = client->view->queryacl;
    989   1.9  christos 		if ((client->query.attributes & NS_QUERYATTR_QUERYOKVALID) != 0)
    990   1.9  christos 		{
    991   1.1  christos 			/*
    992   1.1  christos 			 * We've evaluated the view's queryacl already.  If
    993   1.1  christos 			 * NS_QUERYATTR_QUERYOK is set, then the client is
    994   1.1  christos 			 * allowed to make queries, otherwise the query should
    995   1.1  christos 			 * be refused.
    996   1.1  christos 			 */
    997   1.3  christos 			dbversion->acl_checked = true;
    998   1.9  christos 			if ((client->query.attributes & NS_QUERYATTR_QUERYOK) ==
    999  1.16  christos 			    0)
   1000  1.16  christos 			{
   1001   1.3  christos 				dbversion->queryok = false;
   1002   1.1  christos 				return (DNS_R_REFUSED);
   1003   1.1  christos 			}
   1004   1.3  christos 			dbversion->queryok = true;
   1005   1.1  christos 			goto approved;
   1006   1.1  christos 		}
   1007   1.1  christos 	}
   1008   1.1  christos 
   1009   1.3  christos 	result = ns_client_checkaclsilent(client, NULL, queryacl, true);
   1010   1.1  christos 	if ((options & DNS_GETDB_NOLOG) == 0) {
   1011   1.1  christos 		char msg[NS_CLIENT_ACLMSGSIZE("query")];
   1012   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1013   1.1  christos 			if (isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(3))) {
   1014   1.1  christos 				ns_client_aclmsg("query", name, qtype,
   1015   1.9  christos 						 client->view->rdclass, msg,
   1016   1.9  christos 						 sizeof(msg));
   1017   1.9  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1018   1.1  christos 					      NS_LOGMODULE_QUERY,
   1019   1.9  christos 					      ISC_LOG_DEBUG(3), "%s approved",
   1020   1.9  christos 					      msg);
   1021   1.1  christos 			}
   1022   1.1  christos 		} else {
   1023   1.7  christos 			pfilter_notify(result, client, "validatezonedb");
   1024   1.1  christos 			ns_client_aclmsg("query", name, qtype,
   1025   1.9  christos 					 client->view->rdclass, msg,
   1026   1.9  christos 					 sizeof(msg));
   1027   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1028   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   1029   1.1  christos 				      "%s denied", msg);
   1030   1.1  christos 		}
   1031   1.1  christos 	}
   1032   1.1  christos 
   1033   1.1  christos 	if (queryacl == client->view->queryacl) {
   1034   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1035   1.1  christos 			/*
   1036   1.1  christos 			 * We were allowed by the default
   1037   1.1  christos 			 * "allow-query" ACL.  Remember this so we
   1038   1.1  christos 			 * don't have to check again.
   1039   1.1  christos 			 */
   1040   1.1  christos 			client->query.attributes |= NS_QUERYATTR_QUERYOK;
   1041   1.1  christos 		}
   1042   1.1  christos 		/*
   1043   1.1  christos 		 * We've now evaluated the view's query ACL, and
   1044   1.1  christos 		 * the NS_QUERYATTR_QUERYOK attribute is now valid.
   1045   1.1  christos 		 */
   1046   1.1  christos 		client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
   1047   1.1  christos 	}
   1048   1.1  christos 
   1049   1.1  christos 	/* If and only if we've gotten this far, check allow-query-on too */
   1050   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1051   1.1  christos 		queryonacl = dns_zone_getqueryonacl(zone);
   1052   1.9  christos 		if (queryonacl == NULL) {
   1053   1.1  christos 			queryonacl = client->view->queryonacl;
   1054   1.9  christos 		}
   1055   1.1  christos 
   1056   1.1  christos 		result = ns_client_checkaclsilent(client, &client->destaddr,
   1057   1.3  christos 						  queryonacl, true);
   1058   1.9  christos 		if ((options & DNS_GETDB_NOLOG) == 0 && result != ISC_R_SUCCESS)
   1059   1.9  christos 		{
   1060   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   1061   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   1062   1.1  christos 				      "query-on denied");
   1063   1.9  christos 		}
   1064   1.1  christos 	}
   1065   1.1  christos 
   1066   1.3  christos 	dbversion->acl_checked = true;
   1067   1.1  christos 	if (result != ISC_R_SUCCESS) {
   1068   1.3  christos 		dbversion->queryok = false;
   1069   1.1  christos 		return (DNS_R_REFUSED);
   1070   1.1  christos 	}
   1071   1.3  christos 	dbversion->queryok = true;
   1072   1.1  christos 
   1073   1.9  christos approved:
   1074   1.1  christos 	/* Transfer ownership, if necessary. */
   1075   1.9  christos 	if (versionp != NULL) {
   1076   1.1  christos 		*versionp = dbversion->version;
   1077   1.9  christos 	}
   1078   1.1  christos 	return (ISC_R_SUCCESS);
   1079   1.1  christos }
   1080   1.1  christos 
   1081  1.15  christos static isc_result_t
   1082   1.1  christos query_getzonedb(ns_client_t *client, const dns_name_t *name,
   1083   1.9  christos 		dns_rdatatype_t qtype, unsigned int options, dns_zone_t **zonep,
   1084   1.9  christos 		dns_db_t **dbp, dns_dbversion_t **versionp) {
   1085   1.1  christos 	isc_result_t result;
   1086   1.1  christos 	unsigned int ztoptions;
   1087   1.1  christos 	dns_zone_t *zone = NULL;
   1088   1.1  christos 	dns_db_t *db = NULL;
   1089   1.3  christos 	bool partial = false;
   1090   1.1  christos 
   1091   1.1  christos 	REQUIRE(zonep != NULL && *zonep == NULL);
   1092   1.1  christos 	REQUIRE(dbp != NULL && *dbp == NULL);
   1093   1.1  christos 
   1094   1.1  christos 	/*%
   1095   1.1  christos 	 * Find a zone database to answer the query.
   1096   1.1  christos 	 */
   1097   1.3  christos 	ztoptions = DNS_ZTFIND_MIRROR;
   1098   1.3  christos 	if ((options & DNS_GETDB_NOEXACT) != 0) {
   1099   1.3  christos 		ztoptions |= DNS_ZTFIND_NOEXACT;
   1100   1.3  christos 	}
   1101   1.1  christos 
   1102   1.1  christos 	result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
   1103   1.1  christos 			     &zone);
   1104   1.1  christos 
   1105   1.9  christos 	if (result == DNS_R_PARTIALMATCH) {
   1106   1.3  christos 		partial = true;
   1107   1.9  christos 	}
   1108   1.9  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
   1109   1.1  christos 		result = dns_zone_getdb(zone, &db);
   1110   1.9  christos 	}
   1111   1.1  christos 
   1112   1.9  christos 	if (result != ISC_R_SUCCESS) {
   1113   1.1  christos 		goto fail;
   1114   1.9  christos 	}
   1115   1.1  christos 
   1116   1.1  christos 	result = query_validatezonedb(client, name, qtype, options, zone, db,
   1117   1.1  christos 				      versionp);
   1118   1.1  christos 
   1119   1.9  christos 	if (result != ISC_R_SUCCESS) {
   1120   1.1  christos 		goto fail;
   1121   1.9  christos 	}
   1122   1.1  christos 
   1123   1.1  christos 	/* Transfer ownership. */
   1124   1.1  christos 	*zonep = zone;
   1125   1.1  christos 	*dbp = db;
   1126   1.1  christos 
   1127   1.9  christos 	if (partial && (options & DNS_GETDB_PARTIAL) != 0) {
   1128   1.1  christos 		return (DNS_R_PARTIALMATCH);
   1129   1.9  christos 	}
   1130   1.1  christos 	return (ISC_R_SUCCESS);
   1131   1.1  christos 
   1132   1.9  christos fail:
   1133   1.9  christos 	if (zone != NULL) {
   1134   1.1  christos 		dns_zone_detach(&zone);
   1135   1.9  christos 	}
   1136   1.9  christos 	if (db != NULL) {
   1137   1.1  christos 		dns_db_detach(&db);
   1138   1.9  christos 	}
   1139   1.1  christos 
   1140   1.1  christos 	return (result);
   1141   1.1  christos }
   1142   1.1  christos 
   1143   1.1  christos static void
   1144   1.9  christos rpz_log_rewrite(ns_client_t *client, bool disabled, dns_rpz_policy_t policy,
   1145   1.9  christos 		dns_rpz_type_t type, dns_zone_t *p_zone, dns_name_t *p_name,
   1146   1.9  christos 		dns_name_t *cname, dns_rpz_num_t rpz_num) {
   1147   1.3  christos 	char cname_buf[DNS_NAME_FORMATSIZE] = { 0 };
   1148   1.3  christos 	char p_name_buf[DNS_NAME_FORMATSIZE];
   1149   1.1  christos 	char qname_buf[DNS_NAME_FORMATSIZE];
   1150   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   1151   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   1152   1.1  christos 	const char *s1 = cname_buf, *s2 = cname_buf;
   1153   1.3  christos 	dns_rdataset_t *rdataset;
   1154   1.1  christos 	dns_rpz_st_t *st;
   1155   1.3  christos 	isc_stats_t *zonestats;
   1156   1.1  christos 
   1157   1.1  christos 	/*
   1158   1.1  christos 	 * Count enabled rewrites in the global counter.
   1159   1.1  christos 	 * Count both enabled and disabled rewrites for each zone.
   1160   1.1  christos 	 */
   1161   1.1  christos 	if (!disabled && policy != DNS_RPZ_POLICY_PASSTHRU) {
   1162   1.1  christos 		ns_stats_increment(client->sctx->nsstats,
   1163   1.1  christos 				   ns_statscounter_rpz_rewrites);
   1164   1.1  christos 	}
   1165   1.1  christos 	if (p_zone != NULL) {
   1166   1.1  christos 		zonestats = dns_zone_getrequeststats(p_zone);
   1167   1.9  christos 		if (zonestats != NULL) {
   1168   1.1  christos 			isc_stats_increment(zonestats,
   1169   1.1  christos 					    ns_statscounter_rpz_rewrites);
   1170   1.9  christos 		}
   1171   1.1  christos 	}
   1172   1.1  christos 
   1173   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, DNS_RPZ_INFO_LEVEL)) {
   1174   1.1  christos 		return;
   1175   1.9  christos 	}
   1176   1.1  christos 
   1177   1.1  christos 	st = client->query.rpz_st;
   1178   1.9  christos 	if ((st->popt.no_log & DNS_RPZ_ZBIT(rpz_num)) != 0) {
   1179   1.1  christos 		return;
   1180   1.9  christos 	}
   1181   1.1  christos 
   1182   1.1  christos 	dns_name_format(client->query.qname, qname_buf, sizeof(qname_buf));
   1183   1.1  christos 	dns_name_format(p_name, p_name_buf, sizeof(p_name_buf));
   1184   1.1  christos 	if (cname != NULL) {
   1185   1.1  christos 		s1 = " (CNAME to: ";
   1186   1.1  christos 		dns_name_format(cname, cname_buf, sizeof(cname_buf));
   1187   1.1  christos 		s2 = ")";
   1188   1.1  christos 	}
   1189   1.1  christos 
   1190   1.3  christos 	/*
   1191   1.3  christos 	 *  Log Qclass and Qtype in addition to existing
   1192   1.3  christos 	 *  fields.
   1193   1.3  christos 	 */
   1194   1.3  christos 	rdataset = ISC_LIST_HEAD(client->query.origqname->list);
   1195   1.3  christos 	INSIST(rdataset != NULL);
   1196   1.3  christos 	dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf));
   1197   1.3  christos 	dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
   1198   1.3  christos 
   1199   1.1  christos 	ns_client_log(client, DNS_LOGCATEGORY_RPZ, NS_LOGMODULE_QUERY,
   1200   1.3  christos 		      DNS_RPZ_INFO_LEVEL,
   1201   1.3  christos 		      "%srpz %s %s rewrite %s/%s/%s via %s%s%s%s",
   1202   1.9  christos 		      disabled ? "disabled " : "", dns_rpz_type2str(type),
   1203   1.9  christos 		      dns_rpz_policy2str(policy), qname_buf, typebuf, classbuf,
   1204   1.3  christos 		      p_name_buf, s1, cname_buf, s2);
   1205   1.1  christos }
   1206   1.1  christos 
   1207   1.1  christos static void
   1208   1.1  christos rpz_log_fail_helper(ns_client_t *client, int level, dns_name_t *p_name,
   1209   1.1  christos 		    dns_rpz_type_t rpz_type1, dns_rpz_type_t rpz_type2,
   1210   1.9  christos 		    const char *str, isc_result_t result) {
   1211   1.1  christos 	char qnamebuf[DNS_NAME_FORMATSIZE];
   1212   1.1  christos 	char p_namebuf[DNS_NAME_FORMATSIZE];
   1213   1.1  christos 	const char *failed, *via, *slash, *str_blank;
   1214   1.1  christos 	const char *rpztypestr1;
   1215   1.1  christos 	const char *rpztypestr2;
   1216   1.1  christos 
   1217   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   1218   1.1  christos 		return;
   1219   1.9  christos 	}
   1220   1.1  christos 
   1221   1.1  christos 	/*
   1222   1.1  christos 	 * bin/tests/system/rpz/tests.sh looks for "rpz.*failed" for problems.
   1223   1.1  christos 	 */
   1224   1.9  christos 	if (level <= DNS_RPZ_DEBUG_LEVEL1) {
   1225   1.3  christos 		failed = " failed: ";
   1226   1.9  christos 	} else {
   1227   1.1  christos 		failed = ": ";
   1228   1.9  christos 	}
   1229   1.1  christos 
   1230   1.1  christos 	rpztypestr1 = dns_rpz_type2str(rpz_type1);
   1231   1.1  christos 	if (rpz_type2 != DNS_RPZ_TYPE_BAD) {
   1232   1.1  christos 		slash = "/";
   1233   1.1  christos 		rpztypestr2 = dns_rpz_type2str(rpz_type2);
   1234   1.1  christos 	} else {
   1235   1.1  christos 		slash = "";
   1236   1.1  christos 		rpztypestr2 = "";
   1237   1.1  christos 	}
   1238   1.1  christos 
   1239   1.1  christos 	str_blank = (*str != ' ' && *str != '\0') ? " " : "";
   1240   1.1  christos 
   1241   1.1  christos 	dns_name_format(client->query.qname, qnamebuf, sizeof(qnamebuf));
   1242   1.1  christos 
   1243   1.1  christos 	if (p_name != NULL) {
   1244   1.1  christos 		via = " via ";
   1245   1.1  christos 		dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
   1246   1.1  christos 	} else {
   1247   1.1  christos 		via = "";
   1248   1.1  christos 		p_namebuf[0] = '\0';
   1249   1.1  christos 	}
   1250   1.1  christos 
   1251   1.9  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS, NS_LOGMODULE_QUERY,
   1252   1.9  christos 		      level, "rpz %s%s%s rewrite %s%s%s%s%s%s%s", rpztypestr1,
   1253   1.9  christos 		      slash, rpztypestr2, qnamebuf, via, p_namebuf, str_blank,
   1254   1.1  christos 		      str, failed, isc_result_totext(result));
   1255   1.1  christos }
   1256   1.1  christos 
   1257   1.1  christos static void
   1258   1.1  christos rpz_log_fail(ns_client_t *client, int level, dns_name_t *p_name,
   1259   1.9  christos 	     dns_rpz_type_t rpz_type, const char *str, isc_result_t result) {
   1260   1.9  christos 	rpz_log_fail_helper(client, level, p_name, rpz_type, DNS_RPZ_TYPE_BAD,
   1261   1.9  christos 			    str, result);
   1262   1.1  christos }
   1263   1.1  christos 
   1264   1.1  christos /*
   1265   1.1  christos  * Get a policy rewrite zone database.
   1266   1.1  christos  */
   1267   1.1  christos static isc_result_t
   1268   1.1  christos rpz_getdb(ns_client_t *client, dns_name_t *p_name, dns_rpz_type_t rpz_type,
   1269   1.9  christos 	  dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp) {
   1270   1.1  christos 	char qnamebuf[DNS_NAME_FORMATSIZE];
   1271   1.1  christos 	char p_namebuf[DNS_NAME_FORMATSIZE];
   1272   1.1  christos 	dns_dbversion_t *rpz_version = NULL;
   1273   1.1  christos 	isc_result_t result;
   1274   1.1  christos 
   1275   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_getdb");
   1276   1.1  christos 
   1277   1.1  christos 	result = query_getzonedb(client, p_name, dns_rdatatype_any,
   1278   1.1  christos 				 DNS_GETDB_IGNOREACL, zonep, dbp, &rpz_version);
   1279   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1280   1.1  christos 		dns_rpz_st_t *st = client->query.rpz_st;
   1281   1.1  christos 
   1282   1.1  christos 		/*
   1283   1.1  christos 		 * It isn't meaningful to log this message when
   1284   1.1  christos 		 * logging is disabled for some policy zones.
   1285   1.1  christos 		 */
   1286   1.1  christos 		if (st->popt.no_log == 0 &&
   1287  1.16  christos 		    isc_log_wouldlog(ns_lctx, DNS_RPZ_DEBUG_LEVEL2))
   1288  1.16  christos 		{
   1289   1.1  christos 			dns_name_format(client->query.qname, qnamebuf,
   1290   1.1  christos 					sizeof(qnamebuf));
   1291   1.1  christos 			dns_name_format(p_name, p_namebuf, sizeof(p_namebuf));
   1292   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_RPZ,
   1293   1.1  christos 				      NS_LOGMODULE_QUERY, DNS_RPZ_DEBUG_LEVEL2,
   1294   1.1  christos 				      "try rpz %s rewrite %s via %s",
   1295   1.9  christos 				      dns_rpz_type2str(rpz_type), qnamebuf,
   1296   1.9  christos 				      p_namebuf);
   1297   1.1  christos 		}
   1298   1.1  christos 		*versionp = rpz_version;
   1299   1.1  christos 		return (ISC_R_SUCCESS);
   1300   1.1  christos 	}
   1301   1.1  christos 	rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type,
   1302   1.3  christos 		     "query_getzonedb()", result);
   1303   1.1  christos 	return (result);
   1304   1.1  christos }
   1305   1.1  christos 
   1306   1.3  christos /*%
   1307   1.3  christos  * Find a cache database to answer the query.  This may fail with DNS_R_REFUSED
   1308   1.3  christos  * if the client is not allowed to use the cache.
   1309   1.3  christos  */
   1310  1.15  christos static isc_result_t
   1311   1.1  christos query_getcachedb(ns_client_t *client, const dns_name_t *name,
   1312   1.9  christos 		 dns_rdatatype_t qtype, dns_db_t **dbp, unsigned int options) {
   1313   1.1  christos 	isc_result_t result;
   1314   1.1  christos 	dns_db_t *db = NULL;
   1315   1.1  christos 
   1316   1.1  christos 	REQUIRE(dbp != NULL && *dbp == NULL);
   1317   1.1  christos 
   1318   1.3  christos 	if (!USECACHE(client)) {
   1319   1.1  christos 		return (DNS_R_REFUSED);
   1320   1.1  christos 	}
   1321   1.1  christos 
   1322   1.3  christos 	dns_db_attach(client->view->cachedb, &db);
   1323   1.1  christos 
   1324   1.3  christos 	result = query_checkcacheaccess(client, name, qtype, options);
   1325   1.3  christos 	if (result != ISC_R_SUCCESS) {
   1326   1.3  christos 		dns_db_detach(&db);
   1327   1.1  christos 	}
   1328   1.1  christos 
   1329   1.3  christos 	/*
   1330   1.3  christos 	 * If query_checkcacheaccess() succeeded, transfer ownership of 'db'.
   1331   1.3  christos 	 * Otherwise, 'db' will be NULL due to the dns_db_detach() call above.
   1332   1.3  christos 	 */
   1333   1.1  christos 	*dbp = db;
   1334   1.1  christos 
   1335   1.3  christos 	return (result);
   1336   1.3  christos }
   1337   1.1  christos 
   1338  1.15  christos static isc_result_t
   1339   1.3  christos query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype,
   1340   1.1  christos 	    unsigned int options, dns_zone_t **zonep, dns_db_t **dbp,
   1341   1.9  christos 	    dns_dbversion_t **versionp, bool *is_zonep) {
   1342   1.1  christos 	isc_result_t result;
   1343   1.1  christos 	isc_result_t tresult;
   1344   1.1  christos 	unsigned int namelabels;
   1345   1.1  christos 	unsigned int zonelabels;
   1346   1.1  christos 	dns_zone_t *zone = NULL;
   1347   1.1  christos 
   1348   1.1  christos 	REQUIRE(zonep != NULL && *zonep == NULL);
   1349   1.1  christos 
   1350   1.1  christos 	/* Calculate how many labels are in name. */
   1351   1.1  christos 	namelabels = dns_name_countlabels(name);
   1352   1.1  christos 	zonelabels = 0;
   1353   1.1  christos 
   1354   1.1  christos 	/* Try to find name in bind's standard database. */
   1355   1.9  christos 	result = query_getzonedb(client, name, qtype, options, &zone, dbp,
   1356   1.9  christos 				 versionp);
   1357   1.1  christos 
   1358   1.1  christos 	/* See how many labels are in the zone's name.	  */
   1359   1.5  christos 	if (result == ISC_R_SUCCESS && zone != NULL) {
   1360   1.1  christos 		zonelabels = dns_name_countlabels(dns_zone_getorigin(zone));
   1361   1.5  christos 	}
   1362   1.1  christos 
   1363   1.1  christos 	/*
   1364   1.1  christos 	 * If # zone labels < # name labels, try to find an even better match
   1365   1.1  christos 	 * Only try if DLZ drivers are loaded for this view
   1366   1.1  christos 	 */
   1367   1.1  christos 	if (ISC_UNLIKELY(zonelabels < namelabels &&
   1368   1.1  christos 			 !ISC_LIST_EMPTY(client->view->dlz_searched)))
   1369   1.1  christos 	{
   1370   1.1  christos 		dns_clientinfomethods_t cm;
   1371   1.1  christos 		dns_clientinfo_t ci;
   1372   1.1  christos 		dns_db_t *tdbp;
   1373   1.1  christos 
   1374   1.1  christos 		dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1375  1.15  christos 		dns_clientinfo_init(&ci, client, &client->ecs, NULL);
   1376   1.1  christos 
   1377   1.1  christos 		tdbp = NULL;
   1378   1.9  christos 		tresult = dns_view_searchdlz(client->view, name, zonelabels,
   1379   1.9  christos 					     &cm, &ci, &tdbp);
   1380   1.9  christos 		/* If we successful, we found a better match. */
   1381   1.1  christos 		if (tresult == ISC_R_SUCCESS) {
   1382   1.1  christos 			ns_dbversion_t *dbversion;
   1383   1.1  christos 
   1384   1.1  christos 			/*
   1385   1.1  christos 			 * If the previous search returned a zone, detach it.
   1386   1.1  christos 			 */
   1387   1.9  christos 			if (zone != NULL) {
   1388   1.1  christos 				dns_zone_detach(&zone);
   1389   1.9  christos 			}
   1390   1.1  christos 
   1391   1.1  christos 			/*
   1392   1.1  christos 			 * If the previous search returned a database,
   1393   1.1  christos 			 * detach it.
   1394   1.1  christos 			 */
   1395   1.9  christos 			if (*dbp != NULL) {
   1396   1.1  christos 				dns_db_detach(dbp);
   1397   1.9  christos 			}
   1398   1.1  christos 
   1399   1.1  christos 			/*
   1400   1.1  christos 			 * If the previous search returned a version, clear it.
   1401   1.1  christos 			 */
   1402   1.1  christos 			*versionp = NULL;
   1403   1.1  christos 
   1404   1.3  christos 			dbversion = ns_client_findversion(client, tdbp);
   1405   1.1  christos 			if (dbversion == NULL) {
   1406   1.1  christos 				tresult = ISC_R_NOMEMORY;
   1407   1.1  christos 			} else {
   1408   1.1  christos 				/*
   1409   1.1  christos 				 * Be sure to return our database.
   1410   1.1  christos 				 */
   1411   1.1  christos 				*dbp = tdbp;
   1412   1.1  christos 				*versionp = dbversion->version;
   1413   1.1  christos 			}
   1414   1.1  christos 
   1415   1.1  christos 			/*
   1416   1.1  christos 			 * We return a null zone, No stats for DLZ zones.
   1417   1.1  christos 			 */
   1418   1.1  christos 			zone = NULL;
   1419   1.1  christos 			result = tresult;
   1420   1.1  christos 		}
   1421   1.1  christos 	}
   1422   1.1  christos 
   1423   1.1  christos 	/* If successful, Transfer ownership of zone. */
   1424   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1425   1.1  christos 		*zonep = zone;
   1426   1.1  christos 		/*
   1427   1.1  christos 		 * If neither attempt above succeeded, return the cache instead
   1428   1.1  christos 		 */
   1429   1.3  christos 		*is_zonep = true;
   1430   1.5  christos 	} else {
   1431   1.5  christos 		if (result == ISC_R_NOTFOUND) {
   1432   1.5  christos 			result = query_getcachedb(client, name, qtype, dbp,
   1433   1.5  christos 						  options);
   1434   1.5  christos 		}
   1435   1.3  christos 		*is_zonep = false;
   1436   1.1  christos 	}
   1437   1.1  christos 	return (result);
   1438   1.1  christos }
   1439   1.1  christos 
   1440  1.15  christos static bool
   1441   1.9  christos query_isduplicate(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
   1442   1.9  christos 		  dns_name_t **mnamep) {
   1443   1.1  christos 	dns_section_t section;
   1444   1.1  christos 	dns_name_t *mname = NULL;
   1445   1.1  christos 	isc_result_t result;
   1446   1.1  christos 
   1447   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate");
   1448   1.1  christos 
   1449   1.9  christos 	for (section = DNS_SECTION_ANSWER; section <= DNS_SECTION_ADDITIONAL;
   1450  1.16  christos 	     section++)
   1451  1.16  christos 	{
   1452   1.9  christos 		result = dns_message_findname(client->message, section, name,
   1453   1.9  christos 					      type, 0, &mname, NULL);
   1454   1.1  christos 		if (result == ISC_R_SUCCESS) {
   1455   1.1  christos 			/*
   1456   1.1  christos 			 * We've already got this RRset in the response.
   1457   1.1  christos 			 */
   1458   1.9  christos 			CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: true: "
   1459   1.9  christos 						 "done");
   1460   1.3  christos 			return (true);
   1461   1.1  christos 		} else if (result == DNS_R_NXRRSET) {
   1462   1.1  christos 			/*
   1463   1.1  christos 			 * The name exists, but the rdataset does not.
   1464   1.1  christos 			 */
   1465   1.9  christos 			if (section == DNS_SECTION_ADDITIONAL) {
   1466   1.1  christos 				break;
   1467   1.9  christos 			}
   1468   1.9  christos 		} else {
   1469   1.1  christos 			RUNTIME_CHECK(result == DNS_R_NXDOMAIN);
   1470   1.9  christos 		}
   1471   1.1  christos 		mname = NULL;
   1472   1.1  christos 	}
   1473   1.1  christos 
   1474   1.9  christos 	if (mnamep != NULL) {
   1475   1.1  christos 		*mnamep = mname;
   1476   1.9  christos 	}
   1477   1.1  christos 
   1478   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_isduplicate: false: done");
   1479   1.3  christos 	return (false);
   1480   1.1  christos }
   1481   1.1  christos 
   1482   1.6  christos /*
   1483   1.6  christos  * Look up data for given 'name' and 'type' in given 'version' of 'db' for
   1484   1.6  christos  * 'client'. Called from query_additionalauth().
   1485   1.6  christos  *
   1486   1.6  christos  * If the lookup is successful:
   1487   1.6  christos  *
   1488   1.6  christos  *   - store the node containing the result at 'nodep',
   1489   1.6  christos  *
   1490   1.6  christos  *   - store the owner name of the returned node in 'fname',
   1491   1.6  christos  *
   1492   1.6  christos  *   - if 'type' is not ANY, dns_db_findext() will put the exact rdataset being
   1493   1.6  christos  *     looked for in 'rdataset' and its signatures (if any) in 'sigrdataset',
   1494   1.6  christos  *
   1495   1.6  christos  *   - if 'type' is ANY, dns_db_findext() will leave 'rdataset' and
   1496   1.6  christos  *     'sigrdataset' disassociated and the returned node will be iterated in
   1497   1.6  christos  *     query_additional_cb().
   1498   1.6  christos  *
   1499   1.6  christos  * If the lookup is not successful:
   1500   1.6  christos  *
   1501   1.6  christos  *   - 'nodep' will not be written to,
   1502   1.6  christos  *   - 'fname' may still be modified as it is passed to dns_db_findext(),
   1503   1.6  christos  *   - 'rdataset' and 'sigrdataset' will remain disassociated.
   1504   1.6  christos  */
   1505   1.6  christos static isc_result_t
   1506   1.6  christos query_additionalauthfind(dns_db_t *db, dns_dbversion_t *version,
   1507   1.6  christos 			 const dns_name_t *name, dns_rdatatype_t type,
   1508   1.6  christos 			 ns_client_t *client, dns_dbnode_t **nodep,
   1509   1.6  christos 			 dns_name_t *fname, dns_rdataset_t *rdataset,
   1510   1.9  christos 			 dns_rdataset_t *sigrdataset) {
   1511   1.6  christos 	dns_clientinfomethods_t cm;
   1512   1.6  christos 	dns_dbnode_t *node = NULL;
   1513   1.6  christos 	dns_clientinfo_t ci;
   1514   1.6  christos 	isc_result_t result;
   1515   1.6  christos 
   1516   1.6  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1517  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   1518   1.6  christos 
   1519   1.6  christos 	/*
   1520   1.6  christos 	 * Since we are looking for authoritative data, we do not set
   1521   1.6  christos 	 * the GLUEOK flag.  Glue will be looked for later, but not
   1522   1.6  christos 	 * necessarily in the same database.
   1523   1.6  christos 	 */
   1524   1.6  christos 	result = dns_db_findext(db, name, version, type,
   1525   1.6  christos 				client->query.dboptions, client->now, &node,
   1526   1.6  christos 				fname, &cm, &ci, rdataset, sigrdataset);
   1527   1.6  christos 	if (result != ISC_R_SUCCESS) {
   1528   1.6  christos 		if (dns_rdataset_isassociated(rdataset)) {
   1529   1.6  christos 			dns_rdataset_disassociate(rdataset);
   1530   1.6  christos 		}
   1531   1.6  christos 
   1532   1.6  christos 		if (sigrdataset != NULL &&
   1533  1.16  christos 		    dns_rdataset_isassociated(sigrdataset))
   1534  1.16  christos 		{
   1535   1.6  christos 			dns_rdataset_disassociate(sigrdataset);
   1536   1.6  christos 		}
   1537   1.6  christos 
   1538   1.6  christos 		if (node != NULL) {
   1539   1.6  christos 			dns_db_detachnode(db, &node);
   1540   1.6  christos 		}
   1541   1.6  christos 
   1542   1.6  christos 		return (result);
   1543   1.6  christos 	}
   1544   1.6  christos 
   1545   1.6  christos 	/*
   1546   1.6  christos 	 * Do not return signatures if the zone is not fully signed.
   1547   1.6  christos 	 */
   1548   1.6  christos 	if (sigrdataset != NULL && !dns_db_issecure(db) &&
   1549   1.6  christos 	    dns_rdataset_isassociated(sigrdataset))
   1550   1.6  christos 	{
   1551   1.6  christos 		dns_rdataset_disassociate(sigrdataset);
   1552   1.6  christos 	}
   1553   1.6  christos 
   1554   1.6  christos 	*nodep = node;
   1555   1.6  christos 
   1556   1.6  christos 	return (ISC_R_SUCCESS);
   1557   1.6  christos }
   1558   1.6  christos 
   1559   1.6  christos /*
   1560   1.6  christos  * For query context 'qctx', try finding authoritative additional data for
   1561   1.6  christos  * given 'name' and 'type'. Called from query_additional_cb().
   1562   1.6  christos  *
   1563   1.6  christos  * If successful:
   1564   1.6  christos  *
   1565   1.6  christos  *   - store pointers to the database and node which contain the result in
   1566   1.6  christos  *     'dbp' and 'nodep', respectively,
   1567   1.6  christos  *
   1568   1.6  christos  *   - store the owner name of the returned node in 'fname',
   1569   1.6  christos  *
   1570   1.6  christos  *   - potentially bind 'rdataset' and 'sigrdataset', as explained in the
   1571   1.6  christos  *     comment for query_additionalauthfind().
   1572   1.6  christos  *
   1573   1.6  christos  * If unsuccessful:
   1574   1.6  christos  *
   1575   1.6  christos  *   - 'dbp' and 'nodep' will not be written to,
   1576   1.6  christos  *   - 'fname' may still be modified as it is passed to dns_db_findext(),
   1577   1.6  christos  *   - 'rdataset' and 'sigrdataset' will remain disassociated.
   1578   1.6  christos  */
   1579   1.6  christos static isc_result_t
   1580   1.6  christos query_additionalauth(query_ctx_t *qctx, const dns_name_t *name,
   1581   1.9  christos 		     dns_rdatatype_t type, dns_db_t **dbp, dns_dbnode_t **nodep,
   1582   1.9  christos 		     dns_name_t *fname, dns_rdataset_t *rdataset,
   1583   1.9  christos 		     dns_rdataset_t *sigrdataset) {
   1584   1.6  christos 	ns_client_t *client = qctx->client;
   1585   1.6  christos 	ns_dbversion_t *dbversion = NULL;
   1586   1.6  christos 	dns_dbversion_t *version = NULL;
   1587   1.6  christos 	dns_dbnode_t *node = NULL;
   1588   1.6  christos 	dns_zone_t *zone = NULL;
   1589   1.6  christos 	dns_db_t *db = NULL;
   1590   1.6  christos 	isc_result_t result;
   1591   1.6  christos 
   1592   1.6  christos 	/*
   1593   1.6  christos 	 * First, look within the same zone database for authoritative
   1594   1.6  christos 	 * additional data.
   1595   1.6  christos 	 */
   1596   1.6  christos 	if (!client->query.authdbset || client->query.authdb == NULL) {
   1597   1.6  christos 		return (ISC_R_NOTFOUND);
   1598   1.6  christos 	}
   1599   1.6  christos 
   1600   1.6  christos 	dbversion = ns_client_findversion(client, client->query.authdb);
   1601   1.6  christos 	if (dbversion == NULL) {
   1602   1.6  christos 		return (ISC_R_NOTFOUND);
   1603   1.6  christos 	}
   1604   1.6  christos 
   1605   1.6  christos 	dns_db_attach(client->query.authdb, &db);
   1606   1.6  christos 	version = dbversion->version;
   1607   1.6  christos 
   1608   1.6  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: same zone");
   1609   1.6  christos 
   1610   1.6  christos 	result = query_additionalauthfind(db, version, name, type, client,
   1611   1.6  christos 					  &node, fname, rdataset, sigrdataset);
   1612   1.6  christos 	if (result != ISC_R_SUCCESS &&
   1613   1.6  christos 	    qctx->view->minimalresponses == dns_minimal_no &&
   1614   1.6  christos 	    RECURSIONOK(client))
   1615   1.6  christos 	{
   1616   1.6  christos 		/*
   1617   1.6  christos 		 * If we aren't doing response minimization and recursion is
   1618   1.6  christos 		 * allowed, we can try and see if any other zone matches.
   1619   1.6  christos 		 */
   1620   1.6  christos 		version = NULL;
   1621   1.6  christos 		dns_db_detach(&db);
   1622   1.6  christos 		result = query_getzonedb(client, name, type, DNS_GETDB_NOLOG,
   1623   1.6  christos 					 &zone, &db, &version);
   1624   1.6  christos 		if (result != ISC_R_SUCCESS) {
   1625   1.6  christos 			return (result);
   1626   1.6  christos 		}
   1627   1.6  christos 		dns_zone_detach(&zone);
   1628   1.6  christos 
   1629   1.6  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_additionalauth: other zone");
   1630   1.6  christos 
   1631   1.6  christos 		result = query_additionalauthfind(db, version, name, type,
   1632   1.6  christos 						  client, &node, fname,
   1633   1.6  christos 						  rdataset, sigrdataset);
   1634   1.6  christos 	}
   1635   1.6  christos 
   1636   1.6  christos 	if (result != ISC_R_SUCCESS) {
   1637   1.6  christos 		dns_db_detach(&db);
   1638   1.6  christos 	} else {
   1639   1.6  christos 		*nodep = node;
   1640   1.6  christos 		node = NULL;
   1641   1.6  christos 
   1642   1.6  christos 		*dbp = db;
   1643   1.6  christos 		db = NULL;
   1644   1.6  christos 	}
   1645   1.6  christos 
   1646   1.6  christos 	return (result);
   1647   1.6  christos }
   1648   1.6  christos 
   1649   1.1  christos static isc_result_t
   1650   1.3  christos query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) {
   1651   1.3  christos 	query_ctx_t *qctx = arg;
   1652   1.3  christos 	ns_client_t *client = qctx->client;
   1653   1.3  christos 	isc_result_t result, eresult = ISC_R_SUCCESS;
   1654   1.3  christos 	dns_dbnode_t *node = NULL;
   1655   1.3  christos 	dns_db_t *db = NULL;
   1656   1.3  christos 	dns_name_t *fname = NULL, *mname = NULL;
   1657   1.3  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   1658   1.3  christos 	dns_rdataset_t *trdataset = NULL;
   1659   1.3  christos 	isc_buffer_t *dbuf = NULL;
   1660   1.1  christos 	isc_buffer_t b;
   1661   1.3  christos 	ns_dbversion_t *dbversion = NULL;
   1662   1.3  christos 	dns_dbversion_t *version = NULL;
   1663   1.3  christos 	bool added_something = false, need_addname = false;
   1664   1.1  christos 	dns_rdatatype_t type;
   1665   1.1  christos 	dns_clientinfomethods_t cm;
   1666   1.1  christos 	dns_clientinfo_t ci;
   1667   1.3  christos 	dns_rdatasetadditional_t additionaltype =
   1668   1.3  christos 		dns_rdatasetadditional_fromauth;
   1669   1.1  christos 
   1670   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   1671   1.1  christos 	REQUIRE(qtype != dns_rdatatype_any);
   1672   1.1  christos 
   1673   1.3  christos 	if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) {
   1674   1.1  christos 		return (ISC_R_SUCCESS);
   1675   1.3  christos 	}
   1676   1.1  christos 
   1677   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb");
   1678   1.1  christos 
   1679   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   1680  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   1681   1.1  christos 
   1682   1.1  christos 	/*
   1683   1.1  christos 	 * We treat type A additional section processing as if it
   1684   1.1  christos 	 * were "any address type" additional section processing.
   1685   1.1  christos 	 * To avoid multiple lookups, we do an 'any' database
   1686   1.1  christos 	 * lookup and iterate over the node.
   1687   1.1  christos 	 */
   1688   1.3  christos 	if (qtype == dns_rdatatype_a) {
   1689   1.1  christos 		type = dns_rdatatype_any;
   1690   1.3  christos 	} else {
   1691   1.1  christos 		type = qtype;
   1692   1.3  christos 	}
   1693   1.1  christos 
   1694   1.1  christos 	/*
   1695   1.1  christos 	 * Get some resources.
   1696   1.1  christos 	 */
   1697   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   1698   1.3  christos 	if (dbuf == NULL) {
   1699   1.1  christos 		goto cleanup;
   1700   1.3  christos 	}
   1701   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   1702   1.3  christos 	rdataset = ns_client_newrdataset(client);
   1703   1.3  christos 	if (fname == NULL || rdataset == NULL) {
   1704   1.1  christos 		goto cleanup;
   1705   1.3  christos 	}
   1706   1.1  christos 	if (WANTDNSSEC(client)) {
   1707   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   1708   1.3  christos 		if (sigrdataset == NULL) {
   1709   1.1  christos 			goto cleanup;
   1710   1.3  christos 		}
   1711   1.1  christos 	}
   1712   1.1  christos 
   1713   1.1  christos 	/*
   1714   1.1  christos 	 * If we want only minimal responses and are here, then it must
   1715   1.1  christos 	 * be for glue.
   1716   1.1  christos 	 */
   1717  1.11  christos 	if (qctx->view->minimalresponses == dns_minimal_yes &&
   1718  1.11  christos 	    client->query.qtype != dns_rdatatype_ns)
   1719  1.11  christos 	{
   1720   1.1  christos 		goto try_glue;
   1721   1.3  christos 	}
   1722   1.1  christos 
   1723   1.1  christos 	/*
   1724   1.6  christos 	 * First, look for authoritative additional data.
   1725   1.1  christos 	 */
   1726   1.6  christos 	result = query_additionalauth(qctx, name, type, &db, &node, fname,
   1727   1.6  christos 				      rdataset, sigrdataset);
   1728   1.1  christos 	if (result == ISC_R_SUCCESS) {
   1729   1.1  christos 		goto found;
   1730   1.1  christos 	}
   1731   1.1  christos 
   1732   1.1  christos 	/*
   1733   1.1  christos 	 * No authoritative data was found.  The cache is our next best bet.
   1734   1.1  christos 	 */
   1735   1.3  christos 	if (!qctx->view->recursion) {
   1736   1.1  christos 		goto try_glue;
   1737   1.3  christos 	}
   1738   1.1  christos 
   1739   1.1  christos 	additionaltype = dns_rdatasetadditional_fromcache;
   1740   1.1  christos 	result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG);
   1741   1.1  christos 	if (result != ISC_R_SUCCESS) {
   1742   1.1  christos 		/*
   1743   1.1  christos 		 * Most likely the client isn't allowed to query the cache.
   1744   1.1  christos 		 */
   1745   1.1  christos 		goto try_glue;
   1746   1.1  christos 	}
   1747   1.1  christos 	/*
   1748   1.1  christos 	 * Attempt to validate glue.
   1749   1.1  christos 	 */
   1750   1.1  christos 	if (sigrdataset == NULL) {
   1751   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   1752   1.3  christos 		if (sigrdataset == NULL) {
   1753   1.1  christos 			goto cleanup;
   1754   1.3  christos 		}
   1755   1.1  christos 	}
   1756   1.1  christos 
   1757   1.1  christos 	version = NULL;
   1758   1.1  christos 	result = dns_db_findext(db, name, version, type,
   1759   1.9  christos 				client->query.dboptions | DNS_DBFIND_GLUEOK |
   1760   1.9  christos 					DNS_DBFIND_ADDITIONALOK,
   1761   1.9  christos 				client->now, &node, fname, &cm, &ci, rdataset,
   1762   1.9  christos 				sigrdataset);
   1763   1.1  christos 
   1764   1.3  christos 	dns_cache_updatestats(qctx->view->cache, result);
   1765   1.3  christos 	if (!WANTDNSSEC(client)) {
   1766   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   1767   1.3  christos 	}
   1768   1.9  christos 	if (result == ISC_R_SUCCESS) {
   1769   1.1  christos 		goto found;
   1770   1.9  christos 	}
   1771   1.1  christos 
   1772   1.3  christos 	if (dns_rdataset_isassociated(rdataset)) {
   1773   1.1  christos 		dns_rdataset_disassociate(rdataset);
   1774   1.3  christos 	}
   1775   1.3  christos 	if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
   1776   1.1  christos 		dns_rdataset_disassociate(sigrdataset);
   1777   1.3  christos 	}
   1778   1.3  christos 	if (node != NULL) {
   1779   1.1  christos 		dns_db_detachnode(db, &node);
   1780   1.3  christos 	}
   1781   1.1  christos 	dns_db_detach(&db);
   1782   1.1  christos 
   1783   1.9  christos try_glue:
   1784   1.1  christos 	/*
   1785   1.1  christos 	 * No cached data was found.  Glue is our last chance.
   1786   1.1  christos 	 * RFC1035 sayeth:
   1787   1.1  christos 	 *
   1788   1.1  christos 	 *	NS records cause both the usual additional section
   1789   1.1  christos 	 *	processing to locate a type A record, and, when used
   1790   1.1  christos 	 *	in a referral, a special search of the zone in which
   1791   1.1  christos 	 *	they reside for glue information.
   1792   1.1  christos 	 *
   1793   1.1  christos 	 * This is the "special search".  Note that we must search
   1794   1.1  christos 	 * the zone where the NS record resides, not the zone it
   1795   1.1  christos 	 * points to, and that we only do the search in the delegation
   1796   1.1  christos 	 * case (identified by client->query.gluedb being set).
   1797   1.1  christos 	 */
   1798   1.1  christos 
   1799   1.3  christos 	if (client->query.gluedb == NULL) {
   1800   1.1  christos 		goto cleanup;
   1801   1.3  christos 	}
   1802   1.1  christos 
   1803   1.1  christos 	/*
   1804   1.1  christos 	 * Don't poison caches using the bailiwick protection model.
   1805   1.1  christos 	 */
   1806   1.3  christos 	if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) {
   1807   1.1  christos 		goto cleanup;
   1808   1.3  christos 	}
   1809   1.1  christos 
   1810   1.3  christos 	dbversion = ns_client_findversion(client, client->query.gluedb);
   1811   1.3  christos 	if (dbversion == NULL) {
   1812   1.1  christos 		goto cleanup;
   1813   1.3  christos 	}
   1814   1.1  christos 
   1815   1.1  christos 	dns_db_attach(client->query.gluedb, &db);
   1816   1.1  christos 	version = dbversion->version;
   1817   1.1  christos 	additionaltype = dns_rdatasetadditional_fromglue;
   1818   1.1  christos 	result = dns_db_findext(db, name, version, type,
   1819   1.1  christos 				client->query.dboptions | DNS_DBFIND_GLUEOK,
   1820   1.9  christos 				client->now, &node, fname, &cm, &ci, rdataset,
   1821   1.9  christos 				sigrdataset);
   1822   1.9  christos 	if (result != ISC_R_SUCCESS && result != DNS_R_ZONECUT &&
   1823  1.16  christos 	    result != DNS_R_GLUE)
   1824  1.16  christos 	{
   1825   1.1  christos 		goto cleanup;
   1826   1.3  christos 	}
   1827   1.1  christos 
   1828   1.9  christos found:
   1829   1.1  christos 	/*
   1830   1.1  christos 	 * We have found a potential additional data rdataset, or
   1831   1.1  christos 	 * at least a node to iterate over.
   1832   1.1  christos 	 */
   1833   1.3  christos 	ns_client_keepname(client, fname, dbuf);
   1834   1.1  christos 
   1835   1.1  christos 	/*
   1836   1.1  christos 	 * If we have an rdataset, add it to the additional data
   1837   1.1  christos 	 * section.
   1838   1.1  christos 	 */
   1839   1.1  christos 	mname = NULL;
   1840   1.1  christos 	if (dns_rdataset_isassociated(rdataset) &&
   1841   1.3  christos 	    !query_isduplicate(client, fname, type, &mname))
   1842   1.3  christos 	{
   1843   1.1  christos 		if (mname != NULL) {
   1844   1.1  christos 			INSIST(mname != fname);
   1845   1.3  christos 			ns_client_releasename(client, &fname);
   1846   1.1  christos 			fname = mname;
   1847   1.3  christos 		} else {
   1848   1.3  christos 			need_addname = true;
   1849   1.3  christos 		}
   1850   1.1  christos 		ISC_LIST_APPEND(fname->list, rdataset, link);
   1851   1.1  christos 		trdataset = rdataset;
   1852   1.1  christos 		rdataset = NULL;
   1853   1.3  christos 		added_something = true;
   1854   1.1  christos 		/*
   1855   1.1  christos 		 * Note: we only add SIGs if we've added the type they cover,
   1856   1.1  christos 		 * so we do not need to check if the SIG rdataset is already
   1857   1.1  christos 		 * in the response.
   1858   1.1  christos 		 */
   1859   1.1  christos 		if (sigrdataset != NULL &&
   1860  1.16  christos 		    dns_rdataset_isassociated(sigrdataset))
   1861  1.16  christos 		{
   1862   1.1  christos 			ISC_LIST_APPEND(fname->list, sigrdataset, link);
   1863   1.1  christos 			sigrdataset = NULL;
   1864   1.1  christos 		}
   1865   1.1  christos 	}
   1866   1.1  christos 
   1867   1.1  christos 	if (qtype == dns_rdatatype_a) {
   1868   1.1  christos 		/*
   1869   1.1  christos 		 * We now go looking for A and AAAA records, along with
   1870   1.1  christos 		 * their signatures.
   1871   1.1  christos 		 *
   1872   1.1  christos 		 * XXXRTH  This code could be more efficient.
   1873   1.1  christos 		 */
   1874   1.1  christos 		if (rdataset != NULL) {
   1875   1.3  christos 			if (dns_rdataset_isassociated(rdataset)) {
   1876   1.1  christos 				dns_rdataset_disassociate(rdataset);
   1877   1.3  christos 			}
   1878   1.1  christos 		} else {
   1879   1.3  christos 			rdataset = ns_client_newrdataset(client);
   1880   1.3  christos 			if (rdataset == NULL) {
   1881   1.1  christos 				goto addname;
   1882   1.3  christos 			}
   1883   1.1  christos 		}
   1884   1.1  christos 		if (sigrdataset != NULL) {
   1885   1.3  christos 			if (dns_rdataset_isassociated(sigrdataset)) {
   1886   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   1887   1.3  christos 			}
   1888   1.1  christos 		} else if (WANTDNSSEC(client)) {
   1889   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   1890   1.3  christos 			if (sigrdataset == NULL) {
   1891   1.1  christos 				goto addname;
   1892   1.3  christos 			}
   1893   1.1  christos 		}
   1894   1.3  christos 		if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) {
   1895   1.1  christos 			goto aaaa_lookup;
   1896   1.3  christos 		}
   1897   1.9  christos 		result = dns_db_findrdataset(db, node, version, dns_rdatatype_a,
   1898   1.9  christos 					     0, client->now, rdataset,
   1899   1.9  christos 					     sigrdataset);
   1900   1.1  christos 		if (result == DNS_R_NCACHENXDOMAIN) {
   1901   1.1  christos 			goto addname;
   1902   1.1  christos 		} else if (result == DNS_R_NCACHENXRRSET) {
   1903   1.1  christos 			dns_rdataset_disassociate(rdataset);
   1904   1.1  christos 			if (sigrdataset != NULL &&
   1905  1.16  christos 			    dns_rdataset_isassociated(sigrdataset))
   1906  1.16  christos 			{
   1907   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   1908   1.3  christos 			}
   1909   1.1  christos 		} else if (result == ISC_R_SUCCESS) {
   1910   1.3  christos 			bool invalid = false;
   1911   1.1  christos 			mname = NULL;
   1912   1.1  christos 			if (additionaltype ==
   1913   1.9  christos 				    dns_rdatasetadditional_fromcache &&
   1914   1.1  christos 			    (DNS_TRUST_PENDING(rdataset->trust) ||
   1915   1.1  christos 			     DNS_TRUST_GLUE(rdataset->trust)))
   1916   1.1  christos 			{
   1917   1.1  christos 				/* validate() may change rdataset->trust */
   1918   1.9  christos 				invalid = !validate(client, db, fname, rdataset,
   1919   1.9  christos 						    sigrdataset);
   1920   1.1  christos 			}
   1921   1.1  christos 			if (invalid && DNS_TRUST_PENDING(rdataset->trust)) {
   1922   1.1  christos 				dns_rdataset_disassociate(rdataset);
   1923   1.1  christos 				if (sigrdataset != NULL &&
   1924  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   1925  1.16  christos 				{
   1926   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   1927   1.3  christos 				}
   1928   1.1  christos 			} else if (!query_isduplicate(client, fname,
   1929   1.9  christos 						      dns_rdatatype_a, &mname))
   1930   1.9  christos 			{
   1931   1.1  christos 				if (mname != fname) {
   1932   1.1  christos 					if (mname != NULL) {
   1933   1.3  christos 						ns_client_releasename(client,
   1934   1.3  christos 								      &fname);
   1935   1.1  christos 						fname = mname;
   1936   1.3  christos 					} else {
   1937   1.3  christos 						need_addname = true;
   1938   1.3  christos 					}
   1939   1.1  christos 				}
   1940   1.1  christos 				ISC_LIST_APPEND(fname->list, rdataset, link);
   1941   1.3  christos 				added_something = true;
   1942   1.1  christos 				if (sigrdataset != NULL &&
   1943  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   1944  1.16  christos 				{
   1945   1.1  christos 					ISC_LIST_APPEND(fname->list,
   1946   1.1  christos 							sigrdataset, link);
   1947   1.1  christos 					sigrdataset =
   1948   1.3  christos 						ns_client_newrdataset(client);
   1949   1.1  christos 				}
   1950   1.3  christos 				rdataset = ns_client_newrdataset(client);
   1951   1.3  christos 				if (rdataset == NULL) {
   1952   1.1  christos 					goto addname;
   1953   1.3  christos 				}
   1954   1.3  christos 				if (WANTDNSSEC(client) && sigrdataset == NULL) {
   1955   1.1  christos 					goto addname;
   1956   1.3  christos 				}
   1957   1.1  christos 			} else {
   1958   1.1  christos 				dns_rdataset_disassociate(rdataset);
   1959   1.1  christos 				if (sigrdataset != NULL &&
   1960  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   1961  1.16  christos 				{
   1962   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   1963   1.3  christos 				}
   1964   1.1  christos 			}
   1965   1.1  christos 		}
   1966   1.9  christos 	aaaa_lookup:
   1967   1.1  christos 		if (query_isduplicate(client, fname, dns_rdatatype_aaaa, NULL))
   1968   1.3  christos 		{
   1969   1.1  christos 			goto addname;
   1970   1.3  christos 		}
   1971   1.1  christos 		result = dns_db_findrdataset(db, node, version,
   1972   1.9  christos 					     dns_rdatatype_aaaa, 0, client->now,
   1973   1.1  christos 					     rdataset, sigrdataset);
   1974   1.1  christos 		if (result == DNS_R_NCACHENXDOMAIN) {
   1975   1.1  christos 			goto addname;
   1976   1.1  christos 		} else if (result == DNS_R_NCACHENXRRSET) {
   1977   1.1  christos 			dns_rdataset_disassociate(rdataset);
   1978   1.1  christos 			if (sigrdataset != NULL &&
   1979  1.16  christos 			    dns_rdataset_isassociated(sigrdataset))
   1980  1.16  christos 			{
   1981   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   1982   1.3  christos 			}
   1983   1.1  christos 		} else if (result == ISC_R_SUCCESS) {
   1984   1.3  christos 			bool invalid = false;
   1985   1.1  christos 			mname = NULL;
   1986   1.3  christos 
   1987   1.1  christos 			if (additionaltype ==
   1988   1.9  christos 				    dns_rdatasetadditional_fromcache &&
   1989   1.1  christos 			    (DNS_TRUST_PENDING(rdataset->trust) ||
   1990   1.1  christos 			     DNS_TRUST_GLUE(rdataset->trust)))
   1991   1.1  christos 			{
   1992   1.1  christos 				/* validate() may change rdataset->trust */
   1993   1.9  christos 				invalid = !validate(client, db, fname, rdataset,
   1994   1.9  christos 						    sigrdataset);
   1995   1.1  christos 			}
   1996   1.1  christos 
   1997   1.1  christos 			if (invalid && DNS_TRUST_PENDING(rdataset->trust)) {
   1998   1.1  christos 				dns_rdataset_disassociate(rdataset);
   1999   1.1  christos 				if (sigrdataset != NULL &&
   2000  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2001  1.16  christos 				{
   2002   1.1  christos 					dns_rdataset_disassociate(sigrdataset);
   2003   1.3  christos 				}
   2004   1.1  christos 			} else if (!query_isduplicate(client, fname,
   2005   1.9  christos 						      dns_rdatatype_aaaa,
   2006  1.16  christos 						      &mname))
   2007  1.16  christos 			{
   2008   1.1  christos 				if (mname != fname) {
   2009   1.1  christos 					if (mname != NULL) {
   2010   1.3  christos 						ns_client_releasename(client,
   2011   1.3  christos 								      &fname);
   2012   1.1  christos 						fname = mname;
   2013   1.3  christos 					} else {
   2014   1.3  christos 						need_addname = true;
   2015   1.3  christos 					}
   2016   1.1  christos 				}
   2017   1.1  christos 				ISC_LIST_APPEND(fname->list, rdataset, link);
   2018   1.3  christos 				added_something = true;
   2019   1.1  christos 				if (sigrdataset != NULL &&
   2020  1.16  christos 				    dns_rdataset_isassociated(sigrdataset))
   2021  1.16  christos 				{
   2022   1.1  christos 					ISC_LIST_APPEND(fname->list,
   2023   1.1  christos 							sigrdataset, link);
   2024   1.1  christos 					sigrdataset = NULL;
   2025   1.1  christos 				}
   2026   1.1  christos 				rdataset = NULL;
   2027   1.1  christos 			}
   2028   1.1  christos 		}
   2029   1.1  christos 	}
   2030   1.1  christos 
   2031   1.9  christos addname:
   2032   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: addname");
   2033   1.1  christos 	/*
   2034   1.1  christos 	 * If we haven't added anything, then we're done.
   2035   1.1  christos 	 */
   2036   1.3  christos 	if (!added_something) {
   2037   1.1  christos 		goto cleanup;
   2038   1.3  christos 	}
   2039   1.1  christos 
   2040   1.1  christos 	/*
   2041   1.1  christos 	 * We may have added our rdatasets to an existing name, if so, then
   2042   1.3  christos 	 * need_addname will be false.  Whether we used an existing name
   2043   1.1  christos 	 * or a new one, we must set fname to NULL to prevent cleanup.
   2044   1.1  christos 	 */
   2045   1.3  christos 	if (need_addname) {
   2046   1.1  christos 		dns_message_addname(client->message, fname,
   2047   1.1  christos 				    DNS_SECTION_ADDITIONAL);
   2048   1.3  christos 	}
   2049   1.1  christos 	fname = NULL;
   2050   1.1  christos 
   2051   1.1  christos 	/*
   2052  1.15  christos 	 * In some cases, a record that has been added as additional
   2053  1.15  christos 	 * data may *also* trigger the addition of additional data.
   2054  1.15  christos 	 * This cannot go more than MAX_RESTARTS levels deep.
   2055  1.15  christos 	 */
   2056  1.15  christos 	if (trdataset != NULL && dns_rdatatype_followadditional(type)) {
   2057   1.9  christos 		eresult = dns_rdataset_additionaldata(
   2058   1.9  christos 			trdataset, query_additional_cb, qctx);
   2059   1.1  christos 	}
   2060   1.1  christos 
   2061   1.9  christos cleanup:
   2062   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup");
   2063   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   2064   1.3  christos 	if (sigrdataset != NULL) {
   2065   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   2066   1.3  christos 	}
   2067   1.3  christos 	if (fname != NULL) {
   2068   1.3  christos 		ns_client_releasename(client, &fname);
   2069   1.3  christos 	}
   2070   1.3  christos 	if (node != NULL) {
   2071   1.1  christos 		dns_db_detachnode(db, &node);
   2072   1.3  christos 	}
   2073   1.3  christos 	if (db != NULL) {
   2074   1.1  christos 		dns_db_detach(&db);
   2075   1.3  christos 	}
   2076   1.1  christos 
   2077   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: done");
   2078   1.1  christos 	return (eresult);
   2079   1.1  christos }
   2080   1.1  christos 
   2081   1.3  christos /*
   2082   1.3  christos  * Add 'rdataset' to 'name'.
   2083   1.3  christos  */
   2084  1.15  christos static void
   2085   1.3  christos query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) {
   2086   1.3  christos 	ISC_LIST_APPEND(name->list, rdataset, link);
   2087   1.3  christos }
   2088   1.3  christos 
   2089   1.3  christos /*
   2090   1.3  christos  * Set the ordering for 'rdataset'.
   2091   1.3  christos  */
   2092   1.1  christos static void
   2093   1.3  christos query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) {
   2094   1.3  christos 	ns_client_t *client = qctx->client;
   2095   1.3  christos 	dns_order_t *order = client->view->order;
   2096   1.1  christos 
   2097   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_setorder");
   2098   1.1  christos 
   2099   1.3  christos 	UNUSED(client);
   2100   1.1  christos 
   2101   1.3  christos 	if (order != NULL) {
   2102   1.9  christos 		rdataset->attributes |= dns_order_find(
   2103   1.9  christos 			order, name, rdataset->type, rdataset->rdclass);
   2104   1.3  christos 	}
   2105   1.1  christos 	rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
   2106   1.9  christos }
   2107   1.3  christos 
   2108   1.3  christos /*
   2109   1.3  christos  * Handle glue and fetch any other needed additional data for 'rdataset'.
   2110   1.3  christos  */
   2111   1.3  christos static void
   2112   1.3  christos query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) {
   2113   1.3  christos 	ns_client_t *client = qctx->client;
   2114   1.3  christos 	isc_result_t result;
   2115   1.3  christos 
   2116   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional");
   2117   1.1  christos 
   2118   1.3  christos 	if (NOADDITIONAL(client)) {
   2119   1.1  christos 		return;
   2120   1.3  christos 	}
   2121   1.1  christos 
   2122   1.1  christos 	/*
   2123   1.1  christos 	 * Try to process glue directly.
   2124   1.1  christos 	 */
   2125   1.3  christos 	if (qctx->view->use_glue_cache &&
   2126   1.1  christos 	    (rdataset->type == dns_rdatatype_ns) &&
   2127   1.1  christos 	    (client->query.gluedb != NULL) &&
   2128   1.1  christos 	    dns_db_iszone(client->query.gluedb))
   2129   1.1  christos 	{
   2130   1.1  christos 		ns_dbversion_t *dbversion;
   2131   1.1  christos 
   2132   1.3  christos 		dbversion = ns_client_findversion(client, client->query.gluedb);
   2133   1.3  christos 		if (dbversion == NULL) {
   2134   1.1  christos 			goto regular;
   2135   1.1  christos 		}
   2136   1.1  christos 
   2137   1.1  christos 		result = dns_rdataset_addglue(rdataset, dbversion->version,
   2138   1.3  christos 					      client->message);
   2139   1.3  christos 		if (result == ISC_R_SUCCESS) {
   2140   1.1  christos 			return;
   2141   1.3  christos 		}
   2142   1.1  christos 	}
   2143   1.1  christos 
   2144   1.9  christos regular:
   2145   1.1  christos 	/*
   2146   1.3  christos 	 * Add other additional data if needed.
   2147   1.1  christos 	 * We don't care if dns_rdataset_additionaldata() fails.
   2148   1.1  christos 	 */
   2149   1.3  christos 	(void)dns_rdataset_additionaldata(rdataset, query_additional_cb, qctx);
   2150   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_additional: done");
   2151   1.1  christos }
   2152   1.1  christos 
   2153   1.1  christos static void
   2154   1.3  christos query_addrrset(query_ctx_t *qctx, dns_name_t **namep,
   2155   1.1  christos 	       dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,
   2156   1.9  christos 	       isc_buffer_t *dbuf, dns_section_t section) {
   2157   1.3  christos 	isc_result_t result;
   2158   1.3  christos 	ns_client_t *client = qctx->client;
   2159   1.1  christos 	dns_name_t *name = *namep, *mname = NULL;
   2160   1.1  christos 	dns_rdataset_t *rdataset = *rdatasetp, *mrdataset = NULL;
   2161   1.1  christos 	dns_rdataset_t *sigrdataset = NULL;
   2162   1.1  christos 
   2163   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addrrset");
   2164   1.1  christos 
   2165   1.3  christos 	REQUIRE(name != NULL);
   2166   1.3  christos 
   2167   1.3  christos 	if (sigrdatasetp != NULL) {
   2168   1.1  christos 		sigrdataset = *sigrdatasetp;
   2169   1.3  christos 	}
   2170   1.1  christos 
   2171   1.1  christos 	/*%
   2172   1.1  christos 	 * To the current response for 'client', add the answer RRset
   2173   1.1  christos 	 * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
   2174   1.1  christos 	 * owner name '*namep', to section 'section', unless they are
   2175   1.1  christos 	 * already there.  Also add any pertinent additional data.
   2176   1.1  christos 	 *
   2177   1.1  christos 	 * If 'dbuf' is not NULL, then '*namep' is the name whose data is
   2178   1.1  christos 	 * stored in 'dbuf'.  In this case, query_addrrset() guarantees that
   2179   1.1  christos 	 * when it returns the name will either have been kept or released.
   2180   1.1  christos 	 */
   2181   1.9  christos 	result = dns_message_findname(client->message, section, name,
   2182   1.9  christos 				      rdataset->type, rdataset->covers, &mname,
   2183   1.9  christos 				      &mrdataset);
   2184   1.1  christos 	if (result == ISC_R_SUCCESS) {
   2185   1.1  christos 		/*
   2186   1.1  christos 		 * We've already got an RRset of the given name and type.
   2187   1.1  christos 		 */
   2188   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: dns_message_findname "
   2189   1.9  christos 					 "succeeded: done");
   2190   1.3  christos 		if (dbuf != NULL) {
   2191   1.3  christos 			ns_client_releasename(client, namep);
   2192   1.3  christos 		}
   2193   1.3  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) {
   2194   1.1  christos 			mrdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   2195   1.3  christos 		}
   2196  1.13  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_STALE_ADDED) != 0)
   2197  1.13  christos 		{
   2198  1.13  christos 			mrdataset->attributes |= DNS_RDATASETATTR_STALE_ADDED;
   2199  1.13  christos 		}
   2200   1.1  christos 		return;
   2201   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   2202   1.1  christos 		/*
   2203   1.1  christos 		 * The name doesn't exist.
   2204   1.1  christos 		 */
   2205   1.3  christos 		if (dbuf != NULL) {
   2206   1.3  christos 			ns_client_keepname(client, name, dbuf);
   2207   1.3  christos 		}
   2208   1.1  christos 		dns_message_addname(client->message, name, section);
   2209   1.1  christos 		*namep = NULL;
   2210   1.1  christos 		mname = name;
   2211   1.1  christos 	} else {
   2212   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   2213   1.3  christos 		if (dbuf != NULL) {
   2214   1.3  christos 			ns_client_releasename(client, namep);
   2215   1.3  christos 		}
   2216   1.1  christos 	}
   2217   1.1  christos 
   2218   1.1  christos 	if (rdataset->trust != dns_trust_secure &&
   2219   1.9  christos 	    (section == DNS_SECTION_ANSWER || section == DNS_SECTION_AUTHORITY))
   2220   1.3  christos 	{
   2221   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   2222   1.3  christos 	}
   2223   1.3  christos 
   2224   1.3  christos 	/*
   2225   1.3  christos 	 * Update message name, set rdataset order, and do additional
   2226   1.3  christos 	 * section processing if needed.
   2227   1.3  christos 	 */
   2228   1.3  christos 	query_addtoname(mname, rdataset);
   2229   1.3  christos 	query_setorder(qctx, mname, rdataset);
   2230   1.3  christos 	query_additional(qctx, rdataset);
   2231   1.1  christos 
   2232   1.1  christos 	/*
   2233   1.1  christos 	 * Note: we only add SIGs if we've added the type they cover, so
   2234   1.1  christos 	 * we do not need to check if the SIG rdataset is already in the
   2235   1.1  christos 	 * response.
   2236   1.1  christos 	 */
   2237   1.1  christos 	*rdatasetp = NULL;
   2238   1.1  christos 	if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
   2239   1.1  christos 		/*
   2240   1.1  christos 		 * We have a signature.  Add it to the response.
   2241   1.1  christos 		 */
   2242   1.1  christos 		ISC_LIST_APPEND(mname->list, sigrdataset, link);
   2243   1.1  christos 		*sigrdatasetp = NULL;
   2244   1.1  christos 	}
   2245   1.1  christos 
   2246   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: done");
   2247   1.1  christos }
   2248   1.1  christos 
   2249   1.1  christos /*
   2250   1.1  christos  * Mark the RRsets as secure.  Update the cache (db) to reflect the
   2251   1.1  christos  * change in trust level.
   2252   1.1  christos  */
   2253   1.1  christos static void
   2254   1.1  christos mark_secure(ns_client_t *client, dns_db_t *db, dns_name_t *name,
   2255   1.1  christos 	    dns_rdata_rrsig_t *rrsig, dns_rdataset_t *rdataset,
   2256   1.9  christos 	    dns_rdataset_t *sigrdataset) {
   2257   1.1  christos 	isc_result_t result;
   2258   1.1  christos 	dns_dbnode_t *node = NULL;
   2259   1.1  christos 	dns_clientinfomethods_t cm;
   2260   1.1  christos 	dns_clientinfo_t ci;
   2261   1.1  christos 	isc_stdtime_t now;
   2262   1.1  christos 
   2263   1.1  christos 	rdataset->trust = dns_trust_secure;
   2264   1.1  christos 	sigrdataset->trust = dns_trust_secure;
   2265   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2266  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   2267   1.1  christos 
   2268   1.1  christos 	/*
   2269   1.1  christos 	 * Save the updated secure state.  Ignore failures.
   2270   1.1  christos 	 */
   2271   1.3  christos 	result = dns_db_findnodeext(db, name, true, &cm, &ci, &node);
   2272   1.9  christos 	if (result != ISC_R_SUCCESS) {
   2273   1.1  christos 		return;
   2274   1.9  christos 	}
   2275   1.1  christos 
   2276   1.1  christos 	isc_stdtime_get(&now);
   2277   1.1  christos 	dns_rdataset_trimttl(rdataset, sigrdataset, rrsig, now,
   2278   1.1  christos 			     client->view->acceptexpired);
   2279   1.1  christos 
   2280   1.9  christos 	(void)dns_db_addrdataset(db, node, NULL, client->now, rdataset, 0,
   2281   1.9  christos 				 NULL);
   2282   1.9  christos 	(void)dns_db_addrdataset(db, node, NULL, client->now, sigrdataset, 0,
   2283   1.9  christos 				 NULL);
   2284   1.1  christos 	dns_db_detachnode(db, &node);
   2285   1.1  christos }
   2286   1.1  christos 
   2287   1.1  christos /*
   2288   1.1  christos  * Find the secure key that corresponds to rrsig.
   2289   1.1  christos  * Note: 'keyrdataset' maintains state between successive calls,
   2290   1.1  christos  * there may be multiple keys with the same keyid.
   2291   1.3  christos  * Return false if we have exhausted all the possible keys.
   2292   1.1  christos  */
   2293   1.3  christos static bool
   2294   1.1  christos get_key(ns_client_t *client, dns_db_t *db, dns_rdata_rrsig_t *rrsig,
   2295   1.9  christos 	dns_rdataset_t *keyrdataset, dst_key_t **keyp) {
   2296   1.1  christos 	isc_result_t result;
   2297   1.1  christos 	dns_dbnode_t *node = NULL;
   2298   1.3  christos 	bool secure = false;
   2299   1.1  christos 	dns_clientinfomethods_t cm;
   2300   1.1  christos 	dns_clientinfo_t ci;
   2301   1.1  christos 
   2302   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2303  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   2304   1.1  christos 
   2305   1.1  christos 	if (!dns_rdataset_isassociated(keyrdataset)) {
   2306   1.9  christos 		result = dns_db_findnodeext(db, &rrsig->signer, false, &cm, &ci,
   2307   1.9  christos 					    &node);
   2308   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2309   1.3  christos 			return (false);
   2310   1.9  christos 		}
   2311   1.1  christos 
   2312   1.1  christos 		result = dns_db_findrdataset(db, node, NULL,
   2313   1.1  christos 					     dns_rdatatype_dnskey, 0,
   2314   1.1  christos 					     client->now, keyrdataset, NULL);
   2315   1.1  christos 		dns_db_detachnode(db, &node);
   2316   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2317   1.3  christos 			return (false);
   2318   1.9  christos 		}
   2319   1.1  christos 
   2320   1.9  christos 		if (keyrdataset->trust != dns_trust_secure) {
   2321   1.3  christos 			return (false);
   2322   1.9  christos 		}
   2323   1.1  christos 
   2324   1.1  christos 		result = dns_rdataset_first(keyrdataset);
   2325   1.9  christos 	} else {
   2326   1.1  christos 		result = dns_rdataset_next(keyrdataset);
   2327   1.9  christos 	}
   2328   1.1  christos 
   2329   1.9  christos 	for (; result == ISC_R_SUCCESS; result = dns_rdataset_next(keyrdataset))
   2330   1.9  christos 	{
   2331   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   2332   1.1  christos 		isc_buffer_t b;
   2333   1.1  christos 
   2334   1.1  christos 		dns_rdataset_current(keyrdataset, &rdata);
   2335   1.1  christos 		isc_buffer_init(&b, rdata.data, rdata.length);
   2336   1.1  christos 		isc_buffer_add(&b, rdata.length);
   2337   1.1  christos 		result = dst_key_fromdns(&rrsig->signer, rdata.rdclass, &b,
   2338   1.1  christos 					 client->mctx, keyp);
   2339   1.9  christos 		if (result != ISC_R_SUCCESS) {
   2340   1.1  christos 			continue;
   2341   1.9  christos 		}
   2342   1.1  christos 		if (rrsig->algorithm == (dns_secalg_t)dst_key_alg(*keyp) &&
   2343   1.1  christos 		    rrsig->keyid == (dns_keytag_t)dst_key_id(*keyp) &&
   2344   1.9  christos 		    dst_key_iszonekey(*keyp))
   2345   1.9  christos 		{
   2346   1.3  christos 			secure = true;
   2347   1.1  christos 			break;
   2348   1.1  christos 		}
   2349   1.1  christos 		dst_key_free(keyp);
   2350   1.1  christos 	}
   2351   1.1  christos 	return (secure);
   2352   1.1  christos }
   2353   1.1  christos 
   2354   1.3  christos static bool
   2355   1.1  christos verify(dst_key_t *key, dns_name_t *name, dns_rdataset_t *rdataset,
   2356   1.9  christos        dns_rdata_t *rdata, ns_client_t *client) {
   2357   1.1  christos 	isc_result_t result;
   2358   1.1  christos 	dns_fixedname_t fixed;
   2359   1.3  christos 	bool ignore = false;
   2360   1.1  christos 
   2361   1.1  christos 	dns_fixedname_init(&fixed);
   2362   1.1  christos 
   2363   1.1  christos again:
   2364   1.3  christos 	result = dns_dnssec_verify(name, rdataset, key, ignore,
   2365   1.9  christos 				   client->view->maxbits, client->mctx, rdata,
   2366   1.9  christos 				   NULL);
   2367   1.1  christos 	if (result == DNS_R_SIGEXPIRED && client->view->acceptexpired) {
   2368   1.3  christos 		ignore = true;
   2369   1.1  christos 		goto again;
   2370   1.1  christos 	}
   2371   1.9  christos 	if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
   2372   1.3  christos 		return (true);
   2373   1.9  christos 	}
   2374   1.3  christos 	return (false);
   2375   1.1  christos }
   2376   1.1  christos 
   2377   1.1  christos /*
   2378   1.1  christos  * Validate the rdataset if possible with available records.
   2379   1.1  christos  */
   2380   1.3  christos static bool
   2381   1.1  christos validate(ns_client_t *client, dns_db_t *db, dns_name_t *name,
   2382   1.9  christos 	 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
   2383   1.1  christos 	isc_result_t result;
   2384   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   2385   1.1  christos 	dns_rdata_rrsig_t rrsig;
   2386   1.1  christos 	dst_key_t *key = NULL;
   2387   1.1  christos 	dns_rdataset_t keyrdataset;
   2388   1.1  christos 
   2389   1.9  christos 	if (sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset)) {
   2390   1.3  christos 		return (false);
   2391   1.9  christos 	}
   2392   1.1  christos 
   2393   1.9  christos 	for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
   2394   1.9  christos 	     result = dns_rdataset_next(sigrdataset))
   2395   1.9  christos 	{
   2396   1.1  christos 		dns_rdata_reset(&rdata);
   2397   1.1  christos 		dns_rdataset_current(sigrdataset, &rdata);
   2398   1.1  christos 		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
   2399   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2400   1.1  christos 		if (!dns_resolver_algorithm_supported(client->view->resolver,
   2401   1.1  christos 						      name, rrsig.algorithm))
   2402   1.9  christos 		{
   2403   1.1  christos 			continue;
   2404   1.9  christos 		}
   2405   1.9  christos 		if (!dns_name_issubdomain(name, &rrsig.signer)) {
   2406   1.1  christos 			continue;
   2407   1.9  christos 		}
   2408   1.1  christos 		dns_rdataset_init(&keyrdataset);
   2409   1.1  christos 		do {
   2410   1.9  christos 			if (!get_key(client, db, &rrsig, &keyrdataset, &key)) {
   2411   1.1  christos 				break;
   2412   1.9  christos 			}
   2413   1.1  christos 			if (verify(key, name, rdataset, &rdata, client)) {
   2414   1.1  christos 				dst_key_free(&key);
   2415   1.1  christos 				dns_rdataset_disassociate(&keyrdataset);
   2416   1.9  christos 				mark_secure(client, db, name, &rrsig, rdataset,
   2417   1.9  christos 					    sigrdataset);
   2418   1.3  christos 				return (true);
   2419   1.1  christos 			}
   2420   1.1  christos 			dst_key_free(&key);
   2421   1.1  christos 		} while (1);
   2422   1.9  christos 		if (dns_rdataset_isassociated(&keyrdataset)) {
   2423   1.1  christos 			dns_rdataset_disassociate(&keyrdataset);
   2424   1.9  christos 		}
   2425   1.1  christos 	}
   2426   1.3  christos 	return (false);
   2427   1.1  christos }
   2428   1.1  christos 
   2429   1.1  christos static void
   2430   1.1  christos fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) {
   2431   1.9  christos 	if (*rdataset == NULL) {
   2432   1.3  christos 		*rdataset = ns_client_newrdataset(client);
   2433   1.9  christos 	} else if (dns_rdataset_isassociated(*rdataset)) {
   2434   1.1  christos 		dns_rdataset_disassociate(*rdataset);
   2435   1.9  christos 	}
   2436   1.1  christos }
   2437   1.1  christos 
   2438   1.1  christos static void
   2439   1.1  christos fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf,
   2440   1.9  christos 	 isc_buffer_t *nbuf) {
   2441   1.1  christos 	if (*fname == NULL) {
   2442   1.3  christos 		*dbuf = ns_client_getnamebuf(client);
   2443   1.9  christos 		if (*dbuf == NULL) {
   2444   1.1  christos 			return;
   2445   1.9  christos 		}
   2446   1.3  christos 		*fname = ns_client_newname(client, *dbuf, nbuf);
   2447   1.1  christos 	}
   2448   1.1  christos }
   2449   1.1  christos 
   2450   1.1  christos static void
   2451   1.1  christos free_devent(ns_client_t *client, isc_event_t **eventp,
   2452   1.9  christos 	    dns_fetchevent_t **deventp) {
   2453   1.1  christos 	dns_fetchevent_t *devent = *deventp;
   2454   1.1  christos 
   2455   1.9  christos 	REQUIRE((void *)(*eventp) == (void *)(*deventp));
   2456   1.9  christos 
   2457   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "free_devent");
   2458   1.1  christos 
   2459   1.3  christos 	if (devent->fetch != NULL) {
   2460   1.1  christos 		dns_resolver_destroyfetch(&devent->fetch);
   2461   1.3  christos 	}
   2462   1.3  christos 	if (devent->node != NULL) {
   2463   1.1  christos 		dns_db_detachnode(devent->db, &devent->node);
   2464   1.3  christos 	}
   2465   1.3  christos 	if (devent->db != NULL) {
   2466   1.1  christos 		dns_db_detach(&devent->db);
   2467   1.3  christos 	}
   2468   1.3  christos 	if (devent->rdataset != NULL) {
   2469   1.3  christos 		ns_client_putrdataset(client, &devent->rdataset);
   2470   1.3  christos 	}
   2471   1.3  christos 	if (devent->sigrdataset != NULL) {
   2472   1.3  christos 		ns_client_putrdataset(client, &devent->sigrdataset);
   2473   1.3  christos 	}
   2474   1.9  christos 
   2475   1.1  christos 	/*
   2476   1.1  christos 	 * If the two pointers are the same then leave the setting of
   2477   1.1  christos 	 * (*deventp) to NULL to isc_event_free.
   2478   1.1  christos 	 */
   2479   1.9  christos 	if ((void *)eventp != (void *)deventp) {
   2480   1.1  christos 		(*deventp) = NULL;
   2481   1.9  christos 	}
   2482   1.1  christos 	isc_event_free(eventp);
   2483   1.1  christos }
   2484   1.1  christos 
   2485   1.1  christos static void
   2486   1.1  christos prefetch_done(isc_task_t *task, isc_event_t *event) {
   2487   1.1  christos 	dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
   2488   1.1  christos 	ns_client_t *client;
   2489   1.1  christos 
   2490   1.1  christos 	UNUSED(task);
   2491   1.1  christos 
   2492   1.1  christos 	REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
   2493   1.1  christos 	client = devent->ev_arg;
   2494   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   2495   1.1  christos 	REQUIRE(task == client->task);
   2496   1.1  christos 
   2497   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "prefetch_done");
   2498   1.9  christos 
   2499   1.1  christos 	LOCK(&client->query.fetchlock);
   2500   1.1  christos 	if (client->query.prefetch != NULL) {
   2501   1.1  christos 		INSIST(devent->fetch == client->query.prefetch);
   2502   1.1  christos 		client->query.prefetch = NULL;
   2503   1.1  christos 	}
   2504   1.1  christos 	UNLOCK(&client->query.fetchlock);
   2505   1.9  christos 
   2506   1.9  christos 	/*
   2507   1.9  christos 	 * We're done prefetching, detach from quota.
   2508   1.9  christos 	 */
   2509   1.9  christos 	if (client->recursionquota != NULL) {
   2510   1.9  christos 		isc_quota_detach(&client->recursionquota);
   2511  1.16  christos 		ns_stats_decrement(client->sctx->nsstats,
   2512  1.16  christos 				   ns_statscounter_recursclients);
   2513   1.9  christos 	}
   2514   1.9  christos 
   2515   1.1  christos 	free_devent(client, &event, &devent);
   2516  1.11  christos 	isc_nmhandle_detach(&client->prefetchhandle);
   2517   1.1  christos }
   2518   1.1  christos 
   2519   1.1  christos static void
   2520   1.1  christos query_prefetch(ns_client_t *client, dns_name_t *qname,
   2521   1.9  christos 	       dns_rdataset_t *rdataset) {
   2522   1.1  christos 	isc_result_t result;
   2523   1.1  christos 	isc_sockaddr_t *peeraddr;
   2524   1.1  christos 	dns_rdataset_t *tmprdataset;
   2525   1.1  christos 	unsigned int options;
   2526   1.1  christos 
   2527   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_prefetch");
   2528   1.9  christos 
   2529   1.1  christos 	if (client->query.prefetch != NULL ||
   2530   1.1  christos 	    client->view->prefetch_trigger == 0U ||
   2531   1.1  christos 	    rdataset->ttl > client->view->prefetch_trigger ||
   2532   1.1  christos 	    (rdataset->attributes & DNS_RDATASETATTR_PREFETCH) == 0)
   2533   1.9  christos 	{
   2534   1.1  christos 		return;
   2535   1.9  christos 	}
   2536   1.1  christos 
   2537   1.1  christos 	if (client->recursionquota == NULL) {
   2538   1.1  christos 		result = isc_quota_attach(&client->sctx->recursionquota,
   2539   1.1  christos 					  &client->recursionquota);
   2540  1.15  christos 		switch (result) {
   2541  1.15  christos 		case ISC_R_SUCCESS:
   2542  1.16  christos 			ns_stats_increment(client->sctx->nsstats,
   2543  1.16  christos 					   ns_statscounter_recursclients);
   2544  1.15  christos 			break;
   2545  1.15  christos 		case ISC_R_SOFTQUOTA:
   2546   1.9  christos 			isc_quota_detach(&client->recursionquota);
   2547  1.15  christos 			FALLTHROUGH;
   2548  1.15  christos 		default:
   2549   1.1  christos 			return;
   2550   1.6  christos 		}
   2551   1.1  christos 	}
   2552   1.1  christos 
   2553   1.3  christos 	tmprdataset = ns_client_newrdataset(client);
   2554   1.9  christos 	if (tmprdataset == NULL) {
   2555   1.1  christos 		return;
   2556   1.9  christos 	}
   2557   1.9  christos 
   2558   1.9  christos 	if (!TCP(client)) {
   2559   1.1  christos 		peeraddr = &client->peeraddr;
   2560   1.9  christos 	} else {
   2561   1.1  christos 		peeraddr = NULL;
   2562   1.9  christos 	}
   2563   1.9  christos 
   2564  1.11  christos 	isc_nmhandle_attach(client->handle, &client->prefetchhandle);
   2565   1.1  christos 	options = client->query.fetchoptions | DNS_FETCHOPT_PREFETCH;
   2566   1.9  christos 	result = dns_resolver_createfetch(
   2567   1.9  christos 		client->view->resolver, qname, rdataset->type, NULL, NULL, NULL,
   2568   1.9  christos 		peeraddr, client->message->id, options, 0, NULL, client->task,
   2569   1.9  christos 		prefetch_done, client, tmprdataset, NULL,
   2570   1.9  christos 		&client->query.prefetch);
   2571   1.1  christos 	if (result != ISC_R_SUCCESS) {
   2572   1.3  christos 		ns_client_putrdataset(client, &tmprdataset);
   2573  1.11  christos 		isc_nmhandle_detach(&client->prefetchhandle);
   2574   1.1  christos 	}
   2575   1.9  christos 
   2576   1.1  christos 	dns_rdataset_clearprefetch(rdataset);
   2577   1.9  christos 	ns_stats_increment(client->sctx->nsstats, ns_statscounter_prefetch);
   2578   1.1  christos }
   2579   1.1  christos 
   2580  1.15  christos static void
   2581   1.1  christos rpz_clean(dns_zone_t **zonep, dns_db_t **dbp, dns_dbnode_t **nodep,
   2582   1.9  christos 	  dns_rdataset_t **rdatasetp) {
   2583   1.1  christos 	if (nodep != NULL && *nodep != NULL) {
   2584   1.1  christos 		REQUIRE(dbp != NULL && *dbp != NULL);
   2585   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   2586   1.1  christos 	}
   2587   1.9  christos 	if (dbp != NULL && *dbp != NULL) {
   2588   1.1  christos 		dns_db_detach(dbp);
   2589   1.9  christos 	}
   2590   1.9  christos 	if (zonep != NULL && *zonep != NULL) {
   2591   1.1  christos 		dns_zone_detach(zonep);
   2592   1.9  christos 	}
   2593   1.1  christos 	if (rdatasetp != NULL && *rdatasetp != NULL &&
   2594   1.1  christos 	    dns_rdataset_isassociated(*rdatasetp))
   2595   1.9  christos 	{
   2596   1.1  christos 		dns_rdataset_disassociate(*rdatasetp);
   2597   1.9  christos 	}
   2598   1.1  christos }
   2599   1.1  christos 
   2600  1.15  christos static void
   2601   1.1  christos rpz_match_clear(dns_rpz_st_t *st) {
   2602   1.1  christos 	rpz_clean(&st->m.zone, &st->m.db, &st->m.node, &st->m.rdataset);
   2603   1.1  christos 	st->m.version = NULL;
   2604   1.1  christos }
   2605   1.1  christos 
   2606  1.15  christos static isc_result_t
   2607   1.1  christos rpz_ready(ns_client_t *client, dns_rdataset_t **rdatasetp) {
   2608   1.1  christos 	REQUIRE(rdatasetp != NULL);
   2609   1.1  christos 
   2610   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_ready");
   2611   1.1  christos 
   2612   1.1  christos 	if (*rdatasetp == NULL) {
   2613   1.3  christos 		*rdatasetp = ns_client_newrdataset(client);
   2614   1.1  christos 		if (*rdatasetp == NULL) {
   2615   1.9  christos 			CTRACE(ISC_LOG_ERROR, "rpz_ready: "
   2616   1.9  christos 					      "ns_client_newrdataset failed");
   2617   1.1  christos 			return (DNS_R_SERVFAIL);
   2618   1.1  christos 		}
   2619   1.1  christos 	} else if (dns_rdataset_isassociated(*rdatasetp)) {
   2620   1.1  christos 		dns_rdataset_disassociate(*rdatasetp);
   2621   1.1  christos 	}
   2622   1.1  christos 	return (ISC_R_SUCCESS);
   2623   1.1  christos }
   2624   1.1  christos 
   2625   1.1  christos static void
   2626   1.1  christos rpz_st_clear(ns_client_t *client) {
   2627   1.1  christos 	dns_rpz_st_t *st = client->query.rpz_st;
   2628   1.1  christos 
   2629   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_st_clear");
   2630   1.1  christos 
   2631   1.1  christos 	if (st->m.rdataset != NULL) {
   2632   1.3  christos 		ns_client_putrdataset(client, &st->m.rdataset);
   2633   1.1  christos 	}
   2634   1.1  christos 	rpz_match_clear(st);
   2635   1.1  christos 
   2636   1.1  christos 	rpz_clean(NULL, &st->r.db, NULL, NULL);
   2637   1.1  christos 	if (st->r.ns_rdataset != NULL) {
   2638   1.3  christos 		ns_client_putrdataset(client, &st->r.ns_rdataset);
   2639   1.1  christos 	}
   2640   1.1  christos 	if (st->r.r_rdataset != NULL) {
   2641   1.3  christos 		ns_client_putrdataset(client, &st->r.r_rdataset);
   2642   1.1  christos 	}
   2643   1.1  christos 
   2644   1.1  christos 	rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL);
   2645   1.1  christos 	if (st->q.rdataset != NULL) {
   2646   1.3  christos 		ns_client_putrdataset(client, &st->q.rdataset);
   2647   1.1  christos 	}
   2648   1.1  christos 	if (st->q.sigrdataset != NULL) {
   2649   1.3  christos 		ns_client_putrdataset(client, &st->q.sigrdataset);
   2650   1.1  christos 	}
   2651   1.1  christos 	st->state = 0;
   2652   1.1  christos 	st->m.type = DNS_RPZ_TYPE_BAD;
   2653   1.1  christos 	st->m.policy = DNS_RPZ_POLICY_MISS;
   2654   1.1  christos 	if (st->rpsdb != NULL) {
   2655   1.1  christos 		dns_db_detach(&st->rpsdb);
   2656   1.1  christos 	}
   2657   1.1  christos }
   2658   1.1  christos 
   2659   1.1  christos static dns_rpz_zbits_t
   2660   1.9  christos rpz_get_zbits(ns_client_t *client, dns_rdatatype_t ip_type,
   2661   1.9  christos 	      dns_rpz_type_t rpz_type) {
   2662   1.1  christos 	dns_rpz_st_t *st;
   2663   1.3  christos 	dns_rpz_zbits_t zbits = 0;
   2664   1.1  christos 
   2665   1.1  christos 	REQUIRE(client != NULL);
   2666   1.1  christos 	REQUIRE(client->query.rpz_st != NULL);
   2667   1.1  christos 
   2668   1.1  christos 	st = client->query.rpz_st;
   2669   1.1  christos 
   2670   1.1  christos #ifdef USE_DNSRPS
   2671   1.1  christos 	if (st->popt.dnsrps_enabled) {
   2672   1.1  christos 		if (st->rpsdb == NULL ||
   2673   1.1  christos 		    librpz->have_trig(dns_dnsrps_type2trig(rpz_type),
   2674   1.1  christos 				      ip_type == dns_rdatatype_aaaa,
   2675   1.1  christos 				      ((rpsdb_t *)st->rpsdb)->rsp))
   2676   1.1  christos 		{
   2677   1.1  christos 			return (DNS_RPZ_ALL_ZBITS);
   2678   1.1  christos 		}
   2679   1.1  christos 		return (0);
   2680   1.1  christos 	}
   2681   1.9  christos #endif /* ifdef USE_DNSRPS */
   2682   1.1  christos 
   2683   1.1  christos 	switch (rpz_type) {
   2684   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   2685   1.1  christos 		zbits = st->have.client_ip;
   2686   1.1  christos 		break;
   2687   1.1  christos 	case DNS_RPZ_TYPE_QNAME:
   2688   1.1  christos 		zbits = st->have.qname;
   2689   1.1  christos 		break;
   2690   1.1  christos 	case DNS_RPZ_TYPE_IP:
   2691   1.1  christos 		if (ip_type == dns_rdatatype_a) {
   2692   1.1  christos 			zbits = st->have.ipv4;
   2693   1.1  christos 		} else if (ip_type == dns_rdatatype_aaaa) {
   2694   1.1  christos 			zbits = st->have.ipv6;
   2695   1.1  christos 		} else {
   2696   1.1  christos 			zbits = st->have.ip;
   2697   1.1  christos 		}
   2698   1.1  christos 		break;
   2699   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   2700   1.1  christos 		zbits = st->have.nsdname;
   2701   1.1  christos 		break;
   2702   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   2703   1.1  christos 		if (ip_type == dns_rdatatype_a) {
   2704   1.1  christos 			zbits = st->have.nsipv4;
   2705   1.1  christos 		} else if (ip_type == dns_rdatatype_aaaa) {
   2706   1.1  christos 			zbits = st->have.nsipv6;
   2707   1.1  christos 		} else {
   2708   1.1  christos 			zbits = st->have.nsip;
   2709   1.1  christos 		}
   2710   1.1  christos 		break;
   2711   1.1  christos 	default:
   2712  1.15  christos 		UNREACHABLE();
   2713   1.1  christos 	}
   2714   1.1  christos 
   2715   1.1  christos 	/*
   2716   1.1  christos 	 * Choose
   2717   1.1  christos 	 *	the earliest configured policy zone (rpz->num)
   2718   1.1  christos 	 *	QNAME over IP over NSDNAME over NSIP (rpz_type)
   2719   1.1  christos 	 *	the smallest name,
   2720   1.1  christos 	 *	the longest IP address prefix,
   2721   1.1  christos 	 *	the lexically smallest address.
   2722   1.1  christos 	 */
   2723   1.1  christos 	if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   2724   1.1  christos 		if (st->m.type >= rpz_type) {
   2725   1.1  christos 			zbits &= DNS_RPZ_ZMASK(st->m.rpz->num);
   2726   1.9  christos 		} else {
   2727   1.1  christos 			zbits &= DNS_RPZ_ZMASK(st->m.rpz->num) >> 1;
   2728   1.1  christos 		}
   2729   1.1  christos 	}
   2730   1.1  christos 
   2731   1.1  christos 	/*
   2732   1.1  christos 	 * If the client wants recursion, allow only compatible policies.
   2733   1.1  christos 	 */
   2734   1.9  christos 	if (!RECURSIONOK(client)) {
   2735   1.1  christos 		zbits &= st->popt.no_rd_ok;
   2736   1.9  christos 	}
   2737   1.1  christos 
   2738   1.1  christos 	return (zbits);
   2739   1.1  christos }
   2740   1.1  christos 
   2741   1.1  christos static void
   2742   1.1  christos query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) {
   2743   1.1  christos 	isc_result_t result;
   2744   1.1  christos 	isc_sockaddr_t *peeraddr;
   2745   1.1  christos 	dns_rdataset_t *tmprdataset;
   2746   1.1  christos 	unsigned int options;
   2747   1.1  christos 
   2748   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_rpzfetch");
   2749   1.9  christos 
   2750   1.9  christos 	if (client->query.prefetch != NULL) {
   2751   1.1  christos 		return;
   2752   1.9  christos 	}
   2753   1.1  christos 
   2754   1.1  christos 	if (client->recursionquota == NULL) {
   2755   1.1  christos 		result = isc_quota_attach(&client->sctx->recursionquota,
   2756   1.1  christos 					  &client->recursionquota);
   2757  1.15  christos 		switch (result) {
   2758  1.15  christos 		case ISC_R_SUCCESS:
   2759  1.16  christos 			ns_stats_increment(client->sctx->nsstats,
   2760  1.16  christos 					   ns_statscounter_recursclients);
   2761  1.15  christos 			break;
   2762  1.15  christos 		case ISC_R_SOFTQUOTA:
   2763   1.9  christos 			isc_quota_detach(&client->recursionquota);
   2764  1.15  christos 			FALLTHROUGH;
   2765  1.15  christos 		default:
   2766   1.1  christos 			return;
   2767   1.6  christos 		}
   2768   1.1  christos 	}
   2769   1.1  christos 
   2770   1.3  christos 	tmprdataset = ns_client_newrdataset(client);
   2771   1.9  christos 	if (tmprdataset == NULL) {
   2772   1.1  christos 		return;
   2773   1.9  christos 	}
   2774   1.9  christos 
   2775   1.9  christos 	if (!TCP(client)) {
   2776   1.1  christos 		peeraddr = &client->peeraddr;
   2777   1.9  christos 	} else {
   2778   1.1  christos 		peeraddr = NULL;
   2779   1.9  christos 	}
   2780   1.9  christos 
   2781   1.1  christos 	options = client->query.fetchoptions;
   2782  1.11  christos 	isc_nmhandle_attach(client->handle, &client->prefetchhandle);
   2783   1.9  christos 	result = dns_resolver_createfetch(
   2784   1.9  christos 		client->view->resolver, qname, type, NULL, NULL, NULL, peeraddr,
   2785   1.9  christos 		client->message->id, options, 0, NULL, client->task,
   2786   1.9  christos 		prefetch_done, client, tmprdataset, NULL,
   2787   1.9  christos 		&client->query.prefetch);
   2788   1.1  christos 	if (result != ISC_R_SUCCESS) {
   2789   1.3  christos 		ns_client_putrdataset(client, &tmprdataset);
   2790  1.11  christos 		isc_nmhandle_detach(&client->prefetchhandle);
   2791   1.1  christos 	}
   2792   1.1  christos }
   2793   1.1  christos 
   2794   1.1  christos /*
   2795   1.1  christos  * Get an NS, A, or AAAA rrset related to the response for the client
   2796   1.1  christos  * to check the contents of that rrset for hits by eligible policy zones.
   2797   1.1  christos  */
   2798   1.1  christos static isc_result_t
   2799   1.1  christos rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type,
   2800  1.15  christos 	       unsigned int options, dns_rpz_type_t rpz_type, dns_db_t **dbp,
   2801   1.1  christos 	       dns_dbversion_t *version, dns_rdataset_t **rdatasetp,
   2802   1.9  christos 	       bool resuming) {
   2803   1.1  christos 	dns_rpz_st_t *st;
   2804   1.3  christos 	bool is_zone;
   2805   1.1  christos 	dns_dbnode_t *node;
   2806   1.1  christos 	dns_fixedname_t fixed;
   2807   1.1  christos 	dns_name_t *found;
   2808   1.1  christos 	isc_result_t result;
   2809   1.1  christos 	dns_clientinfomethods_t cm;
   2810   1.1  christos 	dns_clientinfo_t ci;
   2811   1.1  christos 
   2812   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rrset_find");
   2813   1.1  christos 
   2814   1.1  christos 	st = client->query.rpz_st;
   2815   1.1  christos 	if ((st->state & DNS_RPZ_RECURSING) != 0) {
   2816   1.1  christos 		INSIST(st->r.r_type == type);
   2817   1.1  christos 		INSIST(dns_name_equal(name, st->r_name));
   2818   1.1  christos 		INSIST(*rdatasetp == NULL ||
   2819   1.1  christos 		       !dns_rdataset_isassociated(*rdatasetp));
   2820   1.1  christos 		st->state &= ~DNS_RPZ_RECURSING;
   2821   1.1  christos 		RESTORE(*dbp, st->r.db);
   2822   1.3  christos 		if (*rdatasetp != NULL) {
   2823   1.3  christos 			ns_client_putrdataset(client, rdatasetp);
   2824   1.3  christos 		}
   2825   1.1  christos 		RESTORE(*rdatasetp, st->r.r_rdataset);
   2826   1.1  christos 		result = st->r.r_result;
   2827   1.1  christos 		if (result == DNS_R_DELEGATION) {
   2828   1.1  christos 			CTRACE(ISC_LOG_ERROR, "RPZ recursing");
   2829   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   2830   1.3  christos 				     rpz_type, "rpz_rrset_find(1)", result);
   2831   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   2832   1.1  christos 			result = DNS_R_SERVFAIL;
   2833   1.1  christos 		}
   2834   1.1  christos 		return (result);
   2835   1.1  christos 	}
   2836   1.1  christos 
   2837   1.1  christos 	result = rpz_ready(client, rdatasetp);
   2838   1.1  christos 	if (result != ISC_R_SUCCESS) {
   2839   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   2840   1.1  christos 		return (result);
   2841   1.1  christos 	}
   2842   1.1  christos 	if (*dbp != NULL) {
   2843   1.3  christos 		is_zone = false;
   2844   1.1  christos 	} else {
   2845   1.1  christos 		dns_zone_t *zone;
   2846   1.1  christos 
   2847   1.1  christos 		version = NULL;
   2848   1.1  christos 		zone = NULL;
   2849   1.1  christos 		result = query_getdb(client, name, type, 0, &zone, dbp,
   2850   1.1  christos 				     &version, &is_zone);
   2851   1.1  christos 		if (result != ISC_R_SUCCESS) {
   2852   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   2853   1.3  christos 				     rpz_type, "rpz_rrset_find(2)", result);
   2854   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   2855   1.9  christos 			if (zone != NULL) {
   2856   1.1  christos 				dns_zone_detach(&zone);
   2857   1.9  christos 			}
   2858   1.1  christos 			return (result);
   2859   1.1  christos 		}
   2860   1.9  christos 		if (zone != NULL) {
   2861   1.1  christos 			dns_zone_detach(&zone);
   2862   1.9  christos 		}
   2863   1.1  christos 	}
   2864   1.1  christos 
   2865   1.1  christos 	node = NULL;
   2866   1.1  christos 	found = dns_fixedname_initname(&fixed);
   2867   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   2868  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   2869  1.15  christos 	result = dns_db_findext(*dbp, name, version, type, options, client->now,
   2870  1.15  christos 				&node, found, &cm, &ci, *rdatasetp, NULL);
   2871   1.1  christos 	if (result == DNS_R_DELEGATION && is_zone && USECACHE(client)) {
   2872   1.1  christos 		/*
   2873   1.1  christos 		 * Try the cache if we're authoritative for an
   2874   1.1  christos 		 * ancestor but not the domain itself.
   2875   1.1  christos 		 */
   2876   1.1  christos 		rpz_clean(NULL, dbp, &node, rdatasetp);
   2877   1.1  christos 		version = NULL;
   2878   1.1  christos 		dns_db_attach(client->view->cachedb, dbp);
   2879   1.9  christos 		result = dns_db_findext(*dbp, name, version, type, 0,
   2880   1.9  christos 					client->now, &node, found, &cm, &ci,
   2881   1.9  christos 					*rdatasetp, NULL);
   2882   1.1  christos 	}
   2883   1.1  christos 	rpz_clean(NULL, dbp, &node, NULL);
   2884   1.1  christos 	if (result == DNS_R_DELEGATION) {
   2885   1.1  christos 		rpz_clean(NULL, NULL, NULL, rdatasetp);
   2886   1.1  christos 		/*
   2887   1.1  christos 		 * Recurse for NS rrset or A or AAAA rrset for an NS.
   2888   1.1  christos 		 * Do not recurse for addresses for the query name.
   2889   1.1  christos 		 */
   2890   1.1  christos 		if (rpz_type == DNS_RPZ_TYPE_IP) {
   2891   1.1  christos 			result = DNS_R_NXRRSET;
   2892   1.1  christos 		} else if (!client->view->rpzs->p.nsip_wait_recurse) {
   2893   1.1  christos 			query_rpzfetch(client, name, type);
   2894   1.1  christos 			result = DNS_R_NXRRSET;
   2895   1.1  christos 		} else {
   2896   1.8  christos 			dns_name_copynf(name, st->r_name);
   2897   1.3  christos 			result = ns_query_recurse(client, type, st->r_name,
   2898   1.3  christos 						  NULL, NULL, resuming);
   2899   1.1  christos 			if (result == ISC_R_SUCCESS) {
   2900   1.1  christos 				st->state |= DNS_RPZ_RECURSING;
   2901   1.1  christos 				result = DNS_R_DELEGATION;
   2902   1.1  christos 			}
   2903   1.1  christos 		}
   2904   1.1  christos 	}
   2905   1.1  christos 	return (result);
   2906   1.1  christos }
   2907   1.1  christos 
   2908   1.1  christos /*
   2909   1.1  christos  * Compute a policy owner name, p_name, in a policy zone given the needed
   2910   1.1  christos  * policy type and the trigger name.
   2911   1.1  christos  */
   2912   1.1  christos static isc_result_t
   2913   1.9  christos rpz_get_p_name(ns_client_t *client, dns_name_t *p_name, dns_rpz_zone_t *rpz,
   2914   1.9  christos 	       dns_rpz_type_t rpz_type, dns_name_t *trig_name) {
   2915   1.1  christos 	dns_offsets_t prefix_offsets;
   2916   1.1  christos 	dns_name_t prefix, *suffix;
   2917   1.1  christos 	unsigned int first, labels;
   2918   1.1  christos 	isc_result_t result;
   2919   1.1  christos 
   2920   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_get_p_name");
   2921   1.1  christos 
   2922   1.1  christos 	/*
   2923   1.1  christos 	 * The policy owner name consists of a suffix depending on the type
   2924   1.1  christos 	 * and policy zone and a prefix that is the longest possible string
   2925   1.1  christos 	 * from the trigger name that keesp the resulting policy owner name
   2926   1.1  christos 	 * from being too long.
   2927   1.1  christos 	 */
   2928   1.1  christos 	switch (rpz_type) {
   2929   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   2930   1.1  christos 		suffix = &rpz->client_ip;
   2931   1.1  christos 		break;
   2932   1.1  christos 	case DNS_RPZ_TYPE_QNAME:
   2933   1.1  christos 		suffix = &rpz->origin;
   2934   1.1  christos 		break;
   2935   1.1  christos 	case DNS_RPZ_TYPE_IP:
   2936   1.1  christos 		suffix = &rpz->ip;
   2937   1.1  christos 		break;
   2938   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   2939   1.1  christos 		suffix = &rpz->nsdname;
   2940   1.1  christos 		break;
   2941   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   2942   1.1  christos 		suffix = &rpz->nsip;
   2943   1.1  christos 		break;
   2944   1.1  christos 	default:
   2945  1.15  christos 		UNREACHABLE();
   2946   1.1  christos 	}
   2947   1.1  christos 
   2948   1.1  christos 	/*
   2949   1.1  christos 	 * Start with relative version of the full trigger name,
   2950   1.1  christos 	 * and trim enough allow the addition of the suffix.
   2951   1.1  christos 	 */
   2952   1.1  christos 	dns_name_init(&prefix, prefix_offsets);
   2953   1.1  christos 	labels = dns_name_countlabels(trig_name);
   2954   1.1  christos 	first = 0;
   2955   1.1  christos 	for (;;) {
   2956   1.9  christos 		dns_name_getlabelsequence(trig_name, first, labels - first - 1,
   2957   1.1  christos 					  &prefix);
   2958   1.1  christos 		result = dns_name_concatenate(&prefix, suffix, p_name, NULL);
   2959   1.9  christos 		if (result == ISC_R_SUCCESS) {
   2960   1.1  christos 			break;
   2961   1.9  christos 		}
   2962   1.1  christos 		INSIST(result == DNS_R_NAMETOOLONG);
   2963   1.1  christos 		/*
   2964   1.1  christos 		 * Trim the trigger name until the combination is not too long.
   2965   1.1  christos 		 */
   2966   1.9  christos 		if (labels - first < 2) {
   2967   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, suffix,
   2968   1.9  christos 				     rpz_type, "concatenate()", result);
   2969   1.1  christos 			return (ISC_R_FAILURE);
   2970   1.1  christos 		}
   2971   1.1  christos 		/*
   2972   1.1  christos 		 * Complain once about trimming the trigger name.
   2973   1.1  christos 		 */
   2974   1.1  christos 		if (first == 0) {
   2975   1.1  christos 			rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, suffix,
   2976   1.9  christos 				     rpz_type, "concatenate()", result);
   2977   1.1  christos 		}
   2978   1.1  christos 		++first;
   2979   1.1  christos 	}
   2980   1.1  christos 	return (ISC_R_SUCCESS);
   2981   1.1  christos }
   2982   1.1  christos 
   2983   1.1  christos /*
   2984   1.1  christos  * Look in policy zone rpz for a policy of rpz_type by p_name.
   2985   1.1  christos  * The self-name (usually the client qname or an NS name) is compared with
   2986   1.1  christos  * the target of a CNAME policy for the old style passthru encoding.
   2987   1.1  christos  * If found, the policy is recorded in *zonep, *dbp, *versionp, *nodep,
   2988   1.1  christos  * *rdatasetp, and *policyp.
   2989   1.1  christos  * The target DNS type, qtype, chooses the best rdataset for *rdatasetp.
   2990   1.1  christos  * The caller must decide if the found policy is most suitable, including
   2991   1.1  christos  * better than a previously found policy.
   2992   1.1  christos  * If it is best, the caller records it in client->query.rpz_st->m.
   2993   1.1  christos  */
   2994   1.1  christos static isc_result_t
   2995   1.1  christos rpz_find_p(ns_client_t *client, dns_name_t *self_name, dns_rdatatype_t qtype,
   2996   1.1  christos 	   dns_name_t *p_name, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
   2997   1.1  christos 	   dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp,
   2998   1.1  christos 	   dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp,
   2999   1.9  christos 	   dns_rpz_policy_t *policyp) {
   3000   1.1  christos 	dns_fixedname_t foundf;
   3001   1.1  christos 	dns_name_t *found;
   3002   1.1  christos 	isc_result_t result;
   3003   1.1  christos 	dns_clientinfomethods_t cm;
   3004   1.1  christos 	dns_clientinfo_t ci;
   3005   1.6  christos 	bool found_a = false;
   3006   1.1  christos 
   3007   1.1  christos 	REQUIRE(nodep != NULL);
   3008   1.1  christos 
   3009   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_find_p");
   3010   1.1  christos 
   3011   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   3012  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   3013   1.1  christos 
   3014   1.1  christos 	/*
   3015   1.1  christos 	 * Try to find either a CNAME or the type of record demanded by the
   3016   1.1  christos 	 * request from the policy zone.
   3017   1.1  christos 	 */
   3018   1.1  christos 	rpz_clean(zonep, dbp, nodep, rdatasetp);
   3019   1.1  christos 	result = rpz_ready(client, rdatasetp);
   3020   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3021   1.1  christos 		CTRACE(ISC_LOG_ERROR, "rpz_ready() failed");
   3022   1.1  christos 		return (DNS_R_SERVFAIL);
   3023   1.1  christos 	}
   3024   1.1  christos 	*versionp = NULL;
   3025   1.1  christos 	result = rpz_getdb(client, p_name, rpz_type, zonep, dbp, versionp);
   3026   1.9  christos 	if (result != ISC_R_SUCCESS) {
   3027   1.1  christos 		return (DNS_R_NXDOMAIN);
   3028   1.9  christos 	}
   3029   1.1  christos 	found = dns_fixedname_initname(&foundf);
   3030   1.1  christos 
   3031   1.1  christos 	result = dns_db_findext(*dbp, p_name, *versionp, dns_rdatatype_any, 0,
   3032   1.9  christos 				client->now, nodep, found, &cm, &ci, *rdatasetp,
   3033   1.9  christos 				NULL);
   3034   1.1  christos 	/*
   3035   1.1  christos 	 * Choose the best rdataset if we found something.
   3036   1.1  christos 	 */
   3037   1.1  christos 	if (result == ISC_R_SUCCESS) {
   3038   1.1  christos 		dns_rdatasetiter_t *rdsiter;
   3039   1.1  christos 
   3040   1.1  christos 		rdsiter = NULL;
   3041  1.16  christos 		result = dns_db_allrdatasets(*dbp, *nodep, *versionp, 0, 0,
   3042   1.1  christos 					     &rdsiter);
   3043   1.1  christos 		if (result != ISC_R_SUCCESS) {
   3044   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name,
   3045   1.3  christos 				     rpz_type, "allrdatasets()", result);
   3046   1.1  christos 			CTRACE(ISC_LOG_ERROR,
   3047   1.1  christos 			       "rpz_find_p: allrdatasets failed");
   3048   1.1  christos 			return (DNS_R_SERVFAIL);
   3049   1.1  christos 		}
   3050   1.6  christos 		if (qtype == dns_rdatatype_aaaa &&
   3051  1.16  christos 		    !ISC_LIST_EMPTY(client->view->dns64))
   3052  1.16  christos 		{
   3053   1.6  christos 			for (result = dns_rdatasetiter_first(rdsiter);
   3054   1.6  christos 			     result == ISC_R_SUCCESS;
   3055   1.9  christos 			     result = dns_rdatasetiter_next(rdsiter))
   3056   1.9  christos 			{
   3057   1.6  christos 				dns_rdatasetiter_current(rdsiter, *rdatasetp);
   3058   1.6  christos 				if ((*rdatasetp)->type == dns_rdatatype_a) {
   3059   1.6  christos 					found_a = true;
   3060   1.6  christos 				}
   3061   1.6  christos 				dns_rdataset_disassociate(*rdatasetp);
   3062   1.6  christos 			}
   3063   1.6  christos 		}
   3064   1.1  christos 		for (result = dns_rdatasetiter_first(rdsiter);
   3065   1.1  christos 		     result == ISC_R_SUCCESS;
   3066   1.9  christos 		     result = dns_rdatasetiter_next(rdsiter))
   3067   1.9  christos 		{
   3068   1.1  christos 			dns_rdatasetiter_current(rdsiter, *rdatasetp);
   3069   1.1  christos 			if ((*rdatasetp)->type == dns_rdatatype_cname ||
   3070  1.16  christos 			    (*rdatasetp)->type == qtype)
   3071  1.16  christos 			{
   3072   1.1  christos 				break;
   3073   1.9  christos 			}
   3074   1.1  christos 			dns_rdataset_disassociate(*rdatasetp);
   3075   1.1  christos 		}
   3076   1.1  christos 		dns_rdatasetiter_destroy(&rdsiter);
   3077   1.1  christos 		if (result != ISC_R_SUCCESS) {
   3078   1.1  christos 			if (result != ISC_R_NOMORE) {
   3079   1.1  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL,
   3080   1.9  christos 					     p_name, rpz_type, "rdatasetiter",
   3081   1.9  christos 					     result);
   3082   1.9  christos 				CTRACE(ISC_LOG_ERROR, "rpz_find_p: "
   3083   1.9  christos 						      "rdatasetiter failed");
   3084   1.1  christos 				return (DNS_R_SERVFAIL);
   3085   1.1  christos 			}
   3086   1.1  christos 			/*
   3087   1.1  christos 			 * Ask again to get the right DNS_R_DNAME/NXRRSET/...
   3088   1.1  christos 			 * result if there is neither a CNAME nor target type.
   3089   1.1  christos 			 */
   3090   1.9  christos 			if (dns_rdataset_isassociated(*rdatasetp)) {
   3091   1.1  christos 				dns_rdataset_disassociate(*rdatasetp);
   3092   1.9  christos 			}
   3093   1.1  christos 			dns_db_detachnode(*dbp, nodep);
   3094   1.1  christos 
   3095   1.1  christos 			if (qtype == dns_rdatatype_rrsig ||
   3096  1.16  christos 			    qtype == dns_rdatatype_sig)
   3097  1.16  christos 			{
   3098   1.1  christos 				result = DNS_R_NXRRSET;
   3099   1.9  christos 			} else {
   3100   1.1  christos 				result = dns_db_findext(*dbp, p_name, *versionp,
   3101   1.1  christos 							qtype, 0, client->now,
   3102   1.1  christos 							nodep, found, &cm, &ci,
   3103   1.1  christos 							*rdatasetp, NULL);
   3104   1.9  christos 			}
   3105   1.1  christos 		}
   3106   1.1  christos 	}
   3107   1.1  christos 	switch (result) {
   3108   1.1  christos 	case ISC_R_SUCCESS:
   3109   1.1  christos 		if ((*rdatasetp)->type != dns_rdatatype_cname) {
   3110   1.1  christos 			*policyp = DNS_RPZ_POLICY_RECORD;
   3111   1.1  christos 		} else {
   3112   1.1  christos 			*policyp = dns_rpz_decode_cname(rpz, *rdatasetp,
   3113   1.1  christos 							self_name);
   3114   1.1  christos 			if ((*policyp == DNS_RPZ_POLICY_RECORD ||
   3115   1.1  christos 			     *policyp == DNS_RPZ_POLICY_WILDCNAME) &&
   3116   1.1  christos 			    qtype != dns_rdatatype_cname &&
   3117   1.1  christos 			    qtype != dns_rdatatype_any)
   3118   1.9  christos 			{
   3119   1.1  christos 				return (DNS_R_CNAME);
   3120   1.9  christos 			}
   3121   1.1  christos 		}
   3122   1.1  christos 		return (ISC_R_SUCCESS);
   3123   1.1  christos 	case DNS_R_NXRRSET:
   3124   1.6  christos 		if (found_a) {
   3125   1.6  christos 			*policyp = DNS_RPZ_POLICY_DNS64;
   3126   1.6  christos 		} else {
   3127   1.6  christos 			*policyp = DNS_RPZ_POLICY_NODATA;
   3128   1.6  christos 		}
   3129   1.1  christos 		return (result);
   3130   1.1  christos 	case DNS_R_DNAME:
   3131   1.9  christos 	/*
   3132   1.9  christos 	 * DNAME policy RRs have very few if any uses that are not
   3133   1.9  christos 	 * better served with simple wildcards.  Making them work would
   3134   1.9  christos 	 * require complications to get the number of labels matched
   3135   1.9  christos 	 * in the name or the found name to the main DNS_R_DNAME case
   3136   1.9  christos 	 * in query_dname().  The domain also does not appear in the
   3137   1.9  christos 	 * summary database at the right level, so this happens only
   3138   1.9  christos 	 * with a single policy zone when we have no summary database.
   3139   1.9  christos 	 * Treat it as a miss.
   3140   1.9  christos 	 */
   3141   1.1  christos 	case DNS_R_NXDOMAIN:
   3142   1.1  christos 	case DNS_R_EMPTYNAME:
   3143   1.1  christos 		return (DNS_R_NXDOMAIN);
   3144   1.1  christos 	default:
   3145   1.9  christos 		rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, p_name, rpz_type, "",
   3146   1.9  christos 			     result);
   3147   1.9  christos 		CTRACE(ISC_LOG_ERROR, "rpz_find_p: unexpected result");
   3148   1.1  christos 		return (DNS_R_SERVFAIL);
   3149   1.1  christos 	}
   3150   1.1  christos }
   3151   1.1  christos 
   3152   1.1  christos static void
   3153   1.1  christos rpz_save_p(dns_rpz_st_t *st, dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type,
   3154   1.1  christos 	   dns_rpz_policy_t policy, dns_name_t *p_name, dns_rpz_prefix_t prefix,
   3155   1.1  christos 	   isc_result_t result, dns_zone_t **zonep, dns_db_t **dbp,
   3156   1.1  christos 	   dns_dbnode_t **nodep, dns_rdataset_t **rdatasetp,
   3157   1.9  christos 	   dns_dbversion_t *version) {
   3158   1.1  christos 	dns_rdataset_t *trdataset = NULL;
   3159   1.1  christos 
   3160   1.1  christos 	rpz_match_clear(st);
   3161   1.1  christos 	st->m.rpz = rpz;
   3162   1.1  christos 	st->m.type = rpz_type;
   3163   1.1  christos 	st->m.policy = policy;
   3164   1.8  christos 	dns_name_copynf(p_name, st->p_name);
   3165   1.1  christos 	st->m.prefix = prefix;
   3166   1.1  christos 	st->m.result = result;
   3167   1.1  christos 	SAVE(st->m.zone, *zonep);
   3168   1.1  christos 	SAVE(st->m.db, *dbp);
   3169   1.1  christos 	SAVE(st->m.node, *nodep);
   3170   1.1  christos 	if (*rdatasetp != NULL && dns_rdataset_isassociated(*rdatasetp)) {
   3171   1.1  christos 		/*
   3172   1.1  christos 		 * Save the replacement rdataset from the policy
   3173   1.1  christos 		 * and make the previous replacement rdataset scratch.
   3174   1.1  christos 		 */
   3175   1.1  christos 		SAVE(trdataset, st->m.rdataset);
   3176   1.1  christos 		SAVE(st->m.rdataset, *rdatasetp);
   3177   1.1  christos 		SAVE(*rdatasetp, trdataset);
   3178   1.1  christos 		st->m.ttl = ISC_MIN(st->m.rdataset->ttl, rpz->max_policy_ttl);
   3179   1.1  christos 	} else {
   3180   1.1  christos 		st->m.ttl = ISC_MIN(DNS_RPZ_TTL_DEFAULT, rpz->max_policy_ttl);
   3181   1.1  christos 	}
   3182   1.1  christos 	SAVE(st->m.version, version);
   3183   1.1  christos }
   3184   1.1  christos 
   3185   1.1  christos #ifdef USE_DNSRPS
   3186   1.1  christos /*
   3187   1.1  christos  * Check the results of a RPZ service interface lookup.
   3188   1.1  christos  * Stop after an error (<0) or not a hit on a disabled zone (0).
   3189   1.1  christos  * Continue after a hit on a disabled zone (>0).
   3190   1.1  christos  */
   3191   1.1  christos static int
   3192   1.1  christos dnsrps_ck(librpz_emsg_t *emsg, ns_client_t *client, rpsdb_t *rpsdb,
   3193   1.9  christos 	  bool recursed) {
   3194   1.1  christos 	isc_region_t region;
   3195   1.1  christos 	librpz_domain_buf_t pname_buf;
   3196   1.1  christos 
   3197   1.1  christos 	if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
   3198   1.1  christos 		return (-1);
   3199   1.1  christos 	}
   3200   1.1  christos 
   3201   1.1  christos 	/*
   3202   1.1  christos 	 * Forget the state from before the IP address or domain check
   3203   1.1  christos 	 * if the lookup hit nothing.
   3204   1.1  christos 	 */
   3205   1.1  christos 	if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED ||
   3206   1.1  christos 	    rpsdb->result.hit_id != rpsdb->hit_id ||
   3207   1.1  christos 	    rpsdb->result.policy != LIBRPZ_POLICY_DISABLED)
   3208   1.1  christos 	{
   3209   1.1  christos 		if (!librpz->rsp_pop_discard(emsg, rpsdb->rsp)) {
   3210   1.1  christos 			return (-1);
   3211   1.1  christos 		}
   3212   1.1  christos 		return (0);
   3213   1.1  christos 	}
   3214   1.1  christos 
   3215   1.1  christos 	/*
   3216   1.1  christos 	 * Log a hit on a disabled zone.
   3217   1.1  christos 	 * Forget the zone to not try it again, and restore the pre-hit state.
   3218   1.1  christos 	 */
   3219   1.1  christos 	if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
   3220   1.1  christos 		return (-1);
   3221   1.1  christos 	}
   3222   1.1  christos 	region.base = pname_buf.d;
   3223   1.1  christos 	region.length = pname_buf.size;
   3224   1.1  christos 	dns_name_fromregion(client->query.rpz_st->p_name, &region);
   3225   1.9  christos 	rpz_log_rewrite(client, true, dns_dnsrps_2policy(rpsdb->result.zpolicy),
   3226   1.1  christos 			dns_dnsrps_trig2type(rpsdb->result.trig), NULL,
   3227   1.1  christos 			client->query.rpz_st->p_name, NULL,
   3228   1.1  christos 			rpsdb->result.cznum);
   3229   1.1  christos 
   3230   1.1  christos 	if (!librpz->rsp_forget_zone(emsg, rpsdb->result.cznum, rpsdb->rsp) ||
   3231   1.1  christos 	    !librpz->rsp_pop(emsg, &rpsdb->result, rpsdb->rsp))
   3232   1.1  christos 	{
   3233   1.1  christos 		return (-1);
   3234   1.1  christos 	}
   3235   1.1  christos 	return (1);
   3236   1.1  christos }
   3237   1.1  christos 
   3238   1.1  christos /*
   3239   1.1  christos  * Ready the shim database and rdataset for a DNSRPS hit.
   3240   1.1  christos  */
   3241   1.3  christos static bool
   3242   1.1  christos dnsrps_set_p(librpz_emsg_t *emsg, ns_client_t *client, dns_rpz_st_t *st,
   3243   1.1  christos 	     dns_rdatatype_t qtype, dns_rdataset_t **p_rdatasetp,
   3244   1.9  christos 	     bool recursed) {
   3245   1.1  christos 	rpsdb_t *rpsdb;
   3246   1.1  christos 	librpz_domain_buf_t pname_buf;
   3247   1.1  christos 	isc_region_t region;
   3248   1.1  christos 	dns_zone_t *p_zone;
   3249   1.1  christos 	dns_db_t *p_db;
   3250   1.1  christos 	dns_dbnode_t *p_node;
   3251   1.1  christos 	dns_rpz_policy_t policy;
   3252   1.1  christos 	dns_fixedname_t foundf;
   3253   1.1  christos 	dns_name_t *found;
   3254   1.1  christos 	dns_rdatatype_t foundtype, searchtype;
   3255   1.1  christos 	isc_result_t result;
   3256   1.1  christos 
   3257   1.1  christos 	rpsdb = (rpsdb_t *)st->rpsdb;
   3258   1.1  christos 
   3259   1.1  christos 	if (!librpz->rsp_result(emsg, &rpsdb->result, recursed, rpsdb->rsp)) {
   3260   1.3  christos 		return (false);
   3261   1.1  christos 	}
   3262   1.1  christos 
   3263   1.1  christos 	if (rpsdb->result.policy == LIBRPZ_POLICY_UNDEFINED) {
   3264   1.3  christos 		return (true);
   3265   1.1  christos 	}
   3266   1.1  christos 
   3267   1.1  christos 	/*
   3268   1.1  christos 	 * Give the fake or shim DNSRPS database its new origin.
   3269   1.1  christos 	 */
   3270   1.1  christos 	if (!librpz->rsp_soa(emsg, NULL, NULL, &rpsdb->origin_buf,
   3271   1.1  christos 			     &rpsdb->result, rpsdb->rsp))
   3272   1.1  christos 	{
   3273   1.3  christos 		return (false);
   3274   1.1  christos 	}
   3275   1.1  christos 	region.base = rpsdb->origin_buf.d;
   3276   1.1  christos 	region.length = rpsdb->origin_buf.size;
   3277   1.1  christos 	dns_name_fromregion(&rpsdb->common.origin, &region);
   3278   1.1  christos 
   3279   1.1  christos 	if (!librpz->rsp_domain(emsg, &pname_buf, rpsdb->rsp)) {
   3280   1.3  christos 		return (false);
   3281   1.1  christos 	}
   3282   1.1  christos 	region.base = pname_buf.d;
   3283   1.1  christos 	region.length = pname_buf.size;
   3284   1.1  christos 	dns_name_fromregion(st->p_name, &region);
   3285   1.1  christos 
   3286   1.1  christos 	p_zone = NULL;
   3287   1.1  christos 	p_db = NULL;
   3288   1.1  christos 	p_node = NULL;
   3289   1.1  christos 	rpz_ready(client, p_rdatasetp);
   3290   1.1  christos 	dns_db_attach(st->rpsdb, &p_db);
   3291   1.1  christos 	policy = dns_dnsrps_2policy(rpsdb->result.policy);
   3292   1.1  christos 	if (policy != DNS_RPZ_POLICY_RECORD) {
   3293   1.1  christos 		result = ISC_R_SUCCESS;
   3294   1.1  christos 	} else if (qtype == dns_rdatatype_rrsig) {
   3295   1.1  christos 		/*
   3296   1.1  christos 		 * dns_find_db() refuses to look for and fail to
   3297   1.1  christos 		 * find dns_rdatatype_rrsig.
   3298   1.1  christos 		 */
   3299   1.1  christos 		result = DNS_R_NXRRSET;
   3300   1.1  christos 		policy = DNS_RPZ_POLICY_NODATA;
   3301   1.1  christos 	} else {
   3302   1.1  christos 		/*
   3303   1.1  christos 		 * Get the next (and so first) RR from the policy node.
   3304   1.1  christos 		 * If it is a CNAME, then look for it regardless of the
   3305   1.1  christos 		 * query type.
   3306   1.1  christos 		 */
   3307   1.1  christos 		if (!librpz->rsp_rr(emsg, &foundtype, NULL, NULL, NULL,
   3308   1.1  christos 				    &rpsdb->result, rpsdb->qname->ndata,
   3309   1.1  christos 				    rpsdb->qname->length, rpsdb->rsp))
   3310   1.1  christos 		{
   3311   1.3  christos 			return (false);
   3312   1.1  christos 		}
   3313   1.1  christos 		if (foundtype == dns_rdatatype_cname) {
   3314   1.1  christos 			searchtype = dns_rdatatype_cname;
   3315   1.1  christos 		} else {
   3316   1.1  christos 			searchtype = qtype;
   3317   1.1  christos 		}
   3318   1.1  christos 		/*
   3319   1.1  christos 		 * Get the DNSPRS imitation rdataset.
   3320   1.1  christos 		 */
   3321   1.1  christos 		found = dns_fixedname_initname(&foundf);
   3322   1.9  christos 		result = dns_db_find(p_db, st->p_name, NULL, searchtype, 0, 0,
   3323   1.9  christos 				     &p_node, found, *p_rdatasetp, NULL);
   3324   1.1  christos 
   3325   1.1  christos 		if (result == ISC_R_SUCCESS) {
   3326   1.1  christos 			if (searchtype == dns_rdatatype_cname &&
   3327  1.16  christos 			    qtype != dns_rdatatype_cname)
   3328  1.16  christos 			{
   3329   1.1  christos 				result = DNS_R_CNAME;
   3330   1.1  christos 			}
   3331   1.1  christos 		} else if (result == DNS_R_NXRRSET) {
   3332   1.1  christos 			policy = DNS_RPZ_POLICY_NODATA;
   3333   1.1  christos 		} else {
   3334   1.1  christos 			snprintf(emsg->c, sizeof(emsg->c), "dns_db_find(): %s",
   3335   1.1  christos 				 isc_result_totext(result));
   3336   1.3  christos 			return (false);
   3337   1.1  christos 		}
   3338   1.1  christos 	}
   3339   1.1  christos 
   3340   1.1  christos 	rpz_save_p(st, client->view->rpzs->zones[rpsdb->result.cznum],
   3341   1.9  christos 		   dns_dnsrps_trig2type(rpsdb->result.trig), policy, st->p_name,
   3342   1.9  christos 		   0, result, &p_zone, &p_db, &p_node, p_rdatasetp, NULL);
   3343   1.1  christos 
   3344   1.1  christos 	rpz_clean(NULL, NULL, NULL, p_rdatasetp);
   3345   1.1  christos 
   3346   1.3  christos 	return (true);
   3347   1.1  christos }
   3348   1.1  christos 
   3349   1.1  christos static isc_result_t
   3350   1.1  christos dnsrps_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
   3351   1.9  christos 		  dns_rpz_type_t rpz_type, dns_rdataset_t **p_rdatasetp) {
   3352   1.1  christos 	dns_rpz_st_t *st;
   3353   1.1  christos 	rpsdb_t *rpsdb;
   3354   1.1  christos 	librpz_trig_t trig = LIBRPZ_TRIG_CLIENT_IP;
   3355   1.3  christos 	bool recursed = false;
   3356   1.1  christos 	int res;
   3357   1.1  christos 	librpz_emsg_t emsg;
   3358   1.1  christos 	isc_result_t result;
   3359   1.1  christos 
   3360   1.1  christos 	st = client->query.rpz_st;
   3361   1.1  christos 	rpsdb = (rpsdb_t *)st->rpsdb;
   3362   1.1  christos 
   3363   1.1  christos 	result = rpz_ready(client, p_rdatasetp);
   3364   1.1  christos 	if (result != ISC_R_SUCCESS) {
   3365   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   3366   1.1  christos 		return (result);
   3367   1.1  christos 	}
   3368   1.1  christos 
   3369   1.1  christos 	switch (rpz_type) {
   3370   1.1  christos 	case DNS_RPZ_TYPE_CLIENT_IP:
   3371   1.1  christos 		trig = LIBRPZ_TRIG_CLIENT_IP;
   3372   1.3  christos 		recursed = false;
   3373   1.1  christos 		break;
   3374   1.1  christos 	case DNS_RPZ_TYPE_IP:
   3375   1.1  christos 		trig = LIBRPZ_TRIG_IP;
   3376   1.3  christos 		recursed = true;
   3377   1.1  christos 		break;
   3378   1.1  christos 	case DNS_RPZ_TYPE_NSIP:
   3379   1.1  christos 		trig = LIBRPZ_TRIG_NSIP;
   3380   1.3  christos 		recursed = true;
   3381   1.1  christos 		break;
   3382   1.1  christos 	default:
   3383  1.15  christos 		UNREACHABLE();
   3384   1.1  christos 	}
   3385   1.1  christos 
   3386   1.1  christos 	do {
   3387   1.1  christos 		if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
   3388   1.1  christos 		    !librpz->ck_ip(&emsg,
   3389   1.1  christos 				   netaddr->family == AF_INET
   3390   1.9  christos 					   ? (const void *)&netaddr->type.in
   3391   1.9  christos 					   : (const void *)&netaddr->type.in6,
   3392   1.1  christos 				   netaddr->family, trig, ++rpsdb->hit_id,
   3393   1.1  christos 				   recursed, rpsdb->rsp) ||
   3394   1.1  christos 		    (res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
   3395   1.1  christos 		{
   3396   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   3397   1.1  christos 				     rpz_type, emsg.c, DNS_R_SERVFAIL);
   3398   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3399   1.1  christos 			return (DNS_R_SERVFAIL);
   3400   1.1  christos 		}
   3401   1.1  christos 	} while (res != 0);
   3402   1.1  christos 	return (ISC_R_SUCCESS);
   3403   1.1  christos }
   3404   1.1  christos 
   3405   1.1  christos static isc_result_t
   3406   1.9  christos dnsrps_rewrite_name(ns_client_t *client, dns_name_t *trig_name, bool recursed,
   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.1  christos 	isc_region_t r;
   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_QNAME:
   3427   1.1  christos 		trig = LIBRPZ_TRIG_QNAME;
   3428   1.1  christos 		break;
   3429   1.1  christos 	case DNS_RPZ_TYPE_NSDNAME:
   3430   1.1  christos 		trig = LIBRPZ_TRIG_NSDNAME;
   3431   1.1  christos 		break;
   3432   1.1  christos 	default:
   3433  1.15  christos 		UNREACHABLE();
   3434   1.1  christos 	}
   3435   1.1  christos 
   3436   1.1  christos 	dns_name_toregion(trig_name, &r);
   3437   1.1  christos 	do {
   3438   1.1  christos 		if (!librpz->rsp_push(&emsg, rpsdb->rsp) ||
   3439   1.9  christos 		    !librpz->ck_domain(&emsg, r.base, r.length, trig,
   3440   1.9  christos 				       ++rpsdb->hit_id, recursed, rpsdb->rsp) ||
   3441   1.1  christos 		    (res = dnsrps_ck(&emsg, client, rpsdb, recursed)) < 0)
   3442   1.1  christos 		{
   3443   1.1  christos 			rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   3444   1.1  christos 				     rpz_type, emsg.c, DNS_R_SERVFAIL);
   3445   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3446   1.1  christos 			return (DNS_R_SERVFAIL);
   3447   1.1  christos 		}
   3448   1.1  christos 	} while (res != 0);
   3449   1.1  christos 	return (ISC_R_SUCCESS);
   3450   1.1  christos }
   3451   1.1  christos #endif /* USE_DNSRPS */
   3452   1.1  christos 
   3453   1.1  christos /*
   3454   1.1  christos  * Check this address in every eligible policy zone.
   3455   1.1  christos  */
   3456   1.1  christos static isc_result_t
   3457   1.1  christos rpz_rewrite_ip(ns_client_t *client, const isc_netaddr_t *netaddr,
   3458   1.1  christos 	       dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3459   1.9  christos 	       dns_rpz_zbits_t zbits, dns_rdataset_t **p_rdatasetp) {
   3460   1.1  christos 	dns_rpz_zones_t *rpzs;
   3461   1.1  christos 	dns_rpz_st_t *st;
   3462   1.1  christos 	dns_rpz_zone_t *rpz;
   3463   1.1  christos 	dns_rpz_prefix_t prefix;
   3464   1.1  christos 	dns_rpz_num_t rpz_num;
   3465   1.1  christos 	dns_fixedname_t ip_namef, p_namef;
   3466   1.1  christos 	dns_name_t *ip_name, *p_name;
   3467   1.1  christos 	dns_zone_t *p_zone;
   3468   1.1  christos 	dns_db_t *p_db;
   3469   1.1  christos 	dns_dbversion_t *p_version;
   3470   1.1  christos 	dns_dbnode_t *p_node;
   3471   1.1  christos 	dns_rpz_policy_t policy;
   3472   1.1  christos 	isc_result_t result;
   3473   1.1  christos 
   3474   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip");
   3475   1.1  christos 
   3476   1.1  christos 	rpzs = client->view->rpzs;
   3477   1.1  christos 	st = client->query.rpz_st;
   3478   1.1  christos #ifdef USE_DNSRPS
   3479   1.1  christos 	if (st->popt.dnsrps_enabled) {
   3480   1.1  christos 		return (dnsrps_rewrite_ip(client, netaddr, rpz_type,
   3481   1.9  christos 					  p_rdatasetp));
   3482   1.1  christos 	}
   3483   1.9  christos #endif /* ifdef USE_DNSRPS */
   3484   1.1  christos 
   3485   1.1  christos 	ip_name = dns_fixedname_initname(&ip_namef);
   3486   1.1  christos 
   3487   1.1  christos 	p_zone = NULL;
   3488   1.1  christos 	p_db = NULL;
   3489   1.1  christos 	p_node = NULL;
   3490   1.1  christos 
   3491   1.1  christos 	while (zbits != 0) {
   3492   1.1  christos 		rpz_num = dns_rpz_find_ip(rpzs, rpz_type, zbits, netaddr,
   3493   1.1  christos 					  ip_name, &prefix);
   3494   1.9  christos 		if (rpz_num == DNS_RPZ_INVALID_NUM) {
   3495   1.1  christos 			break;
   3496   1.9  christos 		}
   3497   1.1  christos 		zbits &= (DNS_RPZ_ZMASK(rpz_num) >> 1);
   3498   1.1  christos 
   3499   1.1  christos 		/*
   3500   1.1  christos 		 * Do not try applying policy zones that cannot replace a
   3501   1.1  christos 		 * previously found policy zone.
   3502   1.1  christos 		 * Stop looking if the next best choice cannot
   3503   1.1  christos 		 * replace what we already have.
   3504   1.1  christos 		 */
   3505   1.1  christos 		rpz = rpzs->zones[rpz_num];
   3506   1.1  christos 		if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   3507   1.9  christos 			if (st->m.rpz->num < rpz->num) {
   3508   1.1  christos 				break;
   3509   1.9  christos 			}
   3510   1.1  christos 			if (st->m.rpz->num == rpz->num &&
   3511   1.9  christos 			    (st->m.type < rpz_type || st->m.prefix > prefix))
   3512   1.9  christos 			{
   3513   1.1  christos 				break;
   3514   1.9  christos 			}
   3515   1.1  christos 		}
   3516   1.1  christos 
   3517   1.1  christos 		/*
   3518   1.1  christos 		 * Get the policy for a prefix at least as long
   3519   1.1  christos 		 * as the prefix of the entry we had before.
   3520   1.1  christos 		 */
   3521   1.1  christos 		p_name = dns_fixedname_initname(&p_namef);
   3522   1.1  christos 		result = rpz_get_p_name(client, p_name, rpz, rpz_type, ip_name);
   3523   1.9  christos 		if (result != ISC_R_SUCCESS) {
   3524   1.1  christos 			continue;
   3525   1.9  christos 		}
   3526   1.9  christos 		result = rpz_find_p(client, ip_name, qtype, p_name, rpz,
   3527   1.9  christos 				    rpz_type, &p_zone, &p_db, &p_version,
   3528   1.9  christos 				    &p_node, p_rdatasetp, &policy);
   3529   1.1  christos 		switch (result) {
   3530   1.1  christos 		case DNS_R_NXDOMAIN:
   3531   1.1  christos 			/*
   3532   1.1  christos 			 * Continue after a policy record that is missing
   3533   1.1  christos 			 * contrary to the summary data.  The summary
   3534   1.1  christos 			 * data can out of date during races with and among
   3535   1.1  christos 			 * policy zone updates.
   3536   1.1  christos 			 */
   3537   1.9  christos 			CTRACE(ISC_LOG_ERROR, "rpz_rewrite_ip: mismatched "
   3538   1.9  christos 					      "summary data; "
   3539   1.9  christos 					      "continuing");
   3540   1.1  christos 			continue;
   3541   1.1  christos 		case DNS_R_SERVFAIL:
   3542   1.1  christos 			rpz_clean(&p_zone, &p_db, &p_node, p_rdatasetp);
   3543   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3544   1.1  christos 			return (DNS_R_SERVFAIL);
   3545   1.1  christos 		default:
   3546   1.1  christos 			/*
   3547   1.1  christos 			 * Forget this policy if it is not preferable
   3548   1.1  christos 			 * to the previously found policy.
   3549   1.1  christos 			 * If this policy is not good, then stop looking
   3550   1.1  christos 			 * because none of the later policy zones would work.
   3551   1.1  christos 			 *
   3552   1.1  christos 			 * With more than one applicable policy, prefer
   3553   1.1  christos 			 * the earliest configured policy,
   3554   1.1  christos 			 * client-IP over QNAME over IP over NSDNAME over NSIP,
   3555   1.1  christos 			 * the longest prefix
   3556   1.1  christos 			 * the lexically smallest address.
   3557   1.1  christos 			 * dns_rpz_find_ip() ensures st->m.rpz->num >= rpz->num.
   3558   1.1  christos 			 * We can compare new and current p_name because
   3559   1.1  christos 			 * both are of the same type and in the same zone.
   3560   1.1  christos 			 * The tests above eliminate other reasons to
   3561   1.1  christos 			 * reject this policy.  If this policy can't work,
   3562   1.1  christos 			 * then neither can later zones.
   3563   1.1  christos 			 */
   3564   1.1  christos 			if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   3565   1.1  christos 			    rpz->num == st->m.rpz->num &&
   3566   1.9  christos 			    (st->m.type == rpz_type && st->m.prefix == prefix &&
   3567   1.9  christos 			     0 > dns_name_rdatacompare(st->p_name, p_name)))
   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 			 * Stop checking after saving an enabled hit in this
   3574   1.1  christos 			 * policy zone.  The radix tree in the policy zone
   3575   1.1  christos 			 * ensures that we found the longest match.
   3576   1.1  christos 			 */
   3577   1.1  christos 			if (rpz->policy != DNS_RPZ_POLICY_DISABLED) {
   3578   1.9  christos 				CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip: "
   3579   1.9  christos 							 "rpz_save_p");
   3580   1.9  christos 				rpz_save_p(st, rpz, rpz_type, policy, p_name,
   3581   1.9  christos 					   prefix, result, &p_zone, &p_db,
   3582   1.9  christos 					   &p_node, p_rdatasetp, p_version);
   3583   1.1  christos 				break;
   3584   1.1  christos 			}
   3585   1.1  christos 
   3586   1.1  christos 			/*
   3587   1.1  christos 			 * Log DNS_RPZ_POLICY_DISABLED zones
   3588   1.1  christos 			 * and try the next eligible policy zone.
   3589   1.1  christos 			 */
   3590   1.9  christos 			rpz_log_rewrite(client, true, policy, rpz_type, p_zone,
   3591   1.9  christos 					p_name, NULL, rpz_num);
   3592   1.1  christos 		}
   3593   1.1  christos 	}
   3594   1.1  christos 
   3595   1.1  christos 	rpz_clean(&p_zone, &p_db, &p_node, p_rdatasetp);
   3596   1.1  christos 	return (ISC_R_SUCCESS);
   3597   1.1  christos }
   3598   1.1  christos 
   3599   1.1  christos /*
   3600   1.1  christos  * Check the IP addresses in the A or AAAA rrsets for name against
   3601   1.1  christos  * all eligible rpz_type (IP or NSIP) response policy rewrite rules.
   3602   1.1  christos  */
   3603   1.1  christos static isc_result_t
   3604   1.9  christos rpz_rewrite_ip_rrset(ns_client_t *client, dns_name_t *name,
   3605   1.9  christos 		     dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3606   1.9  christos 		     dns_rdatatype_t ip_type, dns_db_t **ip_dbp,
   3607   1.9  christos 		     dns_dbversion_t *ip_version, dns_rdataset_t **ip_rdatasetp,
   3608   1.9  christos 		     dns_rdataset_t **p_rdatasetp, bool resuming) {
   3609   1.1  christos 	dns_rpz_zbits_t zbits;
   3610   1.1  christos 	isc_netaddr_t netaddr;
   3611   1.1  christos 	struct in_addr ina;
   3612   1.1  christos 	struct in6_addr in6a;
   3613   1.1  christos 	isc_result_t result;
   3614  1.16  christos 	unsigned int options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   3615  1.15  christos 	bool done = false;
   3616   1.1  christos 
   3617   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip_rrset");
   3618   1.1  christos 
   3619  1.15  christos 	do {
   3620  1.15  christos 		zbits = rpz_get_zbits(client, ip_type, rpz_type);
   3621  1.15  christos 		if (zbits == 0) {
   3622  1.15  christos 			return (ISC_R_SUCCESS);
   3623  1.15  christos 		}
   3624   1.1  christos 
   3625  1.15  christos 		/*
   3626  1.15  christos 		 * Get the A or AAAA rdataset.
   3627  1.15  christos 		 */
   3628  1.15  christos 		result = rpz_rrset_find(client, name, ip_type, options,
   3629  1.15  christos 					rpz_type, ip_dbp, ip_version,
   3630  1.15  christos 					ip_rdatasetp, resuming);
   3631  1.15  christos 		switch (result) {
   3632  1.15  christos 		case ISC_R_SUCCESS:
   3633  1.15  christos 		case DNS_R_GLUE:
   3634  1.15  christos 		case DNS_R_ZONECUT:
   3635  1.15  christos 			break;
   3636  1.15  christos 		case DNS_R_EMPTYNAME:
   3637  1.15  christos 		case DNS_R_EMPTYWILD:
   3638  1.15  christos 		case DNS_R_NXDOMAIN:
   3639  1.15  christos 		case DNS_R_NCACHENXDOMAIN:
   3640  1.15  christos 		case DNS_R_NXRRSET:
   3641  1.15  christos 		case DNS_R_NCACHENXRRSET:
   3642  1.15  christos 		case ISC_R_NOTFOUND:
   3643  1.15  christos 			return (ISC_R_SUCCESS);
   3644  1.15  christos 		case DNS_R_DELEGATION:
   3645  1.15  christos 		case DNS_R_DUPLICATE:
   3646  1.15  christos 		case DNS_R_DROP:
   3647  1.15  christos 			return (result);
   3648  1.15  christos 		case DNS_R_CNAME:
   3649  1.15  christos 		case DNS_R_DNAME:
   3650  1.15  christos 			rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, name,
   3651   1.3  christos 				     rpz_type, "NS address rewrite rrset",
   3652   1.1  christos 				     result);
   3653  1.15  christos 			return (ISC_R_SUCCESS);
   3654  1.15  christos 		default:
   3655  1.15  christos 			if (client->query.rpz_st->m.policy !=
   3656  1.16  christos 			    DNS_RPZ_POLICY_ERROR)
   3657  1.16  christos 			{
   3658  1.15  christos 				client->query.rpz_st->m.policy =
   3659  1.15  christos 					DNS_RPZ_POLICY_ERROR;
   3660  1.15  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, name,
   3661  1.15  christos 					     rpz_type,
   3662  1.15  christos 					     "NS address rewrite rrset",
   3663  1.15  christos 					     result);
   3664  1.15  christos 			}
   3665  1.15  christos 			CTRACE(ISC_LOG_ERROR,
   3666  1.15  christos 			       "rpz_rewrite_ip_rrset: unexpected "
   3667  1.15  christos 			       "result");
   3668  1.15  christos 			return (DNS_R_SERVFAIL);
   3669   1.1  christos 		}
   3670   1.1  christos 
   3671  1.15  christos 		/*
   3672  1.15  christos 		 * If we are processing glue setup for the next loop
   3673  1.15  christos 		 * otherwise we are done.
   3674  1.15  christos 		 */
   3675  1.15  christos 		if (result == DNS_R_GLUE) {
   3676  1.16  christos 			options = client->query.dboptions;
   3677  1.15  christos 		} else {
   3678  1.16  christos 			options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   3679  1.15  christos 			done = true;
   3680   1.1  christos 		}
   3681   1.1  christos 
   3682  1.15  christos 		/*
   3683  1.15  christos 		 * Check all of the IP addresses in the rdataset.
   3684  1.15  christos 		 */
   3685  1.15  christos 		for (result = dns_rdataset_first(*ip_rdatasetp);
   3686  1.15  christos 		     result == ISC_R_SUCCESS;
   3687  1.15  christos 		     result = dns_rdataset_next(*ip_rdatasetp))
   3688  1.15  christos 		{
   3689  1.15  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   3690  1.15  christos 			dns_rdataset_current(*ip_rdatasetp, &rdata);
   3691  1.15  christos 			switch (rdata.type) {
   3692  1.15  christos 			case dns_rdatatype_a:
   3693  1.15  christos 				INSIST(rdata.length == 4);
   3694  1.15  christos 				memmove(&ina.s_addr, rdata.data, 4);
   3695  1.15  christos 				isc_netaddr_fromin(&netaddr, &ina);
   3696  1.15  christos 				break;
   3697  1.15  christos 			case dns_rdatatype_aaaa:
   3698  1.15  christos 				INSIST(rdata.length == 16);
   3699  1.15  christos 				memmove(in6a.s6_addr, rdata.data, 16);
   3700  1.15  christos 				isc_netaddr_fromin6(&netaddr, &in6a);
   3701  1.15  christos 				break;
   3702  1.15  christos 			default:
   3703  1.15  christos 				continue;
   3704  1.15  christos 			}
   3705  1.15  christos 
   3706  1.15  christos 			result = rpz_rewrite_ip(client, &netaddr, qtype,
   3707  1.15  christos 						rpz_type, zbits, p_rdatasetp);
   3708  1.15  christos 			if (result != ISC_R_SUCCESS) {
   3709  1.15  christos 				return (result);
   3710  1.15  christos 			}
   3711   1.9  christos 		}
   3712  1.15  christos 	} while (!done &&
   3713  1.15  christos 		 client->query.rpz_st->m.policy == DNS_RPZ_POLICY_MISS);
   3714   1.1  christos 
   3715   1.1  christos 	return (ISC_R_SUCCESS);
   3716   1.1  christos }
   3717   1.1  christos 
   3718   1.1  christos /*
   3719   1.1  christos  * Look for IP addresses in A and AAAA rdatasets
   3720   1.1  christos  * that trigger all eligible IP or NSIP policy rules.
   3721   1.1  christos  */
   3722   1.1  christos static isc_result_t
   3723   1.1  christos rpz_rewrite_ip_rrsets(ns_client_t *client, dns_name_t *name,
   3724   1.1  christos 		      dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3725   1.9  christos 		      dns_rdataset_t **ip_rdatasetp, bool resuming) {
   3726   1.1  christos 	dns_rpz_st_t *st;
   3727   1.1  christos 	dns_dbversion_t *ip_version;
   3728   1.1  christos 	dns_db_t *ip_db;
   3729   1.1  christos 	dns_rdataset_t *p_rdataset;
   3730   1.1  christos 	isc_result_t result;
   3731   1.1  christos 
   3732   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ip_rrsets");
   3733   1.1  christos 
   3734   1.1  christos 	st = client->query.rpz_st;
   3735   1.1  christos 	ip_version = NULL;
   3736   1.1  christos 	ip_db = NULL;
   3737   1.1  christos 	p_rdataset = NULL;
   3738   1.1  christos 	if ((st->state & DNS_RPZ_DONE_IPv4) == 0 &&
   3739   1.9  christos 	    (qtype == dns_rdatatype_a || qtype == dns_rdatatype_any ||
   3740   1.9  christos 	     rpz_type == DNS_RPZ_TYPE_NSIP))
   3741   1.9  christos 	{
   3742   1.1  christos 		/*
   3743   1.1  christos 		 * Rewrite based on an IPv4 address that will appear
   3744   1.1  christos 		 * in the ANSWER section or if we are checking IP addresses.
   3745   1.1  christos 		 */
   3746   1.9  christos 		result = rpz_rewrite_ip_rrset(
   3747   1.9  christos 			client, name, qtype, rpz_type, dns_rdatatype_a, &ip_db,
   3748   1.9  christos 			ip_version, ip_rdatasetp, &p_rdataset, resuming);
   3749   1.9  christos 		if (result == ISC_R_SUCCESS) {
   3750   1.1  christos 			st->state |= DNS_RPZ_DONE_IPv4;
   3751   1.9  christos 		}
   3752   1.1  christos 	} else {
   3753   1.1  christos 		result = ISC_R_SUCCESS;
   3754   1.1  christos 	}
   3755   1.1  christos 	if (result == ISC_R_SUCCESS &&
   3756   1.9  christos 	    (qtype == dns_rdatatype_aaaa || qtype == dns_rdatatype_any ||
   3757   1.9  christos 	     rpz_type == DNS_RPZ_TYPE_NSIP))
   3758   1.9  christos 	{
   3759   1.1  christos 		/*
   3760   1.1  christos 		 * Rewrite based on IPv6 addresses that will appear
   3761   1.1  christos 		 * in the ANSWER section or if we are checking IP addresses.
   3762   1.1  christos 		 */
   3763   1.9  christos 		result = rpz_rewrite_ip_rrset(client, name, qtype, rpz_type,
   3764   1.9  christos 					      dns_rdatatype_aaaa, &ip_db,
   3765   1.9  christos 					      ip_version, ip_rdatasetp,
   3766   1.1  christos 					      &p_rdataset, resuming);
   3767   1.1  christos 	}
   3768   1.9  christos 	if (ip_db != NULL) {
   3769   1.1  christos 		dns_db_detach(&ip_db);
   3770   1.9  christos 	}
   3771   1.3  christos 	ns_client_putrdataset(client, &p_rdataset);
   3772   1.1  christos 	return (result);
   3773   1.1  christos }
   3774   1.1  christos 
   3775   1.1  christos /*
   3776   1.1  christos  * Try to rewrite a request for a qtype rdataset based on the trigger name
   3777   1.1  christos  * trig_name and rpz_type (DNS_RPZ_TYPE_QNAME or DNS_RPZ_TYPE_NSDNAME).
   3778   1.1  christos  * Record the results including the replacement rdataset if any
   3779   1.1  christos  * in client->query.rpz_st.
   3780   1.1  christos  * *rdatasetp is a scratch rdataset.
   3781   1.1  christos  */
   3782   1.1  christos static isc_result_t
   3783   1.1  christos rpz_rewrite_name(ns_client_t *client, dns_name_t *trig_name,
   3784   1.1  christos 		 dns_rdatatype_t qtype, dns_rpz_type_t rpz_type,
   3785   1.3  christos 		 dns_rpz_zbits_t allowed_zbits, bool recursed,
   3786   1.9  christos 		 dns_rdataset_t **rdatasetp) {
   3787   1.1  christos 	dns_rpz_zones_t *rpzs;
   3788   1.1  christos 	dns_rpz_zone_t *rpz;
   3789   1.1  christos 	dns_rpz_st_t *st;
   3790   1.1  christos 	dns_fixedname_t p_namef;
   3791   1.1  christos 	dns_name_t *p_name;
   3792   1.1  christos 	dns_rpz_zbits_t zbits;
   3793   1.1  christos 	dns_rpz_num_t rpz_num;
   3794   1.1  christos 	dns_zone_t *p_zone;
   3795   1.1  christos 	dns_db_t *p_db;
   3796   1.1  christos 	dns_dbversion_t *p_version;
   3797   1.1  christos 	dns_dbnode_t *p_node;
   3798   1.1  christos 	dns_rpz_policy_t policy;
   3799   1.1  christos 	isc_result_t result;
   3800   1.1  christos 
   3801   1.1  christos #ifndef USE_DNSRPS
   3802   1.1  christos 	UNUSED(recursed);
   3803   1.9  christos #endif /* ifndef USE_DNSRPS */
   3804   1.1  christos 
   3805   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name");
   3806   1.1  christos 
   3807   1.1  christos 	rpzs = client->view->rpzs;
   3808   1.1  christos 	st = client->query.rpz_st;
   3809   1.1  christos 
   3810   1.1  christos #ifdef USE_DNSRPS
   3811   1.1  christos 	if (st->popt.dnsrps_enabled) {
   3812   1.1  christos 		return (dnsrps_rewrite_name(client, trig_name, recursed,
   3813   1.9  christos 					    rpz_type, rdatasetp));
   3814   1.1  christos 	}
   3815   1.9  christos #endif /* ifdef USE_DNSRPS */
   3816   1.1  christos 
   3817   1.1  christos 	zbits = rpz_get_zbits(client, qtype, rpz_type);
   3818   1.1  christos 	zbits &= allowed_zbits;
   3819   1.9  christos 	if (zbits == 0) {
   3820   1.1  christos 		return (ISC_R_SUCCESS);
   3821   1.9  christos 	}
   3822   1.1  christos 
   3823   1.1  christos 	/*
   3824   1.1  christos 	 * Use the summary database to find the bit mask of policy zones
   3825   1.1  christos 	 * with policies for this trigger name. We do this even if there
   3826   1.1  christos 	 * is only one eligible policy zone so that wildcard triggers
   3827   1.1  christos 	 * are matched correctly, and not into their parent.
   3828   1.1  christos 	 */
   3829   1.1  christos 	zbits = dns_rpz_find_name(rpzs, rpz_type, zbits, trig_name);
   3830   1.9  christos 	if (zbits == 0) {
   3831   1.1  christos 		return (ISC_R_SUCCESS);
   3832   1.9  christos 	}
   3833   1.1  christos 
   3834   1.1  christos 	p_name = dns_fixedname_initname(&p_namef);
   3835   1.1  christos 
   3836   1.1  christos 	p_zone = NULL;
   3837   1.1  christos 	p_db = NULL;
   3838   1.1  christos 	p_node = NULL;
   3839   1.1  christos 
   3840   1.1  christos 	/*
   3841   1.1  christos 	 * Check the trigger name in every policy zone that the summary data
   3842   1.1  christos 	 * says has a hit for the trigger name.
   3843   1.1  christos 	 * Most of the time there are no eligible zones and the summary data
   3844   1.1  christos 	 * keeps us from getting this far.
   3845   1.1  christos 	 * We check the most eligible zone first and so usually check only
   3846   1.1  christos 	 * one policy zone.
   3847   1.1  christos 	 */
   3848   1.1  christos 	for (rpz_num = 0; zbits != 0; ++rpz_num, zbits >>= 1) {
   3849   1.9  christos 		if ((zbits & 1) == 0) {
   3850   1.1  christos 			continue;
   3851   1.9  christos 		}
   3852   1.1  christos 
   3853   1.1  christos 		/*
   3854   1.1  christos 		 * Do not check policy zones that cannot replace a previously
   3855   1.1  christos 		 * found policy.
   3856   1.1  christos 		 */
   3857   1.1  christos 		rpz = rpzs->zones[rpz_num];
   3858   1.1  christos 		if (st->m.policy != DNS_RPZ_POLICY_MISS) {
   3859   1.9  christos 			if (st->m.rpz->num < rpz->num) {
   3860   1.1  christos 				break;
   3861   1.9  christos 			}
   3862   1.9  christos 			if (st->m.rpz->num == rpz->num && st->m.type < rpz_type)
   3863   1.9  christos 			{
   3864   1.1  christos 				break;
   3865   1.9  christos 			}
   3866   1.1  christos 		}
   3867   1.1  christos 
   3868   1.1  christos 		/*
   3869   1.1  christos 		 * Get the next policy zone's record for this trigger name.
   3870   1.1  christos 		 */
   3871   1.1  christos 		result = rpz_get_p_name(client, p_name, rpz, rpz_type,
   3872   1.1  christos 					trig_name);
   3873   1.9  christos 		if (result != ISC_R_SUCCESS) {
   3874   1.1  christos 			continue;
   3875   1.9  christos 		}
   3876   1.9  christos 		result = rpz_find_p(client, trig_name, qtype, p_name, rpz,
   3877   1.9  christos 				    rpz_type, &p_zone, &p_db, &p_version,
   3878   1.9  christos 				    &p_node, rdatasetp, &policy);
   3879   1.1  christos 		switch (result) {
   3880   1.1  christos 		case DNS_R_NXDOMAIN:
   3881   1.1  christos 			/*
   3882   1.1  christos 			 * Continue after a missing policy record
   3883   1.1  christos 			 * contrary to the summary data.  The summary
   3884   1.1  christos 			 * data can out of date during races with and among
   3885   1.1  christos 			 * policy zone updates.
   3886   1.1  christos 			 */
   3887   1.9  christos 			CTRACE(ISC_LOG_ERROR, "rpz_rewrite_name: mismatched "
   3888   1.9  christos 					      "summary data; "
   3889   1.9  christos 					      "continuing");
   3890   1.1  christos 			continue;
   3891   1.1  christos 		case DNS_R_SERVFAIL:
   3892   1.1  christos 			rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   3893   1.1  christos 			st->m.policy = DNS_RPZ_POLICY_ERROR;
   3894   1.1  christos 			return (DNS_R_SERVFAIL);
   3895   1.1  christos 		default:
   3896   1.1  christos 			/*
   3897   1.1  christos 			 * With more than one applicable policy, prefer
   3898   1.1  christos 			 * the earliest configured policy,
   3899   1.1  christos 			 * client-IP over QNAME over IP over NSDNAME over NSIP,
   3900   1.1  christos 			 * and the smallest name.
   3901   1.1  christos 			 * We known st->m.rpz->num >= rpz->num  and either
   3902   1.1  christos 			 * st->m.rpz->num > rpz->num or st->m.type >= rpz_type
   3903   1.1  christos 			 */
   3904   1.1  christos 			if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   3905   1.1  christos 			    rpz->num == st->m.rpz->num &&
   3906   1.1  christos 			    (st->m.type < rpz_type ||
   3907   1.1  christos 			     (st->m.type == rpz_type &&
   3908   1.1  christos 			      0 >= dns_name_compare(p_name, st->p_name))))
   3909   1.9  christos 			{
   3910   1.1  christos 				continue;
   3911   1.9  christos 			}
   3912   1.4  christos 
   3913   1.1  christos 			if (rpz->policy != DNS_RPZ_POLICY_DISABLED) {
   3914   1.9  christos 				CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_name: "
   3915   1.9  christos 							 "rpz_save_p");
   3916   1.9  christos 				rpz_save_p(st, rpz, rpz_type, policy, p_name, 0,
   3917   1.9  christos 					   result, &p_zone, &p_db, &p_node,
   3918   1.1  christos 					   rdatasetp, p_version);
   3919   1.1  christos 				/*
   3920   1.1  christos 				 * After a hit, higher numbered policy zones
   3921   1.1  christos 				 * are irrelevant
   3922   1.1  christos 				 */
   3923   1.1  christos 				rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   3924   1.1  christos 				return (ISC_R_SUCCESS);
   3925   1.1  christos 			}
   3926   1.1  christos 			/*
   3927   1.1  christos 			 * Log DNS_RPZ_POLICY_DISABLED zones
   3928   1.1  christos 			 * and try the next eligible policy zone.
   3929   1.1  christos 			 */
   3930   1.9  christos 			rpz_log_rewrite(client, true, policy, rpz_type, p_zone,
   3931   1.9  christos 					p_name, NULL, rpz_num);
   3932   1.1  christos 			break;
   3933   1.1  christos 		}
   3934   1.1  christos 	}
   3935   1.1  christos 
   3936   1.1  christos 	rpz_clean(&p_zone, &p_db, &p_node, rdatasetp);
   3937   1.1  christos 	return (ISC_R_SUCCESS);
   3938   1.1  christos }
   3939   1.1  christos 
   3940   1.1  christos static void
   3941   1.1  christos rpz_rewrite_ns_skip(ns_client_t *client, dns_name_t *nsname,
   3942   1.9  christos 		    isc_result_t result, int level, const char *str) {
   3943   1.1  christos 	dns_rpz_st_t *st;
   3944   1.1  christos 
   3945   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite_ns_skip");
   3946   1.1  christos 
   3947   1.1  christos 	st = client->query.rpz_st;
   3948   1.1  christos 
   3949   1.9  christos 	if (str != NULL) {
   3950   1.9  christos 		rpz_log_fail_helper(client, level, nsname, DNS_RPZ_TYPE_NSIP,
   3951   1.9  christos 				    DNS_RPZ_TYPE_NSDNAME, str, result);
   3952   1.9  christos 	}
   3953   1.1  christos 	if (st->r.ns_rdataset != NULL &&
   3954  1.16  christos 	    dns_rdataset_isassociated(st->r.ns_rdataset))
   3955  1.16  christos 	{
   3956   1.1  christos 		dns_rdataset_disassociate(st->r.ns_rdataset);
   3957   1.9  christos 	}
   3958   1.1  christos 
   3959   1.1  christos 	st->r.label--;
   3960   1.1  christos }
   3961   1.1  christos 
   3962   1.1  christos /*
   3963   1.1  christos  * RPZ query result types
   3964   1.1  christos  */
   3965   1.1  christos typedef enum {
   3966   1.1  christos 	qresult_type_done = 0,
   3967   1.1  christos 	qresult_type_restart = 1,
   3968   1.1  christos 	qresult_type_recurse = 2
   3969   1.1  christos } qresult_type_t;
   3970   1.1  christos 
   3971   1.1  christos /*
   3972   1.1  christos  * Look for response policy zone QNAME, NSIP, and NSDNAME rewriting.
   3973   1.1  christos  */
   3974   1.1  christos static isc_result_t
   3975   1.9  christos rpz_rewrite(ns_client_t *client, dns_rdatatype_t qtype, isc_result_t qresult,
   3976   1.9  christos 	    bool resuming, dns_rdataset_t *ordataset, dns_rdataset_t *osigset) {
   3977   1.1  christos 	dns_rpz_zones_t *rpzs;
   3978   1.1  christos 	dns_rpz_st_t *st;
   3979   1.1  christos 	dns_rdataset_t *rdataset;
   3980   1.1  christos 	dns_fixedname_t nsnamef;
   3981   1.1  christos 	dns_name_t *nsname;
   3982   1.1  christos 	qresult_type_t qresult_type;
   3983   1.1  christos 	dns_rpz_zbits_t zbits;
   3984   1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   3985   1.1  christos 	dns_rpz_have_t have;
   3986   1.1  christos 	dns_rpz_popt_t popt;
   3987   1.1  christos 	int rpz_ver;
   3988  1.15  christos 	unsigned int options;
   3989   1.1  christos #ifdef USE_DNSRPS
   3990   1.1  christos 	librpz_emsg_t emsg;
   3991   1.9  christos #endif /* ifdef USE_DNSRPS */
   3992   1.1  christos 
   3993   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_rewrite");
   3994   1.1  christos 
   3995   1.1  christos 	rpzs = client->view->rpzs;
   3996   1.1  christos 	st = client->query.rpz_st;
   3997   1.1  christos 
   3998  1.13  christos 	if (rpzs == NULL) {
   3999  1.13  christos 		return (ISC_R_NOTFOUND);
   4000  1.13  christos 	}
   4001  1.13  christos 	if (st != NULL && (st->state & DNS_RPZ_REWRITTEN) != 0) {
   4002  1.13  christos 		return (DNS_R_DISALLOWED);
   4003  1.13  christos 	}
   4004  1.13  christos 	if (RECURSING(client)) {
   4005   1.1  christos 		return (DNS_R_DISALLOWED);
   4006   1.9  christos 	}
   4007   1.1  christos 
   4008   1.1  christos 	RWLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4009   1.1  christos 	if ((rpzs->p.num_zones == 0 && !rpzs->p.dnsrps_enabled) ||
   4010   1.1  christos 	    (!RECURSIONOK(client) && rpzs->p.no_rd_ok == 0) ||
   4011   1.1  christos 	    !rpz_ck_dnssec(client, qresult, ordataset, osigset))
   4012   1.1  christos 	{
   4013   1.1  christos 		RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4014   1.1  christos 		return (DNS_R_DISALLOWED);
   4015   1.1  christos 	}
   4016   1.1  christos 	have = rpzs->have;
   4017   1.1  christos 	popt = rpzs->p;
   4018   1.1  christos 	rpz_ver = rpzs->rpz_ver;
   4019   1.1  christos 	RWUNLOCK(&rpzs->search_lock, isc_rwlocktype_read);
   4020   1.1  christos 
   4021   1.1  christos #ifndef USE_DNSRPS
   4022   1.1  christos 	INSIST(!popt.dnsrps_enabled);
   4023   1.9  christos #endif /* ifndef USE_DNSRPS */
   4024   1.1  christos 
   4025   1.1  christos 	if (st == NULL) {
   4026   1.1  christos 		st = isc_mem_get(client->mctx, sizeof(*st));
   4027   1.1  christos 		st->state = 0;
   4028   1.1  christos 		st->rpsdb = NULL;
   4029   1.1  christos 	}
   4030   1.1  christos 	if (st->state == 0) {
   4031   1.1  christos 		st->state |= DNS_RPZ_ACTIVE;
   4032   1.1  christos 		memset(&st->m, 0, sizeof(st->m));
   4033   1.1  christos 		st->m.type = DNS_RPZ_TYPE_BAD;
   4034   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_MISS;
   4035   1.1  christos 		st->m.ttl = ~0;
   4036   1.1  christos 		memset(&st->r, 0, sizeof(st->r));
   4037   1.1  christos 		memset(&st->q, 0, sizeof(st->q));
   4038   1.1  christos 		st->p_name = dns_fixedname_initname(&st->_p_namef);
   4039   1.1  christos 		st->r_name = dns_fixedname_initname(&st->_r_namef);
   4040   1.1  christos 		st->fname = dns_fixedname_initname(&st->_fnamef);
   4041   1.1  christos 		st->have = have;
   4042   1.1  christos 		st->popt = popt;
   4043   1.1  christos 		st->rpz_ver = rpz_ver;
   4044   1.1  christos 		client->query.rpz_st = st;
   4045   1.1  christos #ifdef USE_DNSRPS
   4046   1.1  christos 		if (popt.dnsrps_enabled) {
   4047   1.1  christos 			if (st->rpsdb != NULL) {
   4048   1.1  christos 				dns_db_detach(&st->rpsdb);
   4049   1.1  christos 			}
   4050   1.9  christos 			result = dns_dnsrps_rewrite_init(
   4051   1.9  christos 				&emsg, st, rpzs, client->query.qname,
   4052   1.9  christos 				client->mctx, RECURSIONOK(client));
   4053   1.1  christos 			if (result != ISC_R_SUCCESS) {
   4054   1.9  christos 				rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   4055   1.9  christos 					     DNS_RPZ_TYPE_QNAME, emsg.c,
   4056   1.9  christos 					     result);
   4057   1.1  christos 				st->m.policy = DNS_RPZ_POLICY_ERROR;
   4058   1.1  christos 				return (ISC_R_SUCCESS);
   4059   1.1  christos 			}
   4060   1.1  christos 		}
   4061   1.9  christos #endif /* ifdef USE_DNSRPS */
   4062   1.1  christos 	}
   4063   1.1  christos 
   4064   1.1  christos 	/*
   4065   1.1  christos 	 * There is nothing to rewrite if the main query failed.
   4066   1.1  christos 	 */
   4067   1.1  christos 	switch (qresult) {
   4068   1.1  christos 	case ISC_R_SUCCESS:
   4069   1.1  christos 	case DNS_R_GLUE:
   4070   1.1  christos 	case DNS_R_ZONECUT:
   4071   1.1  christos 		qresult_type = qresult_type_done;
   4072   1.1  christos 		break;
   4073   1.1  christos 	case DNS_R_EMPTYNAME:
   4074   1.1  christos 	case DNS_R_NXRRSET:
   4075   1.1  christos 	case DNS_R_NXDOMAIN:
   4076   1.1  christos 	case DNS_R_EMPTYWILD:
   4077   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   4078   1.1  christos 	case DNS_R_NCACHENXRRSET:
   4079   1.3  christos 	case DNS_R_COVERINGNSEC:
   4080   1.1  christos 	case DNS_R_CNAME:
   4081   1.1  christos 	case DNS_R_DNAME:
   4082   1.1  christos 		qresult_type = qresult_type_restart;
   4083   1.1  christos 		break;
   4084   1.1  christos 	case DNS_R_DELEGATION:
   4085   1.1  christos 	case ISC_R_NOTFOUND:
   4086   1.1  christos 		/*
   4087   1.1  christos 		 * If recursion is on, do only tentative rewriting.
   4088   1.1  christos 		 * If recursion is off, this the normal and only time we
   4089   1.1  christos 		 * can rewrite.
   4090   1.1  christos 		 */
   4091   1.9  christos 		if (RECURSIONOK(client)) {
   4092   1.1  christos 			qresult_type = qresult_type_recurse;
   4093   1.9  christos 		} else {
   4094   1.1  christos 			qresult_type = qresult_type_restart;
   4095   1.9  christos 		}
   4096   1.1  christos 		break;
   4097   1.1  christos 	case ISC_R_FAILURE:
   4098   1.1  christos 	case ISC_R_TIMEDOUT:
   4099   1.1  christos 	case DNS_R_BROKENCHAIN:
   4100   1.1  christos 		rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL3, NULL,
   4101   1.1  christos 			     DNS_RPZ_TYPE_QNAME,
   4102   1.3  christos 			     "stop on qresult in rpz_rewrite()", qresult);
   4103   1.1  christos 		return (ISC_R_SUCCESS);
   4104   1.1  christos 	default:
   4105   1.1  christos 		rpz_log_fail(client, DNS_RPZ_DEBUG_LEVEL1, NULL,
   4106   1.1  christos 			     DNS_RPZ_TYPE_QNAME,
   4107   1.3  christos 			     "stop on unrecognized qresult in rpz_rewrite()",
   4108   1.1  christos 			     qresult);
   4109   1.1  christos 		return (ISC_R_SUCCESS);
   4110   1.1  christos 	}
   4111   1.1  christos 
   4112   1.1  christos 	rdataset = NULL;
   4113   1.1  christos 
   4114   1.1  christos 	if ((st->state & (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME)) !=
   4115   1.1  christos 	    (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME))
   4116   1.1  christos 	{
   4117   1.1  christos 		isc_netaddr_t netaddr;
   4118   1.1  christos 		dns_rpz_zbits_t allowed;
   4119   1.1  christos 
   4120   1.1  christos 		if (!st->popt.dnsrps_enabled &&
   4121  1.16  christos 		    qresult_type == qresult_type_recurse)
   4122  1.16  christos 		{
   4123   1.1  christos 			/*
   4124   1.1  christos 			 * This request needs recursion that has not been done.
   4125   1.1  christos 			 * Get bits for the policy zones that do not need
   4126   1.1  christos 			 * to wait for the results of recursion.
   4127   1.1  christos 			 */
   4128   1.1  christos 			allowed = st->have.qname_skip_recurse;
   4129   1.1  christos 			if (allowed == 0) {
   4130   1.1  christos 				return (ISC_R_SUCCESS);
   4131   1.1  christos 			}
   4132   1.1  christos 		} else {
   4133   1.1  christos 			allowed = DNS_RPZ_ALL_ZBITS;
   4134   1.1  christos 		}
   4135   1.1  christos 
   4136   1.1  christos 		/*
   4137   1.1  christos 		 * Check once for triggers for the client IP address.
   4138   1.1  christos 		 */
   4139   1.1  christos 		if ((st->state & DNS_RPZ_DONE_CLIENT_IP) == 0) {
   4140   1.1  christos 			zbits = rpz_get_zbits(client, dns_rdatatype_none,
   4141   1.1  christos 					      DNS_RPZ_TYPE_CLIENT_IP);
   4142   1.1  christos 			zbits &= allowed;
   4143   1.1  christos 			if (zbits != 0) {
   4144   1.1  christos 				isc_netaddr_fromsockaddr(&netaddr,
   4145   1.1  christos 							 &client->peeraddr);
   4146   1.1  christos 				result = rpz_rewrite_ip(client, &netaddr, qtype,
   4147   1.1  christos 							DNS_RPZ_TYPE_CLIENT_IP,
   4148   1.1  christos 							zbits, &rdataset);
   4149   1.9  christos 				if (result != ISC_R_SUCCESS) {
   4150   1.1  christos 					goto cleanup;
   4151   1.9  christos 				}
   4152   1.1  christos 			}
   4153   1.1  christos 		}
   4154   1.1  christos 
   4155   1.1  christos 		/*
   4156   1.1  christos 		 * Check triggers for the query name if this is the first time
   4157   1.1  christos 		 * for the current qname.
   4158   1.1  christos 		 * There is a first time for each name in a CNAME chain
   4159   1.1  christos 		 */
   4160   1.1  christos 		if ((st->state & DNS_RPZ_DONE_QNAME) == 0) {
   4161   1.3  christos 			bool norec = (qresult_type != qresult_type_recurse);
   4162   1.1  christos 			result = rpz_rewrite_name(client, client->query.qname,
   4163   1.1  christos 						  qtype, DNS_RPZ_TYPE_QNAME,
   4164   1.9  christos 						  allowed, norec, &rdataset);
   4165   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4166   1.1  christos 				goto cleanup;
   4167   1.9  christos 			}
   4168   1.1  christos 
   4169   1.1  christos 			/*
   4170   1.1  christos 			 * Check IPv4 addresses in A RRs next.
   4171   1.1  christos 			 * Reset to the start of the NS names.
   4172   1.1  christos 			 */
   4173   1.1  christos 			st->r.label = dns_name_countlabels(client->query.qname);
   4174   1.1  christos 			st->state &= ~(DNS_RPZ_DONE_QNAME_IP |
   4175   1.1  christos 				       DNS_RPZ_DONE_IPv4);
   4176   1.1  christos 		}
   4177   1.1  christos 
   4178   1.1  christos 		/*
   4179   1.1  christos 		 * Quit if this was an attempt to find a qname or
   4180   1.1  christos 		 * client-IP trigger before recursion.
   4181   1.1  christos 		 * We will be back if no pre-recursion triggers hit.
   4182   1.1  christos 		 * For example, consider 2 policy zones, both with qname and
   4183   1.1  christos 		 * IP address triggers.  If the qname misses the 1st zone,
   4184   1.1  christos 		 * then we cannot know whether a hit for the qname in the
   4185   1.1  christos 		 * 2nd zone matters until after recursing to get the A RRs and
   4186   1.1  christos 		 * testing them in the first zone.
   4187   1.1  christos 		 * Do not bother saving the work from this attempt,
   4188   1.9  christos 		 * because recursion is so slow.
   4189   1.1  christos 		 */
   4190   1.9  christos 		if (qresult_type == qresult_type_recurse) {
   4191   1.1  christos 			goto cleanup;
   4192   1.9  christos 		}
   4193   1.1  christos 
   4194   1.1  christos 		/*
   4195   1.1  christos 		 * DNS_RPZ_DONE_QNAME but not DNS_RPZ_DONE_CLIENT_IP
   4196   1.1  christos 		 * is reset at the end of dealing with each CNAME.
   4197   1.1  christos 		 */
   4198   1.1  christos 		st->state |= (DNS_RPZ_DONE_CLIENT_IP | DNS_RPZ_DONE_QNAME);
   4199   1.1  christos 	}
   4200   1.1  christos 
   4201   1.1  christos 	/*
   4202   1.1  christos 	 * Check known IP addresses for the query name if the database lookup
   4203   1.1  christos 	 * resulted in some addresses (qresult_type == qresult_type_done)
   4204   1.1  christos 	 * and if we have not already checked them.
   4205   1.1  christos 	 * Any recursion required for the query has already happened.
   4206   1.1  christos 	 * Do not check addresses that will not be in the ANSWER section.
   4207   1.1  christos 	 */
   4208   1.1  christos 	if ((st->state & DNS_RPZ_DONE_QNAME_IP) == 0 &&
   4209   1.1  christos 	    qresult_type == qresult_type_done &&
   4210   1.9  christos 	    rpz_get_zbits(client, qtype, DNS_RPZ_TYPE_IP) != 0)
   4211   1.9  christos 	{
   4212   1.9  christos 		result = rpz_rewrite_ip_rrsets(client, client->query.qname,
   4213   1.9  christos 					       qtype, DNS_RPZ_TYPE_IP,
   4214   1.1  christos 					       &rdataset, resuming);
   4215   1.9  christos 		if (result != ISC_R_SUCCESS) {
   4216   1.1  christos 			goto cleanup;
   4217   1.9  christos 		}
   4218   1.1  christos 		/*
   4219   1.1  christos 		 * We are finished checking the IP addresses for the qname.
   4220   1.9  christos 		 * Start with IPv4 if we will check NS IP addresses.
   4221   1.1  christos 		 */
   4222   1.1  christos 		st->state |= DNS_RPZ_DONE_QNAME_IP;
   4223   1.1  christos 		st->state &= ~DNS_RPZ_DONE_IPv4;
   4224   1.1  christos 	}
   4225   1.1  christos 
   4226   1.1  christos 	/*
   4227   1.1  christos 	 * Stop looking for rules if there are none of the other kinds
   4228   1.1  christos 	 * that could override what we already have.
   4229   1.1  christos 	 */
   4230   1.9  christos 	if (rpz_get_zbits(client, dns_rdatatype_any, DNS_RPZ_TYPE_NSDNAME) ==
   4231   1.9  christos 		    0 &&
   4232   1.9  christos 	    rpz_get_zbits(client, dns_rdatatype_any, DNS_RPZ_TYPE_NSIP) == 0)
   4233   1.9  christos 	{
   4234   1.1  christos 		result = ISC_R_SUCCESS;
   4235   1.1  christos 		goto cleanup;
   4236   1.1  christos 	}
   4237   1.1  christos 
   4238   1.1  christos 	dns_fixedname_init(&nsnamef);
   4239   1.1  christos 	dns_name_clone(client->query.qname, dns_fixedname_name(&nsnamef));
   4240  1.16  christos 	options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   4241   1.1  christos 	while (st->r.label > st->popt.min_ns_labels) {
   4242  1.15  christos 		bool was_glue = false;
   4243   1.1  christos 		/*
   4244   1.1  christos 		 * Get NS rrset for each domain in the current qname.
   4245   1.1  christos 		 */
   4246   1.1  christos 		if (st->r.label == dns_name_countlabels(client->query.qname)) {
   4247   1.1  christos 			nsname = client->query.qname;
   4248   1.1  christos 		} else {
   4249   1.1  christos 			nsname = dns_fixedname_name(&nsnamef);
   4250   1.9  christos 			dns_name_split(client->query.qname, st->r.label, NULL,
   4251   1.9  christos 				       nsname);
   4252   1.1  christos 		}
   4253   1.1  christos 		if (st->r.ns_rdataset == NULL ||
   4254  1.16  christos 		    !dns_rdataset_isassociated(st->r.ns_rdataset))
   4255  1.16  christos 		{
   4256   1.1  christos 			dns_db_t *db = NULL;
   4257   1.1  christos 			result = rpz_rrset_find(client, nsname,
   4258  1.15  christos 						dns_rdatatype_ns, options,
   4259   1.9  christos 						DNS_RPZ_TYPE_NSDNAME, &db, NULL,
   4260   1.9  christos 						&st->r.ns_rdataset, resuming);
   4261   1.9  christos 			if (db != NULL) {
   4262   1.1  christos 				dns_db_detach(&db);
   4263   1.9  christos 			}
   4264   1.9  christos 			if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
   4265   1.1  christos 				goto cleanup;
   4266   1.9  christos 			}
   4267   1.1  christos 			switch (result) {
   4268  1.15  christos 			case DNS_R_GLUE:
   4269  1.15  christos 				was_glue = true;
   4270  1.15  christos 				FALLTHROUGH;
   4271   1.1  christos 			case ISC_R_SUCCESS:
   4272   1.1  christos 				result = dns_rdataset_first(st->r.ns_rdataset);
   4273   1.9  christos 				if (result != ISC_R_SUCCESS) {
   4274   1.1  christos 					goto cleanup;
   4275   1.9  christos 				}
   4276   1.1  christos 				st->state &= ~(DNS_RPZ_DONE_NSDNAME |
   4277   1.1  christos 					       DNS_RPZ_DONE_IPv4);
   4278   1.1  christos 				break;
   4279   1.1  christos 			case DNS_R_DELEGATION:
   4280   1.1  christos 			case DNS_R_DUPLICATE:
   4281   1.1  christos 			case DNS_R_DROP:
   4282   1.1  christos 				goto cleanup;
   4283   1.1  christos 			case DNS_R_EMPTYNAME:
   4284   1.1  christos 			case DNS_R_NXRRSET:
   4285   1.1  christos 			case DNS_R_EMPTYWILD:
   4286   1.1  christos 			case DNS_R_NXDOMAIN:
   4287   1.1  christos 			case DNS_R_NCACHENXDOMAIN:
   4288   1.1  christos 			case DNS_R_NCACHENXRRSET:
   4289   1.1  christos 			case ISC_R_NOTFOUND:
   4290   1.1  christos 			case DNS_R_CNAME:
   4291   1.1  christos 			case DNS_R_DNAME:
   4292   1.9  christos 				rpz_rewrite_ns_skip(client, nsname, result, 0,
   4293   1.9  christos 						    NULL);
   4294   1.1  christos 				continue;
   4295   1.1  christos 			case ISC_R_TIMEDOUT:
   4296   1.1  christos 			case DNS_R_BROKENCHAIN:
   4297   1.1  christos 			case ISC_R_FAILURE:
   4298   1.1  christos 				rpz_rewrite_ns_skip(client, nsname, result,
   4299   1.9  christos 						    DNS_RPZ_DEBUG_LEVEL3,
   4300   1.9  christos 						    " NS rpz_rrset_find()");
   4301   1.1  christos 				continue;
   4302   1.1  christos 			default:
   4303   1.1  christos 				rpz_rewrite_ns_skip(client, nsname, result,
   4304   1.9  christos 						    DNS_RPZ_INFO_LEVEL,
   4305   1.9  christos 						    " unrecognized NS"
   4306   1.9  christos 						    " rpz_rrset_find()");
   4307   1.1  christos 				continue;
   4308   1.1  christos 			}
   4309   1.1  christos 		}
   4310  1.15  christos 
   4311   1.1  christos 		/*
   4312   1.1  christos 		 * Check all NS names.
   4313   1.1  christos 		 */
   4314   1.1  christos 		do {
   4315   1.1  christos 			dns_rdata_ns_t ns;
   4316   1.1  christos 			dns_rdata_t nsrdata = DNS_RDATA_INIT;
   4317   1.1  christos 
   4318   1.1  christos 			dns_rdataset_current(st->r.ns_rdataset, &nsrdata);
   4319   1.1  christos 			result = dns_rdata_tostruct(&nsrdata, &ns, NULL);
   4320   1.3  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4321   1.1  christos 			dns_rdata_reset(&nsrdata);
   4322   1.3  christos 
   4323   1.1  christos 			/*
   4324   1.1  christos 			 * Do nothing about "NS ."
   4325   1.1  christos 			 */
   4326   1.1  christos 			if (dns_name_equal(&ns.name, dns_rootname)) {
   4327   1.1  christos 				dns_rdata_freestruct(&ns);
   4328   1.1  christos 				result = dns_rdataset_next(st->r.ns_rdataset);
   4329   1.1  christos 				continue;
   4330   1.1  christos 			}
   4331   1.1  christos 			/*
   4332   1.1  christos 			 * Check this NS name if we did not handle it
   4333   1.1  christos 			 * during a previous recursion.
   4334   1.1  christos 			 */
   4335   1.1  christos 			if ((st->state & DNS_RPZ_DONE_NSDNAME) == 0) {
   4336   1.9  christos 				result = rpz_rewrite_name(
   4337   1.9  christos 					client, &ns.name, qtype,
   4338   1.9  christos 					DNS_RPZ_TYPE_NSDNAME, DNS_RPZ_ALL_ZBITS,
   4339   1.9  christos 					true, &rdataset);
   4340   1.1  christos 				if (result != ISC_R_SUCCESS) {
   4341   1.1  christos 					dns_rdata_freestruct(&ns);
   4342   1.1  christos 					goto cleanup;
   4343   1.1  christos 				}
   4344   1.1  christos 				st->state |= DNS_RPZ_DONE_NSDNAME;
   4345   1.1  christos 			}
   4346   1.1  christos 			/*
   4347   1.1  christos 			 * Check all IP addresses for this NS name.
   4348   1.1  christos 			 */
   4349   1.1  christos 			result = rpz_rewrite_ip_rrsets(client, &ns.name, qtype,
   4350   1.1  christos 						       DNS_RPZ_TYPE_NSIP,
   4351   1.1  christos 						       &rdataset, resuming);
   4352   1.1  christos 			dns_rdata_freestruct(&ns);
   4353   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4354   1.1  christos 				goto cleanup;
   4355   1.9  christos 			}
   4356   1.1  christos 			st->state &= ~(DNS_RPZ_DONE_NSDNAME |
   4357   1.1  christos 				       DNS_RPZ_DONE_IPv4);
   4358   1.1  christos 			result = dns_rdataset_next(st->r.ns_rdataset);
   4359   1.1  christos 		} while (result == ISC_R_SUCCESS);
   4360   1.1  christos 		dns_rdataset_disassociate(st->r.ns_rdataset);
   4361  1.15  christos 
   4362  1.15  christos 		/*
   4363  1.15  christos 		 * If we just checked a glue NS RRset retry without allowing
   4364  1.15  christos 		 * glue responses, otherwise setup for the next name.
   4365  1.15  christos 		 */
   4366  1.15  christos 		if (was_glue) {
   4367  1.16  christos 			options = client->query.dboptions;
   4368  1.15  christos 		} else {
   4369  1.16  christos 			options = client->query.dboptions | DNS_DBFIND_GLUEOK;
   4370  1.15  christos 			st->r.label--;
   4371  1.15  christos 		}
   4372   1.1  christos 
   4373   1.1  christos 		if (rpz_get_zbits(client, dns_rdatatype_any,
   4374   1.1  christos 				  DNS_RPZ_TYPE_NSDNAME) == 0 &&
   4375   1.1  christos 		    rpz_get_zbits(client, dns_rdatatype_any,
   4376   1.1  christos 				  DNS_RPZ_TYPE_NSIP) == 0)
   4377   1.9  christos 		{
   4378   1.1  christos 			break;
   4379   1.9  christos 		}
   4380   1.1  christos 	}
   4381   1.1  christos 
   4382   1.1  christos 	/*
   4383   1.1  christos 	 * Use the best hit, if any.
   4384   1.1  christos 	 */
   4385   1.1  christos 	result = ISC_R_SUCCESS;
   4386   1.1  christos 
   4387   1.1  christos cleanup:
   4388   1.1  christos #ifdef USE_DNSRPS
   4389   1.9  christos 	if (st->popt.dnsrps_enabled && st->m.policy != DNS_RPZ_POLICY_ERROR &&
   4390   1.1  christos 	    !dnsrps_set_p(&emsg, client, st, qtype, &rdataset,
   4391   1.3  christos 			  (qresult_type != qresult_type_recurse)))
   4392   1.1  christos 	{
   4393   1.1  christos 		rpz_log_fail(client, DNS_RPZ_ERROR_LEVEL, NULL,
   4394   1.1  christos 			     DNS_RPZ_TYPE_BAD, emsg.c, DNS_R_SERVFAIL);
   4395   1.1  christos 		st->m.policy = DNS_RPZ_POLICY_ERROR;
   4396   1.1  christos 	}
   4397   1.9  christos #endif /* ifdef USE_DNSRPS */
   4398   1.1  christos 	if (st->m.policy != DNS_RPZ_POLICY_MISS &&
   4399   1.1  christos 	    st->m.policy != DNS_RPZ_POLICY_ERROR &&
   4400   1.1  christos 	    st->m.rpz->policy != DNS_RPZ_POLICY_GIVEN)
   4401   1.9  christos 	{
   4402   1.1  christos 		st->m.policy = st->m.rpz->policy;
   4403   1.9  christos 	}
   4404   1.1  christos 	if (st->m.policy == DNS_RPZ_POLICY_MISS ||
   4405   1.1  christos 	    st->m.policy == DNS_RPZ_POLICY_PASSTHRU ||
   4406   1.9  christos 	    st->m.policy == DNS_RPZ_POLICY_ERROR)
   4407   1.9  christos 	{
   4408   1.1  christos 		if (st->m.policy == DNS_RPZ_POLICY_PASSTHRU &&
   4409  1.16  christos 		    result != DNS_R_DELEGATION)
   4410  1.16  christos 		{
   4411   1.9  christos 			rpz_log_rewrite(client, false, st->m.policy, st->m.type,
   4412   1.9  christos 					st->m.zone, st->p_name, NULL,
   4413   1.9  christos 					st->m.rpz->num);
   4414   1.9  christos 		}
   4415   1.1  christos 		rpz_match_clear(st);
   4416   1.1  christos 	}
   4417   1.1  christos 	if (st->m.policy == DNS_RPZ_POLICY_ERROR) {
   4418   1.1  christos 		CTRACE(ISC_LOG_ERROR, "SERVFAIL due to RPZ policy");
   4419   1.1  christos 		st->m.type = DNS_RPZ_TYPE_BAD;
   4420   1.1  christos 		result = DNS_R_SERVFAIL;
   4421   1.1  christos 	}
   4422   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   4423   1.9  christos 	if ((st->state & DNS_RPZ_RECURSING) == 0) {
   4424   1.1  christos 		rpz_clean(NULL, &st->r.db, NULL, &st->r.ns_rdataset);
   4425   1.9  christos 	}
   4426   1.1  christos 
   4427   1.1  christos 	return (result);
   4428   1.1  christos }
   4429   1.1  christos 
   4430   1.1  christos /*
   4431   1.1  christos  * See if response policy zone rewriting is allowed by a lack of interest
   4432   1.1  christos  * by the client in DNSSEC or a lack of signatures.
   4433   1.1  christos  */
   4434   1.3  christos static bool
   4435   1.1  christos rpz_ck_dnssec(ns_client_t *client, isc_result_t qresult,
   4436   1.9  christos 	      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
   4437   1.1  christos 	dns_fixedname_t fixed;
   4438   1.1  christos 	dns_name_t *found;
   4439   1.1  christos 	dns_rdataset_t trdataset;
   4440   1.1  christos 	dns_rdatatype_t type;
   4441   1.1  christos 	isc_result_t result;
   4442   1.1  christos 
   4443   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "rpz_ck_dnssec");
   4444   1.1  christos 
   4445   1.9  christos 	if (client->view->rpzs->p.break_dnssec || !WANTDNSSEC(client)) {
   4446   1.3  christos 		return (true);
   4447   1.9  christos 	}
   4448   1.1  christos 
   4449   1.1  christos 	/*
   4450   1.1  christos 	 * We do not know if there are signatures if we have not recursed
   4451   1.1  christos 	 * for them.
   4452   1.1  christos 	 */
   4453   1.9  christos 	if (qresult == DNS_R_DELEGATION || qresult == ISC_R_NOTFOUND) {
   4454   1.3  christos 		return (false);
   4455   1.9  christos 	}
   4456   1.1  christos 
   4457   1.9  christos 	if (sigrdataset == NULL) {
   4458   1.3  christos 		return (true);
   4459   1.9  christos 	}
   4460   1.9  christos 	if (dns_rdataset_isassociated(sigrdataset)) {
   4461   1.3  christos 		return (false);
   4462   1.9  christos 	}
   4463   1.1  christos 
   4464   1.1  christos 	/*
   4465   1.1  christos 	 * We are happy to rewrite nothing.
   4466   1.1  christos 	 */
   4467   1.9  christos 	if (rdataset == NULL || !dns_rdataset_isassociated(rdataset)) {
   4468   1.3  christos 		return (true);
   4469   1.9  christos 	}
   4470   1.1  christos 	/*
   4471   1.1  christos 	 * Do not rewrite if there is any sign of signatures.
   4472   1.1  christos 	 */
   4473   1.1  christos 	if (rdataset->type == dns_rdatatype_nsec ||
   4474   1.1  christos 	    rdataset->type == dns_rdatatype_nsec3 ||
   4475   1.1  christos 	    rdataset->type == dns_rdatatype_rrsig)
   4476   1.9  christos 	{
   4477   1.3  christos 		return (false);
   4478   1.9  christos 	}
   4479   1.1  christos 
   4480   1.1  christos 	/*
   4481   1.1  christos 	 * Look for a signature in a negative cache rdataset.
   4482   1.1  christos 	 */
   4483   1.9  christos 	if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) == 0) {
   4484   1.3  christos 		return (true);
   4485   1.9  christos 	}
   4486   1.1  christos 	found = dns_fixedname_initname(&fixed);
   4487   1.1  christos 	dns_rdataset_init(&trdataset);
   4488   1.9  christos 	for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
   4489   1.9  christos 	     result = dns_rdataset_next(rdataset))
   4490   1.9  christos 	{
   4491   1.1  christos 		dns_ncache_current(rdataset, found, &trdataset);
   4492   1.1  christos 		type = trdataset.type;
   4493   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   4494   1.9  christos 		if (type == dns_rdatatype_nsec || type == dns_rdatatype_nsec3 ||
   4495   1.1  christos 		    type == dns_rdatatype_rrsig)
   4496   1.9  christos 		{
   4497   1.3  christos 			return (false);
   4498   1.9  christos 		}
   4499   1.1  christos 	}
   4500   1.3  christos 	return (true);
   4501   1.1  christos }
   4502   1.1  christos 
   4503   1.1  christos /*
   4504   1.1  christos  * Extract a network address from the RDATA of an A or AAAA
   4505   1.1  christos  * record.
   4506   1.1  christos  *
   4507   1.1  christos  * Returns:
   4508   1.1  christos  *	ISC_R_SUCCESS
   4509   1.1  christos  *	ISC_R_NOTIMPLEMENTED	The rdata is not a known address type.
   4510   1.1  christos  */
   4511   1.1  christos static isc_result_t
   4512   1.1  christos rdata_tonetaddr(const dns_rdata_t *rdata, isc_netaddr_t *netaddr) {
   4513   1.1  christos 	struct in_addr ina;
   4514   1.1  christos 	struct in6_addr in6a;
   4515   1.1  christos 
   4516   1.1  christos 	switch (rdata->type) {
   4517   1.1  christos 	case dns_rdatatype_a:
   4518   1.1  christos 		INSIST(rdata->length == 4);
   4519   1.1  christos 		memmove(&ina.s_addr, rdata->data, 4);
   4520   1.1  christos 		isc_netaddr_fromin(netaddr, &ina);
   4521   1.1  christos 		return (ISC_R_SUCCESS);
   4522   1.1  christos 	case dns_rdatatype_aaaa:
   4523   1.1  christos 		INSIST(rdata->length == 16);
   4524   1.1  christos 		memmove(in6a.s6_addr, rdata->data, 16);
   4525   1.1  christos 		isc_netaddr_fromin6(netaddr, &in6a);
   4526   1.1  christos 		return (ISC_R_SUCCESS);
   4527   1.1  christos 	default:
   4528   1.1  christos 		return (ISC_R_NOTIMPLEMENTED);
   4529   1.1  christos 	}
   4530   1.1  christos }
   4531   1.1  christos 
   4532   1.1  christos static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
   4533   1.1  christos static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
   4534   1.1  christos static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
   4535   1.1  christos 
   4536   1.1  christos static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
   4537   1.1  christos 
   4538   1.1  christos static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
   4539   1.1  christos static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
   4540   1.1  christos static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
   4541   1.1  christos static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
   4542   1.1  christos static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
   4543   1.1  christos static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
   4544   1.1  christos static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
   4545   1.1  christos static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
   4546   1.1  christos static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
   4547   1.1  christos static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
   4548   1.1  christos static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
   4549   1.1  christos static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
   4550   1.1  christos static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
   4551   1.1  christos static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
   4552   1.1  christos static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
   4553   1.1  christos static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
   4554   1.1  christos 
   4555   1.1  christos static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
   4556   1.1  christos 
   4557   1.1  christos static dns_name_t rfc1918names[] = {
   4558   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr10, inaddr10_offsets),
   4559   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr16172, inaddr172_offsets),
   4560   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr17172, inaddr172_offsets),
   4561   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr18172, inaddr172_offsets),
   4562   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr19172, inaddr172_offsets),
   4563   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr20172, inaddr172_offsets),
   4564   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr21172, inaddr172_offsets),
   4565   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr22172, inaddr172_offsets),
   4566   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr23172, inaddr172_offsets),
   4567   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr24172, inaddr172_offsets),
   4568   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr25172, inaddr172_offsets),
   4569   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr26172, inaddr172_offsets),
   4570   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr27172, inaddr172_offsets),
   4571   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr28172, inaddr172_offsets),
   4572   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr29172, inaddr172_offsets),
   4573   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr30172, inaddr172_offsets),
   4574   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr31172, inaddr172_offsets),
   4575   1.1  christos 	DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets)
   4576   1.1  christos };
   4577   1.1  christos 
   4578   1.1  christos static unsigned char prisoner_data[] = "\010prisoner\004iana\003org";
   4579   1.9  christos static unsigned char hostmaster_data[] = "\012hostmaster\014root-"
   4580   1.9  christos 					 "servers\003org";
   4581   1.1  christos 
   4582   1.1  christos static unsigned char prisoner_offsets[] = { 0, 9, 14, 18 };
   4583   1.1  christos static unsigned char hostmaster_offsets[] = { 0, 11, 24, 28 };
   4584   1.1  christos 
   4585   1.9  christos static dns_name_t const prisoner = DNS_NAME_INITABSOLUTE(prisoner_data,
   4586   1.9  christos 							 prisoner_offsets);
   4587   1.9  christos static dns_name_t const hostmaster = DNS_NAME_INITABSOLUTE(hostmaster_data,
   4588   1.9  christos 							   hostmaster_offsets);
   4589   1.1  christos 
   4590   1.1  christos static void
   4591   1.1  christos warn_rfc1918(ns_client_t *client, dns_name_t *fname, dns_rdataset_t *rdataset) {
   4592   1.1  christos 	unsigned int i;
   4593   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   4594   1.1  christos 	dns_rdata_soa_t soa;
   4595   1.1  christos 	dns_rdataset_t found;
   4596   1.1  christos 	isc_result_t result;
   4597   1.1  christos 
   4598   1.9  christos 	for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) {
   4599   1.1  christos 		if (dns_name_issubdomain(fname, &rfc1918names[i])) {
   4600   1.1  christos 			dns_rdataset_init(&found);
   4601   1.9  christos 			result = dns_ncache_getrdataset(
   4602   1.9  christos 				rdataset, &rfc1918names[i], dns_rdatatype_soa,
   4603   1.9  christos 				&found);
   4604   1.9  christos 			if (result != ISC_R_SUCCESS) {
   4605   1.1  christos 				return;
   4606   1.9  christos 			}
   4607   1.1  christos 
   4608   1.1  christos 			result = dns_rdataset_first(&found);
   4609   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4610   1.1  christos 			dns_rdataset_current(&found, &rdata);
   4611   1.1  christos 			result = dns_rdata_tostruct(&rdata, &soa, NULL);
   4612   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4613   1.1  christos 			if (dns_name_equal(&soa.origin, &prisoner) &&
   4614   1.9  christos 			    dns_name_equal(&soa.contact, &hostmaster))
   4615   1.9  christos 			{
   4616   1.1  christos 				char buf[DNS_NAME_FORMATSIZE];
   4617   1.1  christos 				dns_name_format(fname, buf, sizeof(buf));
   4618   1.1  christos 				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
   4619   1.1  christos 					      NS_LOGMODULE_QUERY,
   4620   1.1  christos 					      ISC_LOG_WARNING,
   4621   1.1  christos 					      "RFC 1918 response from "
   4622   1.9  christos 					      "Internet for %s",
   4623   1.9  christos 					      buf);
   4624   1.1  christos 			}
   4625   1.1  christos 			dns_rdataset_disassociate(&found);
   4626   1.1  christos 			return;
   4627   1.1  christos 		}
   4628   1.1  christos 	}
   4629   1.1  christos }
   4630   1.1  christos 
   4631   1.1  christos static void
   4632   1.1  christos query_findclosestnsec3(dns_name_t *qname, dns_db_t *db,
   4633   1.1  christos 		       dns_dbversion_t *version, ns_client_t *client,
   4634   1.1  christos 		       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
   4635   1.9  christos 		       dns_name_t *fname, bool exact, dns_name_t *found) {
   4636   1.1  christos 	unsigned char salt[256];
   4637   1.1  christos 	size_t salt_length;
   4638   1.3  christos 	uint16_t iterations;
   4639   1.1  christos 	isc_result_t result;
   4640   1.1  christos 	unsigned int dboptions;
   4641   1.1  christos 	dns_fixedname_t fixed;
   4642   1.1  christos 	dns_hash_t hash;
   4643   1.1  christos 	dns_name_t name;
   4644   1.1  christos 	unsigned int skip = 0, labels;
   4645   1.1  christos 	dns_rdata_nsec3_t nsec3;
   4646   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   4647   1.3  christos 	bool optout;
   4648   1.1  christos 	dns_clientinfomethods_t cm;
   4649   1.1  christos 	dns_clientinfo_t ci;
   4650   1.1  christos 
   4651   1.1  christos 	salt_length = sizeof(salt);
   4652   1.1  christos 	result = dns_db_getnsec3parameters(db, version, &hash, NULL,
   4653   1.1  christos 					   &iterations, salt, &salt_length);
   4654   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4655   1.1  christos 		return;
   4656   1.9  christos 	}
   4657   1.1  christos 
   4658   1.1  christos 	dns_name_init(&name, NULL);
   4659   1.1  christos 	dns_name_clone(qname, &name);
   4660   1.1  christos 	labels = dns_name_countlabels(&name);
   4661   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   4662  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   4663   1.1  christos 
   4664   1.1  christos 	/*
   4665   1.1  christos 	 * Map unknown algorithm to known value.
   4666   1.1  christos 	 */
   4667   1.9  christos 	if (hash == DNS_NSEC3_UNKNOWNALG) {
   4668   1.1  christos 		hash = 1;
   4669   1.9  christos 	}
   4670   1.1  christos 
   4671   1.9  christos again:
   4672   1.1  christos 	dns_fixedname_init(&fixed);
   4673   1.1  christos 	result = dns_nsec3_hashname(&fixed, NULL, NULL, &name,
   4674   1.9  christos 				    dns_db_origin(db), hash, iterations, salt,
   4675   1.9  christos 				    salt_length);
   4676   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4677   1.1  christos 		return;
   4678   1.9  christos 	}
   4679   1.1  christos 
   4680   1.1  christos 	dboptions = client->query.dboptions | DNS_DBFIND_FORCENSEC3;
   4681   1.1  christos 	result = dns_db_findext(db, dns_fixedname_name(&fixed), version,
   4682   1.1  christos 				dns_rdatatype_nsec3, dboptions, client->now,
   4683   1.1  christos 				NULL, fname, &cm, &ci, rdataset, sigrdataset);
   4684   1.1  christos 
   4685   1.1  christos 	if (result == DNS_R_NXDOMAIN) {
   4686   1.1  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   4687   1.1  christos 			return;
   4688   1.1  christos 		}
   4689   1.1  christos 		result = dns_rdataset_first(rdataset);
   4690   1.1  christos 		INSIST(result == ISC_R_SUCCESS);
   4691   1.1  christos 		dns_rdataset_current(rdataset, &rdata);
   4692   1.3  christos 		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
   4693   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4694   1.1  christos 		dns_rdata_reset(&rdata);
   4695   1.3  christos 		optout = ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
   4696   1.1  christos 		if (found != NULL && optout &&
   4697  1.16  christos 		    dns_name_issubdomain(&name, dns_db_origin(db)))
   4698  1.16  christos 		{
   4699   1.1  christos 			dns_rdataset_disassociate(rdataset);
   4700   1.9  christos 			if (dns_rdataset_isassociated(sigrdataset)) {
   4701   1.1  christos 				dns_rdataset_disassociate(sigrdataset);
   4702   1.9  christos 			}
   4703   1.1  christos 			skip++;
   4704   1.1  christos 			dns_name_getlabelsequence(qname, skip, labels - skip,
   4705   1.1  christos 						  &name);
   4706   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   4707   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3),
   4708   1.1  christos 				      "looking for closest provable encloser");
   4709   1.1  christos 			goto again;
   4710   1.1  christos 		}
   4711   1.9  christos 		if (exact) {
   4712   1.1  christos 			ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   4713   1.1  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   4714   1.1  christos 				      "expected a exact match NSEC3, got "
   4715   1.1  christos 				      "a covering record");
   4716   1.9  christos 		}
   4717   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   4718   1.1  christos 		return;
   4719   1.9  christos 	} else if (!exact) {
   4720   1.1  christos 		ns_client_log(client, DNS_LOGCATEGORY_DNSSEC,
   4721   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   4722   1.1  christos 			      "expected covering NSEC3, got an exact match");
   4723   1.9  christos 	}
   4724   1.1  christos 	if (found == qname) {
   4725   1.9  christos 		if (skip != 0U) {
   4726   1.1  christos 			dns_name_getlabelsequence(qname, skip, labels - skip,
   4727   1.1  christos 						  found);
   4728   1.9  christos 		}
   4729   1.9  christos 	} else if (found != NULL) {
   4730   1.8  christos 		dns_name_copynf(&name, found);
   4731   1.9  christos 	}
   4732   1.1  christos 	return;
   4733   1.1  christos }
   4734   1.1  christos 
   4735   1.3  christos static uint32_t
   4736   1.1  christos dns64_ttl(dns_db_t *db, dns_dbversion_t *version) {
   4737   1.1  christos 	dns_dbnode_t *node = NULL;
   4738   1.1  christos 	dns_rdata_soa_t soa;
   4739   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   4740   1.1  christos 	dns_rdataset_t rdataset;
   4741   1.1  christos 	isc_result_t result;
   4742   1.3  christos 	uint32_t ttl = UINT32_MAX;
   4743   1.1  christos 
   4744   1.1  christos 	dns_rdataset_init(&rdataset);
   4745   1.1  christos 
   4746   1.1  christos 	result = dns_db_getoriginnode(db, &node);
   4747   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4748   1.1  christos 		goto cleanup;
   4749   1.9  christos 	}
   4750   1.1  christos 
   4751   1.9  christos 	result = dns_db_findrdataset(db, node, version, dns_rdatatype_soa, 0, 0,
   4752   1.9  christos 				     &rdataset, NULL);
   4753   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4754   1.1  christos 		goto cleanup;
   4755   1.9  christos 	}
   4756   1.1  christos 	result = dns_rdataset_first(&rdataset);
   4757   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4758   1.1  christos 		goto cleanup;
   4759   1.9  christos 	}
   4760   1.1  christos 
   4761   1.1  christos 	dns_rdataset_current(&rdataset, &rdata);
   4762   1.1  christos 	result = dns_rdata_tostruct(&rdata, &soa, NULL);
   4763   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   4764   1.1  christos 	ttl = ISC_MIN(rdataset.ttl, soa.minimum);
   4765   1.1  christos 
   4766   1.1  christos cleanup:
   4767   1.9  christos 	if (dns_rdataset_isassociated(&rdataset)) {
   4768   1.1  christos 		dns_rdataset_disassociate(&rdataset);
   4769   1.9  christos 	}
   4770   1.9  christos 	if (node != NULL) {
   4771   1.1  christos 		dns_db_detachnode(db, &node);
   4772   1.9  christos 	}
   4773   1.1  christos 	return (ttl);
   4774   1.1  christos }
   4775   1.1  christos 
   4776   1.3  christos static bool
   4777   1.1  christos dns64_aaaaok(ns_client_t *client, dns_rdataset_t *rdataset,
   4778   1.9  christos 	     dns_rdataset_t *sigrdataset) {
   4779   1.1  christos 	isc_netaddr_t netaddr;
   4780   1.9  christos 	dns_aclenv_t *env =
   4781   1.9  christos 		ns_interfacemgr_getaclenv(client->manager->interface->mgr);
   4782   1.1  christos 	dns_dns64_t *dns64 = ISC_LIST_HEAD(client->view->dns64);
   4783   1.1  christos 	unsigned int flags = 0;
   4784   1.1  christos 	unsigned int i, count;
   4785   1.3  christos 	bool *aaaaok;
   4786   1.1  christos 
   4787   1.1  christos 	INSIST(client->query.dns64_aaaaok == NULL);
   4788   1.1  christos 	INSIST(client->query.dns64_aaaaoklen == 0);
   4789   1.1  christos 	INSIST(client->query.dns64_aaaa == NULL);
   4790   1.1  christos 	INSIST(client->query.dns64_sigaaaa == NULL);
   4791   1.1  christos 
   4792   1.9  christos 	if (dns64 == NULL) {
   4793   1.3  christos 		return (true);
   4794   1.9  christos 	}
   4795   1.1  christos 
   4796   1.9  christos 	if (RECURSIONOK(client)) {
   4797   1.1  christos 		flags |= DNS_DNS64_RECURSIVE;
   4798   1.9  christos 	}
   4799   1.1  christos 
   4800   1.1  christos 	if (WANTDNSSEC(client) && sigrdataset != NULL &&
   4801   1.1  christos 	    dns_rdataset_isassociated(sigrdataset))
   4802   1.9  christos 	{
   4803   1.1  christos 		flags |= DNS_DNS64_DNSSEC;
   4804   1.9  christos 	}
   4805   1.1  christos 
   4806   1.1  christos 	count = dns_rdataset_count(rdataset);
   4807   1.3  christos 	aaaaok = isc_mem_get(client->mctx, sizeof(bool) * count);
   4808   1.1  christos 
   4809   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   4810   1.9  christos 	if (dns_dns64_aaaaok(dns64, &netaddr, client->signer, env, flags,
   4811   1.9  christos 			     rdataset, aaaaok, count))
   4812   1.1  christos 	{
   4813   1.1  christos 		for (i = 0; i < count; i++) {
   4814   1.1  christos 			if (aaaaok != NULL && !aaaaok[i]) {
   4815   1.1  christos 				SAVE(client->query.dns64_aaaaok, aaaaok);
   4816   1.1  christos 				client->query.dns64_aaaaoklen = count;
   4817   1.1  christos 				break;
   4818   1.1  christos 			}
   4819   1.1  christos 		}
   4820   1.9  christos 		if (aaaaok != NULL) {
   4821   1.9  christos 			isc_mem_put(client->mctx, aaaaok, sizeof(bool) * count);
   4822   1.9  christos 		}
   4823   1.3  christos 		return (true);
   4824   1.1  christos 	}
   4825   1.9  christos 	if (aaaaok != NULL) {
   4826   1.9  christos 		isc_mem_put(client->mctx, aaaaok, sizeof(bool) * count);
   4827   1.9  christos 	}
   4828   1.3  christos 	return (false);
   4829   1.1  christos }
   4830   1.1  christos 
   4831   1.1  christos /*
   4832   1.1  christos  * Look for the name and type in the redirection zone.  If found update
   4833   1.3  christos  * the arguments as appropriate.  Return true if a update was
   4834   1.1  christos  * performed.
   4835   1.1  christos  *
   4836   1.1  christos  * Only perform the update if the client is in the allow query acl and
   4837   1.1  christos  * returning the update would not cause a DNSSEC validation failure.
   4838   1.1  christos  */
   4839   1.1  christos static isc_result_t
   4840   1.1  christos redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
   4841   1.1  christos 	 dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
   4842   1.9  christos 	 dns_rdatatype_t qtype) {
   4843   1.1  christos 	dns_db_t *db = NULL;
   4844   1.1  christos 	dns_dbnode_t *node = NULL;
   4845   1.1  christos 	dns_fixedname_t fixed;
   4846   1.1  christos 	dns_name_t *found;
   4847   1.1  christos 	dns_rdataset_t trdataset;
   4848   1.1  christos 	isc_result_t result;
   4849   1.1  christos 	dns_rdatatype_t type;
   4850   1.1  christos 	dns_clientinfomethods_t cm;
   4851   1.1  christos 	dns_clientinfo_t ci;
   4852   1.1  christos 	ns_dbversion_t *dbversion;
   4853   1.1  christos 
   4854   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect");
   4855   1.1  christos 
   4856   1.9  christos 	if (client->view->redirect == NULL) {
   4857   1.1  christos 		return (ISC_R_NOTFOUND);
   4858   1.9  christos 	}
   4859   1.1  christos 
   4860   1.1  christos 	found = dns_fixedname_initname(&fixed);
   4861   1.1  christos 	dns_rdataset_init(&trdataset);
   4862   1.1  christos 
   4863   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   4864  1.15  christos 	dns_clientinfo_init(&ci, client, &client->ecs, NULL);
   4865   1.1  christos 
   4866   1.1  christos 	if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
   4867   1.9  christos 	{
   4868   1.1  christos 		return (ISC_R_NOTFOUND);
   4869   1.9  christos 	}
   4870   1.1  christos 
   4871   1.1  christos 	if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
   4872   1.9  christos 		if (rdataset->trust == dns_trust_secure) {
   4873   1.1  christos 			return (ISC_R_NOTFOUND);
   4874   1.9  christos 		}
   4875   1.1  christos 		if (rdataset->trust == dns_trust_ultimate &&
   4876   1.1  christos 		    (rdataset->type == dns_rdatatype_nsec ||
   4877   1.1  christos 		     rdataset->type == dns_rdatatype_nsec3))
   4878   1.9  christos 		{
   4879   1.1  christos 			return (ISC_R_NOTFOUND);
   4880   1.9  christos 		}
   4881   1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
   4882   1.1  christos 			for (result = dns_rdataset_first(rdataset);
   4883   1.1  christos 			     result == ISC_R_SUCCESS;
   4884   1.9  christos 			     result = dns_rdataset_next(rdataset))
   4885   1.9  christos 			{
   4886   1.1  christos 				dns_ncache_current(rdataset, found, &trdataset);
   4887   1.1  christos 				type = trdataset.type;
   4888   1.1  christos 				dns_rdataset_disassociate(&trdataset);
   4889   1.1  christos 				if (type == dns_rdatatype_nsec ||
   4890   1.1  christos 				    type == dns_rdatatype_nsec3 ||
   4891   1.1  christos 				    type == dns_rdatatype_rrsig)
   4892   1.9  christos 				{
   4893   1.1  christos 					return (ISC_R_NOTFOUND);
   4894   1.9  christos 				}
   4895   1.1  christos 			}
   4896   1.1  christos 		}
   4897   1.1  christos 	}
   4898   1.1  christos 
   4899   1.9  christos 	result = ns_client_checkaclsilent(
   4900   1.9  christos 		client, NULL, dns_zone_getqueryacl(client->view->redirect),
   4901   1.9  christos 		true);
   4902   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4903   1.1  christos 		return (ISC_R_NOTFOUND);
   4904   1.9  christos 	}
   4905   1.1  christos 
   4906   1.1  christos 	result = dns_zone_getdb(client->view->redirect, &db);
   4907   1.9  christos 	if (result != ISC_R_SUCCESS) {
   4908   1.1  christos 		return (ISC_R_NOTFOUND);
   4909   1.9  christos 	}
   4910   1.1  christos 
   4911   1.3  christos 	dbversion = ns_client_findversion(client, db);
   4912   1.1  christos 	if (dbversion == NULL) {
   4913   1.1  christos 		dns_db_detach(&db);
   4914   1.1  christos 		return (ISC_R_NOTFOUND);
   4915   1.1  christos 	}
   4916   1.1  christos 
   4917   1.1  christos 	/*
   4918   1.1  christos 	 * Lookup the requested data in the redirect zone.
   4919   1.1  christos 	 */
   4920   1.1  christos 	result = dns_db_findext(db, client->query.qname, dbversion->version,
   4921   1.9  christos 				qtype, DNS_DBFIND_NOZONECUT, client->now, &node,
   4922   1.9  christos 				found, &cm, &ci, &trdataset, NULL);
   4923   1.1  christos 	if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
   4924   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   4925   1.1  christos 			dns_rdataset_disassociate(rdataset);
   4926   1.9  christos 		}
   4927   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   4928   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   4929   1.9  christos 		}
   4930   1.1  christos 		goto nxrrset;
   4931   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   4932   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   4933   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   4934   1.9  christos 		}
   4935   1.9  christos 		if (node != NULL) {
   4936   1.1  christos 			dns_db_detachnode(db, &node);
   4937   1.9  christos 		}
   4938   1.1  christos 		dns_db_detach(&db);
   4939   1.1  christos 		return (ISC_R_NOTFOUND);
   4940   1.1  christos 	}
   4941   1.1  christos 
   4942   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect: found data: done");
   4943   1.8  christos 	dns_name_copynf(found, name);
   4944   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   4945   1.1  christos 		dns_rdataset_disassociate(rdataset);
   4946   1.9  christos 	}
   4947   1.1  christos 	if (dns_rdataset_isassociated(&trdataset)) {
   4948   1.1  christos 		dns_rdataset_clone(&trdataset, rdataset);
   4949   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   4950   1.1  christos 	}
   4951   1.9  christos nxrrset:
   4952   1.9  christos 	if (*nodep != NULL) {
   4953   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   4954   1.9  christos 	}
   4955   1.1  christos 	dns_db_detach(dbp);
   4956   1.1  christos 	dns_db_attachnode(db, node, nodep);
   4957   1.1  christos 	dns_db_attach(db, dbp);
   4958   1.1  christos 	dns_db_detachnode(db, &node);
   4959   1.1  christos 	dns_db_detach(&db);
   4960   1.1  christos 	*versionp = dbversion->version;
   4961   1.1  christos 
   4962   1.1  christos 	client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   4963   1.1  christos 				     NS_QUERYATTR_NOADDITIONAL);
   4964   1.1  christos 
   4965   1.1  christos 	return (result);
   4966   1.1  christos }
   4967   1.1  christos 
   4968   1.1  christos static isc_result_t
   4969   1.1  christos redirect2(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset,
   4970   1.1  christos 	  dns_dbnode_t **nodep, dns_db_t **dbp, dns_dbversion_t **versionp,
   4971   1.9  christos 	  dns_rdatatype_t qtype, bool *is_zonep) {
   4972   1.1  christos 	dns_db_t *db = NULL;
   4973   1.1  christos 	dns_dbnode_t *node = NULL;
   4974   1.1  christos 	dns_fixedname_t fixed;
   4975   1.1  christos 	dns_fixedname_t fixedredirect;
   4976   1.1  christos 	dns_name_t *found, *redirectname;
   4977   1.1  christos 	dns_rdataset_t trdataset;
   4978   1.1  christos 	isc_result_t result;
   4979   1.1  christos 	dns_rdatatype_t type;
   4980   1.1  christos 	dns_clientinfomethods_t cm;
   4981   1.1  christos 	dns_clientinfo_t ci;
   4982   1.1  christos 	dns_dbversion_t *version = NULL;
   4983   1.1  christos 	dns_zone_t *zone = NULL;
   4984   1.3  christos 	bool is_zone;
   4985   1.5  christos 	unsigned int labels;
   4986   1.1  christos 	unsigned int options;
   4987   1.1  christos 
   4988   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect2");
   4989   1.1  christos 
   4990   1.5  christos 	if (client->view->redirectzone == NULL) {
   4991   1.1  christos 		return (ISC_R_NOTFOUND);
   4992   1.5  christos 	}
   4993   1.1  christos 
   4994   1.5  christos 	if (dns_name_issubdomain(name, client->view->redirectzone)) {
   4995   1.1  christos 		return (ISC_R_NOTFOUND);
   4996   1.5  christos 	}
   4997   1.1  christos 
   4998   1.1  christos 	found = dns_fixedname_initname(&fixed);
   4999   1.1  christos 	dns_rdataset_init(&trdataset);
   5000   1.1  christos 
   5001   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   5002  1.15  christos 	dns_clientinfo_init(&ci, client, &client->ecs, NULL);
   5003   1.1  christos 
   5004   1.9  christos 	if (WANTDNSSEC(client) && dns_db_iszone(*dbp) && dns_db_issecure(*dbp))
   5005   1.9  christos 	{
   5006   1.1  christos 		return (ISC_R_NOTFOUND);
   5007   1.5  christos 	}
   5008   1.1  christos 
   5009   1.1  christos 	if (WANTDNSSEC(client) && dns_rdataset_isassociated(rdataset)) {
   5010   1.9  christos 		if (rdataset->trust == dns_trust_secure) {
   5011   1.1  christos 			return (ISC_R_NOTFOUND);
   5012   1.9  christos 		}
   5013   1.1  christos 		if (rdataset->trust == dns_trust_ultimate &&
   5014   1.1  christos 		    (rdataset->type == dns_rdatatype_nsec ||
   5015   1.1  christos 		     rdataset->type == dns_rdatatype_nsec3))
   5016   1.9  christos 		{
   5017   1.1  christos 			return (ISC_R_NOTFOUND);
   5018   1.9  christos 		}
   5019   1.1  christos 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
   5020   1.1  christos 			for (result = dns_rdataset_first(rdataset);
   5021   1.1  christos 			     result == ISC_R_SUCCESS;
   5022   1.9  christos 			     result = dns_rdataset_next(rdataset))
   5023   1.9  christos 			{
   5024   1.1  christos 				dns_ncache_current(rdataset, found, &trdataset);
   5025   1.1  christos 				type = trdataset.type;
   5026   1.1  christos 				dns_rdataset_disassociate(&trdataset);
   5027   1.1  christos 				if (type == dns_rdatatype_nsec ||
   5028   1.1  christos 				    type == dns_rdatatype_nsec3 ||
   5029   1.1  christos 				    type == dns_rdatatype_rrsig)
   5030   1.9  christos 				{
   5031   1.1  christos 					return (ISC_R_NOTFOUND);
   5032   1.9  christos 				}
   5033   1.1  christos 			}
   5034   1.1  christos 		}
   5035   1.1  christos 	}
   5036   1.1  christos 
   5037   1.1  christos 	redirectname = dns_fixedname_initname(&fixedredirect);
   5038   1.5  christos 	labels = dns_name_countlabels(client->query.qname);
   5039   1.5  christos 	if (labels > 1U) {
   5040   1.1  christos 		dns_name_t prefix;
   5041   1.1  christos 
   5042   1.1  christos 		dns_name_init(&prefix, NULL);
   5043   1.5  christos 		dns_name_getlabelsequence(client->query.qname, 0, labels - 1,
   5044   1.5  christos 					  &prefix);
   5045   1.1  christos 		result = dns_name_concatenate(&prefix,
   5046   1.1  christos 					      client->view->redirectzone,
   5047   1.1  christos 					      redirectname, NULL);
   5048   1.9  christos 		if (result != ISC_R_SUCCESS) {
   5049   1.1  christos 			return (ISC_R_NOTFOUND);
   5050   1.9  christos 		}
   5051   1.5  christos 	} else {
   5052   1.8  christos 		dns_name_copynf(redirectname, client->view->redirectzone);
   5053   1.5  christos 	}
   5054   1.1  christos 
   5055   1.1  christos 	options = 0;
   5056   1.9  christos 	result = query_getdb(client, redirectname, qtype, options, &zone, &db,
   5057   1.9  christos 			     &version, &is_zone);
   5058   1.5  christos 	if (result != ISC_R_SUCCESS) {
   5059   1.1  christos 		return (ISC_R_NOTFOUND);
   5060   1.5  christos 	}
   5061   1.5  christos 	if (zone != NULL) {
   5062   1.1  christos 		dns_zone_detach(&zone);
   5063   1.5  christos 	}
   5064   1.1  christos 
   5065   1.1  christos 	/*
   5066   1.1  christos 	 * Lookup the requested data in the redirect zone.
   5067   1.1  christos 	 */
   5068   1.9  christos 	result = dns_db_findext(db, redirectname, version, qtype, 0,
   5069   1.9  christos 				client->now, &node, found, &cm, &ci, &trdataset,
   5070   1.9  christos 				NULL);
   5071   1.1  christos 	if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
   5072   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   5073   1.1  christos 			dns_rdataset_disassociate(rdataset);
   5074   1.9  christos 		}
   5075   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5076   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5077   1.9  christos 		}
   5078   1.1  christos 		goto nxrrset;
   5079   1.1  christos 	} else if (result == ISC_R_NOTFOUND || result == DNS_R_DELEGATION) {
   5080   1.1  christos 		/*
   5081   1.1  christos 		 * Cleanup.
   5082   1.1  christos 		 */
   5083   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5084   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5085   1.9  christos 		}
   5086   1.9  christos 		if (node != NULL) {
   5087   1.1  christos 			dns_db_detachnode(db, &node);
   5088   1.9  christos 		}
   5089   1.1  christos 		dns_db_detach(&db);
   5090   1.1  christos 		/*
   5091   1.1  christos 		 * Don't loop forever if the lookup failed last time.
   5092   1.1  christos 		 */
   5093   1.1  christos 		if (!REDIRECT(client)) {
   5094   1.3  christos 			result = ns_query_recurse(client, qtype, redirectname,
   5095   1.3  christos 						  NULL, NULL, true);
   5096   1.1  christos 			if (result == ISC_R_SUCCESS) {
   5097   1.1  christos 				client->query.attributes |=
   5098   1.9  christos 					NS_QUERYATTR_RECURSING;
   5099   1.1  christos 				client->query.attributes |=
   5100   1.9  christos 					NS_QUERYATTR_REDIRECT;
   5101   1.1  christos 				return (DNS_R_CONTINUE);
   5102   1.1  christos 			}
   5103   1.1  christos 		}
   5104   1.1  christos 		return (ISC_R_NOTFOUND);
   5105   1.1  christos 	} else if (result != ISC_R_SUCCESS) {
   5106   1.9  christos 		if (dns_rdataset_isassociated(&trdataset)) {
   5107   1.1  christos 			dns_rdataset_disassociate(&trdataset);
   5108   1.9  christos 		}
   5109   1.9  christos 		if (node != NULL) {
   5110   1.1  christos 			dns_db_detachnode(db, &node);
   5111   1.9  christos 		}
   5112   1.1  christos 		dns_db_detach(&db);
   5113   1.1  christos 		return (ISC_R_NOTFOUND);
   5114   1.1  christos 	}
   5115   1.1  christos 
   5116   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "redirect2: found data: done");
   5117   1.1  christos 	/*
   5118   1.1  christos 	 * Adjust the found name to not include the redirectzone suffix.
   5119   1.1  christos 	 */
   5120   1.1  christos 	dns_name_split(found, dns_name_countlabels(client->view->redirectzone),
   5121   1.1  christos 		       found, NULL);
   5122   1.1  christos 	/*
   5123   1.1  christos 	 * Make the name absolute.
   5124   1.1  christos 	 */
   5125   1.1  christos 	result = dns_name_concatenate(found, dns_rootname, found, NULL);
   5126   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   5127   1.1  christos 
   5128   1.8  christos 	dns_name_copynf(found, name);
   5129   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   5130   1.1  christos 		dns_rdataset_disassociate(rdataset);
   5131   1.9  christos 	}
   5132   1.1  christos 	if (dns_rdataset_isassociated(&trdataset)) {
   5133   1.1  christos 		dns_rdataset_clone(&trdataset, rdataset);
   5134   1.1  christos 		dns_rdataset_disassociate(&trdataset);
   5135   1.1  christos 	}
   5136   1.9  christos nxrrset:
   5137   1.9  christos 	if (*nodep != NULL) {
   5138   1.1  christos 		dns_db_detachnode(*dbp, nodep);
   5139   1.9  christos 	}
   5140   1.1  christos 	dns_db_detach(dbp);
   5141   1.1  christos 	dns_db_attachnode(db, node, nodep);
   5142   1.1  christos 	dns_db_attach(db, dbp);
   5143   1.1  christos 	dns_db_detachnode(db, &node);
   5144   1.1  christos 	dns_db_detach(&db);
   5145   1.1  christos 	*is_zonep = is_zone;
   5146   1.1  christos 	*versionp = version;
   5147   1.1  christos 
   5148   1.1  christos 	client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   5149   1.1  christos 				     NS_QUERYATTR_NOADDITIONAL);
   5150   1.1  christos 
   5151   1.1  christos 	return (result);
   5152   1.1  christos }
   5153   1.1  christos 
   5154   1.1  christos /*%
   5155   1.1  christos  * Initialize query context 'qctx'. Run by query_setup() when
   5156   1.1  christos  * first handling a client query, and by query_resume() when
   5157   1.1  christos  * returning from recursion.
   5158   1.3  christos  *
   5159   1.3  christos  * Whenever this function is called, qctx_destroy() must be called
   5160   1.3  christos  * when leaving the scope or freeing the qctx.
   5161   1.1  christos  */
   5162   1.1  christos static void
   5163  1.11  christos qctx_init(ns_client_t *client, dns_fetchevent_t **eventp, dns_rdatatype_t qtype,
   5164   1.9  christos 	  query_ctx_t *qctx) {
   5165   1.1  christos 	REQUIRE(qctx != NULL);
   5166   1.1  christos 	REQUIRE(client != NULL);
   5167   1.1  christos 
   5168   1.3  christos 	memset(qctx, 0, sizeof(*qctx));
   5169   1.3  christos 
   5170   1.1  christos 	/* Set this first so CCTRACE will work */
   5171   1.1  christos 	qctx->client = client;
   5172   1.9  christos 
   5173   1.3  christos 	dns_view_attach(client->view, &qctx->view);
   5174   1.1  christos 
   5175   1.3  christos 	CCTRACE(ISC_LOG_DEBUG(3), "qctx_init");
   5176   1.1  christos 
   5177  1.11  christos 	if (eventp != NULL) {
   5178  1.11  christos 		qctx->event = *eventp;
   5179  1.11  christos 		*eventp = NULL;
   5180  1.11  christos 	} else {
   5181  1.11  christos 		qctx->event = NULL;
   5182  1.11  christos 	}
   5183   1.1  christos 	qctx->qtype = qctx->type = qtype;
   5184   1.1  christos 	qctx->result = ISC_R_SUCCESS;
   5185   1.3  christos 	qctx->findcoveringnsec = qctx->view->synthfromdnssec;
   5186   1.3  christos 
   5187  1.16  christos 	/*
   5188  1.16  christos 	 * If it's an RRSIG or SIG query, we'll iterate the node.
   5189  1.16  christos 	 */
   5190  1.16  christos 	if (qctx->qtype == dns_rdatatype_rrsig ||
   5191  1.16  christos 	    qctx->qtype == dns_rdatatype_sig)
   5192  1.16  christos 	{
   5193  1.16  christos 		qctx->type = dns_rdatatype_any;
   5194  1.16  christos 	}
   5195  1.16  christos 
   5196   1.3  christos 	CALL_HOOK_NORETURN(NS_QUERY_QCTX_INITIALIZED, qctx);
   5197   1.1  christos }
   5198   1.1  christos 
   5199  1.11  christos /*
   5200  1.11  christos  * Make 'dst' and exact copy of 'src', with exception of the
   5201  1.11  christos  * option field, which is reset to zero.
   5202  1.11  christos  * This function also attaches dst's view and db to the src's
   5203  1.11  christos  * view and cachedb.
   5204  1.11  christos  */
   5205  1.11  christos static void
   5206  1.11  christos qctx_copy(const query_ctx_t *qctx, query_ctx_t *dst) {
   5207  1.11  christos 	REQUIRE(qctx != NULL);
   5208  1.11  christos 	REQUIRE(dst != NULL);
   5209  1.11  christos 
   5210  1.11  christos 	memmove(dst, qctx, sizeof(*dst));
   5211  1.11  christos 	dst->view = NULL;
   5212  1.11  christos 	dst->db = NULL;
   5213  1.11  christos 	dst->options = 0;
   5214  1.11  christos 	dns_view_attach(qctx->view, &dst->view);
   5215  1.11  christos 	dns_db_attach(qctx->view->cachedb, &dst->db);
   5216  1.11  christos 	CCTRACE(ISC_LOG_DEBUG(3), "qctx_copy");
   5217  1.11  christos }
   5218  1.11  christos 
   5219   1.1  christos /*%
   5220   1.1  christos  * Clean up and disassociate the rdataset and node pointers in qctx.
   5221   1.1  christos  */
   5222   1.1  christos static void
   5223   1.1  christos qctx_clean(query_ctx_t *qctx) {
   5224   1.9  christos 	if (qctx->rdataset != NULL && dns_rdataset_isassociated(qctx->rdataset))
   5225   1.1  christos 	{
   5226   1.1  christos 		dns_rdataset_disassociate(qctx->rdataset);
   5227   1.1  christos 	}
   5228   1.1  christos 	if (qctx->sigrdataset != NULL &&
   5229  1.16  christos 	    dns_rdataset_isassociated(qctx->sigrdataset))
   5230  1.16  christos 	{
   5231   1.1  christos 		dns_rdataset_disassociate(qctx->sigrdataset);
   5232   1.1  christos 	}
   5233   1.1  christos 	if (qctx->db != NULL && qctx->node != NULL) {
   5234   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   5235   1.1  christos 	}
   5236   1.1  christos }
   5237   1.1  christos 
   5238   1.1  christos /*%
   5239   1.1  christos  * Free any allocated memory associated with qctx.
   5240   1.1  christos  */
   5241   1.1  christos static void
   5242   1.1  christos qctx_freedata(query_ctx_t *qctx) {
   5243   1.1  christos 	if (qctx->rdataset != NULL) {
   5244   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   5245   1.1  christos 	}
   5246   1.1  christos 
   5247   1.1  christos 	if (qctx->sigrdataset != NULL) {
   5248   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   5249   1.1  christos 	}
   5250   1.1  christos 
   5251   1.1  christos 	if (qctx->fname != NULL) {
   5252   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   5253   1.1  christos 	}
   5254   1.1  christos 
   5255   1.1  christos 	if (qctx->db != NULL) {
   5256   1.1  christos 		INSIST(qctx->node == NULL);
   5257   1.1  christos 		dns_db_detach(&qctx->db);
   5258   1.1  christos 	}
   5259   1.1  christos 
   5260   1.1  christos 	if (qctx->zone != NULL) {
   5261   1.1  christos 		dns_zone_detach(&qctx->zone);
   5262   1.1  christos 	}
   5263   1.1  christos 
   5264   1.1  christos 	if (qctx->zdb != NULL) {
   5265   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->zsigrdataset);
   5266   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->zrdataset);
   5267   1.3  christos 		ns_client_releasename(qctx->client, &qctx->zfname);
   5268   1.3  christos 		dns_db_detachnode(qctx->zdb, &qctx->znode);
   5269   1.1  christos 		dns_db_detach(&qctx->zdb);
   5270   1.1  christos 	}
   5271   1.1  christos 
   5272  1.13  christos 	if (qctx->event != NULL && !qctx->client->nodetach) {
   5273   1.9  christos 		free_devent(qctx->client, ISC_EVENT_PTR(&qctx->event),
   5274   1.9  christos 			    &qctx->event);
   5275   1.1  christos 	}
   5276   1.1  christos }
   5277   1.1  christos 
   5278   1.3  christos static void
   5279   1.3  christos qctx_destroy(query_ctx_t *qctx) {
   5280   1.3  christos 	CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx);
   5281   1.3  christos 
   5282   1.3  christos 	dns_view_detach(&qctx->view);
   5283   1.3  christos }
   5284   1.3  christos 
   5285   1.1  christos /*%
   5286   1.1  christos  * Log detailed information about the query immediately after
   5287   1.1  christos  * the client request or a return from recursion.
   5288   1.1  christos  */
   5289   1.1  christos static void
   5290   1.1  christos query_trace(query_ctx_t *qctx) {
   5291   1.1  christos #ifdef WANT_QUERYTRACE
   5292   1.6  christos 	char mbuf[2 * DNS_NAME_FORMATSIZE];
   5293   1.1  christos 	char qbuf[DNS_NAME_FORMATSIZE];
   5294   1.1  christos 
   5295   1.9  christos 	if (qctx->client->query.origqname != NULL) {
   5296   1.1  christos 		dns_name_format(qctx->client->query.origqname, qbuf,
   5297   1.1  christos 				sizeof(qbuf));
   5298   1.9  christos 	} else {
   5299   1.1  christos 		snprintf(qbuf, sizeof(qbuf), "<unset>");
   5300   1.9  christos 	}
   5301   1.1  christos 
   5302   1.1  christos 	snprintf(mbuf, sizeof(mbuf) - 1,
   5303   1.1  christos 		 "client attr:0x%x, query attr:0x%X, restarts:%u, "
   5304   1.1  christos 		 "origqname:%s, timer:%d, authdb:%d, referral:%d",
   5305   1.9  christos 		 qctx->client->attributes, qctx->client->query.attributes,
   5306   1.1  christos 		 qctx->client->query.restarts, qbuf,
   5307   1.9  christos 		 (int)qctx->client->query.timerset,
   5308   1.9  christos 		 (int)qctx->client->query.authdbset,
   5309   1.9  christos 		 (int)qctx->client->query.isreferral);
   5310   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   5311   1.9  christos #else  /* ifdef WANT_QUERYTRACE */
   5312   1.1  christos 	UNUSED(qctx);
   5313   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   5314   1.1  christos }
   5315   1.1  christos 
   5316   1.1  christos /*
   5317   1.1  christos  * Set up query processing for the current query of 'client'.
   5318   1.1  christos  * Calls qctx_init() to initialize a query context, checks
   5319   1.1  christos  * the SERVFAIL cache, then hands off processing to ns__query_start().
   5320   1.1  christos  *
   5321   1.1  christos  * This is called only from ns_query_start(), to begin a query
   5322   1.1  christos  * for the first time.  Restarting an existing query (for
   5323   1.1  christos  * instance, to handle CNAME lookups), is done by calling
   5324   1.1  christos  * ns__query_start() again with the same query context. Resuming from
   5325   1.1  christos  * recursion is handled by query_resume().
   5326   1.1  christos  */
   5327   1.1  christos static isc_result_t
   5328   1.1  christos query_setup(ns_client_t *client, dns_rdatatype_t qtype) {
   5329   1.1  christos 	isc_result_t result;
   5330   1.1  christos 	query_ctx_t qctx;
   5331   1.1  christos 
   5332   1.1  christos 	qctx_init(client, NULL, qtype, &qctx);
   5333   1.1  christos 	query_trace(&qctx);
   5334   1.1  christos 
   5335   1.3  christos 	CALL_HOOK(NS_QUERY_SETUP, &qctx);
   5336   1.3  christos 
   5337   1.1  christos 	/*
   5338   1.1  christos 	 * Check SERVFAIL cache
   5339   1.1  christos 	 */
   5340   1.1  christos 	result = ns__query_sfcache(&qctx);
   5341   1.1  christos 	if (result != ISC_R_COMPLETE) {
   5342   1.3  christos 		qctx_destroy(&qctx);
   5343   1.1  christos 		return (result);
   5344   1.1  christos 	}
   5345   1.1  christos 
   5346   1.3  christos 	result = ns__query_start(&qctx);
   5347   1.3  christos 
   5348   1.9  christos cleanup:
   5349   1.3  christos 	qctx_destroy(&qctx);
   5350   1.3  christos 	return (result);
   5351   1.1  christos }
   5352   1.1  christos 
   5353   1.3  christos static bool
   5354   1.1  christos get_root_key_sentinel_id(query_ctx_t *qctx, const char *ndata) {
   5355   1.1  christos 	unsigned int v = 0;
   5356   1.1  christos 	int i;
   5357   1.1  christos 
   5358   1.1  christos 	for (i = 0; i < 5; i++) {
   5359  1.14  christos 		if (!isdigit((unsigned char)ndata[i])) {
   5360   1.3  christos 			return (false);
   5361   1.1  christos 		}
   5362   1.1  christos 		v *= 10;
   5363   1.1  christos 		v += ndata[i] - '0';
   5364   1.1  christos 	}
   5365   1.1  christos 	if (v > 65535U) {
   5366   1.3  christos 		return (false);
   5367   1.1  christos 	}
   5368   1.1  christos 	qctx->client->query.root_key_sentinel_keyid = v;
   5369   1.3  christos 	return (true);
   5370   1.1  christos }
   5371   1.1  christos 
   5372   1.1  christos /*%
   5373   1.1  christos  * Find out if the query is for a root key sentinel and if so, record the type
   5374   1.1  christos  * of root key sentinel query and the key id that is being checked for.
   5375   1.1  christos  *
   5376   1.1  christos  * The code is assuming a zero padded decimal field of width 5.
   5377   1.1  christos  */
   5378   1.1  christos static void
   5379   1.1  christos root_key_sentinel_detect(query_ctx_t *qctx) {
   5380   1.1  christos 	const char *ndata = (const char *)qctx->client->query.qname->ndata;
   5381   1.1  christos 
   5382   1.1  christos 	if (qctx->client->query.qname->length > 30 && ndata[0] == 29 &&
   5383   1.1  christos 	    strncasecmp(ndata + 1, "root-key-sentinel-is-ta-", 24) == 0)
   5384   1.1  christos 	{
   5385   1.1  christos 		if (!get_root_key_sentinel_id(qctx, ndata + 25)) {
   5386   1.1  christos 			return;
   5387   1.1  christos 		}
   5388   1.3  christos 		qctx->client->query.root_key_sentinel_is_ta = true;
   5389   1.1  christos 		/*
   5390   1.9  christos 		 * Simplify processing by disabling aggressive
   5391   1.1  christos 		 * negative caching.
   5392   1.1  christos 		 */
   5393   1.3  christos 		qctx->findcoveringnsec = false;
   5394   1.1  christos 		ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
   5395   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5396   1.1  christos 			      "root-key-sentinel-is-ta query label found");
   5397   1.1  christos 	} else if (qctx->client->query.qname->length > 31 && ndata[0] == 30 &&
   5398   1.1  christos 		   strncasecmp(ndata + 1, "root-key-sentinel-not-ta-", 25) == 0)
   5399   1.1  christos 	{
   5400   1.1  christos 		if (!get_root_key_sentinel_id(qctx, ndata + 26)) {
   5401   1.1  christos 			return;
   5402   1.1  christos 		}
   5403   1.3  christos 		qctx->client->query.root_key_sentinel_not_ta = true;
   5404   1.1  christos 		/*
   5405   1.9  christos 		 * Simplify processing by disabling aggressive
   5406   1.1  christos 		 * negative caching.
   5407   1.1  christos 		 */
   5408   1.3  christos 		qctx->findcoveringnsec = false;
   5409   1.1  christos 		ns_client_log(qctx->client, NS_LOGCATEGORY_TAT,
   5410   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5411   1.1  christos 			      "root-key-sentinel-not-ta query label found");
   5412   1.1  christos 	}
   5413   1.1  christos }
   5414   1.1  christos 
   5415   1.1  christos /*%
   5416   1.1  christos  * Starting point for a client query or a chaining query.
   5417   1.1  christos  *
   5418   1.1  christos  * Called first by query_setup(), and then again as often as needed to
   5419   1.1  christos  * follow a CNAME chain.  Determines which authoritative database to
   5420   1.1  christos  * search, then hands off processing to query_lookup().
   5421   1.1  christos  */
   5422   1.1  christos isc_result_t
   5423   1.1  christos ns__query_start(query_ctx_t *qctx) {
   5424   1.1  christos 	isc_result_t result;
   5425   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "ns__query_start");
   5426   1.3  christos 	qctx->want_restart = false;
   5427   1.3  christos 	qctx->authoritative = false;
   5428   1.1  christos 	qctx->version = NULL;
   5429   1.1  christos 	qctx->zversion = NULL;
   5430   1.3  christos 	qctx->need_wildcardproof = false;
   5431   1.3  christos 	qctx->rpz = false;
   5432   1.3  christos 
   5433   1.3  christos 	CALL_HOOK(NS_QUERY_START_BEGIN, qctx);
   5434   1.3  christos 
   5435   1.3  christos 	/*
   5436   1.3  christos 	 * If we require a server cookie then send back BADCOOKIE
   5437   1.3  christos 	 * before we have done too much work.
   5438   1.3  christos 	 */
   5439   1.3  christos 	if (!TCP(qctx->client) && qctx->view->requireservercookie &&
   5440   1.3  christos 	    WANTCOOKIE(qctx->client) && !HAVECOOKIE(qctx->client))
   5441   1.3  christos 	{
   5442   1.3  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
   5443   1.3  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
   5444   1.3  christos 		qctx->client->message->rcode = dns_rcode_badcookie;
   5445   1.3  christos 		return (ns_query_done(qctx));
   5446   1.3  christos 	}
   5447   1.1  christos 
   5448   1.3  christos 	if (qctx->view->checknames &&
   5449   1.1  christos 	    !dns_rdata_checkowner(qctx->client->query.qname,
   5450   1.9  christos 				  qctx->client->message->rdclass, qctx->qtype,
   5451   1.9  christos 				  false))
   5452   1.1  christos 	{
   5453   1.1  christos 		char namebuf[DNS_NAME_FORMATSIZE];
   5454   1.3  christos 		char typebuf[DNS_RDATATYPE_FORMATSIZE];
   5455   1.3  christos 		char classbuf[DNS_RDATACLASS_FORMATSIZE];
   5456   1.1  christos 
   5457   1.9  christos 		dns_name_format(qctx->client->query.qname, namebuf,
   5458   1.9  christos 				sizeof(namebuf));
   5459   1.3  christos 		dns_rdatatype_format(qctx->qtype, typebuf, sizeof(typebuf));
   5460   1.9  christos 		dns_rdataclass_format(qctx->client->message->rdclass, classbuf,
   5461   1.9  christos 				      sizeof(classbuf));
   5462   1.1  christos 		ns_client_log(qctx->client, DNS_LOGCATEGORY_SECURITY,
   5463   1.1  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_ERROR,
   5464   1.9  christos 			      "check-names failure %s/%s/%s", namebuf, typebuf,
   5465   1.9  christos 			      classbuf);
   5466   1.1  christos 		QUERY_ERROR(qctx, DNS_R_REFUSED);
   5467   1.3  christos 		return (ns_query_done(qctx));
   5468   1.1  christos 	}
   5469   1.1  christos 
   5470   1.1  christos 	/*
   5471   1.1  christos 	 * Setup for root key sentinel processing.
   5472   1.1  christos 	 */
   5473   1.3  christos 	if (qctx->view->root_key_sentinel &&
   5474   1.1  christos 	    qctx->client->query.restarts == 0 &&
   5475   1.1  christos 	    (qctx->qtype == dns_rdatatype_a ||
   5476   1.1  christos 	     qctx->qtype == dns_rdatatype_aaaa) &&
   5477   1.1  christos 	    (qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)
   5478   1.1  christos 	{
   5479   1.9  christos 		root_key_sentinel_detect(qctx);
   5480   1.1  christos 	}
   5481   1.1  christos 
   5482   1.1  christos 	/*
   5483   1.1  christos 	 * First we must find the right database.
   5484   1.1  christos 	 */
   5485   1.1  christos 	qctx->options &= DNS_GETDB_NOLOG; /* Preserve DNS_GETDB_NOLOG. */
   5486   1.1  christos 	if (dns_rdatatype_atparent(qctx->qtype) &&
   5487   1.1  christos 	    !dns_name_equal(qctx->client->query.qname, dns_rootname))
   5488   1.1  christos 	{
   5489   1.1  christos 		/*
   5490   1.1  christos 		 * If authoritative data for this QTYPE is supposed to live in
   5491   1.1  christos 		 * the parent zone, do not look for an exact match for QNAME,
   5492   1.1  christos 		 * but rather for its containing zone (unless the QNAME is
   5493   1.1  christos 		 * root).
   5494   1.1  christos 		 */
   5495   1.1  christos 		qctx->options |= DNS_GETDB_NOEXACT;
   5496   1.1  christos 	}
   5497   1.1  christos 
   5498   1.1  christos 	result = query_getdb(qctx->client, qctx->client->query.qname,
   5499   1.9  christos 			     qctx->qtype, qctx->options, &qctx->zone, &qctx->db,
   5500   1.9  christos 			     &qctx->version, &qctx->is_zone);
   5501   1.1  christos 	if (ISC_UNLIKELY((result != ISC_R_SUCCESS || !qctx->is_zone) &&
   5502   1.1  christos 			 qctx->qtype == dns_rdatatype_ds &&
   5503   1.1  christos 			 !RECURSIONOK(qctx->client) &&
   5504   1.1  christos 			 (qctx->options & DNS_GETDB_NOEXACT) != 0))
   5505   1.1  christos 	{
   5506   1.1  christos 		/*
   5507   1.1  christos 		 * This is a non-recursive QTYPE=DS query with QNAME whose
   5508   1.1  christos 		 * parent we are not authoritative for.  Check whether we are
   5509   1.1  christos 		 * authoritative for QNAME, because if so, we need to send a
   5510   1.1  christos 		 * "no data" response as required by RFC 4035, section 3.1.4.1.
   5511   1.1  christos 		 */
   5512   1.1  christos 		dns_db_t *tdb = NULL;
   5513   1.1  christos 		dns_zone_t *tzone = NULL;
   5514   1.1  christos 		dns_dbversion_t *tversion = NULL;
   5515   1.1  christos 		isc_result_t tresult;
   5516   1.1  christos 
   5517   1.9  christos 		tresult = query_getzonedb(
   5518   1.9  christos 			qctx->client, qctx->client->query.qname, qctx->qtype,
   5519   1.9  christos 			DNS_GETDB_PARTIAL, &tzone, &tdb, &tversion);
   5520   1.1  christos 		if (tresult == ISC_R_SUCCESS) {
   5521   1.1  christos 			/*
   5522   1.1  christos 			 * We are authoritative for QNAME.  Attach the relevant
   5523   1.1  christos 			 * zone to query context, set result to ISC_R_SUCCESS.
   5524   1.1  christos 			 */
   5525   1.1  christos 			qctx->options &= ~DNS_GETDB_NOEXACT;
   5526   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   5527   1.1  christos 			if (qctx->db != NULL) {
   5528   1.1  christos 				dns_db_detach(&qctx->db);
   5529   1.1  christos 			}
   5530   1.1  christos 			if (qctx->zone != NULL) {
   5531   1.1  christos 				dns_zone_detach(&qctx->zone);
   5532   1.1  christos 			}
   5533   1.1  christos 			qctx->version = NULL;
   5534   1.1  christos 			RESTORE(qctx->version, tversion);
   5535   1.1  christos 			RESTORE(qctx->db, tdb);
   5536   1.1  christos 			RESTORE(qctx->zone, tzone);
   5537   1.3  christos 			qctx->is_zone = true;
   5538   1.1  christos 			result = ISC_R_SUCCESS;
   5539   1.1  christos 		} else {
   5540   1.1  christos 			/*
   5541   1.1  christos 			 * We are not authoritative for QNAME.  Clean up and
   5542   1.1  christos 			 * leave result as it was.
   5543   1.1  christos 			 */
   5544   1.1  christos 			if (tdb != NULL) {
   5545   1.1  christos 				dns_db_detach(&tdb);
   5546   1.1  christos 			}
   5547   1.1  christos 			if (tzone != NULL) {
   5548   1.1  christos 				dns_zone_detach(&tzone);
   5549   1.1  christos 			}
   5550   1.1  christos 		}
   5551   1.1  christos 	}
   5552   1.1  christos 	/*
   5553   1.1  christos 	 * If we did not find a database from which we can answer the query,
   5554   1.1  christos 	 * respond with either REFUSED or SERVFAIL, depending on what the
   5555   1.1  christos 	 * result of query_getdb() was.
   5556   1.1  christos 	 */
   5557   1.1  christos 	if (result != ISC_R_SUCCESS) {
   5558   1.1  christos 		if (result == DNS_R_REFUSED) {
   5559   1.1  christos 			if (WANTRECURSION(qctx->client)) {
   5560   1.1  christos 				inc_stats(qctx->client,
   5561   1.1  christos 					  ns_statscounter_recurserej);
   5562   1.1  christos 			} else {
   5563   1.1  christos 				inc_stats(qctx->client,
   5564   1.1  christos 					  ns_statscounter_authrej);
   5565   1.1  christos 			}
   5566   1.1  christos 			if (!PARTIALANSWER(qctx->client)) {
   5567   1.1  christos 				QUERY_ERROR(qctx, DNS_R_REFUSED);
   5568   1.1  christos 			}
   5569   1.1  christos 		} else {
   5570   1.9  christos 			CCTRACE(ISC_LOG_ERROR, "ns__query_start: query_getdb "
   5571   1.9  christos 					       "failed");
   5572   1.3  christos 			QUERY_ERROR(qctx, result);
   5573   1.1  christos 		}
   5574   1.3  christos 		return (ns_query_done(qctx));
   5575   1.1  christos 	}
   5576   1.1  christos 
   5577   1.1  christos 	/*
   5578   1.1  christos 	 * We found a database from which we can answer the query.  Update
   5579   1.1  christos 	 * relevant query context flags if the answer is to be prepared using
   5580   1.1  christos 	 * authoritative data.
   5581   1.1  christos 	 */
   5582   1.3  christos 	qctx->is_staticstub_zone = false;
   5583   1.1  christos 	if (qctx->is_zone) {
   5584   1.3  christos 		qctx->authoritative = true;
   5585   1.3  christos 		if (qctx->zone != NULL) {
   5586   1.3  christos 			if (dns_zone_gettype(qctx->zone) == dns_zone_mirror) {
   5587   1.3  christos 				qctx->authoritative = false;
   5588   1.3  christos 			}
   5589   1.9  christos 			if (dns_zone_gettype(qctx->zone) == dns_zone_staticstub)
   5590   1.3  christos 			{
   5591   1.3  christos 				qctx->is_staticstub_zone = true;
   5592   1.3  christos 			}
   5593   1.1  christos 		}
   5594   1.1  christos 	}
   5595   1.1  christos 
   5596   1.1  christos 	/*
   5597   1.1  christos 	 * Attach to the database which will be used to prepare the answer.
   5598   1.1  christos 	 * Update query statistics.
   5599   1.1  christos 	 */
   5600   1.1  christos 	if (qctx->event == NULL && qctx->client->query.restarts == 0) {
   5601   1.1  christos 		if (qctx->is_zone) {
   5602   1.1  christos 			if (qctx->zone != NULL) {
   5603   1.1  christos 				/*
   5604   1.1  christos 				 * if is_zone = true, zone = NULL then this is
   5605   1.1  christos 				 * a DLZ zone.  Don't attempt to attach zone.
   5606   1.1  christos 				 */
   5607   1.1  christos 				dns_zone_attach(qctx->zone,
   5608   1.1  christos 						&qctx->client->query.authzone);
   5609   1.1  christos 			}
   5610   1.1  christos 			dns_db_attach(qctx->db, &qctx->client->query.authdb);
   5611   1.1  christos 		}
   5612   1.3  christos 		qctx->client->query.authdbset = true;
   5613   1.1  christos 
   5614   1.1  christos 		/* Track TCP vs UDP stats per zone */
   5615   1.1  christos 		if (TCP(qctx->client)) {
   5616   1.1  christos 			inc_stats(qctx->client, ns_statscounter_tcp);
   5617   1.1  christos 		} else {
   5618   1.1  christos 			inc_stats(qctx->client, ns_statscounter_udp);
   5619   1.1  christos 		}
   5620   1.1  christos 	}
   5621   1.1  christos 
   5622  1.11  christos 	if (!qctx->is_zone && (qctx->view->staleanswerclienttimeout == 0) &&
   5623  1.11  christos 	    dns_view_staleanswerenabled(qctx->view))
   5624  1.11  christos 	{
   5625  1.11  christos 		/*
   5626  1.11  christos 		 * If stale answers are enabled and
   5627  1.11  christos 		 * stale-answer-client-timeout is zero, then we can promptly
   5628  1.11  christos 		 * answer with a stale RRset if one is available in cache.
   5629  1.11  christos 		 */
   5630  1.11  christos 		qctx->options |= DNS_GETDB_STALEFIRST;
   5631  1.11  christos 	}
   5632  1.11  christos 
   5633  1.11  christos 	result = query_lookup(qctx);
   5634  1.11  christos 
   5635  1.11  christos 	/*
   5636  1.11  christos 	 * Clear "look-also-for-stale-data" flag.
   5637  1.11  christos 	 * If a fetch is created to resolve this query, then,
   5638  1.11  christos 	 * when it completes, this option is not expected to be set.
   5639  1.11  christos 	 */
   5640  1.11  christos 	qctx->options &= ~DNS_GETDB_STALEFIRST;
   5641   1.3  christos 
   5642   1.9  christos cleanup:
   5643   1.3  christos 	return (result);
   5644   1.1  christos }
   5645   1.1  christos 
   5646  1.11  christos /*
   5647  1.11  christos  * Allocate buffers in 'qctx' used to store query results.
   5648  1.11  christos  *
   5649  1.11  christos  * 'buffer' must be a pointer to an object whose lifetime
   5650  1.11  christos  * doesn't expire while 'qctx' is in use.
   5651  1.11  christos  */
   5652  1.11  christos static isc_result_t
   5653  1.11  christos qctx_prepare_buffers(query_ctx_t *qctx, isc_buffer_t *buffer) {
   5654  1.11  christos 	REQUIRE(qctx != NULL);
   5655  1.11  christos 	REQUIRE(qctx->client != NULL);
   5656  1.11  christos 	REQUIRE(buffer != NULL);
   5657  1.11  christos 
   5658  1.11  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   5659  1.11  christos 	if (ISC_UNLIKELY(qctx->dbuf == NULL)) {
   5660  1.11  christos 		CCTRACE(ISC_LOG_ERROR,
   5661  1.11  christos 			"qctx_prepare_buffers: ns_client_getnamebuf "
   5662  1.11  christos 			"failed");
   5663  1.11  christos 		return (ISC_R_NOMEMORY);
   5664  1.11  christos 	}
   5665  1.11  christos 
   5666  1.11  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, buffer);
   5667  1.11  christos 	if (ISC_UNLIKELY(qctx->fname == NULL)) {
   5668  1.11  christos 		CCTRACE(ISC_LOG_ERROR,
   5669  1.11  christos 			"qctx_prepare_buffers: ns_client_newname failed");
   5670  1.11  christos 
   5671  1.11  christos 		return (ISC_R_NOMEMORY);
   5672  1.11  christos 	}
   5673  1.11  christos 
   5674  1.11  christos 	qctx->rdataset = ns_client_newrdataset(qctx->client);
   5675  1.11  christos 	if (ISC_UNLIKELY(qctx->rdataset == NULL)) {
   5676  1.11  christos 		CCTRACE(ISC_LOG_ERROR,
   5677  1.11  christos 			"qctx_prepare_buffers: ns_client_newrdataset failed");
   5678  1.11  christos 		goto error;
   5679  1.11  christos 	}
   5680  1.11  christos 
   5681  1.11  christos 	if ((WANTDNSSEC(qctx->client) || qctx->findcoveringnsec) &&
   5682  1.11  christos 	    (!qctx->is_zone || dns_db_issecure(qctx->db)))
   5683  1.11  christos 	{
   5684  1.11  christos 		qctx->sigrdataset = ns_client_newrdataset(qctx->client);
   5685  1.11  christos 		if (qctx->sigrdataset == NULL) {
   5686  1.11  christos 			CCTRACE(ISC_LOG_ERROR,
   5687  1.11  christos 				"qctx_prepare_buffers: "
   5688  1.11  christos 				"ns_client_newrdataset failed (2)");
   5689  1.11  christos 			goto error;
   5690  1.11  christos 		}
   5691  1.11  christos 	}
   5692  1.11  christos 
   5693  1.11  christos 	return (ISC_R_SUCCESS);
   5694  1.11  christos 
   5695  1.11  christos error:
   5696  1.11  christos 	if (qctx->fname != NULL) {
   5697  1.11  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   5698  1.11  christos 	}
   5699  1.11  christos 	if (qctx->rdataset != NULL) {
   5700  1.11  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   5701  1.11  christos 	}
   5702  1.11  christos 
   5703  1.11  christos 	return (ISC_R_NOMEMORY);
   5704  1.11  christos }
   5705  1.11  christos 
   5706  1.11  christos /*
   5707  1.11  christos  * Setup a new query context for resolving a query.
   5708  1.11  christos  *
   5709  1.11  christos  * This function is only called if both these conditions are met:
   5710  1.11  christos  *    1. BIND is configured with stale-answer-client-timeout 0.
   5711  1.11  christos  *    2. A stale RRset is found in cache during initial query
   5712  1.11  christos  *       database lookup.
   5713  1.11  christos  *
   5714  1.11  christos  * We continue with this function for refreshing/resolving an RRset
   5715  1.11  christos  * after answering a client with stale data.
   5716  1.11  christos  */
   5717  1.11  christos static void
   5718  1.11  christos query_refresh_rrset(query_ctx_t *orig_qctx) {
   5719  1.11  christos 	isc_buffer_t buffer;
   5720  1.11  christos 	query_ctx_t qctx;
   5721  1.11  christos 
   5722  1.11  christos 	REQUIRE(orig_qctx != NULL);
   5723  1.11  christos 	REQUIRE(orig_qctx->client != NULL);
   5724  1.11  christos 
   5725  1.11  christos 	qctx_copy(orig_qctx, &qctx);
   5726  1.13  christos 	qctx.client->query.dboptions &= ~(DNS_DBFIND_STALETIMEOUT |
   5727  1.11  christos 					  DNS_DBFIND_STALEOK |
   5728  1.11  christos 					  DNS_DBFIND_STALEENABLED);
   5729  1.17  christos 	qctx.client->nodetach = false;
   5730  1.11  christos 
   5731  1.11  christos 	/*
   5732  1.11  christos 	 * We'll need some resources...
   5733  1.11  christos 	 */
   5734  1.11  christos 	if (qctx_prepare_buffers(&qctx, &buffer) != ISC_R_SUCCESS) {
   5735  1.11  christos 		dns_db_detach(&qctx.db);
   5736  1.11  christos 		qctx_destroy(&qctx);
   5737  1.11  christos 		return;
   5738  1.11  christos 	}
   5739  1.11  christos 
   5740  1.11  christos 	/*
   5741  1.11  christos 	 * Pretend we didn't find anything in cache.
   5742  1.11  christos 	 */
   5743  1.11  christos 	(void)query_gotanswer(&qctx, ISC_R_NOTFOUND);
   5744  1.11  christos 
   5745  1.11  christos 	if (qctx.fname != NULL) {
   5746  1.11  christos 		ns_client_releasename(qctx.client, &qctx.fname);
   5747  1.11  christos 	}
   5748  1.11  christos 	if (qctx.rdataset != NULL) {
   5749  1.11  christos 		ns_client_putrdataset(qctx.client, &qctx.rdataset);
   5750  1.11  christos 	}
   5751  1.11  christos 
   5752  1.11  christos 	qctx_destroy(&qctx);
   5753  1.11  christos }
   5754  1.11  christos 
   5755   1.1  christos /*%
   5756  1.17  christos  * Depending on the db lookup result, we can respond to the
   5757  1.17  christos  * client this stale answer.
   5758  1.17  christos  */
   5759  1.17  christos static bool
   5760  1.17  christos stale_client_answer(isc_result_t result) {
   5761  1.17  christos 	switch (result) {
   5762  1.17  christos 	case ISC_R_SUCCESS:
   5763  1.17  christos 	case DNS_R_EMPTYNAME:
   5764  1.17  christos 	case DNS_R_NXRRSET:
   5765  1.17  christos 	case DNS_R_NCACHENXRRSET:
   5766  1.17  christos 	case DNS_R_CNAME:
   5767  1.17  christos 	case DNS_R_DNAME:
   5768  1.17  christos 		return (true);
   5769  1.17  christos 	default:
   5770  1.17  christos 		return (false);
   5771  1.17  christos 	}
   5772  1.17  christos 
   5773  1.17  christos 	UNREACHABLE();
   5774  1.17  christos }
   5775  1.17  christos 
   5776  1.17  christos /*%
   5777   1.1  christos  * Perform a local database lookup, in either an authoritative or
   5778   1.3  christos  * cache database. If unable to answer, call ns_query_done(); otherwise
   5779   1.1  christos  * hand off processing to query_gotanswer().
   5780   1.1  christos  */
   5781   1.1  christos static isc_result_t
   5782   1.1  christos query_lookup(query_ctx_t *qctx) {
   5783  1.11  christos 	isc_buffer_t buffer;
   5784  1.11  christos 	isc_result_t result = ISC_R_UNSET;
   5785   1.1  christos 	dns_clientinfomethods_t cm;
   5786   1.1  christos 	dns_clientinfo_t ci;
   5787   1.1  christos 	dns_name_t *rpzqname = NULL;
   5788  1.13  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   5789   1.1  christos 	unsigned int dboptions;
   5790  1.11  christos 	dns_ttl_t stale_refresh = 0;
   5791  1.11  christos 	bool dbfind_stale = false;
   5792  1.13  christos 	bool stale_timeout = false;
   5793  1.16  christos 	bool answer_found = false;
   5794  1.11  christos 	bool stale_found = false;
   5795  1.11  christos 	bool stale_refresh_window = false;
   5796   1.1  christos 
   5797   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_lookup");
   5798   1.1  christos 
   5799   1.3  christos 	CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx);
   5800   1.1  christos 
   5801   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   5802  1.15  christos 	dns_clientinfo_init(&ci, qctx->client,
   5803  1.15  christos 			    HAVEECS(qctx->client) ? &qctx->client->ecs : NULL,
   5804  1.15  christos 			    NULL);
   5805   1.1  christos 
   5806   1.1  christos 	/*
   5807   1.1  christos 	 * We'll need some resources...
   5808   1.1  christos 	 */
   5809  1.11  christos 	result = qctx_prepare_buffers(qctx, &buffer);
   5810  1.11  christos 	if (result != ISC_R_SUCCESS) {
   5811  1.11  christos 		QUERY_ERROR(qctx, result);
   5812   1.3  christos 		return (ns_query_done(qctx));
   5813   1.1  christos 	}
   5814   1.1  christos 
   5815   1.1  christos 	/*
   5816   1.1  christos 	 * Now look for an answer in the database.
   5817   1.1  christos 	 */
   5818   1.1  christos 	if (qctx->dns64 && qctx->rpz) {
   5819   1.1  christos 		rpzqname = qctx->client->query.rpz_st->p_name;
   5820   1.1  christos 	} else {
   5821   1.1  christos 		rpzqname = qctx->client->query.qname;
   5822   1.1  christos 	}
   5823   1.1  christos 
   5824  1.11  christos 	if ((qctx->options & DNS_GETDB_STALEFIRST) != 0) {
   5825  1.11  christos 		/*
   5826  1.11  christos 		 * If DNS_GETDB_STALEFIRST is set, it means that a stale
   5827  1.11  christos 		 * RRset may be returned as part of this lookup. An attempt
   5828  1.11  christos 		 * to refresh the RRset will still take place if an
   5829  1.11  christos 		 * active RRset is not available.
   5830  1.11  christos 		 */
   5831  1.13  christos 		qctx->client->query.dboptions |= DNS_DBFIND_STALETIMEOUT;
   5832  1.11  christos 	}
   5833  1.11  christos 
   5834   1.1  christos 	dboptions = qctx->client->query.dboptions;
   5835   1.1  christos 	if (!qctx->is_zone && qctx->findcoveringnsec &&
   5836   1.1  christos 	    (qctx->type != dns_rdatatype_null || !dns_name_istat(rpzqname)))
   5837   1.9  christos 	{
   5838   1.1  christos 		dboptions |= DNS_DBFIND_COVERINGNSEC;
   5839   1.9  christos 	}
   5840   1.1  christos 
   5841  1.11  christos 	(void)dns_db_getservestalerefresh(qctx->client->view->cachedb,
   5842  1.11  christos 					  &stale_refresh);
   5843  1.11  christos 	if (stale_refresh > 0 &&
   5844  1.16  christos 	    dns_view_staleanswerenabled(qctx->client->view))
   5845  1.16  christos 	{
   5846  1.11  christos 		dboptions |= DNS_DBFIND_STALEENABLED;
   5847  1.11  christos 	}
   5848  1.11  christos 
   5849   1.1  christos 	result = dns_db_findext(qctx->db, rpzqname, qctx->version, qctx->type,
   5850   1.1  christos 				dboptions, qctx->client->now, &qctx->node,
   5851   1.9  christos 				qctx->fname, &cm, &ci, qctx->rdataset,
   5852   1.9  christos 				qctx->sigrdataset);
   5853   1.1  christos 
   5854   1.1  christos 	/*
   5855   1.1  christos 	 * Fixup fname and sigrdataset.
   5856   1.1  christos 	 */
   5857   1.1  christos 	if (qctx->dns64 && qctx->rpz) {
   5858   1.8  christos 		dns_name_copynf(qctx->client->query.qname, qctx->fname);
   5859   1.1  christos 		if (qctx->sigrdataset != NULL &&
   5860  1.16  christos 		    dns_rdataset_isassociated(qctx->sigrdataset))
   5861  1.16  christos 		{
   5862   1.1  christos 			dns_rdataset_disassociate(qctx->sigrdataset);
   5863   1.1  christos 		}
   5864   1.1  christos 	}
   5865   1.1  christos 
   5866   1.1  christos 	if (!qctx->is_zone) {
   5867   1.3  christos 		dns_cache_updatestats(qctx->view->cache, result);
   5868   1.1  christos 	}
   5869   1.1  christos 
   5870  1.11  christos 	/*
   5871  1.11  christos 	 * If DNS_DBFIND_STALEOK is set this means we are dealing with a
   5872  1.11  christos 	 * lookup following a failed lookup and it is okay to serve a stale
   5873  1.11  christos 	 * answer. This will (re)start the 'stale-refresh-time' window in
   5874  1.11  christos 	 * rbtdb, tracking the last time the RRset lookup failed.
   5875  1.11  christos 	 */
   5876  1.11  christos 	dbfind_stale = ((dboptions & DNS_DBFIND_STALEOK) != 0);
   5877  1.11  christos 
   5878  1.11  christos 	/*
   5879  1.11  christos 	 * If DNS_DBFIND_STALEENABLED is set, this may be a normal lookup, but
   5880  1.11  christos 	 * we are allowed to immediately respond with a stale answer if the
   5881  1.11  christos 	 * request is within the 'stale-refresh-time' window.
   5882  1.11  christos 	 */
   5883  1.11  christos 	stale_refresh_window = (STALE_WINDOW(qctx->rdataset) &&
   5884  1.11  christos 				(dboptions & DNS_DBFIND_STALEENABLED) != 0);
   5885  1.11  christos 
   5886  1.11  christos 	/*
   5887  1.13  christos 	 * If DNS_DBFIND_STALETIMEOUT is set, a stale answer is requested.
   5888  1.11  christos 	 * This can happen if 'stale-answer-client-timeout' is enabled.
   5889  1.11  christos 	 *
   5890  1.13  christos 	 * If 'stale-answer-client-timeout' is set to 0, and a stale
   5891  1.11  christos 	 * answer is found, send it to the client, and try to refresh the
   5892  1.13  christos 	 * RRset.
   5893  1.11  christos 	 *
   5894  1.13  christos 	 * If 'stale-answer-client-timeout' is non-zero, and a stale
   5895  1.11  christos 	 * answer is found, send it to the client. Don't try to refresh the
   5896  1.13  christos 	 * RRset because a fetch is already in progress.
   5897  1.11  christos 	 */
   5898  1.13  christos 	stale_timeout = ((dboptions & DNS_DBFIND_STALETIMEOUT) != 0);
   5899  1.11  christos 
   5900  1.16  christos 	if (dns_rdataset_isassociated(qctx->rdataset) &&
   5901  1.16  christos 	    dns_rdataset_count(qctx->rdataset) > 0 && !STALE(qctx->rdataset))
   5902  1.16  christos 	{
   5903  1.16  christos 		/* Found non-stale usable rdataset. */
   5904  1.16  christos 		answer_found = true;
   5905  1.16  christos 	}
   5906  1.16  christos 
   5907  1.13  christos 	if (dbfind_stale || stale_refresh_window || stale_timeout) {
   5908  1.13  christos 		dns_name_format(qctx->client->query.qname, namebuf,
   5909  1.13  christos 				sizeof(namebuf));
   5910   1.1  christos 
   5911  1.11  christos 		inc_stats(qctx->client, ns_statscounter_trystale);
   5912  1.11  christos 
   5913   1.1  christos 		if (dns_rdataset_isassociated(qctx->rdataset) &&
   5914   1.1  christos 		    dns_rdataset_count(qctx->rdataset) > 0 &&
   5915   1.9  christos 		    STALE(qctx->rdataset))
   5916   1.9  christos 		{
   5917   1.3  christos 			qctx->rdataset->ttl = qctx->view->staleanswerttl;
   5918  1.11  christos 			stale_found = true;
   5919  1.14  christos 			inc_stats(qctx->client, ns_statscounter_usedstale);
   5920   1.1  christos 		} else {
   5921  1.11  christos 			stale_found = false;
   5922   1.1  christos 		}
   5923  1.13  christos 	}
   5924   1.1  christos 
   5925  1.13  christos 	if (dbfind_stale) {
   5926  1.13  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   5927  1.13  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5928  1.13  christos 			      "%s resolver failure, stale answer %s", namebuf,
   5929  1.13  christos 			      stale_found ? "used" : "unavailable");
   5930  1.17  christos 		if (!stale_found && !answer_found) {
   5931  1.13  christos 			/*
   5932  1.13  christos 			 * Resolver failure, no stale data, nothing more we
   5933  1.13  christos 			 * can do, return SERVFAIL.
   5934  1.13  christos 			 */
   5935  1.13  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   5936  1.13  christos 			return (ns_query_done(qctx));
   5937  1.13  christos 		}
   5938  1.13  christos 	} else if (stale_refresh_window) {
   5939  1.13  christos 		/*
   5940  1.13  christos 		 * A recent lookup failed, so during this time window we are
   5941  1.13  christos 		 * allowed to return stale data immediately.
   5942  1.13  christos 		 */
   5943  1.13  christos 		isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   5944  1.13  christos 			      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5945  1.13  christos 			      "%s query within stale refresh time, stale "
   5946  1.13  christos 			      "answer %s",
   5947  1.13  christos 			      namebuf, stale_found ? "used" : "unavailable");
   5948  1.11  christos 
   5949  1.17  christos 		if (!stale_found && !answer_found) {
   5950  1.11  christos 			/*
   5951  1.13  christos 			 * During the stale refresh window explicitly do not try
   5952  1.13  christos 			 * to refresh the data, because a recent lookup failed.
   5953  1.11  christos 			 */
   5954  1.13  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   5955  1.13  christos 			return (ns_query_done(qctx));
   5956  1.13  christos 		}
   5957  1.13  christos 	} else if (stale_timeout) {
   5958  1.13  christos 		if ((qctx->options & DNS_GETDB_STALEFIRST) != 0) {
   5959  1.17  christos 			if (!stale_found && !answer_found) {
   5960  1.11  christos 				/*
   5961  1.13  christos 				 * We have nothing useful in cache to return
   5962  1.13  christos 				 * immediately.
   5963  1.11  christos 				 */
   5964  1.13  christos 				qctx_clean(qctx);
   5965  1.13  christos 				qctx_freedata(qctx);
   5966  1.13  christos 				dns_db_attach(qctx->client->view->cachedb,
   5967  1.13  christos 					      &qctx->db);
   5968  1.13  christos 				qctx->client->query.dboptions &=
   5969  1.13  christos 					~DNS_DBFIND_STALETIMEOUT;
   5970  1.13  christos 				qctx->options &= ~DNS_GETDB_STALEFIRST;
   5971  1.13  christos 				if (qctx->client->query.fetch != NULL) {
   5972  1.13  christos 					dns_resolver_destroyfetch(
   5973  1.13  christos 						&qctx->client->query.fetch);
   5974  1.11  christos 				}
   5975  1.14  christos 				return (query_lookup(qctx));
   5976  1.17  christos 			} else if (stale_client_answer(result)) {
   5977  1.11  christos 				/*
   5978  1.13  christos 				 * Immediately return the stale answer, start a
   5979  1.13  christos 				 * resolver fetch to refresh the data in cache.
   5980  1.11  christos 				 */
   5981  1.11  christos 				isc_log_write(
   5982  1.11  christos 					ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   5983  1.11  christos 					NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   5984  1.13  christos 					"%s stale answer used, an attempt to "
   5985  1.13  christos 					"refresh the RRset will still be made",
   5986  1.13  christos 					namebuf);
   5987  1.17  christos 
   5988  1.15  christos 				qctx->refresh_rrset = STALE(qctx->rdataset);
   5989  1.17  christos 
   5990  1.17  christos 				/*
   5991  1.17  christos 				 * If we are refreshing the RRSet, we must not
   5992  1.17  christos 				 * detach from the client in query_send().
   5993  1.17  christos 				 */
   5994  1.17  christos 				qctx->client->nodetach = qctx->refresh_rrset;
   5995  1.13  christos 			}
   5996  1.13  christos 		} else {
   5997  1.13  christos 			/*
   5998  1.13  christos 			 * The 'stale-answer-client-timeout' triggered, return
   5999  1.13  christos 			 * the stale answer if available, otherwise wait until
   6000  1.13  christos 			 * the resolver finishes.
   6001  1.13  christos 			 */
   6002  1.13  christos 			isc_log_write(ns_lctx, NS_LOGCATEGORY_SERVE_STALE,
   6003  1.13  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_INFO,
   6004  1.13  christos 				      "%s client timeout, stale answer %s",
   6005  1.13  christos 				      namebuf,
   6006  1.13  christos 				      stale_found ? "used" : "unavailable");
   6007  1.17  christos 			if (!stale_found && !answer_found) {
   6008  1.17  christos 				return (result);
   6009  1.17  christos 			}
   6010  1.17  christos 
   6011  1.17  christos 			if (!stale_client_answer(result)) {
   6012  1.13  christos 				return (result);
   6013  1.11  christos 			}
   6014  1.14  christos 
   6015  1.14  christos 			/*
   6016  1.14  christos 			 * There still might be real answer later. Mark the
   6017  1.14  christos 			 * query so we'll know we can skip answering.
   6018  1.14  christos 			 */
   6019  1.14  christos 			qctx->client->query.attributes |=
   6020  1.14  christos 				NS_QUERYATTR_STALEPENDING;
   6021   1.1  christos 		}
   6022  1.11  christos 	}
   6023  1.11  christos 
   6024  1.16  christos 	if (stale_timeout && (answer_found || stale_found)) {
   6025  1.11  christos 		/*
   6026  1.13  christos 		 * Mark RRsets that we are adding to the client message on a
   6027  1.13  christos 		 * lookup during 'stale-answer-client-timeout', so we can
   6028  1.13  christos 		 * clean it up if needed when we resume from recursion.
   6029  1.11  christos 		 */
   6030  1.13  christos 		qctx->client->query.attributes |= NS_QUERYATTR_STALEOK;
   6031  1.13  christos 		qctx->rdataset->attributes |= DNS_RDATASETATTR_STALE_ADDED;
   6032  1.11  christos 	}
   6033  1.14  christos 
   6034  1.11  christos 	result = query_gotanswer(qctx, result);
   6035  1.11  christos 
   6036   1.9  christos cleanup:
   6037   1.3  christos 	return (result);
   6038   1.1  christos }
   6039   1.1  christos 
   6040   1.1  christos /*
   6041  1.13  christos  * Clear all rdatasets from the message that are in the given section and
   6042  1.13  christos  * that have the 'attr' attribute set.
   6043  1.13  christos  */
   6044  1.13  christos static void
   6045  1.13  christos message_clearrdataset(dns_message_t *msg, unsigned int attr) {
   6046  1.13  christos 	unsigned int i;
   6047  1.13  christos 	dns_name_t *name, *next_name;
   6048  1.13  christos 	dns_rdataset_t *rds, *next_rds;
   6049  1.13  christos 
   6050  1.13  christos 	/*
   6051  1.13  christos 	 * Clean up name lists by calling the rdataset disassociate function.
   6052  1.13  christos 	 */
   6053  1.13  christos 	for (i = DNS_SECTION_ANSWER; i < DNS_SECTION_MAX; i++) {
   6054  1.13  christos 		name = ISC_LIST_HEAD(msg->sections[i]);
   6055  1.13  christos 		while (name != NULL) {
   6056  1.13  christos 			next_name = ISC_LIST_NEXT(name, link);
   6057  1.13  christos 
   6058  1.13  christos 			rds = ISC_LIST_HEAD(name->list);
   6059  1.13  christos 			while (rds != NULL) {
   6060  1.13  christos 				next_rds = ISC_LIST_NEXT(rds, link);
   6061  1.13  christos 				if ((rds->attributes & attr) != attr) {
   6062  1.13  christos 					rds = next_rds;
   6063  1.13  christos 					continue;
   6064  1.13  christos 				}
   6065  1.13  christos 				ISC_LIST_UNLINK(name->list, rds, link);
   6066  1.13  christos 				INSIST(dns_rdataset_isassociated(rds));
   6067  1.13  christos 				dns_rdataset_disassociate(rds);
   6068  1.13  christos 				isc_mempool_put(msg->rdspool, rds);
   6069  1.13  christos 				rds = next_rds;
   6070  1.13  christos 			}
   6071  1.13  christos 
   6072  1.13  christos 			if (ISC_LIST_EMPTY(name->list)) {
   6073  1.13  christos 				ISC_LIST_UNLINK(msg->sections[i], name, link);
   6074  1.13  christos 				if (dns_name_dynamic(name)) {
   6075  1.13  christos 					dns_name_free(name, msg->mctx);
   6076  1.13  christos 				}
   6077  1.13  christos 				isc_mempool_put(msg->namepool, name);
   6078  1.13  christos 			}
   6079  1.13  christos 
   6080  1.13  christos 			name = next_name;
   6081  1.13  christos 		}
   6082  1.13  christos 	}
   6083  1.13  christos }
   6084  1.13  christos 
   6085  1.13  christos /*
   6086  1.13  christos  * Clear any rdatasets from the client's message that were added on a lookup
   6087  1.13  christos  * due to a client timeout.
   6088  1.13  christos  */
   6089  1.13  christos static void
   6090  1.13  christos query_clear_stale(ns_client_t *client) {
   6091  1.13  christos 	message_clearrdataset(client->message, DNS_RDATASETATTR_STALE_ADDED);
   6092  1.13  christos }
   6093  1.13  christos 
   6094  1.13  christos /*
   6095  1.13  christos  * Create a new query context with the sole intent of looking up for a stale
   6096  1.13  christos  * RRset in cache. If an entry is found, we mark the original query as
   6097  1.13  christos  * answered, in order to avoid answering the query twice, when the original
   6098  1.13  christos  * fetch finishes.
   6099  1.11  christos  */
   6100  1.15  christos static void
   6101  1.13  christos query_lookup_stale(ns_client_t *client) {
   6102  1.11  christos 	query_ctx_t qctx;
   6103  1.11  christos 
   6104  1.11  christos 	qctx_init(client, NULL, client->query.qtype, &qctx);
   6105  1.11  christos 	dns_db_attach(client->view->cachedb, &qctx.db);
   6106  1.13  christos 	client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
   6107  1.13  christos 	client->query.dboptions |= DNS_DBFIND_STALETIMEOUT;
   6108  1.13  christos 	client->nodetach = true;
   6109  1.11  christos 	(void)query_lookup(&qctx);
   6110  1.11  christos 	if (qctx.node != NULL) {
   6111  1.11  christos 		dns_db_detachnode(qctx.db, &qctx.node);
   6112  1.11  christos 	}
   6113  1.11  christos 	qctx_freedata(&qctx);
   6114  1.11  christos 	qctx_destroy(&qctx);
   6115  1.11  christos }
   6116  1.11  christos 
   6117  1.11  christos /*
   6118  1.11  christos  * Event handler to resume processing a query after recursion, or when a
   6119  1.11  christos  * client timeout is triggered. If the query has timed out or been cancelled
   6120  1.11  christos  * or the system is shutting down, clean up and exit. If a client timeout is
   6121  1.11  christos  * triggered, see if we can respond with a stale answer from cache. Otherwise,
   6122  1.11  christos  * call query_resume() to continue the ongoing work.
   6123   1.1  christos  */
   6124   1.1  christos static void
   6125   1.1  christos fetch_callback(isc_task_t *task, isc_event_t *event) {
   6126   1.1  christos 	dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
   6127   1.1  christos 	dns_fetch_t *fetch = NULL;
   6128  1.14  christos 	ns_client_t *client = NULL;
   6129  1.14  christos 	bool fetch_canceled = false;
   6130  1.14  christos 	bool fetch_answered = false;
   6131  1.14  christos 	bool client_shuttingdown = false;
   6132  1.14  christos 	isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_ERRORS;
   6133   1.1  christos 	isc_result_t result;
   6134   1.1  christos 	int errorloglevel;
   6135  1.11  christos 	query_ctx_t qctx;
   6136   1.1  christos 
   6137   1.1  christos 	UNUSED(task);
   6138   1.1  christos 
   6139  1.11  christos 	REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE ||
   6140  1.11  christos 		event->ev_type == DNS_EVENT_TRYSTALE);
   6141  1.14  christos 
   6142   1.1  christos 	client = devent->ev_arg;
   6143  1.14  christos 
   6144   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   6145   1.1  christos 	REQUIRE(task == client->task);
   6146   1.1  christos 	REQUIRE(RECURSING(client));
   6147   1.1  christos 
   6148   1.9  christos 	CTRACE(ISC_LOG_DEBUG(3), "fetch_callback");
   6149   1.9  christos 
   6150  1.11  christos 	if (event->ev_type == DNS_EVENT_TRYSTALE) {
   6151  1.16  christos 		if (devent->result != ISC_R_CANCELED) {
   6152  1.16  christos 			query_lookup_stale(client);
   6153  1.16  christos 		}
   6154  1.11  christos 		isc_event_free(ISC_EVENT_PTR(&event));
   6155  1.11  christos 		return;
   6156  1.11  christos 	}
   6157  1.13  christos 	/*
   6158  1.13  christos 	 * We are resuming from recursion. Reset any attributes, options
   6159  1.13  christos 	 * that a lookup due to stale-answer-client-timeout may have set.
   6160  1.13  christos 	 */
   6161  1.13  christos 	if (client->view->cachedb != NULL && client->view->recursion) {
   6162  1.13  christos 		client->query.attributes |= NS_QUERYATTR_RECURSIONOK;
   6163  1.13  christos 	}
   6164  1.14  christos 	client->query.fetchoptions &= ~DNS_FETCHOPT_TRYSTALE_ONTIMEOUT;
   6165  1.13  christos 	client->query.dboptions &= ~DNS_DBFIND_STALETIMEOUT;
   6166  1.13  christos 	client->nodetach = false;
   6167  1.13  christos 
   6168   1.1  christos 	LOCK(&client->query.fetchlock);
   6169  1.14  christos 	INSIST(client->query.fetch == devent->fetch ||
   6170  1.14  christos 	       client->query.fetch == NULL);
   6171  1.14  christos 	if (QUERY_STALEPENDING(&client->query)) {
   6172  1.14  christos 		/*
   6173  1.14  christos 		 * We've gotten an authoritative answer to a query that
   6174  1.14  christos 		 * was left pending after a stale timeout. We don't need
   6175  1.14  christos 		 * to do anything with it; free all the data and go home.
   6176  1.14  christos 		 */
   6177  1.14  christos 		client->query.fetch = NULL;
   6178  1.14  christos 		fetch_answered = true;
   6179  1.14  christos 	} else if (client->query.fetch != NULL) {
   6180   1.1  christos 		/*
   6181   1.1  christos 		 * This is the fetch we've been waiting for.
   6182   1.1  christos 		 */
   6183   1.1  christos 		INSIST(devent->fetch == client->query.fetch);
   6184   1.1  christos 		client->query.fetch = NULL;
   6185  1.14  christos 
   6186   1.1  christos 		/*
   6187   1.1  christos 		 * Update client->now.
   6188   1.1  christos 		 */
   6189   1.1  christos 		isc_stdtime_get(&client->now);
   6190   1.1  christos 	} else {
   6191   1.1  christos 		/*
   6192   1.1  christos 		 * This is a fetch completion event for a canceled fetch.
   6193   1.1  christos 		 * Clean up and don't resume the find.
   6194   1.1  christos 		 */
   6195   1.3  christos 		fetch_canceled = true;
   6196   1.1  christos 	}
   6197   1.1  christos 	UNLOCK(&client->query.fetchlock);
   6198   1.1  christos 
   6199   1.9  christos 	SAVE(fetch, devent->fetch);
   6200   1.9  christos 
   6201   1.9  christos 	/*
   6202   1.9  christos 	 * We're done recursing, detach from quota and unlink from
   6203   1.9  christos 	 * the manager's recursing-clients list.
   6204   1.9  christos 	 */
   6205   1.9  christos 
   6206   1.9  christos 	if (client->recursionquota != NULL) {
   6207   1.9  christos 		isc_quota_detach(&client->recursionquota);
   6208  1.16  christos 		ns_stats_decrement(client->sctx->nsstats,
   6209  1.16  christos 				   ns_statscounter_recursclients);
   6210   1.9  christos 	}
   6211   1.9  christos 
   6212   1.9  christos 	LOCK(&client->manager->reclock);
   6213   1.9  christos 	if (ISC_LINK_LINKED(client, rlink)) {
   6214   1.9  christos 		ISC_LIST_UNLINK(client->manager->recursing, client, rlink);
   6215   1.9  christos 	}
   6216   1.9  christos 	UNLOCK(&client->manager->reclock);
   6217   1.9  christos 
   6218  1.11  christos 	isc_nmhandle_detach(&client->fetchhandle);
   6219  1.11  christos 
   6220   1.1  christos 	client->query.attributes &= ~NS_QUERYATTR_RECURSING;
   6221   1.9  christos 	client->state = NS_CLIENTSTATE_WORKING;
   6222   1.1  christos 
   6223   1.1  christos 	/*
   6224  1.11  christos 	 * Initialize a new qctx and use it to either resume from
   6225  1.11  christos 	 * recursion or clean up after cancelation.  Transfer
   6226  1.11  christos 	 * ownership of devent to the new qctx in the process.
   6227   1.1  christos 	 */
   6228  1.11  christos 	qctx_init(client, &devent, 0, &qctx);
   6229  1.11  christos 
   6230   1.1  christos 	client_shuttingdown = ns_client_shuttingdown(client);
   6231  1.14  christos 	if (fetch_canceled || fetch_answered || client_shuttingdown) {
   6232  1.11  christos 		/*
   6233  1.11  christos 		 * We've timed out or are shutting down. We can now
   6234  1.11  christos 		 * free the event and other resources held by qctx, but
   6235  1.11  christos 		 * don't call qctx_destroy() yet: it might destroy the
   6236  1.11  christos 		 * client, which we still need for a moment.
   6237  1.11  christos 		 */
   6238  1.11  christos 		qctx_freedata(&qctx);
   6239  1.11  christos 
   6240  1.11  christos 		/*
   6241  1.11  christos 		 * Return an error to the client, or just drop.
   6242  1.11  christos 		 */
   6243   1.1  christos 		if (fetch_canceled) {
   6244   1.1  christos 			CTRACE(ISC_LOG_ERROR, "fetch cancelled");
   6245   1.1  christos 			query_error(client, DNS_R_SERVFAIL, __LINE__);
   6246   1.1  christos 		} else {
   6247   1.1  christos 			query_next(client, ISC_R_CANCELED);
   6248   1.1  christos 		}
   6249  1.11  christos 
   6250  1.11  christos 		/*
   6251  1.11  christos 		 * Free any persistent plugin data that was allocated to
   6252  1.11  christos 		 * service the client, then detach the client object.
   6253  1.11  christos 		 */
   6254  1.11  christos 		qctx.detach_client = true;
   6255  1.11  christos 		qctx_destroy(&qctx);
   6256   1.1  christos 	} else {
   6257   1.3  christos 		/*
   6258  1.11  christos 		 * Resume the find process.
   6259   1.3  christos 		 */
   6260   1.1  christos 		query_trace(&qctx);
   6261   1.1  christos 
   6262   1.1  christos 		result = query_resume(&qctx);
   6263   1.1  christos 		if (result != ISC_R_SUCCESS) {
   6264   1.1  christos 			if (result == DNS_R_SERVFAIL) {
   6265   1.1  christos 				errorloglevel = ISC_LOG_DEBUG(2);
   6266   1.1  christos 			} else {
   6267   1.1  christos 				errorloglevel = ISC_LOG_DEBUG(4);
   6268   1.1  christos 			}
   6269   1.1  christos 			if (isc_log_wouldlog(ns_lctx, errorloglevel)) {
   6270   1.1  christos 				dns_resolver_logfetch(fetch, ns_lctx,
   6271   1.1  christos 						      logcategory,
   6272   1.1  christos 						      NS_LOGMODULE_QUERY,
   6273   1.3  christos 						      errorloglevel, false);
   6274   1.1  christos 			}
   6275   1.1  christos 		}
   6276   1.3  christos 
   6277   1.3  christos 		qctx_destroy(&qctx);
   6278   1.1  christos 	}
   6279   1.1  christos 
   6280   1.1  christos 	dns_resolver_destroyfetch(&fetch);
   6281   1.1  christos }
   6282   1.1  christos 
   6283   1.1  christos /*%
   6284   1.1  christos  * Check whether the recursion parameters in 'param' match the current query's
   6285   1.1  christos  * recursion parameters provided in 'qtype', 'qname', and 'qdomain'.
   6286   1.1  christos  */
   6287   1.3  christos static bool
   6288   1.1  christos recparam_match(const ns_query_recparam_t *param, dns_rdatatype_t qtype,
   6289   1.9  christos 	       const dns_name_t *qname, const dns_name_t *qdomain) {
   6290   1.1  christos 	REQUIRE(param != NULL);
   6291   1.1  christos 
   6292   1.9  christos 	return (param->qtype == qtype && param->qname != NULL &&
   6293   1.9  christos 		qname != NULL && param->qdomain != NULL && qdomain != NULL &&
   6294   1.3  christos 		dns_name_equal(param->qname, qname) &&
   6295   1.3  christos 		dns_name_equal(param->qdomain, qdomain));
   6296   1.1  christos }
   6297   1.1  christos 
   6298   1.1  christos /*%
   6299   1.1  christos  * Update 'param' with current query's recursion parameters provided in
   6300   1.1  christos  * 'qtype', 'qname', and 'qdomain'.
   6301   1.1  christos  */
   6302   1.1  christos static void
   6303   1.1  christos recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype,
   6304   1.9  christos 		const dns_name_t *qname, const dns_name_t *qdomain) {
   6305   1.1  christos 	REQUIRE(param != NULL);
   6306   1.1  christos 
   6307   1.1  christos 	param->qtype = qtype;
   6308   1.1  christos 
   6309   1.1  christos 	if (qname == NULL) {
   6310   1.1  christos 		param->qname = NULL;
   6311   1.1  christos 	} else {
   6312   1.3  christos 		param->qname = dns_fixedname_initname(&param->fqname);
   6313   1.8  christos 		dns_name_copynf(qname, param->qname);
   6314   1.1  christos 	}
   6315   1.1  christos 
   6316   1.1  christos 	if (qdomain == NULL) {
   6317   1.1  christos 		param->qdomain = NULL;
   6318   1.1  christos 	} else {
   6319   1.3  christos 		param->qdomain = dns_fixedname_initname(&param->fqdomain);
   6320   1.8  christos 		dns_name_copynf(qdomain, param->qdomain);
   6321   1.1  christos 	}
   6322   1.1  christos }
   6323   1.9  christos static atomic_uint_fast32_t last_soft, last_hard;
   6324   1.1  christos 
   6325   1.3  christos isc_result_t
   6326   1.3  christos ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname,
   6327   1.3  christos 		 dns_name_t *qdomain, dns_rdataset_t *nameservers,
   6328   1.9  christos 		 bool resuming) {
   6329   1.1  christos 	isc_result_t result;
   6330   1.1  christos 	dns_rdataset_t *rdataset, *sigrdataset;
   6331   1.1  christos 	isc_sockaddr_t *peeraddr = NULL;
   6332   1.1  christos 
   6333   1.3  christos 	CTRACE(ISC_LOG_DEBUG(3), "ns_query_recurse");
   6334   1.1  christos 
   6335   1.1  christos 	/*
   6336   1.1  christos 	 * Check recursion parameters from the previous query to see if they
   6337   1.1  christos 	 * match.  If not, update recursion parameters and proceed.
   6338   1.1  christos 	 */
   6339   1.1  christos 	if (recparam_match(&client->query.recparam, qtype, qname, qdomain)) {
   6340   1.9  christos 		ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY,
   6341   1.9  christos 			      ISC_LOG_INFO, "recursion loop detected");
   6342  1.17  christos 		return (ISC_R_ALREADYRUNNING);
   6343   1.1  christos 	}
   6344   1.1  christos 
   6345   1.1  christos 	recparam_update(&client->query.recparam, qtype, qname, qdomain);
   6346   1.1  christos 
   6347   1.9  christos 	if (!resuming) {
   6348   1.1  christos 		inc_stats(client, ns_statscounter_recursion);
   6349   1.9  christos 	}
   6350   1.1  christos 
   6351   1.1  christos 	/*
   6352   1.1  christos 	 * We are about to recurse, which means that this client will
   6353   1.1  christos 	 * be unavailable for serving new requests for an indeterminate
   6354   1.1  christos 	 * amount of time.  If this client is currently responsible
   6355   1.1  christos 	 * for handling incoming queries, set up a new client
   6356   1.1  christos 	 * object to handle them while we are waiting for a
   6357   1.1  christos 	 * response.  There is no need to replace TCP clients
   6358   1.1  christos 	 * because those have already been replaced when the
   6359   1.1  christos 	 * connection was accepted (if allowed by the TCP quota).
   6360   1.1  christos 	 */
   6361   1.1  christos 	if (client->recursionquota == NULL) {
   6362   1.1  christos 		result = isc_quota_attach(&client->sctx->recursionquota,
   6363   1.1  christos 					  &client->recursionquota);
   6364  1.16  christos 		if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) {
   6365  1.16  christos 			ns_stats_increment(client->sctx->nsstats,
   6366  1.16  christos 					   ns_statscounter_recursclients);
   6367  1.16  christos 		}
   6368  1.16  christos 
   6369   1.9  christos 		if (result == ISC_R_SOFTQUOTA) {
   6370   1.1  christos 			isc_stdtime_t now;
   6371   1.1  christos 			isc_stdtime_get(&now);
   6372   1.9  christos 			if (now != atomic_load_relaxed(&last_soft)) {
   6373   1.9  christos 				atomic_store_relaxed(&last_soft, now);
   6374   1.1  christos 				ns_client_log(client, NS_LOGCATEGORY_CLIENT,
   6375   1.9  christos 					      NS_LOGMODULE_QUERY,
   6376   1.9  christos 					      ISC_LOG_WARNING,
   6377   1.9  christos 					      "recursive-clients soft limit "
   6378   1.9  christos 					      "exceeded (%u/%u/%u), "
   6379   1.9  christos 					      "aborting oldest query",
   6380   1.9  christos 					      isc_quota_getused(
   6381   1.9  christos 						      client->recursionquota),
   6382   1.9  christos 					      isc_quota_getsoft(
   6383   1.9  christos 						      client->recursionquota),
   6384   1.9  christos 					      isc_quota_getmax(
   6385   1.9  christos 						      client->recursionquota));
   6386   1.1  christos 			}
   6387   1.1  christos 			ns_client_killoldestquery(client);
   6388   1.1  christos 			result = ISC_R_SUCCESS;
   6389   1.1  christos 		} else if (result == ISC_R_QUOTA) {
   6390   1.1  christos 			isc_stdtime_t now;
   6391   1.1  christos 			isc_stdtime_get(&now);
   6392   1.9  christos 			if (now != atomic_load_relaxed(&last_hard)) {
   6393   1.4  christos 				ns_server_t *sctx = client->sctx;
   6394   1.9  christos 				atomic_store_relaxed(&last_hard, now);
   6395   1.9  christos 				ns_client_log(
   6396   1.9  christos 					client, NS_LOGCATEGORY_CLIENT,
   6397   1.9  christos 					NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   6398   1.9  christos 					"no more recursive clients "
   6399   1.9  christos 					"(%u/%u/%u): %s",
   6400   1.9  christos 					isc_quota_getused(
   6401   1.9  christos 						&sctx->recursionquota),
   6402   1.9  christos 					isc_quota_getsoft(
   6403   1.9  christos 						&sctx->recursionquota),
   6404   1.9  christos 					isc_quota_getmax(&sctx->recursionquota),
   6405   1.9  christos 					isc_result_totext(result));
   6406   1.1  christos 			}
   6407   1.1  christos 			ns_client_killoldestquery(client);
   6408   1.1  christos 		}
   6409   1.9  christos 		if (result != ISC_R_SUCCESS) {
   6410   1.9  christos 			return (result);
   6411   1.1  christos 		}
   6412   1.9  christos 
   6413  1.11  christos 		dns_message_clonebuffer(client->message);
   6414   1.1  christos 		ns_client_recursing(client);
   6415   1.1  christos 	}
   6416   1.1  christos 
   6417   1.1  christos 	/*
   6418   1.1  christos 	 * Invoke the resolver.
   6419   1.1  christos 	 */
   6420   1.1  christos 	REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
   6421   1.1  christos 	REQUIRE(client->query.fetch == NULL);
   6422   1.1  christos 
   6423   1.3  christos 	rdataset = ns_client_newrdataset(client);
   6424   1.1  christos 	if (rdataset == NULL) {
   6425   1.1  christos 		return (ISC_R_NOMEMORY);
   6426   1.1  christos 	}
   6427   1.1  christos 
   6428   1.1  christos 	if (WANTDNSSEC(client)) {
   6429   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   6430   1.1  christos 		if (sigrdataset == NULL) {
   6431   1.3  christos 			ns_client_putrdataset(client, &rdataset);
   6432   1.1  christos 			return (ISC_R_NOMEMORY);
   6433   1.1  christos 		}
   6434   1.1  christos 	} else {
   6435   1.1  christos 		sigrdataset = NULL;
   6436   1.1  christos 	}
   6437   1.1  christos 
   6438  1.10  christos 	if (!client->query.timerset) {
   6439   1.1  christos 		ns_client_settimeout(client, 60);
   6440   1.1  christos 	}
   6441   1.1  christos 
   6442   1.1  christos 	if (!TCP(client)) {
   6443   1.1  christos 		peeraddr = &client->peeraddr;
   6444   1.1  christos 	}
   6445   1.1  christos 
   6446  1.11  christos 	if (client->view->staleanswerclienttimeout > 0 &&
   6447  1.11  christos 	    client->view->staleanswerclienttimeout != (uint32_t)-1 &&
   6448  1.11  christos 	    dns_view_staleanswerenabled(client->view))
   6449  1.11  christos 	{
   6450  1.11  christos 		client->query.fetchoptions |= DNS_FETCHOPT_TRYSTALE_ONTIMEOUT;
   6451  1.11  christos 	}
   6452  1.11  christos 
   6453  1.11  christos 	isc_nmhandle_attach(client->handle, &client->fetchhandle);
   6454   1.9  christos 	result = dns_resolver_createfetch(
   6455   1.9  christos 		client->view->resolver, qname, qtype, qdomain, nameservers,
   6456   1.9  christos 		NULL, peeraddr, client->message->id, client->query.fetchoptions,
   6457   1.9  christos 		0, NULL, client->task, fetch_callback, client, rdataset,
   6458   1.9  christos 		sigrdataset, &client->query.fetch);
   6459   1.1  christos 	if (result != ISC_R_SUCCESS) {
   6460  1.11  christos 		isc_nmhandle_detach(&client->fetchhandle);
   6461   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   6462   1.1  christos 		if (sigrdataset != NULL) {
   6463   1.3  christos 			ns_client_putrdataset(client, &sigrdataset);
   6464   1.1  christos 		}
   6465   1.1  christos 	}
   6466   1.1  christos 
   6467   1.1  christos 	/*
   6468   1.1  christos 	 * We're now waiting for a fetch event. A client which is
   6469   1.1  christos 	 * shutting down will not be destroyed until all the events
   6470   1.1  christos 	 * have been received.
   6471   1.1  christos 	 */
   6472   1.1  christos 
   6473   1.1  christos 	return (result);
   6474   1.1  christos }
   6475   1.1  christos 
   6476   1.1  christos /*%
   6477   1.1  christos  * Restores the query context after resuming from recursion, and
   6478   1.1  christos  * continues the query processing if needed.
   6479   1.1  christos  */
   6480   1.1  christos static isc_result_t
   6481   1.1  christos query_resume(query_ctx_t *qctx) {
   6482   1.1  christos 	isc_result_t result;
   6483   1.1  christos 	dns_name_t *tname;
   6484   1.1  christos 	isc_buffer_t b;
   6485   1.1  christos #ifdef WANT_QUERYTRACE
   6486   1.6  christos 	char mbuf[4 * DNS_NAME_FORMATSIZE];
   6487   1.1  christos 	char qbuf[DNS_NAME_FORMATSIZE];
   6488   1.1  christos 	char tbuf[DNS_RDATATYPE_FORMATSIZE];
   6489   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6490   1.9  christos 
   6491   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_resume");
   6492   1.1  christos 
   6493   1.3  christos 	CALL_HOOK(NS_QUERY_RESUME_BEGIN, qctx);
   6494   1.3  christos 
   6495   1.3  christos 	qctx->want_restart = false;
   6496   1.1  christos 
   6497   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   6498   1.1  christos 	if (qctx->rpz_st != NULL &&
   6499  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6500  1.16  christos 	{
   6501   1.1  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from RPZ recursion");
   6502   1.1  christos #ifdef WANT_QUERYTRACE
   6503   1.1  christos 		{
   6504   1.1  christos 			char pbuf[DNS_NAME_FORMATSIZE] = "<unset>";
   6505   1.1  christos 			char fbuf[DNS_NAME_FORMATSIZE] = "<unset>";
   6506   1.9  christos 			if (qctx->rpz_st->r_name != NULL) {
   6507   1.9  christos 				dns_name_format(qctx->rpz_st->r_name, qbuf,
   6508   1.9  christos 						sizeof(qbuf));
   6509   1.9  christos 			} else {
   6510   1.9  christos 				snprintf(qbuf, sizeof(qbuf), "<unset>");
   6511   1.9  christos 			}
   6512   1.9  christos 			if (qctx->rpz_st->p_name != NULL) {
   6513   1.9  christos 				dns_name_format(qctx->rpz_st->p_name, pbuf,
   6514   1.9  christos 						sizeof(pbuf));
   6515   1.9  christos 			}
   6516   1.9  christos 			if (qctx->rpz_st->fname != NULL) {
   6517   1.9  christos 				dns_name_format(qctx->rpz_st->fname, fbuf,
   6518   1.9  christos 						sizeof(fbuf));
   6519   1.9  christos 			}
   6520   1.1  christos 
   6521   1.1  christos 			snprintf(mbuf, sizeof(mbuf) - 1,
   6522   1.9  christos 				 "rpz rname:%s, pname:%s, qctx->fname:%s", qbuf,
   6523   1.9  christos 				 pbuf, fbuf);
   6524   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   6525   1.1  christos 		}
   6526   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6527   1.1  christos 
   6528   1.1  christos 		qctx->is_zone = qctx->rpz_st->q.is_zone;
   6529   1.1  christos 		qctx->authoritative = qctx->rpz_st->q.authoritative;
   6530   1.1  christos 		RESTORE(qctx->zone, qctx->rpz_st->q.zone);
   6531   1.1  christos 		RESTORE(qctx->node, qctx->rpz_st->q.node);
   6532   1.1  christos 		RESTORE(qctx->db, qctx->rpz_st->q.db);
   6533   1.1  christos 		RESTORE(qctx->rdataset, qctx->rpz_st->q.rdataset);
   6534   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->rpz_st->q.sigrdataset);
   6535   1.1  christos 		qctx->qtype = qctx->rpz_st->q.qtype;
   6536   1.1  christos 
   6537   1.9  christos 		if (qctx->event->node != NULL) {
   6538   1.1  christos 			dns_db_detachnode(qctx->event->db, &qctx->event->node);
   6539   1.9  christos 		}
   6540   1.1  christos 		SAVE(qctx->rpz_st->r.db, qctx->event->db);
   6541   1.1  christos 		qctx->rpz_st->r.r_type = qctx->event->qtype;
   6542   1.1  christos 		SAVE(qctx->rpz_st->r.r_rdataset, qctx->event->rdataset);
   6543   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->event->sigrdataset);
   6544   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6545   1.1  christos 		/*
   6546   1.1  christos 		 * Restore saved state.
   6547   1.1  christos 		 */
   6548   1.9  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from redirect recursion");
   6549   1.1  christos #ifdef WANT_QUERYTRACE
   6550   1.9  christos 		dns_name_format(qctx->client->query.redirect.fname, qbuf,
   6551   1.9  christos 				sizeof(qbuf));
   6552   1.9  christos 		dns_rdatatype_format(qctx->client->query.redirect.qtype, tbuf,
   6553   1.9  christos 				     sizeof(tbuf));
   6554   1.1  christos 		snprintf(mbuf, sizeof(mbuf) - 1,
   6555   1.9  christos 			 "redirect qctx->fname:%s, qtype:%s, auth:%d", qbuf,
   6556   1.9  christos 			 tbuf, qctx->client->query.redirect.authoritative);
   6557   1.1  christos 		CCTRACE(ISC_LOG_DEBUG(3), mbuf);
   6558   1.9  christos #endif /* ifdef WANT_QUERYTRACE */
   6559   1.1  christos 		qctx->qtype = qctx->client->query.redirect.qtype;
   6560   1.1  christos 		INSIST(qctx->client->query.redirect.rdataset != NULL);
   6561   1.1  christos 		RESTORE(qctx->rdataset, qctx->client->query.redirect.rdataset);
   6562   1.1  christos 		RESTORE(qctx->sigrdataset,
   6563   1.1  christos 			qctx->client->query.redirect.sigrdataset);
   6564   1.1  christos 		RESTORE(qctx->db, qctx->client->query.redirect.db);
   6565   1.1  christos 		RESTORE(qctx->node, qctx->client->query.redirect.node);
   6566   1.1  christos 		RESTORE(qctx->zone, qctx->client->query.redirect.zone);
   6567   1.1  christos 		qctx->authoritative =
   6568   1.1  christos 			qctx->client->query.redirect.authoritative;
   6569   1.1  christos 
   6570   1.1  christos 		/*
   6571   1.1  christos 		 * Free resources used while recursing.
   6572   1.1  christos 		 */
   6573   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->event->rdataset);
   6574   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->event->sigrdataset);
   6575   1.9  christos 		if (qctx->event->node != NULL) {
   6576   1.1  christos 			dns_db_detachnode(qctx->event->db, &qctx->event->node);
   6577   1.9  christos 		}
   6578   1.9  christos 		if (qctx->event->db != NULL) {
   6579   1.1  christos 			dns_db_detach(&qctx->event->db);
   6580   1.9  christos 		}
   6581   1.1  christos 	} else {
   6582   1.9  christos 		CCTRACE(ISC_LOG_DEBUG(3), "resume from normal recursion");
   6583   1.3  christos 		qctx->authoritative = false;
   6584   1.1  christos 
   6585   1.1  christos 		qctx->qtype = qctx->event->qtype;
   6586   1.1  christos 		SAVE(qctx->db, qctx->event->db);
   6587   1.1  christos 		SAVE(qctx->node, qctx->event->node);
   6588   1.1  christos 		SAVE(qctx->rdataset, qctx->event->rdataset);
   6589   1.1  christos 		SAVE(qctx->sigrdataset, qctx->event->sigrdataset);
   6590   1.1  christos 	}
   6591   1.1  christos 	INSIST(qctx->rdataset != NULL);
   6592   1.1  christos 
   6593   1.1  christos 	if (qctx->qtype == dns_rdatatype_rrsig ||
   6594  1.16  christos 	    qctx->qtype == dns_rdatatype_sig)
   6595  1.16  christos 	{
   6596   1.1  christos 		qctx->type = dns_rdatatype_any;
   6597   1.1  christos 	} else {
   6598   1.1  christos 		qctx->type = qctx->qtype;
   6599   1.1  christos 	}
   6600   1.1  christos 
   6601   1.3  christos 	CALL_HOOK(NS_QUERY_RESUME_RESTORED, qctx);
   6602   1.3  christos 
   6603   1.1  christos 	if (DNS64(qctx->client)) {
   6604   1.1  christos 		qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64;
   6605   1.3  christos 		qctx->dns64 = true;
   6606   1.1  christos 	}
   6607   1.1  christos 
   6608   1.1  christos 	if (DNS64EXCLUDE(qctx->client)) {
   6609   1.1  christos 		qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64EXCLUDE;
   6610   1.3  christos 		qctx->dns64_exclude = true;
   6611   1.1  christos 	}
   6612   1.1  christos 
   6613   1.1  christos 	if (qctx->rpz_st != NULL &&
   6614  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6615  1.16  christos 	{
   6616   1.1  christos 		/*
   6617   1.1  christos 		 * Has response policy changed out from under us?
   6618   1.1  christos 		 */
   6619   1.9  christos 		if (qctx->rpz_st->rpz_ver != qctx->view->rpzs->rpz_ver) {
   6620   1.1  christos 			ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
   6621   1.9  christos 				      NS_LOGMODULE_QUERY, DNS_RPZ_INFO_LEVEL,
   6622   1.1  christos 				      "query_resume: RPZ settings "
   6623   1.1  christos 				      "out of date "
   6624   1.1  christos 				      "(rpz_ver %d, expected %d)",
   6625   1.3  christos 				      qctx->view->rpzs->rpz_ver,
   6626   1.1  christos 				      qctx->rpz_st->rpz_ver);
   6627   1.1  christos 			QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   6628   1.3  christos 			return (ns_query_done(qctx));
   6629   1.1  christos 		}
   6630   1.1  christos 	}
   6631   1.1  christos 
   6632   1.1  christos 	/*
   6633   1.1  christos 	 * We'll need some resources...
   6634   1.1  christos 	 */
   6635   1.3  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   6636   1.1  christos 	if (qctx->dbuf == NULL) {
   6637   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_resume: ns_client_getnamebuf "
   6638   1.9  christos 				       "failed (1)");
   6639   1.3  christos 		QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   6640   1.3  christos 		return (ns_query_done(qctx));
   6641   1.1  christos 	}
   6642   1.1  christos 
   6643   1.3  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   6644   1.1  christos 	if (qctx->fname == NULL) {
   6645   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_resume: ns_client_newname failed "
   6646   1.9  christos 				       "(1)");
   6647   1.3  christos 		QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   6648   1.3  christos 		return (ns_query_done(qctx));
   6649   1.1  christos 	}
   6650   1.1  christos 
   6651   1.1  christos 	if (qctx->rpz_st != NULL &&
   6652  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6653  1.16  christos 	{
   6654   1.1  christos 		tname = qctx->rpz_st->fname;
   6655   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6656   1.1  christos 		tname = qctx->client->query.redirect.fname;
   6657   1.1  christos 	} else {
   6658   1.1  christos 		tname = dns_fixedname_name(&qctx->event->foundname);
   6659   1.1  christos 	}
   6660   1.1  christos 
   6661   1.8  christos 	dns_name_copynf(tname, qctx->fname);
   6662   1.1  christos 
   6663   1.1  christos 	if (qctx->rpz_st != NULL &&
   6664  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) != 0)
   6665  1.16  christos 	{
   6666   1.1  christos 		qctx->rpz_st->r.r_result = qctx->event->result;
   6667   1.1  christos 		result = qctx->rpz_st->q.result;
   6668   1.9  christos 		free_devent(qctx->client, ISC_EVENT_PTR(&qctx->event),
   6669   1.9  christos 			    &qctx->event);
   6670   1.1  christos 	} else if (REDIRECT(qctx->client)) {
   6671   1.1  christos 		result = qctx->client->query.redirect.result;
   6672   1.1  christos 	} else {
   6673   1.1  christos 		result = qctx->event->result;
   6674   1.1  christos 	}
   6675   1.1  christos 
   6676   1.3  christos 	qctx->resuming = true;
   6677   1.1  christos 
   6678   1.1  christos 	return (query_gotanswer(qctx, result));
   6679   1.3  christos 
   6680   1.9  christos cleanup:
   6681   1.3  christos 	return (result);
   6682   1.1  christos }
   6683   1.1  christos 
   6684   1.1  christos /*%
   6685   1.1  christos  * If the query is recursive, check the SERVFAIL cache to see whether
   6686   1.1  christos  * identical queries have failed recently.  If we find a match, and it was
   6687   1.1  christos  * from a query with CD=1, *or* if the current query has CD=0, then we just
   6688   1.1  christos  * return SERVFAIL again.  This prevents a validation failure from eliciting a
   6689   1.1  christos  * SERVFAIL response to a CD=1 query.
   6690   1.1  christos  */
   6691   1.1  christos isc_result_t
   6692   1.1  christos ns__query_sfcache(query_ctx_t *qctx) {
   6693   1.3  christos 	bool failcache;
   6694   1.3  christos 	uint32_t flags;
   6695   1.1  christos 
   6696   1.1  christos 	/*
   6697   1.1  christos 	 * The SERVFAIL cache doesn't apply to authoritative queries.
   6698   1.1  christos 	 */
   6699   1.1  christos 	if (!RECURSIONOK(qctx->client)) {
   6700   1.1  christos 		return (ISC_R_COMPLETE);
   6701   1.1  christos 	}
   6702   1.1  christos 
   6703   1.1  christos 	flags = 0;
   6704   1.1  christos #ifdef ENABLE_AFL
   6705   1.1  christos 	if (qctx->client->sctx->fuzztype == isc_fuzz_resolver) {
   6706   1.3  christos 		failcache = false;
   6707   1.1  christos 	} else {
   6708   1.9  christos 		failcache = dns_badcache_find(
   6709   1.9  christos 			qctx->view->failcache, qctx->client->query.qname,
   6710   1.9  christos 			qctx->qtype, &flags, &qctx->client->tnow);
   6711   1.1  christos 	}
   6712   1.9  christos #else  /* ifdef ENABLE_AFL */
   6713   1.3  christos 	failcache = dns_badcache_find(qctx->view->failcache,
   6714   1.9  christos 				      qctx->client->query.qname, qctx->qtype,
   6715   1.9  christos 				      &flags, &qctx->client->tnow);
   6716   1.9  christos #endif /* ifdef ENABLE_AFL */
   6717   1.1  christos 	if (failcache &&
   6718   1.1  christos 	    (((flags & NS_FAILCACHE_CD) != 0) ||
   6719   1.1  christos 	     ((qctx->client->message->flags & DNS_MESSAGEFLAG_CD) == 0)))
   6720   1.1  christos 	{
   6721   1.1  christos 		if (isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1))) {
   6722   1.1  christos 			char namebuf[DNS_NAME_FORMATSIZE];
   6723   1.3  christos 			char typebuf[DNS_RDATATYPE_FORMATSIZE];
   6724   1.1  christos 
   6725   1.9  christos 			dns_name_format(qctx->client->query.qname, namebuf,
   6726   1.9  christos 					sizeof(namebuf));
   6727   1.3  christos 			dns_rdatatype_format(qctx->qtype, typebuf,
   6728   1.3  christos 					     sizeof(typebuf));
   6729   1.9  christos 			ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT,
   6730   1.9  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(1),
   6731   1.9  christos 				      "servfail cache hit %s/%s (%s)", namebuf,
   6732   1.9  christos 				      typebuf,
   6733   1.9  christos 				      ((flags & NS_FAILCACHE_CD) != 0) ? "CD=1"
   6734   1.9  christos 								       : "CD="
   6735   1.9  christos 									 "0");
   6736   1.1  christos 		}
   6737   1.1  christos 
   6738   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
   6739   1.1  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   6740   1.3  christos 		return (ns_query_done(qctx));
   6741   1.1  christos 	}
   6742   1.1  christos 
   6743   1.1  christos 	return (ISC_R_COMPLETE);
   6744   1.1  christos }
   6745   1.1  christos 
   6746   1.1  christos /*%
   6747   1.1  christos  * Handle response rate limiting (RRL).
   6748   1.1  christos  */
   6749   1.1  christos static isc_result_t
   6750   1.1  christos query_checkrrl(query_ctx_t *qctx, isc_result_t result) {
   6751   1.1  christos 	/*
   6752   1.1  christos 	 * Rate limit these responses to this client.
   6753   1.1  christos 	 * Do not delay counting and handling obvious referrals,
   6754   1.1  christos 	 *	since those won't come here again.
   6755   1.1  christos 	 * Delay handling delegations for which we are certain to recurse and
   6756   1.1  christos 	 *	return here (DNS_R_DELEGATION, not a child of one of our
   6757   1.1  christos 	 *	own zones, and recursion enabled)
   6758   1.1  christos 	 * Don't mess with responses rewritten by RPZ
   6759   1.1  christos 	 * Count each response at most once.
   6760   1.1  christos 	 */
   6761   1.3  christos 
   6762   1.3  christos 	/*
   6763   1.3  christos 	 * XXXMPA the rrl system tests fails sometimes and RRL_CHECKED
   6764   1.3  christos 	 * is set when we are called the second time preventing the
   6765   1.3  christos 	 * response being dropped.
   6766   1.3  christos 	 */
   6767   1.9  christos 	ns_client_log(
   6768   1.9  christos 		qctx->client, DNS_LOGCATEGORY_RRL, NS_LOGMODULE_QUERY,
   6769   1.9  christos 		ISC_LOG_DEBUG(99),
   6770   1.9  christos 		"rrl=%p, HAVECOOKIE=%u, result=%s, "
   6771   1.9  christos 		"fname=%p(%u), is_zone=%u, RECURSIONOK=%u, "
   6772   1.9  christos 		"query.rpz_st=%p(%u), RRL_CHECKED=%u\n",
   6773   1.9  christos 		qctx->client->view->rrl, HAVECOOKIE(qctx->client),
   6774   1.9  christos 		isc_result_toid(result), qctx->fname,
   6775   1.9  christos 		qctx->fname != NULL ? dns_name_isabsolute(qctx->fname) : 0,
   6776   1.9  christos 		qctx->is_zone, RECURSIONOK(qctx->client),
   6777   1.9  christos 		qctx->client->query.rpz_st,
   6778   1.9  christos 		qctx->client->query.rpz_st != NULL
   6779   1.9  christos 			? ((qctx->client->query.rpz_st->state &
   6780   1.9  christos 			    DNS_RPZ_REWRITTEN) != 0)
   6781   1.9  christos 			: 0,
   6782   1.9  christos 		(qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) !=
   6783   1.9  christos 			0);
   6784   1.3  christos 
   6785   1.9  christos 	if (qctx->view->rrl != NULL && !HAVECOOKIE(qctx->client) &&
   6786   1.1  christos 	    ((qctx->fname != NULL && dns_name_isabsolute(qctx->fname)) ||
   6787   1.1  christos 	     (result == ISC_R_NOTFOUND && !RECURSIONOK(qctx->client))) &&
   6788   1.9  christos 	    !(result == DNS_R_DELEGATION && !qctx->is_zone &&
   6789   1.9  christos 	      RECURSIONOK(qctx->client)) &&
   6790   1.1  christos 	    (qctx->client->query.rpz_st == NULL ||
   6791   1.1  christos 	     (qctx->client->query.rpz_st->state & DNS_RPZ_REWRITTEN) == 0) &&
   6792   1.1  christos 	    (qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) == 0)
   6793   1.1  christos 	{
   6794   1.1  christos 		dns_rdataset_t nc_rdataset;
   6795   1.3  christos 		bool wouldlog;
   6796   1.1  christos 		dns_fixedname_t fixed;
   6797   1.1  christos 		const dns_name_t *constname;
   6798   1.1  christos 		char log_buf[DNS_RRL_LOG_BUF_LEN];
   6799   1.1  christos 		isc_result_t nc_result, resp_result;
   6800   1.1  christos 		dns_rrl_result_t rrl_result;
   6801   1.1  christos 
   6802   1.1  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RRL_CHECKED;
   6803   1.1  christos 
   6804   1.1  christos 		wouldlog = isc_log_wouldlog(ns_lctx, DNS_RRL_LOG_DROP);
   6805   1.1  christos 		constname = qctx->fname;
   6806   1.1  christos 		if (result == DNS_R_NXDOMAIN) {
   6807   1.1  christos 			/*
   6808   1.1  christos 			 * Use the database origin name to rate limit NXDOMAIN
   6809   1.1  christos 			 */
   6810   1.9  christos 			if (qctx->db != NULL) {
   6811   1.1  christos 				constname = dns_db_origin(qctx->db);
   6812   1.9  christos 			}
   6813   1.1  christos 			resp_result = result;
   6814   1.1  christos 		} else if (result == DNS_R_NCACHENXDOMAIN &&
   6815   1.1  christos 			   qctx->rdataset != NULL &&
   6816   1.1  christos 			   dns_rdataset_isassociated(qctx->rdataset) &&
   6817   1.1  christos 			   (qctx->rdataset->attributes &
   6818   1.9  christos 			    DNS_RDATASETATTR_NEGATIVE) != 0)
   6819   1.9  christos 		{
   6820   1.1  christos 			/*
   6821   1.1  christos 			 * Try to use owner name in the negative cache SOA.
   6822   1.1  christos 			 */
   6823   1.1  christos 			dns_fixedname_init(&fixed);
   6824   1.1  christos 			dns_rdataset_init(&nc_rdataset);
   6825   1.1  christos 			for (nc_result = dns_rdataset_first(qctx->rdataset);
   6826   1.1  christos 			     nc_result == ISC_R_SUCCESS;
   6827   1.1  christos 			     nc_result = dns_rdataset_next(qctx->rdataset))
   6828   1.1  christos 			{
   6829   1.1  christos 				dns_ncache_current(qctx->rdataset,
   6830   1.1  christos 						   dns_fixedname_name(&fixed),
   6831   1.1  christos 						   &nc_rdataset);
   6832   1.1  christos 				if (nc_rdataset.type == dns_rdatatype_soa) {
   6833   1.1  christos 					dns_rdataset_disassociate(&nc_rdataset);
   6834   1.1  christos 					constname = dns_fixedname_name(&fixed);
   6835   1.1  christos 					break;
   6836   1.1  christos 				}
   6837   1.1  christos 				dns_rdataset_disassociate(&nc_rdataset);
   6838   1.1  christos 			}
   6839   1.1  christos 			resp_result = DNS_R_NXDOMAIN;
   6840   1.9  christos 		} else if (result == DNS_R_NXRRSET || result == DNS_R_EMPTYNAME)
   6841   1.9  christos 		{
   6842   1.1  christos 			resp_result = DNS_R_NXRRSET;
   6843   1.1  christos 		} else if (result == DNS_R_DELEGATION) {
   6844   1.1  christos 			resp_result = result;
   6845   1.1  christos 		} else if (result == ISC_R_NOTFOUND) {
   6846   1.1  christos 			/*
   6847   1.1  christos 			 * Handle referral to ".", including when recursion
   6848   1.1  christos 			 * is off or not requested and the hints have not
   6849   1.1  christos 			 * been loaded or we have "additional-from-cache no".
   6850   1.1  christos 			 */
   6851   1.1  christos 			constname = dns_rootname;
   6852   1.1  christos 			resp_result = DNS_R_DELEGATION;
   6853   1.1  christos 		} else {
   6854   1.1  christos 			resp_result = ISC_R_SUCCESS;
   6855   1.1  christos 		}
   6856   1.1  christos 
   6857   1.9  christos 		rrl_result = dns_rrl(
   6858  1.15  christos 			qctx->view, qctx->zone, &qctx->client->peeraddr,
   6859  1.15  christos 			TCP(qctx->client), qctx->client->message->rdclass,
   6860  1.15  christos 			qctx->qtype, constname, resp_result, qctx->client->now,
   6861  1.15  christos 			wouldlog, log_buf, sizeof(log_buf));
   6862   1.1  christos 		if (rrl_result != DNS_RRL_RESULT_OK) {
   6863   1.1  christos 			/*
   6864   1.1  christos 			 * Log dropped or slipped responses in the query
   6865   1.1  christos 			 * category so that requests are not silently lost.
   6866   1.1  christos 			 * Starts of rate-limited bursts are logged in
   6867   1.1  christos 			 * DNS_LOGCATEGORY_RRL.
   6868   1.1  christos 			 *
   6869   1.1  christos 			 * Dropped responses are counted with dropped queries
   6870   1.1  christos 			 * in QryDropped while slipped responses are counted
   6871   1.1  christos 			 * with other truncated responses in RespTruncated.
   6872   1.1  christos 			 */
   6873   1.1  christos 			if (wouldlog) {
   6874   1.1  christos 				ns_client_log(qctx->client, DNS_LOGCATEGORY_RRL,
   6875   1.1  christos 					      NS_LOGMODULE_QUERY,
   6876   1.9  christos 					      DNS_RRL_LOG_DROP, "%s", log_buf);
   6877   1.1  christos 			}
   6878   1.1  christos 
   6879   1.3  christos 			if (!qctx->view->rrl->log_only) {
   6880   1.1  christos 				if (rrl_result == DNS_RRL_RESULT_DROP) {
   6881   1.1  christos 					/*
   6882   1.1  christos 					 * These will also be counted in
   6883   1.1  christos 					 * ns_statscounter_dropped
   6884   1.1  christos 					 */
   6885   1.1  christos 					inc_stats(qctx->client,
   6886   1.9  christos 						  ns_statscounter_ratedropped);
   6887   1.1  christos 					QUERY_ERROR(qctx, DNS_R_DROP);
   6888   1.1  christos 				} else {
   6889   1.1  christos 					/*
   6890   1.1  christos 					 * These will also be counted in
   6891   1.1  christos 					 * ns_statscounter_truncatedresp
   6892   1.1  christos 					 */
   6893   1.1  christos 					inc_stats(qctx->client,
   6894   1.9  christos 						  ns_statscounter_rateslipped);
   6895   1.1  christos 					if (WANTCOOKIE(qctx->client)) {
   6896   1.1  christos 						qctx->client->message->flags &=
   6897   1.1  christos 							~DNS_MESSAGEFLAG_AA;
   6898   1.1  christos 						qctx->client->message->flags &=
   6899   1.1  christos 							~DNS_MESSAGEFLAG_AD;
   6900   1.1  christos 						qctx->client->message->rcode =
   6901   1.9  christos 							dns_rcode_badcookie;
   6902   1.1  christos 					} else {
   6903   1.1  christos 						qctx->client->message->flags |=
   6904   1.1  christos 							DNS_MESSAGEFLAG_TC;
   6905   1.1  christos 						if (resp_result ==
   6906  1.16  christos 						    DNS_R_NXDOMAIN)
   6907  1.16  christos 						{
   6908   1.9  christos 							qctx->client->message
   6909   1.9  christos 								->rcode =
   6910   1.9  christos 								dns_rcode_nxdomain;
   6911   1.1  christos 						}
   6912   1.1  christos 					}
   6913   1.1  christos 				}
   6914   1.1  christos 				return (DNS_R_DROP);
   6915   1.1  christos 			}
   6916   1.1  christos 		}
   6917   1.1  christos 	}
   6918   1.1  christos 
   6919   1.1  christos 	return (ISC_R_SUCCESS);
   6920   1.1  christos }
   6921   1.1  christos 
   6922   1.1  christos /*%
   6923   1.1  christos  * Do any RPZ rewriting that may be needed for this query.
   6924   1.1  christos  */
   6925   1.1  christos static isc_result_t
   6926   1.1  christos query_checkrpz(query_ctx_t *qctx, isc_result_t result) {
   6927   1.1  christos 	isc_result_t rresult;
   6928   1.1  christos 
   6929   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_checkrpz");
   6930   1.9  christos 
   6931   1.9  christos 	rresult = rpz_rewrite(qctx->client, qctx->qtype, result, qctx->resuming,
   6932   1.1  christos 			      qctx->rdataset, qctx->sigrdataset);
   6933   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   6934   1.1  christos 	switch (rresult) {
   6935   1.1  christos 	case ISC_R_SUCCESS:
   6936   1.1  christos 		break;
   6937  1.13  christos 	case ISC_R_NOTFOUND:
   6938   1.1  christos 	case DNS_R_DISALLOWED:
   6939   1.1  christos 		return (result);
   6940   1.1  christos 	case DNS_R_DELEGATION:
   6941   1.1  christos 		/*
   6942   1.1  christos 		 * recursing for NS names or addresses,
   6943   1.1  christos 		 * so save the main query state
   6944   1.1  christos 		 */
   6945  1.13  christos 		INSIST(!RECURSING(qctx->client));
   6946   1.1  christos 		qctx->rpz_st->q.qtype = qctx->qtype;
   6947   1.1  christos 		qctx->rpz_st->q.is_zone = qctx->is_zone;
   6948   1.1  christos 		qctx->rpz_st->q.authoritative = qctx->authoritative;
   6949   1.1  christos 		SAVE(qctx->rpz_st->q.zone, qctx->zone);
   6950   1.1  christos 		SAVE(qctx->rpz_st->q.db, qctx->db);
   6951   1.1  christos 		SAVE(qctx->rpz_st->q.node, qctx->node);
   6952   1.1  christos 		SAVE(qctx->rpz_st->q.rdataset, qctx->rdataset);
   6953   1.1  christos 		SAVE(qctx->rpz_st->q.sigrdataset, qctx->sigrdataset);
   6954   1.8  christos 		dns_name_copynf(qctx->fname, qctx->rpz_st->fname);
   6955   1.1  christos 		qctx->rpz_st->q.result = result;
   6956   1.1  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   6957   1.1  christos 		return (ISC_R_COMPLETE);
   6958   1.1  christos 	default:
   6959   1.3  christos 		QUERY_ERROR(qctx, rresult);
   6960   1.3  christos 		return (ISC_R_COMPLETE);
   6961   1.1  christos 	}
   6962   1.1  christos 
   6963   1.1  christos 	if (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS) {
   6964   1.1  christos 		qctx->rpz_st->state |= DNS_RPZ_REWRITTEN;
   6965   1.1  christos 	}
   6966   1.1  christos 
   6967   1.1  christos 	if (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_MISS &&
   6968   1.1  christos 	    qctx->rpz_st->m.policy != DNS_RPZ_POLICY_PASSTHRU &&
   6969   1.1  christos 	    (qctx->rpz_st->m.policy != DNS_RPZ_POLICY_TCP_ONLY ||
   6970   1.1  christos 	     !TCP(qctx->client)) &&
   6971   1.1  christos 	    qctx->rpz_st->m.policy != DNS_RPZ_POLICY_ERROR)
   6972   1.1  christos 	{
   6973   1.1  christos 		/*
   6974   1.1  christos 		 * We got a hit and are going to answer with our
   6975   1.1  christos 		 * fiction. Ensure that we answer with the name
   6976   1.1  christos 		 * we looked up even if we were stopped short
   6977   1.1  christos 		 * in recursion or for a deferral.
   6978   1.1  christos 		 */
   6979   1.8  christos 		dns_name_copynf(qctx->client->query.qname, qctx->fname);
   6980   1.1  christos 		rpz_clean(&qctx->zone, &qctx->db, &qctx->node, NULL);
   6981   1.1  christos 		if (qctx->rpz_st->m.rdataset != NULL) {
   6982   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   6983   1.1  christos 			RESTORE(qctx->rdataset, qctx->rpz_st->m.rdataset);
   6984   1.1  christos 		} else {
   6985   1.1  christos 			qctx_clean(qctx);
   6986   1.1  christos 		}
   6987   1.1  christos 		qctx->version = NULL;
   6988   1.1  christos 
   6989   1.1  christos 		RESTORE(qctx->node, qctx->rpz_st->m.node);
   6990   1.1  christos 		RESTORE(qctx->db, qctx->rpz_st->m.db);
   6991   1.1  christos 		RESTORE(qctx->version, qctx->rpz_st->m.version);
   6992   1.1  christos 		RESTORE(qctx->zone, qctx->rpz_st->m.zone);
   6993   1.1  christos 
   6994   1.1  christos 		/*
   6995   1.1  christos 		 * Add SOA record to additional section
   6996   1.1  christos 		 */
   6997   1.5  christos 		if (qctx->rpz_st->m.rpz->addsoa) {
   6998   1.5  christos 			bool override_ttl =
   6999   1.9  christos 				dns_rdataset_isassociated(qctx->rdataset);
   7000   1.5  christos 			rresult = query_addsoa(qctx, override_ttl,
   7001   1.5  christos 					       DNS_SECTION_ADDITIONAL);
   7002   1.5  christos 			if (rresult != ISC_R_SUCCESS) {
   7003   1.5  christos 				QUERY_ERROR(qctx, result);
   7004   1.5  christos 				return (ISC_R_COMPLETE);
   7005   1.5  christos 			}
   7006   1.1  christos 		}
   7007   1.1  christos 
   7008   1.1  christos 		switch (qctx->rpz_st->m.policy) {
   7009   1.1  christos 		case DNS_RPZ_POLICY_TCP_ONLY:
   7010   1.1  christos 			qctx->client->message->flags |= DNS_MESSAGEFLAG_TC;
   7011   1.1  christos 			if (result == DNS_R_NXDOMAIN ||
   7012  1.16  christos 			    result == DNS_R_NCACHENXDOMAIN)
   7013  1.16  christos 			{
   7014   1.1  christos 				qctx->client->message->rcode =
   7015   1.9  christos 					dns_rcode_nxdomain;
   7016   1.9  christos 			}
   7017   1.3  christos 			rpz_log_rewrite(qctx->client, false,
   7018   1.1  christos 					qctx->rpz_st->m.policy,
   7019   1.1  christos 					qctx->rpz_st->m.type, qctx->zone,
   7020   1.1  christos 					qctx->rpz_st->p_name, NULL,
   7021   1.1  christos 					qctx->rpz_st->m.rpz->num);
   7022   1.1  christos 			return (ISC_R_COMPLETE);
   7023   1.1  christos 		case DNS_RPZ_POLICY_DROP:
   7024   1.1  christos 			QUERY_ERROR(qctx, DNS_R_DROP);
   7025   1.3  christos 			rpz_log_rewrite(qctx->client, false,
   7026   1.1  christos 					qctx->rpz_st->m.policy,
   7027   1.1  christos 					qctx->rpz_st->m.type, qctx->zone,
   7028   1.1  christos 					qctx->rpz_st->p_name, NULL,
   7029   1.1  christos 					qctx->rpz_st->m.rpz->num);
   7030   1.1  christos 			return (ISC_R_COMPLETE);
   7031   1.1  christos 		case DNS_RPZ_POLICY_NXDOMAIN:
   7032   1.1  christos 			result = DNS_R_NXDOMAIN;
   7033   1.3  christos 			qctx->nxrewrite = true;
   7034   1.3  christos 			qctx->rpz = true;
   7035   1.1  christos 			break;
   7036   1.1  christos 		case DNS_RPZ_POLICY_NODATA:
   7037   1.6  christos 			qctx->nxrewrite = true;
   7038  1.15  christos 			FALLTHROUGH;
   7039   1.6  christos 		case DNS_RPZ_POLICY_DNS64:
   7040   1.1  christos 			result = DNS_R_NXRRSET;
   7041   1.3  christos 			qctx->rpz = true;
   7042   1.1  christos 			break;
   7043   1.1  christos 		case DNS_RPZ_POLICY_RECORD:
   7044   1.1  christos 			result = qctx->rpz_st->m.result;
   7045   1.1  christos 			if (qctx->qtype == dns_rdatatype_any &&
   7046  1.16  christos 			    result != DNS_R_CNAME)
   7047  1.16  christos 			{
   7048   1.1  christos 				/*
   7049   1.1  christos 				 * We will add all of the rdatasets of
   7050   1.1  christos 				 * the node by iterating later,
   7051   1.1  christos 				 * and set the TTL then.
   7052   1.1  christos 				 */
   7053   1.9  christos 				if (dns_rdataset_isassociated(qctx->rdataset)) {
   7054   1.9  christos 					dns_rdataset_disassociate(
   7055   1.9  christos 						qctx->rdataset);
   7056   1.9  christos 				}
   7057   1.1  christos 			} else {
   7058   1.1  christos 				/*
   7059   1.1  christos 				 * We will add this rdataset.
   7060   1.1  christos 				 */
   7061   1.1  christos 				qctx->rdataset->ttl =
   7062   1.1  christos 					ISC_MIN(qctx->rdataset->ttl,
   7063   1.1  christos 						qctx->rpz_st->m.ttl);
   7064   1.1  christos 			}
   7065   1.3  christos 			qctx->rpz = true;
   7066   1.1  christos 			break;
   7067   1.1  christos 		case DNS_RPZ_POLICY_WILDCNAME: {
   7068   1.1  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   7069   1.1  christos 			dns_rdata_cname_t cname;
   7070   1.1  christos 			result = dns_rdataset_first(qctx->rdataset);
   7071   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7072   1.1  christos 			dns_rdataset_current(qctx->rdataset, &rdata);
   7073   1.9  christos 			result = dns_rdata_tostruct(&rdata, &cname, NULL);
   7074   1.1  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7075   1.1  christos 			dns_rdata_reset(&rdata);
   7076   1.1  christos 			result = query_rpzcname(qctx, &cname.cname);
   7077   1.9  christos 			if (result != ISC_R_SUCCESS) {
   7078   1.1  christos 				return (ISC_R_COMPLETE);
   7079   1.9  christos 			}
   7080   1.1  christos 			qctx->fname = NULL;
   7081   1.3  christos 			qctx->want_restart = true;
   7082   1.1  christos 			return (ISC_R_COMPLETE);
   7083   1.1  christos 		}
   7084   1.1  christos 		case DNS_RPZ_POLICY_CNAME:
   7085   1.1  christos 			/*
   7086   1.9  christos 			 * Add overriding CNAME from a named.conf
   7087   1.1  christos 			 * response-policy statement
   7088   1.1  christos 			 */
   7089   1.1  christos 			result = query_rpzcname(qctx,
   7090   1.1  christos 						&qctx->rpz_st->m.rpz->cname);
   7091   1.9  christos 			if (result != ISC_R_SUCCESS) {
   7092   1.1  christos 				return (ISC_R_COMPLETE);
   7093   1.9  christos 			}
   7094   1.1  christos 			qctx->fname = NULL;
   7095   1.3  christos 			qctx->want_restart = true;
   7096   1.1  christos 			return (ISC_R_COMPLETE);
   7097   1.1  christos 		default:
   7098  1.15  christos 			UNREACHABLE();
   7099   1.1  christos 		}
   7100   1.1  christos 
   7101   1.1  christos 		/*
   7102   1.1  christos 		 * Turn off DNSSEC because the results of a
   7103   1.1  christos 		 * response policy zone cannot verify.
   7104   1.1  christos 		 */
   7105   1.1  christos 		qctx->client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC |
   7106   1.1  christos 					      NS_CLIENTATTR_WANTAD);
   7107   1.1  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD;
   7108   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   7109   1.1  christos 		qctx->rpz_st->q.is_zone = qctx->is_zone;
   7110   1.3  christos 		qctx->is_zone = true;
   7111   1.9  christos 		rpz_log_rewrite(qctx->client, false, qctx->rpz_st->m.policy,
   7112   1.1  christos 				qctx->rpz_st->m.type, qctx->zone,
   7113   1.1  christos 				qctx->rpz_st->p_name, NULL,
   7114   1.1  christos 				qctx->rpz_st->m.rpz->num);
   7115   1.1  christos 	}
   7116   1.1  christos 
   7117   1.1  christos 	return (result);
   7118   1.1  christos }
   7119   1.1  christos 
   7120   1.1  christos /*%
   7121   1.1  christos  * Add a CNAME to a query response, including translating foo.evil.com and
   7122   1.1  christos  *	*.evil.com CNAME *.example.com
   7123   1.1  christos  * to
   7124   1.1  christos  *	foo.evil.com CNAME foo.evil.com.example.com
   7125   1.1  christos  */
   7126   1.1  christos static isc_result_t
   7127   1.1  christos query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) {
   7128   1.6  christos 	ns_client_t *client;
   7129   1.1  christos 	dns_fixedname_t prefix, suffix;
   7130   1.1  christos 	unsigned int labels;
   7131   1.1  christos 	isc_result_t result;
   7132   1.1  christos 
   7133   1.6  christos 	REQUIRE(qctx != NULL && qctx->client != NULL);
   7134   1.6  christos 
   7135   1.6  christos 	client = qctx->client;
   7136   1.6  christos 
   7137   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_rpzcname");
   7138   1.1  christos 
   7139   1.1  christos 	labels = dns_name_countlabels(cname);
   7140   1.1  christos 	if (labels > 2 && dns_name_iswildcard(cname)) {
   7141   1.1  christos 		dns_fixedname_init(&prefix);
   7142   1.1  christos 		dns_name_split(client->query.qname, 1,
   7143   1.1  christos 			       dns_fixedname_name(&prefix), NULL);
   7144   1.1  christos 		dns_fixedname_init(&suffix);
   7145   1.9  christos 		dns_name_split(cname, labels - 1, NULL,
   7146   1.9  christos 			       dns_fixedname_name(&suffix));
   7147   1.1  christos 		result = dns_name_concatenate(dns_fixedname_name(&prefix),
   7148   1.1  christos 					      dns_fixedname_name(&suffix),
   7149   1.1  christos 					      qctx->fname, NULL);
   7150   1.1  christos 		if (result == DNS_R_NAMETOOLONG) {
   7151   1.1  christos 			client->message->rcode = dns_rcode_yxdomain;
   7152   1.1  christos 		} else if (result != ISC_R_SUCCESS) {
   7153   1.1  christos 			return (result);
   7154   1.1  christos 		}
   7155   1.1  christos 	} else {
   7156   1.8  christos 		dns_name_copynf(cname, qctx->fname);
   7157   1.1  christos 	}
   7158   1.1  christos 
   7159   1.3  christos 	ns_client_keepname(client, qctx->fname, qctx->dbuf);
   7160   1.1  christos 	result = query_addcname(qctx, dns_trust_authanswer,
   7161   1.1  christos 				qctx->rpz_st->m.ttl);
   7162   1.1  christos 	if (result != ISC_R_SUCCESS) {
   7163   1.1  christos 		return (result);
   7164   1.1  christos 	}
   7165   1.1  christos 
   7166   1.3  christos 	rpz_log_rewrite(client, false, qctx->rpz_st->m.policy,
   7167   1.1  christos 			qctx->rpz_st->m.type, qctx->rpz_st->m.zone,
   7168   1.1  christos 			qctx->rpz_st->p_name, qctx->fname,
   7169   1.1  christos 			qctx->rpz_st->m.rpz->num);
   7170   1.1  christos 
   7171   1.1  christos 	ns_client_qnamereplace(client, qctx->fname);
   7172   1.1  christos 
   7173   1.1  christos 	/*
   7174   1.1  christos 	 * Turn off DNSSEC because the results of a
   7175   1.1  christos 	 * response policy zone cannot verify.
   7176   1.1  christos 	 */
   7177   1.1  christos 	client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC |
   7178   1.1  christos 				NS_CLIENTATTR_WANTAD);
   7179   1.1  christos 
   7180   1.1  christos 	return (ISC_R_SUCCESS);
   7181   1.1  christos }
   7182   1.1  christos 
   7183   1.1  christos /*%
   7184   1.1  christos  * Check the configured trust anchors for a root zone trust anchor
   7185   1.1  christos  * with a key id that matches qctx->client->query.root_key_sentinel_keyid.
   7186   1.1  christos  *
   7187   1.3  christos  * Return true when found, otherwise return false.
   7188   1.1  christos  */
   7189   1.3  christos static bool
   7190   1.1  christos has_ta(query_ctx_t *qctx) {
   7191   1.1  christos 	dns_keytable_t *keytable = NULL;
   7192   1.1  christos 	dns_keynode_t *keynode = NULL;
   7193  1.10  christos 	dns_rdataset_t dsset;
   7194   1.9  christos 	dns_keytag_t sentinel = qctx->client->query.root_key_sentinel_keyid;
   7195   1.1  christos 	isc_result_t result;
   7196   1.1  christos 
   7197   1.3  christos 	result = dns_view_getsecroots(qctx->view, &keytable);
   7198   1.1  christos 	if (result != ISC_R_SUCCESS) {
   7199   1.3  christos 		return (false);
   7200   1.1  christos 	}
   7201   1.1  christos 
   7202   1.1  christos 	result = dns_keytable_find(keytable, dns_rootname, &keynode);
   7203   1.9  christos 	if (result != ISC_R_SUCCESS) {
   7204   1.9  christos 		if (keynode != NULL) {
   7205   1.1  christos 			dns_keytable_detachkeynode(keytable, &keynode);
   7206   1.1  christos 		}
   7207   1.9  christos 		dns_keytable_detach(&keytable);
   7208   1.9  christos 		return (false);
   7209   1.9  christos 	}
   7210   1.9  christos 
   7211  1.10  christos 	dns_rdataset_init(&dsset);
   7212  1.10  christos 	if (dns_keynode_dsset(keynode, &dsset)) {
   7213  1.10  christos 		for (result = dns_rdataset_first(&dsset);
   7214  1.10  christos 		     result == ISC_R_SUCCESS;
   7215  1.10  christos 		     result = dns_rdataset_next(&dsset))
   7216   1.9  christos 		{
   7217   1.9  christos 			dns_rdata_t rdata = DNS_RDATA_INIT;
   7218   1.9  christos 			dns_rdata_ds_t ds;
   7219   1.9  christos 
   7220   1.9  christos 			dns_rdata_reset(&rdata);
   7221  1.10  christos 			dns_rdataset_current(&dsset, &rdata);
   7222   1.9  christos 			result = dns_rdata_tostruct(&rdata, &ds, NULL);
   7223   1.9  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7224   1.9  christos 			if (ds.key_tag == sentinel) {
   7225   1.9  christos 				dns_keytable_detachkeynode(keytable, &keynode);
   7226   1.9  christos 				dns_keytable_detach(&keytable);
   7227  1.10  christos 				dns_rdataset_disassociate(&dsset);
   7228   1.9  christos 				return (true);
   7229   1.9  christos 			}
   7230   1.9  christos 		}
   7231  1.10  christos 		dns_rdataset_disassociate(&dsset);
   7232   1.9  christos 	}
   7233   1.9  christos 
   7234   1.9  christos 	if (keynode != NULL) {
   7235   1.1  christos 		dns_keytable_detachkeynode(keytable, &keynode);
   7236   1.1  christos 	}
   7237   1.9  christos 
   7238   1.1  christos 	dns_keytable_detach(&keytable);
   7239   1.1  christos 
   7240   1.3  christos 	return (false);
   7241   1.1  christos }
   7242   1.1  christos 
   7243   1.1  christos /*%
   7244   1.1  christos  * Check if a root key sentinel SERVFAIL should be returned.
   7245   1.1  christos  */
   7246   1.3  christos static bool
   7247   1.1  christos root_key_sentinel_return_servfail(query_ctx_t *qctx, isc_result_t result) {
   7248   1.1  christos 	/*
   7249   1.1  christos 	 * Are we looking at a "root-key-sentinel" query?
   7250   1.1  christos 	 */
   7251   1.1  christos 	if (!qctx->client->query.root_key_sentinel_is_ta &&
   7252   1.1  christos 	    !qctx->client->query.root_key_sentinel_not_ta)
   7253   1.1  christos 	{
   7254   1.3  christos 		return (false);
   7255   1.1  christos 	}
   7256   1.1  christos 
   7257   1.1  christos 	/*
   7258   1.1  christos 	 * We only care about the query if 'result' indicates we have a cached
   7259   1.1  christos 	 * answer.
   7260   1.1  christos 	 */
   7261   1.1  christos 	switch (result) {
   7262   1.1  christos 	case ISC_R_SUCCESS:
   7263   1.1  christos 	case DNS_R_CNAME:
   7264   1.1  christos 	case DNS_R_DNAME:
   7265   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   7266   1.1  christos 	case DNS_R_NCACHENXRRSET:
   7267   1.1  christos 		break;
   7268   1.1  christos 	default:
   7269   1.3  christos 		return (false);
   7270   1.1  christos 	}
   7271   1.1  christos 
   7272   1.1  christos 	/*
   7273   1.1  christos 	 * Do we meet the specified conditions to return SERVFAIL?
   7274   1.1  christos 	 */
   7275   1.9  christos 	if (!qctx->is_zone && qctx->rdataset->trust == dns_trust_secure &&
   7276   1.1  christos 	    ((qctx->client->query.root_key_sentinel_is_ta && !has_ta(qctx)) ||
   7277   1.1  christos 	     (qctx->client->query.root_key_sentinel_not_ta && has_ta(qctx))))
   7278   1.1  christos 	{
   7279   1.3  christos 		return (true);
   7280   1.1  christos 	}
   7281   1.1  christos 
   7282   1.1  christos 	/*
   7283   1.1  christos 	 * As special processing may only be triggered by the original QNAME,
   7284   1.1  christos 	 * disable it after following a CNAME/DNAME.
   7285   1.1  christos 	 */
   7286   1.3  christos 	qctx->client->query.root_key_sentinel_is_ta = false;
   7287   1.3  christos 	qctx->client->query.root_key_sentinel_not_ta = false;
   7288   1.1  christos 
   7289   1.3  christos 	return (false);
   7290   1.1  christos }
   7291   1.1  christos 
   7292   1.1  christos /*%
   7293   1.3  christos  * If serving stale answers is allowed, set up 'qctx' to look for one and
   7294   1.3  christos  * return true; otherwise, return false.
   7295   1.3  christos  */
   7296   1.3  christos static bool
   7297  1.13  christos query_usestale(query_ctx_t *qctx, isc_result_t result) {
   7298  1.13  christos 	if ((qctx->client->query.dboptions & DNS_DBFIND_STALEOK) != 0) {
   7299  1.13  christos 		/*
   7300  1.13  christos 		 * Query was already using stale, if that didn't work the
   7301  1.13  christos 		 * last time, it won't work this time either.
   7302  1.13  christos 		 */
   7303  1.13  christos 		return (false);
   7304  1.13  christos 	}
   7305  1.13  christos 
   7306  1.17  christos 	if (qctx->refresh_rrset) {
   7307  1.17  christos 		/*
   7308  1.17  christos 		 * This is a refreshing query, we have already prioritized
   7309  1.17  christos 		 * stale data, so don't enable serve-stale again.
   7310  1.17  christos 		 */
   7311  1.17  christos 		return (false);
   7312  1.17  christos 	}
   7313  1.17  christos 
   7314  1.17  christos 	if (result == DNS_R_DUPLICATE || result == DNS_R_DROP ||
   7315  1.17  christos 	    result == ISC_R_ALREADYRUNNING)
   7316  1.17  christos 	{
   7317  1.15  christos 		/*
   7318  1.15  christos 		 * Don't enable serve-stale if the result signals a duplicate
   7319  1.17  christos 		 * query or a query that is being dropped or can't proceed
   7320  1.17  christos 		 * because of a recursion loop.
   7321  1.15  christos 		 */
   7322  1.15  christos 		return (false);
   7323  1.15  christos 	}
   7324  1.15  christos 
   7325   1.3  christos 	qctx_clean(qctx);
   7326   1.3  christos 	qctx_freedata(qctx);
   7327   1.3  christos 
   7328  1.11  christos 	if (dns_view_staleanswerenabled(qctx->client->view)) {
   7329  1.11  christos 		dns_db_attach(qctx->client->view->cachedb, &qctx->db);
   7330  1.13  christos 		qctx->version = NULL;
   7331   1.3  christos 		qctx->client->query.dboptions |= DNS_DBFIND_STALEOK;
   7332   1.3  christos 		if (qctx->client->query.fetch != NULL) {
   7333   1.3  christos 			dns_resolver_destroyfetch(&qctx->client->query.fetch);
   7334   1.3  christos 		}
   7335  1.11  christos 
   7336  1.13  christos 		/*
   7337  1.13  christos 		 * Start the stale-refresh-time window in case there was a
   7338  1.13  christos 		 * resolver query timeout.
   7339  1.13  christos 		 */
   7340  1.13  christos 		if (qctx->resuming && result == ISC_R_TIMEDOUT) {
   7341  1.13  christos 			qctx->client->query.dboptions |= DNS_DBFIND_STALESTART;
   7342  1.13  christos 		}
   7343  1.11  christos 		return (true);
   7344   1.3  christos 	}
   7345   1.3  christos 
   7346  1.11  christos 	return (false);
   7347   1.3  christos }
   7348   1.3  christos 
   7349   1.3  christos /*%
   7350   1.3  christos  * Continue after doing a database lookup or returning from
   7351   1.3  christos  * recursion, and call out to the next function depending on the
   7352   1.3  christos  * result from the search.
   7353   1.1  christos  */
   7354   1.1  christos static isc_result_t
   7355  1.18  christos query_gotanswer(query_ctx_t *qctx, isc_result_t result) {
   7356   1.1  christos 	char errmsg[256];
   7357   1.1  christos 
   7358   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer");
   7359   1.1  christos 
   7360   1.3  christos 	CALL_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx);
   7361   1.3  christos 
   7362   1.1  christos 	if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) {
   7363   1.3  christos 		return (ns_query_done(qctx));
   7364   1.1  christos 	}
   7365   1.1  christos 
   7366  1.13  christos 	if (!dns_name_equal(qctx->client->query.qname, dns_rootname)) {
   7367   1.1  christos 		result = query_checkrpz(qctx, result);
   7368  1.13  christos 		if (result == ISC_R_NOTFOUND) {
   7369  1.13  christos 			/*
   7370  1.13  christos 			 * RPZ not configured for this view.
   7371  1.13  christos 			 */
   7372  1.13  christos 			goto root_key_sentinel;
   7373  1.13  christos 		}
   7374  1.13  christos 		if (RECURSING(qctx->client) && result == DNS_R_DISALLOWED) {
   7375  1.13  christos 			/*
   7376  1.13  christos 			 * We are recursing, and thus RPZ processing is not
   7377  1.13  christos 			 * allowed at the moment. This could happen on a
   7378  1.13  christos 			 * "stale-answer-client-timeout" lookup. In this case,
   7379  1.13  christos 			 * bail out and wait for recursion to complete, as we
   7380  1.13  christos 			 * we can't perform the RPZ rewrite rules.
   7381  1.13  christos 			 */
   7382  1.13  christos 			return (result);
   7383  1.13  christos 		}
   7384   1.3  christos 		if (result == ISC_R_COMPLETE) {
   7385   1.3  christos 			return (ns_query_done(qctx));
   7386   1.3  christos 		}
   7387   1.1  christos 	}
   7388   1.1  christos 
   7389  1.13  christos root_key_sentinel:
   7390   1.1  christos 	/*
   7391   1.1  christos 	 * If required, handle special "root-key-sentinel-is-ta-<keyid>" and
   7392   1.1  christos 	 * "root-key-sentinel-not-ta-<keyid>" labels by returning SERVFAIL.
   7393   1.1  christos 	 */
   7394   1.1  christos 	if (root_key_sentinel_return_servfail(qctx, result)) {
   7395   1.1  christos 		/*
   7396   1.1  christos 		 * Don't record this response in the SERVFAIL cache.
   7397   1.1  christos 		 */
   7398   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_NOSETFC;
   7399   1.1  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   7400   1.3  christos 		return (ns_query_done(qctx));
   7401   1.1  christos 	}
   7402   1.1  christos 
   7403   1.1  christos 	switch (result) {
   7404   1.1  christos 	case ISC_R_SUCCESS:
   7405   1.1  christos 		return (query_prepresponse(qctx));
   7406   1.1  christos 
   7407   1.1  christos 	case DNS_R_GLUE:
   7408   1.1  christos 	case DNS_R_ZONECUT:
   7409   1.1  christos 		INSIST(qctx->is_zone);
   7410   1.3  christos 		qctx->authoritative = false;
   7411   1.1  christos 		return (query_prepresponse(qctx));
   7412   1.1  christos 
   7413   1.1  christos 	case ISC_R_NOTFOUND:
   7414   1.1  christos 		return (query_notfound(qctx));
   7415   1.1  christos 
   7416   1.1  christos 	case DNS_R_DELEGATION:
   7417   1.1  christos 		return (query_delegation(qctx));
   7418   1.1  christos 
   7419   1.1  christos 	case DNS_R_EMPTYNAME:
   7420   1.1  christos 		return (query_nodata(qctx, DNS_R_EMPTYNAME));
   7421   1.1  christos 	case DNS_R_NXRRSET:
   7422   1.1  christos 		return (query_nodata(qctx, DNS_R_NXRRSET));
   7423   1.1  christos 
   7424   1.1  christos 	case DNS_R_EMPTYWILD:
   7425  1.18  christos 		return (query_nxdomain(qctx, DNS_R_EMPTYWILD));
   7426   1.1  christos 
   7427   1.1  christos 	case DNS_R_NXDOMAIN:
   7428  1.18  christos 		return (query_nxdomain(qctx, DNS_R_NXDOMAIN));
   7429   1.1  christos 
   7430   1.1  christos 	case DNS_R_COVERINGNSEC:
   7431   1.1  christos 		return (query_coveringnsec(qctx));
   7432   1.1  christos 
   7433   1.1  christos 	case DNS_R_NCACHENXDOMAIN:
   7434  1.18  christos 		result = query_redirect(qctx, result);
   7435   1.9  christos 		if (result != ISC_R_COMPLETE) {
   7436   1.1  christos 			return (result);
   7437   1.9  christos 		}
   7438   1.1  christos 		return (query_ncache(qctx, DNS_R_NCACHENXDOMAIN));
   7439   1.1  christos 
   7440   1.1  christos 	case DNS_R_NCACHENXRRSET:
   7441   1.1  christos 		return (query_ncache(qctx, DNS_R_NCACHENXRRSET));
   7442   1.1  christos 
   7443   1.1  christos 	case DNS_R_CNAME:
   7444   1.1  christos 		return (query_cname(qctx));
   7445   1.1  christos 
   7446   1.1  christos 	case DNS_R_DNAME:
   7447   1.1  christos 		return (query_dname(qctx));
   7448   1.1  christos 
   7449   1.1  christos 	default:
   7450   1.1  christos 		/*
   7451   1.1  christos 		 * Something has gone wrong.
   7452   1.1  christos 		 */
   7453   1.1  christos 		snprintf(errmsg, sizeof(errmsg) - 1,
   7454   1.1  christos 			 "query_gotanswer: unexpected error: %s",
   7455   1.1  christos 			 isc_result_totext(result));
   7456   1.1  christos 		CCTRACE(ISC_LOG_ERROR, errmsg);
   7457  1.13  christos 		if (query_usestale(qctx, result)) {
   7458   1.3  christos 			/*
   7459   1.3  christos 			 * If serve-stale is enabled, query_usestale() already
   7460   1.3  christos 			 * set up 'qctx' for looking up a stale response.
   7461   1.3  christos 			 */
   7462   1.3  christos 			return (query_lookup(qctx));
   7463   1.1  christos 		}
   7464   1.6  christos 
   7465   1.6  christos 		/*
   7466   1.6  christos 		 * Regardless of the triggering result, we definitely
   7467   1.6  christos 		 * want to return SERVFAIL from here.
   7468   1.6  christos 		 */
   7469   1.6  christos 		qctx->client->rcode_override = dns_rcode_servfail;
   7470   1.6  christos 
   7471   1.3  christos 		QUERY_ERROR(qctx, result);
   7472   1.3  christos 		return (ns_query_done(qctx));
   7473   1.1  christos 	}
   7474   1.3  christos 
   7475   1.9  christos cleanup:
   7476   1.3  christos 	return (result);
   7477   1.1  christos }
   7478   1.1  christos 
   7479   1.1  christos static void
   7480   1.1  christos query_addnoqnameproof(query_ctx_t *qctx) {
   7481   1.1  christos 	ns_client_t *client = qctx->client;
   7482   1.1  christos 	isc_buffer_t *dbuf, b;
   7483   1.1  christos 	dns_name_t *fname = NULL;
   7484   1.1  christos 	dns_rdataset_t *neg = NULL, *negsig = NULL;
   7485   1.1  christos 	isc_result_t result = ISC_R_NOMEMORY;
   7486   1.1  christos 
   7487   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addnoqnameproof");
   7488   1.1  christos 
   7489   1.1  christos 	if (qctx->noqname == NULL) {
   7490   1.1  christos 		return;
   7491   1.1  christos 	}
   7492   1.1  christos 
   7493   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   7494   1.1  christos 	if (dbuf == NULL) {
   7495   1.1  christos 		goto cleanup;
   7496   1.1  christos 	}
   7497   1.1  christos 
   7498   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   7499   1.3  christos 	neg = ns_client_newrdataset(client);
   7500   1.3  christos 	negsig = ns_client_newrdataset(client);
   7501   1.1  christos 	if (fname == NULL || neg == NULL || negsig == NULL) {
   7502   1.1  christos 		goto cleanup;
   7503   1.1  christos 	}
   7504   1.1  christos 
   7505   1.1  christos 	result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig);
   7506   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7507   1.1  christos 
   7508   1.3  christos 	query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
   7509   1.1  christos 		       DNS_SECTION_AUTHORITY);
   7510   1.1  christos 
   7511   1.1  christos 	if ((qctx->noqname->attributes & DNS_RDATASETATTR_CLOSEST) == 0) {
   7512   1.1  christos 		goto cleanup;
   7513   1.1  christos 	}
   7514   1.1  christos 
   7515   1.1  christos 	if (fname == NULL) {
   7516   1.3  christos 		dbuf = ns_client_getnamebuf(client);
   7517   1.9  christos 		if (dbuf == NULL) {
   7518   1.1  christos 			goto cleanup;
   7519   1.9  christos 		}
   7520   1.3  christos 		fname = ns_client_newname(client, dbuf, &b);
   7521   1.1  christos 	}
   7522   1.1  christos 
   7523   1.1  christos 	if (neg == NULL) {
   7524   1.3  christos 		neg = ns_client_newrdataset(client);
   7525   1.1  christos 	} else if (dns_rdataset_isassociated(neg)) {
   7526   1.1  christos 		dns_rdataset_disassociate(neg);
   7527   1.1  christos 	}
   7528   1.1  christos 
   7529   1.1  christos 	if (negsig == NULL) {
   7530   1.3  christos 		negsig = ns_client_newrdataset(client);
   7531   1.1  christos 	} else if (dns_rdataset_isassociated(negsig)) {
   7532   1.1  christos 		dns_rdataset_disassociate(negsig);
   7533   1.1  christos 	}
   7534   1.1  christos 
   7535   1.9  christos 	if (fname == NULL || neg == NULL || negsig == NULL) {
   7536   1.1  christos 		goto cleanup;
   7537   1.9  christos 	}
   7538   1.1  christos 	result = dns_rdataset_getclosest(qctx->noqname, fname, neg, negsig);
   7539   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7540   1.1  christos 
   7541   1.3  christos 	query_addrrset(qctx, &fname, &neg, &negsig, dbuf,
   7542   1.1  christos 		       DNS_SECTION_AUTHORITY);
   7543   1.1  christos 
   7544   1.9  christos cleanup:
   7545   1.1  christos 	if (neg != NULL) {
   7546   1.3  christos 		ns_client_putrdataset(client, &neg);
   7547   1.1  christos 	}
   7548   1.1  christos 	if (negsig != NULL) {
   7549   1.3  christos 		ns_client_putrdataset(client, &negsig);
   7550   1.1  christos 	}
   7551   1.1  christos 	if (fname != NULL) {
   7552   1.3  christos 		ns_client_releasename(client, &fname);
   7553   1.1  christos 	}
   7554   1.1  christos }
   7555   1.1  christos 
   7556   1.1  christos /*%
   7557   1.1  christos  * Build the response for a query for type ANY.
   7558   1.1  christos  */
   7559   1.1  christos static isc_result_t
   7560   1.1  christos query_respond_any(query_ctx_t *qctx) {
   7561   1.5  christos 	bool found = false, hidden = false;
   7562   1.1  christos 	dns_rdatasetiter_t *rdsiter = NULL;
   7563   1.1  christos 	isc_result_t result;
   7564   1.9  christos 	dns_rdatatype_t onetype = 0; /* type to use for minimal-any */
   7565   1.3  christos 	isc_buffer_t b;
   7566   1.1  christos 
   7567   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_respond_any");
   7568   1.9  christos 
   7569   1.3  christos 	CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx);
   7570   1.1  christos 
   7571  1.16  christos 	result = dns_db_allrdatasets(qctx->db, qctx->node, qctx->version, 0, 0,
   7572   1.9  christos 				     &rdsiter);
   7573   1.1  christos 	if (result != ISC_R_SUCCESS) {
   7574   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_respond_any: allrdatasets "
   7575   1.9  christos 				       "failed");
   7576   1.3  christos 		QUERY_ERROR(qctx, result);
   7577   1.3  christos 		return (ns_query_done(qctx));
   7578   1.1  christos 	}
   7579   1.1  christos 
   7580   1.1  christos 	/*
   7581   1.1  christos 	 * Calling query_addrrset() with a non-NULL dbuf is going
   7582   1.1  christos 	 * to either keep or release the name.  We don't want it to
   7583   1.1  christos 	 * release fname, since we may have to call query_addrrset()
   7584   1.3  christos 	 * more than once.  That means we have to call ns_client_keepname()
   7585   1.1  christos 	 * now, and pass a NULL dbuf to query_addrrset().
   7586   1.1  christos 	 *
   7587   1.1  christos 	 * If we do a query_addrrset() below, we must set qctx->fname to
   7588   1.1  christos 	 * NULL before leaving this block, otherwise we might try to
   7589   1.1  christos 	 * cleanup qctx->fname even though we're using it!
   7590   1.1  christos 	 */
   7591   1.3  christos 	ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   7592   1.3  christos 	qctx->tname = qctx->fname;
   7593   1.1  christos 
   7594   1.1  christos 	result = dns_rdatasetiter_first(rdsiter);
   7595   1.1  christos 	while (result == ISC_R_SUCCESS) {
   7596   1.1  christos 		dns_rdatasetiter_current(rdsiter, qctx->rdataset);
   7597   1.1  christos 
   7598   1.1  christos 		/*
   7599   1.1  christos 		 * We found an NS RRset; no need to add one later.
   7600   1.1  christos 		 */
   7601   1.1  christos 		if (qctx->qtype == dns_rdatatype_any &&
   7602   1.1  christos 		    qctx->rdataset->type == dns_rdatatype_ns)
   7603   1.1  christos 		{
   7604   1.3  christos 			qctx->answer_has_ns = true;
   7605   1.1  christos 		}
   7606   1.1  christos 
   7607   1.1  christos 		/*
   7608   1.1  christos 		 * Note: if we're in this function, then qctx->type
   7609   1.1  christos 		 * is guaranteed to be ANY, but qctx->qtype (i.e. the
   7610   1.1  christos 		 * original type requested) might have been RRSIG or
   7611   1.1  christos 		 * SIG; we need to check for that.
   7612   1.1  christos 		 */
   7613   1.1  christos 		if (qctx->is_zone && qctx->qtype == dns_rdatatype_any &&
   7614   1.1  christos 		    !dns_db_issecure(qctx->db) &&
   7615   1.1  christos 		    dns_rdatatype_isdnssec(qctx->rdataset->type))
   7616   1.1  christos 		{
   7617   1.1  christos 			/*
   7618   1.5  christos 			 * The zone may be transitioning from insecure
   7619   1.5  christos 			 * to secure. Hide DNSSEC records from ANY queries.
   7620   1.1  christos 			 */
   7621   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   7622   1.5  christos 			hidden = true;
   7623   1.9  christos 		} else if (qctx->view->minimal_any && !TCP(qctx->client) &&
   7624   1.9  christos 			   !WANTDNSSEC(qctx->client) &&
   7625   1.1  christos 			   qctx->qtype == dns_rdatatype_any &&
   7626   1.1  christos 			   (qctx->rdataset->type == dns_rdatatype_sig ||
   7627   1.1  christos 			    qctx->rdataset->type == dns_rdatatype_rrsig))
   7628   1.1  christos 		{
   7629   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
   7630   1.9  christos 						  "minimal-any skip signature");
   7631   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   7632   1.9  christos 		} else if (qctx->view->minimal_any && !TCP(qctx->client) &&
   7633   1.9  christos 			   onetype != 0 && qctx->rdataset->type != onetype &&
   7634   1.1  christos 			   qctx->rdataset->covers != onetype)
   7635   1.1  christos 		{
   7636   1.1  christos 			CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: "
   7637   1.9  christos 						  "minimal-any skip rdataset");
   7638   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   7639   1.1  christos 		} else if ((qctx->qtype == dns_rdatatype_any ||
   7640   1.1  christos 			    qctx->rdataset->type == qctx->qtype) &&
   7641   1.1  christos 			   qctx->rdataset->type != 0)
   7642   1.1  christos 		{
   7643   1.9  christos 			if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client))
   7644   1.1  christos 			{
   7645   1.1  christos 				qctx->noqname = qctx->rdataset;
   7646   1.1  christos 			} else {
   7647   1.1  christos 				qctx->noqname = NULL;
   7648   1.1  christos 			}
   7649   1.1  christos 
   7650   1.1  christos 			qctx->rpz_st = qctx->client->query.rpz_st;
   7651   1.9  christos 			if (qctx->rpz_st != NULL) {
   7652   1.1  christos 				qctx->rdataset->ttl =
   7653   1.1  christos 					ISC_MIN(qctx->rdataset->ttl,
   7654   1.1  christos 						qctx->rpz_st->m.ttl);
   7655   1.9  christos 			}
   7656   1.1  christos 
   7657   1.1  christos 			if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   7658   1.1  christos 				dns_name_t *name;
   7659   1.9  christos 				name = (qctx->fname != NULL) ? qctx->fname
   7660   1.9  christos 							     : qctx->tname;
   7661   1.1  christos 				query_prefetch(qctx->client, name,
   7662   1.1  christos 					       qctx->rdataset);
   7663   1.1  christos 			}
   7664   1.1  christos 
   7665   1.1  christos 			/*
   7666   1.1  christos 			 * Remember the first RRtype we find so we
   7667   1.1  christos 			 * can skip others with minimal-any.
   7668   1.1  christos 			 */
   7669   1.1  christos 			if (qctx->rdataset->type == dns_rdatatype_sig ||
   7670   1.1  christos 			    qctx->rdataset->type == dns_rdatatype_rrsig)
   7671   1.3  christos 			{
   7672   1.1  christos 				onetype = qctx->rdataset->covers;
   7673   1.3  christos 			} else {
   7674   1.1  christos 				onetype = qctx->rdataset->type;
   7675   1.3  christos 			}
   7676   1.1  christos 
   7677   1.3  christos 			query_addrrset(qctx,
   7678   1.9  christos 				       (qctx->fname != NULL) ? &qctx->fname
   7679   1.9  christos 							     : &qctx->tname,
   7680   1.9  christos 				       &qctx->rdataset, NULL, NULL,
   7681   1.9  christos 				       DNS_SECTION_ANSWER);
   7682   1.1  christos 
   7683   1.1  christos 			query_addnoqnameproof(qctx);
   7684   1.1  christos 
   7685   1.3  christos 			found = true;
   7686   1.3  christos 			INSIST(qctx->tname != NULL);
   7687   1.1  christos 
   7688   1.1  christos 			/*
   7689   1.1  christos 			 * rdataset is non-NULL only in certain
   7690   1.1  christos 			 * pathological cases involving DNAMEs.
   7691   1.1  christos 			 */
   7692   1.3  christos 			if (qctx->rdataset != NULL) {
   7693   1.3  christos 				ns_client_putrdataset(qctx->client,
   7694   1.3  christos 						      &qctx->rdataset);
   7695   1.3  christos 			}
   7696   1.1  christos 
   7697   1.3  christos 			qctx->rdataset = ns_client_newrdataset(qctx->client);
   7698   1.5  christos 			if (qctx->rdataset == NULL) {
   7699   1.1  christos 				break;
   7700   1.5  christos 			}
   7701   1.1  christos 		} else {
   7702   1.1  christos 			/*
   7703   1.1  christos 			 * We're not interested in this rdataset.
   7704   1.1  christos 			 */
   7705   1.1  christos 			dns_rdataset_disassociate(qctx->rdataset);
   7706   1.1  christos 		}
   7707   1.1  christos 
   7708   1.1  christos 		result = dns_rdatasetiter_next(rdsiter);
   7709   1.1  christos 	}
   7710   1.1  christos 
   7711   1.3  christos 	dns_rdatasetiter_destroy(&rdsiter);
   7712   1.3  christos 
   7713   1.3  christos 	if (result != ISC_R_NOMORE) {
   7714   1.9  christos 		CCTRACE(ISC_LOG_ERROR, "query_respond_any: rdataset iterator "
   7715   1.9  christos 				       "failed");
   7716   1.3  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   7717   1.3  christos 		return (ns_query_done(qctx));
   7718   1.3  christos 	}
   7719   1.3  christos 
   7720   1.3  christos 	if (found) {
   7721   1.5  christos 		/*
   7722   1.5  christos 		 * Call hook if any answers were found.
   7723   1.5  christos 		 * Do this before releasing qctx->fname, in case
   7724   1.5  christos 		 * the hook function needs it.
   7725   1.5  christos 		 */
   7726   1.3  christos 		CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx);
   7727   1.3  christos 	}
   7728   1.3  christos 
   7729   1.3  christos 	if (qctx->fname != NULL) {
   7730   1.5  christos 		dns_message_puttempname(qctx->client->message, &qctx->fname);
   7731   1.1  christos 	}
   7732   1.1  christos 
   7733   1.5  christos 	if (found) {
   7734   1.5  christos 		/*
   7735   1.5  christos 		 * At least one matching rdataset was found
   7736   1.5  christos 		 */
   7737   1.1  christos 		query_addauth(qctx);
   7738   1.5  christos 	} else if (qctx->qtype == dns_rdatatype_rrsig ||
   7739   1.5  christos 		   qctx->qtype == dns_rdatatype_sig)
   7740   1.5  christos 	{
   7741   1.5  christos 		/*
   7742   1.5  christos 		 * No matching rdatasets were found, but we got
   7743   1.5  christos 		 * here on a search for RRSIG/SIG, so that's okay.
   7744   1.5  christos 		 */
   7745   1.5  christos 		if (!qctx->is_zone) {
   7746   1.5  christos 			qctx->authoritative = false;
   7747   1.5  christos 			qctx->client->attributes &= ~NS_CLIENTATTR_RA;
   7748   1.5  christos 			query_addauth(qctx);
   7749   1.5  christos 			return (ns_query_done(qctx));
   7750   1.5  christos 		}
   7751   1.5  christos 
   7752   1.5  christos 		if (qctx->qtype == dns_rdatatype_rrsig &&
   7753  1.16  christos 		    dns_db_issecure(qctx->db))
   7754  1.16  christos 		{
   7755   1.5  christos 			char namebuf[DNS_NAME_FORMATSIZE];
   7756   1.9  christos 			dns_name_format(qctx->client->query.qname, namebuf,
   7757   1.9  christos 					sizeof(namebuf));
   7758   1.5  christos 			ns_client_log(qctx->client, DNS_LOGCATEGORY_DNSSEC,
   7759   1.5  christos 				      NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
   7760   1.5  christos 				      "missing signature for %s", namebuf);
   7761   1.5  christos 		}
   7762   1.1  christos 
   7763   1.5  christos 		qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   7764   1.5  christos 		return (query_sign_nodata(qctx));
   7765   1.5  christos 	} else if (!hidden) {
   7766   1.5  christos 		/*
   7767   1.5  christos 		 * No matching rdatasets were found and nothing was
   7768   1.5  christos 		 * deliberately hidden: something must have gone wrong.
   7769   1.5  christos 		 */
   7770   1.5  christos 		QUERY_ERROR(qctx, DNS_R_SERVFAIL);
   7771   1.3  christos 	}
   7772   1.3  christos 
   7773   1.5  christos 	return (ns_query_done(qctx));
   7774   1.3  christos 
   7775   1.9  christos cleanup:
   7776   1.3  christos 	return (result);
   7777   1.1  christos }
   7778   1.1  christos 
   7779   1.1  christos /*
   7780   1.3  christos  * Set the expire time, if requested, when answering from a slave, mirror, or
   7781   1.3  christos  * master zone.
   7782   1.1  christos  */
   7783   1.1  christos static void
   7784   1.1  christos query_getexpire(query_ctx_t *qctx) {
   7785   1.1  christos 	dns_zone_t *raw = NULL, *mayberaw;
   7786   1.1  christos 
   7787   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_getexpire");
   7788   1.9  christos 
   7789   1.1  christos 	if (qctx->zone == NULL || !qctx->is_zone ||
   7790   1.1  christos 	    qctx->qtype != dns_rdatatype_soa ||
   7791   1.1  christos 	    qctx->client->query.restarts != 0 ||
   7792   1.1  christos 	    (qctx->client->attributes & NS_CLIENTATTR_WANTEXPIRE) == 0)
   7793   1.1  christos 	{
   7794   1.1  christos 		return;
   7795   1.1  christos 	}
   7796   1.1  christos 
   7797   1.1  christos 	dns_zone_getraw(qctx->zone, &raw);
   7798   1.1  christos 	mayberaw = (raw != NULL) ? raw : qctx->zone;
   7799   1.1  christos 
   7800  1.15  christos 	if (dns_zone_gettype(mayberaw) == dns_zone_secondary ||
   7801   1.3  christos 	    dns_zone_gettype(mayberaw) == dns_zone_mirror)
   7802   1.3  christos 	{
   7803   1.1  christos 		isc_time_t expiretime;
   7804   1.3  christos 		uint32_t secs;
   7805   1.1  christos 		dns_zone_getexpiretime(qctx->zone, &expiretime);
   7806   1.1  christos 		secs = isc_time_seconds(&expiretime);
   7807   1.9  christos 		if (secs >= qctx->client->now && qctx->result == ISC_R_SUCCESS)
   7808   1.1  christos 		{
   7809   1.9  christos 			qctx->client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
   7810   1.1  christos 			qctx->client->expire = secs - qctx->client->now;
   7811   1.1  christos 		}
   7812  1.15  christos 	} else if (dns_zone_gettype(mayberaw) == dns_zone_primary) {
   7813   1.1  christos 		isc_result_t result;
   7814   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   7815   1.1  christos 		dns_rdata_soa_t soa;
   7816   1.1  christos 
   7817   1.1  christos 		result = dns_rdataset_first(qctx->rdataset);
   7818   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7819   1.1  christos 
   7820   1.1  christos 		dns_rdataset_current(qctx->rdataset, &rdata);
   7821   1.1  christos 		result = dns_rdata_tostruct(&rdata, &soa, NULL);
   7822   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   7823   1.1  christos 
   7824   1.1  christos 		qctx->client->expire = soa.expire;
   7825   1.1  christos 		qctx->client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
   7826   1.1  christos 	}
   7827   1.1  christos 
   7828   1.1  christos 	if (raw != NULL) {
   7829   1.1  christos 		dns_zone_detach(&raw);
   7830   1.1  christos 	}
   7831   1.1  christos }
   7832   1.1  christos 
   7833   1.3  christos /*%
   7834   1.3  christos  * Fill the ANSWER section of a positive response.
   7835   1.1  christos  */
   7836   1.1  christos static isc_result_t
   7837   1.3  christos query_addanswer(query_ctx_t *qctx) {
   7838   1.3  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   7839   1.1  christos 	isc_result_t result;
   7840   1.1  christos 
   7841   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_addanswer");
   7842   1.9  christos 
   7843   1.3  christos 	CALL_HOOK(NS_QUERY_ADDANSWER_BEGIN, qctx);
   7844   1.1  christos 
   7845  1.13  christos 	/*
   7846  1.13  christos 	 * On normal lookups, clear any rdatasets that were added on a
   7847  1.15  christos 	 * lookup due to stale-answer-client-timeout. Do not clear if we
   7848  1.15  christos 	 * are going to refresh the RRset, because the stale contents are
   7849  1.15  christos 	 * prioritized.
   7850  1.13  christos 	 */
   7851  1.13  christos 	if (QUERY_STALEOK(&qctx->client->query) &&
   7852  1.15  christos 	    !QUERY_STALETIMEOUT(&qctx->client->query) && !qctx->refresh_rrset)
   7853  1.13  christos 	{
   7854  1.15  christos 		CCTRACE(ISC_LOG_DEBUG(3), "query_clear_stale");
   7855  1.13  christos 		query_clear_stale(qctx->client);
   7856  1.13  christos 		/*
   7857  1.13  christos 		 * We can clear the attribute to prevent redundant clearing
   7858  1.13  christos 		 * in subsequent lookups.
   7859  1.13  christos 		 */
   7860  1.14  christos 		qctx->client->query.attributes &= ~NS_QUERYATTR_STALEOK;
   7861  1.13  christos 	}
   7862  1.13  christos 
   7863   1.3  christos 	if (qctx->dns64) {
   7864   1.3  christos 		result = query_dns64(qctx);
   7865   1.3  christos 		qctx->noqname = NULL;
   7866   1.3  christos 		dns_rdataset_disassociate(qctx->rdataset);
   7867   1.3  christos 		dns_message_puttemprdataset(qctx->client->message,
   7868   1.3  christos 					    &qctx->rdataset);
   7869   1.3  christos 		if (result == ISC_R_NOMORE) {
   7870   1.3  christos #ifndef dns64_bis_return_excluded_addresses
   7871   1.3  christos 			if (qctx->dns64_exclude) {
   7872   1.9  christos 				if (!qctx->is_zone) {
   7873   1.3  christos 					return (ns_query_done(qctx));
   7874   1.9  christos 				}
   7875   1.3  christos 				/*
   7876   1.3  christos 				 * Add a fake SOA record.
   7877   1.3  christos 				 */
   7878   1.3  christos 				(void)query_addsoa(qctx, 600,
   7879   1.3  christos 						   DNS_SECTION_AUTHORITY);
   7880   1.3  christos 				return (ns_query_done(qctx));
   7881   1.3  christos 			}
   7882   1.9  christos #endif /* ifndef dns64_bis_return_excluded_addresses */
   7883   1.3  christos 			if (qctx->is_zone) {
   7884   1.3  christos 				return (query_nodata(qctx, DNS_R_NXDOMAIN));
   7885   1.3  christos 			} else {
   7886   1.3  christos 				return (query_ncache(qctx, DNS_R_NXDOMAIN));
   7887   1.1  christos 			}
   7888   1.3  christos 		} else if (result != ISC_R_SUCCESS) {
   7889   1.3  christos 			qctx->result = result;
   7890   1.3  christos 			return (ns_query_done(qctx));
   7891   1.3  christos 		}
   7892   1.3  christos 	} else if (qctx->client->query.dns64_aaaaok != NULL) {
   7893   1.3  christos 		query_filter64(qctx);
   7894   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   7895   1.3  christos 	} else {
   7896  1.11  christos 		if (!qctx->is_zone && RECURSIONOK(qctx->client) &&
   7897  1.13  christos 		    !QUERY_STALETIMEOUT(&qctx->client->query))
   7898  1.11  christos 		{
   7899   1.3  christos 			query_prefetch(qctx->client, qctx->fname,
   7900   1.3  christos 				       qctx->rdataset);
   7901   1.1  christos 		}
   7902   1.3  christos 		if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   7903   1.3  christos 			sigrdatasetp = &qctx->sigrdataset;
   7904   1.3  christos 		}
   7905   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   7906   1.9  christos 			       sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER);
   7907   1.1  christos 	}
   7908   1.1  christos 
   7909   1.1  christos 	return (ISC_R_COMPLETE);
   7910   1.3  christos 
   7911   1.9  christos cleanup:
   7912   1.3  christos 	return (result);
   7913   1.1  christos }
   7914   1.1  christos 
   7915   1.1  christos /*%
   7916   1.9  christos  * Build a response for a "normal" query, for a type other than ANY,
   7917   1.1  christos  * for which we have an answer (either positive or negative).
   7918   1.1  christos  */
   7919   1.1  christos static isc_result_t
   7920   1.1  christos query_respond(query_ctx_t *qctx) {
   7921   1.1  christos 	isc_result_t result;
   7922   1.1  christos 
   7923   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_respond");
   7924   1.9  christos 
   7925   1.1  christos 	/*
   7926   1.1  christos 	 * Check to see if the AAAA RRset has non-excluded addresses
   7927   1.1  christos 	 * in it.  If not look for a A RRset.
   7928   1.1  christos 	 */
   7929   1.1  christos 	INSIST(qctx->client->query.dns64_aaaaok == NULL);
   7930   1.1  christos 
   7931   1.1  christos 	if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude &&
   7932   1.3  christos 	    !ISC_LIST_EMPTY(qctx->view->dns64) &&
   7933   1.1  christos 	    qctx->client->message->rdclass == dns_rdataclass_in &&
   7934   1.1  christos 	    !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset))
   7935   1.1  christos 	{
   7936   1.1  christos 		/*
   7937   1.1  christos 		 * Look to see if there are A records for this name.
   7938   1.1  christos 		 */
   7939   1.1  christos 		qctx->client->query.dns64_ttl = qctx->rdataset->ttl;
   7940   1.1  christos 		SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset);
   7941   1.1  christos 		SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset);
   7942   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   7943   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   7944   1.1  christos 		qctx->type = qctx->qtype = dns_rdatatype_a;
   7945   1.3  christos 		qctx->dns64_exclude = qctx->dns64 = true;
   7946   1.1  christos 
   7947   1.1  christos 		return (query_lookup(qctx));
   7948   1.1  christos 	}
   7949   1.1  christos 
   7950   1.3  christos 	/*
   7951   1.3  christos 	 * XXX: This hook is meant to be at the top of this function,
   7952   1.3  christos 	 * but is postponed until after DNS64 in order to avoid an
   7953   1.3  christos 	 * assertion if the hook causes recursion. (When DNS64 also
   7954   1.3  christos 	 * becomes a plugin, it will be necessary to find some
   7955   1.3  christos 	 * other way to prevent that assertion, since the order in
   7956   1.3  christos 	 * which plugins are configured can't be enforced.)
   7957   1.3  christos 	 */
   7958   1.3  christos 	CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx);
   7959   1.1  christos 
   7960   1.1  christos 	if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) {
   7961   1.1  christos 		qctx->noqname = qctx->rdataset;
   7962   1.1  christos 	} else {
   7963   1.1  christos 		qctx->noqname = NULL;
   7964   1.1  christos 	}
   7965   1.1  christos 
   7966   1.1  christos 	/*
   7967   1.1  christos 	 * Special case NS handling
   7968   1.1  christos 	 */
   7969   1.1  christos 	if (qctx->is_zone && qctx->qtype == dns_rdatatype_ns) {
   7970   1.1  christos 		/*
   7971   1.1  christos 		 * We've already got an NS, no need to add one in
   7972   1.1  christos 		 * the authority section
   7973   1.1  christos 		 */
   7974   1.1  christos 		if (dns_name_equal(qctx->client->query.qname,
   7975  1.16  christos 				   dns_db_origin(qctx->db)))
   7976  1.16  christos 		{
   7977   1.3  christos 			qctx->answer_has_ns = true;
   7978   1.1  christos 		}
   7979   1.1  christos 
   7980   1.1  christos 		/*
   7981   1.6  christos 		 * Always add glue for root priming queries, regardless
   7982   1.6  christos 		 * of "minimal-responses" setting.
   7983   1.1  christos 		 */
   7984   1.1  christos 		if (dns_name_equal(qctx->client->query.qname, dns_rootname)) {
   7985   1.1  christos 			qctx->client->query.attributes &=
   7986   1.1  christos 				~NS_QUERYATTR_NOADDITIONAL;
   7987   1.6  christos 			dns_db_attach(qctx->db, &qctx->client->query.gluedb);
   7988   1.1  christos 		}
   7989   1.1  christos 	}
   7990   1.1  christos 
   7991   1.1  christos 	/*
   7992   1.1  christos 	 * Set expire time
   7993   1.1  christos 	 */
   7994   1.1  christos 	query_getexpire(qctx);
   7995   1.1  christos 
   7996   1.3  christos 	result = query_addanswer(qctx);
   7997   1.3  christos 	if (result != ISC_R_COMPLETE) {
   7998   1.3  christos 		return (result);
   7999   1.1  christos 	}
   8000   1.1  christos 
   8001   1.1  christos 	query_addnoqnameproof(qctx);
   8002   1.1  christos 
   8003   1.1  christos 	/*
   8004  1.13  christos 	 * 'qctx->rdataset' will only be non-NULL here if the ANSWER section of
   8005  1.13  christos 	 * the message to be sent to the client already contains an RRset with
   8006  1.13  christos 	 * the same owner name and the same type as 'qctx->rdataset'.  This
   8007  1.13  christos 	 * should never happen, with one exception: when chasing DNAME records,
   8008  1.13  christos 	 * one of the DNAME records placed in the ANSWER section may turn out
   8009  1.13  christos 	 * to be the final answer to the client's query, but we have no way of
   8010  1.13  christos 	 * knowing that until now.  In such a case, 'qctx->rdataset' will be
   8011  1.13  christos 	 * freed later, so we do not need to free it here.
   8012   1.1  christos 	 */
   8013  1.13  christos 	INSIST(qctx->rdataset == NULL || qctx->qtype == dns_rdatatype_dname);
   8014   1.1  christos 
   8015   1.1  christos 	query_addauth(qctx);
   8016   1.1  christos 
   8017   1.3  christos 	return (ns_query_done(qctx));
   8018   1.3  christos 
   8019   1.9  christos cleanup:
   8020   1.3  christos 	return (result);
   8021   1.1  christos }
   8022   1.1  christos 
   8023   1.1  christos static isc_result_t
   8024   1.1  christos query_dns64(query_ctx_t *qctx) {
   8025   1.1  christos 	ns_client_t *client = qctx->client;
   8026   1.9  christos 	dns_aclenv_t *env =
   8027   1.9  christos 		ns_interfacemgr_getaclenv(client->manager->interface->mgr);
   8028   1.1  christos 	dns_name_t *name, *mname;
   8029   1.1  christos 	dns_rdata_t *dns64_rdata;
   8030   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   8031   1.1  christos 	dns_rdatalist_t *dns64_rdatalist;
   8032   1.1  christos 	dns_rdataset_t *dns64_rdataset;
   8033   1.1  christos 	dns_rdataset_t *mrdataset;
   8034   1.1  christos 	isc_buffer_t *buffer;
   8035   1.1  christos 	isc_region_t r;
   8036   1.1  christos 	isc_result_t result;
   8037   1.1  christos 	dns_view_t *view = client->view;
   8038   1.1  christos 	isc_netaddr_t netaddr;
   8039   1.1  christos 	dns_dns64_t *dns64;
   8040   1.1  christos 	unsigned int flags = 0;
   8041   1.1  christos 	const dns_section_t section = DNS_SECTION_ANSWER;
   8042   1.1  christos 
   8043   1.1  christos 	/*%
   8044   1.1  christos 	 * To the current response for 'qctx->client', add the answer RRset
   8045   1.1  christos 	 * '*rdatasetp' and an optional signature set '*sigrdatasetp', with
   8046   1.1  christos 	 * owner name '*namep', to the answer section, unless they are
   8047   1.1  christos 	 * already there.  Also add any pertinent additional data.
   8048   1.1  christos 	 *
   8049   1.1  christos 	 * If 'qctx->dbuf' is not NULL, then 'qctx->fname' is the name
   8050   1.1  christos 	 * whose data is stored 'qctx->dbuf'.  In this case,
   8051   1.1  christos 	 * query_addrrset() guarantees that when it returns the name
   8052   1.1  christos 	 * will either have been kept or released.
   8053   1.1  christos 	 */
   8054   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_dns64");
   8055   1.1  christos 
   8056   1.1  christos 	qctx->qtype = qctx->type = dns_rdatatype_aaaa;
   8057   1.1  christos 
   8058   1.1  christos 	name = qctx->fname;
   8059   1.1  christos 	mname = NULL;
   8060   1.1  christos 	mrdataset = NULL;
   8061   1.1  christos 	buffer = NULL;
   8062   1.1  christos 	dns64_rdata = NULL;
   8063   1.1  christos 	dns64_rdataset = NULL;
   8064   1.1  christos 	dns64_rdatalist = NULL;
   8065   1.9  christos 	result = dns_message_findname(
   8066   1.9  christos 		client->message, section, name, dns_rdatatype_aaaa,
   8067   1.9  christos 		qctx->rdataset->covers, &mname, &mrdataset);
   8068   1.1  christos 	if (result == ISC_R_SUCCESS) {
   8069   1.1  christos 		/*
   8070   1.1  christos 		 * We've already got an RRset of the given name and type.
   8071   1.1  christos 		 * There's nothing else to do;
   8072   1.1  christos 		 */
   8073   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_dns64: dns_message_findname "
   8074   1.9  christos 					 "succeeded: done");
   8075   1.3  christos 		if (qctx->dbuf != NULL) {
   8076   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8077   1.3  christos 		}
   8078   1.1  christos 		return (ISC_R_SUCCESS);
   8079   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   8080   1.1  christos 		/*
   8081   1.1  christos 		 * The name doesn't exist.
   8082   1.1  christos 		 */
   8083   1.3  christos 		if (qctx->dbuf != NULL) {
   8084   1.3  christos 			ns_client_keepname(client, name, qctx->dbuf);
   8085   1.3  christos 		}
   8086   1.1  christos 		dns_message_addname(client->message, name, section);
   8087   1.1  christos 		qctx->fname = NULL;
   8088   1.1  christos 		mname = name;
   8089   1.1  christos 	} else {
   8090   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   8091   1.3  christos 		if (qctx->dbuf != NULL) {
   8092   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8093   1.3  christos 		}
   8094   1.1  christos 	}
   8095   1.1  christos 
   8096   1.1  christos 	if (qctx->rdataset->trust != dns_trust_secure) {
   8097   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   8098   1.1  christos 	}
   8099   1.1  christos 
   8100   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   8101   1.1  christos 
   8102   1.9  christos 	isc_buffer_allocate(client->mctx, &buffer,
   8103   1.9  christos 			    view->dns64cnt * 16 *
   8104   1.9  christos 				    dns_rdataset_count(qctx->rdataset));
   8105   1.9  christos 	result = dns_message_gettemprdataset(client->message, &dns64_rdataset);
   8106   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8107   1.1  christos 		goto cleanup;
   8108   1.9  christos 	}
   8109   1.1  christos 	result = dns_message_gettemprdatalist(client->message,
   8110   1.1  christos 					      &dns64_rdatalist);
   8111   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8112   1.1  christos 		goto cleanup;
   8113   1.9  christos 	}
   8114   1.1  christos 
   8115   1.1  christos 	dns_rdatalist_init(dns64_rdatalist);
   8116   1.1  christos 	dns64_rdatalist->rdclass = dns_rdataclass_in;
   8117   1.1  christos 	dns64_rdatalist->type = dns_rdatatype_aaaa;
   8118   1.9  christos 	if (client->query.dns64_ttl != UINT32_MAX) {
   8119   1.1  christos 		dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl,
   8120   1.1  christos 					       client->query.dns64_ttl);
   8121   1.9  christos 	} else {
   8122   1.1  christos 		dns64_rdatalist->ttl = ISC_MIN(qctx->rdataset->ttl, 600);
   8123   1.9  christos 	}
   8124   1.1  christos 
   8125   1.9  christos 	if (RECURSIONOK(client)) {
   8126   1.1  christos 		flags |= DNS_DNS64_RECURSIVE;
   8127   1.9  christos 	}
   8128   1.1  christos 
   8129   1.1  christos 	/*
   8130   1.1  christos 	 * We use the signatures from the A lookup to set DNS_DNS64_DNSSEC
   8131   1.1  christos 	 * as this provides a easy way to see if the answer was signed.
   8132   1.1  christos 	 */
   8133   1.1  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL &&
   8134   1.1  christos 	    dns_rdataset_isassociated(qctx->sigrdataset))
   8135   1.9  christos 	{
   8136   1.1  christos 		flags |= DNS_DNS64_DNSSEC;
   8137   1.9  christos 	}
   8138   1.1  christos 
   8139   1.1  christos 	for (result = dns_rdataset_first(qctx->rdataset);
   8140   1.1  christos 	     result == ISC_R_SUCCESS;
   8141   1.9  christos 	     result = dns_rdataset_next(qctx->rdataset))
   8142   1.9  christos 	{
   8143   1.9  christos 		for (dns64 = ISC_LIST_HEAD(client->view->dns64); dns64 != NULL;
   8144   1.9  christos 		     dns64 = dns_dns64_next(dns64))
   8145   1.9  christos 		{
   8146   1.1  christos 			dns_rdataset_current(qctx->rdataset, &rdata);
   8147   1.1  christos 			isc_buffer_availableregion(buffer, &r);
   8148   1.1  christos 			INSIST(r.length >= 16);
   8149   1.1  christos 			result = dns_dns64_aaaafroma(dns64, &netaddr,
   8150   1.1  christos 						     client->signer, env, flags,
   8151   1.1  christos 						     rdata.data, r.base);
   8152   1.1  christos 			if (result != ISC_R_SUCCESS) {
   8153   1.1  christos 				dns_rdata_reset(&rdata);
   8154   1.1  christos 				continue;
   8155   1.1  christos 			}
   8156   1.1  christos 			isc_buffer_add(buffer, 16);
   8157   1.1  christos 			isc_buffer_remainingregion(buffer, &r);
   8158   1.1  christos 			isc_buffer_forward(buffer, 16);
   8159   1.1  christos 			result = dns_message_gettemprdata(client->message,
   8160   1.1  christos 							  &dns64_rdata);
   8161   1.9  christos 			if (result != ISC_R_SUCCESS) {
   8162   1.1  christos 				goto cleanup;
   8163   1.9  christos 			}
   8164   1.1  christos 			dns_rdata_init(dns64_rdata);
   8165   1.1  christos 			dns_rdata_fromregion(dns64_rdata, dns_rdataclass_in,
   8166   1.1  christos 					     dns_rdatatype_aaaa, &r);
   8167   1.1  christos 			ISC_LIST_APPEND(dns64_rdatalist->rdata, dns64_rdata,
   8168   1.1  christos 					link);
   8169   1.1  christos 			dns64_rdata = NULL;
   8170   1.1  christos 			dns_rdata_reset(&rdata);
   8171   1.1  christos 		}
   8172   1.1  christos 	}
   8173   1.9  christos 	if (result != ISC_R_NOMORE) {
   8174   1.1  christos 		goto cleanup;
   8175   1.9  christos 	}
   8176   1.1  christos 
   8177   1.9  christos 	if (ISC_LIST_EMPTY(dns64_rdatalist->rdata)) {
   8178   1.1  christos 		goto cleanup;
   8179   1.9  christos 	}
   8180   1.1  christos 
   8181   1.1  christos 	result = dns_rdatalist_tordataset(dns64_rdatalist, dns64_rdataset);
   8182   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8183   1.1  christos 		goto cleanup;
   8184   1.9  christos 	}
   8185   1.1  christos 	dns_rdataset_setownercase(dns64_rdataset, mname);
   8186   1.1  christos 	client->query.attributes |= NS_QUERYATTR_NOADDITIONAL;
   8187   1.1  christos 	dns64_rdataset->trust = qctx->rdataset->trust;
   8188   1.3  christos 
   8189   1.3  christos 	query_addtoname(mname, dns64_rdataset);
   8190   1.3  christos 	query_setorder(qctx, mname, dns64_rdataset);
   8191   1.3  christos 
   8192   1.1  christos 	dns64_rdataset = NULL;
   8193   1.1  christos 	dns64_rdatalist = NULL;
   8194   1.1  christos 	dns_message_takebuffer(client->message, &buffer);
   8195   1.1  christos 	inc_stats(client, ns_statscounter_dns64);
   8196   1.1  christos 	result = ISC_R_SUCCESS;
   8197   1.1  christos 
   8198   1.9  christos cleanup:
   8199   1.9  christos 	if (buffer != NULL) {
   8200   1.1  christos 		isc_buffer_free(&buffer);
   8201   1.9  christos 	}
   8202   1.1  christos 
   8203   1.9  christos 	if (dns64_rdata != NULL) {
   8204   1.1  christos 		dns_message_puttemprdata(client->message, &dns64_rdata);
   8205   1.9  christos 	}
   8206   1.1  christos 
   8207   1.9  christos 	if (dns64_rdataset != NULL) {
   8208   1.1  christos 		dns_message_puttemprdataset(client->message, &dns64_rdataset);
   8209   1.9  christos 	}
   8210   1.1  christos 
   8211   1.1  christos 	if (dns64_rdatalist != NULL) {
   8212   1.1  christos 		for (dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata);
   8213   1.1  christos 		     dns64_rdata != NULL;
   8214   1.1  christos 		     dns64_rdata = ISC_LIST_HEAD(dns64_rdatalist->rdata))
   8215   1.1  christos 		{
   8216   1.9  christos 			ISC_LIST_UNLINK(dns64_rdatalist->rdata, dns64_rdata,
   8217   1.9  christos 					link);
   8218   1.1  christos 			dns_message_puttemprdata(client->message, &dns64_rdata);
   8219   1.1  christos 		}
   8220   1.1  christos 		dns_message_puttemprdatalist(client->message, &dns64_rdatalist);
   8221   1.1  christos 	}
   8222   1.1  christos 
   8223   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_dns64: done");
   8224   1.1  christos 	return (result);
   8225   1.1  christos }
   8226   1.1  christos 
   8227   1.1  christos static void
   8228   1.1  christos query_filter64(query_ctx_t *qctx) {
   8229   1.1  christos 	ns_client_t *client = qctx->client;
   8230   1.1  christos 	dns_name_t *name, *mname;
   8231   1.1  christos 	dns_rdata_t *myrdata;
   8232   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   8233   1.1  christos 	dns_rdatalist_t *myrdatalist;
   8234   1.1  christos 	dns_rdataset_t *myrdataset;
   8235   1.1  christos 	isc_buffer_t *buffer;
   8236   1.1  christos 	isc_region_t r;
   8237   1.1  christos 	isc_result_t result;
   8238   1.1  christos 	unsigned int i;
   8239   1.1  christos 	const dns_section_t section = DNS_SECTION_ANSWER;
   8240   1.1  christos 
   8241   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_filter64");
   8242   1.1  christos 
   8243   1.1  christos 	INSIST(client->query.dns64_aaaaok != NULL);
   8244   1.1  christos 	INSIST(client->query.dns64_aaaaoklen ==
   8245   1.1  christos 	       dns_rdataset_count(qctx->rdataset));
   8246   1.1  christos 
   8247   1.1  christos 	name = qctx->fname;
   8248   1.1  christos 	mname = NULL;
   8249   1.1  christos 	buffer = NULL;
   8250   1.1  christos 	myrdata = NULL;
   8251   1.1  christos 	myrdataset = NULL;
   8252   1.1  christos 	myrdatalist = NULL;
   8253   1.9  christos 	result = dns_message_findname(
   8254   1.9  christos 		client->message, section, name, dns_rdatatype_aaaa,
   8255   1.9  christos 		qctx->rdataset->covers, &mname, &myrdataset);
   8256   1.1  christos 	if (result == ISC_R_SUCCESS) {
   8257   1.1  christos 		/*
   8258   1.1  christos 		 * We've already got an RRset of the given name and type.
   8259   1.1  christos 		 * There's nothing else to do;
   8260   1.1  christos 		 */
   8261   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_filter64: dns_message_findname "
   8262   1.9  christos 					 "succeeded: done");
   8263   1.3  christos 		if (qctx->dbuf != NULL) {
   8264   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8265   1.3  christos 		}
   8266   1.1  christos 		return;
   8267   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   8268   1.1  christos 		mname = name;
   8269   1.1  christos 		qctx->fname = NULL;
   8270   1.1  christos 	} else {
   8271   1.1  christos 		RUNTIME_CHECK(result == DNS_R_NXRRSET);
   8272   1.3  christos 		if (qctx->dbuf != NULL) {
   8273   1.3  christos 			ns_client_releasename(client, &qctx->fname);
   8274   1.3  christos 		}
   8275   1.1  christos 		qctx->dbuf = NULL;
   8276   1.1  christos 	}
   8277   1.1  christos 
   8278   1.1  christos 	if (qctx->rdataset->trust != dns_trust_secure) {
   8279   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   8280   1.1  christos 	}
   8281   1.1  christos 
   8282   1.9  christos 	isc_buffer_allocate(client->mctx, &buffer,
   8283   1.9  christos 			    16 * dns_rdataset_count(qctx->rdataset));
   8284   1.1  christos 	result = dns_message_gettemprdataset(client->message, &myrdataset);
   8285   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8286   1.1  christos 		goto cleanup;
   8287   1.9  christos 	}
   8288   1.1  christos 	result = dns_message_gettemprdatalist(client->message, &myrdatalist);
   8289   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8290   1.1  christos 		goto cleanup;
   8291   1.9  christos 	}
   8292   1.1  christos 
   8293   1.1  christos 	dns_rdatalist_init(myrdatalist);
   8294   1.1  christos 	myrdatalist->rdclass = dns_rdataclass_in;
   8295   1.1  christos 	myrdatalist->type = dns_rdatatype_aaaa;
   8296   1.1  christos 	myrdatalist->ttl = qctx->rdataset->ttl;
   8297   1.1  christos 
   8298   1.1  christos 	i = 0;
   8299   1.1  christos 	for (result = dns_rdataset_first(qctx->rdataset);
   8300   1.1  christos 	     result == ISC_R_SUCCESS;
   8301   1.3  christos 	     result = dns_rdataset_next(qctx->rdataset))
   8302   1.3  christos 	{
   8303   1.9  christos 		if (!client->query.dns64_aaaaok[i++]) {
   8304   1.1  christos 			continue;
   8305   1.9  christos 		}
   8306   1.1  christos 		dns_rdataset_current(qctx->rdataset, &rdata);
   8307   1.1  christos 		INSIST(rdata.length == 16);
   8308   1.1  christos 		isc_buffer_putmem(buffer, rdata.data, rdata.length);
   8309   1.1  christos 		isc_buffer_remainingregion(buffer, &r);
   8310   1.1  christos 		isc_buffer_forward(buffer, rdata.length);
   8311   1.1  christos 		result = dns_message_gettemprdata(client->message, &myrdata);
   8312   1.9  christos 		if (result != ISC_R_SUCCESS) {
   8313   1.1  christos 			goto cleanup;
   8314   1.9  christos 		}
   8315   1.1  christos 		dns_rdata_init(myrdata);
   8316   1.1  christos 		dns_rdata_fromregion(myrdata, dns_rdataclass_in,
   8317   1.1  christos 				     dns_rdatatype_aaaa, &r);
   8318   1.1  christos 		ISC_LIST_APPEND(myrdatalist->rdata, myrdata, link);
   8319   1.1  christos 		myrdata = NULL;
   8320   1.1  christos 		dns_rdata_reset(&rdata);
   8321   1.1  christos 	}
   8322   1.9  christos 	if (result != ISC_R_NOMORE) {
   8323   1.1  christos 		goto cleanup;
   8324   1.9  christos 	}
   8325   1.1  christos 
   8326   1.1  christos 	result = dns_rdatalist_tordataset(myrdatalist, myrdataset);
   8327   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8328   1.1  christos 		goto cleanup;
   8329   1.9  christos 	}
   8330   1.1  christos 	dns_rdataset_setownercase(myrdataset, name);
   8331   1.1  christos 	client->query.attributes |= NS_QUERYATTR_NOADDITIONAL;
   8332   1.1  christos 	if (mname == name) {
   8333   1.3  christos 		if (qctx->dbuf != NULL) {
   8334   1.3  christos 			ns_client_keepname(client, name, qctx->dbuf);
   8335   1.3  christos 		}
   8336   1.9  christos 		dns_message_addname(client->message, name, section);
   8337   1.1  christos 		qctx->dbuf = NULL;
   8338   1.1  christos 	}
   8339   1.1  christos 	myrdataset->trust = qctx->rdataset->trust;
   8340   1.3  christos 
   8341   1.3  christos 	query_addtoname(mname, myrdataset);
   8342   1.3  christos 	query_setorder(qctx, mname, myrdataset);
   8343   1.3  christos 
   8344   1.1  christos 	myrdataset = NULL;
   8345   1.1  christos 	myrdatalist = NULL;
   8346   1.1  christos 	dns_message_takebuffer(client->message, &buffer);
   8347   1.1  christos 
   8348   1.9  christos cleanup:
   8349   1.9  christos 	if (buffer != NULL) {
   8350   1.1  christos 		isc_buffer_free(&buffer);
   8351   1.9  christos 	}
   8352   1.1  christos 
   8353   1.9  christos 	if (myrdata != NULL) {
   8354   1.1  christos 		dns_message_puttemprdata(client->message, &myrdata);
   8355   1.9  christos 	}
   8356   1.1  christos 
   8357   1.9  christos 	if (myrdataset != NULL) {
   8358   1.1  christos 		dns_message_puttemprdataset(client->message, &myrdataset);
   8359   1.9  christos 	}
   8360   1.1  christos 
   8361   1.1  christos 	if (myrdatalist != NULL) {
   8362   1.1  christos 		for (myrdata = ISC_LIST_HEAD(myrdatalist->rdata);
   8363   1.1  christos 		     myrdata != NULL;
   8364   1.1  christos 		     myrdata = ISC_LIST_HEAD(myrdatalist->rdata))
   8365   1.1  christos 		{
   8366   1.1  christos 			ISC_LIST_UNLINK(myrdatalist->rdata, myrdata, link);
   8367   1.1  christos 			dns_message_puttemprdata(client->message, &myrdata);
   8368   1.1  christos 		}
   8369   1.1  christos 		dns_message_puttemprdatalist(client->message, &myrdatalist);
   8370   1.1  christos 	}
   8371   1.3  christos 	if (qctx->dbuf != NULL) {
   8372   1.3  christos 		ns_client_releasename(client, &name);
   8373   1.3  christos 	}
   8374   1.1  christos 
   8375   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done");
   8376   1.1  christos }
   8377   1.1  christos 
   8378   1.1  christos /*%
   8379   1.1  christos  * Handle the case of a name not being found in a database lookup.
   8380   1.1  christos  * Called from query_gotanswer(). Passes off processing to
   8381   1.1  christos  * query_delegation() for a root referral if appropriate.
   8382   1.1  christos  */
   8383   1.1  christos static isc_result_t
   8384   1.1  christos query_notfound(query_ctx_t *qctx) {
   8385   1.1  christos 	isc_result_t result;
   8386   1.1  christos 
   8387   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_notfound");
   8388   1.9  christos 
   8389   1.3  christos 	CALL_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx);
   8390   1.3  christos 
   8391   1.1  christos 	INSIST(!qctx->is_zone);
   8392   1.1  christos 
   8393   1.9  christos 	if (qctx->db != NULL) {
   8394   1.1  christos 		dns_db_detach(&qctx->db);
   8395   1.9  christos 	}
   8396   1.1  christos 
   8397   1.1  christos 	/*
   8398   1.1  christos 	 * If the cache doesn't even have the root NS,
   8399   1.1  christos 	 * try to get that from the hints DB.
   8400   1.1  christos 	 */
   8401   1.3  christos 	if (qctx->view->hints != NULL) {
   8402   1.1  christos 		dns_clientinfomethods_t cm;
   8403   1.1  christos 		dns_clientinfo_t ci;
   8404   1.1  christos 
   8405   1.1  christos 		dns_clientinfomethods_init(&cm, ns_client_sourceip);
   8406  1.15  christos 		dns_clientinfo_init(&ci, qctx->client, NULL, NULL);
   8407   1.1  christos 
   8408   1.3  christos 		dns_db_attach(qctx->view->hints, &qctx->db);
   8409   1.9  christos 		result = dns_db_findext(qctx->db, dns_rootname, NULL,
   8410   1.9  christos 					dns_rdatatype_ns, 0, qctx->client->now,
   8411   1.9  christos 					&qctx->node, qctx->fname, &cm, &ci,
   8412   1.1  christos 					qctx->rdataset, qctx->sigrdataset);
   8413   1.1  christos 	} else {
   8414   1.1  christos 		/* We have no hints. */
   8415   1.1  christos 		result = ISC_R_FAILURE;
   8416   1.1  christos 	}
   8417   1.1  christos 	if (result != ISC_R_SUCCESS) {
   8418   1.1  christos 		/*
   8419   1.1  christos 		 * Nonsensical root hints may require cleanup.
   8420   1.1  christos 		 */
   8421   1.1  christos 		qctx_clean(qctx);
   8422   1.1  christos 
   8423   1.1  christos 		/*
   8424   1.1  christos 		 * We don't have any root server hints, but
   8425   1.1  christos 		 * we may have working forwarders, so try to
   8426   1.1  christos 		 * recurse anyway.
   8427   1.1  christos 		 */
   8428   1.1  christos 		if (RECURSIONOK(qctx->client)) {
   8429   1.1  christos 			INSIST(!REDIRECT(qctx->client));
   8430   1.3  christos 			result = ns_query_recurse(qctx->client, qctx->qtype,
   8431   1.3  christos 						  qctx->client->query.qname,
   8432   1.3  christos 						  NULL, NULL, qctx->resuming);
   8433   1.1  christos 			if (result == ISC_R_SUCCESS) {
   8434   1.3  christos 				CALL_HOOK(NS_QUERY_NOTFOUND_RECURSE, qctx);
   8435   1.1  christos 				qctx->client->query.attributes |=
   8436   1.9  christos 					NS_QUERYATTR_RECURSING;
   8437   1.3  christos 
   8438   1.3  christos 				if (qctx->dns64) {
   8439   1.1  christos 					qctx->client->query.attributes |=
   8440   1.1  christos 						NS_QUERYATTR_DNS64;
   8441   1.3  christos 				}
   8442   1.3  christos 				if (qctx->dns64_exclude) {
   8443   1.1  christos 					qctx->client->query.attributes |=
   8444   1.1  christos 						NS_QUERYATTR_DNS64EXCLUDE;
   8445   1.3  christos 				}
   8446  1.13  christos 			} else if (query_usestale(qctx, result)) {
   8447  1.13  christos 				/*
   8448  1.13  christos 				 * If serve-stale is enabled, query_usestale()
   8449  1.13  christos 				 * already set up 'qctx' for looking up a
   8450  1.13  christos 				 * stale response.
   8451  1.13  christos 				 */
   8452  1.13  christos 				return (query_lookup(qctx));
   8453   1.3  christos 			} else {
   8454   1.3  christos 				QUERY_ERROR(qctx, result);
   8455   1.3  christos 			}
   8456   1.3  christos 			return (ns_query_done(qctx));
   8457   1.1  christos 		} else {
   8458   1.1  christos 			/* Unable to give root server referral. */
   8459   1.9  christos 			CCTRACE(ISC_LOG_ERROR, "unable to give root server "
   8460   1.9  christos 					       "referral");
   8461   1.3  christos 			QUERY_ERROR(qctx, result);
   8462   1.3  christos 			return (ns_query_done(qctx));
   8463   1.1  christos 		}
   8464   1.1  christos 	}
   8465   1.1  christos 
   8466   1.1  christos 	return (query_delegation(qctx));
   8467   1.3  christos 
   8468   1.9  christos cleanup:
   8469   1.3  christos 	return (result);
   8470   1.3  christos }
   8471   1.3  christos 
   8472   1.3  christos /*%
   8473   1.3  christos  * We have a delegation but recursion is not allowed, so return the delegation
   8474   1.3  christos  * to the client.
   8475   1.3  christos  */
   8476   1.3  christos static isc_result_t
   8477   1.3  christos query_prepare_delegation_response(query_ctx_t *qctx) {
   8478   1.3  christos 	isc_result_t result;
   8479   1.3  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   8480   1.3  christos 	bool detach = false;
   8481   1.3  christos 
   8482   1.3  christos 	CALL_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx);
   8483   1.3  christos 
   8484   1.3  christos 	/*
   8485   1.3  christos 	 * qctx->fname could be released in query_addrrset(), so save a copy of
   8486   1.3  christos 	 * it here in case we need it.
   8487   1.3  christos 	 */
   8488   1.3  christos 	dns_fixedname_init(&qctx->dsname);
   8489   1.8  christos 	dns_name_copynf(qctx->fname, dns_fixedname_name(&qctx->dsname));
   8490   1.3  christos 
   8491   1.3  christos 	/*
   8492   1.3  christos 	 * This is the best answer.
   8493   1.3  christos 	 */
   8494   1.3  christos 	qctx->client->query.isreferral = true;
   8495   1.3  christos 
   8496   1.3  christos 	if (!dns_db_iscache(qctx->db) && qctx->client->query.gluedb == NULL) {
   8497   1.3  christos 		dns_db_attach(qctx->db, &qctx->client->query.gluedb);
   8498   1.3  christos 		detach = true;
   8499   1.3  christos 	}
   8500   1.3  christos 
   8501   1.3  christos 	/*
   8502   1.3  christos 	 * We must ensure NOADDITIONAL is off, because the generation of
   8503   1.3  christos 	 * additional data is required in delegations.
   8504   1.3  christos 	 */
   8505   1.3  christos 	qctx->client->query.attributes &= ~NS_QUERYATTR_NOADDITIONAL;
   8506   1.3  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   8507   1.3  christos 		sigrdatasetp = &qctx->sigrdataset;
   8508   1.3  christos 	}
   8509   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   8510   1.9  christos 		       qctx->dbuf, DNS_SECTION_AUTHORITY);
   8511   1.3  christos 	if (detach) {
   8512   1.3  christos 		dns_db_detach(&qctx->client->query.gluedb);
   8513   1.3  christos 	}
   8514   1.3  christos 
   8515   1.3  christos 	/*
   8516  1.14  christos 	 * Add DS/NSEC(3) record(s) if needed.
   8517   1.3  christos 	 */
   8518   1.3  christos 	query_addds(qctx);
   8519   1.3  christos 
   8520   1.3  christos 	return (ns_query_done(qctx));
   8521   1.3  christos 
   8522   1.9  christos cleanup:
   8523   1.3  christos 	return (result);
   8524   1.1  christos }
   8525   1.1  christos 
   8526   1.1  christos /*%
   8527   1.1  christos  * Handle a delegation response from an authoritative lookup. This
   8528   1.1  christos  * may trigger additional lookups, e.g. from the cache database to
   8529   1.1  christos  * see if we have a better answer; if that is not allowed, return the
   8530   1.3  christos  * delegation to the client and call ns_query_done().
   8531   1.1  christos  */
   8532   1.1  christos static isc_result_t
   8533   1.1  christos query_zone_delegation(query_ctx_t *qctx) {
   8534   1.1  christos 	isc_result_t result;
   8535   1.3  christos 
   8536   1.3  christos 	CALL_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx);
   8537   1.1  christos 
   8538   1.1  christos 	/*
   8539   1.1  christos 	 * If the query type is DS, look to see if we are
   8540   1.1  christos 	 * authoritative for the child zone
   8541   1.1  christos 	 */
   8542   1.1  christos 	if (!RECURSIONOK(qctx->client) &&
   8543   1.1  christos 	    (qctx->options & DNS_GETDB_NOEXACT) != 0 &&
   8544   1.1  christos 	    qctx->qtype == dns_rdatatype_ds)
   8545   1.1  christos 	{
   8546   1.1  christos 		dns_db_t *tdb = NULL;
   8547   1.1  christos 		dns_zone_t *tzone = NULL;
   8548   1.1  christos 		dns_dbversion_t *tversion = NULL;
   8549   1.9  christos 		result = query_getzonedb(
   8550   1.9  christos 			qctx->client, qctx->client->query.qname, qctx->qtype,
   8551   1.9  christos 			DNS_GETDB_PARTIAL, &tzone, &tdb, &tversion);
   8552   1.1  christos 		if (result != ISC_R_SUCCESS) {
   8553   1.9  christos 			if (tdb != NULL) {
   8554   1.1  christos 				dns_db_detach(&tdb);
   8555   1.9  christos 			}
   8556   1.9  christos 			if (tzone != NULL) {
   8557   1.1  christos 				dns_zone_detach(&tzone);
   8558   1.9  christos 			}
   8559   1.1  christos 		} else {
   8560   1.1  christos 			qctx->options &= ~DNS_GETDB_NOEXACT;
   8561   1.9  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   8562   1.3  christos 			if (qctx->sigrdataset != NULL) {
   8563   1.3  christos 				ns_client_putrdataset(qctx->client,
   8564   1.3  christos 						      &qctx->sigrdataset);
   8565   1.3  christos 			}
   8566   1.3  christos 			if (qctx->fname != NULL) {
   8567   1.3  christos 				ns_client_releasename(qctx->client,
   8568   1.3  christos 						      &qctx->fname);
   8569   1.3  christos 			}
   8570   1.9  christos 			if (qctx->node != NULL) {
   8571   1.9  christos 				dns_db_detachnode(qctx->db, &qctx->node);
   8572   1.9  christos 			}
   8573   1.9  christos 			if (qctx->db != NULL) {
   8574   1.1  christos 				dns_db_detach(&qctx->db);
   8575   1.9  christos 			}
   8576   1.9  christos 			if (qctx->zone != NULL) {
   8577   1.1  christos 				dns_zone_detach(&qctx->zone);
   8578   1.9  christos 			}
   8579   1.1  christos 			qctx->version = NULL;
   8580   1.1  christos 			RESTORE(qctx->version, tversion);
   8581   1.1  christos 			RESTORE(qctx->db, tdb);
   8582   1.1  christos 			RESTORE(qctx->zone, tzone);
   8583   1.3  christos 			qctx->authoritative = true;
   8584   1.1  christos 
   8585   1.1  christos 			return (query_lookup(qctx));
   8586   1.1  christos 		}
   8587   1.1  christos 	}
   8588   1.1  christos 
   8589   1.3  christos 	if (USECACHE(qctx->client) &&
   8590   1.3  christos 	    (RECURSIONOK(qctx->client) ||
   8591   1.3  christos 	     (qctx->zone != NULL &&
   8592   1.3  christos 	      dns_zone_gettype(qctx->zone) == dns_zone_mirror)))
   8593   1.3  christos 	{
   8594   1.1  christos 		/*
   8595   1.1  christos 		 * We might have a better answer or delegation in the
   8596   1.1  christos 		 * cache.  We'll remember the current values of fname,
   8597   1.1  christos 		 * rdataset, and sigrdataset.  We'll then go looking for
   8598   1.1  christos 		 * QNAME in the cache.  If we find something better, we'll
   8599   1.1  christos 		 * use it instead. If not, then query_lookup() calls
   8600   1.1  christos 		 * query_notfound() which calls query_delegation(), and
   8601   1.1  christos 		 * we'll restore these values there.
   8602   1.1  christos 		 */
   8603   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   8604   1.1  christos 		SAVE(qctx->zdb, qctx->db);
   8605   1.3  christos 		SAVE(qctx->znode, qctx->node);
   8606   1.1  christos 		SAVE(qctx->zfname, qctx->fname);
   8607   1.1  christos 		SAVE(qctx->zversion, qctx->version);
   8608   1.1  christos 		SAVE(qctx->zrdataset, qctx->rdataset);
   8609   1.1  christos 		SAVE(qctx->zsigrdataset, qctx->sigrdataset);
   8610   1.3  christos 		dns_db_attach(qctx->view->cachedb, &qctx->db);
   8611   1.3  christos 		qctx->is_zone = false;
   8612   1.1  christos 
   8613   1.1  christos 		return (query_lookup(qctx));
   8614   1.1  christos 	}
   8615   1.1  christos 
   8616   1.3  christos 	return (query_prepare_delegation_response(qctx));
   8617   1.1  christos 
   8618   1.9  christos cleanup:
   8619   1.3  christos 	return (result);
   8620   1.1  christos }
   8621   1.1  christos 
   8622   1.1  christos /*%
   8623   1.1  christos  * Handle delegation responses, including root referrals.
   8624   1.1  christos  *
   8625   1.1  christos  * If the delegation was returned from authoritative data,
   8626   1.1  christos  * call query_zone_delgation().  Otherwise, we can start
   8627   1.1  christos  * recursion if allowed; or else return the delegation to the
   8628   1.3  christos  * client and call ns_query_done().
   8629   1.1  christos  */
   8630   1.1  christos static isc_result_t
   8631   1.1  christos query_delegation(query_ctx_t *qctx) {
   8632   1.1  christos 	isc_result_t result;
   8633   1.1  christos 
   8634   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_delegation");
   8635   1.9  christos 
   8636   1.3  christos 	CALL_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx);
   8637   1.3  christos 
   8638   1.3  christos 	qctx->authoritative = false;
   8639   1.1  christos 
   8640   1.1  christos 	if (qctx->is_zone) {
   8641   1.1  christos 		return (query_zone_delegation(qctx));
   8642   1.1  christos 	}
   8643   1.1  christos 
   8644   1.1  christos 	if (qctx->zfname != NULL &&
   8645   1.1  christos 	    (!dns_name_issubdomain(qctx->fname, qctx->zfname) ||
   8646   1.1  christos 	     (qctx->is_staticstub_zone &&
   8647   1.1  christos 	      dns_name_equal(qctx->fname, qctx->zfname))))
   8648   1.1  christos 	{
   8649   1.1  christos 		/*
   8650   1.1  christos 		 * In the following cases use "authoritative"
   8651   1.1  christos 		 * data instead of the cache delegation:
   8652   1.1  christos 		 * 1. We've already got a delegation from
   8653   1.1  christos 		 *    authoritative data, and it is better
   8654   1.1  christos 		 *    than what we found in the cache.
   8655   1.1  christos 		 *    (See the comment above.)
   8656   1.1  christos 		 * 2. The query name matches the origin name
   8657   1.1  christos 		 *    of a static-stub zone.  This needs to be
   8658   1.1  christos 		 *    considered for the case where the NS of
   8659   1.1  christos 		 *    the static-stub zone and the cached NS
   8660   1.1  christos 		 *    are different.  We still need to contact
   8661   1.1  christos 		 *    the nameservers configured in the
   8662   1.1  christos 		 *    static-stub zone.
   8663   1.1  christos 		 */
   8664   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   8665   1.1  christos 
   8666   1.1  christos 		/*
   8667   1.3  christos 		 * We've already done ns_client_keepname() on
   8668   1.1  christos 		 * qctx->zfname, so we must set dbuf to NULL to
   8669   1.1  christos 		 * prevent query_addrrset() from trying to
   8670   1.3  christos 		 * call ns_client_keepname() again.
   8671   1.1  christos 		 */
   8672   1.1  christos 		qctx->dbuf = NULL;
   8673   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   8674   1.3  christos 		if (qctx->sigrdataset != NULL) {
   8675   1.9  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   8676   1.3  christos 		}
   8677   1.1  christos 		qctx->version = NULL;
   8678   1.1  christos 
   8679   1.3  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   8680   1.3  christos 		dns_db_detach(&qctx->db);
   8681   1.3  christos 		RESTORE(qctx->db, qctx->zdb);
   8682   1.3  christos 		RESTORE(qctx->node, qctx->znode);
   8683   1.1  christos 		RESTORE(qctx->fname, qctx->zfname);
   8684   1.1  christos 		RESTORE(qctx->version, qctx->zversion);
   8685   1.1  christos 		RESTORE(qctx->rdataset, qctx->zrdataset);
   8686   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->zsigrdataset);
   8687   1.3  christos 	}
   8688   1.1  christos 
   8689   1.3  christos 	result = query_delegation_recurse(qctx);
   8690   1.3  christos 	if (result != ISC_R_COMPLETE) {
   8691   1.3  christos 		return (result);
   8692   1.1  christos 	}
   8693   1.1  christos 
   8694   1.3  christos 	return (query_prepare_delegation_response(qctx));
   8695   1.1  christos 
   8696   1.9  christos cleanup:
   8697   1.3  christos 	return (result);
   8698   1.3  christos }
   8699   1.1  christos 
   8700   1.3  christos /*%
   8701   1.3  christos  * Handle recursive queries that are triggered as part of the
   8702   1.3  christos  * delegation process.
   8703   1.3  christos  */
   8704   1.3  christos static isc_result_t
   8705   1.3  christos query_delegation_recurse(query_ctx_t *qctx) {
   8706   1.3  christos 	isc_result_t result;
   8707   1.3  christos 	dns_name_t *qname = qctx->client->query.qname;
   8708   1.1  christos 
   8709   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_delegation_recurse");
   8710   1.9  christos 
   8711   1.3  christos 	if (!RECURSIONOK(qctx->client)) {
   8712   1.3  christos 		return (ISC_R_COMPLETE);
   8713   1.1  christos 	}
   8714   1.1  christos 
   8715   1.3  christos 	CALL_HOOK(NS_QUERY_DELEGATION_RECURSE_BEGIN, qctx);
   8716   1.3  christos 
   8717   1.1  christos 	/*
   8718   1.3  christos 	 * We have a delegation and recursion is allowed,
   8719   1.3  christos 	 * so we call ns_query_recurse() to follow it.
   8720   1.3  christos 	 * This phase of the query processing is done;
   8721   1.3  christos 	 * we'll resume via fetch_callback() and
   8722   1.3  christos 	 * query_resume() when the recursion is complete.
   8723   1.1  christos 	 */
   8724   1.1  christos 
   8725   1.3  christos 	INSIST(!REDIRECT(qctx->client));
   8726   1.1  christos 
   8727   1.3  christos 	if (dns_rdatatype_atparent(qctx->type)) {
   8728   1.3  christos 		/*
   8729   1.3  christos 		 * Parent is authoritative for this RDATA type (i.e. DS).
   8730   1.3  christos 		 */
   8731   1.3  christos 		result = ns_query_recurse(qctx->client, qctx->qtype, qname,
   8732   1.3  christos 					  NULL, NULL, qctx->resuming);
   8733   1.3  christos 	} else if (qctx->dns64) {
   8734   1.3  christos 		/*
   8735   1.3  christos 		 * Look up an A record so we can synthesize DNS64.
   8736   1.3  christos 		 */
   8737   1.3  christos 		result = ns_query_recurse(qctx->client, dns_rdatatype_a, qname,
   8738   1.3  christos 					  NULL, NULL, qctx->resuming);
   8739   1.3  christos 	} else {
   8740   1.3  christos 		/*
   8741   1.3  christos 		 * Any other recursion.
   8742   1.3  christos 		 */
   8743   1.3  christos 		result = ns_query_recurse(qctx->client, qctx->qtype, qname,
   8744   1.3  christos 					  qctx->fname, qctx->rdataset,
   8745   1.3  christos 					  qctx->resuming);
   8746   1.1  christos 	}
   8747   1.1  christos 
   8748   1.3  christos 	if (result == ISC_R_SUCCESS) {
   8749   1.3  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   8750   1.3  christos 		if (qctx->dns64) {
   8751   1.3  christos 			qctx->client->query.attributes |= NS_QUERYATTR_DNS64;
   8752   1.3  christos 		}
   8753   1.3  christos 		if (qctx->dns64_exclude) {
   8754   1.3  christos 			qctx->client->query.attributes |=
   8755   1.9  christos 				NS_QUERYATTR_DNS64EXCLUDE;
   8756   1.3  christos 		}
   8757  1.13  christos 	} else if (query_usestale(qctx, result)) {
   8758  1.13  christos 		/*
   8759  1.13  christos 		 * If serve-stale is enabled, query_usestale() already set up
   8760  1.13  christos 		 * 'qctx' for looking up a stale response.
   8761  1.13  christos 		 */
   8762  1.13  christos 		return (query_lookup(qctx));
   8763   1.3  christos 	} else {
   8764   1.3  christos 		QUERY_ERROR(qctx, result);
   8765   1.1  christos 	}
   8766   1.1  christos 
   8767   1.3  christos 	return (ns_query_done(qctx));
   8768   1.1  christos 
   8769   1.9  christos cleanup:
   8770   1.3  christos 	return (result);
   8771   1.1  christos }
   8772   1.1  christos 
   8773   1.1  christos /*%
   8774  1.14  christos  * Add DS/NSEC(3) record(s) if needed.
   8775   1.1  christos  */
   8776   1.1  christos static void
   8777   1.1  christos query_addds(query_ctx_t *qctx) {
   8778   1.1  christos 	ns_client_t *client = qctx->client;
   8779   1.1  christos 	dns_fixedname_t fixed;
   8780   1.1  christos 	dns_name_t *fname = NULL;
   8781   1.1  christos 	dns_name_t *rname = NULL;
   8782   1.1  christos 	dns_name_t *name;
   8783   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   8784   1.1  christos 	isc_buffer_t *dbuf, b;
   8785   1.1  christos 	isc_result_t result;
   8786   1.1  christos 	unsigned int count;
   8787   1.1  christos 
   8788   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addds");
   8789   1.1  christos 
   8790   1.1  christos 	/*
   8791   1.1  christos 	 * DS not needed.
   8792   1.1  christos 	 */
   8793   1.1  christos 	if (!WANTDNSSEC(client)) {
   8794   1.1  christos 		return;
   8795   1.1  christos 	}
   8796   1.1  christos 
   8797   1.1  christos 	/*
   8798   1.1  christos 	 * We'll need some resources...
   8799   1.1  christos 	 */
   8800   1.3  christos 	rdataset = ns_client_newrdataset(client);
   8801   1.3  christos 	sigrdataset = ns_client_newrdataset(client);
   8802   1.9  christos 	if (rdataset == NULL || sigrdataset == NULL) {
   8803   1.1  christos 		goto cleanup;
   8804   1.9  christos 	}
   8805   1.1  christos 
   8806   1.1  christos 	/*
   8807   1.1  christos 	 * Look for the DS record, which may or may not be present.
   8808   1.1  christos 	 */
   8809   1.1  christos 	result = dns_db_findrdataset(qctx->db, qctx->node, qctx->version,
   8810   1.9  christos 				     dns_rdatatype_ds, 0, client->now, rdataset,
   8811   1.9  christos 				     sigrdataset);
   8812   1.1  christos 	/*
   8813   1.1  christos 	 * If we didn't find it, look for an NSEC.
   8814   1.1  christos 	 */
   8815   1.9  christos 	if (result == ISC_R_NOTFOUND) {
   8816   1.9  christos 		result = dns_db_findrdataset(
   8817   1.9  christos 			qctx->db, qctx->node, qctx->version, dns_rdatatype_nsec,
   8818   1.9  christos 			0, client->now, rdataset, sigrdataset);
   8819   1.9  christos 	}
   8820   1.9  christos 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
   8821   1.1  christos 		goto addnsec3;
   8822   1.9  christos 	}
   8823   1.1  christos 	if (!dns_rdataset_isassociated(rdataset) ||
   8824   1.1  christos 	    !dns_rdataset_isassociated(sigrdataset))
   8825   1.9  christos 	{
   8826   1.1  christos 		goto addnsec3;
   8827   1.9  christos 	}
   8828   1.1  christos 
   8829   1.1  christos 	/*
   8830   1.1  christos 	 * We've already added the NS record, so if the name's not there,
   8831  1.14  christos 	 * we have other problems.
   8832   1.1  christos 	 */
   8833   1.1  christos 	result = dns_message_firstname(client->message, DNS_SECTION_AUTHORITY);
   8834   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8835   1.1  christos 		goto cleanup;
   8836   1.9  christos 	}
   8837   1.1  christos 
   8838  1.14  christos 	/*
   8839  1.14  christos 	 * Find the delegation in the response message - it is not necessarily
   8840  1.14  christos 	 * the first name in the AUTHORITY section when wildcard processing is
   8841  1.14  christos 	 * involved.
   8842  1.14  christos 	 */
   8843  1.14  christos 	while (result == ISC_R_SUCCESS) {
   8844  1.14  christos 		rname = NULL;
   8845  1.14  christos 		dns_message_currentname(client->message, DNS_SECTION_AUTHORITY,
   8846  1.14  christos 					&rname);
   8847  1.14  christos 		result = dns_message_findtype(rname, dns_rdatatype_ns, 0, NULL);
   8848  1.14  christos 		if (result == ISC_R_SUCCESS) {
   8849  1.14  christos 			break;
   8850  1.14  christos 		}
   8851  1.14  christos 		result = dns_message_nextname(client->message,
   8852  1.14  christos 					      DNS_SECTION_AUTHORITY);
   8853  1.14  christos 	}
   8854  1.14  christos 
   8855   1.9  christos 	if (result != ISC_R_SUCCESS) {
   8856   1.1  christos 		goto cleanup;
   8857   1.9  christos 	}
   8858   1.1  christos 
   8859  1.14  christos 	/*
   8860  1.14  christos 	 * Add the relevant RRset (DS or NSEC) to the delegation.
   8861  1.14  christos 	 */
   8862  1.14  christos 	query_addrrset(qctx, &rname, &rdataset, &sigrdataset, NULL,
   8863  1.14  christos 		       DNS_SECTION_AUTHORITY);
   8864  1.14  christos 	goto cleanup;
   8865   1.1  christos 
   8866   1.9  christos addnsec3:
   8867   1.9  christos 	if (!dns_db_iszone(qctx->db)) {
   8868   1.1  christos 		goto cleanup;
   8869   1.9  christos 	}
   8870   1.1  christos 	/*
   8871   1.1  christos 	 * Add the NSEC3 which proves the DS does not exist.
   8872   1.1  christos 	 */
   8873   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   8874   1.9  christos 	if (dbuf == NULL) {
   8875   1.1  christos 		goto cleanup;
   8876   1.9  christos 	}
   8877   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   8878   1.1  christos 	dns_fixedname_init(&fixed);
   8879   1.9  christos 	if (dns_rdataset_isassociated(rdataset)) {
   8880   1.1  christos 		dns_rdataset_disassociate(rdataset);
   8881   1.9  christos 	}
   8882   1.9  christos 	if (dns_rdataset_isassociated(sigrdataset)) {
   8883   1.1  christos 		dns_rdataset_disassociate(sigrdataset);
   8884   1.9  christos 	}
   8885   1.1  christos 	name = dns_fixedname_name(&qctx->dsname);
   8886   1.1  christos 	query_findclosestnsec3(name, qctx->db, qctx->version, client, rdataset,
   8887   1.3  christos 			       sigrdataset, fname, true,
   8888   1.1  christos 			       dns_fixedname_name(&fixed));
   8889   1.9  christos 	if (!dns_rdataset_isassociated(rdataset)) {
   8890   1.1  christos 		goto cleanup;
   8891   1.9  christos 	}
   8892   1.3  christos 	query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   8893   1.1  christos 		       DNS_SECTION_AUTHORITY);
   8894   1.1  christos 	/*
   8895   1.1  christos 	 * Did we find the closest provable encloser instead?
   8896   1.1  christos 	 * If so add the nearest to the closest provable encloser.
   8897   1.1  christos 	 */
   8898   1.1  christos 	if (!dns_name_equal(name, dns_fixedname_name(&fixed))) {
   8899   1.1  christos 		count = dns_name_countlabels(dns_fixedname_name(&fixed)) + 1;
   8900   1.1  christos 		dns_name_getlabelsequence(name,
   8901   1.1  christos 					  dns_name_countlabels(name) - count,
   8902   1.1  christos 					  count, dns_fixedname_name(&fixed));
   8903   1.1  christos 		fixfname(client, &fname, &dbuf, &b);
   8904   1.1  christos 		fixrdataset(client, &rdataset);
   8905   1.1  christos 		fixrdataset(client, &sigrdataset);
   8906   1.9  christos 		if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   8907   1.9  christos 			goto cleanup;
   8908   1.9  christos 		}
   8909   1.9  christos 		query_findclosestnsec3(dns_fixedname_name(&fixed), qctx->db,
   8910   1.9  christos 				       qctx->version, client, rdataset,
   8911   1.9  christos 				       sigrdataset, fname, false, NULL);
   8912   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   8913   1.1  christos 			goto cleanup;
   8914   1.9  christos 		}
   8915   1.3  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   8916   1.1  christos 			       DNS_SECTION_AUTHORITY);
   8917   1.1  christos 	}
   8918   1.1  christos 
   8919   1.9  christos cleanup:
   8920   1.3  christos 	if (rdataset != NULL) {
   8921   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   8922   1.3  christos 	}
   8923   1.3  christos 	if (sigrdataset != NULL) {
   8924   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   8925   1.3  christos 	}
   8926   1.3  christos 	if (fname != NULL) {
   8927   1.3  christos 		ns_client_releasename(client, &fname);
   8928   1.3  christos 	}
   8929   1.1  christos }
   8930   1.1  christos 
   8931   1.1  christos /*%
   8932   1.1  christos  * Handle authoritative NOERROR/NODATA responses.
   8933   1.1  christos  */
   8934   1.1  christos static isc_result_t
   8935   1.3  christos query_nodata(query_ctx_t *qctx, isc_result_t res) {
   8936   1.3  christos 	isc_result_t result = res;
   8937   1.3  christos 
   8938   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_nodata");
   8939   1.9  christos 
   8940   1.3  christos 	CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx);
   8941   1.3  christos 
   8942   1.1  christos #ifdef dns64_bis_return_excluded_addresses
   8943   1.1  christos 	if (qctx->dns64)
   8944   1.9  christos #else  /* ifdef dns64_bis_return_excluded_addresses */
   8945   1.1  christos 	if (qctx->dns64 && !qctx->dns64_exclude)
   8946   1.9  christos #endif /* ifdef dns64_bis_return_excluded_addresses */
   8947   1.1  christos 	{
   8948   1.1  christos 		isc_buffer_t b;
   8949   1.1  christos 		/*
   8950   1.1  christos 		 * Restore the answers from the previous AAAA lookup.
   8951   1.1  christos 		 */
   8952   1.9  christos 		if (qctx->rdataset != NULL) {
   8953   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->rdataset);
   8954   1.9  christos 		}
   8955   1.9  christos 		if (qctx->sigrdataset != NULL) {
   8956   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   8957   1.9  christos 		}
   8958   1.1  christos 		RESTORE(qctx->rdataset, qctx->client->query.dns64_aaaa);
   8959   1.1  christos 		RESTORE(qctx->sigrdataset, qctx->client->query.dns64_sigaaaa);
   8960   1.1  christos 		if (qctx->fname == NULL) {
   8961   1.3  christos 			qctx->dbuf = ns_client_getnamebuf(qctx->client);
   8962   1.1  christos 			if (qctx->dbuf == NULL) {
   8963   1.9  christos 				CCTRACE(ISC_LOG_ERROR, "query_nodata: "
   8964   1.9  christos 						       "ns_client_getnamebuf "
   8965   1.9  christos 						       "failed (3)");
   8966   1.3  christos 				QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   8967   1.9  christos 				return (ns_query_done(qctx));
   8968   1.1  christos 			}
   8969   1.3  christos 			qctx->fname = ns_client_newname(qctx->client,
   8970   1.3  christos 							qctx->dbuf, &b);
   8971   1.1  christos 			if (qctx->fname == NULL) {
   8972   1.9  christos 				CCTRACE(ISC_LOG_ERROR, "query_nodata: "
   8973   1.9  christos 						       "ns_client_newname "
   8974   1.9  christos 						       "failed (3)");
   8975   1.3  christos 				QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   8976   1.9  christos 				return (ns_query_done(qctx));
   8977   1.1  christos 			}
   8978   1.1  christos 		}
   8979   1.8  christos 		dns_name_copynf(qctx->client->query.qname, qctx->fname);
   8980   1.3  christos 		qctx->dns64 = false;
   8981   1.1  christos #ifdef dns64_bis_return_excluded_addresses
   8982   1.1  christos 		/*
   8983   1.1  christos 		 * Resume the diverted processing of the AAAA response?
   8984   1.1  christos 		 */
   8985   1.9  christos 		if (qctx->dns64_exclude) {
   8986   1.1  christos 			return (query_prepresponse(qctx));
   8987   1.9  christos 		}
   8988   1.9  christos #endif /* ifdef dns64_bis_return_excluded_addresses */
   8989   1.9  christos 	} else if ((result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) &&
   8990   1.9  christos 		   !ISC_LIST_EMPTY(qctx->view->dns64) && !qctx->nxrewrite &&
   8991   1.1  christos 		   qctx->client->message->rdclass == dns_rdataclass_in &&
   8992   1.1  christos 		   qctx->qtype == dns_rdatatype_aaaa)
   8993   1.1  christos 	{
   8994   1.1  christos 		/*
   8995   1.1  christos 		 * Look to see if there are A records for this name.
   8996   1.1  christos 		 */
   8997   1.1  christos 		switch (result) {
   8998   1.1  christos 		case DNS_R_NCACHENXRRSET:
   8999   1.1  christos 			/*
   9000   1.1  christos 			 * This is from the negative cache; if the ttl is
   9001   1.1  christos 			 * zero, we need to work out whether we have just
   9002   1.1  christos 			 * decremented to zero or there was no negative
   9003   1.1  christos 			 * cache ttl in the answer.
   9004   1.1  christos 			 */
   9005   1.1  christos 			if (qctx->rdataset->ttl != 0) {
   9006   1.1  christos 				qctx->client->query.dns64_ttl =
   9007   1.1  christos 					qctx->rdataset->ttl;
   9008   1.1  christos 				break;
   9009   1.1  christos 			}
   9010   1.1  christos 			if (dns_rdataset_first(qctx->rdataset) == ISC_R_SUCCESS)
   9011   1.9  christos 			{
   9012   1.1  christos 				qctx->client->query.dns64_ttl = 0;
   9013   1.9  christos 			}
   9014   1.1  christos 			break;
   9015   1.1  christos 		case DNS_R_NXRRSET:
   9016   1.1  christos 			qctx->client->query.dns64_ttl =
   9017   1.1  christos 				dns64_ttl(qctx->db, qctx->version);
   9018   1.1  christos 			break;
   9019   1.1  christos 		default:
   9020  1.15  christos 			UNREACHABLE();
   9021   1.1  christos 		}
   9022   1.1  christos 
   9023   1.1  christos 		SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset);
   9024   1.1  christos 		SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset);
   9025   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9026   1.1  christos 		dns_db_detachnode(qctx->db, &qctx->node);
   9027   1.1  christos 		qctx->type = qctx->qtype = dns_rdatatype_a;
   9028   1.3  christos 		qctx->dns64 = true;
   9029   1.1  christos 		return (query_lookup(qctx));
   9030   1.1  christos 	}
   9031   1.1  christos 
   9032   1.1  christos 	if (qctx->is_zone) {
   9033   1.1  christos 		return (query_sign_nodata(qctx));
   9034   1.1  christos 	} else {
   9035   1.1  christos 		/*
   9036   1.1  christos 		 * We don't call query_addrrset() because we don't need any
   9037   1.1  christos 		 * of its extra features (and things would probably break!).
   9038   1.1  christos 		 */
   9039   1.1  christos 		if (dns_rdataset_isassociated(qctx->rdataset)) {
   9040   1.3  christos 			ns_client_keepname(qctx->client, qctx->fname,
   9041   1.3  christos 					   qctx->dbuf);
   9042   1.9  christos 			dns_message_addname(qctx->client->message, qctx->fname,
   9043   1.1  christos 					    DNS_SECTION_AUTHORITY);
   9044   1.9  christos 			ISC_LIST_APPEND(qctx->fname->list, qctx->rdataset,
   9045   1.9  christos 					link);
   9046   1.1  christos 			qctx->fname = NULL;
   9047   1.1  christos 			qctx->rdataset = NULL;
   9048   1.1  christos 		}
   9049   1.1  christos 	}
   9050   1.1  christos 
   9051   1.3  christos 	return (ns_query_done(qctx));
   9052   1.3  christos 
   9053   1.9  christos cleanup:
   9054   1.3  christos 	return (result);
   9055   1.1  christos }
   9056   1.1  christos 
   9057   1.1  christos /*%
   9058   1.1  christos  * Add RRSIGs for NOERROR/NODATA responses when answering authoritatively.
   9059   1.1  christos  */
   9060   1.1  christos isc_result_t
   9061   1.1  christos query_sign_nodata(query_ctx_t *qctx) {
   9062   1.1  christos 	isc_result_t result;
   9063   1.9  christos 
   9064   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_sign_nodata");
   9065   1.9  christos 
   9066   1.1  christos 	/*
   9067   1.1  christos 	 * Look for a NSEC3 record if we don't have a NSEC record.
   9068   1.1  christos 	 */
   9069   1.9  christos 	if (qctx->redirected) {
   9070   1.3  christos 		return (ns_query_done(qctx));
   9071   1.9  christos 	}
   9072   1.1  christos 	if (!dns_rdataset_isassociated(qctx->rdataset) &&
   9073  1.16  christos 	    WANTDNSSEC(qctx->client))
   9074  1.16  christos 	{
   9075   1.1  christos 		if ((qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
   9076   1.1  christos 			dns_name_t *found;
   9077   1.1  christos 			dns_name_t *qname;
   9078   1.1  christos 			dns_fixedname_t fixed;
   9079   1.1  christos 			isc_buffer_t b;
   9080   1.1  christos 
   9081   1.1  christos 			found = dns_fixedname_initname(&fixed);
   9082   1.1  christos 			qname = qctx->client->query.qname;
   9083   1.1  christos 
   9084   1.1  christos 			query_findclosestnsec3(qname, qctx->db, qctx->version,
   9085   1.1  christos 					       qctx->client, qctx->rdataset,
   9086   1.1  christos 					       qctx->sigrdataset, qctx->fname,
   9087   1.3  christos 					       true, found);
   9088   1.1  christos 			/*
   9089   1.1  christos 			 * Did we find the closest provable encloser
   9090   1.1  christos 			 * instead? If so add the nearest to the
   9091   1.1  christos 			 * closest provable encloser.
   9092   1.1  christos 			 */
   9093   1.1  christos 			if (dns_rdataset_isassociated(qctx->rdataset) &&
   9094   1.1  christos 			    !dns_name_equal(qname, found) &&
   9095   1.1  christos 			    (((qctx->client->sctx->options &
   9096   1.1  christos 			       NS_SERVER_NONEAREST) == 0) ||
   9097   1.1  christos 			     qctx->qtype == dns_rdatatype_ds))
   9098   1.1  christos 			{
   9099   1.1  christos 				unsigned int count;
   9100   1.1  christos 				unsigned int skip;
   9101   1.1  christos 
   9102   1.1  christos 				/*
   9103   1.1  christos 				 * Add the closest provable encloser.
   9104   1.1  christos 				 */
   9105   1.3  christos 				query_addrrset(qctx, &qctx->fname,
   9106   1.1  christos 					       &qctx->rdataset,
   9107   1.9  christos 					       &qctx->sigrdataset, qctx->dbuf,
   9108   1.1  christos 					       DNS_SECTION_AUTHORITY);
   9109   1.1  christos 
   9110   1.9  christos 				count = dns_name_countlabels(found) + 1;
   9111   1.9  christos 				skip = dns_name_countlabels(qname) - count;
   9112   1.9  christos 				dns_name_getlabelsequence(qname, skip, count,
   9113   1.1  christos 							  found);
   9114   1.1  christos 
   9115   1.1  christos 				fixfname(qctx->client, &qctx->fname,
   9116   1.1  christos 					 &qctx->dbuf, &b);
   9117   1.1  christos 				fixrdataset(qctx->client, &qctx->rdataset);
   9118   1.1  christos 				fixrdataset(qctx->client, &qctx->sigrdataset);
   9119   1.1  christos 				if (qctx->fname == NULL ||
   9120   1.1  christos 				    qctx->rdataset == NULL ||
   9121  1.16  christos 				    qctx->sigrdataset == NULL)
   9122  1.16  christos 				{
   9123   1.9  christos 					CCTRACE(ISC_LOG_ERROR, "query_sign_"
   9124   1.9  christos 							       "nodata: "
   9125   1.9  christos 							       "failure "
   9126   1.9  christos 							       "getting "
   9127   1.9  christos 							       "closest "
   9128   1.9  christos 							       "encloser");
   9129   1.3  christos 					QUERY_ERROR(qctx, ISC_R_NOMEMORY);
   9130   1.3  christos 					return (ns_query_done(qctx));
   9131   1.1  christos 				}
   9132   1.1  christos 				/*
   9133   1.1  christos 				 * 'nearest' doesn't exist so
   9134   1.3  christos 				 * 'exist' is set to false.
   9135   1.1  christos 				 */
   9136   1.9  christos 				query_findclosestnsec3(
   9137   1.9  christos 					found, qctx->db, qctx->version,
   9138   1.9  christos 					qctx->client, qctx->rdataset,
   9139   1.9  christos 					qctx->sigrdataset, qctx->fname, false,
   9140   1.9  christos 					NULL);
   9141   1.1  christos 			}
   9142   1.1  christos 		} else {
   9143   1.3  christos 			ns_client_releasename(qctx->client, &qctx->fname);
   9144   1.3  christos 			query_addwildcardproof(qctx, false, true);
   9145   1.1  christos 		}
   9146   1.1  christos 	}
   9147   1.1  christos 	if (dns_rdataset_isassociated(qctx->rdataset)) {
   9148   1.1  christos 		/*
   9149   1.1  christos 		 * If we've got a NSEC record, we need to save the
   9150   1.1  christos 		 * name now because we're going call query_addsoa()
   9151   1.1  christos 		 * below, and it needs to use the name buffer.
   9152   1.1  christos 		 */
   9153   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9154   1.1  christos 	} else if (qctx->fname != NULL) {
   9155   1.1  christos 		/*
   9156   1.1  christos 		 * We're not going to use fname, and need to release
   9157   1.1  christos 		 * our hold on the name buffer so query_addsoa()
   9158   1.1  christos 		 * may use it.
   9159   1.1  christos 		 */
   9160   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9161   1.1  christos 	}
   9162   1.1  christos 
   9163   1.1  christos 	/*
   9164   1.1  christos 	 * The RPZ SOA has already been added to the additional section
   9165   1.1  christos 	 * if this was an RPZ rewrite, but if it wasn't, add it now.
   9166   1.1  christos 	 */
   9167   1.1  christos 	if (!qctx->nxrewrite) {
   9168   1.9  christos 		result = query_addsoa(qctx, UINT32_MAX, DNS_SECTION_AUTHORITY);
   9169   1.1  christos 		if (result != ISC_R_SUCCESS) {
   9170   1.1  christos 			QUERY_ERROR(qctx, result);
   9171   1.3  christos 			return (ns_query_done(qctx));
   9172   1.1  christos 		}
   9173   1.1  christos 	}
   9174   1.1  christos 
   9175   1.1  christos 	/*
   9176   1.1  christos 	 * Add NSEC record if we found one.
   9177   1.1  christos 	 */
   9178   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   9179  1.16  christos 	    dns_rdataset_isassociated(qctx->rdataset))
   9180  1.16  christos 	{
   9181   1.1  christos 		query_addnxrrsetnsec(qctx);
   9182   1.1  christos 	}
   9183   1.1  christos 
   9184   1.3  christos 	return (ns_query_done(qctx));
   9185   1.1  christos }
   9186   1.1  christos 
   9187   1.1  christos static void
   9188   1.1  christos query_addnxrrsetnsec(query_ctx_t *qctx) {
   9189   1.1  christos 	ns_client_t *client = qctx->client;
   9190   1.1  christos 	dns_rdata_t sigrdata;
   9191   1.1  christos 	dns_rdata_rrsig_t sig;
   9192   1.1  christos 	unsigned int labels;
   9193   1.1  christos 	isc_buffer_t *dbuf, b;
   9194   1.1  christos 	dns_name_t *fname;
   9195   1.3  christos 	isc_result_t result;
   9196   1.1  christos 
   9197   1.1  christos 	INSIST(qctx->fname != NULL);
   9198   1.1  christos 
   9199   1.1  christos 	if ((qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) {
   9200   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9201   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9202   1.1  christos 		return;
   9203   1.1  christos 	}
   9204   1.1  christos 
   9205   1.1  christos 	if (qctx->sigrdataset == NULL ||
   9206  1.16  christos 	    !dns_rdataset_isassociated(qctx->sigrdataset))
   9207  1.16  christos 	{
   9208   1.1  christos 		return;
   9209   1.1  christos 	}
   9210   1.1  christos 
   9211   1.1  christos 	if (dns_rdataset_first(qctx->sigrdataset) != ISC_R_SUCCESS) {
   9212   1.1  christos 		return;
   9213   1.1  christos 	}
   9214   1.1  christos 
   9215   1.1  christos 	dns_rdata_init(&sigrdata);
   9216   1.1  christos 	dns_rdataset_current(qctx->sigrdataset, &sigrdata);
   9217   1.3  christos 	result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
   9218   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9219   1.1  christos 
   9220   1.1  christos 	labels = dns_name_countlabels(qctx->fname);
   9221   1.1  christos 	if ((unsigned int)sig.labels + 1 >= labels) {
   9222   1.1  christos 		return;
   9223   1.1  christos 	}
   9224   1.1  christos 
   9225   1.3  christos 	query_addwildcardproof(qctx, true, false);
   9226   1.1  christos 
   9227   1.1  christos 	/*
   9228   1.1  christos 	 * We'll need some resources...
   9229   1.1  christos 	 */
   9230   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   9231   1.1  christos 	if (dbuf == NULL) {
   9232   1.1  christos 		return;
   9233   1.1  christos 	}
   9234   1.1  christos 
   9235   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   9236   1.1  christos 	if (fname == NULL) {
   9237   1.1  christos 		return;
   9238   1.1  christos 	}
   9239   1.1  christos 
   9240   1.1  christos 	dns_name_split(qctx->fname, sig.labels + 1, NULL, fname);
   9241   1.1  christos 	/* This will succeed, since we've stripped labels. */
   9242   1.1  christos 	RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname,
   9243   1.1  christos 					   NULL) == ISC_R_SUCCESS);
   9244   1.9  christos 	query_addrrset(qctx, &fname, &qctx->rdataset, &qctx->sigrdataset, dbuf,
   9245   1.9  christos 		       DNS_SECTION_AUTHORITY);
   9246   1.1  christos }
   9247   1.1  christos 
   9248   1.1  christos /*%
   9249   1.1  christos  * Handle NXDOMAIN and empty wildcard responses.
   9250   1.1  christos  */
   9251   1.1  christos static isc_result_t
   9252  1.18  christos query_nxdomain(query_ctx_t *qctx, isc_result_t result) {
   9253   1.1  christos 	dns_section_t section;
   9254   1.3  christos 	uint32_t ttl;
   9255  1.18  christos 	bool empty_wild = (result == DNS_R_EMPTYWILD);
   9256   1.1  christos 
   9257   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_nxdomain");
   9258   1.9  christos 
   9259   1.3  christos 	CALL_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx);
   9260   1.3  christos 
   9261   1.1  christos 	INSIST(qctx->is_zone || REDIRECT(qctx->client));
   9262   1.1  christos 
   9263   1.1  christos 	if (!empty_wild) {
   9264  1.18  christos 		result = query_redirect(qctx, result);
   9265   1.9  christos 		if (result != ISC_R_COMPLETE) {
   9266   1.1  christos 			return (result);
   9267   1.9  christos 		}
   9268   1.1  christos 	}
   9269   1.1  christos 
   9270   1.1  christos 	if (dns_rdataset_isassociated(qctx->rdataset)) {
   9271   1.1  christos 		/*
   9272   1.1  christos 		 * If we've got a NSEC record, we need to save the
   9273   1.1  christos 		 * name now because we're going call query_addsoa()
   9274   1.1  christos 		 * below, and it needs to use the name buffer.
   9275   1.1  christos 		 */
   9276   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9277   1.1  christos 	} else if (qctx->fname != NULL) {
   9278   1.1  christos 		/*
   9279   1.1  christos 		 * We're not going to use fname, and need to release
   9280   1.1  christos 		 * our hold on the name buffer so query_addsoa()
   9281   1.1  christos 		 * may use it.
   9282   1.1  christos 		 */
   9283   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9284   1.1  christos 	}
   9285   1.1  christos 
   9286   1.1  christos 	/*
   9287   1.1  christos 	 * Add SOA to the additional section if generated by a
   9288   1.1  christos 	 * RPZ rewrite.
   9289   1.1  christos 	 *
   9290   1.1  christos 	 * If the query was for a SOA record force the
   9291   1.1  christos 	 * ttl to zero so that it is possible for clients to find
   9292   1.1  christos 	 * the containing zone of an arbitrary name with a stub
   9293   1.1  christos 	 * resolver and not have it cached.
   9294   1.1  christos 	 */
   9295   1.1  christos 	section = qctx->nxrewrite ? DNS_SECTION_ADDITIONAL
   9296   1.1  christos 				  : DNS_SECTION_AUTHORITY;
   9297   1.3  christos 	ttl = UINT32_MAX;
   9298   1.1  christos 	if (!qctx->nxrewrite && qctx->qtype == dns_rdatatype_soa &&
   9299   1.1  christos 	    qctx->zone != NULL && dns_zone_getzeronosoattl(qctx->zone))
   9300   1.1  christos 	{
   9301   1.1  christos 		ttl = 0;
   9302   1.1  christos 	}
   9303  1.16  christos 	if (!qctx->nxrewrite ||
   9304  1.16  christos 	    (qctx->rpz_st != NULL && qctx->rpz_st->m.rpz->addsoa))
   9305  1.16  christos 	{
   9306   1.5  christos 		result = query_addsoa(qctx, ttl, section);
   9307   1.5  christos 		if (result != ISC_R_SUCCESS) {
   9308   1.5  christos 			QUERY_ERROR(qctx, result);
   9309   1.5  christos 			return (ns_query_done(qctx));
   9310   1.5  christos 		}
   9311   1.1  christos 	}
   9312   1.1  christos 
   9313   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9314   1.1  christos 		/*
   9315   1.1  christos 		 * Add NSEC record if we found one.
   9316   1.1  christos 		 */
   9317   1.9  christos 		if (dns_rdataset_isassociated(qctx->rdataset)) {
   9318   1.9  christos 			query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9319   1.9  christos 				       &qctx->sigrdataset, NULL,
   9320   1.9  christos 				       DNS_SECTION_AUTHORITY);
   9321   1.9  christos 		}
   9322   1.3  christos 		query_addwildcardproof(qctx, false, false);
   9323   1.1  christos 	}
   9324   1.1  christos 
   9325   1.1  christos 	/*
   9326   1.1  christos 	 * Set message rcode.
   9327   1.1  christos 	 */
   9328   1.9  christos 	if (empty_wild) {
   9329   1.1  christos 		qctx->client->message->rcode = dns_rcode_noerror;
   9330   1.9  christos 	} else {
   9331   1.1  christos 		qctx->client->message->rcode = dns_rcode_nxdomain;
   9332   1.9  christos 	}
   9333   1.1  christos 
   9334   1.3  christos 	return (ns_query_done(qctx));
   9335   1.3  christos 
   9336   1.9  christos cleanup:
   9337   1.3  christos 	return (result);
   9338   1.1  christos }
   9339   1.1  christos 
   9340   1.1  christos /*
   9341   1.1  christos  * Handle both types of NXDOMAIN redirection, calling redirect()
   9342   1.1  christos  * (which implements type redirect zones) and redirect2() (which
   9343   1.1  christos  * implements recursive nxdomain-redirect lookups).
   9344   1.1  christos  *
   9345   1.1  christos  * Any result code other than ISC_R_COMPLETE means redirection was
   9346   1.1  christos  * successful and the result code should be returned up the call stack.
   9347   1.1  christos  *
   9348   1.1  christos  * ISC_R_COMPLETE means we reached the end of this function without
   9349   1.1  christos  * redirecting, so query processing should continue past it.
   9350   1.1  christos  */
   9351   1.1  christos static isc_result_t
   9352  1.18  christos query_redirect(query_ctx_t *qctx, isc_result_t saved_result) {
   9353   1.1  christos 	isc_result_t result;
   9354   1.1  christos 
   9355   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_redirect");
   9356   1.9  christos 
   9357   1.1  christos 	result = redirect(qctx->client, qctx->fname, qctx->rdataset,
   9358   1.9  christos 			  &qctx->node, &qctx->db, &qctx->version, qctx->type);
   9359   1.1  christos 	switch (result) {
   9360   1.1  christos 	case ISC_R_SUCCESS:
   9361   1.9  christos 		inc_stats(qctx->client, ns_statscounter_nxdomainredirect);
   9362   1.1  christos 		return (query_prepresponse(qctx));
   9363   1.1  christos 	case DNS_R_NXRRSET:
   9364   1.3  christos 		qctx->redirected = true;
   9365   1.3  christos 		qctx->is_zone = true;
   9366   1.1  christos 		return (query_nodata(qctx, DNS_R_NXRRSET));
   9367   1.1  christos 	case DNS_R_NCACHENXRRSET:
   9368   1.3  christos 		qctx->redirected = true;
   9369   1.3  christos 		qctx->is_zone = false;
   9370   1.1  christos 		return (query_ncache(qctx, DNS_R_NCACHENXRRSET));
   9371   1.1  christos 	default:
   9372   1.1  christos 		break;
   9373   1.1  christos 	}
   9374   1.1  christos 
   9375   1.1  christos 	result = redirect2(qctx->client, qctx->fname, qctx->rdataset,
   9376   1.9  christos 			   &qctx->node, &qctx->db, &qctx->version, qctx->type,
   9377   1.9  christos 			   &qctx->is_zone);
   9378   1.1  christos 	switch (result) {
   9379   1.1  christos 	case ISC_R_SUCCESS:
   9380   1.9  christos 		inc_stats(qctx->client, ns_statscounter_nxdomainredirect);
   9381   1.1  christos 		return (query_prepresponse(qctx));
   9382   1.1  christos 	case DNS_R_CONTINUE:
   9383   1.1  christos 		inc_stats(qctx->client,
   9384   1.1  christos 			  ns_statscounter_nxdomainredirect_rlookup);
   9385   1.1  christos 		SAVE(qctx->client->query.redirect.db, qctx->db);
   9386   1.1  christos 		SAVE(qctx->client->query.redirect.node, qctx->node);
   9387   1.1  christos 		SAVE(qctx->client->query.redirect.zone, qctx->zone);
   9388   1.1  christos 		qctx->client->query.redirect.qtype = qctx->qtype;
   9389   1.1  christos 		INSIST(qctx->rdataset != NULL);
   9390   1.1  christos 		SAVE(qctx->client->query.redirect.rdataset, qctx->rdataset);
   9391   1.1  christos 		SAVE(qctx->client->query.redirect.sigrdataset,
   9392   1.1  christos 		     qctx->sigrdataset);
   9393  1.18  christos 		qctx->client->query.redirect.result = saved_result;
   9394   1.8  christos 		dns_name_copynf(qctx->fname,
   9395   1.9  christos 				qctx->client->query.redirect.fname);
   9396   1.1  christos 		qctx->client->query.redirect.authoritative =
   9397   1.1  christos 			qctx->authoritative;
   9398   1.1  christos 		qctx->client->query.redirect.is_zone = qctx->is_zone;
   9399   1.3  christos 		return (ns_query_done(qctx));
   9400   1.1  christos 	case DNS_R_NXRRSET:
   9401   1.3  christos 		qctx->redirected = true;
   9402   1.3  christos 		qctx->is_zone = true;
   9403   1.1  christos 		return (query_nodata(qctx, DNS_R_NXRRSET));
   9404   1.1  christos 	case DNS_R_NCACHENXRRSET:
   9405   1.3  christos 		qctx->redirected = true;
   9406   1.3  christos 		qctx->is_zone = false;
   9407   1.1  christos 		return (query_ncache(qctx, DNS_R_NCACHENXRRSET));
   9408   1.1  christos 	default:
   9409   1.1  christos 		break;
   9410   1.1  christos 	}
   9411   1.1  christos 
   9412   1.1  christos 	return (ISC_R_COMPLETE);
   9413   1.1  christos }
   9414   1.1  christos 
   9415   1.1  christos /*%
   9416   1.1  christos  * Logging function to be passed to dns_nsec_noexistnodata.
   9417   1.1  christos  */
   9418   1.1  christos static void
   9419   1.1  christos log_noexistnodata(void *val, int level, const char *fmt, ...) {
   9420   1.1  christos 	query_ctx_t *qctx = val;
   9421   1.1  christos 	va_list ap;
   9422   1.1  christos 
   9423   1.1  christos 	va_start(ap, fmt);
   9424   1.9  christos 	ns_client_logv(qctx->client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY,
   9425   1.9  christos 		       level, fmt, ap);
   9426   1.1  christos 	va_end(ap);
   9427   1.1  christos }
   9428   1.1  christos 
   9429   1.1  christos static dns_ttl_t
   9430   1.1  christos query_synthttl(dns_rdataset_t *soardataset, dns_rdataset_t *sigsoardataset,
   9431   1.1  christos 	       dns_rdataset_t *p1rdataset, dns_rdataset_t *sigp1rdataset,
   9432   1.9  christos 	       dns_rdataset_t *p2rdataset, dns_rdataset_t *sigp2rdataset) {
   9433   1.1  christos 	dns_rdata_soa_t soa;
   9434   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   9435   1.1  christos 	dns_ttl_t ttl;
   9436   1.1  christos 	isc_result_t result;
   9437   1.1  christos 
   9438   1.1  christos 	REQUIRE(soardataset != NULL);
   9439   1.1  christos 	REQUIRE(sigsoardataset != NULL);
   9440   1.1  christos 	REQUIRE(p1rdataset != NULL);
   9441   1.1  christos 	REQUIRE(sigp1rdataset != NULL);
   9442   1.1  christos 
   9443   1.1  christos 	result = dns_rdataset_first(soardataset);
   9444   1.1  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9445   1.1  christos 	dns_rdataset_current(soardataset, &rdata);
   9446   1.3  christos 	result = dns_rdata_tostruct(&rdata, &soa, NULL);
   9447   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9448   1.1  christos 
   9449   1.1  christos 	ttl = ISC_MIN(soa.minimum, soardataset->ttl);
   9450   1.1  christos 	ttl = ISC_MIN(ttl, sigsoardataset->ttl);
   9451   1.1  christos 	ttl = ISC_MIN(ttl, p1rdataset->ttl);
   9452   1.1  christos 	ttl = ISC_MIN(ttl, sigp1rdataset->ttl);
   9453   1.9  christos 	if (p2rdataset != NULL) {
   9454   1.1  christos 		ttl = ISC_MIN(ttl, p2rdataset->ttl);
   9455   1.9  christos 	}
   9456   1.9  christos 	if (sigp2rdataset != NULL) {
   9457   1.1  christos 		ttl = ISC_MIN(ttl, sigp2rdataset->ttl);
   9458   1.9  christos 	}
   9459   1.1  christos 
   9460   1.1  christos 	return (ttl);
   9461   1.1  christos }
   9462   1.1  christos 
   9463   1.1  christos /*
   9464   1.1  christos  * Synthesize a NODATA response from the SOA and covering NSEC in cache.
   9465   1.1  christos  */
   9466   1.1  christos static isc_result_t
   9467   1.1  christos query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer,
   9468   1.1  christos 		  dns_rdataset_t **soardatasetp,
   9469   1.9  christos 		  dns_rdataset_t **sigsoardatasetp) {
   9470   1.1  christos 	dns_name_t *name = NULL;
   9471   1.1  christos 	dns_ttl_t ttl;
   9472   1.1  christos 	isc_buffer_t *dbuf, b;
   9473   1.1  christos 	isc_result_t result;
   9474   1.1  christos 
   9475   1.1  christos 	/*
   9476   1.9  christos 	 * Determine the correct TTL to use for the SOA and RRSIG
   9477   1.1  christos 	 */
   9478   1.9  christos 	ttl = query_synthttl(*soardatasetp, *sigsoardatasetp, qctx->rdataset,
   9479   1.9  christos 			     qctx->sigrdataset, NULL, NULL);
   9480   1.1  christos 	(*soardatasetp)->ttl = (*sigsoardatasetp)->ttl = ttl;
   9481   1.1  christos 
   9482   1.1  christos 	/*
   9483   1.1  christos 	 * We want the SOA record to be first, so save the
   9484   1.1  christos 	 * NODATA proof's name now or else discard it.
   9485   1.1  christos 	 */
   9486   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9487   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9488   1.1  christos 	} else {
   9489   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9490   1.1  christos 	}
   9491   1.1  christos 
   9492   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   9493   1.1  christos 	if (dbuf == NULL) {
   9494   1.1  christos 		result = ISC_R_NOMEMORY;
   9495   1.1  christos 		goto cleanup;
   9496   1.1  christos 	}
   9497   1.1  christos 
   9498   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   9499   1.1  christos 	if (name == NULL) {
   9500   1.1  christos 		result = ISC_R_NOMEMORY;
   9501   1.1  christos 		goto cleanup;
   9502   1.1  christos 	}
   9503   1.1  christos 
   9504   1.8  christos 	dns_name_copynf(signer, name);
   9505   1.1  christos 
   9506   1.1  christos 	/*
   9507   1.1  christos 	 * Add SOA record. Omit the RRSIG if DNSSEC was not requested.
   9508   1.1  christos 	 */
   9509   1.1  christos 	if (!WANTDNSSEC(qctx->client)) {
   9510   1.1  christos 		sigsoardatasetp = NULL;
   9511   1.1  christos 	}
   9512   1.9  christos 	query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf,
   9513   1.9  christos 		       DNS_SECTION_AUTHORITY);
   9514   1.1  christos 
   9515   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9516   1.1  christos 		/*
   9517   1.1  christos 		 * Add NODATA proof.
   9518   1.1  christos 		 */
   9519   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9520   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9521   1.1  christos 	}
   9522   1.1  christos 
   9523   1.1  christos 	result = ISC_R_SUCCESS;
   9524   1.1  christos 	inc_stats(qctx->client, ns_statscounter_nodatasynth);
   9525   1.1  christos 
   9526   1.1  christos cleanup:
   9527   1.1  christos 	if (name != NULL) {
   9528   1.3  christos 		ns_client_releasename(qctx->client, &name);
   9529   1.1  christos 	}
   9530   1.1  christos 	return (result);
   9531   1.1  christos }
   9532   1.1  christos 
   9533   1.1  christos /*
   9534   1.1  christos  * Synthesize a wildcard answer using the contents of 'rdataset'.
   9535   1.1  christos  * qctx contains the NODATA proof.
   9536   1.1  christos  */
   9537   1.1  christos static isc_result_t
   9538   1.1  christos query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
   9539   1.9  christos 		    dns_rdataset_t *sigrdataset) {
   9540   1.1  christos 	dns_name_t *name = NULL;
   9541   1.1  christos 	isc_buffer_t *dbuf, b;
   9542   1.1  christos 	isc_result_t result;
   9543   1.3  christos 	dns_rdataset_t *cloneset = NULL, *clonesigset = NULL;
   9544   1.1  christos 	dns_rdataset_t **sigrdatasetp;
   9545   1.1  christos 
   9546   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_synthwildcard");
   9547   1.9  christos 
   9548   1.1  christos 	/*
   9549   1.1  christos 	 * We want the answer to be first, so save the
   9550   1.1  christos 	 * NOQNAME proof's name now or else discard it.
   9551   1.1  christos 	 */
   9552   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9553   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9554   1.1  christos 	} else {
   9555   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9556   1.1  christos 	}
   9557   1.1  christos 
   9558   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   9559   1.1  christos 	if (dbuf == NULL) {
   9560   1.1  christos 		result = ISC_R_NOMEMORY;
   9561   1.1  christos 		goto cleanup;
   9562   1.1  christos 	}
   9563   1.1  christos 
   9564   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   9565   1.1  christos 	if (name == NULL) {
   9566   1.1  christos 		result = ISC_R_NOMEMORY;
   9567   1.1  christos 		goto cleanup;
   9568   1.1  christos 	}
   9569   1.8  christos 	dns_name_copynf(qctx->client->query.qname, name);
   9570   1.1  christos 
   9571   1.3  christos 	cloneset = ns_client_newrdataset(qctx->client);
   9572   1.3  christos 	if (cloneset == NULL) {
   9573   1.1  christos 		result = ISC_R_NOMEMORY;
   9574   1.1  christos 		goto cleanup;
   9575   1.1  christos 	}
   9576   1.3  christos 	dns_rdataset_clone(rdataset, cloneset);
   9577   1.1  christos 
   9578   1.1  christos 	/*
   9579   1.1  christos 	 * Add answer RRset. Omit the RRSIG if DNSSEC was not requested.
   9580   1.1  christos 	 */
   9581   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9582   1.3  christos 		clonesigset = ns_client_newrdataset(qctx->client);
   9583   1.3  christos 		if (clonesigset == NULL) {
   9584   1.1  christos 			result = ISC_R_NOMEMORY;
   9585   1.1  christos 			goto cleanup;
   9586   1.1  christos 		}
   9587   1.3  christos 		dns_rdataset_clone(sigrdataset, clonesigset);
   9588   1.3  christos 		sigrdatasetp = &clonesigset;
   9589   1.1  christos 	} else {
   9590   1.1  christos 		sigrdatasetp = NULL;
   9591   1.1  christos 	}
   9592   1.1  christos 
   9593   1.9  christos 	query_addrrset(qctx, &name, &cloneset, sigrdatasetp, dbuf,
   9594   1.9  christos 		       DNS_SECTION_ANSWER);
   9595   1.1  christos 
   9596   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9597   1.1  christos 		/*
   9598   1.1  christos 		 * Add NOQNAME proof.
   9599   1.1  christos 		 */
   9600   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9601   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9602   1.1  christos 	}
   9603   1.1  christos 
   9604   1.1  christos 	result = ISC_R_SUCCESS;
   9605   1.1  christos 	inc_stats(qctx->client, ns_statscounter_wildcardsynth);
   9606   1.1  christos 
   9607   1.1  christos cleanup:
   9608   1.1  christos 	if (name != NULL) {
   9609   1.3  christos 		ns_client_releasename(qctx->client, &name);
   9610   1.1  christos 	}
   9611   1.3  christos 	if (cloneset != NULL) {
   9612   1.3  christos 		ns_client_putrdataset(qctx->client, &cloneset);
   9613   1.1  christos 	}
   9614   1.3  christos 	if (clonesigset != NULL) {
   9615   1.3  christos 		ns_client_putrdataset(qctx->client, &clonesigset);
   9616   1.1  christos 	}
   9617   1.1  christos 	return (result);
   9618   1.1  christos }
   9619   1.1  christos 
   9620   1.1  christos /*
   9621   1.1  christos  * Add a synthesized CNAME record from the wildard RRset (rdataset)
   9622   1.1  christos  * and NODATA proof by calling query_synthwildcard then setup to
   9623   1.1  christos  * follow the CNAME.
   9624   1.1  christos  */
   9625   1.1  christos static isc_result_t
   9626   1.1  christos query_synthcnamewildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset,
   9627   1.9  christos 			 dns_rdataset_t *sigrdataset) {
   9628   1.1  christos 	isc_result_t result;
   9629   1.1  christos 	dns_name_t *tname = NULL;
   9630   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   9631   1.1  christos 	dns_rdata_cname_t cname;
   9632   1.1  christos 
   9633   1.1  christos 	result = query_synthwildcard(qctx, rdataset, sigrdataset);
   9634   1.1  christos 	if (result != ISC_R_SUCCESS) {
   9635   1.1  christos 		return (result);
   9636   1.1  christos 	}
   9637   1.1  christos 
   9638   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   9639   1.1  christos 
   9640   1.1  christos 	/*
   9641   1.1  christos 	 * Reset qname to be the target name of the CNAME and restart
   9642   1.1  christos 	 * the query.
   9643   1.1  christos 	 */
   9644   1.1  christos 	result = dns_message_gettempname(qctx->client->message, &tname);
   9645   1.1  christos 	if (result != ISC_R_SUCCESS) {
   9646   1.1  christos 		return (result);
   9647   1.1  christos 	}
   9648   1.1  christos 
   9649   1.1  christos 	result = dns_rdataset_first(rdataset);
   9650   1.1  christos 	if (result != ISC_R_SUCCESS) {
   9651   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   9652   1.1  christos 		return (result);
   9653   1.1  christos 	}
   9654   1.1  christos 
   9655   1.1  christos 	dns_rdataset_current(rdataset, &rdata);
   9656   1.1  christos 	result = dns_rdata_tostruct(&rdata, &cname, NULL);
   9657   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9658   1.1  christos 	dns_rdata_reset(&rdata);
   9659   1.1  christos 
   9660  1.14  christos 	dns_name_copynf(&cname.cname, tname);
   9661   1.1  christos 
   9662   1.1  christos 	dns_rdata_freestruct(&cname);
   9663   1.1  christos 	ns_client_qnamereplace(qctx->client, tname);
   9664   1.3  christos 	qctx->want_restart = true;
   9665   1.1  christos 	if (!WANTRECURSION(qctx->client)) {
   9666   1.1  christos 		qctx->options |= DNS_GETDB_NOLOG;
   9667   1.1  christos 	}
   9668   1.1  christos 
   9669   1.1  christos 	return (result);
   9670   1.1  christos }
   9671   1.1  christos 
   9672   1.1  christos /*
   9673   1.1  christos  * Synthesize a NXDOMAIN response from qctx (which contains the
   9674   1.1  christos  * NODATA proof), nowild + nowildrdataset + signowildrdataset (which
   9675   1.1  christos  * contains the NOWILDCARD proof) and signer + soardatasetp + sigsoardatasetp
   9676   1.1  christos  * which contain the SOA record + RRSIG for the negative answer.
   9677   1.1  christos  */
   9678   1.1  christos static isc_result_t
   9679   1.9  christos query_synthnxdomain(query_ctx_t *qctx, dns_name_t *nowild,
   9680   1.1  christos 		    dns_rdataset_t *nowildrdataset,
   9681   1.9  christos 		    dns_rdataset_t *signowildrdataset, dns_name_t *signer,
   9682   1.1  christos 		    dns_rdataset_t **soardatasetp,
   9683   1.9  christos 		    dns_rdataset_t **sigsoardatasetp) {
   9684   1.1  christos 	dns_name_t *name = NULL;
   9685   1.1  christos 	dns_ttl_t ttl;
   9686   1.1  christos 	isc_buffer_t *dbuf, b;
   9687   1.1  christos 	isc_result_t result;
   9688   1.3  christos 	dns_rdataset_t *cloneset = NULL, *clonesigset = NULL;
   9689   1.1  christos 
   9690   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_synthnxdomain");
   9691   1.9  christos 
   9692   1.1  christos 	/*
   9693   1.9  christos 	 * Determine the correct TTL to use for the SOA and RRSIG
   9694   1.1  christos 	 */
   9695   1.9  christos 	ttl = query_synthttl(*soardatasetp, *sigsoardatasetp, qctx->rdataset,
   9696   1.9  christos 			     qctx->sigrdataset, nowildrdataset,
   9697   1.9  christos 			     signowildrdataset);
   9698   1.1  christos 	(*soardatasetp)->ttl = (*sigsoardatasetp)->ttl = ttl;
   9699   1.1  christos 
   9700   1.1  christos 	/*
   9701   1.1  christos 	 * We want the SOA record to be first, so save the
   9702   1.1  christos 	 * NOQNAME proof's name now or else discard it.
   9703   1.1  christos 	 */
   9704   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9705   1.3  christos 		ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   9706   1.1  christos 	} else {
   9707   1.3  christos 		ns_client_releasename(qctx->client, &qctx->fname);
   9708   1.1  christos 	}
   9709   1.1  christos 
   9710   1.3  christos 	dbuf = ns_client_getnamebuf(qctx->client);
   9711   1.1  christos 	if (dbuf == NULL) {
   9712   1.1  christos 		result = ISC_R_NOMEMORY;
   9713   1.1  christos 		goto cleanup;
   9714   1.1  christos 	}
   9715   1.1  christos 
   9716   1.3  christos 	name = ns_client_newname(qctx->client, dbuf, &b);
   9717   1.1  christos 	if (name == NULL) {
   9718   1.1  christos 		result = ISC_R_NOMEMORY;
   9719   1.1  christos 		goto cleanup;
   9720   1.1  christos 	}
   9721   1.1  christos 
   9722   1.8  christos 	dns_name_copynf(signer, name);
   9723   1.1  christos 
   9724   1.1  christos 	/*
   9725   1.1  christos 	 * Add SOA record. Omit the RRSIG if DNSSEC was not requested.
   9726   1.1  christos 	 */
   9727   1.1  christos 	if (!WANTDNSSEC(qctx->client)) {
   9728   1.1  christos 		sigsoardatasetp = NULL;
   9729   1.1  christos 	}
   9730   1.9  christos 	query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf,
   9731   1.9  christos 		       DNS_SECTION_AUTHORITY);
   9732   1.1  christos 
   9733   1.1  christos 	if (WANTDNSSEC(qctx->client)) {
   9734   1.1  christos 		/*
   9735   1.1  christos 		 * Add NOQNAME proof.
   9736   1.1  christos 		 */
   9737   1.9  christos 		query_addrrset(qctx, &qctx->fname, &qctx->rdataset,
   9738   1.9  christos 			       &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY);
   9739   1.1  christos 
   9740   1.3  christos 		dbuf = ns_client_getnamebuf(qctx->client);
   9741   1.1  christos 		if (dbuf == NULL) {
   9742   1.1  christos 			result = ISC_R_NOMEMORY;
   9743   1.1  christos 			goto cleanup;
   9744   1.1  christos 		}
   9745   1.1  christos 
   9746   1.3  christos 		name = ns_client_newname(qctx->client, dbuf, &b);
   9747   1.1  christos 		if (name == NULL) {
   9748   1.1  christos 			result = ISC_R_NOMEMORY;
   9749   1.1  christos 			goto cleanup;
   9750   1.1  christos 		}
   9751   1.1  christos 
   9752   1.8  christos 		dns_name_copynf(nowild, name);
   9753   1.1  christos 
   9754   1.3  christos 		cloneset = ns_client_newrdataset(qctx->client);
   9755   1.3  christos 		clonesigset = ns_client_newrdataset(qctx->client);
   9756   1.3  christos 		if (cloneset == NULL || clonesigset == NULL) {
   9757   1.1  christos 			result = ISC_R_NOMEMORY;
   9758   1.1  christos 			goto cleanup;
   9759   1.1  christos 		}
   9760   1.1  christos 
   9761   1.3  christos 		dns_rdataset_clone(nowildrdataset, cloneset);
   9762   1.3  christos 		dns_rdataset_clone(signowildrdataset, clonesigset);
   9763   1.1  christos 
   9764   1.1  christos 		/*
   9765   1.1  christos 		 * Add NOWILDCARD proof.
   9766   1.1  christos 		 */
   9767   1.9  christos 		query_addrrset(qctx, &name, &cloneset, &clonesigset, dbuf,
   9768   1.9  christos 			       DNS_SECTION_AUTHORITY);
   9769   1.1  christos 	}
   9770   1.1  christos 
   9771   1.1  christos 	qctx->client->message->rcode = dns_rcode_nxdomain;
   9772   1.1  christos 	result = ISC_R_SUCCESS;
   9773   1.1  christos 	inc_stats(qctx->client, ns_statscounter_nxdomainsynth);
   9774   1.1  christos 
   9775   1.1  christos cleanup:
   9776   1.1  christos 	if (name != NULL) {
   9777   1.3  christos 		ns_client_releasename(qctx->client, &name);
   9778   1.1  christos 	}
   9779   1.3  christos 	if (cloneset != NULL) {
   9780   1.3  christos 		ns_client_putrdataset(qctx->client, &cloneset);
   9781   1.1  christos 	}
   9782   1.3  christos 	if (clonesigset != NULL) {
   9783   1.3  christos 		ns_client_putrdataset(qctx->client, &clonesigset);
   9784   1.1  christos 	}
   9785   1.1  christos 	return (result);
   9786   1.1  christos }
   9787   1.1  christos 
   9788   1.1  christos /*
   9789   1.1  christos  * Check that all signer names in sigrdataset match the expected signer.
   9790   1.1  christos  */
   9791   1.1  christos static isc_result_t
   9792   1.1  christos checksignames(dns_name_t *signer, dns_rdataset_t *sigrdataset) {
   9793   1.1  christos 	isc_result_t result;
   9794   1.1  christos 
   9795   1.9  christos 	for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
   9796   1.9  christos 	     result = dns_rdataset_next(sigrdataset))
   9797   1.9  christos 	{
   9798   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   9799   1.1  christos 		dns_rdata_rrsig_t rrsig;
   9800   1.1  christos 
   9801   1.1  christos 		dns_rdataset_current(sigrdataset, &rdata);
   9802   1.1  christos 		result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
   9803   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   9804   1.1  christos 		if (dns_name_countlabels(signer) == 0) {
   9805   1.8  christos 			dns_name_copynf(&rrsig.signer, signer);
   9806   1.1  christos 		} else if (!dns_name_equal(signer, &rrsig.signer)) {
   9807   1.1  christos 			return (ISC_R_FAILURE);
   9808   1.1  christos 		}
   9809   1.1  christos 	}
   9810   1.1  christos 
   9811   1.1  christos 	return (ISC_R_SUCCESS);
   9812   1.1  christos }
   9813   1.1  christos 
   9814   1.1  christos /*%
   9815   1.1  christos  * Handle covering NSEC responses.
   9816   1.1  christos  *
   9817   1.9  christos  * Verify the NSEC record is appropriate for the QNAME; if not,
   9818   1.1  christos  * redo the initial query without DNS_DBFIND_COVERINGNSEC.
   9819   1.1  christos  *
   9820   1.1  christos  * If the covering NSEC proves that the name exists but not the type,
   9821   1.1  christos  * synthesize a NODATA response.
   9822   1.1  christos  *
   9823   1.1  christos  * If the name doesn't exist, compute the wildcard record and check whether
   9824   1.1  christos  * the wildcard name exists or not.  If we can't determine this, redo the
   9825   1.1  christos  * initial query without DNS_DBFIND_COVERINGNSEC.
   9826   1.1  christos  *
   9827   1.1  christos  * If the wildcard name does not exist, compute the SOA name and look that
   9828   1.1  christos  * up.  If the SOA record does not exist, redo the initial query without
   9829   1.1  christos  * DNS_DBFIND_COVERINGNSEC.  If the SOA record exists, synthesize an
   9830   1.1  christos  * NXDOMAIN response from the found records.
   9831   1.1  christos  *
   9832   1.1  christos  * If the wildcard name does exist, perform a lookup for the requested
   9833   1.1  christos  * type at the wildcard name.
   9834   1.1  christos  */
   9835   1.1  christos static isc_result_t
   9836   1.1  christos query_coveringnsec(query_ctx_t *qctx) {
   9837   1.1  christos 	dns_db_t *db = NULL;
   9838   1.1  christos 	dns_clientinfo_t ci;
   9839   1.1  christos 	dns_clientinfomethods_t cm;
   9840   1.1  christos 	dns_dbnode_t *node = NULL;
   9841   1.1  christos 	dns_fixedname_t fixed;
   9842   1.1  christos 	dns_fixedname_t fnowild;
   9843   1.1  christos 	dns_fixedname_t fsigner;
   9844   1.1  christos 	dns_fixedname_t fwild;
   9845   1.1  christos 	dns_name_t *fname = NULL;
   9846   1.1  christos 	dns_name_t *nowild = NULL;
   9847   1.1  christos 	dns_name_t *signer = NULL;
   9848   1.1  christos 	dns_name_t *wild = NULL;
   9849   1.1  christos 	dns_rdataset_t *soardataset = NULL, *sigsoardataset = NULL;
   9850   1.1  christos 	dns_rdataset_t rdataset, sigrdataset;
   9851   1.3  christos 	bool done = false;
   9852   1.3  christos 	bool exists = true, data = true;
   9853   1.3  christos 	bool redirected = false;
   9854   1.1  christos 	isc_result_t result = ISC_R_SUCCESS;
   9855   1.1  christos 	unsigned int dboptions = qctx->client->query.dboptions;
   9856   1.1  christos 
   9857   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_coveringnsec");
   9858   1.9  christos 
   9859   1.1  christos 	dns_rdataset_init(&rdataset);
   9860   1.1  christos 	dns_rdataset_init(&sigrdataset);
   9861   1.1  christos 
   9862   1.1  christos 	/*
   9863   1.1  christos 	 * If we have no signer name, stop immediately.
   9864   1.1  christos 	 */
   9865   1.1  christos 	if (!dns_rdataset_isassociated(qctx->sigrdataset)) {
   9866   1.1  christos 		goto cleanup;
   9867   1.1  christos 	}
   9868   1.1  christos 
   9869   1.1  christos 	wild = dns_fixedname_initname(&fwild);
   9870   1.1  christos 	fname = dns_fixedname_initname(&fixed);
   9871   1.1  christos 	signer = dns_fixedname_initname(&fsigner);
   9872   1.1  christos 	nowild = dns_fixedname_initname(&fnowild);
   9873   1.1  christos 
   9874   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   9875  1.15  christos 	dns_clientinfo_init(&ci, qctx->client, NULL, NULL);
   9876   1.1  christos 
   9877   1.1  christos 	/*
   9878   1.1  christos 	 * All signer names must be the same to accept.
   9879   1.1  christos 	 */
   9880   1.1  christos 	result = checksignames(signer, qctx->sigrdataset);
   9881   1.1  christos 	if (result != ISC_R_SUCCESS) {
   9882   1.1  christos 		result = ISC_R_SUCCESS;
   9883   1.1  christos 		goto cleanup;
   9884   1.1  christos 	}
   9885   1.1  christos 
   9886   1.1  christos 	/*
   9887   1.1  christos 	 * Check that we have the correct NOQNAME NSEC record.
   9888   1.1  christos 	 */
   9889   1.1  christos 	result = dns_nsec_noexistnodata(qctx->qtype, qctx->client->query.qname,
   9890   1.9  christos 					qctx->fname, qctx->rdataset, &exists,
   9891   1.9  christos 					&data, wild, log_noexistnodata, qctx);
   9892   1.1  christos 
   9893   1.1  christos 	if (result != ISC_R_SUCCESS || (exists && data)) {
   9894   1.1  christos 		goto cleanup;
   9895   1.1  christos 	}
   9896   1.1  christos 
   9897   1.1  christos 	if (exists) {
   9898   1.9  christos 		if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
   9899   1.1  christos 			goto cleanup;
   9900   1.1  christos 		}
   9901   1.3  christos 		if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
   9902   1.1  christos 		    (qctx->type == dns_rdatatype_a ||
   9903   1.1  christos 		     qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
   9904   1.1  christos 		{
   9905   1.1  christos 			goto cleanup;
   9906   1.1  christos 		}
   9907   1.1  christos 		if (!qctx->resuming && !STALE(qctx->rdataset) &&
   9908   1.1  christos 		    qctx->rdataset->ttl == 0 && RECURSIONOK(qctx->client))
   9909   1.1  christos 		{
   9910   1.1  christos 			goto cleanup;
   9911   1.1  christos 		}
   9912   1.1  christos 
   9913   1.3  christos 		soardataset = ns_client_newrdataset(qctx->client);
   9914   1.3  christos 		sigsoardataset = ns_client_newrdataset(qctx->client);
   9915   1.1  christos 		if (soardataset == NULL || sigsoardataset == NULL) {
   9916   1.1  christos 			goto cleanup;
   9917   1.1  christos 		}
   9918   1.1  christos 
   9919   1.1  christos 		/*
   9920   1.1  christos 		 * Look for SOA record to construct NODATA response.
   9921   1.1  christos 		 */
   9922   1.1  christos 		dns_db_attach(qctx->db, &db);
   9923   1.1  christos 		result = dns_db_findext(db, signer, qctx->version,
   9924   1.1  christos 					dns_rdatatype_soa, dboptions,
   9925   1.9  christos 					qctx->client->now, &node, fname, &cm,
   9926   1.9  christos 					&ci, soardataset, sigsoardataset);
   9927   1.1  christos 
   9928   1.1  christos 		if (result != ISC_R_SUCCESS) {
   9929   1.1  christos 			goto cleanup;
   9930   1.1  christos 		}
   9931   1.9  christos 		(void)query_synthnodata(qctx, signer, &soardataset,
   9932   1.9  christos 					&sigsoardataset);
   9933   1.3  christos 		done = true;
   9934   1.1  christos 		goto cleanup;
   9935   1.1  christos 	}
   9936   1.1  christos 
   9937   1.1  christos 	/*
   9938   1.1  christos 	 * Look up the no-wildcard proof.
   9939   1.1  christos 	 */
   9940   1.1  christos 	dns_db_attach(qctx->db, &db);
   9941   1.1  christos 	result = dns_db_findext(db, wild, qctx->version, qctx->type,
   9942   1.1  christos 				dboptions | DNS_DBFIND_COVERINGNSEC,
   9943   1.9  christos 				qctx->client->now, &node, nowild, &cm, &ci,
   9944   1.9  christos 				&rdataset, &sigrdataset);
   9945   1.1  christos 
   9946   1.1  christos 	if (rdataset.trust != dns_trust_secure ||
   9947  1.16  christos 	    sigrdataset.trust != dns_trust_secure)
   9948  1.16  christos 	{
   9949   1.1  christos 		goto cleanup;
   9950   1.1  christos 	}
   9951   1.1  christos 
   9952   1.1  christos 	/*
   9953   1.1  christos 	 * Zero TTL handling of wildcard record.
   9954   1.1  christos 	 *
   9955   1.3  christos 	 * We don't yet have code to handle synthesis and type ANY or dns64
   9956   1.3  christos 	 * processing so we abort the synthesis here if there would be a
   9957   1.3  christos 	 * interaction.
   9958   1.1  christos 	 */
   9959   1.1  christos 	switch (result) {
   9960   1.1  christos 	case ISC_R_SUCCESS:
   9961   1.9  christos 		if (qctx->type == dns_rdatatype_any) { /* XXX not yet */
   9962   1.1  christos 			goto cleanup;
   9963   1.1  christos 		}
   9964   1.3  christos 		if (!ISC_LIST_EMPTY(qctx->view->dns64) &&
   9965   1.1  christos 		    (qctx->type == dns_rdatatype_a ||
   9966   1.1  christos 		     qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */
   9967   1.1  christos 		{
   9968   1.1  christos 			goto cleanup;
   9969   1.1  christos 		}
   9970  1.15  christos 		FALLTHROUGH;
   9971   1.1  christos 	case DNS_R_CNAME:
   9972   1.9  christos 		if (!qctx->resuming && !STALE(&rdataset) && rdataset.ttl == 0 &&
   9973   1.9  christos 		    RECURSIONOK(qctx->client))
   9974   1.1  christos 		{
   9975   1.1  christos 			goto cleanup;
   9976   1.1  christos 		}
   9977   1.1  christos 	default:
   9978   1.1  christos 		break;
   9979   1.1  christos 	}
   9980   1.1  christos 
   9981   1.1  christos 	switch (result) {
   9982   1.1  christos 	case DNS_R_COVERINGNSEC:
   9983   1.9  christos 		result = dns_nsec_noexistnodata(qctx->qtype, wild, nowild,
   9984   1.9  christos 						&rdataset, &exists, &data, NULL,
   9985   1.1  christos 						log_noexistnodata, qctx);
   9986   1.1  christos 		if (result != ISC_R_SUCCESS || exists) {
   9987   1.1  christos 			goto cleanup;
   9988   1.1  christos 		}
   9989   1.1  christos 		break;
   9990   1.9  christos 	case ISC_R_SUCCESS: /* wild card match */
   9991   1.1  christos 		(void)query_synthwildcard(qctx, &rdataset, &sigrdataset);
   9992   1.3  christos 		done = true;
   9993   1.1  christos 		goto cleanup;
   9994   1.9  christos 	case DNS_R_CNAME: /* wild card cname */
   9995   1.1  christos 		(void)query_synthcnamewildcard(qctx, &rdataset, &sigrdataset);
   9996   1.3  christos 		done = true;
   9997   1.1  christos 		goto cleanup;
   9998   1.9  christos 	case DNS_R_NCACHENXRRSET:  /* wild card nodata */
   9999   1.9  christos 	case DNS_R_NCACHENXDOMAIN: /* direct nxdomain */
   10000   1.1  christos 	default:
   10001   1.1  christos 		goto cleanup;
   10002   1.1  christos 	}
   10003   1.1  christos 
   10004   1.1  christos 	/*
   10005   1.1  christos 	 * We now have the proof that we have an NXDOMAIN.  Apply
   10006   1.1  christos 	 * NXDOMAIN redirection if configured.
   10007   1.1  christos 	 */
   10008  1.18  christos 	result = query_redirect(qctx, DNS_R_COVERINGNSEC);
   10009   1.1  christos 	if (result != ISC_R_COMPLETE) {
   10010   1.3  christos 		redirected = true;
   10011   1.1  christos 		goto cleanup;
   10012   1.1  christos 	}
   10013   1.1  christos 
   10014   1.1  christos 	/*
   10015   1.1  christos 	 * Must be signed to accept.
   10016   1.1  christos 	 */
   10017   1.1  christos 	if (!dns_rdataset_isassociated(&sigrdataset)) {
   10018   1.1  christos 		goto cleanup;
   10019   1.1  christos 	}
   10020   1.1  christos 
   10021   1.1  christos 	/*
   10022   1.1  christos 	 * Check signer signer names again.
   10023   1.1  christos 	 */
   10024   1.1  christos 	result = checksignames(signer, &sigrdataset);
   10025   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10026   1.1  christos 		result = ISC_R_SUCCESS;
   10027   1.1  christos 		goto cleanup;
   10028   1.1  christos 	}
   10029   1.1  christos 
   10030   1.1  christos 	if (node != NULL) {
   10031   1.1  christos 		dns_db_detachnode(db, &node);
   10032   1.1  christos 	}
   10033   1.1  christos 
   10034   1.3  christos 	soardataset = ns_client_newrdataset(qctx->client);
   10035   1.3  christos 	sigsoardataset = ns_client_newrdataset(qctx->client);
   10036   1.1  christos 	if (soardataset == NULL || sigsoardataset == NULL) {
   10037   1.1  christos 		goto cleanup;
   10038   1.1  christos 	}
   10039   1.1  christos 
   10040   1.1  christos 	/*
   10041   1.1  christos 	 * Look for SOA record to construct NXDOMAIN response.
   10042   1.1  christos 	 */
   10043   1.9  christos 	result = dns_db_findext(db, signer, qctx->version, dns_rdatatype_soa,
   10044   1.9  christos 				dboptions, qctx->client->now, &node, fname, &cm,
   10045   1.9  christos 				&ci, soardataset, sigsoardataset);
   10046   1.1  christos 
   10047   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10048   1.1  christos 		goto cleanup;
   10049   1.1  christos 	}
   10050   1.1  christos 
   10051   1.9  christos 	(void)query_synthnxdomain(qctx, nowild, &rdataset, &sigrdataset, signer,
   10052   1.9  christos 				  &soardataset, &sigsoardataset);
   10053   1.3  christos 	done = true;
   10054   1.1  christos 
   10055   1.9  christos cleanup:
   10056   1.1  christos 	if (dns_rdataset_isassociated(&rdataset)) {
   10057   1.1  christos 		dns_rdataset_disassociate(&rdataset);
   10058   1.1  christos 	}
   10059   1.1  christos 	if (dns_rdataset_isassociated(&sigrdataset)) {
   10060   1.1  christos 		dns_rdataset_disassociate(&sigrdataset);
   10061   1.1  christos 	}
   10062   1.1  christos 	if (soardataset != NULL) {
   10063   1.3  christos 		ns_client_putrdataset(qctx->client, &soardataset);
   10064   1.1  christos 	}
   10065   1.1  christos 	if (sigsoardataset != NULL) {
   10066   1.3  christos 		ns_client_putrdataset(qctx->client, &sigsoardataset);
   10067   1.1  christos 	}
   10068   1.1  christos 	if (db != NULL) {
   10069   1.1  christos 		if (node != NULL) {
   10070   1.1  christos 			dns_db_detachnode(db, &node);
   10071   1.1  christos 		}
   10072   1.1  christos 		dns_db_detach(&db);
   10073   1.1  christos 	}
   10074   1.1  christos 
   10075   1.1  christos 	if (redirected) {
   10076   1.1  christos 		return (result);
   10077   1.1  christos 	}
   10078   1.1  christos 
   10079   1.1  christos 	if (!done) {
   10080   1.1  christos 		/*
   10081   1.1  christos 		 * No covering NSEC was found; proceed with recursion.
   10082   1.1  christos 		 */
   10083   1.3  christos 		qctx->findcoveringnsec = false;
   10084   1.1  christos 		if (qctx->fname != NULL) {
   10085   1.3  christos 			ns_client_releasename(qctx->client, &qctx->fname);
   10086   1.1  christos 		}
   10087   1.1  christos 		if (qctx->node != NULL) {
   10088   1.1  christos 			dns_db_detachnode(qctx->db, &qctx->node);
   10089   1.1  christos 		}
   10090   1.3  christos 		ns_client_putrdataset(qctx->client, &qctx->rdataset);
   10091   1.1  christos 		if (qctx->sigrdataset != NULL) {
   10092   1.3  christos 			ns_client_putrdataset(qctx->client, &qctx->sigrdataset);
   10093   1.1  christos 		}
   10094   1.1  christos 		return (query_lookup(qctx));
   10095   1.1  christos 	}
   10096   1.1  christos 
   10097   1.3  christos 	return (ns_query_done(qctx));
   10098   1.1  christos }
   10099   1.1  christos 
   10100   1.1  christos /*%
   10101   1.1  christos  * Handle negative cache responses, DNS_R_NCACHENXRRSET or
   10102   1.1  christos  * DNS_R_NCACHENXDOMAIN. (Note: may also be called with result
   10103   1.1  christos  * set to DNS_R_NXDOMAIN when handling DNS64 lookups.)
   10104   1.1  christos  */
   10105   1.1  christos static isc_result_t
   10106   1.1  christos query_ncache(query_ctx_t *qctx, isc_result_t result) {
   10107   1.1  christos 	INSIST(!qctx->is_zone);
   10108   1.1  christos 	INSIST(result == DNS_R_NCACHENXDOMAIN ||
   10109   1.9  christos 	       result == DNS_R_NCACHENXRRSET || result == DNS_R_NXDOMAIN);
   10110   1.9  christos 
   10111   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_ncache");
   10112   1.1  christos 
   10113   1.3  christos 	CALL_HOOK(NS_QUERY_NCACHE_BEGIN, qctx);
   10114   1.3  christos 
   10115   1.3  christos 	qctx->authoritative = false;
   10116   1.1  christos 
   10117   1.1  christos 	if (result == DNS_R_NCACHENXDOMAIN) {
   10118   1.1  christos 		/*
   10119   1.1  christos 		 * Set message rcode. (This is not done when
   10120   1.1  christos 		 * result == DNS_R_NXDOMAIN because that means we're
   10121   1.1  christos 		 * being called after a DNS64 lookup and don't want
   10122   1.1  christos 		 * to update the rcode now.)
   10123   1.1  christos 		 */
   10124   1.1  christos 		qctx->client->message->rcode = dns_rcode_nxdomain;
   10125   1.1  christos 
   10126   1.1  christos 		/* Look for RFC 1918 leakage from Internet. */
   10127   1.1  christos 		if (qctx->qtype == dns_rdatatype_ptr &&
   10128   1.1  christos 		    qctx->client->message->rdclass == dns_rdataclass_in &&
   10129   1.1  christos 		    dns_name_countlabels(qctx->fname) == 7)
   10130   1.1  christos 		{
   10131   1.1  christos 			warn_rfc1918(qctx->client, qctx->fname, qctx->rdataset);
   10132   1.1  christos 		}
   10133   1.1  christos 	}
   10134   1.1  christos 
   10135   1.1  christos 	return (query_nodata(qctx, result));
   10136   1.3  christos 
   10137   1.9  christos cleanup:
   10138   1.3  christos 	return (result);
   10139   1.3  christos }
   10140   1.3  christos 
   10141   1.3  christos /*
   10142   1.3  christos  * If we have a zero ttl from the cache, refetch.
   10143   1.3  christos  */
   10144   1.3  christos static isc_result_t
   10145   1.3  christos query_zerottl_refetch(query_ctx_t *qctx) {
   10146   1.3  christos 	isc_result_t result;
   10147   1.3  christos 
   10148   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_zerottl_refetch");
   10149   1.9  christos 
   10150   1.3  christos 	if (qctx->is_zone || qctx->resuming || STALE(qctx->rdataset) ||
   10151   1.3  christos 	    qctx->rdataset->ttl != 0 || !RECURSIONOK(qctx->client))
   10152   1.3  christos 	{
   10153   1.3  christos 		return (ISC_R_COMPLETE);
   10154   1.3  christos 	}
   10155   1.3  christos 
   10156   1.3  christos 	qctx_clean(qctx);
   10157   1.3  christos 
   10158   1.3  christos 	INSIST(!REDIRECT(qctx->client));
   10159   1.3  christos 
   10160   1.3  christos 	result = ns_query_recurse(qctx->client, qctx->qtype,
   10161   1.9  christos 				  qctx->client->query.qname, NULL, NULL,
   10162   1.9  christos 				  qctx->resuming);
   10163   1.3  christos 	if (result == ISC_R_SUCCESS) {
   10164   1.3  christos 		CALL_HOOK(NS_QUERY_ZEROTTL_RECURSE, qctx);
   10165   1.9  christos 		qctx->client->query.attributes |= NS_QUERYATTR_RECURSING;
   10166   1.3  christos 
   10167   1.3  christos 		if (qctx->dns64) {
   10168   1.9  christos 			qctx->client->query.attributes |= NS_QUERYATTR_DNS64;
   10169   1.3  christos 		}
   10170   1.3  christos 		if (qctx->dns64_exclude) {
   10171   1.3  christos 			qctx->client->query.attributes |=
   10172   1.3  christos 				NS_QUERYATTR_DNS64EXCLUDE;
   10173   1.3  christos 		}
   10174   1.3  christos 	} else {
   10175  1.13  christos 		/*
   10176  1.13  christos 		 * There was a zero ttl from the cache, don't fallback to
   10177  1.13  christos 		 * serve-stale lookup.
   10178  1.13  christos 		 */
   10179   1.3  christos 		QUERY_ERROR(qctx, result);
   10180   1.3  christos 	}
   10181   1.3  christos 
   10182   1.3  christos 	return (ns_query_done(qctx));
   10183   1.3  christos 
   10184   1.9  christos cleanup:
   10185   1.3  christos 	return (result);
   10186   1.1  christos }
   10187   1.1  christos 
   10188   1.1  christos /*
   10189   1.1  christos  * Handle CNAME responses.
   10190   1.1  christos  */
   10191   1.1  christos static isc_result_t
   10192   1.1  christos query_cname(query_ctx_t *qctx) {
   10193  1.14  christos 	isc_result_t result = ISC_R_UNSET;
   10194  1.14  christos 	dns_name_t *tname = NULL;
   10195  1.14  christos 	dns_rdataset_t *trdataset = NULL;
   10196   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10197   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   10198   1.1  christos 	dns_rdata_cname_t cname;
   10199   1.1  christos 
   10200   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_cname");
   10201   1.9  christos 
   10202   1.3  christos 	CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx);
   10203   1.1  christos 
   10204   1.3  christos 	result = query_zerottl_refetch(qctx);
   10205   1.3  christos 	if (result != ISC_R_COMPLETE) {
   10206   1.3  christos 		return (result);
   10207   1.1  christos 	}
   10208   1.1  christos 
   10209   1.1  christos 	/*
   10210   1.1  christos 	 * Keep a copy of the rdataset.  We have to do this because
   10211   1.1  christos 	 * query_addrrset may clear 'rdataset' (to prevent the
   10212   1.1  christos 	 * cleanup code from cleaning it up).
   10213   1.1  christos 	 */
   10214   1.1  christos 	trdataset = qctx->rdataset;
   10215   1.1  christos 
   10216   1.1  christos 	/*
   10217   1.1  christos 	 * Add the CNAME to the answer section.
   10218   1.1  christos 	 */
   10219   1.9  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   10220   1.1  christos 		sigrdatasetp = &qctx->sigrdataset;
   10221   1.9  christos 	}
   10222   1.1  christos 
   10223   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   10224   1.1  christos 	    (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
   10225   1.1  christos 	{
   10226   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10227   1.8  christos 		dns_name_copynf(qctx->fname,
   10228   1.9  christos 				dns_fixedname_name(&qctx->wildcardname));
   10229   1.3  christos 		qctx->need_wildcardproof = true;
   10230   1.1  christos 	}
   10231   1.1  christos 
   10232   1.1  christos 	if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) {
   10233   1.1  christos 		qctx->noqname = qctx->rdataset;
   10234   1.1  christos 	} else {
   10235   1.1  christos 		qctx->noqname = NULL;
   10236   1.1  christos 	}
   10237   1.1  christos 
   10238   1.9  christos 	if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   10239   1.1  christos 		query_prefetch(qctx->client, qctx->fname, qctx->rdataset);
   10240   1.9  christos 	}
   10241   1.1  christos 
   10242   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   10243   1.9  christos 		       qctx->dbuf, DNS_SECTION_ANSWER);
   10244   1.1  christos 
   10245   1.1  christos 	query_addnoqnameproof(qctx);
   10246   1.1  christos 
   10247   1.1  christos 	/*
   10248   1.1  christos 	 * We set the PARTIALANSWER attribute so that if anything goes
   10249   1.1  christos 	 * wrong later on, we'll return what we've got so far.
   10250   1.1  christos 	 */
   10251   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   10252   1.1  christos 
   10253   1.1  christos 	/*
   10254   1.1  christos 	 * Reset qname to be the target name of the CNAME and restart
   10255   1.1  christos 	 * the query.
   10256   1.1  christos 	 */
   10257   1.1  christos 	result = dns_message_gettempname(qctx->client->message, &tname);
   10258   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10259   1.3  christos 		return (ns_query_done(qctx));
   10260   1.9  christos 	}
   10261   1.1  christos 
   10262   1.1  christos 	result = dns_rdataset_first(trdataset);
   10263   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10264   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10265   1.3  christos 		return (ns_query_done(qctx));
   10266   1.1  christos 	}
   10267   1.1  christos 
   10268   1.1  christos 	dns_rdataset_current(trdataset, &rdata);
   10269   1.1  christos 	result = dns_rdata_tostruct(&rdata, &cname, NULL);
   10270   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10271   1.1  christos 	dns_rdata_reset(&rdata);
   10272   1.1  christos 
   10273  1.14  christos 	dns_name_copynf(&cname.cname, tname);
   10274   1.1  christos 
   10275   1.1  christos 	dns_rdata_freestruct(&cname);
   10276   1.1  christos 	ns_client_qnamereplace(qctx->client, tname);
   10277   1.3  christos 	qctx->want_restart = true;
   10278   1.9  christos 	if (!WANTRECURSION(qctx->client)) {
   10279   1.1  christos 		qctx->options |= DNS_GETDB_NOLOG;
   10280   1.9  christos 	}
   10281   1.1  christos 
   10282   1.1  christos 	query_addauth(qctx);
   10283   1.1  christos 
   10284   1.3  christos 	return (ns_query_done(qctx));
   10285   1.3  christos 
   10286   1.9  christos cleanup:
   10287   1.3  christos 	return (result);
   10288   1.1  christos }
   10289   1.1  christos 
   10290   1.1  christos /*
   10291   1.1  christos  * Handle DNAME responses.
   10292   1.1  christos  */
   10293   1.1  christos static isc_result_t
   10294   1.1  christos query_dname(query_ctx_t *qctx) {
   10295   1.1  christos 	dns_name_t *tname, *prefix;
   10296   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   10297   1.1  christos 	dns_rdata_dname_t dname;
   10298   1.1  christos 	dns_fixedname_t fixed;
   10299   1.1  christos 	dns_rdataset_t *trdataset;
   10300   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10301   1.1  christos 	dns_namereln_t namereln;
   10302   1.1  christos 	isc_buffer_t b;
   10303   1.1  christos 	int order;
   10304   1.1  christos 	isc_result_t result;
   10305   1.1  christos 	unsigned int nlabels;
   10306   1.1  christos 
   10307   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_dname");
   10308   1.9  christos 
   10309   1.3  christos 	CALL_HOOK(NS_QUERY_DNAME_BEGIN, qctx);
   10310   1.3  christos 
   10311   1.1  christos 	/*
   10312   1.1  christos 	 * Compare the current qname to the found name.  We need
   10313   1.1  christos 	 * to know how many labels and bits are in common because
   10314   1.1  christos 	 * we're going to have to split qname later on.
   10315   1.1  christos 	 */
   10316   1.1  christos 	namereln = dns_name_fullcompare(qctx->client->query.qname, qctx->fname,
   10317   1.1  christos 					&order, &nlabels);
   10318   1.1  christos 	INSIST(namereln == dns_namereln_subdomain);
   10319   1.1  christos 
   10320   1.1  christos 	/*
   10321   1.1  christos 	 * Keep a copy of the rdataset.  We have to do this because
   10322   1.1  christos 	 * query_addrrset may clear 'rdataset' (to prevent the
   10323   1.1  christos 	 * cleanup code from cleaning it up).
   10324   1.1  christos 	 */
   10325   1.1  christos 	trdataset = qctx->rdataset;
   10326   1.1  christos 
   10327   1.1  christos 	/*
   10328   1.1  christos 	 * Add the DNAME to the answer section.
   10329   1.1  christos 	 */
   10330   1.9  christos 	if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) {
   10331   1.1  christos 		sigrdatasetp = &qctx->sigrdataset;
   10332   1.9  christos 	}
   10333   1.1  christos 
   10334   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   10335   1.1  christos 	    (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
   10336   1.1  christos 	{
   10337   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10338   1.8  christos 		dns_name_copynf(qctx->fname,
   10339   1.9  christos 				dns_fixedname_name(&qctx->wildcardname));
   10340   1.3  christos 		qctx->need_wildcardproof = true;
   10341   1.1  christos 	}
   10342   1.1  christos 
   10343   1.9  christos 	if (!qctx->is_zone && RECURSIONOK(qctx->client)) {
   10344   1.1  christos 		query_prefetch(qctx->client, qctx->fname, qctx->rdataset);
   10345   1.9  christos 	}
   10346   1.9  christos 	query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp,
   10347   1.9  christos 		       qctx->dbuf, DNS_SECTION_ANSWER);
   10348   1.1  christos 
   10349   1.1  christos 	/*
   10350   1.1  christos 	 * We set the PARTIALANSWER attribute so that if anything goes
   10351   1.1  christos 	 * wrong later on, we'll return what we've got so far.
   10352   1.1  christos 	 */
   10353   1.1  christos 	qctx->client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
   10354   1.1  christos 
   10355   1.1  christos 	/*
   10356   1.1  christos 	 * Get the target name of the DNAME.
   10357   1.1  christos 	 */
   10358   1.1  christos 	tname = NULL;
   10359   1.1  christos 	result = dns_message_gettempname(qctx->client->message, &tname);
   10360   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10361   1.3  christos 		return (ns_query_done(qctx));
   10362   1.9  christos 	}
   10363   1.1  christos 
   10364   1.1  christos 	result = dns_rdataset_first(trdataset);
   10365   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10366   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10367   1.3  christos 		return (ns_query_done(qctx));
   10368   1.1  christos 	}
   10369   1.1  christos 
   10370   1.1  christos 	dns_rdataset_current(trdataset, &rdata);
   10371   1.1  christos 	result = dns_rdata_tostruct(&rdata, &dname, NULL);
   10372   1.3  christos 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10373   1.1  christos 	dns_rdata_reset(&rdata);
   10374   1.1  christos 
   10375  1.14  christos 	dns_name_copynf(&dname.dname, tname);
   10376   1.1  christos 	dns_rdata_freestruct(&dname);
   10377   1.1  christos 
   10378   1.1  christos 	/*
   10379   1.1  christos 	 * Construct the new qname consisting of
   10380   1.1  christos 	 * <found name prefix>.<dname target>
   10381   1.1  christos 	 */
   10382   1.1  christos 	prefix = dns_fixedname_initname(&fixed);
   10383   1.1  christos 	dns_name_split(qctx->client->query.qname, nlabels, prefix, NULL);
   10384   1.1  christos 	INSIST(qctx->fname == NULL);
   10385   1.3  christos 	qctx->dbuf = ns_client_getnamebuf(qctx->client);
   10386   1.1  christos 	if (qctx->dbuf == NULL) {
   10387   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10388   1.3  christos 		return (ns_query_done(qctx));
   10389   1.1  christos 	}
   10390   1.3  christos 	qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b);
   10391   1.1  christos 	if (qctx->fname == NULL) {
   10392   1.1  christos 		dns_message_puttempname(qctx->client->message, &tname);
   10393   1.3  christos 		return (ns_query_done(qctx));
   10394   1.1  christos 	}
   10395   1.1  christos 	result = dns_name_concatenate(prefix, tname, qctx->fname, NULL);
   10396   1.1  christos 	dns_message_puttempname(qctx->client->message, &tname);
   10397   1.1  christos 
   10398   1.1  christos 	/*
   10399   1.1  christos 	 * RFC2672, section 4.1, subsection 3c says
   10400   1.1  christos 	 * we should return YXDOMAIN if the constructed
   10401   1.1  christos 	 * name would be too long.
   10402   1.1  christos 	 */
   10403   1.9  christos 	if (result == DNS_R_NAMETOOLONG) {
   10404   1.1  christos 		qctx->client->message->rcode = dns_rcode_yxdomain;
   10405   1.9  christos 	}
   10406   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10407   1.3  christos 		return (ns_query_done(qctx));
   10408   1.9  christos 	}
   10409   1.1  christos 
   10410   1.3  christos 	ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf);
   10411   1.1  christos 
   10412   1.1  christos 	/*
   10413   1.1  christos 	 * Synthesize a CNAME consisting of
   10414   1.1  christos 	 *   <old qname> <dname ttl> CNAME <new qname>
   10415   1.1  christos 	 *	    with <dname trust value>
   10416   1.1  christos 	 *
   10417   1.1  christos 	 * Synthesize a CNAME so old old clients that don't understand
   10418   1.1  christos 	 * DNAME can chain.
   10419   1.1  christos 	 *
   10420   1.1  christos 	 * We do not try to synthesize a signature because we hope
   10421   1.1  christos 	 * that security aware servers will understand DNAME.  Also,
   10422   1.1  christos 	 * even if we had an online key, making a signature
   10423   1.1  christos 	 * on-the-fly is costly, and not really legitimate anyway
   10424   1.1  christos 	 * since the synthesized CNAME is NOT in the zone.
   10425   1.1  christos 	 */
   10426   1.1  christos 	result = query_addcname(qctx, trdataset->trust, trdataset->ttl);
   10427   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10428   1.3  christos 		return (ns_query_done(qctx));
   10429   1.9  christos 	}
   10430   1.1  christos 
   10431   1.1  christos 	/*
   10432  1.11  christos 	 * If the original query was not for a CNAME or ANY then follow the
   10433  1.11  christos 	 * CNAME.
   10434   1.1  christos 	 */
   10435  1.11  christos 	if (qctx->qtype != dns_rdatatype_cname &&
   10436  1.16  christos 	    qctx->qtype != dns_rdatatype_any)
   10437  1.16  christos 	{
   10438  1.11  christos 		/*
   10439  1.11  christos 		 * Switch to the new qname and restart.
   10440  1.11  christos 		 */
   10441  1.11  christos 		ns_client_qnamereplace(qctx->client, qctx->fname);
   10442  1.11  christos 		qctx->fname = NULL;
   10443  1.11  christos 		qctx->want_restart = true;
   10444  1.11  christos 		if (!WANTRECURSION(qctx->client)) {
   10445  1.11  christos 			qctx->options |= DNS_GETDB_NOLOG;
   10446  1.11  christos 		}
   10447   1.9  christos 	}
   10448   1.1  christos 
   10449   1.1  christos 	query_addauth(qctx);
   10450   1.1  christos 
   10451   1.3  christos 	return (ns_query_done(qctx));
   10452   1.3  christos 
   10453   1.9  christos cleanup:
   10454   1.3  christos 	return (result);
   10455   1.1  christos }
   10456   1.1  christos 
   10457   1.1  christos /*%
   10458   1.9  christos  * Add CNAME to response.
   10459   1.1  christos  */
   10460   1.1  christos static isc_result_t
   10461   1.1  christos query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) {
   10462   1.1  christos 	ns_client_t *client = qctx->client;
   10463   1.1  christos 	dns_rdataset_t *rdataset = NULL;
   10464   1.1  christos 	dns_rdatalist_t *rdatalist = NULL;
   10465   1.1  christos 	dns_rdata_t *rdata = NULL;
   10466   1.1  christos 	isc_region_t r;
   10467   1.1  christos 	dns_name_t *aname = NULL;
   10468   1.1  christos 	isc_result_t result;
   10469   1.1  christos 
   10470   1.1  christos 	result = dns_message_gettempname(client->message, &aname);
   10471   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10472   1.1  christos 		return (result);
   10473   1.1  christos 	}
   10474  1.14  christos 
   10475  1.14  christos 	dns_name_copynf(client->query.qname, aname);
   10476   1.1  christos 
   10477   1.1  christos 	result = dns_message_gettemprdatalist(client->message, &rdatalist);
   10478   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10479   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10480   1.1  christos 		return (result);
   10481   1.1  christos 	}
   10482   1.1  christos 
   10483   1.1  christos 	result = dns_message_gettemprdata(client->message, &rdata);
   10484   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10485   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10486   1.1  christos 		dns_message_puttemprdatalist(client->message, &rdatalist);
   10487   1.1  christos 		return (result);
   10488   1.1  christos 	}
   10489   1.1  christos 
   10490   1.1  christos 	result = dns_message_gettemprdataset(client->message, &rdataset);
   10491   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10492   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10493   1.1  christos 		dns_message_puttemprdatalist(client->message, &rdatalist);
   10494   1.1  christos 		dns_message_puttemprdata(client->message, &rdata);
   10495   1.1  christos 		return (result);
   10496   1.1  christos 	}
   10497   1.1  christos 
   10498   1.1  christos 	rdatalist->type = dns_rdatatype_cname;
   10499   1.1  christos 	rdatalist->rdclass = client->message->rdclass;
   10500   1.1  christos 	rdatalist->ttl = ttl;
   10501   1.1  christos 
   10502   1.1  christos 	dns_name_toregion(qctx->fname, &r);
   10503   1.1  christos 	rdata->data = r.base;
   10504   1.1  christos 	rdata->length = r.length;
   10505   1.1  christos 	rdata->rdclass = client->message->rdclass;
   10506   1.1  christos 	rdata->type = dns_rdatatype_cname;
   10507   1.1  christos 
   10508   1.1  christos 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
   10509   1.9  christos 	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
   10510   1.9  christos 		      ISC_R_SUCCESS);
   10511   1.1  christos 	rdataset->trust = trust;
   10512   1.1  christos 	dns_rdataset_setownercase(rdataset, aname);
   10513   1.1  christos 
   10514   1.9  christos 	query_addrrset(qctx, &aname, &rdataset, NULL, NULL, DNS_SECTION_ANSWER);
   10515   1.1  christos 	if (rdataset != NULL) {
   10516   1.9  christos 		if (dns_rdataset_isassociated(rdataset)) {
   10517   1.1  christos 			dns_rdataset_disassociate(rdataset);
   10518   1.9  christos 		}
   10519   1.1  christos 		dns_message_puttemprdataset(client->message, &rdataset);
   10520   1.1  christos 	}
   10521   1.9  christos 	if (aname != NULL) {
   10522   1.1  christos 		dns_message_puttempname(client->message, &aname);
   10523   1.9  christos 	}
   10524   1.1  christos 
   10525   1.1  christos 	return (ISC_R_SUCCESS);
   10526   1.1  christos }
   10527   1.1  christos 
   10528   1.1  christos /*%
   10529   1.1  christos  * Prepare to respond: determine whether a wildcard proof is needed,
   10530   1.3  christos  * then hand off to query_respond() or (for type ANY queries)
   10531   1.3  christos  * query_respond_any().
   10532   1.1  christos  */
   10533   1.1  christos static isc_result_t
   10534   1.1  christos query_prepresponse(query_ctx_t *qctx) {
   10535   1.3  christos 	isc_result_t result;
   10536   1.3  christos 
   10537   1.9  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_prepresponse");
   10538   1.9  christos 
   10539   1.3  christos 	CALL_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx);
   10540   1.3  christos 
   10541   1.1  christos 	if (WANTDNSSEC(qctx->client) &&
   10542   1.1  christos 	    (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0)
   10543   1.1  christos 	{
   10544   1.1  christos 		dns_fixedname_init(&qctx->wildcardname);
   10545   1.8  christos 		dns_name_copynf(qctx->fname,
   10546   1.9  christos 				dns_fixedname_name(&qctx->wildcardname));
   10547   1.3  christos 		qctx->need_wildcardproof = true;
   10548   1.3  christos 	}
   10549   1.3  christos 
   10550   1.3  christos 	if (qctx->type == dns_rdatatype_any) {
   10551   1.3  christos 		return (query_respond_any(qctx));
   10552   1.1  christos 	}
   10553   1.1  christos 
   10554   1.3  christos 	result = query_zerottl_refetch(qctx);
   10555   1.3  christos 	if (result != ISC_R_COMPLETE) {
   10556   1.3  christos 		return (result);
   10557   1.1  christos 	}
   10558   1.1  christos 
   10559   1.3  christos 	return (query_respond(qctx));
   10560   1.1  christos 
   10561   1.9  christos cleanup:
   10562   1.3  christos 	return (result);
   10563   1.1  christos }
   10564   1.1  christos 
   10565   1.1  christos /*%
   10566   1.1  christos  * Add SOA to the authority section when sending negative responses
   10567   1.1  christos  * (or to the additional section if sending negative responses triggered
   10568   1.1  christos  * by RPZ rewriting.)
   10569   1.1  christos  */
   10570   1.1  christos static isc_result_t
   10571   1.1  christos query_addsoa(query_ctx_t *qctx, unsigned int override_ttl,
   10572   1.9  christos 	     dns_section_t section) {
   10573   1.1  christos 	ns_client_t *client = qctx->client;
   10574   1.1  christos 	dns_name_t *name;
   10575   1.1  christos 	dns_dbnode_t *node;
   10576   1.1  christos 	isc_result_t result, eresult;
   10577   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   10578   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10579   1.1  christos 	dns_clientinfomethods_t cm;
   10580   1.1  christos 	dns_clientinfo_t ci;
   10581   1.1  christos 
   10582   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addsoa");
   10583   1.1  christos 	/*
   10584   1.1  christos 	 * Initialization.
   10585   1.1  christos 	 */
   10586   1.1  christos 	eresult = ISC_R_SUCCESS;
   10587   1.1  christos 	name = NULL;
   10588   1.1  christos 	rdataset = NULL;
   10589   1.1  christos 	node = NULL;
   10590   1.1  christos 
   10591   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   10592  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   10593   1.1  christos 
   10594   1.1  christos 	/*
   10595   1.1  christos 	 * Don't add the SOA record for test which set "-T nosoa".
   10596   1.1  christos 	 */
   10597   1.1  christos 	if (((client->sctx->options & NS_SERVER_NOSOA) != 0) &&
   10598   1.1  christos 	    (!WANTDNSSEC(client) || !dns_rdataset_isassociated(qctx->rdataset)))
   10599   1.1  christos 	{
   10600   1.1  christos 		return (ISC_R_SUCCESS);
   10601   1.1  christos 	}
   10602   1.1  christos 
   10603   1.1  christos 	/*
   10604   1.1  christos 	 * Get resources and make 'name' be the database origin.
   10605   1.1  christos 	 */
   10606   1.1  christos 	result = dns_message_gettempname(client->message, &name);
   10607   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10608   1.1  christos 		return (result);
   10609   1.9  christos 	}
   10610  1.14  christos 
   10611  1.14  christos 	/*
   10612  1.14  christos 	 * We'll be releasing 'name' before returning, so it's safe to
   10613  1.14  christos 	 * use clone instead of copying here.
   10614  1.14  christos 	 */
   10615   1.1  christos 	dns_name_clone(dns_db_origin(qctx->db), name);
   10616  1.14  christos 
   10617   1.3  christos 	rdataset = ns_client_newrdataset(client);
   10618   1.1  christos 	if (rdataset == NULL) {
   10619   1.1  christos 		CTRACE(ISC_LOG_ERROR, "unable to allocate rdataset");
   10620   1.1  christos 		eresult = DNS_R_SERVFAIL;
   10621   1.1  christos 		goto cleanup;
   10622   1.1  christos 	}
   10623   1.1  christos 	if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) {
   10624   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   10625   1.1  christos 		if (sigrdataset == NULL) {
   10626   1.1  christos 			CTRACE(ISC_LOG_ERROR, "unable to allocate sigrdataset");
   10627   1.1  christos 			eresult = DNS_R_SERVFAIL;
   10628   1.1  christos 			goto cleanup;
   10629   1.1  christos 		}
   10630   1.1  christos 	}
   10631   1.1  christos 
   10632   1.1  christos 	/*
   10633   1.1  christos 	 * Find the SOA.
   10634   1.1  christos 	 */
   10635   1.1  christos 	result = dns_db_getoriginnode(qctx->db, &node);
   10636   1.1  christos 	if (result == ISC_R_SUCCESS) {
   10637   1.1  christos 		result = dns_db_findrdataset(qctx->db, node, qctx->version,
   10638   1.9  christos 					     dns_rdatatype_soa, 0, client->now,
   10639   1.1  christos 					     rdataset, sigrdataset);
   10640   1.1  christos 	} else {
   10641   1.1  christos 		dns_fixedname_t foundname;
   10642   1.1  christos 		dns_name_t *fname;
   10643   1.1  christos 
   10644   1.1  christos 		fname = dns_fixedname_initname(&foundname);
   10645   1.1  christos 
   10646   1.1  christos 		result = dns_db_findext(qctx->db, name, qctx->version,
   10647   1.1  christos 					dns_rdatatype_soa,
   10648   1.9  christos 					client->query.dboptions, 0, &node,
   10649   1.9  christos 					fname, &cm, &ci, rdataset, sigrdataset);
   10650   1.1  christos 	}
   10651   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10652   1.1  christos 		/*
   10653   1.1  christos 		 * This is bad.  We tried to get the SOA RR at the zone top
   10654   1.1  christos 		 * and it didn't work!
   10655   1.1  christos 		 */
   10656   1.1  christos 		CTRACE(ISC_LOG_ERROR, "unable to find SOA RR at zone apex");
   10657   1.1  christos 		eresult = DNS_R_SERVFAIL;
   10658   1.1  christos 	} else {
   10659   1.1  christos 		/*
   10660   1.1  christos 		 * Extract the SOA MINIMUM.
   10661   1.1  christos 		 */
   10662   1.1  christos 		dns_rdata_soa_t soa;
   10663   1.1  christos 		dns_rdata_t rdata = DNS_RDATA_INIT;
   10664   1.1  christos 		result = dns_rdataset_first(rdataset);
   10665   1.1  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10666   1.1  christos 		dns_rdataset_current(rdataset, &rdata);
   10667   1.1  christos 		result = dns_rdata_tostruct(&rdata, &soa, NULL);
   10668   1.3  christos 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   10669   1.1  christos 
   10670   1.9  christos 		if (override_ttl != UINT32_MAX && override_ttl < rdataset->ttl)
   10671   1.1  christos 		{
   10672   1.1  christos 			rdataset->ttl = override_ttl;
   10673   1.9  christos 			if (sigrdataset != NULL) {
   10674   1.1  christos 				sigrdataset->ttl = override_ttl;
   10675   1.9  christos 			}
   10676   1.1  christos 		}
   10677   1.1  christos 
   10678   1.1  christos 		/*
   10679   1.1  christos 		 * Add the SOA and its SIG to the response, with the
   10680   1.1  christos 		 * TTLs adjusted per RFC2308 section 3.
   10681   1.1  christos 		 */
   10682   1.9  christos 		if (rdataset->ttl > soa.minimum) {
   10683   1.1  christos 			rdataset->ttl = soa.minimum;
   10684   1.9  christos 		}
   10685   1.9  christos 		if (sigrdataset != NULL && sigrdataset->ttl > soa.minimum) {
   10686   1.1  christos 			sigrdataset->ttl = soa.minimum;
   10687   1.9  christos 		}
   10688   1.1  christos 
   10689   1.9  christos 		if (sigrdataset != NULL) {
   10690   1.1  christos 			sigrdatasetp = &sigrdataset;
   10691   1.9  christos 		} else {
   10692   1.1  christos 			sigrdatasetp = NULL;
   10693   1.9  christos 		}
   10694   1.1  christos 
   10695   1.9  christos 		if (section == DNS_SECTION_ADDITIONAL) {
   10696   1.1  christos 			rdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   10697   1.9  christos 		}
   10698   1.9  christos 		query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL,
   10699   1.9  christos 			       section);
   10700   1.1  christos 	}
   10701   1.1  christos 
   10702   1.9  christos cleanup:
   10703   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   10704   1.9  christos 	if (sigrdataset != NULL) {
   10705   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   10706   1.9  christos 	}
   10707   1.9  christos 	if (name != NULL) {
   10708   1.3  christos 		ns_client_releasename(client, &name);
   10709   1.9  christos 	}
   10710   1.9  christos 	if (node != NULL) {
   10711   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   10712   1.9  christos 	}
   10713   1.1  christos 
   10714   1.1  christos 	return (eresult);
   10715   1.1  christos }
   10716   1.1  christos 
   10717   1.1  christos /*%
   10718   1.1  christos  * Add NS to authority section (used when the zone apex is already known).
   10719   1.1  christos  */
   10720   1.1  christos static isc_result_t
   10721   1.1  christos query_addns(query_ctx_t *qctx) {
   10722   1.1  christos 	ns_client_t *client = qctx->client;
   10723   1.1  christos 	isc_result_t result, eresult;
   10724   1.1  christos 	dns_name_t *name = NULL, *fname;
   10725   1.1  christos 	dns_dbnode_t *node = NULL;
   10726   1.1  christos 	dns_fixedname_t foundname;
   10727   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   10728   1.1  christos 	dns_rdataset_t **sigrdatasetp = NULL;
   10729   1.1  christos 	dns_clientinfomethods_t cm;
   10730   1.1  christos 	dns_clientinfo_t ci;
   10731   1.1  christos 
   10732   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns");
   10733   1.1  christos 
   10734   1.1  christos 	/*
   10735   1.1  christos 	 * Initialization.
   10736   1.1  christos 	 */
   10737   1.1  christos 	eresult = ISC_R_SUCCESS;
   10738   1.1  christos 	fname = dns_fixedname_initname(&foundname);
   10739   1.1  christos 
   10740   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   10741  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   10742   1.1  christos 
   10743   1.1  christos 	/*
   10744   1.1  christos 	 * Get resources and make 'name' be the database origin.
   10745   1.1  christos 	 */
   10746   1.1  christos 	result = dns_message_gettempname(client->message, &name);
   10747   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10748   1.9  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addns: dns_message_gettempname "
   10749   1.9  christos 					 "failed: done");
   10750   1.1  christos 		return (result);
   10751   1.1  christos 	}
   10752   1.1  christos 	dns_name_clone(dns_db_origin(qctx->db), name);
   10753   1.3  christos 	rdataset = ns_client_newrdataset(client);
   10754   1.1  christos 	if (rdataset == NULL) {
   10755   1.9  christos 		CTRACE(ISC_LOG_ERROR, "query_addns: ns_client_newrdataset "
   10756   1.9  christos 				      "failed");
   10757   1.1  christos 		eresult = DNS_R_SERVFAIL;
   10758   1.1  christos 		goto cleanup;
   10759   1.1  christos 	}
   10760   1.1  christos 
   10761   1.1  christos 	if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) {
   10762   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   10763   1.1  christos 		if (sigrdataset == NULL) {
   10764   1.9  christos 			CTRACE(ISC_LOG_ERROR, "query_addns: "
   10765   1.9  christos 					      "ns_client_newrdataset failed");
   10766   1.1  christos 			eresult = DNS_R_SERVFAIL;
   10767   1.1  christos 			goto cleanup;
   10768   1.1  christos 		}
   10769   1.1  christos 	}
   10770   1.1  christos 
   10771   1.1  christos 	/*
   10772   1.1  christos 	 * Find the NS rdataset.
   10773   1.1  christos 	 */
   10774   1.1  christos 	result = dns_db_getoriginnode(qctx->db, &node);
   10775   1.1  christos 	if (result == ISC_R_SUCCESS) {
   10776   1.1  christos 		result = dns_db_findrdataset(qctx->db, node, qctx->version,
   10777   1.1  christos 					     dns_rdatatype_ns, 0, client->now,
   10778   1.1  christos 					     rdataset, sigrdataset);
   10779   1.1  christos 	} else {
   10780   1.1  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addns: calling dns_db_find");
   10781   1.1  christos 		result = dns_db_findext(qctx->db, name, NULL, dns_rdatatype_ns,
   10782   1.1  christos 					client->query.dboptions, 0, &node,
   10783   1.1  christos 					fname, &cm, &ci, rdataset, sigrdataset);
   10784   1.1  christos 		CTRACE(ISC_LOG_DEBUG(3), "query_addns: dns_db_find complete");
   10785   1.1  christos 	}
   10786   1.1  christos 	if (result != ISC_R_SUCCESS) {
   10787   1.9  christos 		CTRACE(ISC_LOG_ERROR, "query_addns: "
   10788   1.9  christos 				      "dns_db_findrdataset or dns_db_find "
   10789   1.9  christos 				      "failed");
   10790   1.1  christos 		/*
   10791   1.1  christos 		 * This is bad.  We tried to get the NS rdataset at the zone
   10792   1.1  christos 		 * top and it didn't work!
   10793   1.1  christos 		 */
   10794   1.1  christos 		eresult = DNS_R_SERVFAIL;
   10795   1.1  christos 	} else {
   10796   1.1  christos 		if (sigrdataset != NULL) {
   10797   1.1  christos 			sigrdatasetp = &sigrdataset;
   10798   1.1  christos 		}
   10799   1.3  christos 		query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL,
   10800   1.1  christos 			       DNS_SECTION_AUTHORITY);
   10801   1.1  christos 	}
   10802   1.1  christos 
   10803   1.9  christos cleanup:
   10804   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns: cleanup");
   10805   1.3  christos 	ns_client_putrdataset(client, &rdataset);
   10806   1.1  christos 	if (sigrdataset != NULL) {
   10807   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   10808   1.1  christos 	}
   10809   1.1  christos 	if (name != NULL) {
   10810   1.3  christos 		ns_client_releasename(client, &name);
   10811   1.1  christos 	}
   10812   1.1  christos 	if (node != NULL) {
   10813   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   10814   1.1  christos 	}
   10815   1.1  christos 
   10816   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addns: done");
   10817   1.1  christos 	return (eresult);
   10818   1.1  christos }
   10819   1.1  christos 
   10820   1.1  christos /*%
   10821   1.1  christos  * Find the zone cut and add the best NS rrset to the authority section.
   10822   1.1  christos  */
   10823   1.1  christos static void
   10824   1.1  christos query_addbestns(query_ctx_t *qctx) {
   10825   1.1  christos 	ns_client_t *client = qctx->client;
   10826   1.1  christos 	dns_db_t *db = NULL, *zdb = NULL;
   10827   1.1  christos 	dns_dbnode_t *node = NULL;
   10828   1.1  christos 	dns_name_t *fname = NULL, *zfname = NULL;
   10829   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   10830   1.1  christos 	dns_rdataset_t *zrdataset = NULL, *zsigrdataset = NULL;
   10831   1.3  christos 	bool is_zone = false, use_zone = false;
   10832   1.1  christos 	isc_buffer_t *dbuf = NULL;
   10833   1.1  christos 	isc_result_t result;
   10834   1.1  christos 	dns_dbversion_t *version = NULL;
   10835   1.1  christos 	dns_zone_t *zone = NULL;
   10836   1.1  christos 	isc_buffer_t b;
   10837   1.1  christos 	dns_clientinfomethods_t cm;
   10838   1.1  christos 	dns_clientinfo_t ci;
   10839   1.1  christos 
   10840   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addbestns");
   10841   1.1  christos 
   10842   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   10843  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   10844   1.1  christos 
   10845   1.1  christos 	/*
   10846   1.1  christos 	 * Find the right database.
   10847   1.1  christos 	 */
   10848   1.1  christos 	result = query_getdb(client, client->query.qname, dns_rdatatype_ns, 0,
   10849   1.1  christos 			     &zone, &db, &version, &is_zone);
   10850   1.9  christos 	if (result != ISC_R_SUCCESS) {
   10851   1.1  christos 		goto cleanup;
   10852   1.9  christos 	}
   10853   1.1  christos 
   10854   1.9  christos db_find:
   10855   1.1  christos 	/*
   10856   1.1  christos 	 * We'll need some resources...
   10857   1.1  christos 	 */
   10858   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   10859   1.1  christos 	if (dbuf == NULL) {
   10860   1.1  christos 		goto cleanup;
   10861   1.1  christos 	}
   10862   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   10863   1.3  christos 	rdataset = ns_client_newrdataset(client);
   10864   1.1  christos 	if (fname == NULL || rdataset == NULL) {
   10865   1.1  christos 		goto cleanup;
   10866   1.1  christos 	}
   10867   1.1  christos 
   10868   1.1  christos 	/*
   10869   1.1  christos 	 * Get the RRSIGs if the client requested them or if we may
   10870   1.1  christos 	 * need to validate answers from the cache.
   10871   1.1  christos 	 */
   10872   1.1  christos 	if (WANTDNSSEC(client) || !is_zone) {
   10873   1.3  christos 		sigrdataset = ns_client_newrdataset(client);
   10874   1.1  christos 		if (sigrdataset == NULL) {
   10875   1.1  christos 			goto cleanup;
   10876   1.1  christos 		}
   10877   1.1  christos 	}
   10878   1.1  christos 
   10879   1.1  christos 	/*
   10880   1.1  christos 	 * Now look for the zonecut.
   10881   1.1  christos 	 */
   10882   1.1  christos 	if (is_zone) {
   10883   1.9  christos 		result = dns_db_findext(
   10884   1.9  christos 			db, client->query.qname, version, dns_rdatatype_ns,
   10885   1.9  christos 			client->query.dboptions, client->now, &node, fname, &cm,
   10886   1.9  christos 			&ci, rdataset, sigrdataset);
   10887   1.1  christos 		if (result != DNS_R_DELEGATION) {
   10888   1.1  christos 			goto cleanup;
   10889   1.1  christos 		}
   10890   1.1  christos 		if (USECACHE(client)) {
   10891   1.3  christos 			ns_client_keepname(client, fname, dbuf);
   10892   1.1  christos 			dns_db_detachnode(db, &node);
   10893   1.1  christos 			SAVE(zdb, db);
   10894   1.1  christos 			SAVE(zfname, fname);
   10895   1.1  christos 			SAVE(zrdataset, rdataset);
   10896   1.1  christos 			SAVE(zsigrdataset, sigrdataset);
   10897   1.1  christos 			version = NULL;
   10898   1.1  christos 			dns_db_attach(client->view->cachedb, &db);
   10899   1.3  christos 			is_zone = false;
   10900   1.1  christos 			goto db_find;
   10901   1.1  christos 		}
   10902   1.1  christos 	} else {
   10903   1.9  christos 		result = dns_db_findzonecut(
   10904   1.9  christos 			db, client->query.qname, client->query.dboptions,
   10905   1.9  christos 			client->now, &node, fname, NULL, rdataset, sigrdataset);
   10906   1.1  christos 		if (result == ISC_R_SUCCESS) {
   10907   1.1  christos 			if (zfname != NULL &&
   10908  1.16  christos 			    !dns_name_issubdomain(fname, zfname))
   10909  1.16  christos 			{
   10910   1.1  christos 				/*
   10911   1.1  christos 				 * We found a zonecut in the cache, but our
   10912   1.1  christos 				 * zone delegation is better.
   10913   1.1  christos 				 */
   10914   1.3  christos 				use_zone = true;
   10915   1.1  christos 			}
   10916   1.1  christos 		} else if (result == ISC_R_NOTFOUND && zfname != NULL) {
   10917   1.1  christos 			/*
   10918   1.1  christos 			 * We didn't find anything in the cache, but we
   10919   1.1  christos 			 * have a zone delegation, so use it.
   10920   1.1  christos 			 */
   10921   1.3  christos 			use_zone = true;
   10922   1.1  christos 		} else {
   10923   1.1  christos 			goto cleanup;
   10924   1.1  christos 		}
   10925   1.1  christos 	}
   10926   1.1  christos 
   10927   1.1  christos 	if (use_zone) {
   10928   1.3  christos 		ns_client_releasename(client, &fname);
   10929   1.1  christos 		/*
   10930   1.3  christos 		 * We've already done ns_client_keepname() on
   10931   1.1  christos 		 * zfname, so we must set dbuf to NULL to
   10932   1.1  christos 		 * prevent query_addrrset() from trying to
   10933   1.3  christos 		 * call ns_client_keepname() again.
   10934   1.1  christos 		 */
   10935   1.1  christos 		dbuf = NULL;
   10936   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   10937   1.1  christos 		if (sigrdataset != NULL) {
   10938   1.3  christos 			ns_client_putrdataset(client, &sigrdataset);
   10939   1.1  christos 		}
   10940   1.1  christos 
   10941   1.1  christos 		if (node != NULL) {
   10942   1.1  christos 			dns_db_detachnode(db, &node);
   10943   1.1  christos 		}
   10944   1.1  christos 		dns_db_detach(&db);
   10945   1.1  christos 
   10946   1.1  christos 		RESTORE(db, zdb);
   10947   1.1  christos 		RESTORE(fname, zfname);
   10948   1.1  christos 		RESTORE(rdataset, zrdataset);
   10949   1.1  christos 		RESTORE(sigrdataset, zsigrdataset);
   10950   1.1  christos 	}
   10951   1.1  christos 
   10952   1.1  christos 	/*
   10953   1.1  christos 	 * Attempt to validate RRsets that are pending or that are glue.
   10954   1.1  christos 	 */
   10955   1.1  christos 	if ((DNS_TRUST_PENDING(rdataset->trust) ||
   10956   1.1  christos 	     (sigrdataset != NULL && DNS_TRUST_PENDING(sigrdataset->trust))) &&
   10957   1.1  christos 	    !validate(client, db, fname, rdataset, sigrdataset) &&
   10958   1.1  christos 	    !PENDINGOK(client->query.dboptions))
   10959   1.1  christos 	{
   10960   1.1  christos 		goto cleanup;
   10961   1.1  christos 	}
   10962   1.1  christos 
   10963   1.1  christos 	if ((DNS_TRUST_GLUE(rdataset->trust) ||
   10964   1.1  christos 	     (sigrdataset != NULL && DNS_TRUST_GLUE(sigrdataset->trust))) &&
   10965   1.1  christos 	    !validate(client, db, fname, rdataset, sigrdataset) &&
   10966   1.1  christos 	    SECURE(client) && WANTDNSSEC(client))
   10967   1.1  christos 	{
   10968   1.1  christos 		goto cleanup;
   10969   1.1  christos 	}
   10970   1.1  christos 
   10971   1.1  christos 	/*
   10972   1.1  christos 	 * If the answer is secure only add NS records if they are secure
   10973   1.1  christos 	 * when the client may be looking for AD in the response.
   10974   1.1  christos 	 */
   10975   1.1  christos 	if (SECURE(client) && (WANTDNSSEC(client) || WANTAD(client)) &&
   10976   1.1  christos 	    ((rdataset->trust != dns_trust_secure) ||
   10977   1.9  christos 	     (sigrdataset != NULL && sigrdataset->trust != dns_trust_secure)))
   10978   1.1  christos 	{
   10979   1.1  christos 		goto cleanup;
   10980   1.1  christos 	}
   10981   1.1  christos 
   10982   1.1  christos 	/*
   10983   1.1  christos 	 * If the client doesn't want DNSSEC we can discard the sigrdataset
   10984   1.1  christos 	 * now.
   10985   1.1  christos 	 */
   10986   1.1  christos 	if (!WANTDNSSEC(client)) {
   10987   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   10988   1.1  christos 	}
   10989   1.1  christos 
   10990   1.3  christos 	query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   10991   1.1  christos 		       DNS_SECTION_AUTHORITY);
   10992   1.1  christos 
   10993   1.9  christos cleanup:
   10994   1.1  christos 	if (rdataset != NULL) {
   10995   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   10996   1.1  christos 	}
   10997   1.1  christos 	if (sigrdataset != NULL) {
   10998   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   10999   1.1  christos 	}
   11000   1.1  christos 	if (fname != NULL) {
   11001   1.3  christos 		ns_client_releasename(client, &fname);
   11002   1.1  christos 	}
   11003   1.1  christos 	if (node != NULL) {
   11004   1.1  christos 		dns_db_detachnode(db, &node);
   11005   1.1  christos 	}
   11006   1.1  christos 	if (db != NULL) {
   11007   1.1  christos 		dns_db_detach(&db);
   11008   1.1  christos 	}
   11009   1.1  christos 	if (zone != NULL) {
   11010   1.1  christos 		dns_zone_detach(&zone);
   11011   1.1  christos 	}
   11012   1.1  christos 	if (zdb != NULL) {
   11013   1.3  christos 		ns_client_putrdataset(client, &zrdataset);
   11014   1.3  christos 		if (zsigrdataset != NULL) {
   11015   1.3  christos 			ns_client_putrdataset(client, &zsigrdataset);
   11016   1.3  christos 		}
   11017   1.3  christos 		if (zfname != NULL) {
   11018   1.3  christos 			ns_client_releasename(client, &zfname);
   11019   1.3  christos 		}
   11020   1.1  christos 		dns_db_detach(&zdb);
   11021   1.1  christos 	}
   11022   1.1  christos }
   11023   1.1  christos 
   11024   1.1  christos static void
   11025   1.9  christos query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata) {
   11026   1.1  christos 	ns_client_t *client = qctx->client;
   11027   1.1  christos 	isc_buffer_t *dbuf, b;
   11028   1.1  christos 	dns_name_t *name;
   11029   1.1  christos 	dns_name_t *fname = NULL;
   11030   1.1  christos 	dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL;
   11031   1.1  christos 	dns_fixedname_t wfixed;
   11032   1.1  christos 	dns_name_t *wname;
   11033   1.1  christos 	dns_dbnode_t *node = NULL;
   11034   1.1  christos 	unsigned int options;
   11035   1.1  christos 	unsigned int olabels, nlabels, labels;
   11036   1.1  christos 	isc_result_t result;
   11037   1.1  christos 	dns_rdata_t rdata = DNS_RDATA_INIT;
   11038   1.1  christos 	dns_rdata_nsec_t nsec;
   11039   1.3  christos 	bool have_wname;
   11040   1.1  christos 	int order;
   11041   1.1  christos 	dns_fixedname_t cfixed;
   11042   1.1  christos 	dns_name_t *cname;
   11043   1.1  christos 	dns_clientinfomethods_t cm;
   11044   1.1  christos 	dns_clientinfo_t ci;
   11045   1.1  christos 
   11046   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "query_addwildcardproof");
   11047   1.1  christos 
   11048   1.1  christos 	dns_clientinfomethods_init(&cm, ns_client_sourceip);
   11049  1.15  christos 	dns_clientinfo_init(&ci, client, NULL, NULL);
   11050   1.1  christos 
   11051   1.1  christos 	/*
   11052   1.1  christos 	 * If a name has been specifically flagged as needing
   11053   1.1  christos 	 * a wildcard proof then it will have been copied to
   11054   1.1  christos 	 * qctx->wildcardname. Otherwise we just use the client
   11055   1.1  christos 	 * QNAME.
   11056   1.1  christos 	 */
   11057   1.1  christos 	if (qctx->need_wildcardproof) {
   11058   1.1  christos 		name = dns_fixedname_name(&qctx->wildcardname);
   11059   1.1  christos 	} else {
   11060   1.1  christos 		name = client->query.qname;
   11061   1.1  christos 	}
   11062   1.1  christos 
   11063   1.1  christos 	/*
   11064   1.1  christos 	 * Get the NOQNAME proof then if !ispositive
   11065   1.1  christos 	 * get the NOWILDCARD proof.
   11066   1.1  christos 	 *
   11067   1.1  christos 	 * DNS_DBFIND_NOWILD finds the NSEC records that covers the
   11068   1.1  christos 	 * name ignoring any wildcard.  From the owner and next names
   11069   1.1  christos 	 * of this record you can compute which wildcard (if it exists)
   11070   1.1  christos 	 * will match by finding the longest common suffix of the
   11071   1.1  christos 	 * owner name and next names with the qname and prefixing that
   11072   1.1  christos 	 * with the wildcard label.
   11073   1.1  christos 	 *
   11074   1.1  christos 	 * e.g.
   11075   1.1  christos 	 *   Given:
   11076   1.1  christos 	 *	example SOA
   11077   1.1  christos 	 *	example NSEC b.example
   11078   1.1  christos 	 *	b.example A
   11079   1.1  christos 	 *	b.example NSEC a.d.example
   11080   1.1  christos 	 *	a.d.example A
   11081   1.1  christos 	 *	a.d.example NSEC g.f.example
   11082   1.1  christos 	 *	g.f.example A
   11083   1.1  christos 	 *	g.f.example NSEC z.i.example
   11084   1.1  christos 	 *	z.i.example A
   11085   1.1  christos 	 *	z.i.example NSEC example
   11086   1.1  christos 	 *
   11087   1.1  christos 	 *   QNAME:
   11088   1.1  christos 	 *   a.example -> example NSEC b.example
   11089   1.1  christos 	 *	owner common example
   11090   1.1  christos 	 *	next common example
   11091   1.1  christos 	 *	wild *.example
   11092   1.1  christos 	 *   d.b.example -> b.example NSEC a.d.example
   11093   1.1  christos 	 *	owner common b.example
   11094   1.1  christos 	 *	next common example
   11095   1.1  christos 	 *	wild *.b.example
   11096   1.1  christos 	 *   a.f.example -> a.d.example NSEC g.f.example
   11097   1.1  christos 	 *	owner common example
   11098   1.1  christos 	 *	next common f.example
   11099   1.1  christos 	 *	wild *.f.example
   11100   1.1  christos 	 *  j.example -> z.i.example NSEC example
   11101   1.1  christos 	 *	owner common example
   11102   1.1  christos 	 *	next common example
   11103   1.1  christos 	 *	wild *.example
   11104   1.1  christos 	 */
   11105   1.1  christos 	options = client->query.dboptions | DNS_DBFIND_NOWILD;
   11106   1.1  christos 	wname = dns_fixedname_initname(&wfixed);
   11107   1.9  christos again:
   11108   1.3  christos 	have_wname = false;
   11109   1.1  christos 	/*
   11110   1.1  christos 	 * We'll need some resources...
   11111   1.1  christos 	 */
   11112   1.3  christos 	dbuf = ns_client_getnamebuf(client);
   11113   1.9  christos 	if (dbuf == NULL) {
   11114   1.1  christos 		goto cleanup;
   11115   1.9  christos 	}
   11116   1.3  christos 	fname = ns_client_newname(client, dbuf, &b);
   11117   1.3  christos 	rdataset = ns_client_newrdataset(client);
   11118   1.3  christos 	sigrdataset = ns_client_newrdataset(client);
   11119   1.9  christos 	if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   11120   1.1  christos 		goto cleanup;
   11121   1.9  christos 	}
   11122   1.1  christos 
   11123   1.1  christos 	result = dns_db_findext(qctx->db, name, qctx->version,
   11124   1.9  christos 				dns_rdatatype_nsec, options, 0, &node, fname,
   11125   1.9  christos 				&cm, &ci, rdataset, sigrdataset);
   11126   1.9  christos 	if (node != NULL) {
   11127   1.1  christos 		dns_db_detachnode(qctx->db, &node);
   11128   1.9  christos 	}
   11129   1.1  christos 
   11130   1.1  christos 	if (!dns_rdataset_isassociated(rdataset)) {
   11131   1.1  christos 		/*
   11132   1.1  christos 		 * No NSEC proof available, return NSEC3 proofs instead.
   11133   1.1  christos 		 */
   11134   1.1  christos 		cname = dns_fixedname_initname(&cfixed);
   11135   1.1  christos 		/*
   11136   1.1  christos 		 * Find the closest encloser.
   11137   1.1  christos 		 */
   11138   1.8  christos 		dns_name_copynf(name, cname);
   11139   1.1  christos 		while (result == DNS_R_NXDOMAIN) {
   11140   1.1  christos 			labels = dns_name_countlabels(cname) - 1;
   11141   1.1  christos 			/*
   11142   1.1  christos 			 * Sanity check.
   11143   1.1  christos 			 */
   11144   1.9  christos 			if (labels == 0U) {
   11145   1.1  christos 				goto cleanup;
   11146   1.9  christos 			}
   11147   1.1  christos 			dns_name_split(cname, labels, NULL, cname);
   11148   1.1  christos 			result = dns_db_findext(qctx->db, cname, qctx->version,
   11149   1.9  christos 						dns_rdatatype_nsec, options, 0,
   11150   1.9  christos 						NULL, fname, &cm, &ci, NULL,
   11151   1.9  christos 						NULL);
   11152   1.1  christos 		}
   11153   1.1  christos 		/*
   11154   1.1  christos 		 * Add closest (provable) encloser NSEC3.
   11155   1.1  christos 		 */
   11156   1.9  christos 		query_findclosestnsec3(cname, qctx->db, qctx->version, client,
   11157   1.9  christos 				       rdataset, sigrdataset, fname, true,
   11158   1.9  christos 				       cname);
   11159   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11160   1.1  christos 			goto cleanup;
   11161   1.9  christos 		}
   11162   1.9  christos 		if (!ispositive) {
   11163   1.3  christos 			query_addrrset(qctx, &fname, &rdataset, &sigrdataset,
   11164   1.1  christos 				       dbuf, DNS_SECTION_AUTHORITY);
   11165   1.9  christos 		}
   11166   1.1  christos 
   11167   1.1  christos 		/*
   11168   1.1  christos 		 * Replace resources which were consumed by query_addrrset.
   11169   1.1  christos 		 */
   11170   1.1  christos 		if (fname == NULL) {
   11171   1.3  christos 			dbuf = ns_client_getnamebuf(client);
   11172   1.9  christos 			if (dbuf == NULL) {
   11173   1.1  christos 				goto cleanup;
   11174   1.9  christos 			}
   11175   1.3  christos 			fname = ns_client_newname(client, dbuf, &b);
   11176   1.1  christos 		}
   11177   1.1  christos 
   11178   1.9  christos 		if (rdataset == NULL) {
   11179   1.3  christos 			rdataset = ns_client_newrdataset(client);
   11180   1.9  christos 		} else if (dns_rdataset_isassociated(rdataset)) {
   11181   1.1  christos 			dns_rdataset_disassociate(rdataset);
   11182   1.9  christos 		}
   11183   1.1  christos 
   11184   1.9  christos 		if (sigrdataset == NULL) {
   11185   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   11186   1.9  christos 		} else if (dns_rdataset_isassociated(sigrdataset)) {
   11187   1.1  christos 			dns_rdataset_disassociate(sigrdataset);
   11188   1.9  christos 		}
   11189   1.1  christos 
   11190   1.9  christos 		if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   11191   1.1  christos 			goto cleanup;
   11192   1.9  christos 		}
   11193   1.1  christos 		/*
   11194   1.1  christos 		 * Add no qname proof.
   11195   1.1  christos 		 */
   11196   1.1  christos 		labels = dns_name_countlabels(cname) + 1;
   11197   1.9  christos 		if (dns_name_countlabels(name) == labels) {
   11198   1.8  christos 			dns_name_copynf(name, wname);
   11199   1.9  christos 		} else {
   11200   1.1  christos 			dns_name_split(name, labels, NULL, wname);
   11201   1.9  christos 		}
   11202   1.1  christos 
   11203   1.9  christos 		query_findclosestnsec3(wname, qctx->db, qctx->version, client,
   11204   1.9  christos 				       rdataset, sigrdataset, fname, false,
   11205   1.9  christos 				       NULL);
   11206   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11207   1.1  christos 			goto cleanup;
   11208   1.9  christos 		}
   11209   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11210   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11211   1.1  christos 
   11212   1.9  christos 		if (ispositive) {
   11213   1.1  christos 			goto cleanup;
   11214   1.9  christos 		}
   11215   1.1  christos 
   11216   1.1  christos 		/*
   11217   1.1  christos 		 * Replace resources which were consumed by query_addrrset.
   11218   1.1  christos 		 */
   11219   1.1  christos 		if (fname == NULL) {
   11220   1.3  christos 			dbuf = ns_client_getnamebuf(client);
   11221   1.9  christos 			if (dbuf == NULL) {
   11222   1.1  christos 				goto cleanup;
   11223   1.9  christos 			}
   11224   1.3  christos 			fname = ns_client_newname(client, dbuf, &b);
   11225   1.1  christos 		}
   11226   1.1  christos 
   11227   1.9  christos 		if (rdataset == NULL) {
   11228   1.3  christos 			rdataset = ns_client_newrdataset(client);
   11229   1.9  christos 		} else if (dns_rdataset_isassociated(rdataset)) {
   11230   1.1  christos 			dns_rdataset_disassociate(rdataset);
   11231   1.9  christos 		}
   11232   1.1  christos 
   11233   1.9  christos 		if (sigrdataset == NULL) {
   11234   1.3  christos 			sigrdataset = ns_client_newrdataset(client);
   11235   1.9  christos 		} else if (dns_rdataset_isassociated(sigrdataset)) {
   11236   1.1  christos 			dns_rdataset_disassociate(sigrdataset);
   11237   1.9  christos 		}
   11238   1.1  christos 
   11239   1.9  christos 		if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
   11240   1.1  christos 			goto cleanup;
   11241   1.9  christos 		}
   11242   1.1  christos 		/*
   11243   1.1  christos 		 * Add the no wildcard proof.
   11244   1.1  christos 		 */
   11245   1.9  christos 		result = dns_name_concatenate(dns_wildcardname, cname, wname,
   11246   1.9  christos 					      NULL);
   11247   1.9  christos 		if (result != ISC_R_SUCCESS) {
   11248   1.1  christos 			goto cleanup;
   11249   1.9  christos 		}
   11250   1.1  christos 
   11251   1.9  christos 		query_findclosestnsec3(wname, qctx->db, qctx->version, client,
   11252   1.9  christos 				       rdataset, sigrdataset, fname, nodata,
   11253   1.9  christos 				       NULL);
   11254   1.9  christos 		if (!dns_rdataset_isassociated(rdataset)) {
   11255   1.1  christos 			goto cleanup;
   11256   1.9  christos 		}
   11257   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11258   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11259   1.1  christos 
   11260   1.1  christos 		goto cleanup;
   11261   1.1  christos 	} else if (result == DNS_R_NXDOMAIN) {
   11262   1.9  christos 		if (!ispositive) {
   11263   1.1  christos 			result = dns_rdataset_first(rdataset);
   11264   1.9  christos 		}
   11265   1.1  christos 		if (result == ISC_R_SUCCESS) {
   11266   1.1  christos 			dns_rdataset_current(rdataset, &rdata);
   11267   1.1  christos 			result = dns_rdata_tostruct(&rdata, &nsec, NULL);
   11268   1.3  christos 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   11269   1.1  christos 			(void)dns_name_fullcompare(name, fname, &order,
   11270   1.1  christos 						   &olabels);
   11271   1.1  christos 			(void)dns_name_fullcompare(name, &nsec.next, &order,
   11272   1.1  christos 						   &nlabels);
   11273   1.1  christos 			/*
   11274   1.1  christos 			 * Check for a pathological condition created when
   11275   1.1  christos 			 * serving some malformed signed zones and bail out.
   11276   1.1  christos 			 */
   11277   1.9  christos 			if (dns_name_countlabels(name) == nlabels) {
   11278   1.1  christos 				goto cleanup;
   11279   1.9  christos 			}
   11280   1.1  christos 
   11281   1.9  christos 			if (olabels > nlabels) {
   11282   1.1  christos 				dns_name_split(name, olabels, NULL, wname);
   11283   1.9  christos 			} else {
   11284   1.1  christos 				dns_name_split(name, nlabels, NULL, wname);
   11285   1.9  christos 			}
   11286   1.9  christos 			result = dns_name_concatenate(dns_wildcardname, wname,
   11287   1.9  christos 						      wname, NULL);
   11288   1.9  christos 			if (result == ISC_R_SUCCESS) {
   11289   1.3  christos 				have_wname = true;
   11290   1.9  christos 			}
   11291   1.1  christos 			dns_rdata_freestruct(&nsec);
   11292   1.1  christos 		}
   11293   1.9  christos 		query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf,
   11294   1.9  christos 			       DNS_SECTION_AUTHORITY);
   11295   1.1  christos 	}
   11296   1.3  christos 	if (rdataset != NULL) {
   11297   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11298   1.3  christos 	}
   11299   1.3  christos 	if (sigrdataset != NULL) {
   11300   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11301   1.3  christos 	}
   11302   1.3  christos 	if (fname != NULL) {
   11303   1.3  christos 		ns_client_releasename(client, &fname);
   11304   1.3  christos 	}
   11305   1.1  christos 	if (have_wname) {
   11306   1.9  christos 		ispositive = true; /* prevent loop */
   11307   1.1  christos 		if (!dns_name_equal(name, wname)) {
   11308   1.1  christos 			name = wname;
   11309   1.1  christos 			goto again;
   11310   1.1  christos 		}
   11311   1.1  christos 	}
   11312   1.9  christos cleanup:
   11313   1.3  christos 	if (rdataset != NULL) {
   11314   1.3  christos 		ns_client_putrdataset(client, &rdataset);
   11315   1.3  christos 	}
   11316   1.3  christos 	if (sigrdataset != NULL) {
   11317   1.3  christos 		ns_client_putrdataset(client, &sigrdataset);
   11318   1.3  christos 	}
   11319   1.3  christos 	if (fname != NULL) {
   11320   1.3  christos 		ns_client_releasename(client, &fname);
   11321   1.3  christos 	}
   11322   1.1  christos }
   11323   1.1  christos 
   11324   1.1  christos /*%
   11325   1.1  christos  * Add NS records, and NSEC/NSEC3 wildcard proof records if needed,
   11326   1.1  christos  * to the authority section.
   11327   1.1  christos  */
   11328   1.1  christos static void
   11329   1.1  christos query_addauth(query_ctx_t *qctx) {
   11330   1.1  christos 	CCTRACE(ISC_LOG_DEBUG(3), "query_addauth");
   11331   1.1  christos 	/*
   11332   1.1  christos 	 * Add NS records to the authority section (if we haven't already
   11333   1.1  christos 	 * added them to the answer section).
   11334   1.1  christos 	 */
   11335   1.1  christos 	if (!qctx->want_restart && !NOAUTHORITY(qctx->client)) {
   11336   1.1  christos 		if (qctx->is_zone) {
   11337   1.1  christos 			if (!qctx->answer_has_ns) {
   11338   1.1  christos 				(void)query_addns(qctx);
   11339   1.1  christos 			}
   11340   1.1  christos 		} else if (!qctx->answer_has_ns &&
   11341  1.16  christos 			   qctx->qtype != dns_rdatatype_ns)
   11342  1.16  christos 		{
   11343   1.1  christos 			if (qctx->fname != NULL) {
   11344   1.3  christos 				ns_client_releasename(qctx->client,
   11345   1.3  christos 						      &qctx->fname);
   11346   1.1  christos 			}
   11347   1.1  christos 			query_addbestns(qctx);
   11348   1.1  christos 		}
   11349   1.1  christos 	}
   11350   1.1  christos 
   11351   1.1  christos 	/*
   11352   1.1  christos 	 * Add NSEC records to the authority section if they're needed for
   11353   1.1  christos 	 * DNSSEC wildcard proofs.
   11354   1.1  christos 	 */
   11355   1.9  christos 	if (qctx->need_wildcardproof && dns_db_issecure(qctx->db)) {
   11356   1.3  christos 		query_addwildcardproof(qctx, true, false);
   11357   1.9  christos 	}
   11358   1.1  christos }
   11359   1.1  christos 
   11360   1.1  christos /*
   11361   1.1  christos  * Find the sort order of 'rdata' in the topology-like
   11362   1.1  christos  * ACL forming the second element in a 2-element top-level
   11363   1.1  christos  * sortlist statement.
   11364   1.1  christos  */
   11365   1.1  christos static int
   11366   1.1  christos query_sortlist_order_2element(const dns_rdata_t *rdata, const void *arg) {
   11367   1.1  christos 	isc_netaddr_t netaddr;
   11368   1.1  christos 
   11369   1.9  christos 	if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) {
   11370   1.1  christos 		return (INT_MAX);
   11371   1.9  christos 	}
   11372   1.1  christos 	return (ns_sortlist_addrorder2(&netaddr, arg));
   11373   1.1  christos }
   11374   1.1  christos 
   11375   1.1  christos /*
   11376   1.1  christos  * Find the sort order of 'rdata' in the matching element
   11377   1.1  christos  * of a 1-element top-level sortlist statement.
   11378   1.1  christos  */
   11379   1.1  christos static int
   11380   1.1  christos query_sortlist_order_1element(const dns_rdata_t *rdata, const void *arg) {
   11381   1.1  christos 	isc_netaddr_t netaddr;
   11382   1.1  christos 
   11383   1.9  christos 	if (rdata_tonetaddr(rdata, &netaddr) != ISC_R_SUCCESS) {
   11384   1.1  christos 		return (INT_MAX);
   11385   1.9  christos 	}
   11386   1.1  christos 	return (ns_sortlist_addrorder1(&netaddr, arg));
   11387   1.1  christos }
   11388   1.1  christos 
   11389   1.1  christos /*
   11390   1.1  christos  * Find the sortlist statement that applies to 'client' and set up
   11391   1.1  christos  * the sortlist info in in client->message appropriately.
   11392   1.1  christos  */
   11393   1.1  christos static void
   11394   1.1  christos query_setup_sortlist(query_ctx_t *qctx) {
   11395   1.1  christos 	isc_netaddr_t netaddr;
   11396   1.1  christos 	ns_client_t *client = qctx->client;
   11397   1.9  christos 	dns_aclenv_t *env =
   11398   1.9  christos 		ns_interfacemgr_getaclenv(client->manager->interface->mgr);
   11399   1.1  christos 	const void *order_arg = NULL;
   11400   1.1  christos 
   11401   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   11402   1.9  christos 	switch (ns_sortlist_setup(client->view->sortlist, env, &netaddr,
   11403  1.16  christos 				  &order_arg))
   11404  1.16  christos 	{
   11405   1.1  christos 	case NS_SORTLISTTYPE_1ELEMENT:
   11406   1.1  christos 		dns_message_setsortorder(client->message,
   11407   1.9  christos 					 query_sortlist_order_1element, env,
   11408   1.9  christos 					 NULL, order_arg);
   11409   1.1  christos 		break;
   11410   1.1  christos 	case NS_SORTLISTTYPE_2ELEMENT:
   11411   1.1  christos 		dns_message_setsortorder(client->message,
   11412   1.9  christos 					 query_sortlist_order_2element, env,
   11413   1.9  christos 					 order_arg, NULL);
   11414   1.1  christos 		break;
   11415   1.1  christos 	case NS_SORTLISTTYPE_NONE:
   11416   1.1  christos 		break;
   11417   1.1  christos 	default:
   11418  1.15  christos 		UNREACHABLE();
   11419   1.1  christos 	}
   11420   1.1  christos }
   11421   1.1  christos 
   11422   1.1  christos /*
   11423   1.1  christos  * When sending a referral, if the answer to the question is
   11424   1.1  christos  * in the glue, sort it to the start of the additional section.
   11425   1.1  christos  */
   11426  1.15  christos static void
   11427   1.1  christos query_glueanswer(query_ctx_t *qctx) {
   11428   1.1  christos 	const dns_namelist_t *secs = qctx->client->message->sections;
   11429   1.1  christos 	const dns_section_t section = DNS_SECTION_ADDITIONAL;
   11430   1.1  christos 	dns_name_t *name;
   11431   1.1  christos 	dns_message_t *msg;
   11432   1.1  christos 	dns_rdataset_t *rdataset = NULL;
   11433   1.1  christos 
   11434   1.1  christos 	if (!ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
   11435   1.1  christos 	    qctx->client->message->rcode != dns_rcode_noerror ||
   11436   1.1  christos 	    (qctx->qtype != dns_rdatatype_a &&
   11437   1.1  christos 	     qctx->qtype != dns_rdatatype_aaaa))
   11438   1.1  christos 	{
   11439   1.1  christos 		return;
   11440   1.1  christos 	}
   11441   1.1  christos 
   11442   1.1  christos 	msg = qctx->client->message;
   11443   1.9  christos 	for (name = ISC_LIST_HEAD(msg->sections[section]); name != NULL;
   11444   1.1  christos 	     name = ISC_LIST_NEXT(name, link))
   11445   1.9  christos 	{
   11446   1.1  christos 		if (dns_name_equal(name, qctx->client->query.qname)) {
   11447   1.1  christos 			for (rdataset = ISC_LIST_HEAD(name->list);
   11448   1.1  christos 			     rdataset != NULL;
   11449   1.1  christos 			     rdataset = ISC_LIST_NEXT(rdataset, link))
   11450   1.9  christos 			{
   11451   1.9  christos 				if (rdataset->type == qctx->qtype) {
   11452   1.1  christos 					break;
   11453   1.9  christos 				}
   11454   1.9  christos 			}
   11455   1.1  christos 			break;
   11456   1.1  christos 		}
   11457   1.9  christos 	}
   11458   1.1  christos 	if (rdataset != NULL) {
   11459   1.1  christos 		ISC_LIST_UNLINK(msg->sections[section], name, link);
   11460   1.1  christos 		ISC_LIST_PREPEND(msg->sections[section], name, link);
   11461   1.1  christos 		ISC_LIST_UNLINK(name->list, rdataset, link);
   11462   1.1  christos 		ISC_LIST_PREPEND(name->list, rdataset, link);
   11463   1.1  christos 		rdataset->attributes |= DNS_RDATASETATTR_REQUIRED;
   11464   1.1  christos 	}
   11465   1.1  christos }
   11466   1.1  christos 
   11467   1.3  christos isc_result_t
   11468   1.3  christos ns_query_done(query_ctx_t *qctx) {
   11469   1.3  christos 	isc_result_t result;
   11470   1.1  christos 	const dns_namelist_t *secs = qctx->client->message->sections;
   11471  1.13  christos 	bool nodetach;
   11472   1.1  christos 
   11473   1.3  christos 	CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done");
   11474   1.3  christos 
   11475   1.3  christos 	CALL_HOOK(NS_QUERY_DONE_BEGIN, qctx);
   11476   1.1  christos 
   11477   1.1  christos 	/*
   11478   1.1  christos 	 * General cleanup.
   11479   1.1  christos 	 */
   11480   1.1  christos 	qctx->rpz_st = qctx->client->query.rpz_st;
   11481   1.1  christos 	if (qctx->rpz_st != NULL &&
   11482  1.16  christos 	    (qctx->rpz_st->state & DNS_RPZ_RECURSING) == 0)
   11483  1.16  christos 	{
   11484   1.1  christos 		rpz_match_clear(qctx->rpz_st);
   11485   1.1  christos 		qctx->rpz_st->state &= ~DNS_RPZ_DONE_QNAME;
   11486   1.1  christos 	}
   11487   1.1  christos 
   11488   1.1  christos 	qctx_clean(qctx);
   11489   1.1  christos 	qctx_freedata(qctx);
   11490   1.1  christos 
   11491   1.6  christos 	if (qctx->client->query.gluedb != NULL) {
   11492   1.6  christos 		dns_db_detach(&qctx->client->query.gluedb);
   11493   1.6  christos 	}
   11494   1.6  christos 
   11495   1.1  christos 	/*
   11496   1.1  christos 	 * Clear the AA bit if we're not authoritative.
   11497   1.1  christos 	 */
   11498   1.1  christos 	if (qctx->client->query.restarts == 0 && !qctx->authoritative) {
   11499   1.1  christos 		qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA;
   11500   1.1  christos 	}
   11501   1.1  christos 
   11502   1.1  christos 	/*
   11503   1.1  christos 	 * Do we need to restart the query (e.g. for CNAME chaining)?
   11504   1.1  christos 	 */
   11505   1.1  christos 	if (qctx->want_restart && qctx->client->query.restarts < MAX_RESTARTS) {
   11506   1.1  christos 		qctx->client->query.restarts++;
   11507   1.1  christos 		return (ns__query_start(qctx));
   11508   1.1  christos 	}
   11509   1.1  christos 
   11510   1.1  christos 	if (qctx->result != ISC_R_SUCCESS &&
   11511   1.1  christos 	    (!PARTIALANSWER(qctx->client) || WANTRECURSION(qctx->client) ||
   11512   1.1  christos 	     qctx->result == DNS_R_DROP))
   11513   1.1  christos 	{
   11514   1.1  christos 		if (qctx->result == DNS_R_DUPLICATE ||
   11515  1.16  christos 		    qctx->result == DNS_R_DROP)
   11516  1.16  christos 		{
   11517   1.1  christos 			/*
   11518   1.1  christos 			 * This was a duplicate query that we are
   11519   1.1  christos 			 * recursing on or the result of rate limiting.
   11520   1.1  christos 			 * Don't send a response now for a duplicate query,
   11521   1.1  christos 			 * because the original will still cause a response.
   11522   1.1  christos 			 */
   11523   1.1  christos 			query_next(qctx->client, qctx->result);
   11524   1.1  christos 		} else {
   11525   1.1  christos 			/*
   11526   1.1  christos 			 * If we don't have any answer to give the client,
   11527   1.1  christos 			 * or if the client requested recursion and thus wanted
   11528   1.1  christos 			 * the complete answer, send an error response.
   11529   1.1  christos 			 */
   11530   1.1  christos 			INSIST(qctx->line >= 0);
   11531   1.1  christos 			query_error(qctx->client, qctx->result, qctx->line);
   11532   1.1  christos 		}
   11533   1.1  christos 
   11534   1.3  christos 		qctx->detach_client = true;
   11535   1.1  christos 		return (qctx->result);
   11536   1.1  christos 	}
   11537   1.1  christos 
   11538   1.1  christos 	/*
   11539   1.1  christos 	 * If we're recursing then just return; the query will
   11540   1.1  christos 	 * resume when recursion ends.
   11541   1.1  christos 	 */
   11542  1.11  christos 	if (RECURSING(qctx->client) &&
   11543  1.13  christos 	    (!QUERY_STALETIMEOUT(&qctx->client->query) ||
   11544  1.11  christos 	     ((qctx->options & DNS_GETDB_STALEFIRST) != 0)))
   11545  1.11  christos 	{
   11546   1.1  christos 		return (qctx->result);
   11547   1.1  christos 	}
   11548   1.1  christos 
   11549   1.1  christos 	/*
   11550   1.1  christos 	 * We are done.  Set up sortlist data for the message
   11551   1.1  christos 	 * rendering code, sort the answer to the front of the
   11552   1.1  christos 	 * additional section if necessary, make a final tweak
   11553   1.1  christos 	 * to the AA bit if the auth-nxdomain config option
   11554   1.1  christos 	 * says so, then render and send the response.
   11555   1.1  christos 	 */
   11556  1.13  christos 	query_setup_sortlist(qctx);
   11557  1.13  christos 	query_glueanswer(qctx);
   11558   1.1  christos 
   11559   1.1  christos 	if (qctx->client->message->rcode == dns_rcode_nxdomain &&
   11560  1.10  christos 	    qctx->view->auth_nxdomain)
   11561   1.1  christos 	{
   11562   1.1  christos 		qctx->client->message->flags |= DNS_MESSAGEFLAG_AA;
   11563   1.1  christos 	}
   11564   1.1  christos 
   11565   1.1  christos 	/*
   11566   1.1  christos 	 * If the response is somehow unexpected for the client and this
   11567   1.1  christos 	 * is a result of recursion, return an error to the caller
   11568   1.1  christos 	 * to indicate it may need to be logged.
   11569   1.1  christos 	 */
   11570   1.1  christos 	if (qctx->resuming &&
   11571   1.1  christos 	    (ISC_LIST_EMPTY(secs[DNS_SECTION_ANSWER]) ||
   11572   1.1  christos 	     qctx->client->message->rcode != dns_rcode_noerror))
   11573   1.1  christos 	{
   11574   1.1  christos 		qctx->result = ISC_R_FAILURE;
   11575   1.1  christos 	}
   11576   1.1  christos 
   11577   1.3  christos 	CALL_HOOK(NS_QUERY_DONE_SEND, qctx);
   11578   1.3  christos 
   11579  1.11  christos 	/*
   11580  1.11  christos 	 * Client may have been detached after query_send(), so
   11581  1.11  christos 	 * we test and store the flag state here, for safety.
   11582  1.11  christos 	 */
   11583  1.13  christos 	nodetach = qctx->client->nodetach;
   11584   1.1  christos 	query_send(qctx->client);
   11585  1.15  christos 
   11586  1.15  christos 	if (qctx->refresh_rrset) {
   11587  1.15  christos 		/*
   11588  1.15  christos 		 * If we reached this point then it means that we have found a
   11589  1.15  christos 		 * stale RRset entry in cache and BIND is configured to allow
   11590  1.15  christos 		 * queries to be answered with stale data if no active RRset
   11591  1.15  christos 		 * is available, i.e. "stale-anwer-client-timeout 0". But, we
   11592  1.15  christos 		 * still need to refresh the RRset. To prevent adding duplicate
   11593  1.15  christos 		 * RRsets, clear the RRsets from the message before doing the
   11594  1.15  christos 		 * refresh.
   11595  1.15  christos 		 */
   11596  1.15  christos 		message_clearrdataset(qctx->client->message, 0);
   11597  1.15  christos 		query_refresh_rrset(qctx);
   11598  1.15  christos 	}
   11599  1.15  christos 
   11600  1.13  christos 	if (!nodetach) {
   11601  1.11  christos 		qctx->detach_client = true;
   11602  1.11  christos 	}
   11603   1.1  christos 	return (qctx->result);
   11604   1.3  christos 
   11605   1.9  christos cleanup:
   11606   1.3  christos 	return (result);
   11607   1.1  christos }
   11608   1.1  christos 
   11609  1.15  christos static void
   11610   1.1  christos log_tat(ns_client_t *client) {
   11611   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   11612   1.1  christos 	char clientbuf[ISC_NETADDR_FORMATSIZE];
   11613   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   11614   1.1  christos 	isc_netaddr_t netaddr;
   11615   1.1  christos 	char *tags = NULL;
   11616   1.1  christos 	size_t taglen = 0;
   11617   1.1  christos 
   11618   1.1  christos 	if (!isc_log_wouldlog(ns_lctx, ISC_LOG_INFO)) {
   11619   1.1  christos 		return;
   11620   1.1  christos 	}
   11621   1.1  christos 
   11622   1.1  christos 	if ((client->query.qtype != dns_rdatatype_null ||
   11623   1.1  christos 	     !dns_name_istat(client->query.qname)) &&
   11624   1.1  christos 	    (client->keytag == NULL ||
   11625   1.1  christos 	     client->query.qtype != dns_rdatatype_dnskey))
   11626   1.1  christos 	{
   11627   1.1  christos 		return;
   11628   1.1  christos 	}
   11629   1.1  christos 
   11630   1.1  christos 	isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
   11631   1.1  christos 	dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
   11632   1.3  christos 	isc_netaddr_format(&netaddr, clientbuf, sizeof(clientbuf));
   11633   1.3  christos 	dns_rdataclass_format(client->view->rdclass, classbuf,
   11634   1.3  christos 			      sizeof(classbuf));
   11635   1.1  christos 
   11636   1.1  christos 	if (client->query.qtype == dns_rdatatype_dnskey) {
   11637   1.3  christos 		uint16_t keytags = client->keytag_len / 2;
   11638   1.1  christos 		size_t len = taglen = sizeof("65000") * keytags + 1;
   11639   1.1  christos 		char *cp = tags = isc_mem_get(client->mctx, taglen);
   11640   1.1  christos 		int i = 0;
   11641   1.1  christos 
   11642   1.1  christos 		INSIST(client->keytag != NULL);
   11643   1.1  christos 		if (tags != NULL) {
   11644   1.1  christos 			while (keytags-- > 0U) {
   11645   1.1  christos 				int n;
   11646   1.3  christos 				uint16_t keytag;
   11647   1.1  christos 				keytag = (client->keytag[i * 2] << 8) |
   11648   1.1  christos 					 client->keytag[i * 2 + 1];
   11649   1.1  christos 				n = snprintf(cp, len, " %u", keytag);
   11650   1.1  christos 				if (n > 0 && (size_t)n <= len) {
   11651   1.1  christos 					cp += n;
   11652   1.1  christos 					len -= n;
   11653   1.1  christos 					i++;
   11654   1.1  christos 				} else {
   11655   1.1  christos 					break;
   11656   1.1  christos 				}
   11657   1.1  christos 			}
   11658   1.1  christos 		}
   11659   1.1  christos 	}
   11660   1.1  christos 
   11661   1.1  christos 	isc_log_write(ns_lctx, NS_LOGCATEGORY_TAT, NS_LOGMODULE_QUERY,
   11662   1.1  christos 		      ISC_LOG_INFO, "trust-anchor-telemetry '%s/%s' from %s%s",
   11663   1.9  christos 		      namebuf, classbuf, clientbuf, tags != NULL ? tags : "");
   11664   1.1  christos 	if (tags != NULL) {
   11665   1.1  christos 		isc_mem_put(client->mctx, tags, taglen);
   11666   1.1  christos 	}
   11667   1.1  christos }
   11668   1.1  christos 
   11669  1.15  christos static void
   11670   1.1  christos log_query(ns_client_t *client, unsigned int flags, unsigned int extflags) {
   11671   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   11672   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   11673   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   11674   1.1  christos 	char onbuf[ISC_NETADDR_FORMATSIZE];
   11675   1.1  christos 	char ecsbuf[DNS_ECS_FORMATSIZE + sizeof(" [ECS ]") - 1] = { 0 };
   11676   1.1  christos 	char ednsbuf[sizeof("E(65535)")] = { 0 };
   11677   1.1  christos 	dns_rdataset_t *rdataset;
   11678   1.1  christos 	int level = ISC_LOG_INFO;
   11679   1.1  christos 
   11680   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   11681   1.1  christos 		return;
   11682   1.9  christos 	}
   11683   1.1  christos 
   11684   1.1  christos 	rdataset = ISC_LIST_HEAD(client->query.qname->list);
   11685   1.1  christos 	INSIST(rdataset != NULL);
   11686   1.1  christos 	dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
   11687   1.3  christos 	dns_rdataclass_format(rdataset->rdclass, classbuf, sizeof(classbuf));
   11688   1.3  christos 	dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
   11689   1.1  christos 	isc_netaddr_format(&client->destaddr, onbuf, sizeof(onbuf));
   11690   1.1  christos 
   11691   1.9  christos 	if (client->ednsversion >= 0) {
   11692   1.1  christos 		snprintf(ednsbuf, sizeof(ednsbuf), "E(%hd)",
   11693   1.1  christos 			 client->ednsversion);
   11694   1.9  christos 	}
   11695   1.1  christos 
   11696   1.1  christos 	if (HAVEECS(client)) {
   11697   1.1  christos 		strlcpy(ecsbuf, " [ECS ", sizeof(ecsbuf));
   11698   1.1  christos 		dns_ecs_format(&client->ecs, ecsbuf + 6, sizeof(ecsbuf) - 6);
   11699   1.1  christos 		strlcat(ecsbuf, "]", sizeof(ecsbuf));
   11700   1.1  christos 	}
   11701   1.1  christos 
   11702   1.9  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERIES, NS_LOGMODULE_QUERY, level,
   11703   1.9  christos 		      "query: %s %s %s %s%s%s%s%s%s%s (%s)%s", namebuf,
   11704   1.9  christos 		      classbuf, typebuf, WANTRECURSION(client) ? "+" : "-",
   11705   1.1  christos 		      (client->signer != NULL) ? "S" : "", ednsbuf,
   11706   1.1  christos 		      TCP(client) ? "T" : "",
   11707   1.1  christos 		      ((extflags & DNS_MESSAGEEXTFLAG_DO) != 0) ? "D" : "",
   11708   1.1  christos 		      ((flags & DNS_MESSAGEFLAG_CD) != 0) ? "C" : "",
   11709  1.11  christos 		      HAVECOOKIE(client)   ? "V"
   11710  1.11  christos 		      : WANTCOOKIE(client) ? "K"
   11711  1.11  christos 					   : "",
   11712   1.1  christos 		      onbuf, ecsbuf);
   11713   1.1  christos }
   11714   1.1  christos 
   11715  1.15  christos static void
   11716   1.1  christos log_queryerror(ns_client_t *client, isc_result_t result, int line, int level) {
   11717   1.1  christos 	char namebuf[DNS_NAME_FORMATSIZE];
   11718   1.3  christos 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
   11719   1.3  christos 	char classbuf[DNS_RDATACLASS_FORMATSIZE];
   11720   1.1  christos 	const char *namep, *typep, *classp, *sep1, *sep2;
   11721   1.1  christos 	dns_rdataset_t *rdataset;
   11722   1.1  christos 
   11723   1.9  christos 	if (!isc_log_wouldlog(ns_lctx, level)) {
   11724   1.1  christos 		return;
   11725   1.9  christos 	}
   11726   1.1  christos 
   11727   1.1  christos 	namep = typep = classp = sep1 = sep2 = "";
   11728   1.1  christos 
   11729   1.1  christos 	/*
   11730   1.1  christos 	 * Query errors can happen for various reasons.  In some cases we cannot
   11731   1.1  christos 	 * even assume the query contains a valid question section, so we should
   11732   1.1  christos 	 * expect exceptional cases.
   11733   1.1  christos 	 */
   11734   1.1  christos 	if (client->query.origqname != NULL) {
   11735   1.1  christos 		dns_name_format(client->query.origqname, namebuf,
   11736   1.1  christos 				sizeof(namebuf));
   11737   1.1  christos 		namep = namebuf;
   11738   1.1  christos 		sep1 = " for ";
   11739   1.1  christos 
   11740   1.1  christos 		rdataset = ISC_LIST_HEAD(client->query.origqname->list);
   11741   1.1  christos 		if (rdataset != NULL) {
   11742   1.3  christos 			dns_rdataclass_format(rdataset->rdclass, classbuf,
   11743   1.3  christos 					      sizeof(classbuf));
   11744   1.3  christos 			classp = classbuf;
   11745   1.3  christos 			dns_rdatatype_format(rdataset->type, typebuf,
   11746   1.3  christos 					     sizeof(typebuf));
   11747   1.3  christos 			typep = typebuf;
   11748   1.1  christos 			sep2 = "/";
   11749   1.1  christos 		}
   11750   1.1  christos 	}
   11751   1.1  christos 
   11752   1.1  christos 	ns_client_log(client, NS_LOGCATEGORY_QUERY_ERRORS, NS_LOGMODULE_QUERY,
   11753   1.1  christos 		      level, "query failed (%s)%s%s%s%s%s%s at %s:%d",
   11754   1.9  christos 		      isc_result_totext(result), sep1, namep, sep2, classp,
   11755   1.9  christos 		      sep2, typep, __FILE__, line);
   11756   1.1  christos }
   11757   1.1  christos 
   11758   1.1  christos void
   11759  1.11  christos ns_query_start(ns_client_t *client, isc_nmhandle_t *handle) {
   11760   1.1  christos 	isc_result_t result;
   11761   1.8  christos 	dns_message_t *message;
   11762   1.1  christos 	dns_rdataset_t *rdataset;
   11763   1.1  christos 	dns_rdatatype_t qtype;
   11764   1.8  christos 	unsigned int saved_extflags;
   11765   1.8  christos 	unsigned int saved_flags;
   11766   1.1  christos 
   11767   1.1  christos 	REQUIRE(NS_CLIENT_VALID(client));
   11768   1.1  christos 
   11769  1.11  christos 	/*
   11770  1.11  christos 	 * Attach to the request handle
   11771  1.11  christos 	 */
   11772  1.11  christos 	isc_nmhandle_attach(handle, &client->reqhandle);
   11773  1.11  christos 
   11774   1.8  christos 	message = client->message;
   11775   1.8  christos 	saved_extflags = client->extflags;
   11776   1.8  christos 	saved_flags = client->message->flags;
   11777   1.8  christos 
   11778   1.1  christos 	CTRACE(ISC_LOG_DEBUG(3), "ns_query_start");
   11779   1.1  christos 
   11780   1.1  christos 	/*
   11781   1.1  christos 	 * Ensure that appropriate cleanups occur.
   11782   1.1  christos 	 */
   11783   1.9  christos 	client->cleanup = query_cleanup;
   11784   1.1  christos 
   11785   1.9  christos 	if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) {
   11786   1.9  christos 		client->query.attributes |= NS_QUERYATTR_WANTRECURSION;
   11787   1.1  christos 	}
   11788   1.1  christos 
   11789   1.9  christos 	if ((client->extflags & DNS_MESSAGEEXTFLAG_DO) != 0) {
   11790   1.1  christos 		client->attributes |= NS_CLIENTATTR_WANTDNSSEC;
   11791   1.9  christos 	}
   11792   1.1  christos 
   11793   1.1  christos 	switch (client->view->minimalresponses) {
   11794   1.1  christos 	case dns_minimal_no:
   11795   1.1  christos 		break;
   11796   1.1  christos 	case dns_minimal_yes:
   11797   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   11798   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   11799   1.1  christos 		break;
   11800   1.1  christos 	case dns_minimal_noauth:
   11801   1.1  christos 		client->query.attributes |= NS_QUERYATTR_NOAUTHORITY;
   11802   1.1  christos 		break;
   11803   1.1  christos 	case dns_minimal_noauthrec:
   11804   1.9  christos 		if ((message->flags & DNS_MESSAGEFLAG_RD) != 0) {
   11805   1.1  christos 			client->query.attributes |= NS_QUERYATTR_NOAUTHORITY;
   11806   1.9  christos 		}
   11807   1.1  christos 		break;
   11808   1.1  christos 	}
   11809   1.1  christos 
   11810   1.1  christos 	if (client->view->cachedb == NULL || !client->view->recursion) {
   11811   1.1  christos 		/*
   11812   1.1  christos 		 * We don't have a cache.  Turn off cache support and
   11813   1.1  christos 		 * recursion.
   11814   1.1  christos 		 */
   11815   1.9  christos 		client->query.attributes &= ~(NS_QUERYATTR_RECURSIONOK |
   11816   1.9  christos 					      NS_QUERYATTR_CACHEOK);
   11817   1.1  christos 		client->attributes |= NS_CLIENTATTR_NOSETFC;
   11818   1.1  christos 	} else if ((client->attributes & NS_CLIENTATTR_RA) == 0 ||
   11819   1.9  christos 		   (message->flags & DNS_MESSAGEFLAG_RD) == 0)
   11820   1.9  christos 	{
   11821   1.1  christos 		/*
   11822   1.1  christos 		 * If the client isn't allowed to recurse (due to
   11823   1.1  christos 		 * "recursion no", the allow-recursion ACL, or the
   11824   1.1  christos 		 * lack of a resolver in this view), or if it
   11825   1.1  christos 		 * doesn't want recursion, turn recursion off.
   11826   1.1  christos 		 */
   11827   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
   11828   1.1  christos 		client->attributes |= NS_CLIENTATTR_NOSETFC;
   11829   1.1  christos 	}
   11830   1.1  christos 
   11831   1.1  christos 	/*
   11832   1.1  christos 	 * Check for multiple question queries, since edns1 is dead.
   11833   1.1  christos 	 */
   11834   1.1  christos 	if (message->counts[DNS_SECTION_QUESTION] > 1) {
   11835   1.1  christos 		query_error(client, DNS_R_FORMERR, __LINE__);
   11836   1.1  christos 		return;
   11837   1.1  christos 	}
   11838   1.1  christos 
   11839   1.1  christos 	/*
   11840   1.1  christos 	 * Get the question name.
   11841   1.1  christos 	 */
   11842   1.1  christos 	result = dns_message_firstname(message, DNS_SECTION_QUESTION);
   11843   1.1  christos 	if (result != ISC_R_SUCCESS) {
   11844   1.1  christos 		query_error(client, result, __LINE__);
   11845   1.1  christos 		return;
   11846   1.1  christos 	}
   11847   1.1  christos 	dns_message_currentname(message, DNS_SECTION_QUESTION,
   11848   1.1  christos 				&client->query.qname);
   11849   1.1  christos 	client->query.origqname = client->query.qname;
   11850   1.1  christos 	result = dns_message_nextname(message, DNS_SECTION_QUESTION);
   11851   1.1  christos 	if (result != ISC_R_NOMORE) {
   11852   1.1  christos 		if (result == ISC_R_SUCCESS) {
   11853   1.1  christos 			/*
   11854   1.1  christos 			 * There's more than one QNAME in the question
   11855   1.1  christos 			 * section.
   11856   1.1  christos 			 */
   11857   1.1  christos 			query_error(client, DNS_R_FORMERR, __LINE__);
   11858   1.9  christos 		} else {
   11859   1.1  christos 			query_error(client, result, __LINE__);
   11860   1.9  christos 		}
   11861   1.1  christos 		return;
   11862   1.1  christos 	}
   11863   1.1  christos 
   11864   1.9  christos 	if ((client->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
   11865   1.1  christos 		log_query(client, saved_flags, saved_extflags);
   11866   1.9  christos 	}
   11867   1.1  christos 
   11868   1.1  christos 	/*
   11869   1.1  christos 	 * Check for meta-queries like IXFR and AXFR.
   11870   1.1  christos 	 */
   11871   1.1  christos 	rdataset = ISC_LIST_HEAD(client->query.qname->list);
   11872   1.1  christos 	INSIST(rdataset != NULL);
   11873   1.1  christos 	client->query.qtype = qtype = rdataset->type;
   11874   1.1  christos 	dns_rdatatypestats_increment(client->sctx->rcvquerystats, qtype);
   11875   1.1  christos 
   11876   1.1  christos 	log_tat(client);
   11877   1.1  christos 
   11878   1.1  christos 	if (dns_rdatatype_ismeta(qtype)) {
   11879   1.1  christos 		switch (qtype) {
   11880   1.1  christos 		case dns_rdatatype_any:
   11881   1.1  christos 			break; /* Let the query logic handle it. */
   11882   1.1  christos 		case dns_rdatatype_ixfr:
   11883   1.1  christos 		case dns_rdatatype_axfr:
   11884   1.1  christos 			ns_xfr_start(client, rdataset->type);
   11885   1.1  christos 			return;
   11886   1.1  christos 		case dns_rdatatype_maila:
   11887   1.1  christos 		case dns_rdatatype_mailb:
   11888   1.1  christos 			query_error(client, DNS_R_NOTIMP, __LINE__);
   11889   1.1  christos 			return;
   11890   1.1  christos 		case dns_rdatatype_tkey:
   11891   1.9  christos 			result = dns_tkey_processquery(
   11892   1.9  christos 				client->message, client->sctx->tkeyctx,
   11893   1.9  christos 				client->view->dynamickeys);
   11894   1.9  christos 			if (result == ISC_R_SUCCESS) {
   11895   1.1  christos 				query_send(client);
   11896   1.9  christos 			} else {
   11897   1.1  christos 				query_error(client, result, __LINE__);
   11898   1.9  christos 			}
   11899   1.1  christos 			return;
   11900   1.1  christos 		default: /* TSIG, etc. */
   11901   1.1  christos 			query_error(client, DNS_R_FORMERR, __LINE__);
   11902   1.1  christos 			return;
   11903   1.1  christos 		}
   11904   1.1  christos 	}
   11905   1.1  christos 
   11906   1.1  christos 	/*
   11907   1.1  christos 	 * Turn on minimal response for (C)DNSKEY and (C)DS queries.
   11908   1.1  christos 	 */
   11909   1.1  christos 	if (qtype == dns_rdatatype_dnskey || qtype == dns_rdatatype_ds ||
   11910   1.1  christos 	    qtype == dns_rdatatype_cdnskey || qtype == dns_rdatatype_cds)
   11911   1.1  christos 	{
   11912   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   11913   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   11914  1.11  christos 	} else if (qtype == dns_rdatatype_ns) {
   11915  1.11  christos 		/*
   11916  1.11  christos 		 * Always turn on additional records for NS queries.
   11917  1.11  christos 		 */
   11918  1.11  christos 		client->query.attributes &= ~(NS_QUERYATTR_NOAUTHORITY |
   11919  1.11  christos 					      NS_QUERYATTR_NOADDITIONAL);
   11920   1.1  christos 	}
   11921   1.1  christos 
   11922   1.1  christos 	/*
   11923   1.1  christos 	 * Maybe turn on minimal responses for ANY queries.
   11924   1.1  christos 	 */
   11925   1.9  christos 	if (qtype == dns_rdatatype_any && client->view->minimal_any &&
   11926  1.16  christos 	    !TCP(client))
   11927  1.16  christos 	{
   11928   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   11929   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   11930   1.9  christos 	}
   11931   1.1  christos 
   11932   1.1  christos 	/*
   11933   1.1  christos 	 * Turn on minimal responses for EDNS/UDP bufsize 512 queries.
   11934   1.1  christos 	 */
   11935   1.1  christos 	if (client->ednsversion >= 0 && client->udpsize <= 512U && !TCP(client))
   11936   1.9  christos 	{
   11937   1.1  christos 		client->query.attributes |= (NS_QUERYATTR_NOAUTHORITY |
   11938   1.1  christos 					     NS_QUERYATTR_NOADDITIONAL);
   11939   1.9  christos 	}
   11940   1.1  christos 
   11941   1.1  christos 	/*
   11942   1.1  christos 	 * If the client has requested that DNSSEC checking be disabled,
   11943   1.1  christos 	 * allow lookups to return pending data and instruct the resolver
   11944   1.1  christos 	 * to return data before validation has completed.
   11945   1.1  christos 	 *
   11946   1.1  christos 	 * We don't need to set DNS_DBFIND_PENDINGOK when validation is
   11947   1.1  christos 	 * disabled as there will be no pending data.
   11948   1.1  christos 	 */
   11949   1.3  christos 	if ((message->flags & DNS_MESSAGEFLAG_CD) != 0 ||
   11950  1.16  christos 	    qtype == dns_rdatatype_rrsig)
   11951  1.16  christos 	{
   11952   1.1  christos 		client->query.dboptions |= DNS_DBFIND_PENDINGOK;
   11953   1.1  christos 		client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
   11954   1.9  christos 	} else if (!client->view->enablevalidation) {
   11955   1.1  christos 		client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
   11956   1.9  christos 	}
   11957   1.1  christos 
   11958   1.3  christos 	if (client->view->qminimization) {
   11959   1.3  christos 		client->query.fetchoptions |= DNS_FETCHOPT_QMINIMIZE |
   11960   1.9  christos 					      DNS_FETCHOPT_QMIN_SKIP_IP6A;
   11961   1.3  christos 		if (client->view->qmin_strict) {
   11962   1.3  christos 			client->query.fetchoptions |= DNS_FETCHOPT_QMIN_STRICT;
   11963   1.6  christos 		} else {
   11964   1.6  christos 			client->query.fetchoptions |= DNS_FETCHOPT_QMIN_USE_A;
   11965   1.3  christos 		}
   11966   1.3  christos 	}
   11967   1.3  christos 
   11968   1.1  christos 	/*
   11969   1.1  christos 	 * Allow glue NS records to be added to the authority section
   11970   1.1  christos 	 * if the answer is secure.
   11971   1.1  christos 	 */
   11972   1.3  christos 	if ((message->flags & DNS_MESSAGEFLAG_CD) != 0) {
   11973   1.1  christos 		client->query.attributes &= ~NS_QUERYATTR_SECURE;
   11974   1.3  christos 	}
   11975   1.1  christos 
   11976   1.1  christos 	/*
   11977   1.1  christos 	 * Set NS_CLIENTATTR_WANTAD if the client has set AD in the query.
   11978   1.1  christos 	 * This allows AD to be returned on queries without DO set.
   11979   1.1  christos 	 */
   11980   1.9  christos 	if ((message->flags & DNS_MESSAGEFLAG_AD) != 0) {
   11981   1.1  christos 		client->attributes |= NS_CLIENTATTR_WANTAD;
   11982   1.9  christos 	}
   11983   1.1  christos 
   11984   1.1  christos 	/*
   11985   1.1  christos 	 * This is an ordinary query.
   11986   1.1  christos 	 */
   11987   1.3  christos 	result = dns_message_reply(message, true);
   11988   1.1  christos 	if (result != ISC_R_SUCCESS) {
   11989   1.1  christos 		query_next(client, result);
   11990   1.1  christos 		return;
   11991   1.1  christos 	}
   11992   1.1  christos 
   11993   1.1  christos 	/*
   11994   1.1  christos 	 * Assume authoritative response until it is known to be
   11995   1.1  christos 	 * otherwise.
   11996   1.1  christos 	 *
   11997   1.1  christos 	 * If "-T noaa" has been set on the command line don't set
   11998   1.1  christos 	 * AA on authoritative answers.
   11999   1.1  christos 	 */
   12000   1.9  christos 	if ((client->sctx->options & NS_SERVER_NOAA) == 0) {
   12001   1.1  christos 		message->flags |= DNS_MESSAGEFLAG_AA;
   12002   1.9  christos 	}
   12003   1.1  christos 
   12004   1.1  christos 	/*
   12005   1.1  christos 	 * Set AD.  We must clear it if we add non-validated data to a
   12006   1.1  christos 	 * response.
   12007   1.1  christos 	 */
   12008   1.9  christos 	if (WANTDNSSEC(client) || WANTAD(client)) {
   12009   1.1  christos 		message->flags |= DNS_MESSAGEFLAG_AD;
   12010   1.9  christos 	}
   12011   1.1  christos 
   12012   1.9  christos 	(void)query_setup(client, qtype);
   12013   1.1  christos }
   12014