1999-07-24 01:17:44 +00:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2000-08-01 01:33:37 +00:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
2020-09-14 16:20:40 -07:00
|
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
1999-07-24 01:17:44 +00:00
|
|
|
*/
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <inttypes.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2018-03-28 14:19:37 +02:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
#include <isc/aes.h>
|
2019-07-04 15:45:06 +02:00
|
|
|
#include <isc/atomic.h>
|
2001-08-08 22:54:55 +00:00
|
|
|
#include <isc/formatcheck.h>
|
2017-09-08 13:39:09 -07:00
|
|
|
#include <isc/fuzz.h>
|
2018-03-20 17:20:50 +00:00
|
|
|
#include <isc/hmac.h>
|
2020-05-15 16:37:44 -07:00
|
|
|
#include <isc/log.h>
|
2000-08-25 01:08:07 +00:00
|
|
|
#include <isc/mutex.h>
|
2018-05-28 15:22:23 +02:00
|
|
|
#include <isc/nonce.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <isc/once.h>
|
2005-06-04 05:32:50 +00:00
|
|
|
#include <isc/platform.h>
|
2001-01-22 18:58:36 +00:00
|
|
|
#include <isc/print.h>
|
2014-02-19 12:53:42 +11:00
|
|
|
#include <isc/random.h>
|
2015-08-17 18:26:44 -07:00
|
|
|
#include <isc/safe.h>
|
2014-02-19 12:53:42 +11:00
|
|
|
#include <isc/serial.h>
|
2019-07-21 14:26:49 -04:00
|
|
|
#include <isc/siphash.h>
|
2009-01-27 22:30:00 +00:00
|
|
|
#include <isc/stats.h>
|
2001-05-25 07:39:48 +00:00
|
|
|
#include <isc/stdio.h>
|
2000-05-08 14:38:29 +00:00
|
|
|
#include <isc/string.h>
|
2001-01-22 18:58:36 +00:00
|
|
|
#include <isc/task.h>
|
2021-05-18 19:44:31 +02:00
|
|
|
#include <isc/thread.h>
|
1999-07-24 01:17:44 +00:00
|
|
|
#include <isc/timer.h>
|
1999-12-16 22:24:22 +00:00
|
|
|
#include <isc/util.h>
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2016-05-05 11:46:11 +02:00
|
|
|
#include <dns/adb.h>
|
2014-09-03 23:28:14 -07:00
|
|
|
#include <dns/badcache.h>
|
2020-02-12 13:59:18 +01:00
|
|
|
#include <dns/cache.h>
|
2000-10-11 17:44:18 +00:00
|
|
|
#include <dns/db.h>
|
1999-07-24 01:17:44 +00:00
|
|
|
#include <dns/dispatch.h>
|
2015-10-02 12:32:42 -07:00
|
|
|
#include <dns/dnstap.h>
|
2014-09-10 15:31:40 +10:00
|
|
|
#include <dns/edns.h>
|
1999-07-24 01:17:44 +00:00
|
|
|
#include <dns/events.h>
|
|
|
|
#include <dns/message.h>
|
2006-01-05 00:01:46 +00:00
|
|
|
#include <dns/peer.h>
|
2002-03-05 00:36:44 +00:00
|
|
|
#include <dns/rcode.h>
|
1999-09-02 01:52:31 +00:00
|
|
|
#include <dns/rdata.h>
|
2000-11-15 19:15:25 +00:00
|
|
|
#include <dns/rdataclass.h>
|
1999-09-02 01:52:31 +00:00
|
|
|
#include <dns/rdatalist.h>
|
|
|
|
#include <dns/rdataset.h>
|
2006-01-05 00:01:46 +00:00
|
|
|
#include <dns/resolver.h>
|
2008-04-03 05:55:52 +00:00
|
|
|
#include <dns/stats.h>
|
2000-09-12 07:48:28 +00:00
|
|
|
#include <dns/tsig.h>
|
1999-08-05 22:14:43 +00:00
|
|
|
#include <dns/view.h>
|
2000-01-27 01:00:16 +00:00
|
|
|
#include <dns/zone.h>
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
#include <ns/client.h>
|
2017-09-08 13:39:09 -07:00
|
|
|
#include <ns/interfacemgr.h>
|
|
|
|
#include <ns/log.h>
|
|
|
|
#include <ns/notify.h>
|
|
|
|
#include <ns/server.h>
|
|
|
|
#include <ns/stats.h>
|
|
|
|
#include <ns/update.h>
|
2000-02-10 22:16:56 +00:00
|
|
|
|
|
|
|
/***
|
|
|
|
*** Client
|
|
|
|
***/
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file
|
|
|
|
* Client Routines
|
|
|
|
*
|
2000-02-10 22:16:56 +00:00
|
|
|
* Important note!
|
|
|
|
*
|
|
|
|
* All client state changes, other than that from idle to listening, occur
|
|
|
|
* as a result of events. This guarantees serialization and avoids the
|
|
|
|
* need for locking.
|
|
|
|
*
|
|
|
|
* If a routine is ever created that allows someone other than the client's
|
|
|
|
* task to change the client, then the client will have to be locked.
|
|
|
|
*/
|
1999-07-24 01:17:44 +00:00
|
|
|
|
|
|
|
#ifdef NS_CLIENT_TRACE
|
2020-02-12 13:59:18 +01:00
|
|
|
#define CTRACE(m) \
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, \
|
|
|
|
ISC_LOG_DEBUG(3), "%s", (m))
|
|
|
|
#define MTRACE(m) \
|
|
|
|
isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT, \
|
|
|
|
ISC_LOG_DEBUG(3), "clientmgr @%p: %s", manager, (m))
|
2020-02-13 21:48:23 +01:00
|
|
|
#else /* ifdef NS_CLIENT_TRACE */
|
2020-02-12 13:59:18 +01:00
|
|
|
#define CTRACE(m) ((void)(m))
|
|
|
|
#define MTRACE(m) ((void)(m))
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* ifdef NS_CLIENT_TRACE */
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
#define TCP_CLIENT(c) (((c)->attributes & NS_CLIENTATTR_TCP) != 0)
|
1999-08-05 01:51:32 +00:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
#define COOKIE_SIZE 24U /* 8 + 4 + 4 + 8 */
|
2020-02-13 14:44:37 -08:00
|
|
|
#define ECS_SIZE 20U /* 2 + 1 + 1 + [0..16] */
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
#define WANTNSID(x) (((x)->attributes & NS_CLIENTATTR_WANTNSID) != 0)
|
|
|
|
#define WANTEXPIRE(x) (((x)->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0)
|
|
|
|
#define WANTPAD(x) (((x)->attributes & NS_CLIENTATTR_WANTPAD) != 0)
|
2017-01-04 09:16:30 -08:00
|
|
|
#define USEKEEPALIVE(x) (((x)->attributes & NS_CLIENTATTR_USEKEEPALIVE) != 0)
|
2016-02-27 11:23:50 +11:00
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
#define MANAGER_MAGIC ISC_MAGIC('N', 'S', 'C', 'm')
|
2020-02-12 13:59:18 +01:00
|
|
|
#define VALID_MANAGER(m) ISC_MAGIC_VALID(m, MANAGER_MAGIC)
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2006-01-04 05:06:10 +00:00
|
|
|
/*
|
|
|
|
* Enable ns_client_dropport() by default.
|
|
|
|
*/
|
|
|
|
#ifndef NS_CLIENT_DROPPORT
|
|
|
|
#define NS_CLIENT_DROPPORT 1
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* ifndef NS_CLIENT_DROPPORT */
|
2006-01-04 05:06:10 +00:00
|
|
|
|
2021-05-26 17:55:43 +10:00
|
|
|
LIBNS_EXTERNAL_DATA atomic_uint_fast64_t ns_client_requests =
|
|
|
|
ATOMIC_VAR_INIT(0);
|
2000-02-10 22:16:56 +00:00
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
|
|
|
clientmgr_attach(ns_clientmgr_t *source, ns_clientmgr_t **targetp);
|
|
|
|
static void
|
|
|
|
clientmgr_detach(ns_clientmgr_t **mp);
|
|
|
|
static void
|
|
|
|
clientmgr_destroy(ns_clientmgr_t *manager);
|
|
|
|
static void
|
|
|
|
ns_client_endrequest(ns_client_t *client);
|
|
|
|
static void
|
|
|
|
ns_client_dumpmessage(ns_client_t *client, const char *reason);
|
|
|
|
static void
|
|
|
|
compute_cookie(ns_client_t *client, uint32_t when, uint32_t nonce,
|
|
|
|
const unsigned char *secret, isc_buffer_t *buf);
|
2000-01-15 00:36:26 +00:00
|
|
|
|
2001-10-24 03:10:18 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_recursing(ns_client_t *client) {
|
2001-10-24 03:10:18 +00:00
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
2011-10-10 22:57:14 +00:00
|
|
|
REQUIRE(client->state == NS_CLIENTSTATE_WORKING);
|
2001-10-24 03:10:18 +00:00
|
|
|
|
2011-10-10 22:57:14 +00:00
|
|
|
LOCK(&client->manager->reclock);
|
2019-11-05 15:34:35 -08:00
|
|
|
client->state = NS_CLIENTSTATE_RECURSING;
|
2011-11-09 22:05:09 +00:00
|
|
|
ISC_LIST_APPEND(client->manager->recursing, client, rlink);
|
2011-10-10 22:57:14 +00:00
|
|
|
UNLOCK(&client->manager->reclock);
|
2001-10-24 03:10:18 +00:00
|
|
|
}
|
|
|
|
|
2005-07-27 02:29:01 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_killoldestquery(ns_client_t *client) {
|
2005-07-27 02:29:01 +00:00
|
|
|
ns_client_t *oldest;
|
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
|
2011-10-10 22:57:14 +00:00
|
|
|
LOCK(&client->manager->reclock);
|
2005-07-27 02:29:01 +00:00
|
|
|
oldest = ISC_LIST_HEAD(client->manager->recursing);
|
|
|
|
if (oldest != NULL) {
|
2011-10-10 22:57:14 +00:00
|
|
|
ISC_LIST_UNLINK(client->manager->recursing, oldest, rlink);
|
2005-07-27 02:29:01 +00:00
|
|
|
ns_query_cancel(oldest);
|
2019-11-25 21:28:10 -08:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_reclimitdropped);
|
|
|
|
}
|
2020-03-03 10:09:17 +01:00
|
|
|
UNLOCK(&client->manager->reclock);
|
2005-07-27 02:29:01 +00:00
|
|
|
}
|
|
|
|
|
2001-01-29 19:49:52 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_settimeout(ns_client_t *client, unsigned int seconds) {
|
2019-11-05 15:34:35 -08:00
|
|
|
UNUSED(client);
|
|
|
|
UNUSED(seconds);
|
|
|
|
/* XXXWPK TODO use netmgr to set timeout */
|
2000-02-10 22:16:56 +00:00
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2000-02-10 22:16:56 +00:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_endrequest(ns_client_t *client) {
|
2004-07-23 02:57:27 +00:00
|
|
|
INSIST(client->nupdates == 0);
|
2011-10-10 22:57:14 +00:00
|
|
|
INSIST(client->state == NS_CLIENTSTATE_WORKING ||
|
|
|
|
client->state == NS_CLIENTSTATE_RECURSING);
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2000-05-02 01:16:21 +00:00
|
|
|
CTRACE("endrequest");
|
|
|
|
|
2020-01-28 10:31:35 +01:00
|
|
|
if (client->state == NS_CLIENTSTATE_RECURSING) {
|
|
|
|
LOCK(&client->manager->reclock);
|
|
|
|
if (ISC_LINK_LINKED(client, rlink)) {
|
|
|
|
ISC_LIST_UNLINK(client->manager->recursing, client,
|
|
|
|
rlink);
|
|
|
|
}
|
|
|
|
UNLOCK(&client->manager->reclock);
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (client->cleanup != NULL) {
|
|
|
|
(client->cleanup)(client);
|
|
|
|
client->cleanup = NULL;
|
1999-08-03 01:21:00 +00:00
|
|
|
}
|
|
|
|
|
2016-05-05 11:46:11 +02:00
|
|
|
if (client->view != NULL) {
|
|
|
|
#ifdef ENABLE_AFL
|
2017-09-08 13:39:09 -07:00
|
|
|
if (client->sctx->fuzztype == isc_fuzz_resolver) {
|
2016-05-05 11:46:11 +02:00
|
|
|
dns_cache_clean(client->view->cache, INT_MAX);
|
|
|
|
dns_adb_flush(client->view->adb);
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* ifdef ENABLE_AFL */
|
1999-08-05 22:14:43 +00:00
|
|
|
dns_view_detach(&client->view);
|
2016-05-05 11:46:11 +02:00
|
|
|
}
|
1999-11-24 21:05:45 +00:00
|
|
|
if (client->opt != NULL) {
|
|
|
|
INSIST(dns_rdataset_isassociated(client->opt));
|
|
|
|
dns_rdataset_disassociate(client->opt);
|
|
|
|
dns_message_puttemprdataset(client->message, &client->opt);
|
|
|
|
}
|
2000-01-07 19:20:25 +00:00
|
|
|
|
2011-05-05 23:44:52 +00:00
|
|
|
client->signer = NULL;
|
1999-10-07 19:43:18 +00:00
|
|
|
client->udpsize = 512;
|
2000-11-13 21:34:03 +00:00
|
|
|
client->extflags = 0;
|
2005-06-07 00:16:01 +00:00
|
|
|
client->ednsversion = -1;
|
2019-02-17 20:32:07 +01:00
|
|
|
dns_ecs_init(&client->ecs);
|
1999-07-24 01:17:44 +00:00
|
|
|
dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
|
2000-01-15 00:36:26 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
/*
|
|
|
|
* Clean up from recursion - normally this would be done in
|
|
|
|
* fetch_callback(), but if we're shutting down and canceling then
|
|
|
|
* it might not have happened.
|
|
|
|
*/
|
2012-05-14 10:06:05 -07:00
|
|
|
if (client->recursionquota != NULL) {
|
2000-02-10 22:16:56 +00:00
|
|
|
isc_quota_detach(&client->recursionquota);
|
2020-03-26 10:57:38 +01:00
|
|
|
if (client->query.prefetch == NULL) {
|
|
|
|
ns_stats_decrement(client->sctx->nsstats,
|
|
|
|
ns_statscounter_recursclients);
|
|
|
|
}
|
2012-05-14 10:06:05 -07:00
|
|
|
}
|
2000-07-17 23:19:14 +00:00
|
|
|
|
|
|
|
/*
|
2019-11-05 15:34:35 -08:00
|
|
|
* Clear all client attributes that are specific to the request
|
2000-07-17 23:19:14 +00:00
|
|
|
*/
|
2019-11-05 15:34:35 -08:00
|
|
|
client->attributes = 0;
|
2016-05-05 11:46:11 +02:00
|
|
|
#ifdef ENABLE_AFL
|
2017-09-08 13:39:09 -07:00
|
|
|
if (client->sctx->fuzznotify != NULL &&
|
|
|
|
(client->sctx->fuzztype == isc_fuzz_client ||
|
|
|
|
client->sctx->fuzztype == isc_fuzz_tcpclient ||
|
2020-02-13 14:44:37 -08:00
|
|
|
client->sctx->fuzztype == isc_fuzz_resolver))
|
|
|
|
{
|
2017-09-08 13:39:09 -07:00
|
|
|
client->sctx->fuzznotify();
|
2016-05-05 11:46:11 +02:00
|
|
|
}
|
|
|
|
#endif /* ENABLE_AFL */
|
2000-03-06 17:35:13 +00:00
|
|
|
}
|
2000-01-15 00:36:26 +00:00
|
|
|
|
2000-02-10 22:16:56 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_drop(ns_client_t *client, isc_result_t result) {
|
2000-02-10 22:16:56 +00:00
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
2003-07-04 04:38:54 +00:00
|
|
|
REQUIRE(client->state == NS_CLIENTSTATE_WORKING ||
|
2019-11-05 15:34:35 -08:00
|
|
|
client->state == NS_CLIENTSTATE_RECURSING);
|
2000-05-02 01:16:21 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
CTRACE("drop");
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-04-04 18:28:51 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
2000-02-10 22:16:56 +00:00
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
|
|
|
|
"request failed: %s", isc_result_totext(result));
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
client_senddone(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_t *client = cbarg;
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
REQUIRE(client->sendhandle == handle);
|
2000-07-26 17:39:12 +00:00
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
CTRACE("senddone");
|
2019-11-05 15:34:35 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
|
|
|
|
"send failed: %s", isc_result_totext(result));
|
2000-06-22 00:05:11 +00:00
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_nmhandle_detach(&client->sendhandle);
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|
|
|
|
|
2020-05-28 15:19:25 +10:00
|
|
|
static void
|
2000-09-13 03:15:01 +00:00
|
|
|
client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer,
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned char **datap) {
|
2000-09-13 01:30:34 +00:00
|
|
|
unsigned char *data;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t bufsize;
|
2000-09-13 01:30:34 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
REQUIRE(datap != NULL);
|
2000-09-13 01:30:34 +00:00
|
|
|
|
|
|
|
if (TCP_CLIENT(client)) {
|
|
|
|
INSIST(client->tcpbuf == NULL);
|
2020-02-13 14:44:37 -08:00
|
|
|
client->tcpbuf = isc_mem_get(client->mctx,
|
|
|
|
NS_CLIENT_TCP_BUFFER_SIZE);
|
2000-09-13 01:30:34 +00:00
|
|
|
data = client->tcpbuf;
|
2020-05-28 15:19:25 +10:00
|
|
|
isc_buffer_init(buffer, data, NS_CLIENT_TCP_BUFFER_SIZE);
|
2000-09-13 01:30:34 +00:00
|
|
|
} else {
|
2019-11-05 15:34:35 -08:00
|
|
|
data = client->sendbuf;
|
2015-07-06 09:44:24 +10:00
|
|
|
if ((client->attributes & NS_CLIENTATTR_HAVECOOKIE) == 0) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (client->view != NULL) {
|
2015-07-06 09:44:24 +10:00
|
|
|
bufsize = client->view->nocookieudp;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2014-02-19 12:53:42 +11:00
|
|
|
bufsize = 512;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
} else {
|
2014-02-19 12:53:42 +11:00
|
|
|
bufsize = client->udpsize;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (bufsize > client->udpsize) {
|
2014-02-19 12:53:42 +11:00
|
|
|
bufsize = client->udpsize;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (bufsize > NS_CLIENT_SEND_BUFFER_SIZE) {
|
2019-11-05 15:34:35 -08:00
|
|
|
bufsize = NS_CLIENT_SEND_BUFFER_SIZE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-09-13 03:15:01 +00:00
|
|
|
isc_buffer_init(buffer, data, bufsize);
|
2000-09-13 01:30:34 +00:00
|
|
|
}
|
2000-09-13 03:15:01 +00:00
|
|
|
*datap = data;
|
|
|
|
}
|
|
|
|
|
2020-10-21 12:52:09 +02:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
client_sendpkg(ns_client_t *client, isc_buffer_t *buffer) {
|
2000-09-13 03:15:01 +00:00
|
|
|
isc_region_t r;
|
2013-03-22 12:27:54 -07:00
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
REQUIRE(client->sendhandle == NULL);
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
isc_buffer_usedregion(buffer, &r);
|
|
|
|
isc_nmhandle_attach(client->handle, &client->sendhandle);
|
2020-10-21 12:52:09 +02:00
|
|
|
isc_nm_send(client->handle, &r, client_senddone, client);
|
2000-09-13 03:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_sendraw(ns_client_t *client, dns_message_t *message) {
|
|
|
|
isc_result_t result;
|
2021-05-22 18:12:11 +02:00
|
|
|
unsigned char *data = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_buffer_t buffer;
|
|
|
|
isc_region_t r;
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_region_t *mr = NULL;
|
2000-09-13 03:15:01 +00:00
|
|
|
|
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
|
|
|
|
CTRACE("sendraw");
|
|
|
|
|
|
|
|
mr = dns_message_getrawmessage(message);
|
|
|
|
if (mr == NULL) {
|
|
|
|
result = ISC_R_UNEXPECTEDEND;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2020-05-28 15:19:25 +10:00
|
|
|
client_allocsendbuf(client, &buffer, &data);
|
|
|
|
|
|
|
|
if (mr->length > isc_buffer_length(&buffer)) {
|
|
|
|
result = ISC_R_NOSPACE;
|
2000-09-13 03:15:01 +00:00
|
|
|
goto done;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-09-13 03:15:01 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy message to buffer and fixup id.
|
|
|
|
*/
|
|
|
|
isc_buffer_availableregion(&buffer, &r);
|
|
|
|
result = isc_buffer_copyregion(&buffer, mr);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-09-13 03:15:01 +00:00
|
|
|
goto done;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-09-13 03:15:01 +00:00
|
|
|
r.base[0] = (client->message->id >> 8) & 0xff;
|
|
|
|
r.base[1] = client->message->id & 0xff;
|
|
|
|
|
2020-11-09 13:44:22 +11:00
|
|
|
#ifdef HAVE_DNSTAP
|
|
|
|
if (client->view != NULL) {
|
|
|
|
bool tcp = TCP_CLIENT(client);
|
|
|
|
dns_dtmsgtype_t dtmsgtype;
|
|
|
|
if (client->message->opcode == dns_opcode_update) {
|
|
|
|
dtmsgtype = DNS_DTTYPE_UR;
|
|
|
|
} else if ((client->message->flags & DNS_MESSAGEFLAG_RD) != 0) {
|
|
|
|
dtmsgtype = DNS_DTTYPE_CR;
|
|
|
|
} else {
|
|
|
|
dtmsgtype = DNS_DTTYPE_AR;
|
|
|
|
}
|
|
|
|
dns_dt_send(client->view, dtmsgtype, &client->peeraddr,
|
|
|
|
&client->destsockaddr, tcp, NULL,
|
|
|
|
&client->requesttime, NULL, &buffer);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-10-21 12:52:09 +02:00
|
|
|
client_sendpkg(client, &buffer);
|
2000-09-13 01:30:34 +00:00
|
|
|
|
2020-10-21 12:52:09 +02:00
|
|
|
return;
|
2020-02-12 13:59:18 +01:00
|
|
|
done:
|
2000-09-13 01:30:34 +00:00
|
|
|
if (client->tcpbuf != NULL) {
|
2019-11-05 15:34:35 -08:00
|
|
|
isc_mem_put(client->mctx, client->tcpbuf,
|
|
|
|
NS_CLIENT_TCP_BUFFER_SIZE);
|
2000-09-13 01:30:34 +00:00
|
|
|
client->tcpbuf = NULL;
|
|
|
|
}
|
2019-11-05 15:34:35 -08:00
|
|
|
|
|
|
|
ns_client_drop(client, result);
|
2000-09-13 01:30:34 +00:00
|
|
|
}
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_send(ns_client_t *client) {
|
|
|
|
isc_result_t result;
|
2021-05-22 18:12:11 +02:00
|
|
|
unsigned char *data = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_buffer_t buffer = { .magic = 0 };
|
|
|
|
isc_region_t r;
|
2001-03-05 21:15:47 +00:00
|
|
|
dns_compress_t cctx;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool cleanup_cctx = false;
|
|
|
|
unsigned int render_opts;
|
|
|
|
unsigned int preferred_glue;
|
|
|
|
bool opt_included = false;
|
|
|
|
size_t respsize;
|
2021-05-22 18:12:11 +02:00
|
|
|
dns_aclenv_t *env = NULL;
|
2015-10-02 12:32:42 -07:00
|
|
|
#ifdef HAVE_DNSTAP
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned char zone[DNS_NAME_MAXWIRE];
|
2015-10-02 12:32:42 -07:00
|
|
|
dns_dtmsgtype_t dtmsgtype;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_region_t zr;
|
2015-10-02 12:32:42 -07:00
|
|
|
#endif /* HAVE_DNSTAP */
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
|
Allow stale data to be used before name resolution
This commit allows stale RRset to be used (if available) for responding
a query, before an attempt to refresh an expired, or otherwise resolve
an unavailable RRset in cache is made.
For that to work, a value of zero must be specified for
stale-answer-client-timeout statement.
To better understand the logic implemented, there are three flags being
used during database lookup and other parts of code that must be
understood:
. DNS_DBFIND_STALEOK: This flag is set when BIND fails to refresh a
RRset due to timeout (resolver-query-timeout), its intent is to
try to look for stale data in cache as a fallback, but only if
stale answers are enabled in configuration.
This flag is also used to activate stale-refresh-time window, since it
is the only way the database knows that a resolution has failed.
. DNS_DBFIND_STALEENABLED: This flag is used as a hint to the database
that it may use stale data. It is always set during query lookup if
stale answers are enabled, but only effectively used during
stale-refresh-time window. Also during this window, the resolver will
not try to resolve the query, in other words no attempt to refresh the
data in cache is made when the stale-refresh-time window is active.
. DNS_DBFIND_STALEONLY: This new introduced flag is used when we want
stale data from the database, but not due to a failure in resolution,
it also doesn't require stale-refresh-time window timer to be active.
As long as there is a stale RRset available, it should be returned.
It is mainly used in two situations:
1. When stale-answer-client-timeout timer is triggered: in that case
we want to know if there is stale data available to answer the
client.
2. When stale-answer-client-timeout value is set to zero: in that
case, we also want to know if there is some stale RRset available
to promptly answer the client.
We must also discern between three situations that may happen when
resolving a query after the addition of stale-answer-client-timeout
statement, and how to handle them:
1. Are we running query_lookup() due to stale-answer-client-timeout
timer being triggered?
In this case, we look for stale data, making use of
DNS_DBFIND_STALEONLY flag. If a stale RRset is available then
respond the client with the data found, mark this query as
answered (query attribute NS_QUERYATTR_ANSWERED), so when the
fetch completes the client won't be answered twice.
We must also take care of not detaching from the client, as a
fetch will still be running in background, this is handled by the
following snippet:
if (!QUERY_STALEONLY(&client->query)) {
isc_nmhandle_detach(&client->reqhandle);
}
Which basically tests if DNS_DBFIND_STALEONLY flag is set, which
means we are here due to a stale-answer-client-timeout timer
expiration.
2. Are we running query_lookup() due to resolver-query-timeout being
triggered?
In this case, DNS_DBFIND_STALEOK flag will be set and an attempt
to look for stale data will be made.
As already explained, this flag is algo used to activate
stale-refresh-time window, as it means that we failed to refresh
a RRset due to timeout.
It is ok in this situation to detach from the client, as the
fetch is already completed.
3. Are we running query_lookup() during the first time, looking for
a RRset in cache and stale-answer-client-timeout value is set to
zero?
In this case, if stale answers are enabled (probably), we must do
an initial database lookup with DNS_DBFIND_STALEONLY flag set, to
indicate to the database that we want stale data.
If we find an active RRset, proceed as normal, answer the client
and the query is done.
If we find a stale RRset we respond to the client and mark the
query as answered, but don't detach from the client yet as an
attempt in refreshing the RRset will still be made by means of
the new introduced function 'query_resolve'.
If no active or stale RRset is available, begin resolution as
usual.
2020-12-21 15:54:54 -03:00
|
|
|
if ((client->query.attributes & NS_QUERYATTR_ANSWERED) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
/*
|
|
|
|
* XXXWPK TODO
|
|
|
|
* Delay the response according to the -T delay option
|
|
|
|
*/
|
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
env = client->manager->aclenv;
|
2019-09-27 12:10:44 +02:00
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
CTRACE("send");
|
|
|
|
|
2016-12-13 16:27:18 +11:00
|
|
|
if (client->message->opcode == dns_opcode_query &&
|
2020-02-13 14:44:37 -08:00
|
|
|
(client->attributes & NS_CLIENTATTR_RA) != 0)
|
|
|
|
{
|
1999-12-10 23:58:04 +00:00
|
|
|
client->message->flags |= DNS_MESSAGEFLAG_RA;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if ((client->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0) {
|
2009-10-26 23:14:54 +00:00
|
|
|
render_opts = 0;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2009-10-26 23:14:54 +00:00
|
|
|
render_opts = DNS_MESSAGERENDER_OMITDNSSEC;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-01-31 06:58:39 +00:00
|
|
|
|
|
|
|
preferred_glue = 0;
|
|
|
|
if (client->view != NULL) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (client->view->preferred_glue == dns_rdatatype_a) {
|
2012-01-31 06:58:39 +00:00
|
|
|
preferred_glue = DNS_MESSAGERENDER_PREFER_A;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else if (client->view->preferred_glue == dns_rdatatype_aaaa) {
|
2012-01-31 06:58:39 +00:00
|
|
|
preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-01-31 06:58:39 +00:00
|
|
|
}
|
2015-09-11 13:27:58 +10:00
|
|
|
if (preferred_glue == 0) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (isc_sockaddr_pf(&client->peeraddr) == AF_INET) {
|
2015-09-11 13:27:58 +10:00
|
|
|
preferred_glue = DNS_MESSAGERENDER_PREFER_A;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2015-09-11 13:27:58 +10:00
|
|
|
preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-09-11 13:27:58 +10:00
|
|
|
}
|
2012-01-31 06:58:39 +00:00
|
|
|
|
2014-02-20 14:56:20 +11:00
|
|
|
/*
|
|
|
|
* Create an OPT for our reply.
|
|
|
|
*/
|
|
|
|
if ((client->attributes & NS_CLIENTATTR_WANTOPT) != 0) {
|
2020-02-13 14:44:37 -08:00
|
|
|
result = ns_client_addopt(client, client->message,
|
|
|
|
&client->opt);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-20 14:56:20 +11:00
|
|
|
}
|
|
|
|
|
2020-05-28 15:19:25 +10:00
|
|
|
client_allocsendbuf(client, &buffer, &data);
|
1999-08-05 01:51:32 +00:00
|
|
|
|
2001-03-05 21:15:47 +00:00
|
|
|
result = dns_compress_init(&cctx, -1, client->mctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-06 19:37:26 -08:00
|
|
|
if (client->peeraddr_valid && client->view != NULL) {
|
|
|
|
isc_netaddr_t netaddr;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_name_t *name = NULL;
|
2014-02-06 19:37:26 -08:00
|
|
|
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (client->message->tsigkey != NULL) {
|
2014-02-06 19:37:26 -08:00
|
|
|
name = &client->message->tsigkey->name;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-11-05 12:19:04 +01:00
|
|
|
|
2014-02-06 19:37:26 -08:00
|
|
|
if (client->view->nocasecompress == NULL ||
|
2018-04-26 20:57:41 -07:00
|
|
|
!dns_acl_allowed(&netaddr, name,
|
2020-02-13 14:44:37 -08:00
|
|
|
client->view->nocasecompress, env))
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
dns_compress_setsensitive(&cctx, true);
|
2014-02-06 19:37:26 -08:00
|
|
|
}
|
2015-11-05 12:19:04 +01:00
|
|
|
|
2020-03-30 13:49:55 -07:00
|
|
|
if (!client->view->msgcompression) {
|
2015-11-05 12:19:04 +01:00
|
|
|
dns_compress_disable(&cctx);
|
|
|
|
}
|
2014-02-06 19:37:26 -08:00
|
|
|
}
|
2018-04-17 08:29:14 -07:00
|
|
|
cleanup_cctx = true;
|
2001-03-05 21:15:47 +00:00
|
|
|
|
|
|
|
result = dns_message_renderbegin(client->message, &cctx, &buffer);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-04-03 02:01:08 +00:00
|
|
|
|
1999-09-02 01:52:31 +00:00
|
|
|
if (client->opt != NULL) {
|
|
|
|
result = dns_message_setopt(client->message, client->opt);
|
2018-04-17 08:29:14 -07:00
|
|
|
opt_included = true;
|
1999-11-24 21:05:45 +00:00
|
|
|
client->opt = NULL;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-09-02 01:52:31 +00:00
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
result = dns_message_rendersection(client->message,
|
1999-12-22 03:22:59 +00:00
|
|
|
DNS_SECTION_QUESTION, 0);
|
2001-01-08 20:36:14 +00:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
|
|
|
client->message->flags |= DNS_MESSAGEFLAG_TC;
|
|
|
|
goto renderend;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-02-25 10:49:30 -08:00
|
|
|
/*
|
|
|
|
* Stop after the question if TC was set for rate limiting.
|
|
|
|
*/
|
2020-02-13 21:48:23 +01:00
|
|
|
if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0) {
|
2013-02-25 10:49:30 -08:00
|
|
|
goto renderend;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_rendersection(client->message, DNS_SECTION_ANSWER,
|
2002-01-23 08:46:40 +00:00
|
|
|
DNS_MESSAGERENDER_PARTIAL |
|
2020-02-12 13:59:18 +01:00
|
|
|
render_opts);
|
1999-09-01 18:25:05 +00:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
|
|
|
client->message->flags |= DNS_MESSAGEFLAG_TC;
|
|
|
|
goto renderend;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_rendersection(
|
|
|
|
client->message, DNS_SECTION_AUTHORITY,
|
|
|
|
DNS_MESSAGERENDER_PARTIAL | render_opts);
|
1999-09-01 18:25:05 +00:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
|
|
|
client->message->flags |= DNS_MESSAGEFLAG_TC;
|
|
|
|
goto renderend;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-07-28 02:20:36 +00:00
|
|
|
result = dns_message_rendersection(client->message,
|
2002-01-23 08:46:40 +00:00
|
|
|
DNS_SECTION_ADDITIONAL,
|
2009-10-26 23:14:54 +00:00
|
|
|
preferred_glue | render_opts);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS && result != ISC_R_NOSPACE) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
renderend:
|
1999-07-24 01:17:44 +00:00
|
|
|
result = dns_message_renderend(client->message);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-10-21 12:52:09 +02:00
|
|
|
goto cleanup;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-08-05 01:51:32 +00:00
|
|
|
|
2015-10-02 12:32:42 -07:00
|
|
|
#ifdef HAVE_DNSTAP
|
|
|
|
memset(&zr, 0, sizeof(zr));
|
|
|
|
if (((client->message->flags & DNS_MESSAGEFLAG_AA) != 0) &&
|
2020-02-13 14:44:37 -08:00
|
|
|
(client->query.authzone != NULL))
|
|
|
|
{
|
2020-10-21 12:52:09 +02:00
|
|
|
isc_result_t eresult;
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_buffer_t b;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_name_t *zo = dns_zone_getorigin(client->query.authzone);
|
2015-10-02 12:32:42 -07:00
|
|
|
|
|
|
|
isc_buffer_init(&b, zone, sizeof(zone));
|
|
|
|
dns_compress_setmethods(&cctx, DNS_COMPRESS_NONE);
|
2020-10-21 12:52:09 +02:00
|
|
|
eresult = dns_name_towire(zo, &cctx, &b);
|
|
|
|
if (eresult == ISC_R_SUCCESS) {
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_buffer_usedregion(&b, &zr);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
|
2018-10-02 14:13:14 -07:00
|
|
|
if (client->message->opcode == dns_opcode_update) {
|
|
|
|
dtmsgtype = DNS_DTTYPE_UR;
|
|
|
|
} else if ((client->message->flags & DNS_MESSAGEFLAG_RD) != 0) {
|
2015-10-02 12:32:42 -07:00
|
|
|
dtmsgtype = DNS_DTTYPE_CR;
|
2018-10-02 14:13:14 -07:00
|
|
|
} else {
|
2015-10-02 12:32:42 -07:00
|
|
|
dtmsgtype = DNS_DTTYPE_AR;
|
2018-10-02 14:13:14 -07:00
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
#endif /* HAVE_DNSTAP */
|
|
|
|
|
2001-03-05 21:15:47 +00:00
|
|
|
if (cleanup_cctx) {
|
|
|
|
dns_compress_invalidate(&cctx);
|
|
|
|
}
|
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
if (client->sendcb != NULL) {
|
|
|
|
client->sendcb(&buffer);
|
|
|
|
} else if (TCP_CLIENT(client)) {
|
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(&buffer, &r);
|
2015-10-02 12:32:42 -07:00
|
|
|
#ifdef HAVE_DNSTAP
|
|
|
|
if (client->view != NULL) {
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_dt_send(client->view, dtmsgtype, &client->peeraddr,
|
|
|
|
&client->destsockaddr, true, &zr,
|
|
|
|
&client->requesttime, NULL, &buffer);
|
2015-10-02 12:32:42 -07:00
|
|
|
}
|
|
|
|
#endif /* HAVE_DNSTAP */
|
|
|
|
|
2020-05-28 15:19:25 +10:00
|
|
|
respsize = isc_buffer_usedlength(&buffer);
|
2019-11-05 15:34:35 -08:00
|
|
|
|
2020-10-21 12:52:09 +02:00
|
|
|
client_sendpkg(client, &buffer);
|
2016-06-22 23:45:21 +00:00
|
|
|
|
2016-06-23 08:44:54 +10:00
|
|
|
switch (isc_sockaddr_pf(&client->peeraddr)) {
|
|
|
|
case AF_INET:
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_stats_increment(client->sctx->tcpoutstats4,
|
2016-06-23 08:44:54 +10:00
|
|
|
ISC_MIN((int)respsize / 16, 256));
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_stats_increment(client->sctx->tcpoutstats6,
|
2016-06-23 08:44:54 +10:00
|
|
|
ISC_MIN((int)respsize / 16, 256));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
2018-11-07 15:00:07 +07:00
|
|
|
ISC_UNREACHABLE();
|
2016-06-23 08:44:54 +10:00
|
|
|
}
|
2015-07-06 22:20:03 -07:00
|
|
|
} else {
|
2015-10-02 12:32:42 -07:00
|
|
|
#ifdef HAVE_DNSTAP
|
2018-10-02 14:13:14 -07:00
|
|
|
/*
|
|
|
|
* Log dnstap data first, because client_sendpkg() may
|
|
|
|
* leave client->view set to NULL.
|
|
|
|
*/
|
2015-10-02 12:32:42 -07:00
|
|
|
if (client->view != NULL) {
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_dt_send(client->view, dtmsgtype, &client->peeraddr,
|
|
|
|
&client->destsockaddr, false, &zr,
|
2015-10-02 12:32:42 -07:00
|
|
|
&client->requesttime, NULL, &buffer);
|
|
|
|
}
|
|
|
|
#endif /* HAVE_DNSTAP */
|
|
|
|
|
2018-10-02 14:13:14 -07:00
|
|
|
respsize = isc_buffer_usedlength(&buffer);
|
2019-11-05 15:34:35 -08:00
|
|
|
|
2020-10-21 12:52:09 +02:00
|
|
|
client_sendpkg(client, &buffer);
|
2018-10-02 14:13:14 -07:00
|
|
|
|
2016-06-23 08:44:54 +10:00
|
|
|
switch (isc_sockaddr_pf(&client->peeraddr)) {
|
|
|
|
case AF_INET:
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_stats_increment(client->sctx->udpoutstats4,
|
2016-06-23 08:44:54 +10:00
|
|
|
ISC_MIN((int)respsize / 16, 256));
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_stats_increment(client->sctx->udpoutstats6,
|
2016-06-23 08:44:54 +10:00
|
|
|
ISC_MIN((int)respsize / 16, 256));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
2018-11-07 15:00:07 +07:00
|
|
|
ISC_UNREACHABLE();
|
2016-06-23 08:44:54 +10:00
|
|
|
}
|
2015-07-06 22:20:03 -07:00
|
|
|
}
|
|
|
|
|
2008-04-03 05:55:52 +00:00
|
|
|
/* update statistics (XXXJT: is it okay to access message->xxxkey?) */
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats, ns_statscounter_response);
|
2015-07-06 22:20:03 -07:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
dns_rcodestats_increment(client->sctx->rcodestats,
|
2016-06-23 08:44:54 +10:00
|
|
|
client->message->rcode);
|
2008-04-03 05:55:52 +00:00
|
|
|
if (opt_included) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_edns0out);
|
2008-04-03 05:55:52 +00:00
|
|
|
}
|
|
|
|
if (client->message->tsigkey != NULL) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_tsigout);
|
2008-04-03 05:55:52 +00:00
|
|
|
}
|
|
|
|
if (client->message->sig0key != NULL) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_sig0out);
|
2008-04-03 05:55:52 +00:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if ((client->message->flags & DNS_MESSAGEFLAG_TC) != 0) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_truncatedresp);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2008-04-03 05:55:52 +00:00
|
|
|
|
Allow stale data to be used before name resolution
This commit allows stale RRset to be used (if available) for responding
a query, before an attempt to refresh an expired, or otherwise resolve
an unavailable RRset in cache is made.
For that to work, a value of zero must be specified for
stale-answer-client-timeout statement.
To better understand the logic implemented, there are three flags being
used during database lookup and other parts of code that must be
understood:
. DNS_DBFIND_STALEOK: This flag is set when BIND fails to refresh a
RRset due to timeout (resolver-query-timeout), its intent is to
try to look for stale data in cache as a fallback, but only if
stale answers are enabled in configuration.
This flag is also used to activate stale-refresh-time window, since it
is the only way the database knows that a resolution has failed.
. DNS_DBFIND_STALEENABLED: This flag is used as a hint to the database
that it may use stale data. It is always set during query lookup if
stale answers are enabled, but only effectively used during
stale-refresh-time window. Also during this window, the resolver will
not try to resolve the query, in other words no attempt to refresh the
data in cache is made when the stale-refresh-time window is active.
. DNS_DBFIND_STALEONLY: This new introduced flag is used when we want
stale data from the database, but not due to a failure in resolution,
it also doesn't require stale-refresh-time window timer to be active.
As long as there is a stale RRset available, it should be returned.
It is mainly used in two situations:
1. When stale-answer-client-timeout timer is triggered: in that case
we want to know if there is stale data available to answer the
client.
2. When stale-answer-client-timeout value is set to zero: in that
case, we also want to know if there is some stale RRset available
to promptly answer the client.
We must also discern between three situations that may happen when
resolving a query after the addition of stale-answer-client-timeout
statement, and how to handle them:
1. Are we running query_lookup() due to stale-answer-client-timeout
timer being triggered?
In this case, we look for stale data, making use of
DNS_DBFIND_STALEONLY flag. If a stale RRset is available then
respond the client with the data found, mark this query as
answered (query attribute NS_QUERYATTR_ANSWERED), so when the
fetch completes the client won't be answered twice.
We must also take care of not detaching from the client, as a
fetch will still be running in background, this is handled by the
following snippet:
if (!QUERY_STALEONLY(&client->query)) {
isc_nmhandle_detach(&client->reqhandle);
}
Which basically tests if DNS_DBFIND_STALEONLY flag is set, which
means we are here due to a stale-answer-client-timeout timer
expiration.
2. Are we running query_lookup() due to resolver-query-timeout being
triggered?
In this case, DNS_DBFIND_STALEOK flag will be set and an attempt
to look for stale data will be made.
As already explained, this flag is algo used to activate
stale-refresh-time window, as it means that we failed to refresh
a RRset due to timeout.
It is ok in this situation to detach from the client, as the
fetch is already completed.
3. Are we running query_lookup() during the first time, looking for
a RRset in cache and stale-answer-client-timeout value is set to
zero?
In this case, if stale answers are enabled (probably), we must do
an initial database lookup with DNS_DBFIND_STALEONLY flag set, to
indicate to the database that we want stale data.
If we find an active RRset, proceed as normal, answer the client
and the query is done.
If we find a stale RRset we respond to the client and mark the
query as answered, but don't detach from the client yet as an
attempt in refreshing the RRset will still be made by means of
the new introduced function 'query_resolve'.
If no active or stale RRset is available, begin resolution as
usual.
2020-12-21 15:54:54 -03:00
|
|
|
client->query.attributes |= NS_QUERYATTR_ANSWERED;
|
|
|
|
|
2020-10-21 12:52:09 +02:00
|
|
|
return;
|
2000-06-22 00:05:11 +00:00
|
|
|
|
2020-10-21 12:52:09 +02:00
|
|
|
cleanup:
|
2000-06-22 00:05:11 +00:00
|
|
|
if (client->tcpbuf != NULL) {
|
2019-11-05 15:34:35 -08:00
|
|
|
isc_mem_put(client->mctx, client->tcpbuf,
|
|
|
|
NS_CLIENT_TCP_BUFFER_SIZE);
|
2000-06-22 00:05:11 +00:00
|
|
|
client->tcpbuf = NULL;
|
|
|
|
}
|
2001-03-05 21:15:47 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (cleanup_cctx) {
|
2001-03-05 21:15:47 +00:00
|
|
|
dns_compress_invalidate(&cctx);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2012-09-29 13:07:09 +10:00
|
|
|
}
|
|
|
|
|
2006-01-04 05:06:10 +00:00
|
|
|
#if NS_CLIENT_DROPPORT
|
2020-02-13 14:44:37 -08:00
|
|
|
#define DROPPORT_NO 0
|
|
|
|
#define DROPPORT_REQUEST 1
|
2020-02-12 13:59:18 +01:00
|
|
|
#define DROPPORT_RESPONSE 2
|
2006-01-04 05:06:10 +00:00
|
|
|
/*%
|
|
|
|
* ns_client_dropport determines if certain requests / responses
|
|
|
|
* should be dropped based on the port number.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* \li 0: Don't drop.
|
|
|
|
* \li 1: Drop request.
|
|
|
|
* \li 2: Drop (error) response.
|
|
|
|
*/
|
|
|
|
static int
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_dropport(in_port_t port) {
|
2006-01-04 05:06:10 +00:00
|
|
|
switch (port) {
|
2020-02-12 13:59:18 +01:00
|
|
|
case 7: /* echo */
|
2006-01-04 05:06:10 +00:00
|
|
|
case 13: /* daytime */
|
|
|
|
case 19: /* chargen */
|
|
|
|
case 37: /* time */
|
|
|
|
return (DROPPORT_REQUEST);
|
|
|
|
case 464: /* kpasswd */
|
|
|
|
return (DROPPORT_RESPONSE);
|
|
|
|
}
|
|
|
|
return (DROPPORT_NO);
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* if NS_CLIENT_DROPPORT */
|
2006-01-04 05:06:10 +00:00
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_error(ns_client_t *client, isc_result_t result) {
|
|
|
|
dns_rcode_t rcode;
|
1999-08-03 01:21:00 +00:00
|
|
|
dns_message_t *message;
|
1999-07-24 01:17:44 +00:00
|
|
|
|
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
|
|
|
|
CTRACE("error");
|
|
|
|
|
1999-08-03 01:21:00 +00:00
|
|
|
message = client->message;
|
2019-04-22 17:19:23 -07:00
|
|
|
|
|
|
|
if (client->rcode_override == -1) {
|
|
|
|
rcode = dns_result_torcode(result);
|
|
|
|
} else {
|
|
|
|
rcode = (dns_rcode_t)(client->rcode_override & 0xfff);
|
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2006-01-04 05:06:10 +00:00
|
|
|
#if NS_CLIENT_DROPPORT
|
|
|
|
/*
|
|
|
|
* Don't send FORMERR to ports on the drop port list.
|
|
|
|
*/
|
|
|
|
if (rcode == dns_rcode_formerr &&
|
|
|
|
ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) !=
|
2020-02-13 14:44:37 -08:00
|
|
|
DROPPORT_NO)
|
|
|
|
{
|
|
|
|
char buf[64];
|
2006-01-04 05:06:10 +00:00
|
|
|
isc_buffer_t b;
|
|
|
|
|
|
|
|
isc_buffer_init(&b, buf, sizeof(buf) - 1);
|
2019-04-22 17:19:23 -07:00
|
|
|
if (dns_rcode_totext(rcode, &b) != ISC_R_SUCCESS) {
|
2006-01-04 05:06:10 +00:00
|
|
|
isc_buffer_putstr(&b, "UNKNOWN RCODE");
|
2019-04-22 17:19:23 -07:00
|
|
|
}
|
2006-01-04 05:06:10 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
|
|
|
|
"dropped error (%.*s) response: suspicious port",
|
|
|
|
(int)isc_buffer_usedlength(&b), buf);
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_drop(client, ISC_R_SUCCESS);
|
2006-01-04 05:06:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* if NS_CLIENT_DROPPORT */
|
2006-01-04 05:06:10 +00:00
|
|
|
|
2013-02-25 10:49:30 -08:00
|
|
|
/*
|
|
|
|
* Try to rate limit error responses.
|
|
|
|
*/
|
|
|
|
if (client->view != NULL && client->view->rrl != NULL) {
|
2020-02-13 14:44:37 -08:00
|
|
|
bool wouldlog;
|
|
|
|
char log_buf[DNS_RRL_LOG_BUF_LEN];
|
2013-02-25 10:49:30 -08:00
|
|
|
dns_rrl_result_t rrl_result;
|
2020-02-13 14:44:37 -08:00
|
|
|
int loglevel;
|
2013-02-25 10:49:30 -08:00
|
|
|
|
|
|
|
INSIST(rcode != dns_rcode_noerror &&
|
|
|
|
rcode != dns_rcode_nxdomain);
|
2019-04-22 17:19:23 -07:00
|
|
|
if ((client->sctx->options & NS_SERVER_LOGQUERIES) != 0) {
|
2015-02-25 16:44:43 -08:00
|
|
|
loglevel = DNS_RRL_LOG_DROP;
|
2019-04-22 17:19:23 -07:00
|
|
|
} else {
|
2015-02-25 16:44:43 -08:00
|
|
|
loglevel = ISC_LOG_DEBUG(1);
|
2019-04-22 17:19:23 -07:00
|
|
|
}
|
2017-09-08 13:39:09 -07:00
|
|
|
wouldlog = isc_log_wouldlog(ns_lctx, loglevel);
|
2020-02-12 13:59:18 +01:00
|
|
|
rrl_result = dns_rrl(
|
|
|
|
client->view, &client->peeraddr, TCP_CLIENT(client),
|
|
|
|
dns_rdataclass_in, dns_rdatatype_none, NULL, result,
|
|
|
|
client->now, wouldlog, log_buf, sizeof(log_buf));
|
2013-02-25 10:49:30 -08:00
|
|
|
if (rrl_result != DNS_RRL_RESULT_OK) {
|
|
|
|
/*
|
|
|
|
* Log dropped errors in the query category
|
|
|
|
* so that they are not lost in silence.
|
|
|
|
* Starts of rate-limited bursts are logged in
|
|
|
|
* NS_LOGCATEGORY_RRL.
|
|
|
|
*/
|
|
|
|
if (wouldlog) {
|
2013-05-21 12:20:54 -07:00
|
|
|
ns_client_log(client,
|
2015-09-29 15:02:49 +10:00
|
|
|
NS_LOGCATEGORY_QUERY_ERRORS,
|
2020-02-12 13:59:18 +01:00
|
|
|
NS_LOGMODULE_CLIENT, loglevel,
|
2013-02-25 10:49:30 -08:00
|
|
|
"%s", log_buf);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Some error responses cannot be 'slipped',
|
2013-04-25 14:40:32 -07:00
|
|
|
* so don't try to slip any error responses.
|
2013-02-25 10:49:30 -08:00
|
|
|
*/
|
|
|
|
if (!client->view->rrl->log_only) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_ratedropped);
|
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_dropped);
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_drop(client, DNS_R_DROP);
|
2013-02-25 10:49:30 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-28 02:20:36 +00:00
|
|
|
/*
|
2000-06-22 23:04:27 +00:00
|
|
|
* Message may be an in-progress reply that we had trouble
|
1999-07-28 02:20:36 +00:00
|
|
|
* with, in which case QR will be set. We need to clear QR before
|
|
|
|
* calling dns_message_reply() to avoid triggering an assertion.
|
|
|
|
*/
|
1999-08-03 01:21:00 +00:00
|
|
|
message->flags &= ~DNS_MESSAGEFLAG_QR;
|
1999-10-07 19:43:18 +00:00
|
|
|
/*
|
|
|
|
* AA and AD shouldn't be set.
|
|
|
|
*/
|
|
|
|
message->flags &= ~(DNS_MESSAGEFLAG_AA | DNS_MESSAGEFLAG_AD);
|
2018-04-17 08:29:14 -07:00
|
|
|
result = dns_message_reply(message, true);
|
1999-07-24 01:17:44 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
1999-08-03 01:21:00 +00:00
|
|
|
/*
|
|
|
|
* It could be that we've got a query with a good header,
|
|
|
|
* but a bad question section, so we try again with
|
2018-04-17 08:29:14 -07:00
|
|
|
* want_question_section set to false.
|
1999-08-03 01:21:00 +00:00
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
result = dns_message_reply(message, false);
|
1999-08-03 01:21:00 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_drop(client, result);
|
1999-08-03 01:21:00 +00:00
|
|
|
return;
|
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|
1999-08-03 01:21:00 +00:00
|
|
|
message->rcode = rcode;
|
2001-03-19 20:52:21 +00:00
|
|
|
|
|
|
|
if (rcode == dns_rcode_formerr) {
|
2014-09-03 23:28:14 -07:00
|
|
|
/*
|
|
|
|
* FORMERR loop avoidance: If we sent a FORMERR message
|
|
|
|
* with the same ID to the same client less than two
|
|
|
|
* seconds ago, assume that we are in an infinite error
|
|
|
|
* packet dialog with a server for some protocol whose
|
|
|
|
* error responses look enough like DNS queries to
|
|
|
|
* elicit a FORMERR response. Drop a packet to break
|
|
|
|
* the loop.
|
|
|
|
*/
|
2001-03-19 20:52:21 +00:00
|
|
|
if (isc_sockaddr_equal(&client->peeraddr,
|
|
|
|
&client->formerrcache.addr) &&
|
|
|
|
message->id == client->formerrcache.id &&
|
2015-10-02 12:32:42 -07:00
|
|
|
(isc_time_seconds(&client->requesttime) -
|
2020-02-13 14:44:37 -08:00
|
|
|
client->formerrcache.time) < 2)
|
|
|
|
{
|
2001-03-19 20:52:21 +00:00
|
|
|
/* Drop packet. */
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
|
|
|
"possible error packet loop, "
|
|
|
|
"FORMERR dropped");
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_drop(client, result);
|
2001-03-19 20:52:21 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
client->formerrcache.addr = client->peeraddr;
|
2015-10-02 12:32:42 -07:00
|
|
|
client->formerrcache.time =
|
|
|
|
isc_time_seconds(&client->requesttime);
|
2001-03-19 20:52:21 +00:00
|
|
|
client->formerrcache.id = message->id;
|
2014-10-01 07:24:16 +10:00
|
|
|
} else if (rcode == dns_rcode_servfail && client->query.qname != NULL &&
|
2014-09-03 23:28:14 -07:00
|
|
|
client->view != NULL && client->view->fail_ttl != 0 &&
|
2020-02-13 14:44:37 -08:00
|
|
|
((client->attributes & NS_CLIENTATTR_NOSETFC) == 0))
|
|
|
|
{
|
2014-09-03 23:28:14 -07:00
|
|
|
/*
|
|
|
|
* SERVFAIL caching: store qname/qtype of failed queries
|
|
|
|
*/
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_time_t expire;
|
2014-09-03 23:28:14 -07:00
|
|
|
isc_interval_t i;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t flags = 0;
|
2014-09-03 23:28:14 -07:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if ((message->flags & DNS_MESSAGEFLAG_CD) != 0) {
|
2014-09-03 23:28:14 -07:00
|
|
|
flags = NS_FAILCACHE_CD;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-09-03 23:28:14 -07:00
|
|
|
|
|
|
|
isc_interval_set(&i, client->view->fail_ttl, 0);
|
|
|
|
result = isc_time_nowplusinterval(&expire, &i);
|
2019-04-22 17:19:23 -07:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_badcache_add(
|
|
|
|
client->view->failcache, client->query.qname,
|
|
|
|
client->query.qtype, true, flags, &expire);
|
2019-04-22 17:19:23 -07:00
|
|
|
}
|
2001-03-19 20:52:21 +00:00
|
|
|
}
|
2019-04-22 17:19:23 -07:00
|
|
|
|
Allow stale data to be used before name resolution
This commit allows stale RRset to be used (if available) for responding
a query, before an attempt to refresh an expired, or otherwise resolve
an unavailable RRset in cache is made.
For that to work, a value of zero must be specified for
stale-answer-client-timeout statement.
To better understand the logic implemented, there are three flags being
used during database lookup and other parts of code that must be
understood:
. DNS_DBFIND_STALEOK: This flag is set when BIND fails to refresh a
RRset due to timeout (resolver-query-timeout), its intent is to
try to look for stale data in cache as a fallback, but only if
stale answers are enabled in configuration.
This flag is also used to activate stale-refresh-time window, since it
is the only way the database knows that a resolution has failed.
. DNS_DBFIND_STALEENABLED: This flag is used as a hint to the database
that it may use stale data. It is always set during query lookup if
stale answers are enabled, but only effectively used during
stale-refresh-time window. Also during this window, the resolver will
not try to resolve the query, in other words no attempt to refresh the
data in cache is made when the stale-refresh-time window is active.
. DNS_DBFIND_STALEONLY: This new introduced flag is used when we want
stale data from the database, but not due to a failure in resolution,
it also doesn't require stale-refresh-time window timer to be active.
As long as there is a stale RRset available, it should be returned.
It is mainly used in two situations:
1. When stale-answer-client-timeout timer is triggered: in that case
we want to know if there is stale data available to answer the
client.
2. When stale-answer-client-timeout value is set to zero: in that
case, we also want to know if there is some stale RRset available
to promptly answer the client.
We must also discern between three situations that may happen when
resolving a query after the addition of stale-answer-client-timeout
statement, and how to handle them:
1. Are we running query_lookup() due to stale-answer-client-timeout
timer being triggered?
In this case, we look for stale data, making use of
DNS_DBFIND_STALEONLY flag. If a stale RRset is available then
respond the client with the data found, mark this query as
answered (query attribute NS_QUERYATTR_ANSWERED), so when the
fetch completes the client won't be answered twice.
We must also take care of not detaching from the client, as a
fetch will still be running in background, this is handled by the
following snippet:
if (!QUERY_STALEONLY(&client->query)) {
isc_nmhandle_detach(&client->reqhandle);
}
Which basically tests if DNS_DBFIND_STALEONLY flag is set, which
means we are here due to a stale-answer-client-timeout timer
expiration.
2. Are we running query_lookup() due to resolver-query-timeout being
triggered?
In this case, DNS_DBFIND_STALEOK flag will be set and an attempt
to look for stale data will be made.
As already explained, this flag is algo used to activate
stale-refresh-time window, as it means that we failed to refresh
a RRset due to timeout.
It is ok in this situation to detach from the client, as the
fetch is already completed.
3. Are we running query_lookup() during the first time, looking for
a RRset in cache and stale-answer-client-timeout value is set to
zero?
In this case, if stale answers are enabled (probably), we must do
an initial database lookup with DNS_DBFIND_STALEONLY flag set, to
indicate to the database that we want stale data.
If we find an active RRset, proceed as normal, answer the client
and the query is done.
If we find a stale RRset we respond to the client and mark the
query as answered, but don't detach from the client yet as an
attempt in refreshing the RRset will still be made by means of
the new introduced function 'query_resolve'.
If no active or stale RRset is available, begin resolution as
usual.
2020-12-21 15:54:54 -03:00
|
|
|
ns_client_send(client);
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|
|
|
|
|
2014-02-20 17:51:31 +11:00
|
|
|
isc_result_t
|
|
|
|
ns_client_addopt(ns_client_t *client, dns_message_t *message,
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_rdataset_t **opt) {
|
|
|
|
unsigned char ecs[ECS_SIZE];
|
2021-05-22 18:12:11 +02:00
|
|
|
char nsid[BUFSIZ], *nsidp = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned char cookie[COOKIE_SIZE];
|
|
|
|
isc_result_t result;
|
2021-05-22 18:12:11 +02:00
|
|
|
dns_view_t *view = NULL;
|
|
|
|
dns_resolver_t *resolver = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint16_t udpsize;
|
|
|
|
dns_ednsopt_t ednsopts[DNS_EDNSOPTIONS];
|
|
|
|
int count = 0;
|
|
|
|
unsigned int flags;
|
|
|
|
unsigned char expire[4];
|
|
|
|
unsigned char advtimo[2];
|
2021-05-22 18:12:11 +02:00
|
|
|
dns_aclenv_t *env = NULL;
|
1999-09-02 01:52:31 +00:00
|
|
|
|
2014-02-20 17:51:31 +11:00
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(opt != NULL && *opt == NULL);
|
|
|
|
REQUIRE(message != NULL);
|
1999-09-02 01:52:31 +00:00
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
env = client->manager->aclenv;
|
2003-02-26 02:04:00 +00:00
|
|
|
view = client->view;
|
|
|
|
resolver = (view != NULL) ? view->resolver : NULL;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (resolver != NULL) {
|
2003-02-26 02:04:00 +00:00
|
|
|
udpsize = dns_resolver_getudpsize(resolver);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2017-09-08 13:39:09 -07:00
|
|
|
udpsize = client->sctx->udpsize;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
1999-09-02 01:52:31 +00:00
|
|
|
|
2013-08-15 12:01:12 +10:00
|
|
|
flags = client->extflags & DNS_MESSAGEEXTFLAG_REPLYPRESERVE;
|
1999-09-02 01:52:31 +00:00
|
|
|
|
2008-04-03 02:01:08 +00:00
|
|
|
/* Set EDNS options if applicable */
|
2017-09-08 13:39:09 -07:00
|
|
|
if (WANTNSID(client)) {
|
|
|
|
if (client->sctx->server_id != NULL) {
|
|
|
|
nsidp = client->sctx->server_id;
|
|
|
|
} else if (client->sctx->gethostname != NULL) {
|
|
|
|
result = client->sctx->gethostname(nsid, sizeof(nsid));
|
2008-04-03 02:01:08 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto no_nsid;
|
|
|
|
}
|
2008-11-16 20:57:55 +00:00
|
|
|
nsidp = nsid;
|
2017-09-08 13:39:09 -07:00
|
|
|
} else {
|
|
|
|
goto no_nsid;
|
|
|
|
}
|
2008-04-03 02:01:08 +00:00
|
|
|
|
2014-02-20 14:00:54 +11:00
|
|
|
INSIST(count < DNS_EDNSOPTIONS);
|
2013-08-15 12:01:12 +10:00
|
|
|
ednsopts[count].code = DNS_OPT_NSID;
|
2018-03-28 14:19:37 +02:00
|
|
|
ednsopts[count].length = (uint16_t)strlen(nsidp);
|
2013-08-15 12:01:12 +10:00
|
|
|
ednsopts[count].value = (unsigned char *)nsidp;
|
|
|
|
count++;
|
2008-04-03 02:01:08 +00:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
no_nsid:
|
2015-07-06 09:44:24 +10:00
|
|
|
if ((client->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0) {
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_buffer_t buf;
|
2014-02-19 12:53:42 +11:00
|
|
|
isc_stdtime_t now;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t nonce;
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
isc_buffer_init(&buf, cookie, sizeof(cookie));
|
2014-02-19 12:53:42 +11:00
|
|
|
isc_stdtime_get(&now);
|
2017-09-28 10:09:22 -07:00
|
|
|
|
2018-10-12 11:59:33 +00:00
|
|
|
isc_random_buf(&nonce, sizeof(nonce));
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
compute_cookie(client, now, nonce, client->sctx->secret, &buf);
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2014-02-20 14:00:54 +11:00
|
|
|
INSIST(count < DNS_EDNSOPTIONS);
|
2015-07-06 09:44:24 +10:00
|
|
|
ednsopts[count].code = DNS_OPT_COOKIE;
|
|
|
|
ednsopts[count].length = COOKIE_SIZE;
|
|
|
|
ednsopts[count].value = cookie;
|
2014-02-19 12:53:42 +11:00
|
|
|
count++;
|
|
|
|
}
|
2014-02-20 14:56:20 +11:00
|
|
|
if ((client->attributes & NS_CLIENTATTR_HAVEEXPIRE) != 0) {
|
|
|
|
isc_buffer_t buf;
|
|
|
|
|
|
|
|
INSIST(count < DNS_EDNSOPTIONS);
|
|
|
|
|
|
|
|
isc_buffer_init(&buf, expire, sizeof(expire));
|
|
|
|
isc_buffer_putuint32(&buf, client->expire);
|
|
|
|
ednsopts[count].code = DNS_OPT_EXPIRE;
|
|
|
|
ednsopts[count].length = 4;
|
|
|
|
ednsopts[count].value = expire;
|
|
|
|
count++;
|
|
|
|
}
|
2014-08-28 22:05:57 -07:00
|
|
|
if (((client->attributes & NS_CLIENTATTR_HAVEECS) != 0) &&
|
2017-02-02 11:54:28 -08:00
|
|
|
(client->ecs.addr.family == AF_INET ||
|
|
|
|
client->ecs.addr.family == AF_INET6 ||
|
2020-02-13 14:44:37 -08:00
|
|
|
client->ecs.addr.family == AF_UNSPEC))
|
|
|
|
{
|
2014-08-28 22:05:57 -07:00
|
|
|
isc_buffer_t buf;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint8_t addr[16];
|
|
|
|
uint32_t plen, addrl;
|
|
|
|
uint16_t family = 0;
|
2016-09-14 08:22:15 +10:00
|
|
|
|
|
|
|
/* Add CLIENT-SUBNET option. */
|
|
|
|
|
2017-02-02 11:54:28 -08:00
|
|
|
plen = client->ecs.source;
|
2016-09-14 08:22:15 +10:00
|
|
|
|
|
|
|
/* Round up prefix len to a multiple of 8 */
|
|
|
|
addrl = (plen + 7) / 8;
|
|
|
|
|
2017-02-02 11:54:28 -08:00
|
|
|
switch (client->ecs.addr.family) {
|
2016-09-14 08:22:15 +10:00
|
|
|
case AF_UNSPEC:
|
|
|
|
INSIST(plen == 0);
|
|
|
|
family = 0;
|
|
|
|
break;
|
|
|
|
case AF_INET:
|
|
|
|
INSIST(plen <= 32);
|
|
|
|
family = 1;
|
2017-02-02 11:54:28 -08:00
|
|
|
memmove(addr, &client->ecs.addr.type, addrl);
|
2016-09-14 08:22:15 +10:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
INSIST(plen <= 128);
|
|
|
|
family = 2;
|
2017-02-02 11:54:28 -08:00
|
|
|
memmove(addr, &client->ecs.addr.type, addrl);
|
2016-09-14 08:22:15 +10:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
2018-11-07 15:00:07 +07:00
|
|
|
ISC_UNREACHABLE();
|
2016-09-14 08:22:15 +10:00
|
|
|
}
|
2014-08-28 22:05:57 -07:00
|
|
|
|
|
|
|
isc_buffer_init(&buf, ecs, sizeof(ecs));
|
2016-09-14 08:22:15 +10:00
|
|
|
/* family */
|
|
|
|
isc_buffer_putuint16(&buf, family);
|
|
|
|
/* source prefix-length */
|
2017-02-02 11:54:28 -08:00
|
|
|
isc_buffer_putuint8(&buf, client->ecs.source);
|
2016-09-14 08:22:15 +10:00
|
|
|
/* scope prefix-length */
|
2017-02-02 11:54:28 -08:00
|
|
|
isc_buffer_putuint8(&buf, client->ecs.scope);
|
2014-08-28 22:05:57 -07:00
|
|
|
|
2016-09-14 08:22:15 +10:00
|
|
|
/* address */
|
|
|
|
if (addrl > 0) {
|
|
|
|
/* Mask off last address byte */
|
2020-02-13 21:48:23 +01:00
|
|
|
if ((plen % 8) != 0) {
|
2020-02-12 13:59:18 +01:00
|
|
|
addr[addrl - 1] &= ~0U << (8 - (plen % 8));
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_putmem(&buf, addr, (unsigned)addrl);
|
2014-08-28 22:05:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
ednsopts[count].code = DNS_OPT_CLIENT_SUBNET;
|
2016-09-14 08:22:15 +10:00
|
|
|
ednsopts[count].length = addrl + 4;
|
2014-08-28 22:05:57 -07:00
|
|
|
ednsopts[count].value = ecs;
|
|
|
|
count++;
|
|
|
|
}
|
2017-01-04 09:16:30 -08:00
|
|
|
if (TCP_CLIENT(client) && USEKEEPALIVE(client)) {
|
|
|
|
isc_buffer_t buf;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint32_t adv;
|
2017-01-04 09:16:30 -08:00
|
|
|
|
|
|
|
INSIST(count < DNS_EDNSOPTIONS);
|
|
|
|
|
Refactor netmgr and add more unit tests
This is a part of the works that intends to make the netmgr stable,
testable, maintainable and tested. It contains a numerous changes to
the netmgr code and unfortunately, it was not possible to split this
into smaller chunks as the work here needs to be committed as a complete
works.
NOTE: There's a quite a lot of duplicated code between udp.c, tcp.c and
tcpdns.c and it should be a subject to refactoring in the future.
The changes that are included in this commit are listed here
(extensively, but not exclusively):
* The netmgr_test unit test was split into individual tests (udp_test,
tcp_test, tcpdns_test and newly added tcp_quota_test)
* The udp_test and tcp_test has been extended to allow programatic
failures from the libuv API. Unfortunately, we can't use cmocka
mock() and will_return(), so we emulate the behaviour with #define and
including the netmgr/{udp,tcp}.c source file directly.
* The netievents that we put on the nm queue have variable number of
members, out of these the isc_nmsocket_t and isc_nmhandle_t always
needs to be attached before enqueueing the netievent_<foo> and
detached after we have called the isc_nm_async_<foo> to ensure that
the socket (handle) doesn't disappear between scheduling the event and
actually executing the event.
* Cancelling the in-flight TCP connection using libuv requires to call
uv_close() on the original uv_tcp_t handle which just breaks too many
assumptions we have in the netmgr code. Instead of using uv_timer for
TCP connection timeouts, we use platform specific socket option.
* Fix the synchronization between {nm,async}_{listentcp,tcpconnect}
When isc_nm_listentcp() or isc_nm_tcpconnect() is called it was
waiting for socket to either end up with error (that path was fine) or
to be listening or connected using condition variable and mutex.
Several things could happen:
0. everything is ok
1. the waiting thread would miss the SIGNAL() - because the enqueued
event would be processed faster than we could start WAIT()ing.
In case the operation would end up with error, it would be ok, as
the error variable would be unchanged.
2. the waiting thread miss the sock->{connected,listening} = `true`
would be set to `false` in the tcp_{listen,connect}close_cb() as
the connection would be so short lived that the socket would be
closed before we could even start WAIT()ing
* The tcpdns has been converted to using libuv directly. Previously,
the tcpdns protocol used tcp protocol from netmgr, this proved to be
very complicated to understand, fix and make changes to. The new
tcpdns protocol is modeled in a similar way how tcp netmgr protocol.
Closes: #2194, #2283, #2318, #2266, #2034, #1920
* The tcp and tcpdns is now not using isc_uv_import/isc_uv_export to
pass accepted TCP sockets between netthreads, but instead (similar to
UDP) uses per netthread uv_loop listener. This greatly reduces the
complexity as the socket is always run in the associated nm and uv
loops, and we are also not touching the libuv internals.
There's an unfortunate side effect though, the new code requires
support for load-balanced sockets from the operating system for both
UDP and TCP (see #2137). If the operating system doesn't support the
load balanced sockets (either SO_REUSEPORT on Linux or SO_REUSEPORT_LB
on FreeBSD 12+), the number of netthreads is limited to 1.
* The netmgr has now two debugging #ifdefs:
1. Already existing NETMGR_TRACE prints any dangling nmsockets and
nmhandles before triggering assertion failure. This options would
reduce performance when enabled, but in theory, it could be enabled
on low-performance systems.
2. New NETMGR_TRACE_VERBOSE option has been added that enables
extensive netmgr logging that allows the software engineer to
precisely track any attach/detach operations on the nmsockets and
nmhandles. This is not suitable for any kind of production
machine, only for debugging.
* The tlsdns netmgr protocol has been split from the tcpdns and it still
uses the old method of stacking the netmgr boxes on top of each other.
We will have to refactor the tlsdns netmgr protocol to use the same
approach - build the stack using only libuv and openssl.
* Limit but not assert the tcp buffer size in tcp_alloc_cb
Closes: #2061
2020-11-12 10:32:18 +01:00
|
|
|
isc_nm_gettimeouts(isc_nmhandle_netmgr(client->handle), NULL,
|
|
|
|
NULL, NULL, &adv);
|
2021-03-18 11:16:45 +01:00
|
|
|
adv /= 100; /* units of 100 milliseconds */
|
2017-01-04 09:16:30 -08:00
|
|
|
isc_buffer_init(&buf, advtimo, sizeof(advtimo));
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_putuint16(&buf, (uint16_t)adv);
|
2017-01-04 09:16:30 -08:00
|
|
|
ednsopts[count].code = DNS_OPT_TCP_KEEPALIVE;
|
|
|
|
ednsopts[count].length = 2;
|
|
|
|
ednsopts[count].value = advtimo;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Padding must be added last */
|
|
|
|
if ((view != NULL) && (view->padding > 0) && WANTPAD(client) &&
|
|
|
|
(TCP_CLIENT(client) ||
|
2020-02-13 14:44:37 -08:00
|
|
|
((client->attributes & NS_CLIENTATTR_HAVECOOKIE) != 0)))
|
|
|
|
{
|
2017-01-04 09:16:30 -08:00
|
|
|
isc_netaddr_t netaddr;
|
2020-02-13 14:44:37 -08:00
|
|
|
int match;
|
2017-01-04 09:16:30 -08:00
|
|
|
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_acl_match(&netaddr, NULL, view->pad_acl, env,
|
|
|
|
&match, NULL);
|
2017-01-04 09:16:30 -08:00
|
|
|
if (result == ISC_R_SUCCESS && match > 0) {
|
|
|
|
INSIST(count < DNS_EDNSOPTIONS);
|
|
|
|
|
|
|
|
ednsopts[count].code = DNS_OPT_PAD;
|
|
|
|
ednsopts[count].length = 0;
|
|
|
|
ednsopts[count].value = NULL;
|
|
|
|
count++;
|
|
|
|
|
|
|
|
dns_message_setpadding(message, view->padding);
|
|
|
|
}
|
|
|
|
}
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_buildopt(message, opt, 0, udpsize, flags, ednsopts,
|
|
|
|
count);
|
2013-08-15 12:01:12 +10:00
|
|
|
return (result);
|
1999-09-02 01:52:31 +00:00
|
|
|
}
|
|
|
|
|
2014-02-19 12:53:42 +11:00
|
|
|
static void
|
2018-03-28 14:19:37 +02:00
|
|
|
compute_cookie(ns_client_t *client, uint32_t when, uint32_t nonce,
|
2020-02-13 14:44:37 -08:00
|
|
|
const unsigned char *secret, isc_buffer_t *buf) {
|
2020-02-12 13:59:18 +01:00
|
|
|
unsigned char digest[ISC_MAX_MD_SIZE] ISC_NONSTRING = { 0 };
|
|
|
|
STATIC_ASSERT(ISC_MAX_MD_SIZE >= ISC_SIPHASH24_TAG_LENGTH, "You need "
|
|
|
|
"to "
|
|
|
|
"increase "
|
|
|
|
"the digest "
|
|
|
|
"buffer.");
|
|
|
|
STATIC_ASSERT(ISC_MAX_MD_SIZE >= ISC_AES_BLOCK_LENGTH, "You need to "
|
|
|
|
"increase the "
|
|
|
|
"digest "
|
|
|
|
"buffer.");
|
2019-07-21 14:26:49 -04:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
switch (client->sctx->cookiealg) {
|
2019-07-21 14:26:49 -04:00
|
|
|
case ns_cookiealg_siphash24: {
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned char input[16 + 16] ISC_NONSTRING = { 0 };
|
|
|
|
size_t inputlen = 0;
|
|
|
|
isc_netaddr_t netaddr;
|
2019-07-21 14:26:49 -04:00
|
|
|
unsigned char *cp;
|
|
|
|
|
|
|
|
cp = isc_buffer_used(buf);
|
|
|
|
isc_buffer_putmem(buf, client->cookie, 8);
|
|
|
|
isc_buffer_putuint8(buf, NS_COOKIE_VERSION_1);
|
|
|
|
isc_buffer_putuint24(buf, 0); /* Reserved */
|
|
|
|
isc_buffer_putuint32(buf, when);
|
|
|
|
|
|
|
|
memmove(input, cp, 16);
|
|
|
|
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
|
|
|
|
switch (netaddr.family) {
|
|
|
|
case AF_INET:
|
|
|
|
cp = (unsigned char *)&netaddr.type.in;
|
|
|
|
memmove(input + 16, cp, 4);
|
|
|
|
inputlen = 20;
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
cp = (unsigned char *)&netaddr.type.in6;
|
|
|
|
memmove(input + 16, cp, 16);
|
|
|
|
inputlen = 32;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
|
|
|
ISC_UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_siphash24(secret, input, inputlen, digest);
|
|
|
|
isc_buffer_putmem(buf, digest, 8);
|
|
|
|
break;
|
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
case ns_cookiealg_aes: {
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned char input[4 + 4 + 16] ISC_NONSTRING = { 0 };
|
|
|
|
isc_netaddr_t netaddr;
|
2015-07-06 09:44:24 +10:00
|
|
|
unsigned char *cp;
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int i;
|
2015-07-06 09:44:24 +10:00
|
|
|
|
|
|
|
cp = isc_buffer_used(buf);
|
|
|
|
isc_buffer_putmem(buf, client->cookie, 8);
|
|
|
|
isc_buffer_putuint32(buf, nonce);
|
|
|
|
isc_buffer_putuint32(buf, when);
|
|
|
|
memmove(input, cp, 16);
|
2017-09-05 09:19:45 +10:00
|
|
|
isc_aes128_crypt(secret, input, digest);
|
2019-07-21 14:26:49 -04:00
|
|
|
for (i = 0; i < 8; i++) {
|
2015-07-06 09:44:24 +10:00
|
|
|
input[i] = digest[i] ^ digest[i + 8];
|
2019-07-21 14:26:49 -04:00
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
|
|
|
|
switch (netaddr.family) {
|
|
|
|
case AF_INET:
|
|
|
|
cp = (unsigned char *)&netaddr.type.in;
|
|
|
|
memmove(input + 8, cp, 4);
|
|
|
|
memset(input + 12, 0, 4);
|
2017-09-05 09:19:45 +10:00
|
|
|
isc_aes128_crypt(secret, input, digest);
|
2015-07-06 09:44:24 +10:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
cp = (unsigned char *)&netaddr.type.in6;
|
|
|
|
memmove(input + 8, cp, 16);
|
2017-09-05 09:19:45 +10:00
|
|
|
isc_aes128_crypt(secret, input, digest);
|
2019-07-21 14:26:49 -04:00
|
|
|
for (i = 0; i < 8; i++) {
|
2015-07-06 09:44:24 +10:00
|
|
|
input[i + 8] = digest[i] ^ digest[i + 8];
|
2019-07-21 14:26:49 -04:00
|
|
|
}
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_aes128_crypt(client->sctx->secret, input + 8,
|
2015-07-06 09:44:24 +10:00
|
|
|
digest);
|
|
|
|
break;
|
2019-07-21 14:26:49 -04:00
|
|
|
default:
|
|
|
|
INSIST(0);
|
|
|
|
ISC_UNREACHABLE();
|
2015-07-06 09:44:24 +10:00
|
|
|
}
|
2019-07-21 14:26:49 -04:00
|
|
|
for (i = 0; i < 8; i++) {
|
2015-07-06 09:44:24 +10:00
|
|
|
digest[i] ^= digest[i + 8];
|
2019-07-21 14:26:49 -04:00
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
isc_buffer_putmem(buf, digest, 8);
|
2014-02-19 12:53:42 +11:00
|
|
|
break;
|
|
|
|
}
|
2015-07-06 09:44:24 +10:00
|
|
|
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
2018-11-07 15:00:07 +07:00
|
|
|
ISC_UNREACHABLE();
|
2015-07-06 09:44:24 +10:00
|
|
|
}
|
2014-02-19 12:53:42 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
2017-09-05 09:19:45 +10:00
|
|
|
ns_altsecret_t *altsecret;
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned char dbuf[COOKIE_SIZE];
|
|
|
|
unsigned char *old;
|
|
|
|
isc_stdtime_t now;
|
|
|
|
uint32_t when;
|
|
|
|
uint32_t nonce;
|
|
|
|
isc_buffer_t db;
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
/*
|
|
|
|
* If we have already seen a cookie option skip this cookie option.
|
|
|
|
*/
|
2018-03-19 18:09:05 +05:30
|
|
|
if ((!client->sctx->answercookie) ||
|
2020-02-13 14:44:37 -08:00
|
|
|
(client->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0)
|
|
|
|
{
|
2015-07-06 09:44:24 +10:00
|
|
|
isc_buffer_forward(buf, (unsigned int)optlen);
|
|
|
|
return;
|
|
|
|
}
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
client->attributes |= NS_CLIENTATTR_WANTCOOKIE;
|
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats, ns_statscounter_cookiein);
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
if (optlen != COOKIE_SIZE) {
|
2014-02-19 12:53:42 +11:00
|
|
|
/*
|
|
|
|
* Not our token.
|
|
|
|
*/
|
2015-07-06 09:44:24 +10:00
|
|
|
INSIST(optlen >= 8U);
|
|
|
|
memmove(client->cookie, isc_buffer_current(buf), 8);
|
2014-02-19 23:17:52 +01:00
|
|
|
isc_buffer_forward(buf, (unsigned int)optlen);
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (optlen == 8U) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_cookienew);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_cookiebadsize);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-19 12:53:42 +11:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process all of the incoming buffer.
|
|
|
|
*/
|
|
|
|
old = isc_buffer_current(buf);
|
2014-02-24 09:29:49 +11:00
|
|
|
memmove(client->cookie, old, 8);
|
2014-02-19 12:53:42 +11:00
|
|
|
isc_buffer_forward(buf, 8);
|
|
|
|
nonce = isc_buffer_getuint32(buf);
|
|
|
|
when = isc_buffer_getuint32(buf);
|
|
|
|
isc_buffer_forward(buf, 8);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allow for a 5 minute clock skew between servers sharing a secret.
|
2015-07-06 09:44:24 +10:00
|
|
|
* Only accept COOKIE if we have talked to the client in the last hour.
|
2014-02-19 12:53:42 +11:00
|
|
|
*/
|
|
|
|
isc_stdtime_get(&now);
|
2020-02-13 14:44:37 -08:00
|
|
|
if (isc_serial_gt(when, (now + 300)) || /* In the future. */
|
|
|
|
isc_serial_lt(when, (now - 3600)))
|
|
|
|
{ /* In the past. */
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_cookiebadtime);
|
2014-02-19 12:53:42 +11:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_buffer_init(&db, dbuf, sizeof(dbuf));
|
2017-09-08 13:39:09 -07:00
|
|
|
compute_cookie(client, when, nonce, client->sctx->secret, &db);
|
2014-02-19 12:53:42 +11:00
|
|
|
|
2017-09-05 09:19:45 +10:00
|
|
|
if (isc_safe_memequal(old, dbuf, COOKIE_SIZE)) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_cookiematch);
|
2017-09-05 09:19:45 +10:00
|
|
|
client->attributes |= NS_CLIENTATTR_HAVECOOKIE;
|
2014-02-19 12:53:42 +11:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
for (altsecret = ISC_LIST_HEAD(client->sctx->altsecrets);
|
2020-02-13 14:44:37 -08:00
|
|
|
altsecret != NULL; altsecret = ISC_LIST_NEXT(altsecret, link))
|
|
|
|
{
|
2017-09-05 09:19:45 +10:00
|
|
|
isc_buffer_init(&db, dbuf, sizeof(dbuf));
|
|
|
|
compute_cookie(client, when, nonce, altsecret->secret, &db);
|
|
|
|
if (isc_safe_memequal(old, dbuf, COOKIE_SIZE)) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_cookiematch);
|
2017-09-05 09:19:45 +10:00
|
|
|
client->attributes |= NS_CLIENTATTR_HAVECOOKIE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_cookienomatch);
|
2014-02-19 12:53:42 +11:00
|
|
|
}
|
|
|
|
|
2014-08-28 22:05:57 -07:00
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
process_ecs(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
|
|
|
uint16_t family;
|
|
|
|
uint8_t addrlen, addrbytes, scope, *paddr;
|
2014-08-28 22:05:57 -07:00
|
|
|
isc_netaddr_t caddr;
|
|
|
|
|
2016-02-27 11:23:50 +11:00
|
|
|
/*
|
|
|
|
* If we have already seen a ECS option skip this ECS option.
|
|
|
|
*/
|
|
|
|
if ((client->attributes & NS_CLIENTATTR_HAVEECS) != 0) {
|
2016-05-17 17:22:51 +10:00
|
|
|
isc_buffer_forward(buf, (unsigned int)optlen);
|
2016-02-27 11:23:50 +11:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2015-07-06 12:52:37 +10:00
|
|
|
/*
|
|
|
|
* XXXMUKS: Is there any need to repeat these checks here
|
|
|
|
* (except query's scope length) when they are done in the OPT
|
|
|
|
* RDATA fromwire code?
|
|
|
|
*/
|
|
|
|
|
2014-09-16 23:46:37 +10:00
|
|
|
if (optlen < 4U) {
|
2014-08-28 22:05:57 -07:00
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
2015-07-06 12:52:37 +10:00
|
|
|
"EDNS client-subnet option too short");
|
2014-08-28 22:05:57 -07:00
|
|
|
return (DNS_R_FORMERR);
|
|
|
|
}
|
|
|
|
|
|
|
|
family = isc_buffer_getuint16(buf);
|
|
|
|
addrlen = isc_buffer_getuint8(buf);
|
|
|
|
scope = isc_buffer_getuint8(buf);
|
|
|
|
optlen -= 4;
|
|
|
|
|
|
|
|
if (scope != 0U) {
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
2015-07-06 12:52:37 +10:00
|
|
|
"EDNS client-subnet option: invalid scope");
|
|
|
|
return (DNS_R_OPTERR);
|
2014-08-28 22:05:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&caddr, 0, sizeof(caddr));
|
|
|
|
switch (family) {
|
2016-03-23 08:54:46 -07:00
|
|
|
case 0:
|
|
|
|
/*
|
|
|
|
* XXXMUKS: In queries, if FAMILY is set to 0, SOURCE
|
|
|
|
* PREFIX-LENGTH must be 0 and ADDRESS should not be
|
|
|
|
* present as the address and prefix lengths don't make
|
|
|
|
* sense because the family is unknown.
|
|
|
|
*/
|
|
|
|
if (addrlen != 0U) {
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
|
|
|
"EDNS client-subnet option: invalid "
|
|
|
|
"address length (%u) for FAMILY=0",
|
|
|
|
addrlen);
|
|
|
|
return (DNS_R_OPTERR);
|
|
|
|
}
|
|
|
|
caddr.family = AF_UNSPEC;
|
|
|
|
break;
|
2014-08-28 22:05:57 -07:00
|
|
|
case 1:
|
2016-03-23 08:54:46 -07:00
|
|
|
if (addrlen > 32U) {
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
|
|
|
"EDNS client-subnet option: invalid "
|
|
|
|
"address length (%u) for IPv4",
|
|
|
|
addrlen);
|
|
|
|
return (DNS_R_OPTERR);
|
|
|
|
}
|
2014-08-28 22:05:57 -07:00
|
|
|
caddr.family = AF_INET;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if (addrlen > 128U) {
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
2015-07-06 12:52:37 +10:00
|
|
|
"EDNS client-subnet option: invalid "
|
2016-03-23 08:54:46 -07:00
|
|
|
"address length (%u) for IPv6",
|
|
|
|
addrlen);
|
2015-07-06 12:52:37 +10:00
|
|
|
return (DNS_R_OPTERR);
|
2014-08-28 22:05:57 -07:00
|
|
|
}
|
|
|
|
caddr.family = AF_INET6;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
2015-07-06 12:52:37 +10:00
|
|
|
"EDNS client-subnet option: invalid family");
|
|
|
|
return (DNS_R_OPTERR);
|
2014-08-28 22:05:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
addrbytes = (addrlen + 7) / 8;
|
|
|
|
if (isc_buffer_remaininglength(buf) < addrbytes) {
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(2),
|
2015-07-06 12:52:37 +10:00
|
|
|
"EDNS client-subnet option: address too short");
|
|
|
|
return (DNS_R_OPTERR);
|
2014-08-28 22:05:57 -07:00
|
|
|
}
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
paddr = (uint8_t *)&caddr.type;
|
2016-03-23 08:54:46 -07:00
|
|
|
if (addrbytes != 0U) {
|
|
|
|
memmove(paddr, isc_buffer_current(buf), addrbytes);
|
|
|
|
isc_buffer_forward(buf, addrbytes);
|
|
|
|
optlen -= addrbytes;
|
|
|
|
|
|
|
|
if ((addrlen % 8) != 0) {
|
2018-03-28 14:19:37 +02:00
|
|
|
uint8_t bits = ~0U << (8 - (addrlen % 8));
|
2020-06-24 14:31:00 +10:00
|
|
|
/* cppcheck-suppress objectIndex */
|
2016-03-23 08:54:46 -07:00
|
|
|
bits &= paddr[addrbytes - 1];
|
2020-06-24 14:31:00 +10:00
|
|
|
/* cppcheck-suppress objectIndex */
|
2020-02-13 21:48:23 +01:00
|
|
|
if (bits != paddr[addrbytes - 1]) {
|
2016-03-23 08:54:46 -07:00
|
|
|
return (DNS_R_OPTERR);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-03-23 08:54:46 -07:00
|
|
|
}
|
2015-07-06 12:52:37 +10:00
|
|
|
}
|
|
|
|
|
2017-02-02 11:54:28 -08:00
|
|
|
memmove(&client->ecs.addr, &caddr, sizeof(caddr));
|
|
|
|
client->ecs.source = addrlen;
|
|
|
|
client->ecs.scope = 0;
|
2014-08-28 22:05:57 -07:00
|
|
|
client->attributes |= NS_CLIENTATTR_HAVEECS;
|
|
|
|
|
2015-04-17 11:39:26 +02:00
|
|
|
isc_buffer_forward(buf, (unsigned int)optlen);
|
2014-08-28 22:05:57 -07:00
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2017-10-06 13:01:14 +11:00
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
process_keytag(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
|
2017-10-06 13:01:14 +11:00
|
|
|
if (optlen == 0 || (optlen % 2) != 0) {
|
|
|
|
isc_buffer_forward(buf, (unsigned int)optlen);
|
|
|
|
return (DNS_R_OPTERR);
|
|
|
|
}
|
|
|
|
|
2018-12-10 08:41:26 +11:00
|
|
|
/* Silently drop additional keytag options. */
|
|
|
|
if (client->keytag != NULL) {
|
|
|
|
isc_buffer_forward(buf, (unsigned int)optlen);
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2017-10-06 13:01:14 +11:00
|
|
|
client->keytag = isc_mem_get(client->mctx, optlen);
|
2019-07-16 15:52:14 +02:00
|
|
|
{
|
2018-03-28 14:19:37 +02:00
|
|
|
client->keytag_len = (uint16_t)optlen;
|
2017-10-06 13:01:14 +11:00
|
|
|
memmove(client->keytag, isc_buffer_current(buf), optlen);
|
|
|
|
}
|
|
|
|
isc_buffer_forward(buf, (unsigned int)optlen);
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2013-08-15 12:01:12 +10:00
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
process_opt(ns_client_t *client, dns_rdataset_t *opt) {
|
|
|
|
dns_rdata_t rdata;
|
2013-08-15 12:01:12 +10:00
|
|
|
isc_buffer_t optbuf;
|
|
|
|
isc_result_t result;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint16_t optcode;
|
|
|
|
uint16_t optlen;
|
2013-08-15 12:01:12 +10:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the client's UDP buffer size.
|
|
|
|
*/
|
|
|
|
client->udpsize = opt->rdclass;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the requested UDP buffer size is less than 512,
|
|
|
|
* ignore it and use 512.
|
|
|
|
*/
|
2020-02-13 21:48:23 +01:00
|
|
|
if (client->udpsize < 512) {
|
2013-08-15 12:01:12 +10:00
|
|
|
client->udpsize = 512;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-08-15 12:01:12 +10:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the flags out of the OPT record.
|
|
|
|
*/
|
2018-03-28 14:19:37 +02:00
|
|
|
client->extflags = (uint16_t)(opt->ttl & 0xFFFF);
|
2013-08-15 12:01:12 +10:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do we understand this version of EDNS?
|
|
|
|
*
|
|
|
|
* XXXRTH need library support for this!
|
|
|
|
*/
|
|
|
|
client->ednsversion = (opt->ttl & 0x00FF0000) >> 16;
|
2014-09-10 15:31:40 +10:00
|
|
|
if (client->ednsversion > DNS_EDNS_VERSION) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_badednsver);
|
2020-02-13 14:44:37 -08:00
|
|
|
result = ns_client_addopt(client, client->message,
|
|
|
|
&client->opt);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2013-08-15 12:01:12 +10:00
|
|
|
result = DNS_R_BADVERS;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-08-15 12:01:12 +10:00
|
|
|
ns_client_error(client, result);
|
2017-09-08 13:39:09 -07:00
|
|
|
return (result);
|
2013-08-15 12:01:12 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for NSID request */
|
|
|
|
result = dns_rdataset_first(opt);
|
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
dns_rdata_init(&rdata);
|
|
|
|
dns_rdataset_current(opt, &rdata);
|
|
|
|
isc_buffer_init(&optbuf, rdata.data, rdata.length);
|
|
|
|
isc_buffer_add(&optbuf, rdata.length);
|
|
|
|
while (isc_buffer_remaininglength(&optbuf) >= 4) {
|
|
|
|
optcode = isc_buffer_getuint16(&optbuf);
|
|
|
|
optlen = isc_buffer_getuint16(&optbuf);
|
|
|
|
switch (optcode) {
|
|
|
|
case DNS_OPT_NSID:
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!WANTNSID(client)) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(
|
2020-02-12 13:59:18 +01:00
|
|
|
client->sctx->nsstats,
|
|
|
|
ns_statscounter_nsidopt);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2013-08-15 12:01:12 +10:00
|
|
|
client->attributes |= NS_CLIENTATTR_WANTNSID;
|
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
break;
|
2015-07-06 09:44:24 +10:00
|
|
|
case DNS_OPT_COOKIE:
|
|
|
|
process_cookie(client, &optbuf, optlen);
|
2014-02-19 12:53:42 +11:00
|
|
|
break;
|
2014-02-20 14:56:20 +11:00
|
|
|
case DNS_OPT_EXPIRE:
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!WANTEXPIRE(client)) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(
|
2020-02-12 13:59:18 +01:00
|
|
|
client->sctx->nsstats,
|
|
|
|
ns_statscounter_expireopt);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-02-20 14:56:20 +11:00
|
|
|
client->attributes |= NS_CLIENTATTR_WANTEXPIRE;
|
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
break;
|
2014-08-28 22:05:57 -07:00
|
|
|
case DNS_OPT_CLIENT_SUBNET:
|
|
|
|
result = process_ecs(client, &optbuf, optlen);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
ns_client_error(client, result);
|
2017-09-08 13:39:09 -07:00
|
|
|
return (result);
|
2014-08-28 22:05:57 -07:00
|
|
|
}
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_ecsopt);
|
2014-08-28 22:05:57 -07:00
|
|
|
break;
|
2017-01-04 09:16:30 -08:00
|
|
|
case DNS_OPT_TCP_KEEPALIVE:
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!USEKEEPALIVE(client)) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(
|
2020-02-12 13:59:18 +01:00
|
|
|
client->sctx->nsstats,
|
|
|
|
ns_statscounter_keepaliveopt);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-01-04 09:16:30 -08:00
|
|
|
client->attributes |=
|
|
|
|
NS_CLIENTATTR_USEKEEPALIVE;
|
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
break;
|
|
|
|
case DNS_OPT_PAD:
|
|
|
|
client->attributes |= NS_CLIENTATTR_WANTPAD;
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_padopt);
|
2017-01-04 09:16:30 -08:00
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
break;
|
2017-10-06 13:01:14 +11:00
|
|
|
case DNS_OPT_KEY_TAG:
|
2020-02-13 14:44:37 -08:00
|
|
|
result = process_keytag(client, &optbuf,
|
|
|
|
optlen);
|
2017-10-06 13:01:14 +11:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
ns_client_error(client, result);
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_keytagopt);
|
|
|
|
break;
|
2013-08-15 12:01:12 +10:00
|
|
|
default:
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_otheropt);
|
2013-08-15 12:01:12 +10:00
|
|
|
isc_buffer_forward(&optbuf, optlen);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_stats_increment(client->sctx->nsstats, ns_statscounter_edns0in);
|
|
|
|
client->attributes |= NS_CLIENTATTR_WANTOPT;
|
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns__client_reset_cb(void *client0) {
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_t *client = client0;
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT,
|
|
|
|
ISC_LOG_DEBUG(3), "reset client");
|
2019-11-05 15:34:35 -08:00
|
|
|
|
2020-02-17 15:52:09 +01:00
|
|
|
/*
|
|
|
|
* We never started processing this client, possible if we're
|
|
|
|
* shutting down, just exit.
|
|
|
|
*/
|
|
|
|
if (client->state == NS_CLIENTSTATE_READY) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_endrequest(client);
|
|
|
|
if (client->tcpbuf != NULL) {
|
|
|
|
isc_mem_put(client->mctx, client->tcpbuf,
|
|
|
|
NS_CLIENT_TCP_BUFFER_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (client->keytag != NULL) {
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_mem_put(client->mctx, client->keytag, client->keytag_len);
|
2019-11-05 15:34:35 -08:00
|
|
|
client->keytag_len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
client->state = NS_CLIENTSTATE_READY;
|
|
|
|
INSIST(client->recursionquota == NULL);
|
2020-05-15 16:37:44 -07:00
|
|
|
|
|
|
|
#ifdef WANT_SINGLETRACE
|
|
|
|
isc_log_setforcelog(false);
|
|
|
|
#endif /* WANT_SINGLETRACE */
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns__client_put_cb(void *client0) {
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_t *client = client0;
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT,
|
|
|
|
ISC_LOG_DEBUG(3), "freeing client");
|
2019-11-05 15:34:35 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Call this first because it requires a valid client.
|
|
|
|
*/
|
|
|
|
ns_query_free(client);
|
|
|
|
|
|
|
|
client->magic = 0;
|
|
|
|
client->shuttingdown = true;
|
|
|
|
|
2020-01-31 22:56:32 +01:00
|
|
|
isc_mem_put(client->mctx, client->sendbuf, NS_CLIENT_SEND_BUFFER_SIZE);
|
2019-11-05 15:34:35 -08:00
|
|
|
if (client->opt != NULL) {
|
|
|
|
INSIST(dns_rdataset_isassociated(client->opt));
|
|
|
|
dns_rdataset_disassociate(client->opt);
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_message_puttemprdataset(client->message, &client->opt);
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
|
|
|
|
2020-09-21 16:16:15 -03:00
|
|
|
dns_message_detach(&client->message);
|
2019-11-05 15:34:35 -08:00
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
if (client->manager != NULL) {
|
|
|
|
clientmgr_detach(&client->manager);
|
|
|
|
}
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
/*
|
|
|
|
* Detaching the task must be done after unlinking from
|
|
|
|
* the manager's lists because the manager accesses
|
|
|
|
* client->task.
|
|
|
|
*/
|
|
|
|
if (client->task != NULL) {
|
|
|
|
isc_task_detach(&client->task);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Destroy the fetchlock mutex that was created in
|
|
|
|
* ns_query_init().
|
|
|
|
*/
|
|
|
|
isc_mutex_destroy(&client->query.fetchlock);
|
2013-08-15 12:01:12 +10:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
if (client->sctx != NULL) {
|
|
|
|
ns_server_detach(&client->sctx);
|
|
|
|
}
|
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_mem_detach(&client->mctx);
|
2013-08-15 12:01:12 +10:00
|
|
|
}
|
|
|
|
|
2000-01-06 01:09:27 +00:00
|
|
|
/*
|
2001-01-27 02:08:07 +00:00
|
|
|
* Handle an incoming request event from the socket (UDP case)
|
2000-01-06 01:09:27 +00:00
|
|
|
* or tcpmsg (TCP case).
|
|
|
|
*/
|
2017-09-08 13:39:09 -07:00
|
|
|
void
|
2020-04-15 19:26:49 -07:00
|
|
|
ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
|
|
|
isc_region_t *region, void *arg) {
|
2021-04-27 10:28:40 +02:00
|
|
|
ns_client_t *client = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
|
|
|
isc_result_t sigresult = ISC_R_SUCCESS;
|
2021-04-27 10:28:40 +02:00
|
|
|
isc_buffer_t *buffer = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_buffer_t tbuffer;
|
2021-04-27 10:28:40 +02:00
|
|
|
dns_rdataset_t *opt = NULL;
|
|
|
|
const dns_name_t *signame = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool ra; /* Recursion available. */
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
int match;
|
|
|
|
dns_messageid_t id;
|
|
|
|
unsigned int flags;
|
|
|
|
bool notimp;
|
|
|
|
size_t reqsize;
|
2021-04-27 10:28:40 +02:00
|
|
|
dns_aclenv_t *env = NULL;
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_sockaddr_t sockaddr;
|
2015-10-02 12:32:42 -07:00
|
|
|
#ifdef HAVE_DNSTAP
|
|
|
|
dns_dtmsgtype_t dtmsgtype;
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* ifdef HAVE_DNSTAP */
|
1999-07-24 01:17:44 +00:00
|
|
|
|
Refactor netmgr and add more unit tests
This is a part of the works that intends to make the netmgr stable,
testable, maintainable and tested. It contains a numerous changes to
the netmgr code and unfortunately, it was not possible to split this
into smaller chunks as the work here needs to be committed as a complete
works.
NOTE: There's a quite a lot of duplicated code between udp.c, tcp.c and
tcpdns.c and it should be a subject to refactoring in the future.
The changes that are included in this commit are listed here
(extensively, but not exclusively):
* The netmgr_test unit test was split into individual tests (udp_test,
tcp_test, tcpdns_test and newly added tcp_quota_test)
* The udp_test and tcp_test has been extended to allow programatic
failures from the libuv API. Unfortunately, we can't use cmocka
mock() and will_return(), so we emulate the behaviour with #define and
including the netmgr/{udp,tcp}.c source file directly.
* The netievents that we put on the nm queue have variable number of
members, out of these the isc_nmsocket_t and isc_nmhandle_t always
needs to be attached before enqueueing the netievent_<foo> and
detached after we have called the isc_nm_async_<foo> to ensure that
the socket (handle) doesn't disappear between scheduling the event and
actually executing the event.
* Cancelling the in-flight TCP connection using libuv requires to call
uv_close() on the original uv_tcp_t handle which just breaks too many
assumptions we have in the netmgr code. Instead of using uv_timer for
TCP connection timeouts, we use platform specific socket option.
* Fix the synchronization between {nm,async}_{listentcp,tcpconnect}
When isc_nm_listentcp() or isc_nm_tcpconnect() is called it was
waiting for socket to either end up with error (that path was fine) or
to be listening or connected using condition variable and mutex.
Several things could happen:
0. everything is ok
1. the waiting thread would miss the SIGNAL() - because the enqueued
event would be processed faster than we could start WAIT()ing.
In case the operation would end up with error, it would be ok, as
the error variable would be unchanged.
2. the waiting thread miss the sock->{connected,listening} = `true`
would be set to `false` in the tcp_{listen,connect}close_cb() as
the connection would be so short lived that the socket would be
closed before we could even start WAIT()ing
* The tcpdns has been converted to using libuv directly. Previously,
the tcpdns protocol used tcp protocol from netmgr, this proved to be
very complicated to understand, fix and make changes to. The new
tcpdns protocol is modeled in a similar way how tcp netmgr protocol.
Closes: #2194, #2283, #2318, #2266, #2034, #1920
* The tcp and tcpdns is now not using isc_uv_import/isc_uv_export to
pass accepted TCP sockets between netthreads, but instead (similar to
UDP) uses per netthread uv_loop listener. This greatly reduces the
complexity as the socket is always run in the associated nm and uv
loops, and we are also not touching the libuv internals.
There's an unfortunate side effect though, the new code requires
support for load-balanced sockets from the operating system for both
UDP and TCP (see #2137). If the operating system doesn't support the
load balanced sockets (either SO_REUSEPORT on Linux or SO_REUSEPORT_LB
on FreeBSD 12+), the number of netthreads is limited to 1.
* The netmgr has now two debugging #ifdefs:
1. Already existing NETMGR_TRACE prints any dangling nmsockets and
nmhandles before triggering assertion failure. This options would
reduce performance when enabled, but in theory, it could be enabled
on low-performance systems.
2. New NETMGR_TRACE_VERBOSE option has been added that enables
extensive netmgr logging that allows the software engineer to
precisely track any attach/detach operations on the nmsockets and
nmhandles. This is not suitable for any kind of production
machine, only for debugging.
* The tlsdns netmgr protocol has been split from the tcpdns and it still
uses the old method of stacking the netmgr boxes on top of each other.
We will have to refactor the tlsdns netmgr protocol to use the same
approach - build the stack using only libuv and openssl.
* Limit but not assert the tcp buffer size in tcp_alloc_cb
Closes: #2061
2020-11-12 10:32:18 +01:00
|
|
|
if (eresult != ISC_R_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
2020-04-15 19:26:49 -07:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
client = isc_nmhandle_getdata(handle);
|
|
|
|
if (client == NULL) {
|
2021-04-27 10:28:40 +02:00
|
|
|
ns_interface_t *ifp = (ns_interface_t *)arg;
|
2021-05-22 18:12:11 +02:00
|
|
|
ns_clientmgr_t *clientmgr =
|
|
|
|
ns_interfacemgr_getclientmgr(ifp->mgr);
|
2021-04-27 10:28:40 +02:00
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
INSIST(VALID_MANAGER(clientmgr));
|
2021-04-27 10:28:40 +02:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
client = isc_nmhandle_getextra(handle);
|
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
result = ns__client_setup(client, clientmgr, true);
|
2019-11-05 15:34:35 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
|
|
|
|
"allocate new client");
|
|
|
|
} else {
|
|
|
|
result = ns__client_setup(client, NULL, false);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
client->state = NS_CLIENTSTATE_READY;
|
|
|
|
|
|
|
|
if (client->handle == NULL) {
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_nmhandle_setdata(handle, client, ns__client_reset_cb,
|
|
|
|
ns__client_put_cb);
|
2019-11-05 15:34:35 -08:00
|
|
|
client->handle = handle;
|
|
|
|
}
|
2020-09-03 13:31:27 -07:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
if (isc_nmhandle_is_stream(handle)) {
|
|
|
|
client->attributes |= NS_CLIENTATTR_TCP;
|
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2000-01-15 00:36:26 +00:00
|
|
|
INSIST(client->recursionquota == NULL);
|
2000-01-27 01:00:16 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
INSIST(client->state == NS_CLIENTSTATE_READY);
|
2000-02-10 22:16:56 +00:00
|
|
|
|
2019-07-04 15:45:06 +02:00
|
|
|
(void)atomic_fetch_add_relaxed(&ns_client_requests, 1);
|
2005-08-15 01:21:07 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
isc_buffer_init(&tbuffer, region->base, region->length);
|
|
|
|
isc_buffer_add(&tbuffer, region->length);
|
|
|
|
buffer = &tbuffer;
|
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
client->peeraddr = isc_nmhandle_peeraddr(handle);
|
2019-11-05 15:34:35 -08:00
|
|
|
client->peeraddr_valid = true;
|
1999-08-05 01:51:32 +00:00
|
|
|
|
2015-07-06 22:20:03 -07:00
|
|
|
reqsize = isc_buffer_usedlength(buffer);
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
client->state = NS_CLIENTSTATE_WORKING;
|
2000-06-15 18:26:28 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
TIME_NOW(&client->requesttime);
|
2015-10-02 12:32:42 -07:00
|
|
|
client->tnow = client->requesttime;
|
|
|
|
client->now = isc_time_seconds(&client->tnow);
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2001-04-16 21:18:10 +00:00
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
|
|
|
|
|
2006-01-04 05:06:10 +00:00
|
|
|
#if NS_CLIENT_DROPPORT
|
|
|
|
if (ns_client_dropport(isc_sockaddr_getport(&client->peeraddr)) ==
|
2020-02-13 14:44:37 -08:00
|
|
|
DROPPORT_REQUEST)
|
|
|
|
{
|
2006-01-04 05:06:10 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
|
|
|
|
"dropped request: suspicious port");
|
2017-09-08 13:39:09 -07:00
|
|
|
return;
|
2006-01-04 05:06:10 +00:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* if NS_CLIENT_DROPPORT */
|
2006-01-04 05:06:10 +00:00
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
env = client->manager->aclenv;
|
2020-06-17 12:09:10 -07:00
|
|
|
if (client->sctx->blackholeacl != NULL &&
|
|
|
|
(dns_acl_match(&netaddr, NULL, client->sctx->blackholeacl, env,
|
|
|
|
&match, NULL) == ISC_R_SUCCESS) &&
|
|
|
|
match > 0)
|
|
|
|
{
|
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(10),
|
|
|
|
"dropped request: blackholed peer");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT,
|
|
|
|
ISC_LOG_DEBUG(3), "%s request",
|
2001-05-14 21:12:32 +00:00
|
|
|
TCP_CLIENT(client) ? "TCP" : "UDP");
|
|
|
|
|
2001-05-09 23:13:03 +00:00
|
|
|
result = dns_message_peekheader(buffer, &id, &flags);
|
1999-07-24 01:17:44 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2001-05-09 23:13:03 +00:00
|
|
|
/*
|
|
|
|
* There isn't enough header to determine whether
|
|
|
|
* this was a request or a response. Drop it.
|
|
|
|
*/
|
2017-09-08 13:39:09 -07:00
|
|
|
return;
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|
1999-12-20 23:06:17 +00:00
|
|
|
|
2020-05-15 16:37:44 -07:00
|
|
|
#ifdef WANT_SINGLETRACE
|
|
|
|
if (id == 0) {
|
|
|
|
isc_log_setforcelog(true);
|
|
|
|
}
|
|
|
|
#endif /* WANT_SINGLETRACE */
|
|
|
|
|
1999-12-20 23:06:17 +00:00
|
|
|
/*
|
2001-05-09 23:13:03 +00:00
|
|
|
* The client object handles requests, not responses.
|
|
|
|
* If this is a UDP response, forward it to the dispatcher.
|
|
|
|
* If it's a TCP response, discard it here.
|
1999-12-20 23:06:17 +00:00
|
|
|
*/
|
2001-05-09 23:13:03 +00:00
|
|
|
if ((flags & DNS_MESSAGEFLAG_QR) != 0) {
|
2019-11-05 15:34:35 -08:00
|
|
|
CTRACE("unexpected response");
|
|
|
|
return;
|
1999-12-20 23:06:17 +00:00
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2008-04-03 05:55:52 +00:00
|
|
|
/*
|
|
|
|
* Update some statistics counters. Don't count responses.
|
|
|
|
*/
|
|
|
|
if (isc_sockaddr_pf(&client->peeraddr) == PF_INET) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_requestv4);
|
2008-04-03 05:55:52 +00:00
|
|
|
} else {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_requestv6);
|
2008-04-03 05:55:52 +00:00
|
|
|
}
|
2015-07-06 22:20:03 -07:00
|
|
|
if (TCP_CLIENT(client)) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_requesttcp);
|
2016-06-23 08:44:54 +10:00
|
|
|
switch (isc_sockaddr_pf(&client->peeraddr)) {
|
|
|
|
case AF_INET:
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_stats_increment(client->sctx->tcpinstats4,
|
2016-06-23 08:44:54 +10:00
|
|
|
ISC_MIN((int)reqsize / 16, 18));
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_stats_increment(client->sctx->tcpinstats6,
|
2016-06-23 08:44:54 +10:00
|
|
|
ISC_MIN((int)reqsize / 16, 18));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
2018-11-07 15:00:07 +07:00
|
|
|
ISC_UNREACHABLE();
|
2016-06-23 08:44:54 +10:00
|
|
|
}
|
2015-07-06 22:20:03 -07:00
|
|
|
} else {
|
2016-06-23 08:44:54 +10:00
|
|
|
switch (isc_sockaddr_pf(&client->peeraddr)) {
|
|
|
|
case AF_INET:
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_stats_increment(client->sctx->udpinstats4,
|
2016-06-23 08:44:54 +10:00
|
|
|
ISC_MIN((int)reqsize / 16, 18));
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_stats_increment(client->sctx->udpinstats6,
|
2016-06-23 08:44:54 +10:00
|
|
|
ISC_MIN((int)reqsize / 16, 18));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
INSIST(0);
|
2018-11-07 15:00:07 +07:00
|
|
|
ISC_UNREACHABLE();
|
2016-06-23 08:44:54 +10:00
|
|
|
}
|
2015-07-06 22:20:03 -07:00
|
|
|
}
|
2008-04-03 05:55:52 +00:00
|
|
|
|
2001-05-09 23:13:03 +00:00
|
|
|
/*
|
|
|
|
* It's a request. Parse it.
|
|
|
|
*/
|
|
|
|
result = dns_message_parse(client->message, buffer, 0);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
/*
|
|
|
|
* Parsing the request failed. Send a response
|
|
|
|
* (typically FORMERR or SERVFAIL).
|
|
|
|
*/
|
2019-01-07 14:05:43 +11:00
|
|
|
if (result == DNS_R_OPTERR) {
|
2015-07-06 09:44:24 +10:00
|
|
|
(void)ns_client_addopt(client, client->message,
|
|
|
|
&client->opt);
|
2019-01-07 14:05:43 +11:00
|
|
|
}
|
2015-07-08 22:53:39 -07:00
|
|
|
|
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
2016-01-04 13:05:23 -08:00
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
2015-07-08 22:53:39 -07:00
|
|
|
"message parsing failed: %s",
|
|
|
|
isc_result_totext(result));
|
2020-07-23 09:47:49 +10:00
|
|
|
if (result == ISC_R_NOSPACE || result == DNS_R_BADTSIG) {
|
2019-01-07 14:05:43 +11:00
|
|
|
result = DNS_R_FORMERR;
|
|
|
|
}
|
2001-05-09 23:13:03 +00:00
|
|
|
ns_client_error(client, result);
|
2017-09-08 13:39:09 -07:00
|
|
|
return;
|
2001-05-09 23:13:03 +00:00
|
|
|
}
|
|
|
|
|
2015-01-20 16:10:30 -08:00
|
|
|
/*
|
2019-11-05 15:34:35 -08:00
|
|
|
* Disable pipelined TCP query processing if necessary.
|
2015-01-20 16:10:30 -08:00
|
|
|
*/
|
2019-02-06 11:27:11 -08:00
|
|
|
if (TCP_CLIENT(client) &&
|
2019-11-05 15:34:35 -08:00
|
|
|
(client->message->opcode != dns_opcode_query ||
|
|
|
|
(client->sctx->keepresporder != NULL &&
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_acl_allowed(&netaddr, NULL, client->sctx->keepresporder,
|
2020-02-13 14:44:37 -08:00
|
|
|
env))))
|
|
|
|
{
|
2019-11-05 15:34:35 -08:00
|
|
|
isc_nm_tcpdns_sequential(handle);
|
2015-01-20 16:10:30 -08:00
|
|
|
}
|
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
dns_opcodestats_increment(client->sctx->opcodestats,
|
2008-04-03 05:55:52 +00:00
|
|
|
client->message->opcode);
|
2001-10-09 02:05:55 +00:00
|
|
|
switch (client->message->opcode) {
|
|
|
|
case dns_opcode_query:
|
|
|
|
case dns_opcode_update:
|
|
|
|
case dns_opcode_notify:
|
2018-04-17 08:29:14 -07:00
|
|
|
notimp = false;
|
2001-10-09 02:05:55 +00:00
|
|
|
break;
|
|
|
|
case dns_opcode_iquery:
|
|
|
|
default:
|
2018-04-17 08:29:14 -07:00
|
|
|
notimp = true;
|
2001-10-09 02:05:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-09-19 00:02:26 +00:00
|
|
|
client->message->rcode = dns_rcode_noerror;
|
|
|
|
|
1999-09-02 01:52:31 +00:00
|
|
|
/*
|
|
|
|
* Deal with EDNS.
|
|
|
|
*/
|
2019-11-05 15:34:35 -08:00
|
|
|
if ((client->sctx->options & NS_SERVER_NOEDNS) != 0) {
|
2012-10-16 10:23:08 +11:00
|
|
|
opt = NULL;
|
2019-11-05 15:34:35 -08:00
|
|
|
} else {
|
2012-10-16 10:23:08 +11:00
|
|
|
opt = dns_message_getopt(client->message);
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
2014-08-28 22:05:57 -07:00
|
|
|
|
2017-02-02 11:54:28 -08:00
|
|
|
client->ecs.source = 0;
|
|
|
|
client->ecs.scope = 0;
|
2014-08-28 22:05:57 -07:00
|
|
|
|
1999-09-02 01:52:31 +00:00
|
|
|
if (opt != NULL) {
|
2018-07-26 17:53:15 +10:00
|
|
|
/*
|
|
|
|
* Are returning FORMERR to all EDNS queries?
|
|
|
|
* Simulate a STD13 compliant server.
|
|
|
|
*/
|
|
|
|
if ((client->sctx->options & NS_SERVER_EDNSFORMERR) != 0) {
|
|
|
|
ns_client_error(client, DNS_R_FORMERR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Are returning NOTIMP to all EDNS queries?
|
|
|
|
*/
|
|
|
|
if ((client->sctx->options & NS_SERVER_EDNSNOTIMP) != 0) {
|
|
|
|
ns_client_error(client, DNS_R_NOTIMP);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Are returning REFUSED to all EDNS queries?
|
|
|
|
*/
|
|
|
|
if ((client->sctx->options & NS_SERVER_EDNSREFUSED) != 0) {
|
|
|
|
ns_client_error(client, DNS_R_REFUSED);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-10-16 10:23:08 +11:00
|
|
|
/*
|
|
|
|
* Are we dropping all EDNS queries?
|
|
|
|
*/
|
2017-09-08 13:39:09 -07:00
|
|
|
if ((client->sctx->options & NS_SERVER_DROPEDNS) != 0) {
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_client_drop(client, ISC_R_SUCCESS);
|
2017-09-08 13:39:09 -07:00
|
|
|
return;
|
2012-10-16 10:23:08 +11:00
|
|
|
}
|
2018-07-26 17:53:15 +10:00
|
|
|
|
2013-08-15 12:01:12 +10:00
|
|
|
result = process_opt(client, opt);
|
2019-11-05 15:34:35 -08:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2017-09-08 13:39:09 -07:00
|
|
|
return;
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
1999-09-02 01:52:31 +00:00
|
|
|
}
|
|
|
|
|
2000-08-21 23:45:05 +00:00
|
|
|
if (client->message->rdclass == 0) {
|
2018-05-16 00:07:17 +05:30
|
|
|
if ((client->attributes & NS_CLIENTATTR_WANTCOOKIE) != 0 &&
|
|
|
|
client->message->opcode == dns_opcode_query &&
|
2020-02-13 14:44:37 -08:00
|
|
|
client->message->counts[DNS_SECTION_QUESTION] == 0U)
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
result = dns_message_reply(client->message, true);
|
2015-07-06 09:44:24 +10:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
ns_client_error(client, result);
|
|
|
|
return;
|
|
|
|
}
|
2019-11-05 15:34:35 -08:00
|
|
|
|
|
|
|
if (notimp) {
|
2015-07-24 13:35:29 +10:00
|
|
|
client->message->rcode = dns_rcode_notimp;
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
|
|
|
|
2015-07-06 09:44:24 +10:00
|
|
|
ns_client_send(client);
|
|
|
|
return;
|
|
|
|
}
|
2019-11-05 15:34:35 -08:00
|
|
|
|
2000-08-21 23:45:05 +00:00
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
2001-06-28 02:39:46 +00:00
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
2000-08-21 23:45:05 +00:00
|
|
|
"message class could not be determined");
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_dumpmessage(client, "message class could not be "
|
|
|
|
"determined");
|
2001-10-09 02:05:55 +00:00
|
|
|
ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_FORMERR);
|
2017-09-08 13:39:09 -07:00
|
|
|
return;
|
2000-08-21 23:45:05 +00:00
|
|
|
}
|
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
sockaddr = isc_nmhandle_localaddr(handle);
|
|
|
|
isc_netaddr_fromsockaddr(&client->destaddr, &sockaddr);
|
2001-11-16 20:01:57 +00:00
|
|
|
|
2018-01-13 00:31:30 +05:30
|
|
|
isc_sockaddr_fromnetaddr(&client->destsockaddr, &client->destaddr, 0);
|
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
result = client->sctx->matchingview(&netaddr, &client->destaddr,
|
2020-02-12 13:59:18 +01:00
|
|
|
client->message, env, &sigresult,
|
|
|
|
&client->view);
|
2017-09-08 13:39:09 -07:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-11-15 19:15:25 +00:00
|
|
|
char classname[DNS_RDATACLASS_FORMATSIZE];
|
|
|
|
|
2000-09-18 22:54:08 +00:00
|
|
|
/*
|
|
|
|
* Do a dummy TSIG verification attempt so that the
|
|
|
|
* response will have a TSIG if the query did, as
|
|
|
|
* required by RFC2845.
|
|
|
|
*/
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_buffer_t b;
|
2000-09-12 07:48:28 +00:00
|
|
|
isc_region_t *r;
|
2001-12-06 04:38:51 +00:00
|
|
|
|
|
|
|
dns_message_resetsig(client->message);
|
|
|
|
|
2000-09-12 07:48:28 +00:00
|
|
|
r = dns_message_getrawmessage(client->message);
|
|
|
|
isc_buffer_init(&b, r->base, r->length);
|
|
|
|
isc_buffer_add(&b, r->length);
|
|
|
|
(void)dns_tsig_verify(&b, client->message, NULL, NULL);
|
|
|
|
|
2000-11-15 19:15:25 +00:00
|
|
|
dns_rdataclass_format(client->message->rdclass, classname,
|
|
|
|
sizeof(classname));
|
2000-04-06 17:29:47 +00:00
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
2001-06-28 02:39:46 +00:00
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
2000-11-15 19:15:25 +00:00
|
|
|
"no matching view in class '%s'", classname);
|
2001-05-25 07:39:48 +00:00
|
|
|
ns_client_dumpmessage(client, "no matching view in class");
|
2001-10-09 02:05:55 +00:00
|
|
|
ns_client_error(client, notimp ? DNS_R_NOTIMP : DNS_R_REFUSED);
|
2017-09-08 13:39:09 -07:00
|
|
|
return;
|
2000-01-21 20:24:49 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT,
|
|
|
|
ISC_LOG_DEBUG(5), "using view '%s'", client->view->name);
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-12-10 18:14:49 +00:00
|
|
|
/*
|
2000-08-01 01:33:37 +00:00
|
|
|
* Check for a signature. We log bad signatures regardless of
|
1999-12-10 18:14:49 +00:00
|
|
|
* whether they ultimately cause the request to be rejected or
|
|
|
|
* not. We do not log the lack of a signature unless we are
|
|
|
|
* debugging.
|
|
|
|
*/
|
|
|
|
client->signer = NULL;
|
2000-01-21 20:24:49 +00:00
|
|
|
dns_name_init(&client->signername, NULL);
|
1999-12-10 18:14:49 +00:00
|
|
|
result = dns_message_signer(client->message, &client->signername);
|
2008-04-03 05:55:52 +00:00
|
|
|
if (result != ISC_R_NOTFOUND) {
|
|
|
|
signame = NULL;
|
|
|
|
if (dns_message_gettsig(client->message, &signame) != NULL) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_tsigin);
|
2008-04-03 05:55:52 +00:00
|
|
|
} else {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_sig0in);
|
2008-04-03 05:55:52 +00:00
|
|
|
}
|
|
|
|
}
|
2000-04-06 22:03:35 +00:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2011-01-10 05:32:04 +00:00
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
|
|
dns_name_format(&client->signername, namebuf, sizeof(namebuf));
|
2000-04-04 18:28:51 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
1999-12-10 18:14:49 +00:00
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
|
2011-01-10 05:32:04 +00:00
|
|
|
"request has valid signature: %s", namebuf);
|
1999-12-10 18:14:49 +00:00
|
|
|
client->signer = &client->signername;
|
2000-04-06 22:03:35 +00:00
|
|
|
} else if (result == ISC_R_NOTFOUND) {
|
2000-04-04 18:28:51 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
1999-12-10 18:14:49 +00:00
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
|
|
|
|
"request is not signed");
|
2000-01-21 20:24:49 +00:00
|
|
|
} else if (result == DNS_R_NOIDENTITY) {
|
2000-04-04 18:28:51 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
2000-01-21 20:24:49 +00:00
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
|
|
|
|
"request is signed by a nonauthoritative key");
|
1999-12-10 18:14:49 +00:00
|
|
|
} else {
|
2020-02-13 14:44:37 -08:00
|
|
|
char tsigrcode[64];
|
2002-03-05 00:36:44 +00:00
|
|
|
isc_buffer_t b;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_rcode_t status;
|
2007-08-22 00:42:42 +00:00
|
|
|
isc_result_t tresult;
|
2002-03-05 00:36:44 +00:00
|
|
|
|
1999-12-10 18:14:49 +00:00
|
|
|
/* There is a signature, but it is bad. */
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_stats_increment(client->sctx->nsstats,
|
|
|
|
ns_statscounter_invalidsig);
|
2008-04-03 05:55:52 +00:00
|
|
|
signame = NULL;
|
|
|
|
if (dns_message_gettsig(client->message, &signame) != NULL) {
|
2004-02-09 23:25:22 +00:00
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
2006-12-04 01:54:53 +00:00
|
|
|
char cnamebuf[DNS_NAME_FORMATSIZE];
|
2008-04-03 05:55:52 +00:00
|
|
|
dns_name_format(signame, namebuf, sizeof(namebuf));
|
2007-08-22 00:42:42 +00:00
|
|
|
status = client->message->tsigstatus;
|
|
|
|
isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1);
|
|
|
|
tresult = dns_tsigrcode_totext(status, &b);
|
|
|
|
INSIST(tresult == ISC_R_SUCCESS);
|
|
|
|
tsigrcode[isc_buffer_usedlength(&b)] = '\0';
|
2006-12-04 01:54:53 +00:00
|
|
|
if (client->message->tsigkey->generated) {
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_name_format(
|
|
|
|
client->message->tsigkey->creator,
|
|
|
|
cnamebuf, sizeof(cnamebuf));
|
|
|
|
ns_client_log(
|
|
|
|
client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
|
|
|
|
"request has invalid signature: "
|
|
|
|
"TSIG %s (%s): %s (%s)",
|
|
|
|
namebuf, cnamebuf,
|
|
|
|
isc_result_totext(result), tsigrcode);
|
2006-12-04 01:54:53 +00:00
|
|
|
} else {
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_log(
|
|
|
|
client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
|
|
|
|
"request has invalid signature: "
|
|
|
|
"TSIG %s: %s (%s)",
|
|
|
|
namebuf, isc_result_totext(result),
|
|
|
|
tsigrcode);
|
2006-12-04 01:54:53 +00:00
|
|
|
}
|
2004-02-09 23:25:22 +00:00
|
|
|
} else {
|
2007-08-22 00:42:42 +00:00
|
|
|
status = client->message->sig0status;
|
|
|
|
isc_buffer_init(&b, tsigrcode, sizeof(tsigrcode) - 1);
|
|
|
|
tresult = dns_tsigrcode_totext(status, &b);
|
|
|
|
INSIST(tresult == ISC_R_SUCCESS);
|
|
|
|
tsigrcode[isc_buffer_usedlength(&b)] = '\0';
|
2004-02-09 23:25:22 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_ERROR,
|
|
|
|
"request has invalid signature: %s (%s)",
|
|
|
|
isc_result_totext(result), tsigrcode);
|
|
|
|
}
|
2019-11-05 15:34:35 -08:00
|
|
|
|
2001-10-12 04:01:40 +00:00
|
|
|
/*
|
|
|
|
* Accept update messages signed by unknown keys so that
|
|
|
|
* update forwarding works transparently through slaves
|
|
|
|
* that don't have all the same keys as the master.
|
|
|
|
*/
|
2000-11-03 04:45:03 +00:00
|
|
|
if (!(client->message->tsigstatus == dns_tsigerror_badkey &&
|
2020-02-13 14:44:37 -08:00
|
|
|
client->message->opcode == dns_opcode_update))
|
|
|
|
{
|
2000-09-13 01:30:34 +00:00
|
|
|
ns_client_error(client, sigresult);
|
2017-09-08 13:39:09 -07:00
|
|
|
return;
|
2000-09-13 01:30:34 +00:00
|
|
|
}
|
1999-12-10 18:14:49 +00:00
|
|
|
}
|
|
|
|
|
1999-12-10 23:58:04 +00:00
|
|
|
/*
|
|
|
|
* Decide whether recursive service is available to this client.
|
|
|
|
* We do this here rather than in the query code so that we can
|
|
|
|
* set the RA bit correctly on all kinds of responses, not just
|
2006-07-22 01:00:04 +00:00
|
|
|
* responses to ordinary queries. Note if you can't query the
|
|
|
|
* cache there is no point in setting RA.
|
1999-12-10 23:58:04 +00:00
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
ra = false;
|
2020-03-30 13:47:58 -07:00
|
|
|
if (client->view->resolver != NULL && client->view->recursion &&
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_checkaclsilent(client, NULL, client->view->recursionacl,
|
2018-04-17 08:29:14 -07:00
|
|
|
true) == ISC_R_SUCCESS &&
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_checkaclsilent(client, NULL, client->view->cacheacl,
|
2018-04-17 08:29:14 -07:00
|
|
|
true) == ISC_R_SUCCESS &&
|
2009-03-03 01:36:17 +00:00
|
|
|
ns_client_checkaclsilent(client, &client->destaddr,
|
2007-03-29 06:36:31 +00:00
|
|
|
client->view->recursiononacl,
|
2018-04-17 08:29:14 -07:00
|
|
|
true) == ISC_R_SUCCESS &&
|
2009-03-03 01:36:17 +00:00
|
|
|
ns_client_checkaclsilent(client, &client->destaddr,
|
2010-09-24 05:09:03 +00:00
|
|
|
client->view->cacheonacl,
|
2020-02-13 14:44:37 -08:00
|
|
|
true) == ISC_R_SUCCESS)
|
|
|
|
{
|
2018-04-17 08:29:14 -07:00
|
|
|
ra = true;
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
2000-04-06 20:26:39 +00:00
|
|
|
|
2020-03-30 13:47:58 -07:00
|
|
|
if (ra) {
|
1999-12-10 23:58:04 +00:00
|
|
|
client->attributes |= NS_CLIENTATTR_RA;
|
2019-03-27 17:45:45 +01:00
|
|
|
}
|
2000-01-07 19:20:25 +00:00
|
|
|
|
2002-05-16 04:05:42 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY, NS_LOGMODULE_CLIENT,
|
2020-02-12 13:59:18 +01:00
|
|
|
ISC_LOG_DEBUG(3),
|
|
|
|
ra ? "recursion available" : "recursion not available");
|
2002-05-16 04:05:42 +00:00
|
|
|
|
2006-01-05 00:01:46 +00:00
|
|
|
/*
|
|
|
|
* Adjust maximum UDP response size for this client.
|
|
|
|
*/
|
|
|
|
if (client->udpsize > 512) {
|
|
|
|
dns_peer_t *peer = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
uint16_t udpsize = client->view->maxudp;
|
2020-02-12 13:59:18 +01:00
|
|
|
(void)dns_peerlist_peerbyaddr(client->view->peers, &netaddr,
|
|
|
|
&peer);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (peer != NULL) {
|
2006-01-05 00:01:46 +00:00
|
|
|
dns_peer_getmaxudp(peer, &udpsize);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (client->udpsize > udpsize) {
|
2006-01-05 00:01:46 +00:00
|
|
|
client->udpsize = udpsize;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-01-05 00:01:46 +00:00
|
|
|
}
|
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
/*
|
|
|
|
* Dispatch the request.
|
|
|
|
*/
|
|
|
|
switch (client->message->opcode) {
|
|
|
|
case dns_opcode_query:
|
|
|
|
CTRACE("query");
|
2015-10-02 12:32:42 -07:00
|
|
|
#ifdef HAVE_DNSTAP
|
2019-03-27 17:45:45 +01:00
|
|
|
if (ra && (client->message->flags & DNS_MESSAGEFLAG_RD) != 0) {
|
2015-10-02 12:32:42 -07:00
|
|
|
dtmsgtype = DNS_DTTYPE_CQ;
|
2019-03-27 17:45:45 +01:00
|
|
|
} else {
|
2015-10-02 12:32:42 -07:00
|
|
|
dtmsgtype = DNS_DTTYPE_AQ;
|
2019-03-27 17:45:45 +01:00
|
|
|
}
|
2015-10-02 12:32:42 -07:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
dns_dt_send(client->view, dtmsgtype, &client->peeraddr,
|
2018-04-09 18:07:47 +01:00
|
|
|
&client->destsockaddr, TCP_CLIENT(client), NULL,
|
2015-10-02 12:32:42 -07:00
|
|
|
&client->requesttime, NULL, buffer);
|
|
|
|
#endif /* HAVE_DNSTAP */
|
|
|
|
|
2020-09-03 13:31:27 -07:00
|
|
|
ns_query_start(client, handle);
|
1999-07-24 01:17:44 +00:00
|
|
|
break;
|
1999-08-20 06:03:02 +00:00
|
|
|
case dns_opcode_update:
|
|
|
|
CTRACE("update");
|
2018-10-02 14:13:14 -07:00
|
|
|
#ifdef HAVE_DNSTAP
|
|
|
|
dns_dt_send(client->view, DNS_DTTYPE_UQ, &client->peeraddr,
|
|
|
|
&client->destsockaddr, TCP_CLIENT(client), NULL,
|
|
|
|
&client->requesttime, NULL, buffer);
|
|
|
|
#endif /* HAVE_DNSTAP */
|
2001-01-29 19:49:52 +00:00
|
|
|
ns_client_settimeout(client, 60);
|
2020-09-03 13:31:27 -07:00
|
|
|
ns_update_start(client, handle, sigresult);
|
1999-08-20 06:03:02 +00:00
|
|
|
break;
|
|
|
|
case dns_opcode_notify:
|
|
|
|
CTRACE("notify");
|
2001-01-29 19:49:52 +00:00
|
|
|
ns_client_settimeout(client, 60);
|
2020-09-03 13:31:27 -07:00
|
|
|
ns_notify_start(client, handle);
|
1999-08-20 06:03:02 +00:00
|
|
|
break;
|
1999-07-24 01:17:44 +00:00
|
|
|
case dns_opcode_iquery:
|
|
|
|
CTRACE("iquery");
|
1999-11-30 22:35:43 +00:00
|
|
|
ns_client_error(client, DNS_R_NOTIMP);
|
2000-02-04 00:46:58 +00:00
|
|
|
break;
|
2019-11-05 15:34:35 -08:00
|
|
|
default:
|
|
|
|
CTRACE("unknown opcode");
|
|
|
|
ns_client_error(client, DNS_R_NOTIMP);
|
2000-02-17 18:18:24 +00:00
|
|
|
}
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
2000-11-03 02:45:55 +00:00
|
|
|
|
2020-06-17 12:09:10 -07:00
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
ns__client_tcpconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
2020-06-17 12:09:10 -07:00
|
|
|
ns_interface_t *ifp = (ns_interface_t *)arg;
|
|
|
|
dns_aclenv_t *env = ns_interfacemgr_getaclenv(ifp->mgr);
|
|
|
|
ns_server_t *sctx = ns_interfacemgr_getserver(ifp->mgr);
|
2019-11-25 18:36:14 -03:00
|
|
|
unsigned int tcpquota;
|
2020-06-17 12:09:10 -07:00
|
|
|
isc_sockaddr_t peeraddr;
|
|
|
|
isc_netaddr_t netaddr;
|
|
|
|
int match;
|
2019-11-25 18:36:14 -03:00
|
|
|
|
Refactor netmgr and add more unit tests
This is a part of the works that intends to make the netmgr stable,
testable, maintainable and tested. It contains a numerous changes to
the netmgr code and unfortunately, it was not possible to split this
into smaller chunks as the work here needs to be committed as a complete
works.
NOTE: There's a quite a lot of duplicated code between udp.c, tcp.c and
tcpdns.c and it should be a subject to refactoring in the future.
The changes that are included in this commit are listed here
(extensively, but not exclusively):
* The netmgr_test unit test was split into individual tests (udp_test,
tcp_test, tcpdns_test and newly added tcp_quota_test)
* The udp_test and tcp_test has been extended to allow programatic
failures from the libuv API. Unfortunately, we can't use cmocka
mock() and will_return(), so we emulate the behaviour with #define and
including the netmgr/{udp,tcp}.c source file directly.
* The netievents that we put on the nm queue have variable number of
members, out of these the isc_nmsocket_t and isc_nmhandle_t always
needs to be attached before enqueueing the netievent_<foo> and
detached after we have called the isc_nm_async_<foo> to ensure that
the socket (handle) doesn't disappear between scheduling the event and
actually executing the event.
* Cancelling the in-flight TCP connection using libuv requires to call
uv_close() on the original uv_tcp_t handle which just breaks too many
assumptions we have in the netmgr code. Instead of using uv_timer for
TCP connection timeouts, we use platform specific socket option.
* Fix the synchronization between {nm,async}_{listentcp,tcpconnect}
When isc_nm_listentcp() or isc_nm_tcpconnect() is called it was
waiting for socket to either end up with error (that path was fine) or
to be listening or connected using condition variable and mutex.
Several things could happen:
0. everything is ok
1. the waiting thread would miss the SIGNAL() - because the enqueued
event would be processed faster than we could start WAIT()ing.
In case the operation would end up with error, it would be ok, as
the error variable would be unchanged.
2. the waiting thread miss the sock->{connected,listening} = `true`
would be set to `false` in the tcp_{listen,connect}close_cb() as
the connection would be so short lived that the socket would be
closed before we could even start WAIT()ing
* The tcpdns has been converted to using libuv directly. Previously,
the tcpdns protocol used tcp protocol from netmgr, this proved to be
very complicated to understand, fix and make changes to. The new
tcpdns protocol is modeled in a similar way how tcp netmgr protocol.
Closes: #2194, #2283, #2318, #2266, #2034, #1920
* The tcp and tcpdns is now not using isc_uv_import/isc_uv_export to
pass accepted TCP sockets between netthreads, but instead (similar to
UDP) uses per netthread uv_loop listener. This greatly reduces the
complexity as the socket is always run in the associated nm and uv
loops, and we are also not touching the libuv internals.
There's an unfortunate side effect though, the new code requires
support for load-balanced sockets from the operating system for both
UDP and TCP (see #2137). If the operating system doesn't support the
load balanced sockets (either SO_REUSEPORT on Linux or SO_REUSEPORT_LB
on FreeBSD 12+), the number of netthreads is limited to 1.
* The netmgr has now two debugging #ifdefs:
1. Already existing NETMGR_TRACE prints any dangling nmsockets and
nmhandles before triggering assertion failure. This options would
reduce performance when enabled, but in theory, it could be enabled
on low-performance systems.
2. New NETMGR_TRACE_VERBOSE option has been added that enables
extensive netmgr logging that allows the software engineer to
precisely track any attach/detach operations on the nmsockets and
nmhandles. This is not suitable for any kind of production
machine, only for debugging.
* The tlsdns netmgr protocol has been split from the tcpdns and it still
uses the old method of stacking the netmgr boxes on top of each other.
We will have to refactor the tlsdns netmgr protocol to use the same
approach - build the stack using only libuv and openssl.
* Limit but not assert the tcp buffer size in tcp_alloc_cb
Closes: #2061
2020-11-12 10:32:18 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
|
|
|
}
|
2019-11-25 18:36:14 -03:00
|
|
|
|
2020-06-17 12:09:10 -07:00
|
|
|
if (handle != NULL) {
|
|
|
|
peeraddr = isc_nmhandle_peeraddr(handle);
|
|
|
|
isc_netaddr_fromsockaddr(&netaddr, &peeraddr);
|
|
|
|
|
|
|
|
if (sctx->blackholeacl != NULL &&
|
|
|
|
(dns_acl_match(&netaddr, NULL, sctx->blackholeacl, env,
|
|
|
|
&match, NULL) == ISC_R_SUCCESS) &&
|
|
|
|
match > 0)
|
|
|
|
{
|
|
|
|
return (ISC_R_CONNREFUSED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-25 18:36:14 -03:00
|
|
|
tcpquota = isc_quota_getused(&sctx->tcpquota);
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_stats_update_if_greater(sctx->nsstats, ns_statscounter_tcphighwater,
|
2019-11-25 18:36:14 -03:00
|
|
|
tcpquota);
|
2020-06-17 12:09:10 -07:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
2019-11-25 18:36:14 -03:00
|
|
|
}
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
ns__client_setup(ns_client_t *client, ns_clientmgr_t *mgr, bool new) {
|
1999-08-05 01:51:32 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
2019-01-04 12:50:51 +01:00
|
|
|
/*
|
2019-11-05 15:34:35 -08:00
|
|
|
* Caller must be holding the manager lock.
|
|
|
|
*
|
|
|
|
* Note: creating a client does not add the client to the
|
|
|
|
* manager's client list or set the client's manager pointer.
|
|
|
|
* The caller is responsible for that.
|
2019-01-04 12:50:51 +01:00
|
|
|
*/
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
if (new) {
|
2021-05-22 18:12:11 +02:00
|
|
|
REQUIRE(VALID_MANAGER(mgr));
|
|
|
|
REQUIRE(client != NULL);
|
|
|
|
REQUIRE(mgr->tid == isc_nm_tid());
|
|
|
|
|
|
|
|
*client = (ns_client_t){ .magic = 0, .tid = mgr->tid };
|
2019-01-04 12:50:51 +01:00
|
|
|
|
2021-05-11 12:03:11 +02:00
|
|
|
isc_mem_attach(mgr->mctx, &client->mctx);
|
2019-11-05 15:34:35 -08:00
|
|
|
clientmgr_attach(mgr, &client->manager);
|
|
|
|
ns_server_attach(mgr->sctx, &client->sctx);
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_task_attach(mgr->task, &client->task);
|
2020-01-28 11:05:07 +01:00
|
|
|
|
2020-09-25 11:51:36 +02:00
|
|
|
dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE,
|
|
|
|
&client->message);
|
2019-11-05 17:48:47 -03:00
|
|
|
|
2020-01-31 22:56:32 +01:00
|
|
|
client->sendbuf = isc_mem_get(client->mctx,
|
|
|
|
NS_CLIENT_SEND_BUFFER_SIZE);
|
1999-08-05 01:51:32 +00:00
|
|
|
/*
|
2019-11-05 15:34:35 -08:00
|
|
|
* Set magic earlier than usual because ns_query_init()
|
|
|
|
* and the functions it calls will require it.
|
1999-08-05 01:51:32 +00:00
|
|
|
*/
|
2019-11-05 15:34:35 -08:00
|
|
|
client->magic = NS_CLIENT_MAGIC;
|
|
|
|
result = ns_query_init(client);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
2021-05-22 18:12:11 +02:00
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(client->tid == isc_nm_tid());
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_clientmgr_t *oldmgr = client->manager;
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_server_t *sctx = client->sctx;
|
|
|
|
isc_task_t *task = client->task;
|
2020-01-31 22:56:32 +01:00
|
|
|
unsigned char *sendbuf = client->sendbuf;
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_message_t *message = client->message;
|
|
|
|
isc_mem_t *oldmctx = client->mctx;
|
|
|
|
ns_query_t query = client->query;
|
2021-05-22 18:12:11 +02:00
|
|
|
int tid = client->tid;
|
2020-02-12 13:59:18 +01:00
|
|
|
|
2020-02-18 13:38:41 -08:00
|
|
|
/*
|
|
|
|
* Retain these values from the existing client, but
|
|
|
|
* zero every thing else.
|
|
|
|
*/
|
2020-02-12 13:59:18 +01:00
|
|
|
*client = (ns_client_t){ .magic = 0,
|
|
|
|
.mctx = oldmctx,
|
|
|
|
.manager = oldmgr,
|
|
|
|
.sctx = sctx,
|
|
|
|
.task = task,
|
2020-01-31 22:56:32 +01:00
|
|
|
.sendbuf = sendbuf,
|
2020-02-12 13:59:18 +01:00
|
|
|
.message = message,
|
2021-05-22 18:12:11 +02:00
|
|
|
.query = query,
|
|
|
|
.tid = tid };
|
1999-08-05 01:51:32 +00:00
|
|
|
}
|
2019-01-04 12:50:51 +01:00
|
|
|
|
Allow stale data to be used before name resolution
This commit allows stale RRset to be used (if available) for responding
a query, before an attempt to refresh an expired, or otherwise resolve
an unavailable RRset in cache is made.
For that to work, a value of zero must be specified for
stale-answer-client-timeout statement.
To better understand the logic implemented, there are three flags being
used during database lookup and other parts of code that must be
understood:
. DNS_DBFIND_STALEOK: This flag is set when BIND fails to refresh a
RRset due to timeout (resolver-query-timeout), its intent is to
try to look for stale data in cache as a fallback, but only if
stale answers are enabled in configuration.
This flag is also used to activate stale-refresh-time window, since it
is the only way the database knows that a resolution has failed.
. DNS_DBFIND_STALEENABLED: This flag is used as a hint to the database
that it may use stale data. It is always set during query lookup if
stale answers are enabled, but only effectively used during
stale-refresh-time window. Also during this window, the resolver will
not try to resolve the query, in other words no attempt to refresh the
data in cache is made when the stale-refresh-time window is active.
. DNS_DBFIND_STALEONLY: This new introduced flag is used when we want
stale data from the database, but not due to a failure in resolution,
it also doesn't require stale-refresh-time window timer to be active.
As long as there is a stale RRset available, it should be returned.
It is mainly used in two situations:
1. When stale-answer-client-timeout timer is triggered: in that case
we want to know if there is stale data available to answer the
client.
2. When stale-answer-client-timeout value is set to zero: in that
case, we also want to know if there is some stale RRset available
to promptly answer the client.
We must also discern between three situations that may happen when
resolving a query after the addition of stale-answer-client-timeout
statement, and how to handle them:
1. Are we running query_lookup() due to stale-answer-client-timeout
timer being triggered?
In this case, we look for stale data, making use of
DNS_DBFIND_STALEONLY flag. If a stale RRset is available then
respond the client with the data found, mark this query as
answered (query attribute NS_QUERYATTR_ANSWERED), so when the
fetch completes the client won't be answered twice.
We must also take care of not detaching from the client, as a
fetch will still be running in background, this is handled by the
following snippet:
if (!QUERY_STALEONLY(&client->query)) {
isc_nmhandle_detach(&client->reqhandle);
}
Which basically tests if DNS_DBFIND_STALEONLY flag is set, which
means we are here due to a stale-answer-client-timeout timer
expiration.
2. Are we running query_lookup() due to resolver-query-timeout being
triggered?
In this case, DNS_DBFIND_STALEOK flag will be set and an attempt
to look for stale data will be made.
As already explained, this flag is algo used to activate
stale-refresh-time window, as it means that we failed to refresh
a RRset due to timeout.
It is ok in this situation to detach from the client, as the
fetch is already completed.
3. Are we running query_lookup() during the first time, looking for
a RRset in cache and stale-answer-client-timeout value is set to
zero?
In this case, if stale answers are enabled (probably), we must do
an initial database lookup with DNS_DBFIND_STALEONLY flag set, to
indicate to the database that we want stale data.
If we find an active RRset, proceed as normal, answer the client
and the query is done.
If we find a stale RRset we respond to the client and mark the
query as answered, but don't detach from the client yet as an
attempt in refreshing the RRset will still be made by means of
the new introduced function 'query_resolve'.
If no active or stale RRset is available, begin resolution as
usual.
2020-12-21 15:54:54 -03:00
|
|
|
client->query.attributes &= ~NS_QUERYATTR_ANSWERED;
|
2019-11-05 15:34:35 -08:00
|
|
|
client->state = NS_CLIENTSTATE_INACTIVE;
|
|
|
|
client->udpsize = 512;
|
|
|
|
client->ednsversion = -1;
|
|
|
|
dns_name_init(&client->signername, NULL);
|
|
|
|
dns_ecs_init(&client->ecs);
|
|
|
|
isc_sockaddr_any(&client->formerrcache.addr);
|
|
|
|
client->formerrcache.time = 0;
|
|
|
|
client->formerrcache.id = 0;
|
|
|
|
ISC_LINK_INIT(client, rlink);
|
2020-02-12 13:59:18 +01:00
|
|
|
client->rcode_override = -1; /* not set */
|
2019-01-04 12:50:51 +01:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
client->magic = NS_CLIENT_MAGIC;
|
1999-12-22 16:59:05 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
CTRACE("client_setup");
|
2001-01-27 02:08:07 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
return (ISC_R_SUCCESS);
|
2001-01-27 02:08:07 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
cleanup:
|
2020-01-31 22:56:32 +01:00
|
|
|
if (client->sendbuf != NULL) {
|
|
|
|
isc_mem_put(client->mctx, client->sendbuf,
|
|
|
|
NS_CLIENT_SEND_BUFFER_SIZE);
|
2001-01-27 02:08:07 +00:00
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
if (client->message != NULL) {
|
2020-09-21 16:16:15 -03:00
|
|
|
dns_message_detach(&client->message);
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
2000-02-11 20:56:19 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
if (client->task != NULL) {
|
|
|
|
isc_task_detach(&client->task);
|
|
|
|
}
|
2000-08-01 01:33:37 +00:00
|
|
|
|
2020-01-16 11:53:31 +01:00
|
|
|
if (client->manager != NULL) {
|
|
|
|
clientmgr_detach(&client->manager);
|
|
|
|
}
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_mem_detach(&client->mctx);
|
2020-01-16 11:53:31 +01:00
|
|
|
if (client->sctx != NULL) {
|
|
|
|
ns_server_detach(&client->sctx);
|
|
|
|
}
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
return (result);
|
1999-12-22 16:59:05 +00:00
|
|
|
}
|
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
bool
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_shuttingdown(ns_client_t *client) {
|
2019-11-05 15:34:35 -08:00
|
|
|
return (client->shuttingdown);
|
2000-01-06 01:09:27 +00:00
|
|
|
}
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
/***
|
|
|
|
*** Client Manager
|
|
|
|
***/
|
2000-05-02 01:16:21 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
clientmgr_attach(ns_clientmgr_t *source, ns_clientmgr_t **targetp) {
|
2019-11-05 15:34:35 -08:00
|
|
|
int32_t oldrefs;
|
2000-01-07 19:20:25 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
REQUIRE(VALID_MANAGER(source));
|
|
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
2012-10-06 14:20:45 +10:00
|
|
|
|
2019-07-23 10:24:50 -04:00
|
|
|
oldrefs = isc_refcount_increment0(&source->references);
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT,
|
|
|
|
ISC_LOG_DEBUG(3), "clientmgr @%p attach: %d", source,
|
|
|
|
oldrefs + 1);
|
2019-02-06 11:26:36 -08:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
*targetp = source;
|
|
|
|
}
|
2000-01-07 19:20:25 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
clientmgr_detach(ns_clientmgr_t **mp) {
|
|
|
|
int32_t oldrefs;
|
2019-11-05 15:34:35 -08:00
|
|
|
ns_clientmgr_t *mgr = *mp;
|
2020-02-08 04:37:54 -08:00
|
|
|
*mp = NULL;
|
2019-02-06 11:27:11 -08:00
|
|
|
|
2020-02-08 04:37:54 -08:00
|
|
|
oldrefs = isc_refcount_decrement(&mgr->references);
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_log_write(ns_lctx, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_CLIENT,
|
|
|
|
ISC_LOG_DEBUG(3), "clientmgr @%p detach: %d", mgr,
|
|
|
|
oldrefs - 1);
|
2019-11-05 15:34:35 -08:00
|
|
|
if (oldrefs == 1) {
|
|
|
|
clientmgr_destroy(mgr);
|
|
|
|
}
|
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
clientmgr_destroy(ns_clientmgr_t *manager) {
|
1999-07-24 01:17:44 +00:00
|
|
|
MTRACE("clientmgr_destroy");
|
|
|
|
|
2019-07-23 08:27:30 -04:00
|
|
|
isc_refcount_destroy(&manager->references);
|
2019-11-05 15:34:35 -08:00
|
|
|
manager->magic = 0;
|
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
dns_aclenv_detach(&manager->aclenv);
|
2017-09-08 13:39:09 -07:00
|
|
|
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&manager->lock);
|
|
|
|
isc_mutex_destroy(&manager->reclock);
|
2017-09-08 13:39:09 -07:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (manager->excl != NULL) {
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_task_detach(&manager->excl);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2017-09-08 13:39:09 -07:00
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_task_detach(&manager->task);
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_server_detach(&manager->sctx);
|
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_mem_putanddetach(&manager->mctx, manager, sizeof(*manager));
|
1999-07-24 01:17:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2021-05-22 18:12:11 +02:00
|
|
|
ns_clientmgr_create(ns_server_t *sctx, isc_taskmgr_t *taskmgr,
|
|
|
|
isc_timermgr_t *timermgr, dns_aclenv_t *aclenv, int tid,
|
|
|
|
ns_clientmgr_t **managerp) {
|
|
|
|
ns_clientmgr_t *manager = NULL;
|
|
|
|
isc_mem_t *mctx = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_mem_create(&mctx);
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
manager = isc_mem_get(mctx, sizeof(*manager));
|
|
|
|
*manager = (ns_clientmgr_t){ .magic = 0, .mctx = mctx };
|
2011-10-10 22:57:14 +00:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
result = isc_taskmgr_excltask(taskmgr, &manager->excl);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_mem_put(mctx, manager, sizeof(*manager));
|
|
|
|
return (result);
|
2017-09-08 13:39:09 -07:00
|
|
|
}
|
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
isc_mutex_init(&manager->lock);
|
|
|
|
isc_mutex_init(&manager->reclock);
|
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
manager->taskmgr = taskmgr;
|
|
|
|
manager->timermgr = timermgr;
|
2021-05-22 18:12:11 +02:00
|
|
|
manager->tid = tid;
|
2017-09-08 13:39:09 -07:00
|
|
|
|
2021-05-22 18:12:11 +02:00
|
|
|
dns_aclenv_attach(aclenv, &manager->aclenv);
|
2019-11-05 15:34:35 -08:00
|
|
|
|
|
|
|
manager->exiting = false;
|
2021-05-22 18:12:11 +02:00
|
|
|
result = isc_task_create_bound(manager->taskmgr, 20, &manager->task,
|
|
|
|
manager->tid);
|
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
isc_refcount_init(&manager->references, 1);
|
2017-09-08 13:39:09 -07:00
|
|
|
manager->sctx = NULL;
|
|
|
|
ns_server_attach(sctx, &manager->sctx);
|
|
|
|
|
2001-10-24 03:10:18 +00:00
|
|
|
ISC_LIST_INIT(manager->recursing);
|
2020-01-28 11:05:07 +01:00
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
manager->magic = MANAGER_MAGIC;
|
|
|
|
|
|
|
|
MTRACE("create");
|
|
|
|
|
|
|
|
*managerp = manager;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
|
|
|
|
isc_result_t result;
|
1999-07-24 01:17:44 +00:00
|
|
|
ns_clientmgr_t *manager;
|
2020-02-13 14:44:37 -08:00
|
|
|
bool unlock = false;
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-07-24 01:17:44 +00:00
|
|
|
REQUIRE(managerp != NULL);
|
|
|
|
manager = *managerp;
|
2020-02-08 04:37:54 -08:00
|
|
|
*managerp = NULL;
|
1999-07-24 01:17:44 +00:00
|
|
|
REQUIRE(VALID_MANAGER(manager));
|
|
|
|
|
|
|
|
MTRACE("destroy");
|
|
|
|
|
2012-08-22 19:19:30 +10:00
|
|
|
/*
|
|
|
|
* Check for success because we may already be task-exclusive
|
|
|
|
* at this point. Only if we succeed at obtaining an exclusive
|
|
|
|
* lock now will we need to relinquish it later.
|
|
|
|
*/
|
2017-09-08 13:39:09 -07:00
|
|
|
result = isc_task_beginexclusive(manager->excl);
|
2019-11-05 15:34:35 -08:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2018-04-17 08:29:14 -07:00
|
|
|
unlock = true;
|
2019-11-05 15:34:35 -08:00
|
|
|
}
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
manager->exiting = true;
|
1999-07-24 01:17:44 +00:00
|
|
|
|
2019-11-05 15:34:35 -08:00
|
|
|
if (unlock) {
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_task_endexclusive(manager->excl);
|
|
|
|
}
|
|
|
|
|
2019-07-23 10:24:50 -04:00
|
|
|
if (isc_refcount_decrement(&manager->references) == 1) {
|
2019-11-05 15:34:35 -08:00
|
|
|
clientmgr_destroy(manager);
|
1999-08-05 01:51:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-30 02:49:38 +00:00
|
|
|
isc_sockaddr_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_getsockaddr(ns_client_t *client) {
|
2000-02-17 18:18:24 +00:00
|
|
|
return (&client->peeraddr);
|
1999-11-30 02:49:38 +00:00
|
|
|
}
|
2000-02-22 21:24:24 +00:00
|
|
|
|
2018-01-13 00:31:30 +05:30
|
|
|
isc_sockaddr_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_getdestaddr(ns_client_t *client) {
|
2018-01-13 00:31:30 +05:30
|
|
|
return (&client->destsockaddr);
|
|
|
|
}
|
|
|
|
|
2000-02-22 21:24:24 +00:00
|
|
|
isc_result_t
|
2009-03-03 01:36:17 +00:00
|
|
|
ns_client_checkaclsilent(ns_client_t *client, isc_netaddr_t *netaddr,
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_acl_t *acl, bool default_allow) {
|
|
|
|
isc_result_t result;
|
2021-05-22 18:12:11 +02:00
|
|
|
dns_aclenv_t *env = client->manager->aclenv;
|
2009-03-03 01:36:17 +00:00
|
|
|
isc_netaddr_t tmpnetaddr;
|
2020-02-13 14:44:37 -08:00
|
|
|
int match;
|
2000-02-22 21:24:24 +00:00
|
|
|
|
|
|
|
if (acl == NULL) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (default_allow) {
|
2000-02-22 21:24:24 +00:00
|
|
|
goto allow;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2000-02-22 21:24:24 +00:00
|
|
|
goto deny;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-02-22 21:24:24 +00:00
|
|
|
}
|
|
|
|
|
2009-03-03 01:36:17 +00:00
|
|
|
if (netaddr == NULL) {
|
|
|
|
isc_netaddr_fromsockaddr(&tmpnetaddr, &client->peeraddr);
|
|
|
|
netaddr = &tmpnetaddr;
|
|
|
|
}
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_acl_match(netaddr, client->signer, acl, env, &match, NULL);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2000-02-22 21:24:24 +00:00
|
|
|
goto deny; /* Internal error, already logged. */
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-08-28 22:05:57 -07:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (match > 0) {
|
2000-02-22 21:24:24 +00:00
|
|
|
goto allow;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-02-22 21:24:24 +00:00
|
|
|
goto deny; /* Negative match or no match. */
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
allow:
|
2000-04-06 22:03:35 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
2000-02-22 21:24:24 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
deny:
|
2000-02-22 21:24:24 +00:00
|
|
|
return (DNS_R_REFUSED);
|
|
|
|
}
|
|
|
|
|
2001-06-15 23:28:29 +00:00
|
|
|
isc_result_t
|
2007-03-29 06:36:31 +00:00
|
|
|
ns_client_checkacl(ns_client_t *client, isc_sockaddr_t *sockaddr,
|
2020-02-12 13:59:18 +01:00
|
|
|
const char *opname, dns_acl_t *acl, bool default_allow,
|
2020-02-13 14:44:37 -08:00
|
|
|
int log_level) {
|
|
|
|
isc_result_t result;
|
2009-03-03 01:36:17 +00:00
|
|
|
isc_netaddr_t netaddr;
|
2009-03-03 23:48:02 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (sockaddr != NULL) {
|
2009-03-03 01:36:17 +00:00
|
|
|
isc_netaddr_fromsockaddr(&netaddr, sockaddr);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2009-03-03 01:36:17 +00:00
|
|
|
|
|
|
|
result = ns_client_checkaclsilent(client, sockaddr ? &netaddr : NULL,
|
|
|
|
acl, default_allow);
|
2001-06-15 23:28:29 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
2001-06-15 23:28:29 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
|
|
|
|
"%s approved", opname);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2001-06-15 23:28:29 +00:00
|
|
|
ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
|
2020-02-12 13:59:18 +01:00
|
|
|
NS_LOGMODULE_CLIENT, log_level, "%s denied",
|
|
|
|
opname);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-06-15 23:28:29 +00:00
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2001-05-25 07:39:48 +00:00
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_name(ns_client_t *client, char *peerbuf, size_t len) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (client->peeraddr_valid) {
|
2013-12-04 12:47:23 +11:00
|
|
|
isc_sockaddr_format(&client->peeraddr, peerbuf,
|
|
|
|
(unsigned int)len);
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2001-05-25 07:39:48 +00:00
|
|
|
snprintf(peerbuf, len, "@%p", client);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-05-25 07:39:48 +00:00
|
|
|
}
|
|
|
|
|
2001-12-10 23:09:24 +00:00
|
|
|
void
|
2000-04-04 18:28:51 +00:00
|
|
|
ns_client_logv(ns_client_t *client, isc_logcategory_t *category,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_logmodule_t *module, int level, const char *fmt,
|
|
|
|
va_list ap) {
|
2013-02-20 13:54:52 -08:00
|
|
|
char msgbuf[4096];
|
2011-11-03 21:14:22 +00:00
|
|
|
char signerbuf[DNS_NAME_FORMATSIZE], qnamebuf[DNS_NAME_FORMATSIZE];
|
2016-09-22 14:45:20 -07:00
|
|
|
char peerbuf[ISC_SOCKADDR_FORMATSIZE];
|
2011-05-05 20:04:24 +00:00
|
|
|
const char *viewname = "";
|
2011-11-03 21:14:22 +00:00
|
|
|
const char *sep1 = "", *sep2 = "", *sep3 = "", *sep4 = "";
|
|
|
|
const char *signer = "", *qname = "";
|
|
|
|
dns_name_t *q = NULL;
|
2000-04-04 18:28:51 +00:00
|
|
|
|
2019-08-08 13:52:44 +10:00
|
|
|
REQUIRE(client != NULL);
|
|
|
|
|
2000-04-04 18:28:51 +00:00
|
|
|
vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
|
2011-05-05 20:04:24 +00:00
|
|
|
|
|
|
|
if (client->signer != NULL) {
|
|
|
|
dns_name_format(client->signer, signerbuf, sizeof(signerbuf));
|
|
|
|
sep1 = "/key ";
|
|
|
|
signer = signerbuf;
|
|
|
|
}
|
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
q = client->query.origqname != NULL ? client->query.origqname
|
|
|
|
: client->query.qname;
|
2011-11-03 21:14:22 +00:00
|
|
|
if (q != NULL) {
|
|
|
|
dns_name_format(q, qnamebuf, sizeof(qnamebuf));
|
|
|
|
sep2 = " (";
|
|
|
|
sep3 = ")";
|
|
|
|
qname = qnamebuf;
|
|
|
|
}
|
|
|
|
|
2002-05-24 06:22:30 +00:00
|
|
|
if (client->view != NULL && strcmp(client->view->name, "_bind") != 0 &&
|
2020-02-13 14:44:37 -08:00
|
|
|
strcmp(client->view->name, "_default") != 0)
|
|
|
|
{
|
2011-11-03 21:14:22 +00:00
|
|
|
sep4 = ": view ";
|
2011-05-05 20:04:24 +00:00
|
|
|
viewname = client->view->name;
|
2002-05-24 06:22:30 +00:00
|
|
|
}
|
2000-04-04 18:28:51 +00:00
|
|
|
|
2016-08-29 11:56:36 -07:00
|
|
|
if (client->peeraddr_valid) {
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_sockaddr_format(&client->peeraddr, peerbuf,
|
|
|
|
sizeof(peerbuf));
|
2016-08-29 11:56:36 -07:00
|
|
|
} else {
|
2016-09-22 14:45:20 -07:00
|
|
|
snprintf(peerbuf, sizeof(peerbuf), "(no-peer)");
|
2016-08-29 11:56:36 -07:00
|
|
|
}
|
2016-09-22 14:45:20 -07:00
|
|
|
|
2017-09-08 13:39:09 -07:00
|
|
|
isc_log_write(ns_lctx, category, module, level,
|
2020-02-12 13:59:18 +01:00
|
|
|
"client @%p %s%s%s%s%s%s%s%s: %s", client, peerbuf, sep1,
|
|
|
|
signer, sep2, qname, sep3, sep4, viewname, msgbuf);
|
2000-04-04 18:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ns_client_log(ns_client_t *client, isc_logcategory_t *category,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_logmodule_t *module, int level, const char *fmt, ...) {
|
2000-05-02 01:16:21 +00:00
|
|
|
va_list ap;
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!isc_log_wouldlog(ns_lctx, level)) {
|
2000-07-13 00:21:27 +00:00
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2000-07-13 00:21:27 +00:00
|
|
|
|
2000-04-04 18:28:51 +00:00
|
|
|
va_start(ap, fmt);
|
|
|
|
ns_client_logv(client, category, module, level, fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2001-03-11 06:19:39 +00:00
|
|
|
void
|
2016-12-30 15:45:08 +11:00
|
|
|
ns_client_aclmsg(const char *msg, const dns_name_t *name, dns_rdatatype_t type,
|
2020-02-13 14:44:37 -08:00
|
|
|
dns_rdataclass_t rdclass, char *buf, size_t len) {
|
2007-03-29 06:36:31 +00:00
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
|
|
char typebuf[DNS_RDATATYPE_FORMATSIZE];
|
|
|
|
char classbuf[DNS_RDATACLASS_FORMATSIZE];
|
|
|
|
|
|
|
|
dns_name_format(name, namebuf, sizeof(namebuf));
|
|
|
|
dns_rdatatype_format(type, typebuf, sizeof(typebuf));
|
|
|
|
dns_rdataclass_format(rdclass, classbuf, sizeof(classbuf));
|
|
|
|
(void)snprintf(buf, len, "%s '%s/%s/%s'", msg, namebuf, typebuf,
|
2003-01-21 06:11:46 +00:00
|
|
|
classbuf);
|
2001-03-11 06:19:39 +00:00
|
|
|
}
|
2001-05-25 07:39:48 +00:00
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_dumpmessage(ns_client_t *client, const char *reason) {
|
2001-05-25 07:39:48 +00:00
|
|
|
isc_buffer_t buffer;
|
2020-02-13 14:44:37 -08:00
|
|
|
char *buf = NULL;
|
|
|
|
int len = 1024;
|
2001-05-25 07:39:48 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (!isc_log_wouldlog(ns_lctx, ISC_LOG_DEBUG(1))) {
|
2014-05-27 12:16:04 +10:00
|
|
|
return;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2014-05-27 12:16:04 +10:00
|
|
|
|
2001-05-28 05:17:05 +00:00
|
|
|
/*
|
2001-06-15 22:35:42 +00:00
|
|
|
* Note that these are multiline debug messages. We want a newline
|
2001-05-28 05:17:05 +00:00
|
|
|
* to appear in the log after each message.
|
|
|
|
*/
|
2001-05-25 07:39:48 +00:00
|
|
|
|
|
|
|
do {
|
|
|
|
buf = isc_mem_get(client->mctx, len);
|
|
|
|
isc_buffer_init(&buffer, buf, len);
|
2020-02-12 13:59:18 +01:00
|
|
|
result = dns_message_totext(
|
|
|
|
client->message, &dns_master_style_debug, 0, &buffer);
|
2001-05-25 07:39:48 +00:00
|
|
|
if (result == ISC_R_NOSPACE) {
|
|
|
|
isc_mem_put(client->mctx, buf, len);
|
|
|
|
len += 1024;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else if (result == ISC_R_SUCCESS) {
|
2017-09-08 13:39:09 -07:00
|
|
|
ns_client_log(client, NS_LOGCATEGORY_CLIENT,
|
2001-06-28 02:39:46 +00:00
|
|
|
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(1),
|
2001-05-28 05:17:05 +00:00
|
|
|
"%s\n%.*s", reason,
|
2020-02-12 13:59:18 +01:00
|
|
|
(int)isc_buffer_usedlength(&buffer), buf);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-05-25 07:39:48 +00:00
|
|
|
} while (result == ISC_R_NOSPACE);
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (buf != NULL) {
|
2001-05-25 07:39:48 +00:00
|
|
|
isc_mem_put(client->mctx, buf, len);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2001-05-25 07:39:48 +00:00
|
|
|
}
|
2002-09-10 04:45:54 +00:00
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_dumprecursing(FILE *f, ns_clientmgr_t *manager) {
|
|
|
|
ns_client_t *client;
|
|
|
|
char namebuf[DNS_NAME_FORMATSIZE];
|
|
|
|
char original[DNS_NAME_FORMATSIZE];
|
|
|
|
char peerbuf[ISC_SOCKADDR_FORMATSIZE];
|
|
|
|
char typebuf[DNS_RDATATYPE_FORMATSIZE];
|
|
|
|
char classbuf[DNS_RDATACLASS_FORMATSIZE];
|
|
|
|
const char *name;
|
|
|
|
const char *sep;
|
|
|
|
const char *origfor;
|
2010-09-13 03:37:43 +00:00
|
|
|
dns_rdataset_t *rdataset;
|
2002-09-10 04:45:54 +00:00
|
|
|
|
|
|
|
REQUIRE(VALID_MANAGER(manager));
|
2007-03-29 06:36:31 +00:00
|
|
|
|
2011-10-10 22:57:14 +00:00
|
|
|
LOCK(&manager->reclock);
|
2002-09-10 04:45:54 +00:00
|
|
|
client = ISC_LIST_HEAD(manager->recursing);
|
|
|
|
while (client != NULL) {
|
2011-11-09 22:05:09 +00:00
|
|
|
INSIST(client->state == NS_CLIENTSTATE_RECURSING);
|
|
|
|
|
2002-09-10 04:45:54 +00:00
|
|
|
ns_client_name(client, peerbuf, sizeof(peerbuf));
|
|
|
|
if (client->view != NULL &&
|
|
|
|
strcmp(client->view->name, "_bind") != 0 &&
|
2020-02-13 14:44:37 -08:00
|
|
|
strcmp(client->view->name, "_default") != 0)
|
|
|
|
{
|
2002-09-10 04:45:54 +00:00
|
|
|
name = client->view->name;
|
|
|
|
sep = ": view ";
|
|
|
|
} else {
|
|
|
|
name = "";
|
|
|
|
sep = "";
|
|
|
|
}
|
2011-10-10 22:57:14 +00:00
|
|
|
|
|
|
|
LOCK(&client->query.fetchlock);
|
2011-11-09 22:05:09 +00:00
|
|
|
INSIST(client->query.qname != NULL);
|
2002-09-10 04:45:54 +00:00
|
|
|
dns_name_format(client->query.qname, namebuf, sizeof(namebuf));
|
2010-09-13 03:37:43 +00:00
|
|
|
if (client->query.qname != client->query.origqname &&
|
2020-02-13 14:44:37 -08:00
|
|
|
client->query.origqname != NULL)
|
|
|
|
{
|
2010-09-13 03:37:43 +00:00
|
|
|
origfor = " for ";
|
|
|
|
dns_name_format(client->query.origqname, original,
|
|
|
|
sizeof(original));
|
|
|
|
} else {
|
|
|
|
origfor = "";
|
|
|
|
original[0] = '\0';
|
|
|
|
}
|
|
|
|
rdataset = ISC_LIST_HEAD(client->query.qname->list);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (rdataset == NULL && client->query.origqname != NULL) {
|
2010-09-13 03:37:43 +00:00
|
|
|
rdataset = ISC_LIST_HEAD(client->query.origqname->list);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2010-09-13 03:37:43 +00:00
|
|
|
if (rdataset != NULL) {
|
|
|
|
dns_rdatatype_format(rdataset->type, typebuf,
|
|
|
|
sizeof(typebuf));
|
|
|
|
dns_rdataclass_format(rdataset->rdclass, classbuf,
|
|
|
|
sizeof(classbuf));
|
|
|
|
} else {
|
2017-09-13 00:14:37 -07:00
|
|
|
strlcpy(typebuf, "-", sizeof(typebuf));
|
|
|
|
strlcpy(classbuf, "-", sizeof(classbuf));
|
2010-09-13 03:37:43 +00:00
|
|
|
}
|
2011-10-10 22:57:14 +00:00
|
|
|
UNLOCK(&client->query.fetchlock);
|
2020-02-12 13:59:18 +01:00
|
|
|
fprintf(f,
|
|
|
|
"; client %s%s%s: id %u '%s/%s/%s'%s%s "
|
|
|
|
"requesttime %u\n",
|
|
|
|
peerbuf, sep, name, client->message->id, namebuf,
|
|
|
|
typebuf, classbuf, origfor, original,
|
2015-10-02 12:32:42 -07:00
|
|
|
isc_time_seconds(&client->requesttime));
|
2011-11-09 22:05:09 +00:00
|
|
|
client = ISC_LIST_NEXT(client, rlink);
|
2002-09-10 04:45:54 +00:00
|
|
|
}
|
2011-10-10 22:57:14 +00:00
|
|
|
UNLOCK(&manager->reclock);
|
2002-09-10 04:45:54 +00:00
|
|
|
}
|
2006-06-04 23:59:33 +00:00
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_qnamereplace(ns_client_t *client, dns_name_t *name) {
|
2011-10-10 22:57:14 +00:00
|
|
|
LOCK(&client->query.fetchlock);
|
2006-06-04 23:59:33 +00:00
|
|
|
if (client->query.restarts > 0) {
|
|
|
|
/*
|
|
|
|
* client->query.qname was dynamically allocated.
|
|
|
|
*/
|
2020-02-12 13:59:18 +01:00
|
|
|
dns_message_puttempname(client->message, &client->query.qname);
|
2006-06-04 23:59:33 +00:00
|
|
|
}
|
|
|
|
client->query.qname = name;
|
2015-04-23 16:57:15 +10:00
|
|
|
client->query.attributes &= ~NS_QUERYATTR_REDIRECT;
|
2011-10-10 22:57:14 +00:00
|
|
|
UNLOCK(&client->query.fetchlock);
|
2006-06-04 23:59:33 +00:00
|
|
|
}
|
2011-10-11 00:09:03 +00:00
|
|
|
|
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_sourceip(dns_clientinfo_t *ci, isc_sockaddr_t **addrp) {
|
2020-02-12 13:59:18 +01:00
|
|
|
ns_client_t *client = (ns_client_t *)ci->data;
|
2011-10-11 23:46:45 +00:00
|
|
|
|
2011-10-11 00:09:03 +00:00
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(addrp != NULL);
|
|
|
|
|
|
|
|
*addrp = &client->peeraddr;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
2018-08-10 15:54:14 -07:00
|
|
|
|
|
|
|
dns_rdataset_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_newrdataset(ns_client_t *client) {
|
2018-08-10 15:54:14 -07:00
|
|
|
dns_rdataset_t *rdataset;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2018-08-10 15:54:14 -07:00
|
|
|
|
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
|
|
|
|
rdataset = NULL;
|
|
|
|
result = dns_message_gettemprdataset(client->message, &rdataset);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rdataset);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) {
|
2018-08-10 15:54:14 -07:00
|
|
|
dns_rdataset_t *rdataset;
|
|
|
|
|
|
|
|
REQUIRE(NS_CLIENT_VALID(client));
|
|
|
|
REQUIRE(rdatasetp != NULL);
|
|
|
|
|
|
|
|
rdataset = *rdatasetp;
|
|
|
|
|
|
|
|
if (rdataset != NULL) {
|
|
|
|
if (dns_rdataset_isassociated(rdataset)) {
|
|
|
|
dns_rdataset_disassociate(rdataset);
|
|
|
|
}
|
|
|
|
dns_message_puttemprdataset(client->message, rdatasetp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_newnamebuf(ns_client_t *client) {
|
2021-05-19 17:18:22 -07:00
|
|
|
isc_buffer_t *dbuf = NULL;
|
2018-08-10 15:54:14 -07:00
|
|
|
|
|
|
|
CTRACE("ns_client_newnamebuf");
|
|
|
|
|
2020-02-02 08:35:46 +01:00
|
|
|
isc_buffer_allocate(client->mctx, &dbuf, 1024);
|
2018-08-10 15:54:14 -07:00
|
|
|
ISC_LIST_APPEND(client->query.namebufs, dbuf, link);
|
|
|
|
|
|
|
|
CTRACE("ns_client_newnamebuf: done");
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
dns_name_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf) {
|
2021-05-19 17:18:22 -07:00
|
|
|
dns_name_t *name = NULL;
|
2018-08-10 15:54:14 -07:00
|
|
|
isc_region_t r;
|
|
|
|
isc_result_t result;
|
|
|
|
|
|
|
|
REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0);
|
|
|
|
|
|
|
|
CTRACE("ns_client_newname");
|
2018-09-14 12:32:36 -07:00
|
|
|
|
2018-08-10 15:54:14 -07:00
|
|
|
result = dns_message_gettempname(client->message, &name);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
CTRACE("ns_client_newname: "
|
|
|
|
"dns_message_gettempname failed: done");
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
isc_buffer_availableregion(dbuf, &r);
|
|
|
|
isc_buffer_init(nbuf, r.base, r.length);
|
2021-05-19 17:18:22 -07:00
|
|
|
dns_name_setbuffer(name, NULL);
|
2018-08-10 15:54:14 -07:00
|
|
|
dns_name_setbuffer(name, nbuf);
|
|
|
|
client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED;
|
|
|
|
|
|
|
|
CTRACE("ns_client_newname: done");
|
|
|
|
return (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_buffer_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_getnamebuf(ns_client_t *client) {
|
2018-08-10 15:54:14 -07:00
|
|
|
isc_buffer_t *dbuf;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_region_t r;
|
2018-08-10 15:54:14 -07:00
|
|
|
|
|
|
|
CTRACE("ns_client_getnamebuf");
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* Return a name buffer with space for a maximal name, allocating
|
|
|
|
* a new one if necessary.
|
|
|
|
*/
|
|
|
|
if (ISC_LIST_EMPTY(client->query.namebufs)) {
|
2021-05-19 17:18:22 -07:00
|
|
|
ns_client_newnamebuf(client);
|
2018-08-10 15:54:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
dbuf = ISC_LIST_TAIL(client->query.namebufs);
|
|
|
|
INSIST(dbuf != NULL);
|
|
|
|
isc_buffer_availableregion(dbuf, &r);
|
|
|
|
if (r.length < DNS_NAME_MAXWIRE) {
|
2021-05-19 17:18:22 -07:00
|
|
|
ns_client_newnamebuf(client);
|
2018-08-10 15:54:14 -07:00
|
|
|
dbuf = ISC_LIST_TAIL(client->query.namebufs);
|
|
|
|
isc_buffer_availableregion(dbuf, &r);
|
|
|
|
INSIST(r.length >= 255);
|
|
|
|
}
|
|
|
|
CTRACE("ns_client_getnamebuf: done");
|
|
|
|
return (dbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) {
|
2018-08-10 15:54:14 -07:00
|
|
|
isc_region_t r;
|
|
|
|
|
|
|
|
CTRACE("ns_client_keepname");
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* '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);
|
|
|
|
isc_buffer_add(dbuf, r.length);
|
|
|
|
dns_name_setbuffer(name, NULL);
|
|
|
|
client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_releasename(ns_client_t *client, dns_name_t **namep) {
|
2018-08-10 15:54:14 -07: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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
CTRACE("ns_client_releasename");
|
2021-05-19 17:18:22 -07:00
|
|
|
client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED;
|
2018-08-10 15:54:14 -07:00
|
|
|
dns_message_puttempname(client->message, namep);
|
|
|
|
CTRACE("ns_client_releasename: done");
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_newdbversion(ns_client_t *client, unsigned int n) {
|
|
|
|
unsigned int i;
|
2021-05-19 17:18:22 -07:00
|
|
|
ns_dbversion_t *dbversion = NULL;
|
2018-08-10 15:54:14 -07:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
dbversion = isc_mem_get(client->mctx, sizeof(*dbversion));
|
2021-05-19 17:18:22 -07:00
|
|
|
*dbversion = (ns_dbversion_t){ 0 };
|
|
|
|
ISC_LIST_INITANDAPPEND(client->query.freeversions, dbversion,
|
|
|
|
link);
|
2018-08-10 15:54:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline ns_dbversion_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
client_getdbversion(ns_client_t *client) {
|
2021-05-19 17:18:22 -07:00
|
|
|
ns_dbversion_t *dbversion = NULL;
|
2018-08-10 15:54:14 -07:00
|
|
|
|
|
|
|
if (ISC_LIST_EMPTY(client->query.freeversions)) {
|
2021-05-19 17:18:22 -07:00
|
|
|
ns_client_newdbversion(client, 1);
|
2018-08-10 15:54:14 -07:00
|
|
|
}
|
|
|
|
dbversion = ISC_LIST_HEAD(client->query.freeversions);
|
|
|
|
INSIST(dbversion != NULL);
|
|
|
|
ISC_LIST_UNLINK(client->query.freeversions, dbversion, link);
|
|
|
|
|
|
|
|
return (dbversion);
|
|
|
|
}
|
|
|
|
|
|
|
|
ns_dbversion_t *
|
2020-02-13 14:44:37 -08:00
|
|
|
ns_client_findversion(ns_client_t *client, dns_db_t *db) {
|
2018-08-10 15:54:14 -07:00
|
|
|
ns_dbversion_t *dbversion;
|
|
|
|
|
|
|
|
for (dbversion = ISC_LIST_HEAD(client->query.activeversions);
|
2020-02-13 14:44:37 -08:00
|
|
|
dbversion != NULL; dbversion = ISC_LIST_NEXT(dbversion, link))
|
|
|
|
{
|
2018-08-10 15:54:14 -07:00
|
|
|
if (dbversion->db == db) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dbversion == NULL) {
|
|
|
|
/*
|
|
|
|
* This is a new zone for this query. Add it to
|
|
|
|
* the active list.
|
|
|
|
*/
|
|
|
|
dbversion = client_getdbversion(client);
|
|
|
|
if (dbversion == NULL) {
|
|
|
|
return (NULL);
|
|
|
|
}
|
|
|
|
dns_db_attach(db, &dbversion->db);
|
|
|
|
dns_db_currentversion(db, &dbversion->version);
|
|
|
|
dbversion->acl_checked = false;
|
|
|
|
dbversion->queryok = false;
|
2020-02-12 13:59:18 +01:00
|
|
|
ISC_LIST_APPEND(client->query.activeversions, dbversion, link);
|
2018-08-10 15:54:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return (dbversion);
|
|
|
|
}
|