1999-07-24 01:17:44 +00:00
|
|
|
/*
|
2000-02-03 22:29:57 +00:00
|
|
|
* Copyright (C) 1999, 2000 Internet Software Consortium.
|
1999-07-24 01:17:44 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
2000-07-27 09:55:03 +00:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
|
|
|
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
|
|
|
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
|
|
|
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
1999-07-24 01:17:44 +00:00
|
|
|
*/
|
|
|
|
|
2000-07-31 21:07:07 +00:00
|
|
|
/* $Id: query.c,v 1.119 2000/07/31 21:06:55 explorer Exp $ */
|
2000-06-22 22:00:42 +00:00
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <isc/mem.h>
|
1999-12-16 22:24:22 +00:00
|
|
|
#include <isc/util.h>
|
1999-07-24 01:17:44 +00:00
|
|
|
|
1999-07-28 02:20:36 +00:00
|
|
|
#include <dns/db.h>
|
1999-07-24 01:17:44 +00:00
|
|
|
#include <dns/events.h>
|
1999-07-28 02:20:36 +00:00
|
|
|
#include <dns/message.h>
|
|
|
|
#include <dns/rdata.h>
|
1999-10-20 23:22:04 +00:00
|
|
|
#include <dns/rdatalist.h>
|
1999-07-28 02:20:36 +00:00
|
|
|
#include <dns/rdataset.h>
|
|
|
|
#include <dns/rdatasetiter.h>
|
2000-05-02 03:54:17 +00:00
|
|
|
#include <dns/rdatatype.h>
|
1999-10-07 19:44:22 +00:00
|
|
|
#include <dns/resolver.h>
|
2000-05-02 03:54:17 +00:00
|
|
|
#include <dns/result.h>
|
1999-10-26 15:41:48 +00:00
|
|
|
#include <dns/tkey.h>
|
2000-05-02 03:54:17 +00:00
|
|
|
#include <dns/view.h>
|
1999-10-14 01:37:00 +00:00
|
|
|
#include <dns/zone.h>
|
|
|
|
#include <dns/zt.h>
|
1999-07-24 01:17:44 +00:00
|
|
|
|
|
|
|
#include <named/client.h>
|
1999-12-16 23:11:07 +00:00
|
|
|
#include <named/log.h>
|
|
|
|
#include <named/server.h>
|
1999-08-20 06:04:28 +00:00
|
|
|
#include <named/xfrout.h>
|
1999-12-16 23:11:07 +00:00
|
|
|
|
1999-08-05 01:51:32 +00:00
|
|
|
#define PARTIALANSWER(c) (((c)->query.attributes & \
|
|
|
|
NS_QUERYATTR_PARTIALANSWER) != 0)
|
1999-09-13 18:26:37 +00:00
|
|
|
#define USECACHE(c) (((c)->query.attributes & \
|
|
|
|
NS_QUERYATTR_CACHEOK) != 0)
|
|
|
|
#define RECURSIONOK(c) (((c)->query.attributes & \
|
|
|
|
NS_QUERYATTR_RECURSIONOK) != 0)
|
1999-10-07 19:44:22 +00:00
|
|
|
#define RECURSING(c) (((c)->query.attributes & \
|
|
|
|
NS_QUERYATTR_RECURSING) != 0)
|
1999-10-25 21:21:55 +00:00
|
|
|
#define CACHEGLUEOK(c) (((c)->query.attributes & \
|
|
|
|
NS_QUERYATTR_CACHEGLUEOK) != 0)
|
1999-08-05 01:51:32 +00:00
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
#if 0
|
|
|
|
#define CTRACE(m) isc_log_write(ns_g_lctx, \
|
|
|
|
NS_LOGCATEGORY_CLIENT, \
|
|
|
|
NS_LOGMODULE_QUERY, \
|
|
|
|
ISC_LOG_DEBUG(3), \
|
|
|
|
"client %p: %s", client, (m))
|
|
|
|
#define QTRACE(m) isc_log_write(ns_g_lctx, \
|
|
|
|
NS_LOGCATEGORY_GENERAL, \
|
|
|
|
NS_LOGMODULE_QUERY, \
|
|
|
|
ISC_LOG_DEBUG(3), \
|
|
|
|
"query %p: %s", query, (m))
|
|
|
|
#else
|
|
|
|
#define CTRACE(m) ((void)m)
|
|
|
|
#define QTRACE(m) ((void)m)
|
|
|
|
#endif
|
|
|
|
|
2000-06-15 04:42:01 +00:00
|
|
|
#define DNS_GETDB_NOEXACT 0x01U
|
|
|
|
#define DNS_GETDB_NOLOG 0x02U
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
|
1999-09-07 23:09:34 +00:00
|
|
|
static isc_result_t
|
|
|
|
query_simplefind(void *arg, dns_name_t *name, dns_rdatatype_t type,
|
1999-11-22 19:52:39 +00:00
|
|
|
isc_stdtime_t now,
|
1999-09-07 23:09:34 +00:00
|
|
|
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
query_adda6rrset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset,
|
|
|
|
dns_rdataset_t *sigrdataset);
|
|
|
|
|
1999-10-07 19:44:22 +00:00
|
|
|
static void
|
|
|
|
query_find(ns_client_t *client, dns_fetchevent_t *event);
|
|
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
query_maybeputqname(ns_client_t *client) {
|
|
|
|
if (client->query.restarts > 0) {
|
|
|
|
/*
|
|
|
|
* client->query.qname was dynamically allocated.
|
|
|
|
*/
|
|
|
|
dns_message_puttempname(client->message,
|
|
|
|
&client->query.qname);
|
|
|
|
client->query.qname = NULL;
|
1999-10-17 19:27:04 +00:00
|
|
|
}
|
1999-10-07 19:44:22 +00:00
|
|
|
}
|
1999-09-07 23:09:34 +00:00
|
|
|
|
1999-07-29 00:55:35 +00:00
|
|
|
static inline void
|
1999-08-03 01:21:00 +00:00
|
|
|
query_reset(ns_client_t *client, isc_boolean_t everything) {
|
1999-09-02 02:10:44 +00:00
|
|
|
isc_buffer_t *dbuf, *dbuf_next;
|
1999-08-18 04:23:39 +00:00
|
|
|
ns_dbversion_t *dbversion, *dbversion_next;
|
|
|
|
unsigned int i;
|
|
|
|
|
1999-09-01 18:16:43 +00:00
|
|
|
/*
|
|
|
|
* Reset the query state of a client to its default state.
|
|
|
|
*/
|
1999-08-18 04:23:39 +00:00
|
|
|
|
1999-10-07 19:44:22 +00:00
|
|
|
/*
|
1999-10-20 01:58:48 +00:00
|
|
|
* Cancel the fetch if it's running.
|
1999-10-07 19:44:22 +00:00
|
|
|
*/
|
|
|
|
if (client->query.fetch != NULL) {
|
2000-01-21 02:51:09 +00:00
|
|
|
dns_resolver_cancelfetch(client->query.fetch);
|
|
|
|
|
1999-10-20 01:58:48 +00:00
|
|
|
client->query.fetch = NULL;
|
1999-10-07 19:44:22 +00:00
|
|
|
}
|
|
|
|
|
1999-08-18 04:23:39 +00:00
|
|
|
/*
|
|
|
|
* Cleanup any active versions.
|
|
|
|
*/
|
|
|
|
for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
|
|
|
|
dbversion != NULL;
|
|
|
|
dbversion = dbversion_next) {
|
|
|
|
dbversion_next = ISC_LIST_NEXT(dbversion, link);
|
|
|
|
dns_db_closeversion(dbversion->db, &dbversion->version,
|
|
|
|
ISC_FALSE);
|
|
|
|
dns_db_detach(&dbversion->db);
|
|
|
|
ISC_LIST_APPEND(client->query.freeversions, dbversion, link);
|
|
|
|
}
|
|
|
|
ISC_LIST_INIT(client->query.activeversions);
|
|
|
|
|
2000-07-31 21:07:07 +00:00
|
|
|
if (client->query.authdb != NULL)
|
|
|
|
dns_db_detach(&client->query.authdb);
|
|
|
|
|
1999-08-18 04:23:39 +00:00
|
|
|
/*
|
|
|
|
* Clean up free versions.
|
|
|
|
*/
|
|
|
|
for (dbversion = ISC_LIST_HEAD(client->query.freeversions), i = 0;
|
|
|
|
dbversion != NULL;
|
|
|
|
dbversion = dbversion_next, i++) {
|
|
|
|
dbversion_next = ISC_LIST_NEXT(dbversion, link);
|
|
|
|
/*
|
|
|
|
* If we're not freeing everything, we keep the first three
|
|
|
|
* dbversions structures around.
|
|
|
|
*/
|
|
|
|
if (i > 3 || everything) {
|
|
|
|
ISC_LIST_UNLINK(client->query.freeversions, dbversion,
|
|
|
|
link);
|
|
|
|
isc_mem_put(client->mctx, dbversion,
|
|
|
|
sizeof *dbversion);
|
|
|
|
}
|
|
|
|
}
|
1999-07-29 00:55:35 +00:00
|
|
|
|
|
|
|
for (dbuf = ISC_LIST_HEAD(client->query.namebufs);
|
|
|
|
dbuf != NULL;
|
|
|
|
dbuf = dbuf_next) {
|
|
|
|
dbuf_next = ISC_LIST_NEXT(dbuf, link);
|
|
|
|
if (dbuf_next != NULL || everything) {
|
|
|
|
ISC_LIST_UNLINK(client->query.namebufs, dbuf, link);
|
1999-09-02 02:10:44 +00:00
|
|
|
isc_buffer_free(&dbuf);
|
1999-07-29 00:55:35 +00:00
|
|
|
}
|
|
|
|
}
|
1999-09-07 23:09:34 +00:00
|
|
|
|
1999-10-07 19:44:22 +00:00
|
|
|
query_maybeputqname(client);
|
|
|
|
|
2000-07-04 01:33:47 +00:00
|
|
|
client->query.attributes = (NS_QUERYATTR_RECURSIONOK |
|
1999-08-03 01:21:00 +00:00
|
|
|
NS_QUERYATTR_CACHEOK);
|
1999-09-17 21:59:55 +00:00
|
|
|
client->query.restarts = 0;
|
1999-08-12 07:54:08 +00:00
|
|
|
client->query.origqname = NULL;
|
1999-10-17 19:27:04 +00:00
|
|
|
client->query.qname = NULL;
|
1999-10-11 19:12:43 +00:00
|
|
|
client->query.qrdataset = NULL;
|
1999-08-03 01:21:00 +00:00
|
|
|
client->query.dboptions = 0;
|
2000-07-25 21:37:05 +00:00
|
|
|
client->query.fetchoptions = 0;
|
1999-09-08 01:21:01 +00:00
|
|
|
client->query.gluedb = NULL;
|
2000-07-31 21:07:07 +00:00
|
|
|
client->query.authdb = NULL;
|
1999-07-29 00:55:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-02-10 22:16:56 +00:00
|
|
|
query_next(ns_client_t *client) {
|
1999-08-03 01:21:00 +00:00
|
|
|
query_reset(client, ISC_FALSE);
|
1999-07-29 00:55:35 +00:00
|
|
|
}
|
|
|
|
|
1999-08-03 01:21:00 +00:00
|
|
|
void
|
|
|
|
ns_query_free(ns_client_t *client) {
|
|
|
|
query_reset(client, ISC_TRUE);
|
1999-07-29 00:55:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline isc_result_t
|
|
|
|
query_newnamebuf(ns_client_t *client) {
|
1999-09-02 02:10:44 +00:00
|
|
|
isc_buffer_t *dbuf;
|
1999-07-29 00:55:35 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_newnamebuf");
|
1999-09-01 18:16:43 +00:00
|
|
|
/*
|
|
|
|
* Allocate a name buffer.
|
|
|
|
*/
|
|
|
|
|
1999-07-29 00:55:35 +00:00
|
|
|
dbuf = NULL;
|
103. [func] libisc buffer API changes for <isc/buffer.h>:
Added:
isc_buffer_base(b) (pointer)
isc_buffer_current(b) (pointer)
isc_buffer_active(b) (pointer)
isc_buffer_used(b) (pointer)
isc_buffer_length(b) (int)
isc_buffer_usedlength(b) (int)
isc_buffer_consumedlength(b) (int)
isc_buffer_remaininglength(b) (int)
isc_buffer_activelength(b) (int)
isc_buffer_availablelength(b) (int)
Removed:
ISC_BUFFER_USEDCOUNT(b)
ISC_BUFFER_AVAILABLECOUNT(b)
isc_buffer_type(b)
Changed names:
isc_buffer_used(b, r) ->
isc_buffer_usedregion(b, r)
isc_buffer_available(b, r) ->
isc_buffer_available_region(b, r)
isc_buffer_consumed(b, r) ->
isc_buffer_consumedregion(b, r)
isc_buffer_active(b, r) ->
isc_buffer_activeregion(b, r)
isc_buffer_remaining(b, r) ->
isc_buffer_remainingregion(b, r)
Buffer types were removed, so the ISC_BUFFERTYPE_*
macros are no more, and the type argument to
isc_buffer_init and isc_buffer_allocate were removed.
isc_buffer_putstr is now void (instead of isc_result_t)
and requires that the caller ensure that there
is enough available buffer space for the string.
2000-04-27 00:03:12 +00:00
|
|
|
result = isc_buffer_allocate(client->mctx, &dbuf, 1024);
|
1999-12-24 00:43:46 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
CTRACE("query_newnamebuf: isc_buffer_allocate failed: done");
|
1999-07-29 00:55:35 +00:00
|
|
|
return (result);
|
1999-12-24 00:43:46 +00:00
|
|
|
}
|
1999-07-29 00:55:35 +00:00
|
|
|
ISC_LIST_APPEND(client->query.namebufs, dbuf, link);
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_newnamebuf: done");
|
1999-07-29 00:55:35 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-09-02 02:10:44 +00:00
|
|
|
static inline isc_buffer_t *
|
1999-07-29 00:55:35 +00:00
|
|
|
query_getnamebuf(ns_client_t *client) {
|
1999-09-02 02:10:44 +00:00
|
|
|
isc_buffer_t *dbuf;
|
1999-07-29 00:55:35 +00:00
|
|
|
isc_result_t result;
|
|
|
|
isc_region_t r;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_getnamebuf");
|
1999-09-01 18:16:43 +00:00
|
|
|
/*
|
|
|
|
* Return a name buffer with space for a maximal name, allocating
|
|
|
|
* a new one if necessary.
|
|
|
|
*/
|
|
|
|
|
1999-07-29 00:55:35 +00:00
|
|
|
if (ISC_LIST_EMPTY(client->query.namebufs)) {
|
|
|
|
result = query_newnamebuf(client);
|
1999-12-24 00:43:46 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
CTRACE("query_getnamebuf: query_newnamebuf failed: done");
|
1999-07-29 00:55:35 +00:00
|
|
|
return (NULL);
|
1999-12-24 00:43:46 +00:00
|
|
|
}
|
1999-07-29 00:55:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
dbuf = ISC_LIST_TAIL(client->query.namebufs);
|
|
|
|
INSIST(dbuf != NULL);
|
103. [func] libisc buffer API changes for <isc/buffer.h>:
Added:
isc_buffer_base(b) (pointer)
isc_buffer_current(b) (pointer)
isc_buffer_active(b) (pointer)
isc_buffer_used(b) (pointer)
isc_buffer_length(b) (int)
isc_buffer_usedlength(b) (int)
isc_buffer_consumedlength(b) (int)
isc_buffer_remaininglength(b) (int)
isc_buffer_activelength(b) (int)
isc_buffer_availablelength(b) (int)
Removed:
ISC_BUFFER_USEDCOUNT(b)
ISC_BUFFER_AVAILABLECOUNT(b)
isc_buffer_type(b)
Changed names:
isc_buffer_used(b, r) ->
isc_buffer_usedregion(b, r)
isc_buffer_available(b, r) ->
isc_buffer_available_region(b, r)
isc_buffer_consumed(b, r) ->
isc_buffer_consumedregion(b, r)
isc_buffer_active(b, r) ->
isc_buffer_activeregion(b, r)
isc_buffer_remaining(b, r) ->
isc_buffer_remainingregion(b, r)
Buffer types were removed, so the ISC_BUFFERTYPE_*
macros are no more, and the type argument to
isc_buffer_init and isc_buffer_allocate were removed.
isc_buffer_putstr is now void (instead of isc_result_t)
and requires that the caller ensure that there
is enough available buffer space for the string.
2000-04-27 00:03:12 +00:00
|
|
|
isc_buffer_availableregion(dbuf, &r);
|
1999-07-29 00:55:35 +00:00
|
|
|
if (r.length < 255) {
|
|
|
|
result = query_newnamebuf(client);
|
1999-12-24 00:43:46 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
CTRACE("query_getnamebuf: query_newnamebuf failed: done");
|
1999-07-29 00:55:35 +00:00
|
|
|
return (NULL);
|
1999-12-24 00:43:46 +00:00
|
|
|
|
|
|
|
}
|
1999-07-29 00:55:35 +00:00
|
|
|
dbuf = ISC_LIST_TAIL(client->query.namebufs);
|
103. [func] libisc buffer API changes for <isc/buffer.h>:
Added:
isc_buffer_base(b) (pointer)
isc_buffer_current(b) (pointer)
isc_buffer_active(b) (pointer)
isc_buffer_used(b) (pointer)
isc_buffer_length(b) (int)
isc_buffer_usedlength(b) (int)
isc_buffer_consumedlength(b) (int)
isc_buffer_remaininglength(b) (int)
isc_buffer_activelength(b) (int)
isc_buffer_availablelength(b) (int)
Removed:
ISC_BUFFER_USEDCOUNT(b)
ISC_BUFFER_AVAILABLECOUNT(b)
isc_buffer_type(b)
Changed names:
isc_buffer_used(b, r) ->
isc_buffer_usedregion(b, r)
isc_buffer_available(b, r) ->
isc_buffer_available_region(b, r)
isc_buffer_consumed(b, r) ->
isc_buffer_consumedregion(b, r)
isc_buffer_active(b, r) ->
isc_buffer_activeregion(b, r)
isc_buffer_remaining(b, r) ->
isc_buffer_remainingregion(b, r)
Buffer types were removed, so the ISC_BUFFERTYPE_*
macros are no more, and the type argument to
isc_buffer_init and isc_buffer_allocate were removed.
isc_buffer_putstr is now void (instead of isc_result_t)
and requires that the caller ensure that there
is enough available buffer space for the string.
2000-04-27 00:03:12 +00:00
|
|
|
isc_buffer_availableregion(dbuf, &r);
|
1999-07-29 00:55:35 +00:00
|
|
|
INSIST(r.length >= 255);
|
|
|
|
}
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_getnamebuf: done");
|
1999-07-29 00:55:35 +00:00
|
|
|
return (dbuf);
|
|
|
|
}
|
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
static inline void
|
1999-09-02 02:10:44 +00:00
|
|
|
query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) {
|
1999-08-12 07:54:08 +00:00
|
|
|
isc_region_t r;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_keepname");
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* 'name' is using space in 'dbuf', but 'dbuf' has not yet been
|
|
|
|
* adjusted to take account of that. We do the adjustment.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0);
|
|
|
|
|
|
|
|
dns_name_toregion(name, &r);
|
1999-09-02 02:10:44 +00:00
|
|
|
isc_buffer_add(dbuf, r.length);
|
1999-08-12 07:54:08 +00:00
|
|
|
dns_name_setbuffer(name, NULL);
|
|
|
|
client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
query_releasename(ns_client_t *client, dns_name_t **namep) {
|
|
|
|
dns_name_t *name = *namep;
|
|
|
|
|
1999-09-01 18:16:43 +00:00
|
|
|
/*
|
|
|
|
* 'name' is no longer needed. Return it to our pool of temporary
|
|
|
|
* names. If it is using a name buffer, relinquish its exclusive
|
|
|
|
* rights on the buffer.
|
|
|
|
*/
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_releasename");
|
1999-08-12 07:54:08 +00:00
|
|
|
if (dns_name_hasbuffer(name)) {
|
|
|
|
INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED)
|
|
|
|
!= 0);
|
|
|
|
client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
|
|
|
|
}
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_message_puttempname(client->message, namep);
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_releasename: done");
|
1999-08-12 07:54:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline dns_name_t *
|
1999-09-02 02:10:44 +00:00
|
|
|
query_newname(ns_client_t *client, isc_buffer_t *dbuf,
|
1999-08-12 07:54:08 +00:00
|
|
|
isc_buffer_t *nbuf)
|
|
|
|
{
|
|
|
|
dns_name_t *name;
|
|
|
|
isc_region_t r;
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_newname");
|
1999-09-13 18:26:37 +00:00
|
|
|
name = NULL;
|
|
|
|
result = dns_message_gettempname(client->message, &name);
|
1999-12-24 00:43:46 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
CTRACE("query_newname: dns_message_gettempname failed: done");
|
1999-09-13 18:26:37 +00:00
|
|
|
return (NULL);
|
1999-12-24 00:43:46 +00:00
|
|
|
}
|
103. [func] libisc buffer API changes for <isc/buffer.h>:
Added:
isc_buffer_base(b) (pointer)
isc_buffer_current(b) (pointer)
isc_buffer_active(b) (pointer)
isc_buffer_used(b) (pointer)
isc_buffer_length(b) (int)
isc_buffer_usedlength(b) (int)
isc_buffer_consumedlength(b) (int)
isc_buffer_remaininglength(b) (int)
isc_buffer_activelength(b) (int)
isc_buffer_availablelength(b) (int)
Removed:
ISC_BUFFER_USEDCOUNT(b)
ISC_BUFFER_AVAILABLECOUNT(b)
isc_buffer_type(b)
Changed names:
isc_buffer_used(b, r) ->
isc_buffer_usedregion(b, r)
isc_buffer_available(b, r) ->
isc_buffer_available_region(b, r)
isc_buffer_consumed(b, r) ->
isc_buffer_consumedregion(b, r)
isc_buffer_active(b, r) ->
isc_buffer_activeregion(b, r)
isc_buffer_remaining(b, r) ->
isc_buffer_remainingregion(b, r)
Buffer types were removed, so the ISC_BUFFERTYPE_*
macros are no more, and the type argument to
isc_buffer_init and isc_buffer_allocate were removed.
isc_buffer_putstr is now void (instead of isc_result_t)
and requires that the caller ensure that there
is enough available buffer space for the string.
2000-04-27 00:03:12 +00:00
|
|
|
isc_buffer_availableregion(dbuf, &r);
|
|
|
|
isc_buffer_init(nbuf, r.base, r.length);
|
1999-08-12 07:54:08 +00:00
|
|
|
dns_name_init(name, NULL);
|
|
|
|
dns_name_setbuffer(name, nbuf);
|
|
|
|
client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_newname: done");
|
1999-08-12 07:54:08 +00:00
|
|
|
return (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline dns_rdataset_t *
|
|
|
|
query_newrdataset(ns_client_t *client) {
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
isc_result_t result;
|
1999-09-01 18:16:43 +00:00
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_newrdataset");
|
1999-09-13 18:26:37 +00:00
|
|
|
rdataset = NULL;
|
|
|
|
result = dns_message_gettemprdataset(client->message, &rdataset);
|
1999-12-24 00:43:46 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-05-24 05:10:00 +00:00
|
|
|
CTRACE("query_newrdataset: "
|
|
|
|
"dns_message_gettemprdataset failed: done");
|
1999-09-13 18:26:37 +00:00
|
|
|
return (NULL);
|
1999-12-24 00:43:46 +00:00
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_newrdataset: done");
|
1999-08-12 07:54:08 +00:00
|
|
|
return (rdataset);
|
|
|
|
}
|
|
|
|
|
1999-09-13 18:26:37 +00:00
|
|
|
static inline void
|
|
|
|
query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
|
|
|
|
dns_rdataset_t *rdataset = *rdatasetp;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_putrdataset");
|
1999-09-13 18:26:37 +00:00
|
|
|
if (rdataset != NULL) {
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
dns_message_puttemprdataset(client->message, rdatasetp);
|
|
|
|
}
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_putrdataset: done");
|
1999-09-13 18:26:37 +00:00
|
|
|
}
|
|
|
|
|
2000-07-05 23:10:06 +00:00
|
|
|
|
1999-08-18 04:23:39 +00:00
|
|
|
static inline isc_result_t
|
|
|
|
query_newdbversion(ns_client_t *client, unsigned int n) {
|
|
|
|
unsigned int i;
|
|
|
|
ns_dbversion_t *dbversion;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
dbversion = isc_mem_get(client->mctx, sizeof *dbversion);
|
|
|
|
if (dbversion != NULL) {
|
|
|
|
dbversion->db = NULL;
|
|
|
|
dbversion->version = NULL;
|
|
|
|
ISC_LIST_APPEND(client->query.freeversions, dbversion,
|
|
|
|
link);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We only return ISC_R_NOMEMORY if we couldn't
|
|
|
|
* allocate anything.
|
|
|
|
*/
|
|
|
|
if (i == 0)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
else
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline ns_dbversion_t *
|
|
|
|
query_getdbversion(ns_client_t *client) {
|
|
|
|
isc_result_t result;
|
|
|
|
ns_dbversion_t *dbversion;
|
|
|
|
|
|
|
|
if (ISC_LIST_EMPTY(client->query.freeversions)) {
|
|
|
|
result = query_newdbversion(client, 1);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
dbversion = ISC_LIST_HEAD(client->query.freeversions);
|
|
|
|
INSIST(dbversion != NULL);
|
|
|
|
ISC_LIST_UNLINK(client->query.freeversions, dbversion, link);
|
|
|
|
|
|
|
|
return (dbversion);
|
|
|
|
}
|
|
|
|
|
1999-07-29 00:55:35 +00:00
|
|
|
isc_result_t
|
|
|
|
ns_query_init(ns_client_t *client) {
|
1999-08-18 04:23:39 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
1999-07-29 00:55:35 +00:00
|
|
|
ISC_LIST_INIT(client->query.namebufs);
|
1999-08-18 04:23:39 +00:00
|
|
|
ISC_LIST_INIT(client->query.activeversions);
|
|
|
|
ISC_LIST_INIT(client->query.freeversions);
|
1999-10-07 19:44:22 +00:00
|
|
|
client->query.restarts = 0;
|
|
|
|
client->query.qname = NULL;
|
|
|
|
client->query.fetch = NULL;
|
2000-07-31 21:07:07 +00:00
|
|
|
client->query.authdb = NULL;
|
1999-08-03 01:21:00 +00:00
|
|
|
query_reset(client, ISC_FALSE);
|
1999-08-18 04:23:39 +00:00
|
|
|
result = query_newdbversion(client, 3);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
1999-09-07 23:09:34 +00:00
|
|
|
dns_a6_init(&client->query.a6ctx, query_simplefind, query_adda6rrset,
|
|
|
|
NULL, NULL, client);
|
1999-07-29 00:55:35 +00:00
|
|
|
return (query_newnamebuf(client));
|
|
|
|
}
|
|
|
|
|
2000-04-25 21:58:17 +00:00
|
|
|
static inline ns_dbversion_t *
|
|
|
|
query_findversion(ns_client_t *client, dns_db_t *db,
|
|
|
|
isc_boolean_t *newzonep)
|
|
|
|
{
|
1999-08-18 04:23:39 +00:00
|
|
|
ns_dbversion_t *dbversion;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We may already have done a query related to this
|
|
|
|
* database. If so, we must be sure to make subsequent
|
|
|
|
* queries from the same version.
|
|
|
|
*/
|
|
|
|
for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
|
|
|
|
dbversion != NULL;
|
|
|
|
dbversion = ISC_LIST_NEXT(dbversion, link)) {
|
|
|
|
if (dbversion->db == db)
|
|
|
|
break;
|
2000-07-31 21:07:07 +00:00
|
|
|
}
|
|
|
|
|
1999-08-18 04:23:39 +00:00
|
|
|
if (dbversion == NULL) {
|
|
|
|
/*
|
|
|
|
* This is a new zone for this query. Add it to
|
|
|
|
* the active list.
|
|
|
|
*/
|
|
|
|
dbversion = query_getdbversion(client);
|
|
|
|
if (dbversion == NULL)
|
|
|
|
return (NULL);
|
|
|
|
dns_db_attach(db, &dbversion->db);
|
|
|
|
dns_db_currentversion(db, &dbversion->version);
|
2000-04-25 21:58:17 +00:00
|
|
|
dbversion->queryok = ISC_FALSE;
|
1999-08-18 04:23:39 +00:00
|
|
|
ISC_LIST_APPEND(client->query.activeversions,
|
|
|
|
dbversion, link);
|
2000-04-25 21:58:17 +00:00
|
|
|
*newzonep = ISC_TRUE;
|
|
|
|
} else
|
|
|
|
*newzonep = ISC_FALSE;
|
1999-08-18 04:23:39 +00:00
|
|
|
|
2000-04-25 21:58:17 +00:00
|
|
|
return (dbversion);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline isc_result_t
|
2000-07-05 23:10:06 +00:00
|
|
|
query_getzonedb(ns_client_t *client, dns_name_t *name, unsigned int options,
|
|
|
|
dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp)
|
2000-04-25 21:58:17 +00:00
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
isc_boolean_t check_acl, new_zone;
|
|
|
|
dns_acl_t *queryacl;
|
|
|
|
ns_dbversion_t *dbversion;
|
2000-06-15 04:42:01 +00:00
|
|
|
unsigned int ztoptions;
|
2000-04-25 21:58:17 +00:00
|
|
|
|
|
|
|
/*
|
2000-07-05 23:10:06 +00:00
|
|
|
* Find a zone database to answer the query.
|
2000-04-25 21:58:17 +00:00
|
|
|
*/
|
2000-07-04 01:33:47 +00:00
|
|
|
ztoptions = ((options & DNS_GETDB_NOEXACT) != 0) ?
|
|
|
|
DNS_ZTFIND_NOEXACT : 0;
|
2000-04-25 21:58:17 +00:00
|
|
|
|
2000-06-15 04:42:01 +00:00
|
|
|
result = dns_zt_find(client->view->zonetable, name, ztoptions, NULL,
|
2000-04-25 21:58:17 +00:00
|
|
|
zonep);
|
2000-07-05 23:10:06 +00:00
|
|
|
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH)
|
2000-04-25 21:58:17 +00:00
|
|
|
result = dns_zone_getdb(*zonep, dbp);
|
|
|
|
|
2000-07-05 23:10:06 +00:00
|
|
|
if (result != ISC_R_SUCCESS)
|
2000-04-25 21:58:17 +00:00
|
|
|
return (result);
|
|
|
|
|
2000-07-31 21:07:07 +00:00
|
|
|
/*
|
|
|
|
* If this is the first time we are called (that is, looking up
|
|
|
|
* the actual name in the query section) remember this database.
|
|
|
|
*
|
|
|
|
* If authdb is non-NULL, we have been here before, and the
|
|
|
|
* found database is always returned.
|
|
|
|
*
|
|
|
|
* This limits our searching to the zone where the first name
|
|
|
|
* (the query target) is found. This prevents following CNAMES
|
|
|
|
* or DNAMES into other zones and prevents returning additional
|
|
|
|
* data from other zones.
|
|
|
|
*/
|
|
|
|
if (!client->view->additionalfromauth) {
|
|
|
|
if (client->query.authdb != NULL) {
|
|
|
|
if (*dbp != client->query.authdb) {
|
|
|
|
dns_zone_detach(zonep);
|
|
|
|
dns_db_detach(dbp);
|
|
|
|
return (DNS_R_REFUSED);
|
|
|
|
}
|
|
|
|
dns_db_attach(client->query.authdb, dbp);
|
|
|
|
} else {
|
|
|
|
dns_db_attach(*dbp, &client->query.authdb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-25 21:58:17 +00:00
|
|
|
/*
|
2000-07-05 23:10:06 +00:00
|
|
|
* If the zone has an ACL, we'll check it, otherwise
|
2000-04-25 21:58:17 +00:00
|
|
|
* we use the view's "allow-query" ACL. Each ACL is only checked
|
|
|
|
* once per query.
|
|
|
|
*
|
2000-07-05 23:10:06 +00:00
|
|
|
* Also, get the database version to use.
|
2000-04-25 21:58:17 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
check_acl = ISC_TRUE; /* Keep compiler happy. */
|
|
|
|
queryacl = NULL;
|
2000-07-05 23:10:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the current version of this database.
|
|
|
|
*/
|
|
|
|
dbversion = query_findversion(client, *dbp, &new_zone);
|
|
|
|
if (dbversion == NULL)
|
|
|
|
return (DNS_R_SERVFAIL);
|
|
|
|
*versionp = dbversion->version;
|
|
|
|
if (new_zone) {
|
|
|
|
queryacl = dns_zone_getqueryacl(*zonep);
|
|
|
|
check_acl = ISC_TRUE;
|
|
|
|
} else if (!dbversion->queryok) {
|
|
|
|
return (DNS_R_REFUSED);
|
|
|
|
} else {
|
|
|
|
check_acl = ISC_FALSE;
|
|
|
|
}
|
2000-04-25 21:58:17 +00:00
|
|
|
|
|
|
|
if (queryacl == NULL) {
|
|
|
|
queryacl = client->view->queryacl;
|
|
|
|
if ((client->query.attributes &
|
|
|
|
NS_QUERYATTR_QUERYOKVALID) != 0) {
|
|
|
|
/*
|
|
|
|
* We've evaluated the view's queryacl already. If
|
|
|
|
* NS_QUERYATTR_QUERYOK is set, then the client is
|
|
|
|
* allowed to make queries, otherwise the query should
|
|
|
|
* be refused.
|
|
|
|
*/
|
|
|
|
check_acl = ISC_FALSE;
|
|
|
|
if ((client->query.attributes &
|
|
|
|
NS_QUERYATTR_QUERYOK) == 0)
|
|
|
|
return (DNS_R_REFUSED);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We haven't evaluated the view's queryacl yet.
|
|
|
|
*/
|
|
|
|
check_acl = ISC_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_acl) {
|
2000-06-15 04:42:01 +00:00
|
|
|
isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
|
2000-04-25 21:58:17 +00:00
|
|
|
result = ns_client_checkacl(client, "query", queryacl,
|
2000-06-15 04:42:01 +00:00
|
|
|
ISC_TRUE, log);
|
2000-04-25 21:58:17 +00:00
|
|
|
if (queryacl == client->view->queryacl) {
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* We were allowed by the default
|
|
|
|
* "allow-query" ACL. Remember this so we
|
|
|
|
* don't have to check again.
|
|
|
|
*/
|
|
|
|
client->query.attributes |=
|
|
|
|
NS_QUERYATTR_QUERYOK;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We've now evaluated the view's query ACL, and
|
|
|
|
* the NS_QUERYATTR_QUERYOK attribute is now valid.
|
|
|
|
*/
|
|
|
|
client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
|
2000-07-31 21:07:07 +00:00
|
|
|
}
|
2000-04-25 21:58:17 +00:00
|
|
|
} else
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
2000-05-11 20:10:34 +00:00
|
|
|
/*
|
|
|
|
* Remember the result of the ACL check so we
|
|
|
|
* don't have to check again.
|
|
|
|
*/
|
2000-07-05 23:10:06 +00:00
|
|
|
if (result == ISC_R_SUCCESS)
|
2000-05-11 20:10:34 +00:00
|
|
|
dbversion->queryok = ISC_TRUE;
|
2000-07-31 21:07:07 +00:00
|
|
|
|
2000-04-25 21:58:17 +00:00
|
|
|
return (result);
|
1999-08-18 04:23:39 +00:00
|
|
|
}
|
|
|
|
|
2000-07-05 23:10:06 +00:00
|
|
|
static inline isc_result_t
|
|
|
|
query_getcachedb(ns_client_t *client, dns_db_t **dbp, unsigned int options)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
isc_boolean_t check_acl;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find a cache database to answer the query.
|
|
|
|
* This may fail with ISC_R_REFUSED if the client
|
|
|
|
* is not allowed to use the cache.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!USECACHE(client))
|
|
|
|
return (DNS_R_REFUSED);
|
|
|
|
dns_db_attach(client->view->cachedb, dbp);
|
|
|
|
|
|
|
|
if ((client->query.attributes &
|
|
|
|
NS_QUERYATTR_QUERYOKVALID) != 0) {
|
|
|
|
/*
|
|
|
|
* We've evaluated the view's queryacl already. If
|
|
|
|
* NS_QUERYATTR_QUERYOK is set, then the client is
|
|
|
|
* allowed to make queries, otherwise the query should
|
|
|
|
* be refused.
|
|
|
|
*/
|
|
|
|
check_acl = ISC_FALSE;
|
|
|
|
if ((client->query.attributes &
|
|
|
|
NS_QUERYATTR_QUERYOK) == 0)
|
|
|
|
return (DNS_R_REFUSED);
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We haven't evaluated the view's queryacl yet.
|
|
|
|
*/
|
|
|
|
check_acl = ISC_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_acl) {
|
|
|
|
isc_boolean_t log = ISC_TF((options & DNS_GETDB_NOLOG) == 0);
|
|
|
|
result = ns_client_checkacl(client, "query", client->view->queryacl,
|
|
|
|
ISC_TRUE, log);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* We were allowed by the default
|
|
|
|
* "allow-query" ACL. Remember this so we
|
|
|
|
* don't have to check again.
|
|
|
|
*/
|
|
|
|
client->query.attributes |=
|
|
|
|
NS_QUERYATTR_QUERYOK;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We've now evaluated the view's query ACL, and
|
|
|
|
* the NS_QUERYATTR_QUERYOK attribute is now valid.
|
|
|
|
*/
|
|
|
|
client->query.attributes |= NS_QUERYATTR_QUERYOKVALID;
|
|
|
|
|
|
|
|
} else
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static inline isc_result_t
|
|
|
|
query_getdb(ns_client_t *client, dns_name_t *name, unsigned int options,
|
|
|
|
dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp,
|
|
|
|
isc_boolean_t *is_zonep)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
result = query_getzonedb(client, name, options, zonep, dbp, versionp);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
*is_zonep = ISC_TRUE;
|
|
|
|
} else if (result == ISC_R_NOTFOUND) {
|
|
|
|
result = query_getcachedb(client, dbp, options);
|
|
|
|
*is_zonep = ISC_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-09-07 23:09:34 +00:00
|
|
|
static isc_result_t
|
|
|
|
query_simplefind(void *arg, dns_name_t *name, dns_rdatatype_t type,
|
1999-11-22 19:52:39 +00:00
|
|
|
isc_stdtime_t now,
|
1999-09-07 23:09:34 +00:00
|
|
|
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
|
|
|
|
{
|
|
|
|
ns_client_t *client = arg;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_fixedname_t foundname;
|
|
|
|
dns_db_t *db;
|
|
|
|
dns_dbversion_t *version;
|
1999-09-08 01:21:01 +00:00
|
|
|
unsigned int dboptions;
|
1999-09-13 18:26:37 +00:00
|
|
|
isc_boolean_t is_zone;
|
|
|
|
dns_rdataset_t zrdataset, zsigrdataset;
|
1999-10-14 01:37:00 +00:00
|
|
|
dns_zone_t *zone;
|
1999-09-07 23:09:34 +00:00
|
|
|
|
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
1999-11-03 23:50:39 +00:00
|
|
|
REQUIRE(rdataset != NULL);
|
|
|
|
REQUIRE(sigrdataset != NULL);
|
1999-09-07 23:09:34 +00:00
|
|
|
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_init(&zrdataset);
|
|
|
|
dns_rdataset_init(&zsigrdataset);
|
|
|
|
|
1999-09-07 23:09:34 +00:00
|
|
|
/*
|
|
|
|
* Find a database to answer the query.
|
|
|
|
*/
|
1999-10-14 01:37:00 +00:00
|
|
|
zone = NULL;
|
1999-09-07 23:09:34 +00:00
|
|
|
db = NULL;
|
|
|
|
version = NULL;
|
2000-04-25 21:58:17 +00:00
|
|
|
result = query_getdb(client, name, 0, &zone, &db, &version, &is_zone);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
1999-09-07 23:09:34 +00:00
|
|
|
|
1999-09-13 18:26:37 +00:00
|
|
|
db_find:
|
1999-09-07 23:09:34 +00:00
|
|
|
/*
|
|
|
|
* Now look for an answer in the database.
|
|
|
|
*/
|
|
|
|
dns_fixedname_init(&foundname);
|
1999-09-08 01:21:01 +00:00
|
|
|
dboptions = client->query.dboptions;
|
1999-10-25 21:21:55 +00:00
|
|
|
if (db == client->query.gluedb || (!is_zone && CACHEGLUEOK(client)))
|
1999-09-08 01:21:01 +00:00
|
|
|
dboptions |= DNS_DBFIND_GLUEOK;
|
|
|
|
result = dns_db_find(db, name, version, type, dboptions,
|
1999-11-22 19:52:39 +00:00
|
|
|
now, NULL, dns_fixedname_name(&foundname),
|
1999-09-07 23:09:34 +00:00
|
|
|
rdataset, sigrdataset);
|
1999-09-13 18:26:37 +00:00
|
|
|
if (result == DNS_R_DELEGATION ||
|
2000-04-06 22:03:35 +00:00
|
|
|
result == ISC_R_NOTFOUND) {
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_disassociate(rdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset))
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_disassociate(sigrdataset);
|
|
|
|
if (is_zone) {
|
|
|
|
if (USECACHE(client)) {
|
|
|
|
/*
|
|
|
|
* Either the answer is in the cache, or we
|
|
|
|
* don't know it.
|
|
|
|
*/
|
|
|
|
is_zone = ISC_FALSE;
|
|
|
|
version = NULL;
|
|
|
|
dns_db_detach(&db);
|
|
|
|
dns_db_attach(client->view->cachedb, &db);
|
|
|
|
goto db_find;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We don't have the data in the cache. If we've got
|
|
|
|
* glue from the zone, use it.
|
|
|
|
*/
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(&zrdataset)) {
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_clone(&zrdataset, rdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(&zsigrdataset))
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_clone(&zsigrdataset,
|
|
|
|
sigrdataset);
|
|
|
|
result = ISC_R_SUCCESS;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We don't know the answer.
|
|
|
|
*/
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_NOTFOUND;
|
1999-09-13 18:26:37 +00:00
|
|
|
} else if (result == DNS_R_GLUE) {
|
2000-02-01 02:23:39 +00:00
|
|
|
if (USECACHE(client) && RECURSIONOK(client)) {
|
1999-09-13 18:26:37 +00:00
|
|
|
/*
|
|
|
|
* We found an answer, but the cache may be better.
|
|
|
|
* Remember what we've got and go look in the cache.
|
|
|
|
*/
|
|
|
|
is_zone = ISC_FALSE;
|
|
|
|
version = NULL;
|
|
|
|
dns_rdataset_clone(rdataset, &zrdataset);
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset)) {
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_clone(sigrdataset, &zsigrdataset);
|
|
|
|
dns_rdataset_disassociate(sigrdataset);
|
|
|
|
}
|
|
|
|
dns_db_detach(&db);
|
|
|
|
dns_db_attach(client->view->cachedb, &db);
|
|
|
|
goto db_find;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Otherwise, the glue is the best answer.
|
|
|
|
*/
|
|
|
|
result = ISC_R_SUCCESS;
|
1999-11-03 23:50:39 +00:00
|
|
|
} else if (result != ISC_R_SUCCESS) {
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
1999-11-03 23:50:39 +00:00
|
|
|
dns_rdataset_disassociate(rdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset))
|
1999-11-03 23:50:39 +00:00
|
|
|
dns_rdataset_disassociate(sigrdataset);
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_NOTFOUND;
|
1999-11-03 23:50:39 +00:00
|
|
|
}
|
1999-09-13 18:26:37 +00:00
|
|
|
|
1999-09-07 23:09:34 +00:00
|
|
|
cleanup:
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(&zrdataset)) {
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_disassociate(&zrdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(&zsigrdataset))
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_disassociate(&zsigrdataset);
|
|
|
|
}
|
1999-09-07 23:09:34 +00:00
|
|
|
if (db != NULL)
|
|
|
|
dns_db_detach(&db);
|
1999-10-14 01:37:00 +00:00
|
|
|
if (zone != NULL)
|
|
|
|
dns_zone_detach(&zone);
|
1999-09-07 23:09:34 +00:00
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
1999-09-08 01:10:26 +00:00
|
|
|
static inline isc_boolean_t
|
|
|
|
query_isduplicate(ns_client_t *client, dns_name_t *name,
|
1999-09-17 21:59:55 +00:00
|
|
|
dns_rdatatype_t type, dns_name_t **mnamep)
|
1999-09-08 01:10:26 +00:00
|
|
|
{
|
|
|
|
dns_section_t section;
|
1999-09-17 21:59:55 +00:00
|
|
|
dns_name_t *mname = NULL;
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t result;
|
1999-09-08 01:10:26 +00:00
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_isduplicate");
|
|
|
|
|
1999-09-08 01:10:26 +00:00
|
|
|
for (section = DNS_SECTION_ANSWER;
|
|
|
|
section <= DNS_SECTION_ADDITIONAL;
|
|
|
|
section++) {
|
1999-09-17 21:59:55 +00:00
|
|
|
result = dns_message_findname(client->message, section,
|
|
|
|
name, type, 0, &mname, NULL);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
1999-09-08 01:10:26 +00:00
|
|
|
/*
|
|
|
|
* We've already got this RRset in the response.
|
|
|
|
*/
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_isduplicate: true: done");
|
1999-09-08 01:10:26 +00:00
|
|
|
return (ISC_TRUE);
|
2000-04-06 22:03:35 +00:00
|
|
|
} else if (result == DNS_R_NXRRSET) {
|
1999-09-17 21:59:55 +00:00
|
|
|
/*
|
|
|
|
* The name exists, but the rdataset does not.
|
|
|
|
*/
|
|
|
|
if (section == DNS_SECTION_ADDITIONAL)
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
RUNTIME_CHECK(result == DNS_R_NXDOMAIN);
|
|
|
|
mname = NULL;
|
1999-09-08 01:10:26 +00:00
|
|
|
}
|
|
|
|
|
1999-09-17 21:59:55 +00:00
|
|
|
/*
|
|
|
|
* If the dns_name_t we're lookup up is already in the message,
|
|
|
|
* we don't want to trigger the caller's name replacement logic.
|
|
|
|
*/
|
|
|
|
if (name == mname)
|
|
|
|
mname = NULL;
|
|
|
|
|
|
|
|
*mnamep = mname;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_isduplicate: false: done");
|
1999-09-08 01:10:26 +00:00
|
|
|
return (ISC_FALSE);
|
|
|
|
}
|
1999-09-07 23:09:34 +00:00
|
|
|
|
1999-08-03 01:21:00 +00:00
|
|
|
static isc_result_t
|
2000-06-01 21:42:42 +00:00
|
|
|
query_addadditional(void *arg, dns_name_t *name, dns_rdatatype_t qtype) {
|
1999-08-03 01:21:00 +00:00
|
|
|
ns_client_t *client = arg;
|
1999-08-12 07:54:08 +00:00
|
|
|
isc_result_t result, eresult;
|
2000-07-05 23:10:06 +00:00
|
|
|
dns_dbnode_t *node;
|
|
|
|
dns_db_t *db;
|
|
|
|
dns_name_t *fname, *mname;
|
2000-01-07 02:42:45 +00:00
|
|
|
dns_rdataset_t *rdataset, *sigrdataset, *a6rdataset, *trdataset;
|
1999-09-02 02:10:44 +00:00
|
|
|
isc_buffer_t *dbuf;
|
1999-08-03 01:21:00 +00:00
|
|
|
isc_buffer_t b;
|
2000-07-05 23:10:06 +00:00
|
|
|
dns_dbversion_t *version;
|
|
|
|
isc_boolean_t added_something, need_addname;
|
1999-10-14 01:37:00 +00:00
|
|
|
dns_zone_t *zone;
|
1999-10-25 21:21:55 +00:00
|
|
|
dns_rdatatype_t type;
|
1999-08-03 01:21:00 +00:00
|
|
|
|
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
1999-10-25 21:21:55 +00:00
|
|
|
REQUIRE(qtype != dns_rdatatype_any);
|
1999-08-03 01:21:00 +00:00
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addadditional");
|
|
|
|
|
1999-08-03 01:21:00 +00:00
|
|
|
/*
|
1999-08-12 07:54:08 +00:00
|
|
|
* Initialization.
|
1999-08-03 01:21:00 +00:00
|
|
|
*/
|
1999-08-12 07:54:08 +00:00
|
|
|
eresult = ISC_R_SUCCESS;
|
1999-08-03 01:21:00 +00:00
|
|
|
fname = NULL;
|
|
|
|
rdataset = NULL;
|
1999-09-01 18:16:43 +00:00
|
|
|
sigrdataset = NULL;
|
1999-09-08 01:10:26 +00:00
|
|
|
a6rdataset = NULL;
|
2000-01-07 02:42:45 +00:00
|
|
|
trdataset = NULL;
|
1999-08-12 07:54:08 +00:00
|
|
|
db = NULL;
|
1999-08-18 04:23:39 +00:00
|
|
|
version = NULL;
|
1999-08-12 07:54:08 +00:00
|
|
|
node = NULL;
|
1999-09-13 18:26:37 +00:00
|
|
|
added_something = ISC_FALSE;
|
1999-09-17 21:59:55 +00:00
|
|
|
need_addname = ISC_FALSE;
|
1999-10-14 01:37:00 +00:00
|
|
|
zone = NULL;
|
2000-07-05 23:10:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We treat type A additional section processing as if it
|
|
|
|
* were "any address type" additional section processing.
|
|
|
|
* To avoid multiple lookups, we do an 'any' database
|
|
|
|
* lookup and iterate over the node.
|
|
|
|
*/
|
1999-10-25 21:21:55 +00:00
|
|
|
if (qtype == dns_rdatatype_a)
|
|
|
|
type = dns_rdatatype_any;
|
|
|
|
else
|
|
|
|
type = qtype;
|
1999-08-03 01:21:00 +00:00
|
|
|
|
|
|
|
/*
|
2000-07-05 23:10:06 +00:00
|
|
|
* Get some resources.
|
1999-09-13 18:26:37 +00:00
|
|
|
*/
|
|
|
|
dbuf = query_getnamebuf(client);
|
|
|
|
if (dbuf == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
fname = query_newname(client, dbuf, &b);
|
|
|
|
rdataset = query_newrdataset(client);
|
|
|
|
sigrdataset = query_newrdataset(client);
|
|
|
|
if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
1999-08-03 01:21:00 +00:00
|
|
|
/*
|
2000-07-05 23:10:06 +00:00
|
|
|
* Look for a zone database that might contain authoritative
|
|
|
|
* additional data.
|
|
|
|
*/
|
|
|
|
result = query_getzonedb(client, name, DNS_GETDB_NOLOG,
|
|
|
|
&zone, &db, &version);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto try_cache;
|
|
|
|
|
|
|
|
CTRACE("query_addadditional: db_find");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we are looking for authoritative data, we do not set
|
|
|
|
* the GLUEOK flag. Glue will be looked for later, but not
|
|
|
|
* necessarily in the same database.
|
1999-08-03 01:21:00 +00:00
|
|
|
*/
|
|
|
|
node = NULL;
|
2000-07-05 23:10:06 +00:00
|
|
|
result = dns_db_find(db, name, version, type, client->query.dboptions,
|
1999-10-29 16:17:15 +00:00
|
|
|
client->now, &node, fname, rdataset,
|
1999-09-01 18:16:43 +00:00
|
|
|
sigrdataset);
|
2000-07-05 23:10:06 +00:00
|
|
|
if (result == ISC_R_SUCCESS)
|
|
|
|
goto found;
|
1999-09-13 18:26:37 +00:00
|
|
|
|
2000-07-05 23:10:06 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
if (dns_rdataset_isassociated(sigrdataset))
|
|
|
|
dns_rdataset_disassociate(sigrdataset);
|
|
|
|
if (node != NULL)
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
version = NULL;
|
|
|
|
dns_db_detach(&db);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No authoritative data was found. The cache is our next best bet.
|
|
|
|
*/
|
|
|
|
|
|
|
|
try_cache:
|
|
|
|
result = query_getcachedb(client, &db, DNS_GETDB_NOLOG);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
/*
|
|
|
|
* Most likely the client isn't allowed to query the cache.
|
|
|
|
*/
|
|
|
|
goto try_glue;
|
|
|
|
|
|
|
|
result = dns_db_find(db, name, version, type, client->query.dboptions,
|
|
|
|
client->now, &node, fname, rdataset,
|
|
|
|
sigrdataset);
|
|
|
|
if (result == ISC_R_SUCCESS)
|
|
|
|
goto found;
|
|
|
|
|
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
if (dns_rdataset_isassociated(sigrdataset))
|
|
|
|
dns_rdataset_disassociate(sigrdataset);
|
|
|
|
if (node != NULL)
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
dns_db_detach(&db);
|
|
|
|
|
|
|
|
try_glue:
|
|
|
|
/*
|
|
|
|
* No cached data was found. Glue is our last chance.
|
|
|
|
* RFC1035 sayeth:
|
|
|
|
*
|
|
|
|
* NS records cause both the usual additional section
|
|
|
|
* processing to locate a type A record, and, when used
|
|
|
|
* in a referral, a special search of the zone in which
|
|
|
|
* they reside for glue information.
|
|
|
|
*
|
|
|
|
* This is the "special search". Note that we must search
|
|
|
|
* the zone where the NS record resides, not the zone it
|
|
|
|
* points to, and that we only do the search in the delegation
|
|
|
|
* case (identified by client->query.gluedb being set).
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (client->query.gluedb == NULL)
|
1999-08-12 07:54:08 +00:00
|
|
|
goto cleanup;
|
1999-08-03 01:21:00 +00:00
|
|
|
|
2000-07-05 23:10:06 +00:00
|
|
|
dns_db_attach(client->query.gluedb, &db);
|
|
|
|
result = dns_db_find(db, name, version, type,
|
|
|
|
client->query.dboptions | DNS_DBFIND_GLUEOK,
|
|
|
|
client->now, &node, fname, rdataset,
|
|
|
|
sigrdataset);
|
|
|
|
if (!(result == ISC_R_SUCCESS ||
|
|
|
|
result == DNS_R_ZONECUT ||
|
|
|
|
result == DNS_R_GLUE))
|
|
|
|
goto cleanup;
|
1999-09-08 01:10:26 +00:00
|
|
|
|
2000-07-05 23:10:06 +00:00
|
|
|
found:
|
|
|
|
/*
|
|
|
|
* We have found a potential additional data rdataset, or
|
|
|
|
* at least a node to iterate over.
|
|
|
|
*/
|
|
|
|
query_keepname(client, fname, dbuf);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have an rdataset, add it to the additional data
|
|
|
|
* section.
|
|
|
|
*/
|
1999-09-17 21:59:55 +00:00
|
|
|
mname = NULL;
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset) &&
|
1999-09-17 21:59:55 +00:00
|
|
|
!query_isduplicate(client, fname, type, &mname)) {
|
|
|
|
if (mname != NULL) {
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
fname = mname;
|
|
|
|
} else
|
|
|
|
need_addname = ISC_TRUE;
|
1999-09-08 01:10:26 +00:00
|
|
|
ISC_LIST_APPEND(fname->list, rdataset, link);
|
2000-01-07 02:42:45 +00:00
|
|
|
trdataset = rdataset;
|
1999-09-08 01:10:26 +00:00
|
|
|
rdataset = NULL;
|
1999-09-13 18:26:37 +00:00
|
|
|
added_something = ISC_TRUE;
|
1999-09-08 01:10:26 +00:00
|
|
|
/*
|
|
|
|
* Note: we only add SIGs if we've added the type they cover,
|
|
|
|
* so we do not need to check if the SIG rdataset is already
|
|
|
|
* in the response.
|
|
|
|
*/
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset)) {
|
1999-09-08 01:10:26 +00:00
|
|
|
ISC_LIST_APPEND(fname->list, sigrdataset, link);
|
|
|
|
sigrdataset = NULL;
|
1999-08-03 01:21:00 +00:00
|
|
|
}
|
|
|
|
}
|
1999-09-08 01:10:26 +00:00
|
|
|
|
1999-10-25 21:21:55 +00:00
|
|
|
if (qtype == dns_rdatatype_a) {
|
1999-09-08 01:10:26 +00:00
|
|
|
/*
|
1999-10-25 21:21:55 +00:00
|
|
|
* We now go looking for A, A6, and AAAA records, along with
|
1999-09-08 01:10:26 +00:00
|
|
|
* their signatures.
|
|
|
|
*
|
|
|
|
* XXXRTH This code could be more efficient.
|
|
|
|
*/
|
|
|
|
if (rdataset != NULL) {
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
1999-09-08 01:10:26 +00:00
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
} else {
|
|
|
|
rdataset = query_newrdataset(client);
|
|
|
|
if (rdataset == NULL)
|
|
|
|
goto addname;
|
|
|
|
}
|
|
|
|
if (sigrdataset != NULL) {
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset))
|
1999-09-08 01:10:26 +00:00
|
|
|
dns_rdataset_disassociate(sigrdataset);
|
|
|
|
} else {
|
|
|
|
sigrdataset = query_newrdataset(client);
|
|
|
|
if (sigrdataset == NULL)
|
|
|
|
goto addname;
|
|
|
|
}
|
1999-10-25 21:21:55 +00:00
|
|
|
result = dns_db_findrdataset(db, node, version,
|
|
|
|
dns_rdatatype_a, 0,
|
1999-10-29 16:17:15 +00:00
|
|
|
client->now, rdataset,
|
1999-10-25 21:21:55 +00:00
|
|
|
sigrdataset);
|
1999-11-03 20:20:38 +00:00
|
|
|
if (result == DNS_R_NCACHENXDOMAIN)
|
|
|
|
goto addname;
|
|
|
|
if (result == DNS_R_NCACHENXRRSET) {
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
/*
|
|
|
|
* Negative cache entries don't have sigrdatasets.
|
|
|
|
*/
|
2000-04-28 23:46:43 +00:00
|
|
|
INSIST(! dns_rdataset_isassociated(sigrdataset));
|
1999-11-03 20:20:38 +00:00
|
|
|
}
|
1999-10-25 21:21:55 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
mname = NULL;
|
|
|
|
if (!query_isduplicate(client, fname,
|
|
|
|
dns_rdatatype_a, &mname)) {
|
|
|
|
if (mname != NULL) {
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
fname = mname;
|
|
|
|
} else
|
|
|
|
need_addname = ISC_TRUE;
|
|
|
|
ISC_LIST_APPEND(fname->list, rdataset, link);
|
|
|
|
added_something = ISC_TRUE;
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset)) {
|
1999-10-25 21:21:55 +00:00
|
|
|
ISC_LIST_APPEND(fname->list,
|
|
|
|
sigrdataset, link);
|
|
|
|
sigrdataset =
|
|
|
|
query_newrdataset(client);
|
|
|
|
}
|
|
|
|
rdataset = query_newrdataset(client);
|
|
|
|
if (rdataset == NULL || sigrdataset == NULL)
|
|
|
|
goto addname;
|
2000-02-14 22:21:25 +00:00
|
|
|
} else {
|
1999-10-25 21:21:55 +00:00
|
|
|
dns_rdataset_disassociate(rdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset))
|
2000-02-14 22:21:25 +00:00
|
|
|
dns_rdataset_disassociate(sigrdataset);
|
|
|
|
}
|
1999-10-25 21:21:55 +00:00
|
|
|
}
|
1999-09-08 01:10:26 +00:00
|
|
|
result = dns_db_findrdataset(db, node, version,
|
|
|
|
dns_rdatatype_a6, 0,
|
1999-10-29 16:17:15 +00:00
|
|
|
client->now, rdataset,
|
1999-09-08 01:10:26 +00:00
|
|
|
sigrdataset);
|
1999-11-03 20:20:38 +00:00
|
|
|
if (result == DNS_R_NCACHENXDOMAIN)
|
|
|
|
goto addname;
|
|
|
|
if (result == DNS_R_NCACHENXRRSET) {
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
INSIST(! dns_rdataset_isassociated(sigrdataset));
|
1999-11-03 20:20:38 +00:00
|
|
|
}
|
1999-09-08 01:10:26 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
1999-09-17 21:59:55 +00:00
|
|
|
mname = NULL;
|
1999-09-08 01:10:26 +00:00
|
|
|
if (!query_isduplicate(client, fname,
|
1999-09-17 21:59:55 +00:00
|
|
|
dns_rdatatype_a6, &mname)) {
|
|
|
|
if (mname != NULL) {
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
fname = mname;
|
|
|
|
} else
|
|
|
|
need_addname = ISC_TRUE;
|
1999-09-08 01:10:26 +00:00
|
|
|
a6rdataset = rdataset;
|
|
|
|
ISC_LIST_APPEND(fname->list, rdataset, link);
|
1999-09-13 18:26:37 +00:00
|
|
|
added_something = ISC_TRUE;
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset)) {
|
1999-09-08 01:10:26 +00:00
|
|
|
ISC_LIST_APPEND(fname->list,
|
|
|
|
sigrdataset, link);
|
|
|
|
sigrdataset =
|
|
|
|
query_newrdataset(client);
|
|
|
|
}
|
|
|
|
rdataset = query_newrdataset(client);
|
|
|
|
if (rdataset == NULL || sigrdataset == NULL)
|
|
|
|
goto addname;
|
|
|
|
} else
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
}
|
|
|
|
result = dns_db_findrdataset(db, node, version,
|
|
|
|
dns_rdatatype_aaaa, 0,
|
1999-10-29 16:17:15 +00:00
|
|
|
client->now, rdataset,
|
1999-09-08 01:10:26 +00:00
|
|
|
sigrdataset);
|
1999-11-03 20:20:38 +00:00
|
|
|
if (result == DNS_R_NCACHENXDOMAIN)
|
|
|
|
goto addname;
|
|
|
|
if (result == DNS_R_NCACHENXRRSET) {
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
INSIST(! dns_rdataset_isassociated(sigrdataset));
|
1999-11-03 20:20:38 +00:00
|
|
|
}
|
1999-09-08 01:10:26 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
1999-09-17 21:59:55 +00:00
|
|
|
mname = NULL;
|
1999-09-08 01:10:26 +00:00
|
|
|
if (!query_isduplicate(client, fname,
|
1999-09-17 21:59:55 +00:00
|
|
|
dns_rdatatype_aaaa, &mname)) {
|
|
|
|
if (mname != NULL) {
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
fname = mname;
|
|
|
|
} else
|
|
|
|
need_addname = ISC_TRUE;
|
1999-09-08 01:10:26 +00:00
|
|
|
ISC_LIST_APPEND(fname->list, rdataset, link);
|
1999-09-13 18:26:37 +00:00
|
|
|
added_something = ISC_TRUE;
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset)) {
|
1999-09-08 01:10:26 +00:00
|
|
|
ISC_LIST_APPEND(fname->list,
|
|
|
|
sigrdataset, link);
|
|
|
|
sigrdataset = NULL;
|
|
|
|
}
|
|
|
|
rdataset = NULL;
|
|
|
|
}
|
|
|
|
}
|
1999-09-01 18:16:43 +00:00
|
|
|
}
|
1999-08-03 01:21:00 +00:00
|
|
|
|
1999-09-08 01:10:26 +00:00
|
|
|
addname:
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addadditional: addname");
|
1999-09-13 18:26:37 +00:00
|
|
|
/*
|
|
|
|
* If we haven't added anything, then we're done.
|
|
|
|
*/
|
|
|
|
if (!added_something)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/*
|
1999-09-17 21:59:55 +00:00
|
|
|
* We may have added our rdatasets to an existing name, if so, then
|
|
|
|
* need_addname will be ISC_FALSE. Whether we used an existing name
|
|
|
|
* or a new one, we must set fname to NULL to prevent cleanup.
|
1999-09-13 18:26:37 +00:00
|
|
|
*/
|
1999-09-17 21:59:55 +00:00
|
|
|
if (need_addname)
|
|
|
|
dns_message_addname(client->message, fname,
|
|
|
|
DNS_SECTION_ADDITIONAL);
|
1999-08-12 07:54:08 +00:00
|
|
|
fname = NULL;
|
1999-08-03 01:21:00 +00:00
|
|
|
|
1999-08-03 20:56:08 +00:00
|
|
|
/*
|
|
|
|
* In a few cases, we want to add additional data for additional
|
|
|
|
* data. It's simpler to just deal with special cases here than
|
|
|
|
* to try to create a general purpose mechanism and allow the
|
|
|
|
* rdata implementations to do it themselves.
|
|
|
|
*
|
|
|
|
* This involves recursion, but the depth is limited. The
|
|
|
|
* most complex case is adding a SRV rdataset, which involves
|
|
|
|
* recursing to add address records, which in turn can cause
|
|
|
|
* recursion to add KEYs.
|
|
|
|
*/
|
1999-09-07 23:09:34 +00:00
|
|
|
if (type == dns_rdatatype_a || type == dns_rdatatype_aaaa) {
|
1999-08-03 20:56:08 +00:00
|
|
|
/*
|
|
|
|
* RFC 2535 section 3.5 says that when A or AAAA records are
|
|
|
|
* retrieved as additional data, any KEY RRs for the owner name
|
1999-09-07 23:09:34 +00:00
|
|
|
* should be added to the additional data section. Note: we
|
1999-10-19 20:22:38 +00:00
|
|
|
* do NOT include A6 in the list of types with such treatment
|
|
|
|
* in additional data because we'd have to do it for each A6
|
|
|
|
* in the A6 chain.
|
1999-08-03 20:56:08 +00:00
|
|
|
*
|
|
|
|
* XXXRTH We should lower the priority here. Alternatively,
|
|
|
|
* we could raise the priority of glue records.
|
|
|
|
*/
|
1999-08-12 07:54:08 +00:00
|
|
|
eresult = query_addadditional(client, name, dns_rdatatype_key);
|
2000-01-07 02:42:45 +00:00
|
|
|
} else if (type == dns_rdatatype_srv && trdataset != NULL) {
|
1999-08-03 20:56:08 +00:00
|
|
|
/*
|
|
|
|
* If we're adding SRV records to the additional data
|
|
|
|
* section, it's helpful if we add the SRV additional data
|
|
|
|
* as well.
|
|
|
|
*/
|
2000-01-07 02:42:45 +00:00
|
|
|
eresult = dns_rdataset_additionaldata(trdataset,
|
1999-08-12 07:54:08 +00:00
|
|
|
query_addadditional,
|
|
|
|
client);
|
1999-08-03 20:56:08 +00:00
|
|
|
}
|
|
|
|
|
1999-09-08 01:10:26 +00:00
|
|
|
/*
|
|
|
|
* If we added an A6 rdataset, we should also add everything we
|
|
|
|
* know about the A6 chains. We wait until now to do this so that
|
|
|
|
* they'll come after any additional data added above.
|
|
|
|
*/
|
1999-09-17 21:59:55 +00:00
|
|
|
if (a6rdataset != NULL) {
|
|
|
|
dns_a6_reset(&client->query.a6ctx);
|
1999-11-22 19:52:39 +00:00
|
|
|
dns_a6_foreach(&client->query.a6ctx, a6rdataset, client->now);
|
1999-09-17 21:59:55 +00:00
|
|
|
}
|
1999-09-08 01:10:26 +00:00
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
cleanup:
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addadditional: cleanup");
|
1999-09-13 18:26:37 +00:00
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
query_putrdataset(client, &sigrdataset);
|
1999-08-12 07:54:08 +00:00
|
|
|
if (fname != NULL)
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
if (node != NULL)
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
if (db != NULL)
|
|
|
|
dns_db_detach(&db);
|
1999-10-14 01:37:00 +00:00
|
|
|
if (zone != NULL)
|
|
|
|
dns_zone_detach(&zone);
|
1999-08-12 07:54:08 +00:00
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addadditional: done");
|
1999-08-12 07:54:08 +00:00
|
|
|
return (eresult);
|
1999-08-03 01:21:00 +00:00
|
|
|
}
|
|
|
|
|
1999-09-07 23:09:34 +00:00
|
|
|
static void
|
|
|
|
query_adda6rrset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset,
|
|
|
|
dns_rdataset_t *sigrdataset)
|
|
|
|
{
|
|
|
|
ns_client_t *client = arg;
|
|
|
|
dns_rdataset_t *crdataset, *csigrdataset;
|
|
|
|
isc_buffer_t b, *dbuf;
|
1999-09-17 21:59:55 +00:00
|
|
|
dns_name_t *fname, *mname;
|
1999-09-07 23:09:34 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Add an rrset to the additional data section.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(rdataset->type == dns_rdatatype_a6);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get some resources...
|
|
|
|
*/
|
|
|
|
fname = NULL;
|
|
|
|
crdataset = NULL;
|
|
|
|
csigrdataset = NULL;
|
|
|
|
dbuf = query_getnamebuf(client);
|
|
|
|
if (dbuf == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
fname = query_newname(client, dbuf, &b);
|
|
|
|
crdataset = query_newrdataset(client);
|
|
|
|
csigrdataset = query_newrdataset(client);
|
|
|
|
if (fname == NULL || crdataset == NULL || csigrdataset == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (dns_name_concatenate(name, NULL, fname, NULL) != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
dns_rdataset_clone(rdataset, crdataset);
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(sigrdataset))
|
1999-09-07 23:09:34 +00:00
|
|
|
dns_rdataset_clone(sigrdataset, csigrdataset);
|
|
|
|
|
1999-09-17 21:59:55 +00:00
|
|
|
mname = NULL;
|
|
|
|
if (query_isduplicate(client, fname, crdataset->type, &mname))
|
1999-09-08 01:10:26 +00:00
|
|
|
goto cleanup;
|
1999-09-17 21:59:55 +00:00
|
|
|
if (mname != NULL) {
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
fname = mname;
|
|
|
|
} else {
|
|
|
|
query_keepname(client, fname, dbuf);
|
|
|
|
dns_message_addname(client->message, fname,
|
|
|
|
DNS_SECTION_ADDITIONAL);
|
|
|
|
}
|
|
|
|
|
1999-09-07 23:09:34 +00:00
|
|
|
ISC_LIST_APPEND(fname->list, crdataset, link);
|
|
|
|
crdataset = NULL;
|
|
|
|
/*
|
|
|
|
* Note: we only add SIGs if we've added the type they cover, so
|
|
|
|
* we do not need to check if the SIG rdataset is already in the
|
|
|
|
* response.
|
|
|
|
*/
|
2000-04-28 23:46:43 +00:00
|
|
|
if (dns_rdataset_isassociated(csigrdataset)) {
|
1999-09-07 23:09:34 +00:00
|
|
|
ISC_LIST_APPEND(fname->list, csigrdataset, link);
|
|
|
|
csigrdataset = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
fname = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In spite of RFC 2535 section 3.5, we don't currently try to add
|
|
|
|
* KEY RRs for the A6 records. It's just too much work.
|
|
|
|
*/
|
|
|
|
|
|
|
|
cleanup:
|
1999-09-13 18:26:37 +00:00
|
|
|
query_putrdataset(client, &crdataset);
|
|
|
|
query_putrdataset(client, &csigrdataset);
|
1999-09-07 23:09:34 +00:00
|
|
|
if (fname != NULL)
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
}
|
|
|
|
|
1999-08-03 20:56:08 +00:00
|
|
|
static inline void
|
|
|
|
query_addrdataset(ns_client_t *client, dns_name_t *fname,
|
|
|
|
dns_rdataset_t *rdataset)
|
|
|
|
{
|
|
|
|
dns_rdatatype_t type = rdataset->type;
|
|
|
|
|
2000-07-04 01:33:47 +00:00
|
|
|
/*
|
|
|
|
* Add 'rdataset' and any pertinent additional data to
|
|
|
|
* 'fname', a name in the response message for 'client'.
|
|
|
|
*/
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addrdataset");
|
|
|
|
|
1999-08-03 20:56:08 +00:00
|
|
|
ISC_LIST_APPEND(fname->list, rdataset, link);
|
|
|
|
/*
|
1999-09-07 23:09:34 +00:00
|
|
|
* Add additional data.
|
|
|
|
*
|
|
|
|
* We don't care if dns_a6_foreach or dns_rdataset_additionaldata()
|
|
|
|
* fail.
|
1999-08-03 20:56:08 +00:00
|
|
|
*/
|
1999-09-17 21:59:55 +00:00
|
|
|
if (type == dns_rdatatype_a6) {
|
|
|
|
dns_a6_reset(&client->query.a6ctx);
|
1999-11-22 19:52:39 +00:00
|
|
|
(void)dns_a6_foreach(&client->query.a6ctx, rdataset,
|
|
|
|
client->now);
|
1999-09-17 21:59:55 +00:00
|
|
|
} else
|
1999-09-07 23:09:34 +00:00
|
|
|
(void)dns_rdataset_additionaldata(rdataset,
|
|
|
|
query_addadditional, client);
|
1999-08-03 20:56:08 +00:00
|
|
|
/*
|
|
|
|
* RFC 2535 section 3.5 says that when NS, SOA, A, or AAAA records
|
|
|
|
* are retrieved, any KEY RRs for the owner name should be added
|
1999-10-19 20:22:38 +00:00
|
|
|
* to the additional data section. We treat A6 records the same way.
|
1999-08-03 20:56:08 +00:00
|
|
|
*
|
2000-07-04 01:33:47 +00:00
|
|
|
* We don't care if query_addadditional() fails.
|
1999-08-03 20:56:08 +00:00
|
|
|
*/
|
|
|
|
if (type == dns_rdatatype_ns || type == dns_rdatatype_soa ||
|
|
|
|
type == dns_rdatatype_a || type == dns_rdatatype_aaaa ||
|
|
|
|
type == dns_rdatatype_a6) {
|
|
|
|
/*
|
|
|
|
* XXXRTH We should lower the priority here. Alternatively,
|
|
|
|
* we could raise the priority of glue records.
|
|
|
|
*/
|
|
|
|
(void)query_addadditional(client, fname, dns_rdatatype_key);
|
|
|
|
}
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addrdataset: done");
|
1999-08-03 20:56:08 +00:00
|
|
|
}
|
1999-08-05 01:51:32 +00:00
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
#define ANSWERED(rds) (((rds)->attributes & DNS_RDATASETATTR_ANSWERED) != 0)
|
|
|
|
|
1999-10-21 17:49:55 +00:00
|
|
|
static void
|
1999-08-12 07:54:08 +00:00
|
|
|
query_addrrset(ns_client_t *client, dns_name_t **namep,
|
1999-08-31 22:14:06 +00:00
|
|
|
dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp,
|
1999-10-19 20:22:38 +00:00
|
|
|
isc_buffer_t *dbuf, dns_section_t section)
|
1999-08-12 07:54:08 +00:00
|
|
|
{
|
|
|
|
dns_name_t *name, *mname;
|
1999-08-31 22:14:06 +00:00
|
|
|
dns_rdataset_t *rdataset, *mrdataset, *sigrdataset;
|
1999-08-12 07:54:08 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
2000-04-13 19:34:02 +00:00
|
|
|
/*
|
2000-07-04 01:33:47 +00:00
|
|
|
* To the current response for 'client', add the answer RRset
|
|
|
|
* '*rdatasetp' and an optional signature set '*sigrdatasetp', with
|
|
|
|
* owner name '*namep', to section 'section', unless they are
|
|
|
|
* already there. Also add any pertinent additional data.
|
|
|
|
*
|
|
|
|
* If 'dbuf' is not NULL, then '*namep' is the name whose data is
|
2000-04-13 19:34:02 +00:00
|
|
|
* stored in 'dbuf'. In this case, query_addrrset() guarantees that
|
|
|
|
* when it returns the name will either have been kept or released.
|
|
|
|
*/
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addrrset");
|
1999-08-12 07:54:08 +00:00
|
|
|
name = *namep;
|
|
|
|
rdataset = *rdatasetp;
|
1999-08-31 22:14:06 +00:00
|
|
|
if (sigrdatasetp != NULL)
|
|
|
|
sigrdataset = *sigrdatasetp;
|
|
|
|
else
|
|
|
|
sigrdataset = NULL;
|
1999-08-12 07:54:08 +00:00
|
|
|
mname = NULL;
|
|
|
|
mrdataset = NULL;
|
|
|
|
result = dns_message_findname(client->message, section,
|
1999-08-31 22:14:06 +00:00
|
|
|
name, rdataset->type, rdataset->covers,
|
1999-08-12 07:54:08 +00:00
|
|
|
&mname, &mrdataset);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* We've already got an RRset of the given name and type.
|
|
|
|
* There's nothing else to do;
|
|
|
|
*/
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addrrset: dns_message_findname succeeded: done");
|
2000-04-13 19:34:02 +00:00
|
|
|
if (dbuf != NULL)
|
|
|
|
query_releasename(client, namep);
|
1999-08-12 07:54:08 +00:00
|
|
|
return;
|
1999-08-19 20:46:59 +00:00
|
|
|
} else if (result == DNS_R_NXDOMAIN) {
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* The name doesn't exist.
|
|
|
|
*/
|
|
|
|
if (dbuf != NULL)
|
|
|
|
query_keepname(client, name, dbuf);
|
|
|
|
dns_message_addname(client->message, name, section);
|
|
|
|
*namep = NULL;
|
|
|
|
mname = name;
|
2000-04-13 19:34:02 +00:00
|
|
|
} else {
|
2000-04-06 22:03:35 +00:00
|
|
|
RUNTIME_CHECK(result == DNS_R_NXRRSET);
|
2000-04-13 19:34:02 +00:00
|
|
|
if (dbuf != NULL)
|
|
|
|
query_releasename(client, namep);
|
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
|
1999-08-31 22:14:06 +00:00
|
|
|
/*
|
|
|
|
* Note: we only add SIGs if we've added the type they cover, so
|
|
|
|
* we do not need to check if the SIG rdataset is already in the
|
|
|
|
* response.
|
|
|
|
*/
|
1999-08-12 07:54:08 +00:00
|
|
|
query_addrdataset(client, mname, rdataset);
|
|
|
|
*rdatasetp = NULL;
|
2000-04-28 23:46:43 +00:00
|
|
|
if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) {
|
1999-08-31 22:14:06 +00:00
|
|
|
/*
|
|
|
|
* We have a signature. Add it to the response.
|
|
|
|
*/
|
1999-09-09 06:55:35 +00:00
|
|
|
ISC_LIST_APPEND(mname->list, sigrdataset, link);
|
1999-08-31 22:14:06 +00:00
|
|
|
*sigrdatasetp = NULL;
|
|
|
|
}
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addrrset: done");
|
1999-08-12 07:54:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline isc_result_t
|
|
|
|
query_addsoa(ns_client_t *client, dns_db_t *db) {
|
|
|
|
dns_name_t *name, *fname;
|
|
|
|
dns_dbnode_t *node;
|
|
|
|
isc_result_t result, eresult;
|
|
|
|
dns_fixedname_t foundname;
|
1999-08-31 22:14:06 +00:00
|
|
|
dns_rdataset_t *rdataset, *sigrdataset;
|
1999-08-05 01:51:32 +00:00
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addsoa");
|
1999-08-05 01:51:32 +00:00
|
|
|
/*
|
1999-08-12 07:54:08 +00:00
|
|
|
* Initialization.
|
1999-08-05 01:51:32 +00:00
|
|
|
*/
|
1999-08-12 07:54:08 +00:00
|
|
|
eresult = ISC_R_SUCCESS;
|
|
|
|
name = NULL;
|
|
|
|
rdataset = NULL;
|
|
|
|
node = NULL;
|
|
|
|
dns_fixedname_init(&foundname);
|
|
|
|
fname = dns_fixedname_name(&foundname);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get resources and make 'name' be the database origin.
|
|
|
|
*/
|
|
|
|
result = dns_message_gettempname(client->message, &name);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
dns_name_init(name, NULL);
|
|
|
|
dns_name_clone(dns_db_origin(db), name);
|
|
|
|
rdataset = query_newrdataset(client);
|
1999-08-31 22:14:06 +00:00
|
|
|
sigrdataset = query_newrdataset(client);
|
|
|
|
if (rdataset == NULL || sigrdataset == NULL) {
|
1999-08-12 07:54:08 +00:00
|
|
|
eresult = DNS_R_SERVFAIL;
|
|
|
|
goto cleanup;
|
1999-08-05 01:51:32 +00:00
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the SOA.
|
|
|
|
*/
|
2000-07-25 01:06:18 +00:00
|
|
|
result = dns_db_find(db, name, NULL, dns_rdatatype_soa,
|
|
|
|
client->query.dboptions, 0, &node,
|
1999-08-31 22:14:06 +00:00
|
|
|
fname, rdataset, sigrdataset);
|
1999-08-12 07:54:08 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* This is bad. We tried to get the SOA RR at the zone top
|
|
|
|
* and it didn't work!
|
|
|
|
*/
|
|
|
|
eresult = DNS_R_SERVFAIL;
|
1999-08-31 22:14:06 +00:00
|
|
|
} else {
|
|
|
|
query_addrrset(client, &name, &rdataset, &sigrdataset, NULL,
|
1999-10-19 20:22:38 +00:00
|
|
|
DNS_SECTION_AUTHORITY);
|
1999-08-31 22:14:06 +00:00
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
|
|
|
|
cleanup:
|
1999-09-13 18:26:37 +00:00
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
query_putrdataset(client, &sigrdataset);
|
1999-08-12 07:54:08 +00:00
|
|
|
if (name != NULL)
|
|
|
|
query_releasename(client, &name);
|
|
|
|
if (node != NULL)
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
|
|
|
|
return (eresult);
|
1999-08-05 01:51:32 +00:00
|
|
|
}
|
1999-08-03 20:56:08 +00:00
|
|
|
|
1999-09-17 21:59:55 +00:00
|
|
|
static inline isc_result_t
|
|
|
|
query_addns(ns_client_t *client, dns_db_t *db) {
|
|
|
|
dns_name_t *name, *fname;
|
|
|
|
dns_dbnode_t *node;
|
|
|
|
isc_result_t result, eresult;
|
|
|
|
dns_fixedname_t foundname;
|
|
|
|
dns_rdataset_t *rdataset, *sigrdataset;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addns");
|
1999-09-17 21:59:55 +00:00
|
|
|
/*
|
|
|
|
* Initialization.
|
|
|
|
*/
|
|
|
|
eresult = ISC_R_SUCCESS;
|
|
|
|
name = NULL;
|
|
|
|
rdataset = NULL;
|
|
|
|
node = NULL;
|
|
|
|
dns_fixedname_init(&foundname);
|
|
|
|
fname = dns_fixedname_name(&foundname);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get resources and make 'name' be the database origin.
|
|
|
|
*/
|
|
|
|
result = dns_message_gettempname(client->message, &name);
|
1999-12-24 00:43:46 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
CTRACE("query_addns: dns_message_gettempname failed: done");
|
1999-09-17 21:59:55 +00:00
|
|
|
return (result);
|
1999-12-24 00:43:46 +00:00
|
|
|
}
|
1999-09-17 21:59:55 +00:00
|
|
|
dns_name_init(name, NULL);
|
|
|
|
dns_name_clone(dns_db_origin(db), name);
|
|
|
|
rdataset = query_newrdataset(client);
|
|
|
|
sigrdataset = query_newrdataset(client);
|
|
|
|
if (rdataset == NULL || sigrdataset == NULL) {
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addns: query_newrdataset failed");
|
1999-09-17 21:59:55 +00:00
|
|
|
eresult = DNS_R_SERVFAIL;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the NS rdataset.
|
|
|
|
*/
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addns: calling dns_db_find");
|
2000-07-25 01:06:18 +00:00
|
|
|
result = dns_db_find(db, name, NULL, dns_rdatatype_ns,
|
|
|
|
client->query.dboptions, 0, &node,
|
1999-09-17 21:59:55 +00:00
|
|
|
fname, rdataset, sigrdataset);
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addns: dns_db_find complete");
|
1999-09-17 21:59:55 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addns: dns_db_find failed");
|
1999-09-17 21:59:55 +00:00
|
|
|
/*
|
|
|
|
* This is bad. We tried to get the NS rdataset at the zone
|
|
|
|
* top and it didn't work!
|
|
|
|
*/
|
|
|
|
eresult = DNS_R_SERVFAIL;
|
|
|
|
} else {
|
|
|
|
query_addrrset(client, &name, &rdataset, &sigrdataset, NULL,
|
1999-10-19 20:22:38 +00:00
|
|
|
DNS_SECTION_AUTHORITY);
|
1999-09-17 21:59:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addns: cleanup");
|
1999-09-17 21:59:55 +00:00
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
query_putrdataset(client, &sigrdataset);
|
|
|
|
if (name != NULL)
|
|
|
|
query_releasename(client, &name);
|
|
|
|
if (node != NULL)
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addns: done");
|
1999-09-17 21:59:55 +00:00
|
|
|
return (eresult);
|
|
|
|
}
|
|
|
|
|
1999-10-20 23:22:04 +00:00
|
|
|
static inline isc_result_t
|
|
|
|
query_addcname(ns_client_t *client, dns_name_t *qname, dns_name_t *tname,
|
|
|
|
dns_ttl_t ttl, dns_name_t **anamep)
|
|
|
|
{
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
dns_rdatalist_t *rdatalist;
|
|
|
|
dns_rdata_t *rdata;
|
|
|
|
isc_result_t result;
|
|
|
|
isc_region_t r;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addcname");
|
1999-10-20 23:22:04 +00:00
|
|
|
/*
|
|
|
|
* We assume the name data referred to by qname and tname won't
|
|
|
|
* go away.
|
|
|
|
*/
|
|
|
|
|
|
|
|
REQUIRE(anamep != NULL);
|
|
|
|
|
|
|
|
rdatalist = NULL;
|
|
|
|
result = dns_message_gettemprdatalist(client->message, &rdatalist);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
rdata = NULL;
|
|
|
|
result = dns_message_gettemprdata(client->message, &rdata);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
rdataset = NULL;
|
|
|
|
result = dns_message_gettemprdataset(client->message, &rdataset);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
return (result);
|
|
|
|
dns_rdataset_init(rdataset);
|
|
|
|
dns_name_clone(qname, *anamep);
|
|
|
|
|
|
|
|
rdatalist->type = dns_rdatatype_cname;
|
|
|
|
rdatalist->covers = 0;
|
|
|
|
rdatalist->rdclass = client->message->rdclass;
|
|
|
|
rdatalist->ttl = ttl;
|
|
|
|
|
|
|
|
dns_name_toregion(tname, &r);
|
|
|
|
rdata->data = r.base;
|
|
|
|
rdata->length = r.length;
|
2000-07-10 18:33:25 +00:00
|
|
|
rdata->rdclass = client->message->rdclass;
|
|
|
|
rdata->type = dns_rdatatype_cname;
|
1999-10-20 23:22:04 +00:00
|
|
|
|
|
|
|
ISC_LIST_INIT(rdatalist->rdata);
|
|
|
|
ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
|
|
|
|
dns_rdatalist_tordataset(rdatalist, rdataset);
|
|
|
|
|
|
|
|
query_addrrset(client, anamep, &rdataset, NULL, NULL,
|
|
|
|
DNS_SECTION_ANSWER);
|
|
|
|
|
|
|
|
if (rdataset != NULL) {
|
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
dns_message_puttemprdataset(client->message, &rdataset);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-10-21 17:49:55 +00:00
|
|
|
static void
|
|
|
|
query_addbestns(ns_client_t *client) {
|
|
|
|
dns_db_t *db, *zdb;
|
|
|
|
dns_dbnode_t *node;
|
|
|
|
dns_name_t *fname, *zfname;
|
|
|
|
dns_rdataset_t *rdataset, *sigrdataset, *zrdataset, *zsigrdataset;
|
|
|
|
isc_boolean_t is_zone, use_zone;
|
|
|
|
isc_buffer_t *dbuf;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_dbversion_t *version;
|
|
|
|
dns_zone_t *zone;
|
|
|
|
isc_buffer_t b;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_addbestns");
|
1999-10-21 17:49:55 +00:00
|
|
|
fname = NULL;
|
|
|
|
zfname = NULL;
|
|
|
|
rdataset = NULL;
|
|
|
|
zrdataset = NULL;
|
|
|
|
sigrdataset = NULL;
|
|
|
|
zsigrdataset = NULL;
|
|
|
|
node = NULL;
|
|
|
|
db = NULL;
|
|
|
|
zdb = NULL;
|
|
|
|
version = NULL;
|
|
|
|
zone = NULL;
|
2000-04-25 21:58:17 +00:00
|
|
|
is_zone = ISC_FALSE;
|
1999-10-21 17:49:55 +00:00
|
|
|
use_zone = ISC_FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the right database.
|
|
|
|
*/
|
2000-04-25 21:58:17 +00:00
|
|
|
result = query_getdb(client, client->query.qname, 0, &zone, &db,
|
|
|
|
&version, &is_zone);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
1999-10-21 17:49:55 +00:00
|
|
|
goto cleanup;
|
2000-04-25 21:58:17 +00:00
|
|
|
|
1999-10-21 17:49:55 +00:00
|
|
|
db_find:
|
|
|
|
/*
|
|
|
|
* We'll need some resources...
|
|
|
|
*/
|
|
|
|
dbuf = query_getnamebuf(client);
|
|
|
|
if (dbuf == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
fname = query_newname(client, dbuf, &b);
|
|
|
|
rdataset = query_newrdataset(client);
|
|
|
|
sigrdataset = query_newrdataset(client);
|
|
|
|
if (fname == NULL || rdataset == NULL || sigrdataset == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now look for the zonecut.
|
|
|
|
*/
|
|
|
|
if (is_zone) {
|
|
|
|
result = dns_db_find(db, client->query.qname, version,
|
2000-07-25 01:06:18 +00:00
|
|
|
dns_rdatatype_ns, client->query.dboptions,
|
1999-10-29 16:17:15 +00:00
|
|
|
client->now, &node, fname,
|
1999-10-21 17:49:55 +00:00
|
|
|
rdataset, sigrdataset);
|
|
|
|
if (result != DNS_R_DELEGATION)
|
|
|
|
goto cleanup;
|
|
|
|
if (USECACHE(client)) {
|
|
|
|
query_keepname(client, fname, dbuf);
|
|
|
|
zdb = db;
|
|
|
|
zfname = fname;
|
|
|
|
zrdataset = rdataset;
|
|
|
|
zsigrdataset = sigrdataset;
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
version = NULL;
|
|
|
|
db = NULL;
|
|
|
|
dns_db_attach(client->view->cachedb, &db);
|
|
|
|
is_zone = ISC_FALSE;
|
|
|
|
goto db_find;
|
|
|
|
}
|
|
|
|
} else {
|
2000-07-25 01:06:18 +00:00
|
|
|
result = dns_db_findzonecut(db, client->query.qname,
|
|
|
|
client->query.dboptions,
|
1999-10-29 16:17:15 +00:00
|
|
|
client->now, &node, fname,
|
1999-10-21 17:49:55 +00:00
|
|
|
rdataset, sigrdataset);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
if (zfname != NULL &&
|
|
|
|
!dns_name_issubdomain(fname, zfname)) {
|
|
|
|
/*
|
|
|
|
* We found a zonecut in the cache, but our
|
|
|
|
* zone delegation is better.
|
|
|
|
*/
|
|
|
|
use_zone = ISC_TRUE;
|
|
|
|
}
|
|
|
|
} else if (result == ISC_R_NOTFOUND && zfname != NULL) {
|
|
|
|
/*
|
|
|
|
* We didn't find anything in the cache, but we
|
|
|
|
* have a zone delegation, so use it.
|
|
|
|
*/
|
|
|
|
use_zone = ISC_TRUE;
|
|
|
|
} else
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (use_zone) {
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
fname = zfname;
|
|
|
|
zfname = NULL;
|
|
|
|
/*
|
|
|
|
* We've already done query_keepname() on
|
|
|
|
* zfname, so we must set dbuf to NULL to
|
|
|
|
* prevent query_addrrset() from trying to
|
|
|
|
* call query_keepname() again.
|
|
|
|
*/
|
|
|
|
dbuf = NULL;
|
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
query_putrdataset(client, &sigrdataset);
|
|
|
|
rdataset = zrdataset;
|
|
|
|
zrdataset = NULL;
|
|
|
|
sigrdataset = zsigrdataset;
|
|
|
|
zsigrdataset = NULL;
|
|
|
|
}
|
|
|
|
|
2000-07-25 01:06:18 +00:00
|
|
|
if ((client->query.dboptions & DNS_DBFIND_PENDINGOK) == 0 &&
|
2000-07-18 22:24:45 +00:00
|
|
|
(rdataset->trust == dns_trust_pending ||
|
|
|
|
sigrdataset->trust == dns_trust_pending))
|
2000-04-11 18:43:27 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
1999-10-21 17:49:55 +00:00
|
|
|
query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
|
|
|
|
DNS_SECTION_AUTHORITY);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
query_putrdataset(client, &sigrdataset);
|
|
|
|
if (fname != NULL)
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
if (node != NULL)
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
if (db != NULL)
|
|
|
|
dns_db_detach(&db);
|
|
|
|
if (zone != NULL)
|
|
|
|
dns_zone_detach(&zone);
|
|
|
|
if (zdb != NULL) {
|
|
|
|
query_putrdataset(client, &zrdataset);
|
|
|
|
query_putrdataset(client, &zsigrdataset);
|
|
|
|
if (zfname != NULL)
|
|
|
|
query_releasename(client, &zfname);
|
|
|
|
dns_db_detach(&zdb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
static inline isc_result_t
|
|
|
|
query_checktype(dns_rdatatype_t type) {
|
|
|
|
|
|
|
|
/*
|
1999-08-31 22:14:06 +00:00
|
|
|
* XXXRTH OPT still needs to be added.
|
1999-08-12 07:54:08 +00:00
|
|
|
* Should get help with this from rdata.c
|
|
|
|
*/
|
|
|
|
switch (type) {
|
|
|
|
case dns_rdatatype_tkey:
|
|
|
|
return (DNS_R_NOTIMP);
|
|
|
|
case dns_rdatatype_tsig:
|
|
|
|
return (DNS_R_FORMERR);
|
|
|
|
case dns_rdatatype_ixfr:
|
|
|
|
case dns_rdatatype_axfr:
|
|
|
|
case dns_rdatatype_mailb:
|
|
|
|
case dns_rdatatype_maila:
|
|
|
|
return (DNS_R_REFUSED);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-10-07 19:44:22 +00:00
|
|
|
static void
|
|
|
|
query_resume(isc_task_t *task, isc_event_t *event) {
|
|
|
|
dns_fetchevent_t *devent = (dns_fetchevent_t *)event;
|
|
|
|
ns_client_t *client;
|
2000-01-06 01:09:27 +00:00
|
|
|
isc_boolean_t fetch_cancelled, client_shuttingdown;
|
1999-10-07 19:44:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Resume a query after recursion.
|
|
|
|
*/
|
|
|
|
|
2000-04-28 01:24:18 +00:00
|
|
|
UNUSED(task);
|
|
|
|
|
2000-04-17 19:22:44 +00:00
|
|
|
REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
|
|
|
|
client = devent->ev_arg;
|
1999-10-07 19:44:22 +00:00
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(task == client->task);
|
|
|
|
REQUIRE(RECURSING(client));
|
|
|
|
|
2000-01-06 01:09:27 +00:00
|
|
|
if (devent->fetch != NULL) {
|
1999-10-20 01:58:48 +00:00
|
|
|
/*
|
|
|
|
* This is the fetch we've been waiting for.
|
|
|
|
*/
|
2000-01-06 01:09:27 +00:00
|
|
|
INSIST(devent->fetch == client->query.fetch);
|
1999-10-20 01:58:48 +00:00
|
|
|
client->query.fetch = NULL;
|
2000-01-06 01:09:27 +00:00
|
|
|
fetch_cancelled = ISC_FALSE;
|
1999-10-29 16:17:15 +00:00
|
|
|
/*
|
2000-01-06 01:09:27 +00:00
|
|
|
* Update client->now.
|
1999-10-29 16:17:15 +00:00
|
|
|
*/
|
2000-01-06 01:09:27 +00:00
|
|
|
isc_stdtime_get(&client->now);
|
1999-10-20 01:58:48 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* This is a fetch completion event for a cancelled fetch.
|
|
|
|
* Clean up and don't resume the find.
|
|
|
|
*/
|
2000-01-06 01:09:27 +00:00
|
|
|
fetch_cancelled = ISC_TRUE;
|
1999-10-20 01:58:48 +00:00
|
|
|
}
|
2000-01-06 01:09:27 +00:00
|
|
|
INSIST(client->query.fetch == NULL);
|
1999-10-20 01:58:48 +00:00
|
|
|
|
1999-10-17 19:27:04 +00:00
|
|
|
client->query.attributes &= ~NS_QUERYATTR_RECURSING;
|
2000-01-21 02:51:09 +00:00
|
|
|
dns_resolver_destroyfetch(&devent->fetch);
|
1999-10-17 19:27:04 +00:00
|
|
|
|
1999-10-07 19:44:22 +00:00
|
|
|
/*
|
2000-01-06 01:09:27 +00:00
|
|
|
* If this client is shutting down, or this transaction
|
|
|
|
* has timed out, do not resume the find.
|
1999-10-07 19:44:22 +00:00
|
|
|
*/
|
2000-01-06 01:09:27 +00:00
|
|
|
client_shuttingdown = ns_client_shuttingdown(client);
|
|
|
|
if (fetch_cancelled || client_shuttingdown) {
|
|
|
|
if (devent->node != NULL)
|
|
|
|
dns_db_detachnode(devent->db, &devent->node);
|
|
|
|
if (devent->db != NULL)
|
|
|
|
dns_db_detach(&devent->db);
|
|
|
|
query_putrdataset(client, &devent->rdataset);
|
|
|
|
query_putrdataset(client, &devent->sigrdataset);
|
|
|
|
isc_event_free(&event);
|
2000-02-10 22:16:56 +00:00
|
|
|
ns_client_next(client, ISC_R_CANCELED);
|
2000-05-24 05:10:00 +00:00
|
|
|
/*
|
|
|
|
* This may destroy the client.
|
|
|
|
*/
|
2000-02-11 20:56:19 +00:00
|
|
|
ns_client_detach(&client);
|
2000-01-06 01:09:27 +00:00
|
|
|
} else {
|
2000-01-27 01:00:16 +00:00
|
|
|
RWLOCK(&ns_g_server->conflock, isc_rwlocktype_read);
|
2000-05-24 05:10:00 +00:00
|
|
|
dns_zonemgr_lockconf(ns_g_server->zonemgr,
|
|
|
|
isc_rwlocktype_read);
|
2000-01-27 01:00:16 +00:00
|
|
|
dns_view_attach(client->view, &client->lockview);
|
|
|
|
RWLOCK(&client->lockview->conflock, isc_rwlocktype_read);
|
|
|
|
|
1999-10-20 01:58:48 +00:00
|
|
|
query_find(client, devent);
|
2000-01-27 01:00:16 +00:00
|
|
|
|
|
|
|
RWUNLOCK(&client->lockview->conflock, isc_rwlocktype_read);
|
|
|
|
dns_view_detach(&client->lockview);
|
2000-05-24 05:10:00 +00:00
|
|
|
dns_zonemgr_unlockconf(ns_g_server->zonemgr,
|
|
|
|
isc_rwlocktype_read);
|
2000-01-27 01:00:16 +00:00
|
|
|
RWUNLOCK(&ns_g_server->conflock, isc_rwlocktype_read);
|
2000-01-06 01:09:27 +00:00
|
|
|
}
|
1999-10-07 19:44:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
|
|
|
|
dns_rdataset_t *nameservers)
|
|
|
|
{
|
|
|
|
isc_result_t result;
|
|
|
|
dns_rdataset_t *rdataset, *sigrdataset;
|
|
|
|
|
|
|
|
/*
|
2000-01-15 00:36:47 +00:00
|
|
|
* We are about to recurse, which means that this client will
|
|
|
|
* be unavailable for serving new requests for an indeterminate
|
|
|
|
* amount of time. If this client is currently responsible
|
|
|
|
* for handling incoming queries, set up a new client
|
|
|
|
* object to handle them while we are waiting for a
|
|
|
|
* response.
|
1999-10-07 19:44:22 +00:00
|
|
|
*/
|
2000-01-15 00:36:47 +00:00
|
|
|
if (! client->mortal) {
|
|
|
|
result = isc_quota_attach(&ns_g_server->recursionquota,
|
|
|
|
&client->recursionquota);
|
|
|
|
if (result == ISC_R_SUCCESS)
|
|
|
|
result = ns_client_replace(client);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-04-04 19:14:05 +00:00
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
2000-01-15 00:36:47 +00:00
|
|
|
NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
|
|
|
|
"no more recursive clients: %s",
|
|
|
|
isc_result_totext(result));
|
|
|
|
return (result);
|
|
|
|
}
|
2000-01-11 21:18:22 +00:00
|
|
|
}
|
1999-10-07 19:44:22 +00:00
|
|
|
|
2000-01-11 21:18:22 +00:00
|
|
|
/*
|
|
|
|
* Invoke the resolver.
|
|
|
|
*/
|
2000-07-06 02:27:26 +00:00
|
|
|
REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns);
|
1999-10-07 19:44:22 +00:00
|
|
|
REQUIRE(client->query.fetch == NULL);
|
|
|
|
|
|
|
|
rdataset = query_newrdataset(client);
|
|
|
|
if (rdataset == NULL)
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
sigrdataset = query_newrdataset(client);
|
|
|
|
if (rdataset == NULL) {
|
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
return (ISC_R_NOMEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
result = dns_resolver_createfetch(client->view->resolver,
|
|
|
|
client->query.qname,
|
|
|
|
qtype, qdomain, nameservers,
|
2000-07-25 21:37:05 +00:00
|
|
|
NULL, client->query.fetchoptions,
|
|
|
|
client->task,
|
1999-11-16 21:08:59 +00:00
|
|
|
query_resume, client,
|
|
|
|
rdataset, sigrdataset,
|
1999-10-07 19:44:22 +00:00
|
|
|
&client->query.fetch);
|
|
|
|
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* Record that we're waiting for an event. A client which
|
|
|
|
* is shutting down will not be destroyed until all the
|
|
|
|
* events have been received.
|
|
|
|
*/
|
|
|
|
} else {
|
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
query_putrdataset(client, &sigrdataset);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2000-04-25 21:58:17 +00:00
|
|
|
static inline isc_result_t
|
|
|
|
query_findparentkey(ns_client_t *client, dns_name_t *name,
|
|
|
|
dns_zone_t **zonep, dns_db_t **dbp,
|
|
|
|
dns_dbversion_t **versionp, dns_dbnode_t **nodep,
|
|
|
|
dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
|
|
|
|
{
|
|
|
|
dns_db_t *pdb;
|
|
|
|
dns_dbnode_t *pnode;
|
|
|
|
dns_dbversion_t *pversion;
|
|
|
|
dns_rdataset_t prdataset, psigrdataset;
|
|
|
|
isc_result_t result;
|
|
|
|
dns_zone_t *pzone;
|
|
|
|
isc_boolean_t is_zone;
|
|
|
|
dns_fixedname_t pfoundname;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 'name' is at a zone cut. Try to find a KEY for 'name' in
|
|
|
|
* the deepest ancestor zone of 'name' (if any). If it exists,
|
|
|
|
* update *zonep, *dbp, *nodep, rdataset, and sigrdataset and
|
|
|
|
* return ISC_R_SUCCESS. If not, leave them alone and return a
|
|
|
|
* non-success status.
|
|
|
|
*/
|
|
|
|
|
|
|
|
pzone = NULL;
|
|
|
|
pdb = NULL;
|
|
|
|
pnode = NULL;
|
|
|
|
pversion = NULL;
|
|
|
|
dns_rdataset_init(&prdataset);
|
|
|
|
dns_rdataset_init(&psigrdataset);
|
|
|
|
is_zone = ISC_FALSE;
|
|
|
|
dns_fixedname_init(&pfoundname);
|
|
|
|
|
2000-06-15 04:42:01 +00:00
|
|
|
result = query_getdb(client, name, DNS_GETDB_NOEXACT,
|
2000-04-25 21:58:17 +00:00
|
|
|
&pzone, &pdb, &pversion, &is_zone);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
if (!is_zone) {
|
|
|
|
result = ISC_R_FAILURE;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2000-07-25 01:06:18 +00:00
|
|
|
result = dns_db_find(pdb, name, pversion, dns_rdatatype_key,
|
|
|
|
client->query.dboptions,
|
2000-04-25 21:58:17 +00:00
|
|
|
client->now, &pnode,
|
|
|
|
dns_fixedname_name(&pfoundname),
|
|
|
|
&prdataset, &psigrdataset);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
if (dns_rdataset_isassociated(rdataset))
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
if (dns_rdataset_isassociated(sigrdataset))
|
|
|
|
dns_rdataset_disassociate(sigrdataset);
|
|
|
|
dns_rdataset_clone(&prdataset, rdataset);
|
|
|
|
if (dns_rdataset_isassociated(&psigrdataset))
|
|
|
|
dns_rdataset_clone(&psigrdataset, sigrdataset);
|
|
|
|
if (*nodep != NULL)
|
|
|
|
dns_db_detachnode(*dbp, nodep);
|
|
|
|
*nodep = pnode;
|
|
|
|
pnode = NULL;
|
|
|
|
*versionp = pversion;
|
|
|
|
if (*dbp != NULL)
|
|
|
|
dns_db_detach(dbp);
|
|
|
|
*dbp = pdb;
|
|
|
|
pdb = NULL;
|
|
|
|
if (*zonep != NULL)
|
|
|
|
dns_zone_detach(zonep);
|
|
|
|
*zonep = pzone;
|
|
|
|
pzone = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (dns_rdataset_isassociated(&prdataset))
|
|
|
|
dns_rdataset_disassociate(&prdataset);
|
|
|
|
if (dns_rdataset_isassociated(&psigrdataset))
|
|
|
|
dns_rdataset_disassociate(&psigrdataset);
|
|
|
|
if (pnode != NULL)
|
|
|
|
dns_db_detachnode(pdb, &pnode);
|
|
|
|
if (pdb != NULL)
|
|
|
|
dns_db_detach(&pdb);
|
|
|
|
if (pzone != NULL)
|
|
|
|
dns_zone_detach(&pzone);
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
1999-10-07 19:44:22 +00:00
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
#define MAX_RESTARTS 16
|
|
|
|
|
|
|
|
#define QUERY_ERROR(r) \
|
|
|
|
do { \
|
|
|
|
eresult = r; \
|
|
|
|
want_restart = ISC_FALSE; \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
static void
|
1999-10-07 19:44:22 +00:00
|
|
|
query_find(ns_client_t *client, dns_fetchevent_t *event) {
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_db_t *db, *zdb;
|
1999-08-12 07:54:08 +00:00
|
|
|
dns_dbnode_t *node;
|
|
|
|
dns_rdatatype_t qtype, type;
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_name_t *fname, *zfname, *tname, *prefix;
|
1999-10-11 19:12:43 +00:00
|
|
|
dns_rdataset_t *rdataset, *trdataset;
|
1999-09-13 18:26:37 +00:00
|
|
|
dns_rdataset_t *sigrdataset, *zrdataset, *zsigrdataset;
|
1999-08-12 07:54:08 +00:00
|
|
|
dns_rdata_t rdata;
|
1999-07-24 01:17:44 +00:00
|
|
|
dns_rdatasetiter_t *rdsiter;
|
2000-04-13 19:34:02 +00:00
|
|
|
isc_boolean_t want_restart, authoritative, is_zone;
|
1999-09-17 21:59:55 +00:00
|
|
|
unsigned int qcount, n, nlabels, nbits;
|
1999-08-12 07:54:08 +00:00
|
|
|
dns_namereln_t namereln;
|
|
|
|
int order;
|
1999-09-02 02:10:44 +00:00
|
|
|
isc_buffer_t *dbuf;
|
1999-07-28 02:20:36 +00:00
|
|
|
isc_region_t r;
|
|
|
|
isc_buffer_t b;
|
1999-08-12 07:54:08 +00:00
|
|
|
isc_result_t result, eresult;
|
|
|
|
dns_fixedname_t fixed;
|
1999-08-18 04:23:39 +00:00
|
|
|
dns_dbversion_t *version;
|
1999-10-14 01:37:00 +00:00
|
|
|
dns_zone_t *zone;
|
1999-07-24 01:17:44 +00:00
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_find");
|
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* One-time initialization.
|
1999-08-05 01:51:32 +00:00
|
|
|
*
|
1999-08-12 07:54:08 +00:00
|
|
|
* It's especially important to initialize anything that the cleanup
|
|
|
|
* code might cleanup.
|
1999-08-05 01:51:32 +00:00
|
|
|
*/
|
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
eresult = ISC_R_SUCCESS;
|
|
|
|
fname = NULL;
|
1999-09-13 18:26:37 +00:00
|
|
|
zfname = NULL;
|
1999-08-12 07:54:08 +00:00
|
|
|
rdataset = NULL;
|
1999-09-13 18:26:37 +00:00
|
|
|
zrdataset = NULL;
|
1999-08-31 22:14:06 +00:00
|
|
|
sigrdataset = NULL;
|
1999-09-13 18:26:37 +00:00
|
|
|
zsigrdataset = NULL;
|
1999-08-12 07:54:08 +00:00
|
|
|
node = NULL;
|
|
|
|
db = NULL;
|
1999-09-13 18:26:37 +00:00
|
|
|
zdb = NULL;
|
1999-08-18 04:23:39 +00:00
|
|
|
version = NULL;
|
1999-10-14 01:37:00 +00:00
|
|
|
zone = NULL;
|
1999-10-07 19:44:22 +00:00
|
|
|
|
|
|
|
if (event != NULL) {
|
|
|
|
/*
|
|
|
|
* We're returning from recursion. Restore the query context
|
|
|
|
* and resume.
|
|
|
|
*/
|
|
|
|
|
|
|
|
want_restart = ISC_FALSE;
|
|
|
|
authoritative = ISC_FALSE;
|
|
|
|
is_zone = ISC_FALSE;
|
|
|
|
|
1999-10-16 20:50:33 +00:00
|
|
|
qtype = event->qtype;
|
1999-10-07 19:44:22 +00:00
|
|
|
if (qtype == dns_rdatatype_sig)
|
|
|
|
type = dns_rdatatype_any;
|
|
|
|
else
|
|
|
|
type = qtype;
|
|
|
|
db = event->db;
|
|
|
|
node = event->node;
|
|
|
|
rdataset = event->rdataset;
|
|
|
|
sigrdataset = event->sigrdataset;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We'll need some resources...
|
|
|
|
*/
|
|
|
|
dbuf = query_getnamebuf(client);
|
|
|
|
if (dbuf == NULL) {
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
fname = query_newname(client, dbuf, &b);
|
|
|
|
if (fname == NULL) {
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
1999-10-11 19:12:43 +00:00
|
|
|
tname = dns_fixedname_name(&event->foundname);
|
|
|
|
result = dns_name_concatenate(tname, NULL, fname, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
1999-10-07 19:44:22 +00:00
|
|
|
|
1999-10-13 02:08:19 +00:00
|
|
|
result = event->result;
|
1999-10-07 19:44:22 +00:00
|
|
|
|
|
|
|
goto resume;
|
1999-10-11 19:12:43 +00:00
|
|
|
} else
|
|
|
|
client->query.qrdataset = NULL;
|
1999-08-12 07:54:08 +00:00
|
|
|
|
|
|
|
restart:
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_find: restart");
|
1999-08-12 07:54:08 +00:00
|
|
|
want_restart = ISC_FALSE;
|
1999-10-07 19:44:22 +00:00
|
|
|
authoritative = ISC_FALSE;
|
2000-04-25 21:58:17 +00:00
|
|
|
version = NULL;
|
1999-07-28 02:20:36 +00:00
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
/*
|
1999-08-12 07:54:08 +00:00
|
|
|
* First we must find the right database.
|
1999-07-24 01:17:44 +00:00
|
|
|
*/
|
2000-04-25 21:58:17 +00:00
|
|
|
result = query_getdb(client, client->query.qname, 0, &zone, &db,
|
|
|
|
&version, &is_zone);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
if (result == DNS_R_REFUSED)
|
1999-08-12 07:54:08 +00:00
|
|
|
QUERY_ERROR(DNS_R_REFUSED);
|
2000-04-25 21:58:17 +00:00
|
|
|
else
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
1999-08-12 07:54:08 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2000-02-22 21:24:24 +00:00
|
|
|
if (is_zone)
|
2000-04-25 21:58:17 +00:00
|
|
|
authoritative = ISC_TRUE;
|
1999-12-10 18:15:32 +00:00
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* Find the first unanswered type in the question section.
|
|
|
|
*/
|
1999-10-17 19:27:04 +00:00
|
|
|
qtype = 0;
|
|
|
|
qcount = 0;
|
|
|
|
client->query.qrdataset = NULL;
|
1999-08-12 07:54:08 +00:00
|
|
|
for (trdataset = ISC_LIST_HEAD(client->query.origqname->list);
|
|
|
|
trdataset != NULL;
|
|
|
|
trdataset = ISC_LIST_NEXT(trdataset, link)) {
|
|
|
|
if (!ANSWERED(trdataset)) {
|
1999-10-11 19:12:43 +00:00
|
|
|
if (client->query.qrdataset == NULL) {
|
|
|
|
client->query.qrdataset = trdataset;
|
1999-08-12 07:54:08 +00:00
|
|
|
qtype = trdataset->type;
|
|
|
|
}
|
|
|
|
qcount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We had better have found something!
|
|
|
|
*/
|
1999-10-11 19:12:43 +00:00
|
|
|
INSIST(client->query.qrdataset != NULL && qcount > 0);
|
1999-10-17 19:27:04 +00:00
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
1999-10-17 19:27:04 +00:00
|
|
|
* If there's more than one question, we'll eventually retrieve the
|
|
|
|
* node and iterate it, trying to find answers. For now, we simply
|
|
|
|
* refuse requests with more than one question.
|
1999-08-12 07:54:08 +00:00
|
|
|
*/
|
|
|
|
if (qcount == 1)
|
|
|
|
type = qtype;
|
|
|
|
else {
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("find_query: REFUSED: qcount != 1");
|
1999-10-17 19:27:04 +00:00
|
|
|
QUERY_ERROR(DNS_R_REFUSED);
|
1999-08-12 07:54:08 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if the type is OK.
|
|
|
|
*/
|
|
|
|
result = query_checktype(qtype);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("find_query: non supported query type");
|
1999-08-12 07:54:08 +00:00
|
|
|
QUERY_ERROR(result);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
1999-08-31 22:14:06 +00:00
|
|
|
/*
|
|
|
|
* If it's a SIG query, we'll iterate the node.
|
|
|
|
*/
|
|
|
|
if (qtype == dns_rdatatype_sig)
|
|
|
|
type = dns_rdatatype_any;
|
|
|
|
|
1999-09-13 18:26:37 +00:00
|
|
|
db_find:
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_find: db_find");
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* We'll need some resources...
|
|
|
|
*/
|
|
|
|
dbuf = query_getnamebuf(client);
|
|
|
|
if (dbuf == NULL) {
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
fname = query_newname(client, dbuf, &b);
|
|
|
|
rdataset = query_newrdataset(client);
|
1999-08-31 22:14:06 +00:00
|
|
|
sigrdataset = query_newrdataset(client);
|
|
|
|
if (fname == NULL || rdataset == NULL || sigrdataset == NULL) {
|
1999-08-12 07:54:08 +00:00
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* Now look for an answer in the database.
|
|
|
|
*/
|
2000-07-25 01:06:18 +00:00
|
|
|
result = dns_db_find(db, client->query.qname, version, type,
|
|
|
|
client->query.dboptions, client->now,
|
|
|
|
&node, fname, rdataset, sigrdataset);
|
1999-10-11 19:12:43 +00:00
|
|
|
|
2000-04-25 21:58:17 +00:00
|
|
|
/*
|
|
|
|
* We interrupt our normal query processing to bring you this special
|
|
|
|
* case...
|
|
|
|
*
|
|
|
|
* RFC 2535 (DNSSEC), section 2.3.4, discusses various special
|
|
|
|
* cases that can occur at delegation points.
|
|
|
|
*
|
|
|
|
* One of these cases is that the NULL KEY for an unsecure zone
|
|
|
|
* may occur in the delegating zone instead of in the delegated zone.
|
|
|
|
* If we're authoritative for both zones, we need to look for the
|
|
|
|
* key in the delegator if we didn't find it in the delegatee. If
|
|
|
|
* we didn't do this, a client doing DNSSEC validation could fail
|
|
|
|
* because it couldn't get the NULL KEY.
|
|
|
|
*/
|
|
|
|
if (type == dns_rdatatype_key &&
|
|
|
|
is_zone &&
|
|
|
|
result == DNS_R_NXRRSET &&
|
|
|
|
!dns_db_issecure(db) &&
|
|
|
|
dns_name_equal(client->query.qname, dns_db_origin(db))) {
|
|
|
|
/*
|
|
|
|
* We're looking for a KEY at the top of an unsecure zone,
|
|
|
|
* and we didn't find it.
|
|
|
|
*/
|
|
|
|
result = query_findparentkey(client, client->query.qname,
|
|
|
|
&zone, &db, &version, &node,
|
|
|
|
rdataset, sigrdataset);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* We found the parent KEY.
|
|
|
|
*
|
|
|
|
* zone, db, version, node, rdataset, and sigrdataset
|
|
|
|
* have all been updated to refer to the parent's
|
|
|
|
* data. We will resume query processing as if
|
|
|
|
* we had looked for the KEY in the parent zone in
|
|
|
|
* the first place.
|
|
|
|
*
|
|
|
|
* We need to set fname correctly. We do this here
|
|
|
|
* instead of in query_findparentkey() because
|
|
|
|
* dns_name_concatenate() can fail (though it shouldn't
|
|
|
|
* ever do so since we should have enough space).
|
|
|
|
*/
|
|
|
|
result = dns_name_concatenate(client->query.qname,
|
|
|
|
NULL, fname, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We couldn't find the KEY in a parent zone.
|
|
|
|
* Continue with processing of the original
|
|
|
|
* results of dns_db_find().
|
|
|
|
*/
|
|
|
|
result = DNS_R_NXRRSET;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-10-07 19:44:22 +00:00
|
|
|
resume:
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_find: resume");
|
1999-08-12 07:54:08 +00:00
|
|
|
switch (result) {
|
2000-04-06 22:03:35 +00:00
|
|
|
case ISC_R_SUCCESS:
|
1999-09-01 18:16:43 +00:00
|
|
|
/*
|
|
|
|
* This case is handled in the main line below.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
case DNS_R_GLUE:
|
1999-08-12 07:54:08 +00:00
|
|
|
case DNS_R_ZONECUT:
|
1999-07-28 02:20:36 +00:00
|
|
|
/*
|
1999-08-12 07:54:08 +00:00
|
|
|
* These cases are handled in the main line below.
|
1999-07-28 02:20:36 +00:00
|
|
|
*/
|
1999-09-13 18:26:37 +00:00
|
|
|
INSIST(is_zone);
|
1999-10-07 19:44:22 +00:00
|
|
|
authoritative = ISC_FALSE;
|
1999-08-12 07:54:08 +00:00
|
|
|
break;
|
2000-04-06 22:03:35 +00:00
|
|
|
case ISC_R_NOTFOUND:
|
1999-10-07 19:44:22 +00:00
|
|
|
/*
|
|
|
|
* The cache doesn't even have the root NS. Get them from
|
|
|
|
* the hints DB.
|
|
|
|
*/
|
|
|
|
INSIST(!is_zone);
|
|
|
|
INSIST(client->view->hints != NULL);
|
2000-03-17 00:07:02 +00:00
|
|
|
if (db != NULL)
|
|
|
|
dns_db_detach(&db);
|
1999-10-15 06:49:58 +00:00
|
|
|
dns_db_attach(client->view->hints, &db);
|
|
|
|
result = dns_db_find(db, dns_rootname, NULL, dns_rdatatype_ns,
|
1999-10-29 16:17:15 +00:00
|
|
|
0, client->now, &node, fname,
|
1999-10-07 19:44:22 +00:00
|
|
|
rdataset, sigrdataset);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* We can't even find the hints for the root
|
|
|
|
* nameservers!
|
|
|
|
*/
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* XXXRTH We should trigger root server priming here.
|
|
|
|
*/
|
|
|
|
/* FALLTHROUGH */
|
1999-08-12 07:54:08 +00:00
|
|
|
case DNS_R_DELEGATION:
|
1999-10-07 19:44:22 +00:00
|
|
|
authoritative = ISC_FALSE;
|
1999-08-12 07:54:08 +00:00
|
|
|
if (is_zone) {
|
|
|
|
/*
|
|
|
|
* We're authoritative for an ancestor of QNAME.
|
|
|
|
*/
|
2000-02-01 02:23:39 +00:00
|
|
|
if (!USECACHE(client) || !RECURSIONOK(client)) {
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
2000-02-01 02:23:39 +00:00
|
|
|
* If we don't have a cache, this is the best
|
1999-08-12 07:54:08 +00:00
|
|
|
* answer.
|
1999-09-01 18:16:43 +00:00
|
|
|
*
|
2000-02-01 02:23:39 +00:00
|
|
|
* If the client is making a nonrecursive
|
|
|
|
* query we always give out the authoritative
|
|
|
|
* delegation. This way even if we get
|
|
|
|
* junk in our cache, we won't fail in our
|
|
|
|
* role as the delegating authority if another
|
|
|
|
* nameserver asks us about a delegated
|
|
|
|
* subzone.
|
|
|
|
*
|
1999-09-08 01:21:01 +00:00
|
|
|
* We enable the retrieval of glue for this
|
|
|
|
* database by setting client->query.gluedb.
|
1999-08-12 07:54:08 +00:00
|
|
|
*/
|
1999-09-08 01:21:01 +00:00
|
|
|
client->query.gluedb = db;
|
1999-08-31 22:14:06 +00:00
|
|
|
query_addrrset(client, &fname, &rdataset,
|
|
|
|
&sigrdataset, dbuf,
|
1999-10-19 20:22:38 +00:00
|
|
|
DNS_SECTION_AUTHORITY);
|
1999-09-08 01:21:01 +00:00
|
|
|
client->query.gluedb = NULL;
|
1999-08-12 07:54:08 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We might have a better answer or delegation
|
|
|
|
* in the cache. We'll remember the current
|
1999-09-13 18:26:37 +00:00
|
|
|
* values of fname, rdataset, and sigrdataset.
|
|
|
|
* We'll then go looking for QNAME in the
|
|
|
|
* cache. If we find something better, we'll
|
|
|
|
* use it instead.
|
1999-08-12 07:54:08 +00:00
|
|
|
*/
|
1999-09-13 18:26:37 +00:00
|
|
|
query_keepname(client, fname, dbuf);
|
|
|
|
zdb = db;
|
|
|
|
zfname = fname;
|
|
|
|
zrdataset = rdataset;
|
|
|
|
zsigrdataset = sigrdataset;
|
|
|
|
dns_db_detachnode(db, &node);
|
|
|
|
version = NULL;
|
|
|
|
db = NULL;
|
|
|
|
dns_db_attach(client->view->cachedb, &db);
|
|
|
|
is_zone = ISC_FALSE;
|
|
|
|
goto db_find;
|
1999-08-12 07:54:08 +00:00
|
|
|
}
|
|
|
|
} else {
|
1999-09-13 18:26:37 +00:00
|
|
|
if (zfname != NULL &&
|
|
|
|
!dns_name_issubdomain(fname, zfname)) {
|
|
|
|
/*
|
|
|
|
* We've already got a delegation from
|
|
|
|
* authoritative data, and it is better
|
|
|
|
* than what we found in the cache. Use
|
|
|
|
* it instead of the cache delegation.
|
|
|
|
*/
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
fname = zfname;
|
|
|
|
zfname = NULL;
|
|
|
|
/*
|
|
|
|
* We've already done query_keepname() on
|
|
|
|
* zfname, so we must set dbuf to NULL to
|
|
|
|
* prevent query_addrrset() from trying to
|
|
|
|
* call query_keepname() again.
|
|
|
|
*/
|
|
|
|
dbuf = NULL;
|
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
query_putrdataset(client, &sigrdataset);
|
|
|
|
rdataset = zrdataset;
|
|
|
|
zrdataset = NULL;
|
|
|
|
sigrdataset = zsigrdataset;
|
|
|
|
zsigrdataset = NULL;
|
|
|
|
/*
|
|
|
|
* We don't clean up zdb here because we
|
|
|
|
* may still need it. It will get cleaned
|
|
|
|
* up by the main cleanup code.
|
|
|
|
*/
|
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
|
1999-10-07 19:44:22 +00:00
|
|
|
if (RECURSIONOK(client)) {
|
|
|
|
/*
|
|
|
|
* Recurse!
|
|
|
|
*/
|
2000-07-06 02:27:26 +00:00
|
|
|
if (type == dns_rdatatype_key)
|
|
|
|
result = query_recurse(client, qtype,
|
|
|
|
NULL, NULL);
|
|
|
|
else
|
|
|
|
result = query_recurse(client, qtype,
|
|
|
|
fname, rdataset);
|
1999-10-07 19:44:22 +00:00
|
|
|
if (result == ISC_R_SUCCESS)
|
|
|
|
client->query.attributes |=
|
|
|
|
NS_QUERYATTR_RECURSING;
|
|
|
|
else
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
} else {
|
1999-09-13 18:26:37 +00:00
|
|
|
/*
|
|
|
|
* This is the best answer.
|
|
|
|
*/
|
|
|
|
client->query.gluedb = zdb;
|
1999-10-25 21:21:55 +00:00
|
|
|
client->query.attributes |=
|
|
|
|
NS_QUERYATTR_CACHEGLUEOK;
|
1999-09-13 18:26:37 +00:00
|
|
|
query_addrrset(client, &fname,
|
|
|
|
&rdataset, &sigrdataset,
|
1999-10-19 20:22:38 +00:00
|
|
|
dbuf, DNS_SECTION_AUTHORITY);
|
1999-09-13 18:26:37 +00:00
|
|
|
client->query.gluedb = NULL;
|
1999-10-25 21:21:55 +00:00
|
|
|
client->query.attributes &=
|
|
|
|
~NS_QUERYATTR_CACHEGLUEOK;
|
1999-09-13 18:26:37 +00:00
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
goto cleanup;
|
2000-04-06 22:03:35 +00:00
|
|
|
case DNS_R_NXRRSET:
|
1999-08-12 07:54:08 +00:00
|
|
|
INSIST(is_zone);
|
1999-08-19 20:46:59 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset)) {
|
|
|
|
/*
|
|
|
|
* If we've got a NXT record, we need to save the
|
|
|
|
* name now because we're going call query_addsoa()
|
|
|
|
* below, and it needs to use the name buffer.
|
|
|
|
*/
|
|
|
|
query_keepname(client, fname, dbuf);
|
|
|
|
/*
|
|
|
|
* We don't want the cleanup code to try to release
|
|
|
|
* fname if we fail below, so we set it to NULL.
|
|
|
|
*/
|
|
|
|
tname = fname;
|
|
|
|
fname = NULL;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We're not going to use fname, and need to release
|
|
|
|
* our hold on the name buffer so query_addsoa()
|
|
|
|
* may use it.
|
|
|
|
*/
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* Add SOA.
|
|
|
|
*/
|
|
|
|
result = query_addsoa(client, db);
|
1999-08-03 20:56:08 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
1999-08-12 07:54:08 +00:00
|
|
|
QUERY_ERROR(result);
|
|
|
|
goto cleanup;
|
1999-08-03 20:56:08 +00:00
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
1999-08-19 20:46:59 +00:00
|
|
|
* Add NXT record if we found one.
|
1999-08-12 07:54:08 +00:00
|
|
|
*/
|
1999-12-14 00:39:57 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset)) {
|
1999-08-31 22:14:06 +00:00
|
|
|
query_addrrset(client, &tname, &rdataset, &sigrdataset,
|
1999-10-19 20:22:38 +00:00
|
|
|
NULL, DNS_SECTION_AUTHORITY);
|
1999-12-14 00:39:57 +00:00
|
|
|
if (tname != NULL)
|
|
|
|
dns_message_puttempname(client->message,
|
|
|
|
&tname);
|
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
goto cleanup;
|
|
|
|
case DNS_R_NXDOMAIN:
|
1999-09-13 18:26:37 +00:00
|
|
|
INSIST(is_zone);
|
1999-09-17 21:59:55 +00:00
|
|
|
if (client->query.restarts > 0) {
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* We hit a dead end following a CNAME or DNAME.
|
|
|
|
*/
|
|
|
|
goto cleanup;
|
1999-08-03 20:56:08 +00:00
|
|
|
}
|
1999-08-26 07:14:06 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset)) {
|
|
|
|
/*
|
|
|
|
* If we've got a NXT record, we need to save the
|
|
|
|
* name now because we're going call query_addsoa()
|
|
|
|
* below, and it needs to use the name buffer.
|
|
|
|
*/
|
|
|
|
query_keepname(client, fname, dbuf);
|
|
|
|
/*
|
|
|
|
* We don't want the cleanup code to try to release
|
|
|
|
* fname if we fail below, so we set it to NULL.
|
|
|
|
*/
|
|
|
|
tname = fname;
|
|
|
|
fname = NULL;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We're not going to use fname, and need to release
|
|
|
|
* our hold on the name buffer so query_addsoa()
|
|
|
|
* may use it.
|
|
|
|
*/
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
}
|
1999-07-28 02:20:36 +00:00
|
|
|
/*
|
1999-08-12 07:54:08 +00:00
|
|
|
* Add SOA.
|
1999-07-28 02:20:36 +00:00
|
|
|
*/
|
1999-08-12 07:54:08 +00:00
|
|
|
result = query_addsoa(client, db);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
QUERY_ERROR(result);
|
|
|
|
goto cleanup;
|
1999-07-28 02:20:36 +00:00
|
|
|
}
|
|
|
|
/*
|
1999-08-26 07:14:06 +00:00
|
|
|
* Add NXT record if we found one.
|
|
|
|
*/
|
1999-12-14 00:39:57 +00:00
|
|
|
if (dns_rdataset_isassociated(rdataset)) {
|
1999-08-31 22:14:06 +00:00
|
|
|
query_addrrset(client, &tname, &rdataset, &sigrdataset,
|
1999-10-19 20:22:38 +00:00
|
|
|
NULL, DNS_SECTION_AUTHORITY);
|
1999-12-14 00:39:57 +00:00
|
|
|
if (tname != NULL)
|
|
|
|
dns_message_puttempname(client->message,
|
|
|
|
&tname);
|
|
|
|
}
|
1999-08-26 07:14:06 +00:00
|
|
|
/*
|
|
|
|
* Set message rcode.
|
1999-07-28 02:20:36 +00:00
|
|
|
*/
|
1999-08-26 07:14:06 +00:00
|
|
|
client->message->rcode = dns_rcode_nxdomain;
|
1999-08-12 07:54:08 +00:00
|
|
|
goto cleanup;
|
1999-10-16 01:04:12 +00:00
|
|
|
case DNS_R_NCACHENXDOMAIN:
|
|
|
|
case DNS_R_NCACHENXRRSET:
|
|
|
|
INSIST(!is_zone);
|
|
|
|
authoritative = ISC_FALSE;
|
|
|
|
/*
|
|
|
|
* Set message rcode, if required.
|
|
|
|
*/
|
|
|
|
if (result == DNS_R_NCACHENXDOMAIN)
|
|
|
|
client->message->rcode = dns_rcode_nxdomain;
|
|
|
|
/*
|
|
|
|
* We don't call query_addrrset() because we don't need any
|
|
|
|
* of its extra features (and things would probably break!).
|
|
|
|
*/
|
|
|
|
query_keepname(client, fname, dbuf);
|
|
|
|
dns_message_addname(client->message, fname,
|
|
|
|
DNS_SECTION_AUTHORITY);
|
|
|
|
ISC_LIST_APPEND(fname->list, rdataset, link);
|
|
|
|
fname = NULL;
|
|
|
|
rdataset = NULL;
|
|
|
|
goto cleanup;
|
1999-08-12 07:54:08 +00:00
|
|
|
case DNS_R_CNAME:
|
1999-07-28 02:20:36 +00:00
|
|
|
/*
|
1999-08-12 07:54:08 +00:00
|
|
|
* Keep a copy of the rdataset. We have to do this because
|
|
|
|
* query_addrrset may clear 'rdataset' (to prevent the
|
|
|
|
* cleanup code from cleaning it up).
|
1999-07-28 02:20:36 +00:00
|
|
|
*/
|
1999-08-12 07:54:08 +00:00
|
|
|
trdataset = rdataset;
|
|
|
|
/*
|
|
|
|
* Add the CNAME to the answer section.
|
|
|
|
*/
|
1999-08-31 22:14:06 +00:00
|
|
|
query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
|
1999-10-19 20:22:38 +00:00
|
|
|
DNS_SECTION_ANSWER);
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* We set the PARTIALANSWER attribute so that if anything goes
|
|
|
|
* wrong later on, we'll return what we've got so far.
|
|
|
|
*/
|
|
|
|
client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
|
|
|
|
/*
|
|
|
|
* Reset qname to be the target name of the CNAME and restart
|
|
|
|
* the query.
|
|
|
|
*/
|
|
|
|
tname = NULL;
|
|
|
|
result = dns_message_gettempname(client->message, &tname);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
result = dns_rdataset_first(trdataset);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
dns_rdataset_current(trdataset, &rdata);
|
|
|
|
r.base = rdata.data;
|
|
|
|
r.length = rdata.length;
|
|
|
|
dns_name_init(tname, NULL);
|
|
|
|
dns_name_fromregion(tname, &r);
|
1999-10-07 19:44:22 +00:00
|
|
|
query_maybeputqname(client);
|
1999-08-12 07:54:08 +00:00
|
|
|
client->query.qname = tname;
|
|
|
|
want_restart = ISC_TRUE;
|
1999-09-17 21:59:55 +00:00
|
|
|
goto addauth;
|
1999-08-12 07:54:08 +00:00
|
|
|
case DNS_R_DNAME:
|
|
|
|
/*
|
|
|
|
* Compare the current qname to the found name. We need
|
|
|
|
* to know how many labels and bits are in common because
|
|
|
|
* we're going to have to split qname later on.
|
|
|
|
*/
|
|
|
|
namereln = dns_name_fullcompare(client->query.qname, fname,
|
|
|
|
&order, &nlabels, &nbits);
|
|
|
|
INSIST(namereln == dns_namereln_subdomain);
|
|
|
|
/*
|
|
|
|
* Keep a copy of the rdataset. We have to do this because
|
|
|
|
* query_addrrset may clear 'rdataset' (to prevent the
|
|
|
|
* cleanup code from cleaning it up).
|
|
|
|
*/
|
|
|
|
trdataset = rdataset;
|
|
|
|
/*
|
|
|
|
* Add the DNAME to the answer section.
|
|
|
|
*/
|
1999-08-31 22:14:06 +00:00
|
|
|
query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
|
1999-10-19 20:22:38 +00:00
|
|
|
DNS_SECTION_ANSWER);
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* We set the PARTIALANSWER attribute so that if anything goes
|
|
|
|
* wrong later on, we'll return what we've got so far.
|
|
|
|
*/
|
|
|
|
client->query.attributes |= NS_QUERYATTR_PARTIALANSWER;
|
1999-07-28 02:20:36 +00:00
|
|
|
/*
|
1999-08-12 07:54:08 +00:00
|
|
|
* Get the target name of the DNAME.
|
1999-07-28 02:20:36 +00:00
|
|
|
*/
|
1999-08-12 07:54:08 +00:00
|
|
|
tname = NULL;
|
|
|
|
result = dns_message_gettempname(client->message, &tname);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
result = dns_rdataset_first(trdataset);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
|
|
|
dns_rdataset_current(trdataset, &rdata);
|
|
|
|
r.base = rdata.data;
|
|
|
|
r.length = rdata.length;
|
|
|
|
dns_name_init(tname, NULL);
|
|
|
|
dns_name_fromregion(tname, &r);
|
|
|
|
/*
|
1999-10-20 23:22:04 +00:00
|
|
|
* Construct the new qname.
|
1999-08-12 07:54:08 +00:00
|
|
|
*/
|
|
|
|
dns_fixedname_init(&fixed);
|
|
|
|
prefix = dns_fixedname_name(&fixed);
|
|
|
|
result = dns_name_split(client->query.qname, nlabels, nbits,
|
|
|
|
prefix, NULL);
|
|
|
|
if (result != ISC_R_SUCCESS)
|
|
|
|
goto cleanup;
|
2000-04-13 19:34:02 +00:00
|
|
|
INSIST(fname == NULL);
|
1999-08-12 07:54:08 +00:00
|
|
|
dbuf = query_getnamebuf(client);
|
|
|
|
if (dbuf == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
fname = query_newname(client, dbuf, &b);
|
|
|
|
if (fname == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
result = dns_name_concatenate(prefix, tname, fname, NULL);
|
1999-08-12 20:27:24 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
1999-10-20 23:22:04 +00:00
|
|
|
dns_message_puttempname(client->message, &tname);
|
1999-08-12 20:27:24 +00:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
|
|
|
/*
|
1999-08-31 22:14:06 +00:00
|
|
|
* RFC 2672, section 4.1, subsection 3c says
|
|
|
|
* we should return YXDOMAIN if the constructed
|
1999-08-12 20:27:24 +00:00
|
|
|
* name would be too long.
|
|
|
|
*/
|
|
|
|
client->message->rcode = dns_rcode_yxdomain;
|
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
goto cleanup;
|
1999-08-12 20:27:24 +00:00
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
query_keepname(client, fname, dbuf);
|
1999-10-20 23:22:04 +00:00
|
|
|
/*
|
|
|
|
* Synthesize a CNAME for this DNAME.
|
1999-10-20 23:27:25 +00:00
|
|
|
*
|
|
|
|
* We want to synthesize a CNAME since if we don't
|
|
|
|
* then older software that doesn't understand DNAME
|
|
|
|
* will not chain like it should.
|
|
|
|
*
|
|
|
|
* We do not try to synthesize a signature because we hope
|
|
|
|
* that security aware servers will understand DNAME. Also,
|
|
|
|
* even if we had an online key, making a signature
|
|
|
|
* on-the-fly is costly, and not really legitimate anyway
|
|
|
|
* since the synthesized CNAME is NOT in the zone.
|
1999-10-20 23:22:04 +00:00
|
|
|
*/
|
|
|
|
dns_name_init(tname, NULL);
|
|
|
|
query_addcname(client, client->query.qname, fname,
|
|
|
|
trdataset->ttl, &tname);
|
|
|
|
if (tname != NULL)
|
|
|
|
dns_message_puttempname(client->message, &tname);
|
|
|
|
/*
|
|
|
|
* Switch to the new qname and restart.
|
|
|
|
*/
|
1999-10-07 19:44:22 +00:00
|
|
|
query_maybeputqname(client);
|
1999-08-12 07:54:08 +00:00
|
|
|
client->query.qname = fname;
|
|
|
|
fname = NULL;
|
|
|
|
want_restart = ISC_TRUE;
|
1999-09-17 21:59:55 +00:00
|
|
|
goto addauth;
|
1999-08-12 07:54:08 +00:00
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* Something has gone wrong.
|
|
|
|
*/
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
if (type == dns_rdatatype_any) {
|
|
|
|
/*
|
|
|
|
* XXXRTH Need to handle zonecuts with special case
|
|
|
|
* code.
|
|
|
|
*/
|
|
|
|
n = 0;
|
|
|
|
rdsiter = NULL;
|
1999-08-31 22:14:06 +00:00
|
|
|
result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
|
1999-08-12 07:54:08 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2000-04-13 19:34:02 +00:00
|
|
|
/*
|
|
|
|
* Calling query_addrrset() with a non-NULL dbuf is going
|
|
|
|
* to either keep or release the name. We don't want it to
|
|
|
|
* release fname, since we may have to call query_addrrset()
|
|
|
|
* more than once. That means we have to call query_keepname()
|
|
|
|
* now, and pass a NULL dbuf to query_addrrset().
|
|
|
|
*
|
|
|
|
* Since we've done the keepname, it's important that we
|
|
|
|
* set fname to NULL before we leave this 'if' block
|
|
|
|
* otherwise we might try to cleanup fname even though we've
|
|
|
|
* kept it!
|
|
|
|
*/
|
|
|
|
query_keepname(client, fname, dbuf);
|
1999-08-12 07:54:08 +00:00
|
|
|
result = dns_rdatasetiter_first(rdsiter);
|
|
|
|
while (result == ISC_R_SUCCESS) {
|
|
|
|
dns_rdatasetiter_current(rdsiter, rdataset);
|
1999-10-15 20:48:34 +00:00
|
|
|
if ((qtype == dns_rdatatype_any ||
|
|
|
|
rdataset->type == qtype) && rdataset->type != 0) {
|
1999-08-31 22:14:06 +00:00
|
|
|
tname = fname;
|
|
|
|
query_addrrset(client, &tname, &rdataset, NULL,
|
2000-04-13 19:34:02 +00:00
|
|
|
NULL, DNS_SECTION_ANSWER);
|
1999-08-31 22:14:06 +00:00
|
|
|
n++;
|
|
|
|
/*
|
|
|
|
* We shouldn't ever fail to add 'rdataset'
|
|
|
|
* because it's already in the answer.
|
|
|
|
*/
|
|
|
|
INSIST(rdataset == NULL);
|
|
|
|
rdataset = query_newrdataset(client);
|
|
|
|
if (rdataset == NULL)
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We're not interested in this rdataset.
|
|
|
|
*/
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
}
|
|
|
|
result = dns_rdatasetiter_next(rdsiter);
|
|
|
|
}
|
2000-04-13 19:34:02 +00:00
|
|
|
/*
|
|
|
|
* As mentioned above, we must now clear fname since we have
|
|
|
|
* kept it.
|
|
|
|
*/
|
|
|
|
fname = NULL;
|
|
|
|
if (n == 0) {
|
1999-07-28 02:20:36 +00:00
|
|
|
/*
|
1999-08-31 22:14:06 +00:00
|
|
|
* We didn't match any rdatasets.
|
1999-07-28 02:20:36 +00:00
|
|
|
*/
|
1999-08-31 22:14:06 +00:00
|
|
|
if (qtype == dns_rdatatype_sig &&
|
2000-04-06 22:03:35 +00:00
|
|
|
result == ISC_R_NOMORE) {
|
1999-08-31 22:14:06 +00:00
|
|
|
/*
|
|
|
|
* XXXRTH If this is a secure zone and we
|
|
|
|
* didn't find any SIGs, we should generate
|
|
|
|
* an error unless we were searching for
|
|
|
|
* glue. Ugh.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* We were searching for SIG records in
|
|
|
|
* a nonsecure zone. Send a "no error,
|
|
|
|
* no data" response.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* Add SOA.
|
|
|
|
*/
|
|
|
|
result = query_addsoa(client, db);
|
1999-08-31 22:24:36 +00:00
|
|
|
if (result == ISC_R_SUCCESS)
|
2000-04-06 22:03:35 +00:00
|
|
|
result = ISC_R_NOMORE;
|
1999-08-31 22:14:06 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Something went wrong.
|
|
|
|
*/
|
|
|
|
result = DNS_R_SERVFAIL;
|
1999-07-28 02:20:36 +00:00
|
|
|
}
|
1999-08-03 01:21:00 +00:00
|
|
|
}
|
1999-08-12 07:54:08 +00:00
|
|
|
dns_rdatasetiter_destroy(&rdsiter);
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result != ISC_R_NOMORE) {
|
1999-08-12 07:54:08 +00:00
|
|
|
QUERY_ERROR(DNS_R_SERVFAIL);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* This is the "normal" case -- an ordinary question to which
|
|
|
|
* we know the answer.
|
|
|
|
*/
|
2000-04-13 19:34:02 +00:00
|
|
|
query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf,
|
1999-10-19 20:22:38 +00:00
|
|
|
DNS_SECTION_ANSWER);
|
1999-09-01 18:16:43 +00:00
|
|
|
/*
|
|
|
|
* We shouldn't ever fail to add 'rdataset'
|
|
|
|
* because it's already in the answer.
|
|
|
|
*/
|
|
|
|
INSIST(rdataset == NULL);
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* Remember that we've answered this question.
|
|
|
|
*/
|
1999-10-11 19:12:43 +00:00
|
|
|
client->query.qrdataset->attributes |=
|
|
|
|
DNS_RDATASETATTR_ANSWERED;
|
1999-08-12 07:54:08 +00:00
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
1999-09-17 21:59:55 +00:00
|
|
|
addauth:
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_find: addauth");
|
1999-09-17 21:59:55 +00:00
|
|
|
/*
|
1999-10-21 17:49:55 +00:00
|
|
|
* Add NS records to the authority section (if we haven't already
|
|
|
|
* added them to the answer section).
|
1999-09-17 21:59:55 +00:00
|
|
|
*/
|
1999-10-21 17:49:55 +00:00
|
|
|
if (!want_restart) {
|
|
|
|
if (is_zone) {
|
|
|
|
if (!(qtype == dns_rdatatype_ns &&
|
|
|
|
dns_name_equal(client->query.qname,
|
|
|
|
dns_db_origin(db))))
|
|
|
|
query_addns(client, db);
|
|
|
|
} else if (qtype != dns_rdatatype_ns) {
|
|
|
|
if (fname != NULL)
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
query_addbestns(client);
|
|
|
|
}
|
|
|
|
}
|
1999-09-17 21:59:55 +00:00
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
cleanup:
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_find: cleanup");
|
1999-09-17 21:59:55 +00:00
|
|
|
/*
|
|
|
|
* General cleanup.
|
|
|
|
*/
|
1999-09-13 18:26:37 +00:00
|
|
|
query_putrdataset(client, &rdataset);
|
|
|
|
query_putrdataset(client, &sigrdataset);
|
1999-08-12 07:54:08 +00:00
|
|
|
if (fname != NULL)
|
|
|
|
query_releasename(client, &fname);
|
|
|
|
if (node != NULL)
|
1999-07-28 02:20:36 +00:00
|
|
|
dns_db_detachnode(db, &node);
|
1999-08-12 07:54:08 +00:00
|
|
|
if (db != NULL)
|
1999-07-28 02:20:36 +00:00
|
|
|
dns_db_detach(&db);
|
1999-10-14 01:37:00 +00:00
|
|
|
if (zone != NULL)
|
|
|
|
dns_zone_detach(&zone);
|
1999-09-13 18:26:37 +00:00
|
|
|
if (zdb != NULL) {
|
|
|
|
query_putrdataset(client, &zrdataset);
|
|
|
|
query_putrdataset(client, &zsigrdataset);
|
|
|
|
if (zfname != NULL)
|
|
|
|
query_releasename(client, &zfname);
|
|
|
|
dns_db_detach(&zdb);
|
|
|
|
}
|
1999-10-13 02:08:19 +00:00
|
|
|
if (event != NULL)
|
|
|
|
isc_event_free((isc_event_t **)(&event));
|
1999-07-24 01:17:44 +00:00
|
|
|
|
1999-09-17 21:59:55 +00:00
|
|
|
/*
|
|
|
|
* AA bit.
|
|
|
|
*/
|
1999-10-07 19:44:22 +00:00
|
|
|
if (client->query.restarts == 0 && !authoritative) {
|
1999-08-12 07:54:08 +00:00
|
|
|
/*
|
|
|
|
* We're not authoritative, so we must ensure the AA bit
|
|
|
|
* isn't set.
|
|
|
|
*/
|
|
|
|
client->message->flags &= ~DNS_MESSAGEFLAG_AA;
|
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
1999-09-17 21:59:55 +00:00
|
|
|
/*
|
|
|
|
* Restart the query?
|
|
|
|
*/
|
|
|
|
if (want_restart && client->query.restarts < MAX_RESTARTS) {
|
|
|
|
client->query.restarts++;
|
1999-08-12 07:54:08 +00:00
|
|
|
goto restart;
|
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2000-02-10 22:16:56 +00:00
|
|
|
if (eresult != ISC_R_SUCCESS && !PARTIALANSWER(client)) {
|
1999-08-12 07:54:08 +00:00
|
|
|
ns_client_error(client, eresult);
|
2000-02-11 20:56:19 +00:00
|
|
|
ns_client_detach(&client);
|
2000-02-10 22:16:56 +00:00
|
|
|
} else if (!RECURSING(client)) {
|
1999-12-10 21:19:40 +00:00
|
|
|
/*
|
|
|
|
* We are done. Make a final tweak to the AA bit if the
|
|
|
|
* auth-nxdomain config option says so, then send the
|
|
|
|
* response.
|
|
|
|
*/
|
1999-12-16 23:11:07 +00:00
|
|
|
if (client->message->rcode == dns_rcode_nxdomain &&
|
2000-04-06 20:25:48 +00:00
|
|
|
client->view->auth_nxdomain == ISC_TRUE)
|
1999-12-16 23:11:07 +00:00
|
|
|
client->message->flags |= DNS_MESSAGEFLAG_AA;
|
|
|
|
|
1999-08-12 07:54:08 +00:00
|
|
|
ns_client_send(client);
|
2000-02-11 20:56:19 +00:00
|
|
|
ns_client_detach(&client);
|
1999-12-10 21:19:40 +00:00
|
|
|
}
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("query_find: done");
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|
|
|
|
|
1999-11-23 20:55:33 +00:00
|
|
|
static inline void
|
|
|
|
log_query(ns_client_t *client) {
|
|
|
|
isc_buffer_t b;
|
2000-04-11 19:24:20 +00:00
|
|
|
char namebuf[1024];
|
|
|
|
char text[256];
|
1999-11-23 20:55:33 +00:00
|
|
|
isc_region_t r;
|
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
/* XXXRTH Allow this to be turned off! */
|
|
|
|
|
2000-04-11 19:24:20 +00:00
|
|
|
dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
|
|
|
|
|
103. [func] libisc buffer API changes for <isc/buffer.h>:
Added:
isc_buffer_base(b) (pointer)
isc_buffer_current(b) (pointer)
isc_buffer_active(b) (pointer)
isc_buffer_used(b) (pointer)
isc_buffer_length(b) (int)
isc_buffer_usedlength(b) (int)
isc_buffer_consumedlength(b) (int)
isc_buffer_remaininglength(b) (int)
isc_buffer_activelength(b) (int)
isc_buffer_availablelength(b) (int)
Removed:
ISC_BUFFER_USEDCOUNT(b)
ISC_BUFFER_AVAILABLECOUNT(b)
isc_buffer_type(b)
Changed names:
isc_buffer_used(b, r) ->
isc_buffer_usedregion(b, r)
isc_buffer_available(b, r) ->
isc_buffer_available_region(b, r)
isc_buffer_consumed(b, r) ->
isc_buffer_consumedregion(b, r)
isc_buffer_active(b, r) ->
isc_buffer_activeregion(b, r)
isc_buffer_remaining(b, r) ->
isc_buffer_remainingregion(b, r)
Buffer types were removed, so the ISC_BUFFERTYPE_*
macros are no more, and the type argument to
isc_buffer_init and isc_buffer_allocate were removed.
isc_buffer_putstr is now void (instead of isc_result_t)
and requires that the caller ensure that there
is enough available buffer space for the string.
2000-04-27 00:03:12 +00:00
|
|
|
isc_buffer_init(&b, (unsigned char *)text, sizeof(text));
|
1999-11-23 20:55:33 +00:00
|
|
|
for (rdataset = ISC_LIST_HEAD(client->query.qname->list);
|
|
|
|
rdataset != NULL;
|
|
|
|
rdataset = ISC_LIST_NEXT(rdataset, link)) {
|
103. [func] libisc buffer API changes for <isc/buffer.h>:
Added:
isc_buffer_base(b) (pointer)
isc_buffer_current(b) (pointer)
isc_buffer_active(b) (pointer)
isc_buffer_used(b) (pointer)
isc_buffer_length(b) (int)
isc_buffer_usedlength(b) (int)
isc_buffer_consumedlength(b) (int)
isc_buffer_remaininglength(b) (int)
isc_buffer_activelength(b) (int)
isc_buffer_availablelength(b) (int)
Removed:
ISC_BUFFER_USEDCOUNT(b)
ISC_BUFFER_AVAILABLECOUNT(b)
isc_buffer_type(b)
Changed names:
isc_buffer_used(b, r) ->
isc_buffer_usedregion(b, r)
isc_buffer_available(b, r) ->
isc_buffer_available_region(b, r)
isc_buffer_consumed(b, r) ->
isc_buffer_consumedregion(b, r)
isc_buffer_active(b, r) ->
isc_buffer_activeregion(b, r)
isc_buffer_remaining(b, r) ->
isc_buffer_remainingregion(b, r)
Buffer types were removed, so the ISC_BUFFERTYPE_*
macros are no more, and the type argument to
isc_buffer_init and isc_buffer_allocate were removed.
isc_buffer_putstr is now void (instead of isc_result_t)
and requires that the caller ensure that there
is enough available buffer space for the string.
2000-04-27 00:03:12 +00:00
|
|
|
isc_buffer_availableregion(&b, &r);
|
1999-11-23 20:55:33 +00:00
|
|
|
if (r.length < 1)
|
|
|
|
return;
|
|
|
|
*r.base = ' ';
|
|
|
|
isc_buffer_add(&b, 1);
|
|
|
|
if (dns_rdatatype_totext(rdataset->type, &b) != ISC_R_SUCCESS)
|
|
|
|
return;
|
|
|
|
}
|
103. [func] libisc buffer API changes for <isc/buffer.h>:
Added:
isc_buffer_base(b) (pointer)
isc_buffer_current(b) (pointer)
isc_buffer_active(b) (pointer)
isc_buffer_used(b) (pointer)
isc_buffer_length(b) (int)
isc_buffer_usedlength(b) (int)
isc_buffer_consumedlength(b) (int)
isc_buffer_remaininglength(b) (int)
isc_buffer_activelength(b) (int)
isc_buffer_availablelength(b) (int)
Removed:
ISC_BUFFER_USEDCOUNT(b)
ISC_BUFFER_AVAILABLECOUNT(b)
isc_buffer_type(b)
Changed names:
isc_buffer_used(b, r) ->
isc_buffer_usedregion(b, r)
isc_buffer_available(b, r) ->
isc_buffer_available_region(b, r)
isc_buffer_consumed(b, r) ->
isc_buffer_consumedregion(b, r)
isc_buffer_active(b, r) ->
isc_buffer_activeregion(b, r)
isc_buffer_remaining(b, r) ->
isc_buffer_remainingregion(b, r)
Buffer types were removed, so the ISC_BUFFERTYPE_*
macros are no more, and the type argument to
isc_buffer_init and isc_buffer_allocate were removed.
isc_buffer_putstr is now void (instead of isc_result_t)
and requires that the caller ensure that there
is enough available buffer space for the string.
2000-04-27 00:03:12 +00:00
|
|
|
isc_buffer_usedregion(&b, &r);
|
2000-04-04 19:14:05 +00:00
|
|
|
ns_client_log(client, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_QUERY,
|
2000-04-11 19:24:20 +00:00
|
|
|
ISC_LOG_DEBUG(1), "query: %s%.*s", namebuf,
|
1999-11-23 20:55:33 +00:00
|
|
|
(int)r.length, (char *)r.base);
|
|
|
|
}
|
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
void
|
|
|
|
ns_query_start(ns_client_t *client) {
|
1999-07-28 02:20:36 +00:00
|
|
|
isc_result_t result;
|
1999-08-03 01:21:00 +00:00
|
|
|
dns_message_t *message = client->message;
|
1999-08-16 09:46:20 +00:00
|
|
|
dns_rdataset_t *rdataset;
|
2000-02-11 20:56:19 +00:00
|
|
|
ns_client_t *qclient;
|
|
|
|
|
1999-12-24 00:43:46 +00:00
|
|
|
CTRACE("ns_query_start");
|
|
|
|
|
1999-08-03 01:21:00 +00:00
|
|
|
/*
|
|
|
|
* Ensure that appropriate cleanups occur.
|
|
|
|
*/
|
|
|
|
client->next = query_next;
|
1999-07-28 02:20:36 +00:00
|
|
|
|
2000-07-31 21:07:07 +00:00
|
|
|
if ((client->view->cachedb == NULL)
|
|
|
|
|| (!client->view->additionalfromcache)) {
|
1999-09-13 18:26:37 +00:00
|
|
|
/*
|
|
|
|
* We don't have a cache. Turn off cache support and
|
|
|
|
* recursion.
|
|
|
|
*/
|
|
|
|
client->query.attributes &=
|
|
|
|
~(NS_QUERYATTR_RECURSIONOK|NS_QUERYATTR_CACHEOK);
|
1999-12-10 23:58:04 +00:00
|
|
|
} else if ((client->attributes & NS_CLIENTATTR_RA) == 0 ||
|
|
|
|
(message->flags & DNS_MESSAGEFLAG_RD) == 0) {
|
1999-09-13 18:26:37 +00:00
|
|
|
/*
|
1999-12-10 23:58:04 +00:00
|
|
|
* If the client isn't allowed to recurse (due to
|
|
|
|
* "recursion no", the allow-recursion ACL, or the
|
|
|
|
* lack of a resolver in this view), or if it
|
|
|
|
* doesn't want recursion, turn recursion off.
|
1999-09-13 18:26:37 +00:00
|
|
|
*/
|
|
|
|
client->query.attributes &= ~NS_QUERYATTR_RECURSIONOK;
|
|
|
|
}
|
1999-08-03 01:21:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the question name.
|
|
|
|
*/
|
|
|
|
result = dns_message_firstname(message, DNS_SECTION_QUESTION);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
ns_client_error(client, result);
|
|
|
|
return;
|
1999-07-28 02:20:36 +00:00
|
|
|
}
|
1999-08-03 01:21:00 +00:00
|
|
|
dns_message_currentname(message, DNS_SECTION_QUESTION,
|
|
|
|
&client->query.qname);
|
1999-08-12 07:54:08 +00:00
|
|
|
client->query.origqname = client->query.qname;
|
1999-08-03 01:21:00 +00:00
|
|
|
result = dns_message_nextname(message, DNS_SECTION_QUESTION);
|
1999-07-28 02:20:36 +00:00
|
|
|
if (result != ISC_R_NOMORE) {
|
1999-08-03 01:21:00 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* There's more than one QNAME in the question
|
|
|
|
* section.
|
|
|
|
*/
|
|
|
|
ns_client_error(client, DNS_R_FORMERR);
|
|
|
|
} else
|
|
|
|
ns_client_error(client, result);
|
1999-07-28 02:20:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-11-23 20:55:33 +00:00
|
|
|
log_query(client);
|
1999-11-02 15:55:39 +00:00
|
|
|
|
1999-08-16 09:46:20 +00:00
|
|
|
/*
|
|
|
|
* Check for illegal meta-classes and meta-types in
|
|
|
|
* multiple question queries (edns1 section 5.1).
|
|
|
|
*/
|
|
|
|
if (message->counts[DNS_SECTION_QUESTION] > 1) {
|
|
|
|
if (dns_rdataclass_ismeta(message->rdclass)) {
|
|
|
|
ns_client_error(client, DNS_R_FORMERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (rdataset = ISC_LIST_HEAD(client->query.qname->list);
|
|
|
|
rdataset != NULL;
|
|
|
|
rdataset = ISC_LIST_NEXT(rdataset, link)) {
|
|
|
|
if (dns_rdatatype_ismeta(rdataset->type)) {
|
|
|
|
ns_client_error(client, DNS_R_FORMERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for meta-queries like IXFR and AXFR.
|
|
|
|
*/
|
|
|
|
if (message->counts[DNS_SECTION_QUESTION] == 1) {
|
|
|
|
rdataset = ISC_LIST_HEAD(client->query.qname->list);
|
|
|
|
INSIST(rdataset != NULL);
|
|
|
|
if (dns_rdatatype_ismeta(rdataset->type)) {
|
|
|
|
switch (rdataset->type) {
|
|
|
|
case dns_rdatatype_any:
|
|
|
|
break; /* Let query_find handle it. */
|
|
|
|
case dns_rdatatype_ixfr:
|
|
|
|
case dns_rdatatype_axfr:
|
|
|
|
ns_xfr_start(client, rdataset->type);
|
|
|
|
return;
|
|
|
|
case dns_rdatatype_maila:
|
|
|
|
case dns_rdatatype_mailb:
|
|
|
|
ns_client_error(client, DNS_R_NOTIMP);
|
|
|
|
return;
|
1999-10-26 15:41:48 +00:00
|
|
|
case dns_rdatatype_tkey:
|
2000-01-21 20:24:49 +00:00
|
|
|
result = dns_tkey_processquery(client->message,
|
2000-05-24 03:23:42 +00:00
|
|
|
ns_g_server->tkeyctx,
|
|
|
|
client->view->dynamickeys);
|
1999-10-26 15:41:48 +00:00
|
|
|
if (result == ISC_R_SUCCESS)
|
|
|
|
ns_client_send(client);
|
|
|
|
else
|
|
|
|
ns_client_error(client, result);
|
|
|
|
return;
|
1999-08-16 09:46:20 +00:00
|
|
|
default: /* TSIG, etc. */
|
|
|
|
ns_client_error(client, DNS_R_FORMERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-07-25 01:06:18 +00:00
|
|
|
/*
|
|
|
|
* If the client has requested that DNSSEC checking be disabled,
|
2000-07-25 21:37:05 +00:00
|
|
|
* allow lookups to return pending data and instruct the resolver
|
|
|
|
* to return data before validation has completed.
|
2000-07-25 01:06:18 +00:00
|
|
|
*/
|
2000-07-25 21:37:05 +00:00
|
|
|
if (message->flags & DNS_MESSAGEFLAG_CD) {
|
2000-07-25 01:06:18 +00:00
|
|
|
client->query.dboptions |= DNS_DBFIND_PENDINGOK;
|
2000-07-25 21:37:05 +00:00
|
|
|
client->query.fetchoptions |= DNS_FETCHOPT_NOVALIDATE;
|
|
|
|
}
|
2000-07-25 01:06:18 +00:00
|
|
|
|
2000-05-24 03:23:42 +00:00
|
|
|
/*
|
|
|
|
* This is an ordinary query.
|
|
|
|
*/
|
1999-08-16 09:46:20 +00:00
|
|
|
result = dns_message_reply(message, ISC_TRUE);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
ns_client_next(client, result);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Assume authoritative response until it is known to be
|
|
|
|
* otherwise.
|
|
|
|
*/
|
|
|
|
message->flags |= DNS_MESSAGEFLAG_AA;
|
|
|
|
|
1999-10-07 19:44:22 +00:00
|
|
|
/*
|
1999-10-19 20:22:38 +00:00
|
|
|
* Set AD. We need only clear it if we add "pending" data to
|
|
|
|
* a response.
|
1999-10-07 19:44:22 +00:00
|
|
|
*/
|
|
|
|
message->flags |= DNS_MESSAGEFLAG_AD;
|
|
|
|
|
2000-02-11 20:56:19 +00:00
|
|
|
qclient = NULL;
|
|
|
|
ns_client_attach(client, &qclient);
|
|
|
|
query_find(qclient, NULL);
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|